# Question
Title: Cron Tasks not running in background, causing pages to take forever to load
We recently upgraded to D8 and I have been experiencing weird issues with Cron. Specifically, whenever the Cron is running, web pages are taking forever to load because cron is running some JS on the front end of any page you attempt to load. Specifically, it appears to be a timeout method that is holding up the page load.

> NOTE: I will update this post and provide the exact JS file and function that is running on the front end the next time it happens to me. At the time of writing, cron wasn't running and therefore I couldn't inspect the web page to get the running method

I know it's not the CPU on the server because when cron was running it never got above 20% CPU utilization.

Isn't cron suppose to run in the background? Why would cron have a JS file being executed on every page, causing any page not to load until cron finishes?

# Answer
> 2 votes
Part of the settings on /admin/config/system/cron are for the *Automated Cron* module, which adds them via `automated_cron_form_system_cron_settings_alter()`. The form field it adds has the following description.

> More information about setting up scheduled tasks can be found by reading the cron tutorial on drupal.org.

If you follow that link, you will read the following sentences. (Emphasis is mine.)

> The automated cron module has **the disadvantage that it is triggered by a request**, and the **unlucky user** who sends the request **may experience a fairly long delay**. For this reason, **the automated cron is typically used by smaller sites that are unable to create a cron job manually**, e.g. using the Linux crontab. If crontab is desired, Drupal console command may be used to simplify the configuration (rather than curling the long URL show in /admin/config/system/cron. Here is an example crontab entry:
>
> ```
> 30 * * * * web_user /var/www/html/vendor/bin/drupal --root=/var/www/html/docroot cron:execute > /dev/null 2>&1
>
> ```

Essentially, what you are experiencing is how the *Automated Cron* module work, but that isn't the only way to run cron tasks for Drupal.
You could also pass the URL shown on on /admin/config/system/cron after *To run cron from outside the site, go to* to `wget` or `curl`. This requires that you have access to, for example, cPanel for the site, which allows to set cron tasks.

---
Tags: 8, cron
---


# Question
Title: Limit of 15 routes in module.routing.yml
I have see when i want to create a new route they have an limit of 15 routes per module. In fact i have created an over route an i'm suprise to see of my road wans in route:debug. However they are in the module.routing.yml

I have cout the number of routes i have , and after 15 the routes arren't seen.

It's me or it's normal?

The YAML file :

```
 //empty line is not comment on the code
 unicef42.unicef_controller_index:
   path: '/unicef42'
   defaults:
     _controller: '\Drupal\unicef42\Controller\UnicefController::world'
     _title: 'Unicef controller'
   requirements:
     _permission: 'access content'

 //...the other routes

 //The 15th routes , no comment in the real code,1 empty road between the 14th and the 15th routes
 unicef42.accueil_controller_index:
   path: '/accueil'
   defaults:
     _controller: '\Drupal\unicef42\Controller\AccueilController::index'
     _title: ''
   requirements:
     _permission: 'access content'

 //The 16th routes , no comment in the real code, 1 empty road between the 15th and the 16th routes
 unicef42.accueil_controller_index:
   path: '/accueil2'
   defaults:
     _controller: '\Drupal\unicef42\Controller\AccueilController::index'
     _title: ''
   requirements:
     _permission: 'access content'
 //empty line is not comment on the code

```

# Answer
> 1 votes
It's just you I'm afraid.

Take the system module's routing file for example; there are a few dozen routes in there, plenty more than 15.

Symfony doesn't impose any limits either, so I'd check that your YAML code is properly formatted and valid. If you're positive it's all good, you've probably hit a bug and the best course of action would be to report it.

# Answer
> 1 votes
If you look at the content of the user.routing.yml file, you will notice there are more than 15 routes defined in that file.

What is wrong in your code is that the fifteenth and the sixteenth routes have the same identifier, *unicef42.accueil\_controller\_index*.

```
unicef42.accueil_controller_index:
  path: '/accueil'
  defaults:
    _controller: '\Drupal\unicef42\Controller\AccueilController::index'
    _title: ''
  requirements:
    _permission: 'access content'

unicef42.accueil_controller_index:
  path: '/accueil2'
  defaults:
    _controller: '\Drupal\unicef42\Controller\AccueilController::index'
    _title: ''
  requirements:
    _permission: 'access content'

```

That's the error in the definition of those routes, and why Drupal doesn't seem to see more than fifteen routes per module.

The User module, which defines two routes using the same path, but for two different HTTP methods and two different output formats, uses two different route IDs.

```
user.pass:
  path: '/user/password'
  defaults:
    _form: '\Drupal\user\Form\UserPasswordForm'
    _title: 'Reset your password'
  requirements:
    _access: 'TRUE'
  options:
    _maintenance_access: TRUE

user.pass.http:
  path: '/user/password'
  defaults:
    _controller: \Drupal\user\Controller\UserAuthenticationController::resetPassword
  methods: [POST]
  requirements:
    _access: 'TRUE'
    _format: 'json'

```

---
Tags: routes
---


# Question
Title: RuntimeException when running drush commands in root folder
I am setting up a local site for development on a ubuntu server 18.04 VM. I pull our repo into my windows machine and then mount this onto the VM as a shared folder. I run composer install and it finishes completely, but when I go to my site's docroot folder and run drush st or drush cr, I get the following error message:

```
RuntimeException: Drush::$container is not initialized yet. \Drush::setContainer() must be called with a real container. in Drush\Drush::getContainer() (line 151 of /media/sf_anothercnas2/vendor/drush/drush/src/Drush.php).
Drush command terminated abnormally due to an unrecoverable error.

```

Drupal installation went through successfully. In my composer.json, I have "drush/drush": "9.7.2"

`Composer show` confirms that the local drush version installed is 9.7.2 but when I run `drush --version`, it returns 8.1.16

# Answer
I still am not sure why I'm getting the RuntimeException, but I can work around this issue by running

```
vendor/drush/drush/drush st //or any other drush 9 commands

```
> 1 votes

---
Tags: drush
---


title: Radix JavaScript

text:
# Question
Title: Radix JavaScript
I am using the Radix Bootstrap Theme and Drupal 9.1.5. I have a Navigation Block with Children (using Bootstrap Dropdown) and some JS in radix\_aur\_scipt.js. I use that JS to open a Bootstrap Modal

```
import 'bootstrap';

...

  function createPdfModal (element) {
    ...
    $('.modal').modal();
  }

```

To use that JS I import bootstrap.min.js with Webpack

```
mix.js('src/js/radix_aur.script.js', 'js');
mix.copy('node_modules/bootstrap/dist/js/bootstrap.min.js', 'assets/js');

```

And radix\_aur.libraries.yml

```
  js:
    assets/js/radix_aur.script.js: {}
    assets/js/bootstrap.min.js: {}

```

When I am logged in as admin everything works as expected (Dropdown opens, Modal opens). As a non admin user I cant open the dropdown in the navigation. So I imported bootstrap.bundle.min.js in webpack assuming that popper.js was missing. I forgott to change that in the radix\_aur.libraries.yml which then didnt deliver bootstrap at all. However that fixed the problem with the dropdown for non admin users but then I cant open the modal

```
Uncaught TypeError: $(...).modal is not a function

```

When I realized my mistacke I changed the radix\_aur.libraries.yml that fixed the problem for the modal but then I am left with not beeing able to open the dropdown as non admin. I also tried using bootstrap.min.js and popper.js with the same outcome.

# Answer
There were one additional import in the radix\_aur\_script.js

```
import bootstrap

```

I deleted that and then everything worked as expected with the bootstrap.bundle.min.js Still dont know why this would block the whole thing from working.
> 0 votes

---
Tags: javascript, bootstrap-theme
---


title: Set default radio button on webform

text:
# Question
Title: Set default radio button on webform
I have a standard contact page created using *webform*, which has a set of radio buttons.

Is it possible to change the pre-selected radio option based on the referring page?

# Answer
I would add ?selectValue=yourvalue to the links pointing to your webform.

Then, create a template node--webform.tpl.php, check if i'm in the correct webform with the $node object and if $\_GET\['selectValue'\] is set. Then use jQuery to select my radio button.

It might not by the perfect solution, but it's clearly a way out!
> 0 votes

# Answer
With Webform you can pre-populate form default values via the url with tokens:

**Setting Default Values from the URL (7.x-3 and earlier)**

The `%get[key]` supported by Webform allows form values to be populated from the URL.

**Setting Default Values from the URL (7.x-4)**

To set the default values of a component to use either:

**Query Format**: For urls formatted like http://example.com/node/120?key=bar use `[current-page:query:key]` to return key value.,

**Args Format**: For urls formatted like http://example.com/node/120/key use `[current-page:url:args:2]` to return key.

Taken verbatim from webform docs
> 1 votes

# Answer
In Drupal 8 using Webforms module you can do the following:

admin/structure/webform/manage/donation/source

Add: '#default\_value': 'Yes'

To the radio button defined in the YML.
> 1 votes

# Answer
When you are adding new field in webform, select "Select option" in the type of field. After that you will get a field configuration page. In field configuration page you will see 3rd option as default value. You can put default value for that field.
> 0 votes

---
Tags: 7, webforms
---


# Question
Title: Change the Source DB for migrating via Drush
A few days ago I originally ran the full migration via the UI to get the site up and running and cleaning up any bugs from a DB instance that is a copy of the current live site. However, now that the site is up and running, I would like to re-migrate just the users from a NEW copy of the current live site in order to have an up-to-date data before going live (instead of losing any changes users made over the last few days).

* I don't want to re-migrate through the UI because I just need to migrate users
* I tried adding a `$databases['migrate']['default']` setting in the `settings.php` file but `migrate-import` doesn't have any option like `--legacy-db-key`
* `drush migrate-status` gives me an error because I deleted the backup db after I successfully migrated, but can't figure out a way to change the source DB

How can I change the source DB for the `migrate` drush commands in order to run a migration on just users via the `drush migrate-import` command?

# Answer
in settings.php add the connection to the source database (that contains users you want to migrate)

```
$databases['myuserssourcedb']['default'] = [
  'database' => '',
  'username' => '',
  'password' => '',
  'host' => '',
  'port' => '',
  'driver' => '',
  'prefix' => '',
  'collation' => '',
];

```

in your migration yml file reference the source database as 'key' in the 'source'

```
id: migration_of_users
label: 'Migrate users from old database'
migration_group: migration
source:
  plugin: mypluginforusers
  key: myuserssourcedb  <-----This is the important line
process:

```
> 0 votes

---
Tags: 8, migrations
---


title: How can I use Html::getUniqueID?

text:
# Question
Title: How can I use Html::getUniqueID?
My Drupal entity (block, node, paragraph, comment, whathaveyou) needs an HTML ID generated in various rendered view modes (full node, teaser, etc).

I could manually generate one using the entity `type_or_bundle_name` \+ `entity_id`, but if the entity appears more than once on a page a few things happen:

* accessibility testing tools report failures.
* many browsers complain about it in the JS console
* all because, technically, this goes against HTML spec (ids must be unique on the page).

In the vast majority of cases, *if you're generating an ID in Twig you really need to be guaranteeing uniqueness*.

It is hard to believe Drupal doesn't support this out of the box.

The Drupal Twig `clean_id` filter calls `HTML::getId()`, which does nothing more than strip invalid characters but doesnt ensure uniqueness.

# Answer
> 1 votes
The purpose of the `clean_id` filter isn't providing a unique ID, but removing from the string used as HTML ID the characters that aren't allowed. Basing on 6.2 SGML basic types HTML IDs can only contain letters, digits, hyphens, underscores, and colons.

`Html::getUniqueId()` itself uses `Html::getId()`.

```
// If this is an Ajax request, then content returned by this page request
// will be merged with content already on the base page. The HTML IDs must
// be unique for the fully merged content. Therefore use unique IDs.
if (static::$isAjax) {
  return static::getId($id) . '--' . Crypt::randomBytesBase64(8);
}

// @todo Remove all that code once we switch over to random IDs only,
// see https://www.drupal.org/node/1090592.
if (!isset(static::$seenIdsInit)) {
  static::$seenIdsInit = [];
}
if (!isset(static::$seenIds)) {
  static::$seenIds = static::$seenIdsInit;
}
$id = static::getId($id);

```

The documentation page for `Html::getId()` says it should be used only when the ID doesn't need to be unique.

For the cases where the ID needs to be unique, Drupal core modules set a variable passed to the template file, which is what's done in `template_preprocess_pager()`, `template_preprocess_block()`, or `template_preprocess_views_view_table()`, for example.

```
variables['heading_id'] = Html::getUniqueId('pagination-heading');

```

```
// Create a valid HTML ID and make sure it is unique.
if (!empty($variables['elements']['#id'])) {
  $variables['attributes']['id'] = Html::getUniqueId('block-' . $variables['elements']['#id']);
}

```

```
// Improves accessibility of complex tables.
$variables['header'][$field]['attributes']['id'] = Html::getUniqueId('view-' . $field . '-table-column');

```

Since Drupal core doesn't have a Twig filter that returns a unique ID, that is the only way to obtain one: Set a variable in a preprocess function used for the template file with the value returned from `Html::getUniqueId()`, and use that variable where the template file needs a unique ID.

---
Tags: theming
---


# Question
Title: How can I style the webform submissions table?
Using Drupal 9 and Webform, I'm unable to find the twig template used to output /contact/form/submissions. Is there a place in the documentation that lists the twig templates? I see there is a View created that looks like it has submissions, but disabling it doesn't break the page. If there is a better way to style it, that could also work.

# Answer
> 2 votes
Check out Is there a "best practice" for overriding a contributed module's controller in Drupal 8?

If you override the WebformSubmissionListBuilder, you can do almost anything you want to the results, including custom theming.

---
Tags: theming, webforms
---


# Question
Title: Force user to create a node after registration
How to force a user to post a node after registering?

The scenario would be the following: after registering, the user could not access the site without having created a node. Once this node is created, it would have access to the site normally.

# Answer
Access to a Drupal site is provided by permissions, and permissions are assigned to Roles. So the first thing to do is to create two types of users - one which can access the site when logged on and one which can't access the site when logged on. After that we can talk about how and when to change a specific user from the "can't access" to the "can access" type.

A new user in Drupal is automatically assigned the "authenticated" role. Because you want new users by default to NOT have access to the site, you should edit the "authenticated" role to remove permissions. Test this to make sure that a new user has only the limited permissions you want them to have.

Now create a new role for your "full access" users. I will call that role "full member access". Edit the role to have the permissions you want. Test to make sure this is what you want.

Once you have the two roles setup, it is now time to figure out how to change a user from "authenticated" to "full member access". Because you tagged this issue as "rules" I assume you want to use Rules to do this. Rules provides a UI where you can do this without programming, and where you can easily modify your conditions for changing the user role or even take addition steps like sending the newly privileged user a welcome email, again without programming.

Here's the outline of what the Rule should look like, followed by an export of the Rule:

* Event: After saving a new content item (This will happen when the user creates a new node. You may also restrict this event to fire only when content of a specific type is created.)
* Condition: User has role(s) (Check to see if the user has the "full member access" role yet.)
* Action: Add user role (This will add the "full member access" role to the user who just created a node and does not yet have full access.)

The following export of *rules.reaction.upgrade\_role\_to\_full\_member\_access.yml* implements this:

```
langcode: en
status: true
dependencies: {  }
id: upgrade_role_to_full_member_access
label: 'Upgrade role to full member access'
events:
  -
    event_name: 'rules_entity_insert:node'
description: 'Upgrade role to full member access after user creates their first node.'
tags: {  }
config_version: '3'
expression:
  id: rules_rule
  uuid: 7d99ef94-f454-405e-bb0d-0375816dec79
  weight: 0
  conditions:
    id: rules_and
    uuid: 3b1072a4-4a67-470f-8cd9-500a24a21b7c
    weight: 0
    conditions:
      -
        id: rules_condition
        uuid: 5b49ef27-e37e-4793-bda9-9fdb3940f374
        weight: 0
        context_values:
          roles:
            - full_member_access
          operation: AND
        context_mapping:
          user: '@user.current_user_context:current_user'
        context_processors:
          roles:
            rules_tokens: {  }
          operation:
            rules_tokens: {  }
        provides_mapping: {  }
        condition_id: rules_user_has_role
        negate: true
  actions:
    id: rules_action_set
    uuid: 994d29d7-302e-4c50-a0b6-a559f74dff3d
    weight: 0
    actions:
      -
        id: rules_action
        uuid: 17e5bbfd-8966-4b7d-aec7-5b9158c1cf18
        weight: 0
        context_values:
          roles:
            - full_member_access
        context_mapping:
          user: '@user.current_user_context:current_user'
        context_processors:
          roles:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_user_role_add

```

The remaining issue is how to inform the new user that they need to create a node in order to get full access. To do this you can use another Rule that looks like this:

* Event: User has logged in
* Condition: User has role(s) (Check to see if the user is "authenticated" - if so the user still needs to create a node.)
* Action: Show a message on the site (If the condition is TRUE then we know the user needs to create a node, so use this message to inform them of what they need to do.)
* Action: Page redirect (Redirect the user to the node create page, /node/add.)

Or if you have a custom page/form set up for the creation of this first node, then you could simply redirect to that page instead.

The following export of *rules.reaction.redirect\_to\_create\_node.yml* implements this:

```
langcode: en
status: true
dependencies: {  }
id: redirect_to_create_node
label: 'Redirect to create node'
events:
  -
    event_name: rules_user_login
description: 'Redirect user to node creation page on login, if user doesn''t already have full access.'
tags: {  }
config_version: '3'
expression:
  id: rules_rule
  uuid: 5e666529-2664-427c-b0b6-e51e9d464606
  weight: 0
  conditions:
    id: rules_and
    uuid: 6cd14b6a-d0d7-4226-99be-42f61ca3d2b0
    weight: 0
    conditions:
      -
        id: rules_condition
        uuid: c3c6c654-96e5-4cea-96f3-ba32a2cbf2ec
        weight: 0
        context_values:
          roles:
            - full_member_access
          operation: AND
        context_mapping:
          user: account
        context_processors:
          roles:
            rules_tokens: {  }
          operation:
            rules_tokens: {  }
        provides_mapping: {  }
        condition_id: rules_user_has_role
        negate: true
  actions:
    id: rules_action_set
    uuid: bacfc01b-bdb8-4386-92ca-1e7dad78574e
    weight: 0
    actions:
      -
        id: rules_action
        uuid: e25bbe11-ef49-4061-a05c-9af5c715cbf6
        weight: 0
        context_values:
          message: 'You need to create a new node using the form on this page before you will be allowed access to the site.'
          type: warning
          repeat: false
        context_mapping: {  }
        context_processors:
          message:
            rules_tokens: {  }
          type:
            rules_tokens: {  }
          repeat:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_system_message
      -
        id: rules_action
        uuid: a449cefe-e3f8-488c-b2ac-ec4cb5e3e835
        weight: 0
        context_values:
          url: /node/add
        context_mapping: {  }
        context_processors:
          url:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_page_redirect

```

Note also that in order to make this work, you will have to temporarily use the Rules patch at https://www.drupal.org/project/rules/issues/2800749#comment-13942286 \- that patch adds the necessary feature to manipulate Roles like this. That patch is already RTBC and should be committed to Rules within the next month, so after that the patch won't be needed anymore.
> 2 votes

---
Tags: 8, rules
---


# Question
Title: How to translate node programmatically with correct revision translation affected value?
I have a question about create node translation programmatically.

First of all, the following is the database screenshot when we use drupal UI to create the translation.

The **revision\_translation\_affected** will be set to the language each time when the new one is created.

For example, I create an English article and then translate it with Chinese.

We can see the revision translation affected has been set with the Chinese version because of the translation is the latest created.

However, I use the following code to create a node and add the translation.

```
$post = \Drupal::entityTypeManager()->getStorage('node')->create(
        [
            'type' => 'page',
            'title' => 'test title',
            'langcode' => 'en'
        ]
    );
    $post->save();
    $source_translation = $post->getTranslation('en');
    $target_translation = $post->addTranslation('zh-hant', $source_translation->toArray());
    $target_translation->save();

```

I got the following database result

This result will cause the revision confusion when we want to see the revision record from each translation.

Does anyone have experience on how to handle this issue?

# Answer
> 1 votes
I just ran into this and this prevented my translated revision also appearing as a revision of my original:

```
$langcode = 'fr';
$node->setRevisionTranslationAffected(FALSE);
$node->addTranslation($langcode, ['title' => $node->getTitle()])->save();

```

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


# Question
Title: How to keep the non mapped paragraphs during migrations?
I am migrating content that contains paragraphs also. So I have two migration files.

When the content is migrated. Everything is fine. I can see the paragraphs are attached with the nodes.

When I edit a migrated node and adds a new paragraph to the node, then when I execute the migration again, that new paragraph removes from that node. Is there any way to keep them?

The paragraph\_import.yml

```
langcode: en
status: true
id: paragraph_import
label: My paragraph import
migration_tags:
  - paragraph
source:
  plugin: csv
  delimiter: ','
  enclosure: '"'
  escape: '`'
  header_offset: 0
  ids: ['personal_number']
destination:
  plugin: 'entity_reference_revisions:paragraph'
  default_bundle: my_paragraph
process:
  mail:
    - plugin: skip_on_empty
      method: process
      source: 'e-mail werk'
  cellphone:
    - plugin: skip_on_empty
      method: process
      source: 'gsm werk'
  phone:
    - plugin: skip_on_empty
      method: process
      source: telefoon
  langcode:
    - plugin: default_value
      default_value: 'nl'
dependencies:
  enforced:
    module:
      - migrate_source_csv

```

The node migration.

```
langcode: en
status: true
id: contact_import
label: Contacts
migration_tags:
  - node
source:
  plugin: csv
  delimiter: ','
  enclosure: '"'
  escape: '`'
  header_offset: 0
  ids: ['personal_number']
destination:
  plugin: 'entity:node'
  default_bundle: contact
process:
  type:
    plugin: default_value
    default_value: contact
  title: title
  paragraph:
    - plugin: migration_lookup
      migration: paragraph_import
      source: personal_number
  my_paragraph_field:
    - plugin: sub_process
      source:
        - '@paragraph'
      process:
        target_id: '0'
        target_revision_id: '1'
  langcode:
    - plugin: default_value
      default_value: 'nl'
dependencies:
  enforced:
    module:
      - migrate_source_csv

```

My migration execute code.

```
$migration = $this->migrationPluginManager->createInstance($migration_id);
$migration->getIdMap()->prepareUpdate();
 try {
   $executable = new MigrateExecutable($migration, new MigrateMessage());
   $executable->import();
 }
 catch (MigrateException $exception) {
   $this->logger->error($exception->getMessage());
 }

```

It is different from this question Because that question talks about the fields in the paragraph. While this question is about the paragraph entity itself.

# Answer
I have created a custom source plugin for this to achieve.

Here is my source plugin code.

```
class MYSOURCECSV extends CSV {

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    $database = \Drupal::database();
    $table = 'migrate_map_migration_id';

    // The migration removes the manually created entities from the system,
    // that are not present in the migration source. But we want them to be
    // ignored during the migration.
    if ($database->schema()->tableExists($table)) {
      $organisations = [];

      try {
        $results = $database->select($table, 'mmt')
          ->fields('mmt', ['destid1', 'destid2'])
          ->condition('sourceid1', $row->getSourceProperty('personal_number'))
          ->execute()
          ->fetchAll();

        if (!empty($results)) {
          foreach ($results as $result) {
            $paragraph_id = $result->destid1;

            $paragraph = \Drupal::entityTypeManager()

  ->getStorage('paragraph')
          ->load($paragraph_id);

        if ($paragraph instanceof ParagraphInterface) {
          $node = $paragraph->getParentEntity();

          // If paragraph is already attached to a node. Get the ids from
          // the node.
          if ($node instanceof NodeInterface) {
            $organisations = $node->get('my_paragraph_field')->getValue();

            if ($key = array_search($paragraph_id, array_column($paragraphs, 'target_id'))) {
              $paragraphs[$key]['target_revision_id'] = $result->destid2;
            }
          }
          else {
            $paragraphs[] = [
              'target_id' => $result->destid1,
              'target_revision_id' => $result->destid2,
            ];
          }
        }
      }
    }

    $row->setSourceProperty('my_paragraph_field', $paragraphs);
  }
  catch (Exception $exception) {
    \Drupal::logger('my_module')->error($exception->getMessage());
  }
}

parent::prepareRow($row);
  }

}

```

And then change the paragraph field mapping in the migration file to:

```
my_paragraph_field:
    - plugin: sub_process
      source: organisations
      process:
        target_id: target_id
        target_revision_id: target_revision_id

```
> 0 votes

---
Tags: 8, migrations, paragraphs
---


title: How do I redirect to the login page?

text:
# Question
Title: How do I redirect to the login page?
I have a custom search form which appears in the modal and is accessible only to logged in users. The ajax url of the form is /my/custom/search/modal/{nojs}. The router definition is the following one.

```
mymodule.my_custom_search_form:
  path: '/my/custom/search/modal/{nojs}'
  defaults:
    _form:  '\Drupal\mymodule\Form\MyCustomSearchForm'
    _title: 'My Custom search'
    nojs: ajax
  requirements:
    _user_is_logged_in: 'TRUE'

```

How do I redirect users to the login page when the anonymous user tries to access /my/custom/search/modal/{nojs} via an AJAX call?

# Answer
> 1 votes
There are a couple of modules that do this

This page was old, but looked like it had been updated along the way for Drupal 8.

---
Tags: 8, ajax, redirection
---


title: Pass data to hook_entity_insert

text:
# Question
Title: Pass data to hook_entity_insert
How can I pass data to `hook_entity_insert()` given that the arguments it takes are fixed?

I'm writing to the database during entity save, and need to be able to pass some data in this hook.

# Answer
> 1 votes
You can add a property to the entity, which is then checked from `hook_entity_insert()`. This isn't different from what the Book module does: `book_node_load()` adds a property to the node object (`node->book`), which is then retrieved from `book_node_insert()`.

```
function book_node_load($nodes, $types) {
  $result = db_query("SELECT * FROM {book} b INNER JOIN {menu_links} ml ON b.mlid = ml.mlid WHERE b.nid IN (:nids)", array(
    ':nids' => array_keys($nodes),
  ), array(
    'fetch' => PDO::FETCH_ASSOC,
  ));
  foreach ($result as $record) {
    $nodes[$record['nid']]->book = $record;
    $nodes[$record['nid']]->book['href'] = $record['link_path'];
    $nodes[$record['nid']]->book['title'] = $record['link_title'];
    $nodes[$record['nid']]->book['options'] = unserialize($record['options']);
  }
}

function book_node_insert($node) {
  if (!empty($node->book['bid'])) {
    if ($node->book['bid'] == 'new') {
      // New nodes that are their own book.
      $node->book['bid'] = $node->nid;
    }
    $node->book['nid'] = $node->nid;
    $node->book['menu_name'] = book_menu_name($node->book['bid']);
    _book_update_outline($node);
  }
}

```

The Book module is implementing `hook_node_insert()` instead of `hook_entity_insert()`. The difference between those hooks is that the first is invoked when a node is created, after the node is saved in the database, while the latter is invoked when any entity is created, after than entity is saved in the database. `hook_entity_insert()` also has the entity type as parameter, while `hook_node_insert()` doesn't have that parameter (since it knows which entity type is being saved).
What I described can be used for both the hooks.

# Answer
> 0 votes
Since you're not initiating the hook, you'll have to find another way. Maybe call a hook in the hook you're implementing?

If you would've been initiating the hook, you could've just passed on more parameters and used func\_get\_args to get the parameters, ie:

```
function sum ($a, $b) {
  $sum = 0;
  foreach (func_get_args() as $arg) {
    $sum += $arg;
  }
}

```

and call it with

```
sum(1, 2, 3, 4)

```

---
Tags: 7, entities
---


# Question
Title: How to add a button in the header of a table form?
I have this table form:

The corresponding code for the header is

```
$form['inscriptions'] = [
  '#type'   => 'table',
  '#header' => [
    [
      'data'    => '',
      'colspan' => 2,
    ],
    [
      'data'    => 'Distribution',
      'colspan' => 2,
    ],
    [
      'data'    => 'Réserve',
      'colspan' => 2,
    ],
    [
      'data'    => 'Référent',
      'colspan' => 2,
    ],
  ],
  '#id'     => 'planningofdistributions',
  '#sticky' => TRUE,
];

```

I would like to replace the (empty) content of the first cell by a submit button.
How can I do that?

# Answer
> 0 votes
Finally, I did it this way:

```
if (some condition) {
  $data = [
    '#type'     => 'inline_template',
    '#template' => '<input type="submit" id="edit-toggle" name="button" value="{{ foo }}" class="button js-form-submit form-submit">',
    '#context'  => ['foo' => $this->t('Toggle')],
  ];
}
else {
  $data = '';
}

$form['inscriptions'] = [
  '#type'   => 'table',
  '#header' => [
    [
      'data'    => $data,
      'colspan' => 2,
    ],
    [
      'data'    => 'Distribution',
      'colspan' => 2,
    ],
    [
      'data'    => 'Réserve',
      'colspan' => 2,
    ],
    [
      'data'    => 'Référent',
      'colspan' => 2,
    ],
  ],
  '#id'     => 'planningofdistributions',
  '#sticky' => TRUE,
];

```

---
Tags: 8, forms
---


# Question
Title: How to expand NodeForm so new argument can passed to it
I have a content type called service request, which have some conditional fields that each might appear or disappear based on an other field value called service type.

I have used conditional field and they work just right but for better user experience I want node form to be called using one of the service types.

so I tried to follow this instructions provided by Jaypan to extend NodeForm, but when overriding form function of NodeForm, it leads to `Error: Call to a member function getEntityTypeId() on null in Drupal\Core\Entity\EntityForm->getBaseFormId()`

this is how I used to create $form:

```
class ServiceBuilderForm extends NodeForm {
  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state, $serviceType = NULL) {
    // Added as a fallback in case a developer uses this form without passing
    // $someId:
    if (is_null($serviceType)) {
      $form = [
        '#prefix' => '<p class="error">',
        '#suffix' => '</p>',
        '#markup' => $this->t('Form is missing Service Type which is required'),
      ];
    }
    else {
      $form = parent::form($form, $form_state);
      // Do something with $form and $some_id
    }

    return $form;
  }
}

```

and in my Controller I have get my form using:

```
$form = \Drupal::formBuilder()->getForm('\Drupal\{my_module}\Form\ServiceFormBuilder', $serviceType);

```

# Answer
> 2 votes
After you have integrated the form class in the entity type as form mode

```
function mymodule_entity_type_build(array &$entity_types) {
  $entity_types['node']->setFormClass('service', 'Drupal\mymodule\Form\ServiceBuilderForm');
}

```

and invoked the node form in a controller

```
$form = $this->entityFormBuilder()->getForm($node, 'service');

```

or without controller directly in a route:

```
_entity_form: 'node.service'

```

the entity including the field data is passed to your form

```
class ServiceBuilderForm extends NodeForm {
  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state) {
    $node = $this->entity;
    if ($node->getType() == 'service_request') {
      $field_value = $node->field_service_type->value;

```

and you avoid the error from your question that the entity is null.

# Answer
> 1 votes
While 4k4 provided a great answer on how to extend an Entity Form and how to instantiate that , for any one who just needs to extend NodeForm class to send new argument to that, they can use a simple code like below :

```
$node = $this->entityService
  ->getStorage('node')
  ->create(['type' => 'service']);

$form = $this->entityService
  ->getFormObject('node', 'default')
  ->setEntity($node);

$form = $this->myFormBuilder->getForm($form, $questions);//arguments will be passed in form and can be accessed in form using `$form_state->getBuildInfo()['args'][0]`

$form['field_service_type']['widget']['#default_value'] = $rbid;
$form['field_service_type']['widget']['#value'] = $rbid;
$form['#validate'][] = 'my_form_validate';

return [
  'form' => $form,
];

```

in the code above `$this->entityService` is an EntityTypeManager object injected to my controller, when I got the usual form object I have set service type field (not recommended cause it is related to widget type).

> as mentioned in code as comment arguments passed can be accessed in form using `$form_state->getBuildInfo()['args']`

So just in mind that if you need to pass arguments to an EntityForm and you are looking for a simple solution, then this code might help.

---
Tags: nodes, forms, 9
---


# Question
Title: Select a module to build an ad or job search site
Select a module to build an ad or job search site

I want to create a site for job search and employment in the field of employer and contractor

I can

1. create an information submission forum with the webform module (Use the webform module and display submission forms by a view module ) 2.Or I can create a new content from the structure and add new content to an information submission form Or other solutions

My question is which method is better for SEO?

# Answer
In short: New content will simpler and better for SEO, because webform submissions require additional handling for SEO.

For content submission, you should:

1. Allow required roles (guest or authorized) to submit content form in User permissions page.
2. Use Content Workflow for controlling submitted content (draft, published statuses).
3. Control SEO of that content by Drupal core and these modules.

p.s. I recommend using both (hard way, but protected, and IMHO, preferred):

1. Webform for collection information. Also, it allows building powerful forms: multistep, grouped fields, messages and so on without programming.
2. New content that show information. This allows you to use SEO modules, that usually work with content types. Webform allow easily control information control, so you will protect from spam, unusable, "broken" form submissions. That allow to reduce "New content" creation. New content, that created after submission - programmatically, Rules Webform or Webform Content Creator modules.
> 2 votes

---
Tags: webforms
---


# Question
Title: HTTP Client Manager $request->getStatusCode() == 200 return?
When I read this HTTP Client Manager docs on Drupal, I don't understand why it returns the $build when $request-\>getStatusCode() == 200, is that supposed to be not equal 200? I also copy and paste the code from Drupal docs.

```
public function posts($limit, $sort) {
    $build = [
      '#theme' => 'mymodule_posts_list',
      '#posts' => [],
    ];

    $request = $this->httpClient->request('GET', 'http://api.example.com/posts', [
      'limit' => $limit,
      'sort' => $sort,
    ]);

    // This is the Part I don't understand.
    if ($request->getStatusCode() == 200) {
      return $build;
    }

    $posts = $request->getBody()->getContents();
    foreach ($posts as $post) {
      $build['#posts'][] = [
        'id' => $post['id'],
        'title' => $post['title'],
        'text' => $post['text'],
      ];
    }
    return $build;
  }

```

# Answer
> 0 votes
The information from https://www.drupal.org/docs/contributed-modules/http-client-manager/introduction was wrong and was updated, now:

```
   if ($request->getStatusCode() != 200) {
      return $build;
    }

```

---
Tags: 8, http-request
---


# Question
Title: Inline Javascript throws an error on drupal_add_js() within an AJAX callback
I am trying to get JavaScript to measure a text field and auto submit at a character limit for an Ajax callback to be validated against a Luhn Algorithm and errors out on failure to validate.

I found this code in Firing ajax\_callback on textfield after a minimum number of character.

```
// Trigger ajax event on myitem only after 5th character typed.
$('.myitem-class').on('keyup', function() {
  if ($(this).val().length == 5) {
    $(this).trigger('change');
  }
});

```

The JavaScript can allegedly be put inline in a wrapper like this to be used in an Ajax callback in a form. See drupal\_add\_js within AJAX callback.

```
function my_module_form($form, &$form_state) {
  drupal_add_js('Drupal.ajax.prototype.commands.myFunction = function(ajax, response, status) {
    // …
    }',
    'inline'
  );

  return $form;
}

```

I got to run replacing `function(ajax, response, status)` with `function($, Drupal)`.

When I put in the code, it throws a PHP error at `).on(`. I wasn't able to get the inline wrapper recommended in Converting 6.x modules to 7.x / JavaScript should be compatible with libraries other than jQuery to work because it fails seeing the `$` as a variable.

```
(function ($) {
  // […]
}(jQuery));

```

Right now, I am stopped by syntax errors.

Does anyone know how to get this JavaScript code work?

# Answer
> 1 votes
Quick written code:

```
      <?php

      /**
        * Form.
        */
      function sample_luhn_form($form, &$form_state) {
        // I don't recommend inline js, prefer usual module js file, attach via $form['#attached'] or in module info file
        // Also I am use jQuery instead of $, but your shown (function ($) { }jQuery)); is preferred, I don't know why it's show errors, try inspect on dev.tools
        drupal_add_js('jQuery(document).ready(function () { jQuery(".luhn-nums").keydown(function() { if (jQuery(this).val().length >= 5) { jQuery(".luhn-check").mousedown(); } }); });', 'inline');

        // text field that should be checked for Luhn
        $form['luhn_nums'] = array(
          '#type' => 'textfield',
          '#title' => t('Luhn numbers'),
          '#prefix' => '<div class="luhn-nums-wrapper">',
          '#suffix' => '</div>',
          '#attributes' => array(
            'class' => array('luhn-nums'),
          ),
        );
        // hidden ajax button
        $form['luhn_check'] = array(
          '#type' => 'submit',
          '#ajax' => array(
            'callback' => 'sample_luhn_form_ajax_submit',
            'wrapper' => 'luhn-nums-wrapper',
          ),
          '#attributes' => array(
            'class' => array('luhn-check', 'element-invisible', 'hidden'), // set class, that hide this ajax submit button or hide via CSS styles
          ),
        );

        // here goes another form elements
        // ...
        $form['submit'] = array(
          '#type' => 'submit',
          '#value' => t('Submit'),
        );
      }

      /**
       * Ajax callback function.
       */
      function sample_luhn_form_ajax_submit($form, &$form_state) {
        if (_sample_luhn_check($form_state['values']['luhn_nums'])) {
          // If luhn not passed
          form_set_message('luhn_nums', t('Luhn error, please fix numbers'));
        }
        // here you can alter luhn_nums textfield value
        return $form['luhn_nums'];
      }

      /**
       * Validate form.
       */
      function sample_luhn_form_validate($form, &$form_state) {
        // Don't allow pass to submit untill luhn will passed
        if (_sample_luhn_check($form_state['values']['luhn_nums'])) {
          // If luhn not passed
          form_set_message('luhn_nums', t('Luhn error, please fix numbers'));
        }
      }

      /**
       * Form submit.
       */
      function sample_luhn_form_submit($form, &$form_state) {
        // save data
      }

      /**
       * Private function that check luhn algorithms.
       */
      function _sample_luhn_check($nums) {
        $result = FALSE;

        // check numns by luhn algorithms
        // lot of code that alter $result

        return $result;
      }

```

---
Tags: 7, forms, javascript, ajax
---


# Question
Title: how to specify the file directory in drush config:status
drush config:import has the --source flag to specify where the import should come from. drush config:export has the --destination flag to specify where the import should go.

I am trying to automate a system for determining if update hooks have modified configuration, to avoid the problem documented in #3110362 If an update hook modifies configuration, then old configuration is imported, the changes made by the update hook are forever lost.

To do so I will export the config to a temporary directory, like:

```
drush config:export --destination=/tmp/check-issue-3110362

```

Then I will run the updates

```
drush updb -y

```

Then I want to run a diff between the database config and the config in /tmp/check-issue-3110362, but the following does not work:

```
drush config:status --source=/tmp/check-issue-3110362
# The "--source" option does not exist.
drush config:status --destination=/tmp/check-issue-3110362
# The "--destination" option does not exist.

```

How can I tell drush config:status to use a specific directory to check against the database?

My version of Drush is 10.3.6

# Answer
> 2 votes
You can use the `config:export` command with the `--no` parameter to prevent the actual export.

```
drush config:export --destination=/tmp/check-issue-3110362 --diff --no

```

The return value `$?` of Drush will tell you if there are differences between the database and the directory containing YAML files:

* 0 means no differences
* 1 means differences

Therefore, you can combine this into an `if` statement:

```
if ! drush config:export --destination=/tmp/check-issue-3110362 --no; then
  # Act on the change here.
  echo "Something in the config was changed."
fi

```

# Answer
> 1 votes
There's no option to do this with `drush config:status`. See the drush 10 documentation for config:status.

Presumably, you want to check if the config has changed so you can export it to your sync directories. Why not export it to them directly? If there are no changes, there will be no changes. But if there are changes, you'll see them in your repository, e.g. with `git status`.

I've always used Moshe's recommendation from comment #7 in your linked issue:

> You *must* get your configuration right before you run a config import. Specifically, the config in the import must represent the values AFTER hook\_updated\_n runs. The developer workflow I advocate is to run the hook\_update\_n() locally, run drush config:export, and and then commit the results. Only then is the saved config ready to be imported.

I.e., start with a site in a clean state in your local environment:

1. Update your project(s) with composer.
2. Run `drush updb` to perform the db updates
3. Run `drush cex` to export any config changes made during those updates
4. Add any changes to your repo, commit, and push.
5. Pull the changes on your new environment
6. Run `drush deploy`

---
Tags: drush
---


# Question
Title: Check if the user is logged-in in a theme
In Drupal 7 we can simply check if the current user is logged-in in a theme by checking `$GLOBAL['user']->uid` or using `user_is_logged_in()`.

How can I check if a user is logged-in in a page template, in Drupal 8?

A solution is to manually check in `hook_preprocess_page()`, but since this is very popular, I think Drupal provides something by default for the Twig theme engine.

# Answer
> 37 votes
If you just need to verify the current user is logged-in, you can use `$variables['logged_in']`, which is generally available in all the template files.

For example, the mark.html.twig file uses the following code, although the only documented variable is `status`.

```
{% if logged_in %}
  {% if status is constant('MARK_NEW') %}
    <span class="marker">{{ 'New'|t }}</span>
  {% elseif status is constant('MARK_UPDATED') %}
    <span class="marker">{{ 'Updated'|t }}</span>
  {% endif %}
{% endif %}

```

The variable is explicitly documented in other template files, such as html.html.twig, page.html.twig, and node.html.twig.

The variable is available in all the template files, since it is initialized in `_template_preprocess_default_variables()` that invokes `user_template_preprocess_default_variables_alter()` (an implementation of `hook_template_preprocess_default_variables_alter()`), which contains the following code.

```
  $user = \Drupal::currentUser();

  $variables['user'] = clone $user;
  // Remove password and session IDs, since themes should not need nor see them.
  unset($variables['user']->pass, $variables['user']->sid, $variables['user']->ssid);

  $variables['is_admin'] = $user->hasPermission('access administration pages');
  $variables['logged_in'] = $user->isAuthenticated();

```

`_template_preprocess_default_variables()` is called by `template_preprocess()`, which is the function called for theme hooks implemented as templates; this guarantees the variable is available in all the template files.

Keep in mind that macros don't have access to the current template variables, so trying to access `logged_in` in the code of a macro would not have any effect.
Between the template files used from Drupal core modules, the ones using a macro are:

* menu.html.twig

```
  {% macro menu_links(items, attributes, menu_level) %}
    {% import _self as menus %}
    {% if items %}
      {% if menu_level == 0 %}
        <ul{{ attributes }}>
      {% else %}
        <ul>
      {% endif %}
      {% for item in items %}
        <li{{ item.attributes }}>
          {{ link(item.title, item.url) }}
          {% if item.below %}
            {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
          {% endif %}
        </li>
      {% endfor %}
      </ul>
    {% endif %}
  {% endmacro %}

```
* book-tree.html.twig

```
  {% macro book_links(items, attributes, menu_level) %}
    {% import _self as book_tree %}
    {% if items %}
      {% if menu_level == 0 %}
        <ul{{ attributes }}>
      {% else %}
        <ul>
      {% endif %}
      {% for item in items %}
        <li{{ item.attributes }}>
          {{ link(item.title, item.url) }}
          {% if item.below %}
            {{ book_tree.book_links(item.below, attributes, menu_level + 1) }}
          {% endif %}
        </li>
      {% endfor %}
      </ul>
    {% endif %}
  {% endmacro %}

```
* menu--toolbar.html.twig

```
  {% macro menu_links(items, attributes, menu_level) %}
    {% import _self as menus %}
    {% if items %}
      {% if menu_level == 0 %}
        <ul{{ attributes.addClass('toolbar-menu') }}>
      {% else %}
        <ul class="toolbar-menu">
      {% endif %}
      {% for item in items %}
        {%
          set classes = [
            'menu-item',
            item.is_expanded ? 'menu-item--expanded',
            item.is_collapsed ? 'menu-item--collapsed',
            item.in_active_trail ? 'menu-item--active-trail',
          ]
        %}
        <li{{ item.attributes.addClass(classes) }}>
          {{ link(item.title, item.url) }}
          {% if item.below %}
            {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
          {% endif %}
        </li>
      {% endfor %}
      </ul>
    {% endif %}
  {% endmacro %}

```

For example, changing the last macro with the following code would not have the expected result.

```
{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
      <ul{{ attributes.addClass('toolbar-menu') }}>
    {% else %}
      <ul class="toolbar-menu">
    {% endif %}
    {% for item in items %}
      {%
        set classes = [
          'menu-item',
          logged_in ? 'menu-item--logged-in-user',
          item.is_expanded ? 'menu-item--expanded',
          item.is_collapsed ? 'menu-item--collapsed',
          item.in_active_trail ? 'menu-item--active-trail',
        ]
      %}
      <li{{ item.attributes.addClass(classes) }}>
        {{ link(item.title, item.url) }}
        {% if item.below %}
          {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
        {% endif %}
      </li>
    {% endfor %}
    </ul>
  {% endif %}
{% endmacro %}

```

# Answer
> 5 votes
You can with the Twig Extender module. Quote from its project page:

> Add a simple plugin system to add new twig extensions (Filter and Functions). Provides a new service provider for "twig.extensions" to add new plugins.
>
> **Function: is\_user\_logged\_in**
>
> Check if user is logged in.
>
> ```
> {% if user_is_logged_in() %}
> Hello user
> {% else %}
> Please login
> {% endif %}
>
> ```

# Answer
> 2 votes
For everybody trying to use `logged_in` from menu.twig.html; you need to call it from outside the `menus.menu_links()` macro as the `logged_in` variable is out of scope within the macro.

# Answer
> 1 votes
You can check if the user is authenticated like so:

For example, I have created the following function in themename.theme.

```
# Function to get user logged info
function tropical_preprocess_page(&$variables){
  // if user is authenticated
  if($variables['user']->isAuthenticated()){
    # gets username
  $user_logged_in_name = $variables['user']->getDisplayName();
  # creates value to ouput in the DOM & capitalize first letter
  $variables['user_logged_in_name'] = ucfirst($user_logged_in_name);

  # gets user email
  $user_email = $variables['user']->getEmail();
  $variables['user_email'] = $user_email;

  // get user picture
  $user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
  $variables['user_picture'] = $user->get('user_picture')->entity->url();

  // Check if user is logged in
  $user_logged = $variables['user']->isAuthenticated();
  $variables['user_logged'] = $user_logged;
  }
}

```

After that, you can create the logic within the Twig file like so:

```
<div class="user-logged-greeting">
  {% if user_logged %}
    <h2>Welcome back, {{ user_logged_in_name }}!</h2>
    <p>The email for this user is: <strong>{{ user_email }}<strong></p>
    <img src="{{ user_picture }}" width="50" height="50">
  {% endif %}
</div>

```

If the user is logged in, you will get the greeting message along with username, email & avatar picture. If user is not logged in, it won't show up anything.

Let me know if that helps and/or if I can edit this post for better understanding.

# Answer
> 0 votes
The issue isn't that the variable doesn't exist in the template file, but rather that it isn't available in the macro. You can fix this via passing it through:

{% macro menu\_links(items, attributes, menu\_level, logged\_in) %}

Then if you have a signin menu item, something like:

{% if item.title == 'Sign In' %} {% if not logged\_in %} Go to login {% endif %} {% endif %}

# Answer
> 0 votes
I moved my login-sensitive button "Login" outside the menu macro. So the twig variable `logged_in` which is not in scope inside the macro could be used again.

Before moving the login-sensitive button (which did not work):

```
{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
<ul{{ attributes.addClass('menu') }}>
  {% else %}
  <ul class="menu">
    {% endif %}
    {% for item in items %}
...
    {% endfor %}

    {% if logged_in %}
    <li class="menu-item register">
      <a href="/user" data-drupal-link-system-path="<front>" class="btn btn-light">{{ 'My user account'|t }}</a>
    </li>
    {% else %}
    <li class="menu-item register">
      <a href="/user/login" data-drupal-link-system-path="<front>" class="btn btn-light">{{ 'Login'|t }}</a>
    </li>
    {% endif %}
  </ul>

  {% endif %}
  {% endmacro %}

```

After moving the login-sensitive button (works for me):

```
{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
<ul{{ attributes.addClass('menu') }}>
  {% else %}
  <ul class="menu">
    {% endif %}
    {% for item in items %}
...
    {% endfor %}
  {% endif %}
{% endmacro %}

{% if logged_in %}
  <li class="menu-item register">
    <a href="/user" data-drupal-link-system-path="<front>" class="btn btn-light">{{ 'My user account'|t }}</a>
  </li>
{% else %}
  <li class="menu-item register">
    <a href="/user/login" data-drupal-link-system-path="<front>" class="btn btn-light">{{ 'Login'|t }}</a>
  </li>
{% endif %}
</ul>

```

---
Tags: theming, 8
---


# Question
Title: error 500: Premature end of script headers: index.php
Everything works except the /node/\[nr\]/edit page of only one content type page. And it's not for every page of this specific content type. Only one.

So let's say I have a content type "product" and created 5 nodes with that content type. Editing 4 of them works but for one the error 500 `Premature end of script headers: index.php` occurs.

I tried increasing the memory limit in the php.ini all the way up to `memory_limit = 1024M` (and restarted apache after that) but this changes nothing. Btw I'm using Acquia DevDesktop and the PHP version is 7.0.15. I also tried downgrading the PHP version (and there also increased the memory limit) but this won't do anything either.

Please help me, I'm incredibly thankful for every answer I can get!

# Answer
This is not "solve it all" answer, but it may help those who use Acquia. The problem went away after switching from Fast CGI (mod\_fcgid) to Apache module (mod\_php) in Acquia DevDesktop-\>Preferences-\>Config.

Just some env notes for future debugging:
Acquia DevDesktop 2 rev:39801a8
PHP version 7.2.9
> 5 votes

# Answer
@mcaleaa answer helped me on an acquia based site. To fix it I commented out the following lines in development.services.yml.

```
parameters:
  http.response.debug_cacheability_headers: true

```
> 32 votes

# Answer
In case this helps anyone: I encountered this error on my local site's front page, just after following the instructions here https://www.drupal.org/node/2598914 (Disable Drupal 8 caching during development)

When I once again *commented out* this line in my settings.local.php, the 500 error went away:

```
# $settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';

```

I suspect that my site's front page is heavily dependent on the cache entries, and when I switch to the null cache, the page is simply having trouble getting built. That's my guess.

**UPDATE 2022-02-16** There is a issue on drupal.org dealing with this problem: https://www.drupal.org/node/2844620

We have been using the patch from that issue for a couple of years now, to deal with this error message during local development:

```
Premature end of script headers: index.php

```
> 8 votes

# Answer
I am using drupalVm and was able to make the switch to using nginx. This was helpful for us cause our site is hosted by pantheon which uses nginx. You'll need these values set in your extra parameters: `fastcgi_buffers` and `fastcgi_buffer_size`. My config.yml looks like this:

```
drupalvm_webserver: nginx
...
nginx_hosts:
  - server_name: "{{ drupal_domain }} www.{{ drupal_domain }}"
  ...
  extra_parameters: |
    ...
    fastcgi_buffers 16 16k;
    fastcgi_buffer_size 32k;

```
> 0 votes

# Answer
In my case, SVG files in my blocks are causing the error. The error went away after replacing them.
> 0 votes

---
Tags: 8, http-request
---


# Question
Title: Entity query on custom entity is not checking access rights
I have a custom entity called project\_member. Not all user have access to this entity. But when I query this entity with entityQuery as follows `\Drupal::entityQuery('project_member')->execute()` all the entities are returning. It is not checking the access rights. I am missing anything. I tried to implement hook\_project\_member\_access() to restrict the access still entityQuery is not checking those access results.

# Answer
> 1 votes
You will need to implement `hook_query_ENTITY_TYPE_access_alter` ( `hook_query_project_member_access_alter`) to apply the custom query access check.

For example https://api.drupal.org/api/drupal/core%21modules%21node%21node.module/function/node\_query\_node\_access\_alter/8.9.x

You might need to `$query->addTag(‘project_member_access’)` but from memory that tag may now be added automatically by the entity query handler.

# Answer
> 0 votes
If I'm not mistaken, entity queries will respect access if you've got the appropriate access tag on the query, which you may or may not be defining. I haven't dug much into how to implement this as custom entities, but the node module defines the `node_access` query tag that's automatically applied to all node entity queries (I believe), so that would be a good place to start looking.

https://api.drupal.org/api/drupal/core%21modules%21node%21node.module/group/node\_access/8.9.x

---
Tags: 8, entities
---


# Question
Title: How can I limit the maximum weight of an order?
Is there a way in drupal commerce 2 to prevent adding a product to the cart, if the order weight exceeds a certain amount, let's say 40kg?

We are also using the commerce\_cart\_api plugin, in case this provides some hooks to prevent an add?

# Answer
Alright, I'm definetly not sure, if this is the intended way of doing things, but I did it now this way via a custom cart event subscriber:

`modules/custom/my_checkout/my_checkout.services.yml`:

```
services:
  my_checkout.cart_subscriber:
    class: Drupal\my_checkout\EventSubscriber\CartEventSubscriber
    arguments: ['@messenger', '@commerce_cart.cart_manager', '@string_translation']
    tags:
      - { name: event_subscriber }

```

`modules/custom/my_checkout/src/EventSubscriber/CartEventSubscriber.php`:

```
<?php

namespace Drupal\my_checkout\EventSubscriber;

use Drupal\commerce_cart\CartManagerInterface;
use Drupal\commerce_cart\Event\CartEntityAddEvent;
use Drupal\commerce_cart\Event\CartEvents;
use Drupal\commerce_cart\Event\CartOrderItemRemoveEvent;
use Drupal\commerce_cart\Event\CartOrderItemUpdateEvent;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\TypedData\Exception\MissingDataException;
use Drupal\physical\Calculator;
use Drupal\physical\Weight;
use Drupal\physical\WeightUnit;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class CartEventSubscriber implements EventSubscriberInterface {

  use StringTranslationTrait;

  /**
   * The messenger.
   *
   * @var MessengerInterface
   */
  protected $messenger;

  /**
   * The cart manager.
   *
   * @var CartManagerInterface
   */
  protected $cartManager;

  /**
   * Constructs event subscriber.
   *
   * @param MessengerInterface $messenger
   *   The messenger.
   */
  public function __construct(MessengerInterface $messenger, CartManagerInterface $cart_manager, TranslationInterface $string_translation) {
    $this->messenger = $messenger;
    $this->cartManager = $cart_manager;
    $this->stringTranslation = $string_translation;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      CartEvents::CART_ENTITY_ADD => [['guardWeight', 100]],
      CartEvents::CART_ORDER_ITEM_UPDATE => [['guardWeight', 100]],
      CartEvents::CART_ORDER_ITEM_REMOVE => [['guardWeight', 100]]
    ];
  }

  /**
   * @param CartEntityAddEvent|CartOrderItemUpdateEvent|CartOrderItemRemoveEvent $event
   * @throws MissingDataException
   */
  public function guardWeight($event) {
    $cart = $event->getCart();

    // @todo - this should be configurable
    $maximumWeight = new Weight(40, WeightUnit::KILOGRAM);
    $orderWeight = new Weight(0, WeightUnit::KILOGRAM);

    foreach ($cart->getItems() as $order_item) {

      $purchased_entity = $order_item->getPurchasedEntity();
      // Calculate only items with a weight
      if (!$purchased_entity || !$purchased_entity->hasField('weight')) {
        continue;
      }

      $quantity = $order_item->getQuantity();
      if (Calculator::compare($order_item->getQuantity(), '0') == 0) {
        continue;
      }

      /** @var Weight $weight */
      $weight = $purchased_entity->get('weight')->first()->toMeasurement();

      $orderWeight = $orderWeight->add($weight->multiply($quantity));
    }

    if (!$orderWeight->lessThanOrEqual($maximumWeight)) {

      switch (get_class($event)) {
        case CartOrderItemUpdateEvent::class:
          $orderItem = $event->getOrderItem();
          $originalQuantity = $event->getOriginalOrderItem()->getQuantity();
          if (intval($orderItem->getQuantity()) > intval($originalQuantity)) {
            $orderItem->setQuantity($originalQuantity);
            $orderItem->save();
          }

          break;
        case CartEntityAddEvent::class:
          $orderItem = $event->getOrderItem();
          $cart->removeItem($orderItem);
          $orderItem->delete();
          break;
      }

      $this->messenger->addError($this->t('You would exceed the maximum order weight of @maxWeight, we could not update your cart.', [
        '@maxWeight' => implode('', $maximumWeight->toArray())
      ]));
    }
  }

}

```

It works well, but the "Your cart was updated" message is unfortunately still there. My guess is, it is still not the best location for this kind of logic.
> 0 votes

---
Tags: 8, commerce
---


# Question
Title: How to allow user to manually change language when using "Browser" Detection as a detection option?
We have a site with multiple languages and have been using the Language Switch Dropdown menu to allow users to change languages on the site. But when we add "Browser | Language from the browser's language settings." as an additional detection option along with "Selected Language" then the selected language no longer works as it is always overridden by the browser's language, even if "Selected Language" is placed before it.

The ideal workflow would be:

1. Language is detected from the browser and translated
2. The Language Dropdown shows the current language (currently it always displays the default language, even if the browser detects and switches to a different language)
3. The user can then override the browser language by selecting a different language from the drop-down switcher. (Currently the dropdown has no effect if a language is detected via the browser)

SOLUTION EDIT:

The proposed solution did not work for us so we ended up writing a custom form alter function and using a one-time cookie to achieve the functionality we were looking for.

In the language detection, we have "selected language" enable as the first item then "URL" and the second item and no other detections are used.

Then we used the below hook to the detect and set the language from the browser one-time using a cookie. The hook also sets the default value of the language dropdown so it shows what the language is, even if set from the browser.

```
<?php

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

    // Only run if our custom language cookie is not set yet
    if (!isset($_COOKIE['Drupal_visitor_user_lang'])){

      // Get language set in browser
      $language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
      user_cookie_save(['user_lang' => $language]);

      // Set the language dropdown's default value
      $form['lang_dropdown_select']['#default_value'] = $language;

      $current_path = \Drupal::service('path.current')->getPath();
      $path = \Drupal::service('path.alias_manager')->getAliasByPath($current_path);
      $config = \Drupal::config('system.site');
      $front_uri = $config->get('page.front');
      $front_alias = \Drupal::service('path.alias_manager')->getAliasByPath($front_uri);

      if ($path == $front_alias){
        $path = '';
      }
      $default_language = \Drupal::languageManager()->getDefaultLanguage()->getId();
      if ($language == $default_language){
        $language = '';
      }
      $response = new RedirectResponse('/' . $language . $path);
      $response->send();

    }
    $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
    $form['lang_dropdown_select']['#default_value'] = $language;
}

```

# Answer
The `Selected language` option comes with this description:

> Changing the selected language here (and leaving this option as the last among the detection and selection options) is the easiest way to change the fallback language for the website, if you need to change how your site works by default (e.g., when using an empty path prefix or using the default domain). Changing the site's default language itself might have other undesired side effects.

This option is meant to be the last on the list and used only as a fallback.

If you give Browser option advantage on the list by placing it above the URL option the language will always be chosen by the browser criteria.

I'm guessing that there are cases where browser language might be not available in which case the URL option will kick in, but in most cases the URL option will not be used because Browser option will set the language and no options that come after it will even be evaluated.

It seems you need the **Session** option before the `Browser` option. This option should work with the Language switcher to add the parameter in the URL that will set the chosen language, but before the user selects something from the dropdown the Browser option will set the language.

Turn the URL option off completely if you don't need the language prefix to avoid confusion when the parameter is present. Having too many options turned on complicates the system unnecessarily and makes it more difficult to figure out what the causes are if there are bugs present.

I haven't tested this configuration. Language configuration can be tricky and you may need to do more adjustments and testing to get to where you want to be.
> 3 votes

---
Tags: i18n-l10n
---


# Question
Title: How to pass current selection to entity browser select view
I am using an Entity Browser (2.x-dev in Drupal 8) as form widget for a custom entity's entity reference base field. The entity browser is configured

* as a modal display,
* with single widget,
* and no selection display,
* using a view with entity browser bulk select field as widget, and
* to append chosen entities to the current selection of the reference field.

Selecting the entities is working fine. But the entity reference field shall not have any duplicates.

In order to ease selecting of entities without duplicates, I'd like to filter already chosen entities from the entity browser view results. So users will see unselected entities only.

For this purpose, I created a custom views argument\_default plugin that exposes the entity browser selection storage as context default argument for the entity ID:

```
<?php

namespace Drupal\my_module\Plugin\views\argument_default;

use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * The entity browser selection argument default handler.
 *
 * @ViewsArgumentDefault(
 *   id = "entity_browser_selection",
 *   title = @Translation("Entity Browser Selection")
 * )
 */
class EntityBrowserSelection extends ArgumentDefaultPluginBase {

  /**
   * The selection storage.
   *
   * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
   */
  protected $selectionStorage;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, KeyValueStoreExpirableInterface $selection_storage) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->selectionStorage = $selection_storage;
  }

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

  /**
   * {@inheritdoc}
   */
  public function access() {
    return $this->view->getDisplay()->pluginId === 'entity_browser';
  }

  /**
   * {@inheritdoc}
   */
  public function getArgument() {
    $argument = NULL;
    $current_request = $this->view->getRequest();

    // Check if the widget context is available.
    if ($current_request->query->has('uuid')) {
      $uuid = $current_request->query->get('uuid');
      if ($storage = $this->selectionStorage->get($uuid)) {
        if (!empty($storage['selected_entities'])) {
          $argument = $storage['selected_entities'];
        }
      }
    }
    return $argument;
  }

}

```

The issue I face, is that the current selection within the selection storage is always empty, no matter how many entities have been selected at the entity reference field, and even after I complete the modal selection and open the entity browser again.

What do I have to do to have the current selection exposed in the entity browser's selection storage?

# Answer
The Entity Browser doesn't current pass current default value items field in persistent data, but it's easy to add it.

1) Add persistent data using field\_widget\_form\_alter()

```
/**
 * Implements hook_field_widget_form_alter().
 */
function mymodule_field_widget_form_alter(&$element, FormStateInterface &$form_state, $context) {
  if (!empty($element['entity_browser'])) {
    $default_value =  $element['entity_browser']['#default_value'];
    $ids = [];
    foreach ($default_value as $entity) {
      $ids[] = $entity->id();
    }
    $element['entity_browser']['#widget_context']['current_ids'] = implode('+', $ids);
  }
}

```

2) Update your selection so that if blank it shows all:

```
  /**
   * {@inheritdoc}
   */
  public function getArgument() {
    $argument = NULL;
    $current_request = $this->view->getRequest();

    // Check if the widget context is available.
    if ($current_request->query->has('uuid')) {
      $uuid = $current_request->query->get('uuid');
      if ($storage = $this->selectionStorage->get($uuid)) {
        if (!empty($storage['widget_context']['current_ids'])) {
          $argument = $storage['widget_context']['current_ids'];
        }
        else {
          $argument = 'all';
        }
      }
    }
    return $argument;
  }

```

3) Make sure you have "exclude" and "allow multiple" checked on your selection.

By the way, if you update to the latest dev release of entity\_browser, you don't need your custom plugin. There is a new entity\_browser\_widget\_context default value views plugin that is configurable.

I also added an issue to the entity\_browser queue to add this information when in the widget\_context.
> 8 votes

# Answer
I used your default argument class and debugged a little. This is my approach:

The entity browser widget stores selected values in its `current` property, which is filled, when the entity form is opened with an existing entity/selection. The widget also uses AJAX when the modal closes and the `current` property is updated accordingly.

So you can get the selected entity IDs using something like the following in your entity form/form alter:

```
use Drupal\Core\Render\Element;

// Current selection. Replace 'field_references' with the actual
// name of your field.
$selection = [];
if (isset($form['field_references']['widget']['current'])) {
  $current = $form['time_records']['widget']['current'];
  foreach (Element::children($current) as $key) {
    if (isset($current[$key]['target_id']['#value'])) {
      $selection[] = $current[$key]['target_id']['#value'];
    }
  }
}

```

Another widget property available in the form is the widget context of the used entity browser. You can simply add the current selection to the widget context and use this information with your views default argument (the widget context is updated in the selection storage on each AJAX reload of the widget/form):

```
$form['field_references']['widget']['entity_browser']['#widget_context']['current_selection'] = $selection;

```

Then alter your `EntityBrowserSelection::getArgument()`:

```
  /**
   * {@inheritdoc}
   */
  public function getArgument() {
    $argument = NULL;
    $current_request = $this->view->getRequest();

    // Check if the widget context is available.
    if ($current_request->query->has('uuid')) {
      $uuid = $current_request->query->get('uuid');
      if ($storage = $this->selectionStorage->get($uuid)) {
        if (!empty($storage['widget_context']['current_selection'])) {
          $selection = $storage['widget_context']['current_selection'];
          if (is_string($selection)) {
            $argument = $selection;
          }
          elseif (is_array($selection)) {
            $non_scalar = array_filter($selection, function ($item) {
              return !is_scalar($item);
            });
            if (empty($non_scalar)) {
              // Replace the ',' with '+', if you like to have an
              // OR filter rather than an AND filter.
              $argument = implode(',', $selection);
            }
          }
        }
      }
    }
    return $argument;
  }

```

With these changes I was able to filter selected items from my view with a contextual filter for the entity IDs, choosing

* When the filter is not available: Provide a default value, Type "Entity Browser Selection"
* More: Exclude

Hope it helps!
> 2 votes

# Answer
I could not get the default filter to work but I did have some success doing the following scary-ness:

```
function mymodule_views_pre_render(\Drupal\views\ViewExecutable $view) {
  if ($view->id() == "media_entity_browser" && $view->current_display ==
    'entity_browser_1') {
    $request = \Drupal::request();
    $prams = $request->query->all();
    $is_edit = FALSE;
    if (!empty($prams['original_path'])) {
      // testing with "/node/1/edit"
      $check_explode = explode('/', $prams['original_path']);
      if (in_array('edit', $check_explode)) {
        $edit_key = array_search ( 'edit', $check_explode);
        $entity_id_key = $edit_key - 1;
        $entity_id = $check_explode[$entity_id_key];
        $entity_type_key = $edit_key - 2;
        $entity_type = $check_explode[$entity_type_key];
        $selected_ids = [];
        try {
          $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
          // This sucks bacause field name is hardcoded.
          $media_entities = $entity->field_image->referencedEntities();
          if (!empty($media_entities)) {
            foreach ($media_entities as $media_entity) {
              $selected_ids[] = (int) $media_entity->id();
            }
          }
        }
        catch (\Exception $e) {
          // log this.
        }

        $my_results = [];
        // Now need to remove from view.
        if (!empty($selected_ids)) {
          $i = 0;
          foreach ($view->result as $key =>  $item) {
            $id = (int) $item->_entity->id();
            if (!in_array($id, $selected_ids)) {
              $my_results[] = new ResultRow([
                '_entity' => $item->_entity,
                'index' => $i,
                'mid' => $item->_entity->id(),
              ]);
              $i++;
            }
          }
          $view->result = $my_results;
        }
      }
    }
  }
}

```

This does work. However, there are quite a few assumptions made... Good thing entity browser allows you to select which view.
> 0 votes

# Answer
Adding to oknate's solution, hook\_field\_widget\_form\_alter won't work if the entity browser is being used as part of an inline entity forms complex widget. Instead, you can populate the widget\_context as follows (and then grab the widget context in a contextual filter as described by oknate):

```
function mymodule_inline_entity_form_reference_form_alter(&$reference_form, FormStateInterface &$form_state) {
  if ($reference_form['entity_browser']) {
    $entity_array = $form_state->get([
      'inline_entity_form',
      $reference_form['#ief_id'],
      'entities',
    ]);
    $ids = array_map(function($entity_wrapper) {
      return $entity_wrapper['entity']->id();
    }, $entity_array);
    $reference_form['entity_browser']['#widget_context']['current_ids'] = implode('+', $ids);
  }
}

```

Note: this MUST run after entity browser's implementation of the same hook so that the widget\_context is already added. It may be necessary to implement hook\_module\_implements\_alter to ensure that your hook is called last:

```
function mymodule_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'inline_entity_form_reference_form_alter') {
    $group = $implementations['mymodule'];
    unset($implementations['mymodule']);
    $implementations['mymodule'] = $group;
  }
}

```
> 0 votes

---
Tags: 8
---


# Question
Title: Node hits getting cached for anonymous user
We are using Drupal 8.8.5. For every page we are trying to provide a counter which increments whenever user hits that node. These are nodes are available to anonymous users. So whenever an anonymous user hits the node, the view counter on that node should be updated to show the no of total hits . So lets say Tom and Hary are anonymous users. Tom hits node1. On top of Node1 it says "View 1" times. Now when Hary hits Node1 it should sat "View 2" times. Again if Tom hits node1 it should day "View 3" times. I checked How can I show node Hits (statistics)? and made the necessary code changes in basic.theme and node.html.twig. Still, it shows *Viewed O times*.

This is the code I have in the *basic.theme* file.

```
function basic_preprocess_node(&$variables) {
  $variables['node_view_count'] = 0;
  if (!empty($variables['node'])) {
    // Get the number of times the current node has been viewed.
    /** @var \Drupal\statistics\StatisticsViewsResult $statistics */
    $statistics = \Drupal::service('statistics.storage.node')
      ->fetchView($variables['node']->id());
    if ($statistics instanceof StatisticsViewsResult) {
      $variables['node_view_count'] = $statistics->getTotalCount();
    }
  }
}

```

This is the code I added in the *node.html.twig* file.

```
Viewed {{ node_view_count }} times

```

I believe there might be a caching issue once it starts working. For each hit, the values should be updated.

On a side note, when I am using the Visitors module, the report is showing an updated page count even for anonymous users. I had to install the Advanced Page Expiration module, though.

How do I increment the node hit for anonymous user visits in each page and show it updated?

# Answer
Ok i have resolved this using a database query and a custom block. Pre-req: Installing visitors module. Then having this query in the custom clock

```
public function build() {
  $node = \Drupal::request()->attributes->get('node');
  $uidValue = $node->getOwnerId();
  $urlValue = $node->toUrl()->toString();
  $database = \Drupal::database();
  **$query = $database->query("SELECT COUNT(visitors_path) AS visitors_path FROM
(visitors) WHERE visitors_path='$urlValue' ");**
  $result = $query->fetchAll();
  $nodecounthit = $result{0}->visitors_path;
  echo "Viewed ".$nodecounthit." times";
//$nodeCount=MyBlock::test();
      }

```

this function ensured results were not cached.

```
 public function getCacheMaxAge()
  {
    return 0;
  }

```
> 0 votes

---
Tags: 8, nodes
---


# Question
Title: Undefined function 'entity_metadata_wrapper'
A custom module is using the following code.

```
function sun_blogs_views_pre_render(&$view) {
        //......
        $wrapper = entity_metadata_wrapper('node', $node);
        $title = $wrapper->field_job_title->value();
        if (strlen($title)) {
          $view->description .= ' - '  . $title;
        }
      }
      Drupal::service('views.breadcrumb')->setBreadcrumb($breadcrumbs);
    }
  }
}

```

It causes the following error.

> Undefined function 'entity\_metadata\_wrapper'.

How can I fix this error?

# Answer
`entity_metadata_wrapper()` is a function implemented by the Drupal 7 version of the Entity API module. Since it returns a class wrapping the `stdClass` instance used from Drupal core for entities objects, and since Drupal 8 doesn't use `stdClass` objects for entities, that function isn't anymore necessary.

In Drupal 8, and Drupal 9, you access that field with `$node->field_job_title->value` or `$node->get('field_job_title')->getValue()`.
> 1 votes

---
Tags: entities, 9
---


title: How to render a field collection?

text:
# Question
Title: How to render a field collection?
How can I properly render a field collection ? Is there any specific function for that ? I tried `field_view_field` but it does not output *children fields*.

My field collection is attached to a *line item entity*, and I want to display it in a *Commerce checkout pane review*.

```
function mymodule_pane_review($form, $form_state, $checkout_pane, $order) {
  //loading line item
  $line_item = commerce_line_item_load($order->commerce_line_items['und'][0]['line_item_id']);
  //loading field_collection from its id
  $paxsup = entity_load('field_collection_item', array($line_item->field_paxsup['und'][0]['value']));

  return drupal_render(field_attach_view('field_collection_item',$paxsup, 'full'));
}

```

but get an error *EntityMalformedException: Missing bundle property on entity of type field\_collection\_item*

**EDIT :** I got a step forward, with the use either of

```
$paxsups = entity_load('field_collection_item', array($line_item->field_paxsup['und'][0]['value']));
$paxsup = end($paxsups);
//or shortcut, as per Marcvangend
$paxsup = field_collection_field_get_entity($line_item->field_paxsup['und'][0]);

```

`dsm($paxsup)` now returns

So I can output a child field with

```
$view = field_view_field('field_collection_item', $paxsup, 'field_paxsup_civilite', $display);
return drupal_render($view);

```

**EDIT 2:** I ended chaining #markup

```
$display = array('label' => 'hidden');
$cv = field_view_field('field_collection_item', $paxsup, 'field_paxsup_civilite', $display);
$nom = field_view_field('field_collection_item', $paxsup, 'field_paxsup_nom', $display);
$prenom = field_view_field('field_collection_item', $paxsup, 'field_paxsup_prenom', $display);
$date = field_view_field('field_collection_item', $paxsup, 'field_paxsup_datenaiss', $display);
$view .= $cv[0]['#markup'] .' '. $nom[0]['#markup'] .' '. $prenom[0]['#markup'] .t(', né(e) le '). $date[0]['#markup'] ;

```

But I'm not happy with this "old style" solution, would have preferred to find a more elegant and Drupal way to output that field collection

# Answer
> 2 votes
You may want to have a look how the field\_collection module itself renders field collections in the field\_collection\_field\_formatter\_view function. I think it's important to note that is uses field\_collection\_field\_get\_entity() to load a field collection.

Looking at the code (not tested) I think you can do something like this:

```
if ($field_collection = field_collection_field_get_entity($line_item->field_paxsup['und'][0])) {
  return $field_collection->view('full');
}

```

# Answer
> 0 votes
Just to expand on the above answer if you put the below into a node preprocess it should work

```
function MODULETHEME_preprocess_node(&$variables) {
  // ...
  foreach ($variables['field_conference_day'] as $day) {
    if ($field_collection = field_collection_field_get_entity($day)) {
      $conference_days[] = drupal_render($field_collection->view('full'));
    }
  }
  $variables['conference_days'] = $conference_days;
  // ...
}

```

You can then render `$conference_days` in your theme node template file.

Note that `field_collection_field_get_entity` wants a field item. Always good to check the source code.

---
Tags: entities, theming, commerce
---


# Question
Title: Manually update core from 7.0 to 7.78 in one fell swoop
I have recently become an admin for a site that has not been updated since 2011. there are broken links (internal links to the site's blog go to page not found, index error.) I think this is due to a bug, so I want to update the software. However this would be a manual update of Drupal Core and I'm wary of doing anything that might mess up the site's code, not being a coder myself.

Should I go somewhere in the middle of the 7.x updates, or should I go straight to the latest one? What issues may arise from my site from updating to the most recent available?

# Answer
> 1 votes
The latest update contains all of the updates before so going straight to the latest one should be okay and is what is usually recommended. Be sure to backup your site and test the backup on a dev copy.

You should update your contributed modules at the same time as some of them may rely on updated versions of Drupal (core).

Lastly and very importantly, there have been numerous security releases since the 1st release and some of them are quite bad so I would say you should probably assume your site is compromised. That's 78(!) releases you've missed out on, including the infamous *Drupalgeddon*.

---
Tags: 7
---


# Question
Title: Calling a Method from another Module's Class
I'm dumb and this is embarrassing, but I'm trying to figure out how I properly use a method from a class in other parts of my code. I need to understand the Drupal way, if not just the php way.

I have a class like this...

```
namespace Drupal\module_name\Utilities;

use GuzzleHttp\Exception\RequestException;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\Core\Messenger\MessengerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use GuzzleHttp\ClientInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;

class Example implements ContainerInjectionInterface {

  private $client;
  protected $loggerFactory;
  protected $messenger;
  protected $config;

  public function __construct(
    LoggerChannelFactory $loggerFactory,
    MessengerInterface $messenger,
    ClientInterface $client,
    ConfigFactoryInterface $config
  ) {
    $this->loggerFactory = $loggerFactory->get('simple_mailchimp');
    $this->messenger = $messenger;
    $this->client = $client;
    $this->config = $config->get('module_name.settings');
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('logger.factory'),
      $container->get('messenger'),
      $container->get('http_client'),
      $container->get('config.factory')
    );
  }

  public function request() {
    return 'whatever';
  }
}

```

What's the proper way to use this class somewhere else? For instance, in another module, I want to call the request() method shown above.

```
  $example = new Example();
  $x = $example->request();

```

This doesn't work, as shown above. I get this...

```
ArgumentCountError: Too few arguments to function Drupal\module_name\Utilities\Example::__construct(), 0 passed... and exactly 4 expected

```

(Even though it seemed to have worked at one time.)

That said, what's the right way to go about this with Drupal, or in general, I guess?

# Answer
> 4 votes
If you want to instantiate a class implementing ContainerInjectionInterface you have to use the Drupal class resolver:

```
$example = \Drupal::classResolver(Example::class);
$x = $example->request();

```

The preferred way though is to use a service class instead and inject other services directly as container arguments, as @Kevin commented.

---
Tags: 8, dependency-injection
---


# Question
Title: How to add custom attributes to description meta tag?
I need to add 'class' and 'data-type' attributes to meta tag containing description attribute. I was able to locate the core Metatag module, however I'm unable to find any documentation on how to customize output without altering the core.

# Answer
> 0 votes
```
function [your-theme]_page_attachments_alter(array &$attachments) {
  $attachments = SwiftypeMetaDescription::add($attachments);
}

 class SwiftypeMetaDescription{
      /**
       * @param array $attachments
       * @return array
       */
      public static function add(array $attachments): array
      {
        // check if $attachments contain html_head
        if (empty($attachments['#attached']['html_head'])) {
          return $attachments;
        }

        // loop through HTML head
        foreach ($attachments['#attached']['html_head'] as $key => $attachment) {
          // check if element name is defined
          if (empty($attachment[1])) {
            // if it's not, skip element
            continue;
          }
          // if the element name equals 'description'
          if ($attachment[1] == 'description') {
            // add 'class' attribute
            $attachments['#attached']['html_head'][$key][0]['#attributes']['class'] = 'swiftype';
            // add 'data-type' attribute
            $attachments['#attached']['html_head'][$key][0]['#attributes']['data-type'] = 'string';
          }
        }

        return $attachments;
      }

    }

```

---
Tags: theming, 9
---


# Question
Title: Create a View Block that shows a taxonomy vocabulary applied to the current node
I have a news section of a Drupal 8 website that contains an ever-growing list of nodes. To avoid a messy menu in the long term, they do not have a menu position assigned but instead are shown via Views, which render News nodes tagged with certain taxonomy terms.

Because they aren't part of the main navigation, the regular Menu Block doesn't work here. Instead, I'm trying to replicate this part of the nav using the taxonomy term structure and exposing that in a View block. The terms IA matches the page IA, down to the News node level.

**How can I expose the taxonomy term used on the Node, plus it's siblings and parent**:

```
- newsroom
  - media release
    - 2019
    - 2020
    - 2021
  - records
  - blog entries

```

So a News node tagged with `records` should show this in the View block:

```
- newsroom
  - media release
  - records
  - blog entries

```

And a News node tagged with `2020` would show:

```
- media release
  - 2019
  - 2020
  - 2021

```

There are plenty of questions about exposing related Nodes to a certain term, but not related Terms on a Node...any help?

# Answer
> 2 votes
It is a common request to show reverse connection information through Views. It can be done with the help of reverse Relationships when starting from Taxonomy term type Views. You can find other answers with simple examples where you can learn about how it works. You are looking to list sibling terms, but commonly siblings are usually called nodes that share the same terms, so be mindful of the difference when reading those answers.

Your case is a bit more complicated because it involves more than one level of connections, and you want both cases to be solved with one Views. I don't know if it can be solved, I suspect it can with the Views Contextual Filters OR module but it still wouldn't be a trivial solution. It's out of scope of an answer here, so I'll just post as much as I can so you can take it to learn and expand on your own time.

This solution will list all three levels of Taxonomy tree for the node that has been tagged with the second level term, and will list third level siblings, (not second level as you'd requested). This requires a lot of tweaking to get it to work the way you want. first independently find the two solutions for each hierarchy level, then combine them with the Contextual OR option.

---

1. Create Views of the type Taxonomy term and Block Display, Filter it to your Vocabulary, and you should have the Taxonomy Name Field there. Set the Pager to `Display all items`. So far it will list all the terms.
2. Add a new Relationship from the Taxonomy term Category for the term Parent. It will be called `Taxonomy term` but you will see its Description explains it's the parent (search for "parent" when on the Relationships list to find it quickly). You can Require it since all your terms will have a parent (no nodes with only the grandparent)
3. Add another Parent Relationship the same way, only make it use the previous Parent Relationship. This second one will introduce the Grandparent term information. Don't require it because some terms will be from the second level and won't have a grandparent so requiring it would exclude them (records)
4. Add the third Relationship but this time the one for your Taxonomy reference field. It will be called something like `Content using field_myTaxonomyField`. Make it use the first Parent Relationship, you can Require it since all the relevant nodes will have that Taxonomy field filled in.
5. Add the Field `Term Parents` and set it to `Exclude from display`. This will show the Parent term for each term but we're hiding it because we'll use it later for grouping. This can probably be done with the term Name Field that has the Parent Reationship applied.
6. Add another `Term Parents` Field but this time make it use the `Parent` Relationship (the first one). This will show the grandparent term if it applies. `Exclude from display` because we'll use it for grouping later so don't need it repeated here.
7. Under `Format` select `HTML list` and set the first grouping to use the Grandparent Field (Parent Field with Parent Relationship), and the second grouping to Parents field (Parent Field without Relationship). You will now see the grandchild terms grouped under their parents and grandparents.
8. Lastly add the Contextual Filter `ID` from the Content Category, this will pass on the node ID to views to filter out only the terms referenced from this node. Configure the Contextual ID Filter:
`When the filter value is NOT available`
**Provide default value**
**Content ID from URL**
`When the filter value IS in the URL or a default is provided`
**Specify validation criteria**
Validator: **Content**
Content type **News**
Set the option for the case when the argument doesn't validate to something that makes sense to you.

With the Contextual Filter present you will see no results unless you enter a node ID into the Preview field. Enter the number of a known node to test it's showing the correct terms and their hierarchy.
9. Lastly save the Views and place the Block into a Region in your theme, and configure the Block Contextual option along with Visibility and other Block settings. Visit a node to test it's showing the hierarchy correctly

If the output doesn't look exactly as you'd like you can play with the Style settings and Override output in the Fields to get closer to what you need. In the end you can control it completely through twig templates. You might also want to look into Views tree.

---
Tags: 8, taxonomy-terms, navigation
---