title: How can I embed PHP code in HTML?

text:
# Question
Title: How can I embed PHP code in HTML?
I want to execute few curl commands from my Drupal site using PHP.

Idea is to create a custom content type that accepts php code. I understood from the internet I have to create a file "node--page.tpl.php" and add the below code in this file.

1. Will this actually work?
2. If yes, at which path should I place node--page.tpl.php file?

Code:

```
<!DOCTYPE html>
<html lang="en">
<head>
    <Relavent Tags/>
    <title>My Page</title>
</head>
<body>
 <h3 style="text-align:center;">Heading</h3>

    <?php
$url = "Service Endpoint";

// Initializing curl
$curl = curl_init();

// Sending GET request to reqres.in
// server to get JSON data
curl_setopt($curl, CURLOPT_URL, $url);

// Telling curl to store JSON
// data in a variable instead
// of dumping on screen
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);

// Executing curl
$response = curl_exec($curl);

// Checking if any error occurs
// during request or not
if($e = curl_error($curl)) {
    echo $e;
} else {

    // Decoding JSON data
    $decodedData = json_decode($response, true);

    // Outputting JSON data in
    // Decoded form

   print_r($decodedData);

}

// Closing curl
curl_close($curl);
?>

</body>
</html>

```

# Answer
In answer to the questions you asked: No this will not work. Drupal 9 uses the Twig templating engine. You cannot execute arbitrary PHP code in Twig. Instead you should write a Drupal module.
> 1 votes

# Answer
As mentioned, the module route is preferred. Pasting PHP code into content type presents a security risk and should be avoided at all costs.
> 0 votes

---
Tags: nodes, 9
---


# Question
Title: Show the Quantity field on the product page but hide it on the catalog page
I created an "ABC Book" product, whose URL is https://example.com/product/1. I added the *Quantity* field from *Administration \> Commerce \> Configuration \> Order item types \> Default \> Manage form display \> Add to cart*.

The field appears on the product details page (https://example.com/product/1).

I created a view to display all products on a page (https://example.com/shop). The field also appears on the view.

How can I hide the field on https://example.com/shop, but still show it on https://example.com/product/1?

# Answer
You may find the views documentation useful

If I understand your question correctly, you may either set, for you view:

1. a different display under the view setting *format, content* and then set up the right fields you want to show on the product display configuration
2. On the view settings, again under the *format* sections use the *fields* settings, and then directly select the fields you want do display in the view
> 0 votes

---
Tags: commerce
---


# Question
Title: Drupal\Component\Plugin\Exception\PluginNotFoundException: The "node_type" plugin does not exist
I have upgraded drupal 9 to drupal 10 and now while creating a content page or editing the existing content page it is throwing error in error logs

> Drupal\Component\Plugin\Exception\PluginNotFoundException: The "node\_type" plugin does not exist. Valid plugin IDs for Drupal\Core\Condition\ConditionManager are: gtag\_domain, gtag\_language, language, current\_theme, request\_path, user\_role, webform, entity\_bundle:block\_content, entity\_bundle:comment, entity\_bundle:contact\_message, entity\_bundle:crop, entity\_bundle:media, entity\_bundle:menu\_link\_content, entity\_bundle:node, entity\_bundle:redirect, entity\_bundle:taxonomy\_term, entity\_bundle:vote, entity\_bundle:webform\_submission, entity\_bundle:paragraph in Drupal\Core\Plugin\DefaultPluginManager-\>doGetDefinition() (line 53 of /var/www/html/docroot/core/lib/Drupal/Component/Plugin/Discovery/DiscoveryTrait.php).

I've also researched a bit and found that node\_type is removed from Drupal 10 and instead we write **entity\_bundle:node** .

How can I solve this issue as it is coming while creating or editing node?

# Answer
> 2 votes
Search your config files and replace every occurrence of

```
id: node_type

```

With

```
id: entity_bundle:node

```

Import updated config and clear caches, and it should work.

---
Tags: nodes, plugins
---


# Question
Title: Update url-aliase for nodes of a specific content type
I'm using drupal 7 in combination with path auto. I imported nodes of a specific content type using the feed importer, but the url alias is not set correctly.

My problem is, that i can not use the bulk update for content paths, because there is other content, that was migrated manually and that uses non generic url-aliases.

Is there a way to trigger the bulk alias update for a specific content type?

# Answer
> 6 votes
* To update URL for Existing Contents You could go to `admin/content`
* In Update Options, You can choose **Update URL alias** after filtering a specific content type

# Answer
> 1 votes
In the settings you can chose what updating needs to do if there already is an alias. Under 'Update action' select 'Do nothing. Leave the old alias intact'. Then do a bulck update.

# Answer
> 0 votes
If you're comfortable using SQL, you can do the bulk operation against the database without involving Drupal.

I'd recommend testing the query against a slave, staging or non-production instance of the database to verify the results first, just to be safe:

```
SELECT alias FROM node
JOIN url_alias
ON CONCAT('node/', node.nid) = url_alias.source
WHERE node.type= 'machine_name';

```

After you've carefully reviewed the query to verify the results, perform the actual delete:

```
DELETE url_alias FROM node
JOIN url_alias
ON CONCAT('node/', node.nid) = url_alias.source
WHERE node.type = 'machine_name';

```

If you don't have access to MySQL database or Drush, you can perform the operation by using a custom Views Bulk Operation or by using Drush:

`$ drush sql-query "DELETE url_alias FROM node [...]"`

# Answer
> 0 votes
If anyone is looking for Drupal 8 version of this SQL it's a bit messy. We had a content type called web\_site which had /content/.... as the URL alias. We needed this to be /website/.... The machine name of the content type in question is 'web\_site'. See query below:-

```
update path_alias pa
set alias = concat('/website/',substring_index(substring_index(pa.alias,'/',-1),'/',1))
where pa.path like '/node/%'
and substring_index(substring_index(pa.path,'/',-1),'/',1)
in (select nid from node where type = 'web_site');

```

NOte: checking the existing path contains /node/% ensures we don't update aliases for users, files, etc...

---
Tags: 7, path-aliases
---


# Question
Title: How to hide a content type on the node add page?
I need a way to hide a content type on the node add page, or better yet, make two separated node add pages that separate my content types. I'm on Drupal 7 and have four different content types. I would like three of them to be on the default node add page and the fourth to be separate. How would I do this? Thanks

# Answer
Two possibilities:

* `admin/structure/menu/manage/navigation` move/delete menu item that you don't want.
* Cleanest way: use roles and permissions. If the user can't create a content type the link will not appear in any menu.
> 12 votes

# Answer
Put this in a custom module:

```
function yourcustommodule_menu_alter(&$items) {
  if (isset($items['node/add/your-content-type'])) {
    $items['node/add/your-content-type']['type'] = MENU_DEFAULT_LOCAL_TASK;
  }
}

```
> 4 votes

# Answer
**UPDATE**

`MENU_CALLBACK`, as suggested in other answers, didn't work for me here. They still appear on the `node/add` page.

This code worked:

```
function MYMODULE_menu_alter(&$items) {
  if (isset($items['node/add/your-content-type'])) {
    unset($items['node/add/your-content-type']);
  }
}

```

Of course, it assumes you want to disable (not hide) the `node/add` link for that type.

---

**ORIGINAL ANSWER**

The `node/add` page is provided by the Node module. You might be able to do what you want by disabling the menu item in the Navigation menu, according to this post: http://data.agaric.com/disabling-or-moving-nodeaddcontent-type-links-from-beneath-add-content-navigation-menu-also-removes

It's a bit of a bug, so it might not be a reliable way to do it. Personally, I'd create a custom version of the `node/add` page in a module by copying the existing one and making my specific modifications. Then I would use `hook_menu_alter` to make `node/add` go to my version.

You might be able to replace it with a view or panel instead (with Page Manager), but I haven't tried this, and you'd probably lose the automation.
> 3 votes

# Answer
There is now a best solution in contrib (Drupal 7 and modern Drupal) that makes it easy again, providing a separate menu to power a replacement "Add content" page:

https://www.drupal.org/project/custom\_add\_content

(Glad i found that module as i was about to make the equivalent, since it was my fault it got difficult— as wizonesolutions pointed to, i reported the bug that disconnected the menu from the page)
> 0 votes

---
Tags: 7, nodes
---


title: Reorder Content Types in ("/node/add")?

text:
# Question
Title: Reorder Content Types in ("/node/add")?
In drupal 7 it can be do like this. 7 - Reorder Content Types in ("/node/add") - Drupal Answers

How can I reorder Content Types with Drupal 8?

# Answer
Drupal 8 doesn't respect the menu structure anymore when displaying the node types. Node types have no weight concept, so there is no direct way to control this.

What you could do is to implement a template/preprocess for node\_add\_list/node-add-list.html.twig and then reorder the types in code.
> 5 votes

# Answer
There is a good solution in contrib (Drupal 7 and modern Drupal) that makes it easy again, providing a separate menu to power a replacement "Add content" page:

https://www.drupal.org/project/custom\_add\_content

(Glad i found that module as i was about to make the equivalent, since it was my fault it got difficult— i reported the bug that disconnected the menu from the page!)

Another really great Drupal 8 option is the Type Tray module:

https://www.drupal.org/project/type\_tray

which vastly enhances the Content Add page.
> 0 votes

# Answer
Install the Admin Toolbar module. The *Navigation* menu is combined with the *Administration* menu; you can edit the *Administration* menu and change the order.

>

>
> -1 votes

---
Tags: 8, navigation
---


title: How to remove all roles from a user?

text:
# Question
Title: How to remove all roles from a user?
Users on my site generally have several roles. However, every once in awhile I get a spam user, and so I close that account by flagging it with a **spam** flag, which triggers a rule to block the account.

Since I compile statistics on my site based on the number of users having a given role, I don't want spam users to be included. How can I automatically remove all roles from spam users? (I suppose I could add rules components to check for each role and remove it if found, but there has to be a more efficient way...)

# Answer
You can iterate over the user's roles and delete them.

```
/** @var \Drupal\user\UserInterface $user */
foreach ($user->getRoles() as $role) {
  $user->removeRole($role);
}

```
> 1 votes

# Answer
This function can help you

```
/**
 * Remove a role from a user.
 *
 * @param $user
 *   User object or user ID.
 * @param $role_name
 *   String value of role to be removed.
 */
function custom_remove_role_from_user($user, $role_name) {
  // For convenience, we'll allow user ids as well as full user objects.
  if (is_numeric($user)) {
    $user = user_load($user);
  }
  // Only remove the role if the user already has it.
  $key = array_search($role_name, $user->roles);
  if ($key == TRUE) {
    // Get the rid from the roles table.
    $roles = user_roles(TRUE);
    $rid = array_search($role_name, $roles);
    if ($rid != FALSE) {
      // Make a copy of the roles array, without the deleted one.
      $new_roles = array();
      foreach($user->roles as $id => $name) {
        if ($id != $rid) {
          $new_roles[$id] = $name;
        }
      }
      user_save($user, array('roles' => $new_roles));
    }
  }
}

```

first load user's roles, then call this function something like

```
$user=user_load($uid);
foreach($user->roles as $role){
custom_remove_role_from_user($user, $role)
}

```
> 2 votes

# Answer
Here are some quick code examples that I have used to add or remove user roles in Drupal 6. This can be very helpful if you are building a module for a specific site that has to manipulate user roles. Using this technique is not the most flexible solution as it limits itself to the roles configured on a specific site (based on role id and role name). However, you could easily add a database table and an administration section and make this more flexible if needed.

**Here is an easy way to add a role:**

//you will need to enter the uid of the user here, I am just using user 1

```
$user = user_load(1);

```

//first we check if the user has the role in question (using the rid of the role)

```
if (!isset($user->roles[7])) {
    //if not we add the role and set the role name based on what is entered
    //in the drupal role administration section
    $user->roles[7] = 'role name seven';
}

```

**Here is an easy way to remove a role:**

//you will need to enter the uid of the user here, I am just using user 1

```
$user = user_load(1);

```

//first we check if the user has the first role in question

```
if (isset($user->roles[8])) {

  //if so, we unset the role
  unset($user->roles[8]);

  $edit = array('roles' => $user->roles);
  user_save($user, $edit);
}

```

**Here is an easy way to do a role swap:**

//you will need to enter the uid of the user here, I am just using user 1

```
$user = user_load(1);

//first we check if the user has the first role in question
if (isset($user->roles[8])) {

  //if so, we unset the role
  unset($user->roles[8]);

  //now we check to see if they have the role we want to swap for
  if (!isset($user->roles[7])) {

    //if not we add this role
    $user->roles[7] = 'role name seven';
  }

  $edit = array('roles' => $user->roles);
  user_save($user, $edit);
}

```

Helpful? Let me know.
> 1 votes

# Answer
Try this I hope this may help you

```
function user_role_delete($role) {

if (is_int($role)) {

        $role = user_role_load($role);

  }

else {

    $role = user_role_load_by_name($role);
  }

 db_delete('role')->condition('rid', $role->rid)->execute();

 db_delete('role_permission')->condition('rid', $role->rid)->execute();

 // Update the users who have this role set:

 db_delete('users_roles')->condition('rid', $role->rid)->execute();

  module_invoke_all('user_role_delete', $role);

  // Clear the user access cache.

 drupal_static_reset('user_access');

 drupal_static_reset('user_role_permissions');
}

```
> 0 votes

---
Tags: users, flags
---


title: Adding a class to a URL object

text:
# Question
Title: Adding a class to a URL object
```
function mytheme_preprocess_menu_local_tasks(&$variables) {
  if (!empty($variables["primary"]["entity.node.edit_form"]["#link"]["url"])) {
    $url = $variables["primary"]["entity.node.edit_form"]["#link"]["url"];
    assert($url instanceof Url);
    $nid = $url->getRouteParameters()['node'];
    $node = Node::load($nid);
    if (_mytheme_some_condition($node)) {
      $attributes = (array) $url->getOption('attributes');
      $attributes['class'][] = 'little-red-riding-hood';
      $url->setOption('attributes', $attributes);
    }
  }
}

```

That's just awful. Surely there's a better way to do this?

# Answer
> 2 votes
Add the class to

```
...['#link']['localized_options']['attributes']['class'][] = 'foo';

```

The Link and Url options are merged in the Link render element.

# Answer
> 0 votes
Not sure if you like this more. Alternatively, you could add a menu-local-task.html.twig and do something like

```
{% if condition %}
  <li{{ attributes.addClass('little-red-riding-hood' }}>{{ link }}</li>
{% else %}
  <li{{ attributes }}>{{ link }}</li>
{% endif %}

```

---
Tags: theming
---


# Question
Title: How to use a token that includes slashes with PathAuto?
I have a custom token that gets the `path` value from a JSON field. The JSON field stores the path like this (in the database, the slashes are escaped, but I'm showing an unescaped example here):

```
{ "path": "a/b/c" }

```

Every node contains this JSON field, so I made a custom token, `[mymodule:json_path]`.

I then set this token as the path for nodes on the PathAuto patterns page (`/admin/config/search/path/patterns`).

However, PathAuto is stripping the slashes, so when I save a node, I get the path `abc` when I want `a/b/c`.

Elsewhere, when I use the token, I get the value with unescaped slashes as expected (for example, `a/b/c`); I know this because if I set a metatag on the node to the token, the expected value appears.

Also, if I disable **Generate automatic URL alias** and manually set the path to `/a/b/c`, then I get the expected path of `/a/b/c`.

So, how can I get PathAuto not to remove the slashes?

# Answer
> 2 votes
This can be done through the UI, at /admin/config/search/path/settings.

Scroll down to "Punctuation" at the bottom, expand it, find the *Slash (/)* option near the end of the list, and set it to something other than *Remove*.

# Answer
> 1 votes
In `admin/config/search/path/settings`, add your custom token to Safe Tokens.

---
Tags: 9, path-aliases
---


title: How can I add a custom field?

text:
# Question
Title: How can I add a custom field?
I am using layout paragraph module. I have a "section" paragraph with the layout paragraph behaviour. I want to add a field Background color to the section.

Should I add it inside the layout configuration form in the same way https://www.drupal.org/docs/drupal-apis/layout-api/how-to-register-layouts adds a textfield, or should I add the background color field to the "section" paragraph?

# Answer
> 2 votes
I suggest adding the fields to the **section** paragraph type.

I've done something similar in the past by adding colour fields (foreground/background) and other properties (margin/padding) to the section paragraph type.

This way you can keep your layouts purely structural, and define all styling on section level, regardless of the chosen layout.

# Answer
> 1 votes
The Style Options Module was designed just for this purpose by the same team. It's used with their Mercury Editor, but it was designed to separate out these types of style related options from the content of the paragraphs.

---
Tags: paragraphs, 10
---


title: How do I parse a path alias?

text:
# Question
Title: How do I parse a path alias?
I have the following code in my `page.tpl.php` file.

```
<?php $path = drupal_get_path_alias($_GET['q']); ?>
<?php if ($path == 'about-us'): ?>
  <div class="container">
    <h1> about us!!!!</h1>
  </div>
<?php endif; ?>

```

This works for `/about-us`, but not for `/about-us/abc`.

What code would work for all the paths under `/about-us`?

I've messed around with `arg()`, but I ended up with a page error.

# Answer
```
// Retrieve an array that contains the path pieces.
$path_args = arg();

// Check if the current page is the page you're looking for.
if ($path_args[0] == 'about-us') {
  // Your code.
}

```
> 1 votes

---
Tags: 7, uri, path-aliases
---


# Question
Title: Why doesn't the list of modules at /admin/modules show module versions?
I'm similarly investigating possible causes for `/admin/reports/updates` never showing any updates except for Drupal core and Zurb Foundation, nothing else is ever listed. `composer outdated "drupal/*"` shows a ton of available updates. This is Drupal 9.5.9.

Here's the composer file:

```
{
  "name": "drupal/recommended-project",
  "description": "Project template for Drupal 9 projects with a relocated document root",
  "type": "project",
  "license": "GPL-2.0-or-later",
  "homepage": "https://www.drupal.org/project/drupal",
  "support": {
    "docs": "https://www.drupal.org/docs/user_guide/en/index.html",
    "chat": "https://www.drupal.org/node/314178"
  },
  "repositories": [
    {
      "type": "composer",
      "url": "https://packages.drupal.org/8"
    },
    {
      "type": "package",
      "package": {
        "name": "woocommerce/flexslider",
        "version": "2.7.2",
        "type": "drupal-library",
        "extra": {
          "installer-name": "flexslider"
        },
        "dist": {
          "url": "https://github.com/woocommerce/FlexSlider/archive/2.7.2.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "furf/jquery-ui-touch-punch",
        "version": "1.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery-ui-touch-punch"
        },
        "dist": {
          "url": "https://github.com/furf/jquery-ui-touch-punch/archive/master.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jackmoore/colorbox",
        "version": "1.6.4",
        "type": "drupal-library",
        "extra": {
          "installer-name": "colorbox"
        },
        "dist": {
          "url": "https://github.com/jackmoore/colorbox/archive/1.6.4.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    }
  ],
  "require": {
    "composer/installers": "^1.2",
    "cweagans/composer-patches": "^1.6",
    "drupal-ckeditor-libraries-group/indentblock": "4.17.1",
    "drupal/admin_toolbar": "^2.3",
    "drupal/audiofield": "^1.9",
    "drupal/auto_entitylabel": "^3.0@beta",
    "drupal/better_exposed_filters": "^6.0",
    "drupal/calendar": "^1.0@alpha",
    "drupal/ckeditor_entity_link": "^1.3",
    "drupal/ckeditor_indentblock": "^1.0@beta",
    "drupal/colorbox": "^2.0",
    "drupal/conditional_fields": "^4.0@alpha",
    "drupal/context": "^4.0@beta",
    "drupal/core-composer-scaffold": "^9.0.0",
    "drupal/core-project-message": "^9.0.0",
    "drupal/core-recommended": "^9.0.0",
    "drupal/core-vendor-hardening": "^9.0.0",
    "drupal/csv_serialization": "^2.0",
    "drupal/ctools": "^3.4",
    "drupal/date_popup": "^1.1",
    "drupal/devel": "^4.0",
    "drupal/devel_php": "^1.2",
    "drupal/draggableviews": "^2.0",
    "drupal/ds": "^3.9",
    "drupal/editor_advanced_link": "^2.1",
    "drupal/entity": "^1.1",
    "drupal/entityconnect": "^2.0@RC",
    "drupal/entityreference_filter": "^1.2",
    "drupal/field_delimiter": "^1.1",
    "drupal/field_group": "^3.1",
    "drupal/flexslider": "^2.0",
    "drupal/google_analytics": "^3.1",
    "drupal/imce": "^2.2",
    "drupal/jquery_ui_accordion": "^1.1",
    "drupal/jquery_ui_checkboxradio": "^2.0",
    "drupal/jquery_ui_datepicker": "^2.0",
    "drupal/jquery_ui_tabs": "^1.1",
    "drupal/masonry": "^1.1",
    "drupal/masonry_views": "^1.1",
    "drupal/menu_link_attributes": "^1.3",
    "drupal/paragraphs": "^1.12",
    "drupal/pathauto": "^1.8",
    "drupal/quicktabs": "^3.0@alpha",
    "drupal/recaptcha": "^3.0",
    "drupal/redirect": "^1.6",
    "drupal/search_api": "^1.29",
    "drupal/token": "^1.7",
    "drupal/upgrade_status": "^3.0",
    "drupal/video_embed_field": "^2.4",
    "drupal/views_bulk_operations": "^3.9",
    "drupal/views_data_export": "^1.0",
    "drupal/views_infinite_scroll": "^1.7",
    "drupal/webform": "^6.0",
    "drupal/zurb_foundation": "^6.0",
    "drush/drush": "^10",
    "furf/jquery-ui-touch-punch": "~1.0",
    "jackmoore/colorbox": "~1.0",
    "wikimedia/composer-merge-plugin": "^2.0",
    "woocommerce/flexslider": "~2.0"
  },
  "conflict": {
    "drupal/drupal": "*"
  },
  "minimum-stability": "dev",
  "prefer-stable": true,
  "config": {
    "sort-packages": true,
    "preferred-install": "source",
    "allow-plugins": {
      "composer/installers": true,
      "cweagans/composer-patches": true,
      "drupal/core-composer-scaffold": true,
      "drupal/core-project-message": true,
      "drupal/core-vendor-hardening": true,
      "wikimedia/composer-merge-plugin": true
    }
  },
  "extra": {
    "drupal-scaffold": {
      "locations": {
        "web-root": "web/"
      }
    },
    "installer-paths": {
      "web/core": [
        "type:drupal-core"
      ],
      "web/libraries/{$name}": [
        "type:drupal-library"
      ],
      "web/modules/contrib/{$name}": [
        "type:drupal-module"
      ],
      "web/profiles/contrib/{$name}": [
        "type:drupal-profile"
      ],
      "web/themes/contrib/{$name}": [
        "type:drupal-theme"
      ],
      "drush/Commands/contrib/{$name}": [
        "type:drupal-drush"
      ],
      "web/modules/custom/{$name}": [
        "type:drupal-custom-module"
      ],
      "web/profiles/custom/{$name}": [
        "type:drupal-custom-profile"
      ],
      "web/themes/custom/{$name}": [
        "type:drupal-custom-theme"
      ]
    },
    "drupal-core-project-message": {
      "include-keys": [
        "homepage",
        "support"
      ],
      "post-create-project-cmd-message": [
        "<bg=blue;fg=white>                                                         </>",
        "<bg=blue;fg=white>  Congratulations, you’ve installed the Drupal codebase  </>",
        "<bg=blue;fg=white>  from the drupal/recommended-project template!          </>",
        "<bg=blue;fg=white>                                                         </>",
        "",
        "<bg=yellow;fg=black>Next steps</>:",
        "  * Install the site: https://www.drupal.org/docs/8/install",
        "  * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html",
        "  * Get support: https://www.drupal.org/support",
        "  * Get involved with the Drupal community:",
        "      https://www.drupal.org/getting-involved",
        "  * Remove the plugin that prints this message:",
        "      composer remove drupal/core-project-message"
      ]
    },
    "patches": {
      "drupal/core": {
        "#2457999: Cannot use relationship for rendered entity on Views": "https://www.drupal.org/files/issues/2020-12-01/cannot-use-relationship-2457999-259.patch"
      }
    },
    "merge-plugin": {
      "include": [
        "web/modules/contrib/masonry/composer.libraries.json"
      ]
    }
  },
  "require-dev": {
    "drupal/twig_xdebug": "^1.2"
  }
}

```

# Answer
The reason is:

```
"preferred-install": "source"

```

To get packaged projects including the Drupal version string set, you must use:

```
"preferred-install": "dist"

```
> 2 votes

---
Tags: 9
---


# Question
Title: Is it logical to give a homepage an alias?
Drupal allows us to give a URL alias to any node (`example.com/my-alias`). The "Home page" node is not an exception.

Is it logical to give a homepage an alias?
Shouldn't we just keep it "`/`"? i.e. without an alias?

The question spans over Drupal logic or web building standards, SEO and user experience. I know it might be a bit to broad, but I think it's worth asking.

# Answer
> 3 votes
Drupal core allows to have multiple paths for the same node. In the case of a node assigned as a homepage and with an alias there are at least three paths to access the node.

* /
* /node/123
* /my-alias

No visitors are typically accessing the alternative paths unless you link them in a menu. But crawlers might find them nonetheless. So many site owners consider it as good SEO practice to limit access to one canonical path. The standard Drupal module for this is Redirect.

There is another Drupal-specific issue. Independently of the homepage being a node, it has a built-in alias /index.php. If you visit the site with this alias the links on this page are generated with the base path including /index.php/ which creates a whole bunch of new aliases which can even spill to the non-index.php path via caching. You can prevent this by installing the module Redirect with default settings.

---
Tags: nodes
---


# Question
Title: Custom datetime field is treated as a string in Views when filtering
I have added a datetime field using `BaseFieldDefinition::create()` to my custom entity:

```
BaseFieldDefinition::create('datetime')
         ->setLabel(t('Target date'))
         ->setCardinality(1)
         ->setRequired(TRUE)
         ->setSetting('datetime_type', 'datetime')
         ->setDisplayConfigurable('form', FALSE)
         ->setDisplayOptions('form', [
           'type' => 'datetime_default',
           'weight' => 10,
         ])
         ->setDisplayConfigurable('view', TRUE);

```

When I create a view of my custom entity and add a filter on this **Target date** field, I expect to see the date filter options:

* is equal to
* is greater than
* is greater than or equal to

Instead, I see the string filter options:

* is equal to
* contains any word
* contains all words

I assume there's something I need to set to let Views know that my custom datetime should be treated as a datetime and not a string, but I can't it.

How do I get the date filter options instead of the string filter options?

# Answer
> 1 votes
Normally Drupal generates the views data for entities automatically, but not yet in this case. So the solution is to extend EntityViewsData and add it yourself until this issue is resolved Base fields miss out on Views data (datetime.module).

You find an example here: Provide a documentation on how to provide views integration for base fields

---
Tags: views, datetime, 10
---


# Question
Title: Modernizr - uncompressed JavaScript and CSS files warning in SEO
I'm using Drupal 9.5.9 version.

I have enabled Aggregation for css/js files under "admin/config/development/performance". But, in page view source, I can see, core modernizr js file is not compressed.

Due to this one uncompressed js file, am getting more errors/warnings in SEO tool. Can you guide me how to compress/aggregate this file, please?

# Answer
Local JavaScript and CSS files are aggregated and then compressed when:

* Their definition sets `preprocess` to `true` (or `1`)
* There is more than a file in that group

Remote JavaScript and CSS files are never aggregated and compressed.

In the case of the core/modernizr library (line 1124 of the core.libraries.yml file), the library uses two files (*assets/vendor/modernizr/modernizr.min.js* and *misc/modernizr-additional-tests.js*), but `preprocess` is set to `0` for both of them.

```
modernizr:
  # Block the page from being loaded until Modernizr is initialized.
  header: true
  remote: https://github.com/Modernizr/Modernizr
  license:
    name: MIT
    url: https://modernizr.com/license/
    gpl-compatible: true
  version: "3.11.7"
  js:
    assets/vendor/modernizr/modernizr.min.js: { preprocess: 0, weight: -21, minified: true }
    misc/modernizr-additional-tests.js: { preprocess: 0, weight: -20 }

```

Implementing `hook_js_alter()`, it is possible to change `preprocess` to `TRUE` for those files. That would let Drupal aggregate and compress those files too, but it could cause the JavaScript code not to work correctly. There must be a reason for Drupal core to set `preprocess` to `0` for those files.
> 2 votes

---
Tags: 9
---


title: Contextual Filter Path Alias

text:
# Question
Title: Contextual Filter Path Alias
I searched for this for some time now but couldnt find an anwser. I am using drupal 9.1.5 and pathauto. I have content types department and depratment news. The news are linked to the department. So whenever you create a department news you link it to a department. Now I want to display all depratment news linked to the department when i am on the department page (all children) and when I am on a page of a children (department news) I want to display all siblings, i.e. all departments news linked with the same department.

My url for departments is \[node:title\] and for department news is \[node:field\_department:entity\]/\[node:title\]

I thought that using a contextual filter in my view using the raw value from the url would work. So I used path component 1 and checked to use path alias. However this does not display anything.

When using path component 2 and disable to use path alias it works for the department news, which makes sence as I am internally on page node/xxx. I was so frustrated that I tried every other combination of path component and use path alias but nothing works. When using a fixed value for a department everything works as expected for that specific department

# Answer
> 0 votes
You can search for examples for each of your questions with "backwards views" and "sibling views". In short:

## Show children on parent page

Create a Views that lists Children, then add the **Entity reference** field as the Contextual filter (**not** Content ID). Configure it to Provide default value Content ID from URL.

No Relationships needed in this solution. Place the Block on Parent pages and don't forget to configure the Block contextual option, it won't work without it.

## Show siblings on child page

Create a Views that lists Children. This time you'll need 2 Relationships and 1 Contextual filter, all sequentially linked.

The first Relationship is for your ER field (the Field on Child that references a Parent), this one introduces the Parent info.

The second Relationship is the "backwards" Relationship for the same field, it is named a bit differently that the "forwards" one. Make the second Relationship use the first Relationship. This will trace path "backwards" from Parent to all their Children.

Add the Content ID Contextual filter and make it use the second Relationship. Configure it to Provide default value Content ID from URL. This will tell Views which Child's page you're currently viewing and will match to the Parent and then Parent's children.

### Exclude current Child from Views

Your current Child will also be listed in Views because it satisfies the same condition! (It's also Parent's Child, just like other Siblings.)

You can exclude it by adding the second Contextual Content ID Filter that **doesn't** use any Relationships, Provides default value Content ID from URL, but under the last section `More` also check **Exclude**.

# Answer
> 0 votes
look Views alias filter https://drupal.org/project/views\_alias\_filter Provides exposed filter to filtering nodes by URL aliases.

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


title: How do I log out with REST?

text:
# Question
Title: How do I log out with REST?
I'm creating a mobile app in Ionic (which uses Angular). I've set up a D8.3-dev BE which will hold the users and their data.

I've figured out how to register as an anonymous user (this is why I'm using D8.3-dev because this functionality is introduced here) and wrote a blog post about it (https://fonsvandamme.be/en/blog/how-create-user-rest-drupal-8).

Logging in also works after I registered a user.

This is how I login:

```
  /*
   * Login User with username and password.
   */
  login: function (email, password) {

    var defer = $q.defer();

    $http({
      method: 'POST',
      url: config.endpoint + '/user/login?_format=json',
      data: {
        name: email,
        pass: password
      },
    })
      .success(function (data, status, headers, config) {

        // Store the CSRF token.
        localStorage.set('csrf_token', data.csrf_token);

        // Store the Logout token
        localStorage.set('logout_token', data.logout_token);

        // Set the user object.
        localStorage.setObject('user', data.current_user);

        defer.resolve(data);
      })
      .error(function (data, status, headers, config) {
        defer.reject(data);
      });

    return defer.promise;
  },

```

When logging in I receive the following:

current user object, a csrf\_token and a logout\_token.

When I use these tokens to logout (I tried a lot of different ways already:

```
  /*
   * Logout User.
   */
  logout: function () {

    var defer = $q.defer();

    $http({
      method: 'POST',
      url: config.endpoint + '/user/logout?_format=json&token=' + localStorage.get('csrf_token'),
      dataType: 'json',
    })
      .success(function (data, status, headers, config) {
        defer.resolve(data);

        // Go to the login page.
        $state.go("login");
      })
      .error(function (data, status, headers, config) {
        defer.reject(data);
      });

    return defer.promise;
  },

```

I keep getting the following error:

```
{"message":"\u0027csrf_token\u0027 URL query argument is invalid."}

```

So it seems the crsf\_token I use from logging in isn't correct.

What am I doing wrong or overseeing here?

EDIT: after testing a lot and trying it seems like I need to use get. I use this code now for logout but I still get a 403:

```
  /*
   * Logout User.
   */
  logout: function () {

    var defer = $q.defer();

    $http({
      method: 'GET',
      url: config.endpoint + '/user/logout?_format=json',
      headers: {
        'X-CSRF-Token': localStorage.get('csrf_token'),
        'Authorization': 'Basic xxxxxxxxx',
      },
    })
      .success(function (data, status, headers, config) {
        defer.resolve(data);
      })
      .error(function (data, status, headers, config) {
        defer.reject(data);
      });

    return defer.promise;
  },

```

Here is what the Drupal 8.3-dev BE returns, it seems like it recognizes the user I want to log out but it's still throwing the 403.

# Answer
> 5 votes
To logout using REST in Drupal 8, you can do a `POST` to:

`https://example.com/user/logout?_format=json&token=logout_token`

Use the following headers on your request:

* `Content-type: application/json`
* `X-CSRF-Token: csrf_token`

The values for `logout_token` and `csrf_token` are available in the login response.

Be sure to visit `admin/config/services/rest` and enable the following for the `User` resource:

* methods: POST
* formats: json
* authentication: cookie

## Earlier versions of Drupal 8

Do a **GET** on `?q=user/logout`

This is noted in the JS D8 REST docs: https://www.drupal.org/docs/8/core/modules/rest/javascript-and-drupal-8-restful-web-services

Although it should not matter, the `Content-type` may need to be set to `application/x-www-form-urlencoded`.

Here's an example usage from jDrupal: https://github.com/signalpoint/jDrupal/blob/8.x-1.x/src/includes/rest.inc.js#L113

# Answer
> 1 votes
It seems to work now after adding this into my Angular App under app.js

```
.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.withCredentials = true;
}])

```

# Answer
> 0 votes
Still having problems to get a REST logout to work. Creating a simple rest\resource workes well.

```
<?php

namespace Drupal\MYMODULE\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Session\SessionManagerInterface;

/**
 * Provides a resource to log a user out.
 *
 * @RestResource(
 *   id = "custom_logout_resource",
 *   label = @Translation("API - Custom Logout Resource"),
 *   uri_paths = {
 *     "canonical" = "/api/logout"
 *   }
 * )
 */
class CustomLogoutResource extends ResourceBase {

  /**
   * The session manager.
   *
   * @var \Drupal\Core\Session\SessionManagerInterface
   */
  protected $sessionManager;
  /**
   * Responds to GET requests.
   *
   * @return \Drupal\rest\ResourceResponse
   */
  public function get() {
    user_logout();

    // Return a response indicating success.
    return new ResourceResponse(['message' => 'Logged out successfully.']);
  }

}

```

---
Tags: 8
---


# Question
Title: How do I add a meta tag inside the <head> tag?
How can I add the following meta tag inside the `<head>` tag?

```
<meta http-equiv="X-UA-Compatible" content="IE=edge" />

```

I am trying to add it to a Drupal 8 site.

# Answer
> 65 votes
From different sources I found different way of adding meta tags in Drupal 8, hence compiling all ways.

### Using a THEME.theme file

The same question has been asked on Add meta tag to `<head>`. One of the answers provides the following code.

Just add the following code in the *.theme* file, and clear the cache.
The `theme_preprocess_html()` function should be already there in the *.theme* file; don't add another function with the same same, or PHP will throw an error.

```
function theme_preprocess_html(&$variables) {
  $xuacompatible = [
    '#tag' => 'meta',
    '#attributes' => [
      'http-equiv' => 'x-ua-compatible',
      'content' => 'ie=edge',
    ],
  ];

  $variables['page']['#attached']['html_head'][] = [$xuacompatible, 'x-ua-compatible'];
}

```

### Through a template file

In How can I set/remove meta tags?, the user who asked the question mentioned that it's possible to add meta tags in the *html.html.twig* file. The template file used by Drupal core is *core/modules/sytem/templates/html.html.twig*. You can copy and paste its content in a theme's template folder.

The relevant part in that template file is the following one.

```
<!DOCTYPE html>
<html{{ html_attributes }}>
  <head>
    <head-placeholder token="{{ placeholder_token|raw }}">
    <title>{{ head_title|safe_join(' | ') }}</title>
    <css-placeholder token="{{ placeholder_token|raw }}">
    <js-placeholder token="{{ placeholder_token|raw }}">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  </head>
  <body{{ attributes }}>
    {#
      Keyboard navigation/accessibility link to main content section in
      page.html.twig.
    #}
    <a href="#main-content" class="visually-hidden focusable">
      {{ 'Skip to main content'|t }}
    </a>
    {{ page_top }}
    {{ page }}
    {{ page_bottom }}
    <js-bottom-placeholder token="{{ placeholder_token|raw }}">
  </body>
</html>

```

### Create your own custom module

If you follow Adding new HTML tags in the `<head>` in Drupal 8, it describes the general way of adding tag to head in Drupal 8. I have modified the code to adapt it to the question you asked.

```
/**
 * Implements hook_page_attachments().
 */
function module_name_page_attachments(array &$page) {
  $xuacompatible = [
        '#tag' => 'meta',
        '#attributes' => [
          'http-equiv' => 'x-ua-compatible',
          'content' => 'ie=edge',
        ],
      ];
  $page['#attached']['html_head'][] = [$xuacompatible, 'x-ua-compatible'];
}

```

### Using a Drupal module

You can use the *Metatag* module for this, which requires the *Token* and the *Chaos Tool Suite (ctools)* modules.

# Answer
> 8 votes
When adding content to a controller, block, entity, field or other places you don't need to create a hook.

You can attach the meta tag directly to a render/build array. Any render array has at least one render child (containing `#theme`, `#type`, `#markup`, `#plain_text`), where you can place the attachment:

```
$build['username'] = [
  '#theme' => 'username',
  '#account' => \Drupal::currentUser(),
  '#attached' => [
    'html_head' => [
      [
        [
          '#tag' => 'meta',
          '#attributes' => [
            'name' => 'foo',
            'content' => 'bar',
          ],
        ],
        'my_module_foo',
      ],
    ],
  ],
];

```

When rendered the tag bubbles up to page level and is added to the `<head>...</head>` section.

In a preprocess hook you can attach to the top level of `$variables`, see https://drupal.stackexchange.com/a/288989/47547

# Answer
> 1 votes
Custom Meta module is the way to go. It has a very straightforward configuration and allows adding any custom meta tag to the page head section.

> The module allows you to define and manage custom meta tags. Simply select the Meta attribute (property, name, http-equiv) and set the value and content value in the format and the module will add your meta tags to all non-admin content for your site.

# Answer
> 0 votes
Here we can use the Metatag module.

We need to enable Metatag: Mobile & UI Adjustments submodule.

After doing this from metatag config page we would be able to see Windows & Windows Mobile under each metatag type and according to our requirement, we can add either globally or page-specific X-UA-Compatible content.

# Answer
> 0 votes
## Drupal 7 answer

Recently had to implement some Open Graph `<meta property="og:xxx" content="xxx">` tags for Facebook embedding. Drupal 7 let's you also do the following (not sure about Drupal 8 though):

```
$ogTitleElement = array(
    '#type' => 'html_tag',
    '#tag' => 'meta', // The #tag is the html tag -
    '#attributes' => array( // Set up an array of attributes inside the tag
        'property' => 'og:title',
        'content' => 'My Custom Title',
    ),
);
drupal_add_html_head($ogTitleElement, 'facebook_title');

```

Code can be added inside your custom module, or inside the `<themename>_preprocess_html` function of your theme's `template.php` file.

# Answer
> 0 votes
The Mix module can be used to set title and meta tags for the front page and a description meta tag for the node page.

## Set title and meta tags for the front page.

Install and enable the Mix module. Goto /admin/config/mix, find and click the Meta tags link or goto /admin/config/mix/meta directly. Fill the Frontpage form then click Save Configuration Goto front page and inspect the page title and source code to see all the changes.

## Set a description meta tag for the node page.

Install and enable the Mix module. Goto /admin/config/mix, find and click the Meta tags link or goto /admin/config/mix/meta directly. Fill the Node form then click Save Configuration Goto any node page and inspect the source code to see the changes.

---
Tags: meta-tags
---


# Question
Title: Rest API show No route found for GET error
I'm using Drupal 9.5 to build my api inside my custom module. When I test the API URL on the browser it show me a message

```
message: "No route found for "GET /api/v1/api_resource""

```

```
<?php

namespace Drupal\demo_api\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;

/**
 * Provides the API resource for the mobile App
 *
 * @RestResource(
 *   id = "demo_api_resource",
 *   label = @Translation("Demo API Resouce"),
 *   uri_paths = {
 *      "canonical" = "/api/v1/api_resource/"
 *   }
 * )
 */
class ApiResource extends ResourceBase {

  public function get() {
    $response = ['message' => 'Hello, this is a rest service'];
    return new ResourceResponse($response);
  }

```

I did configure in REST UI to accept the GET request with cookie authentication.

What could be the issue here?

# Answer
> 1 votes
I just found out, the issue is caused by the forward slash at the end of the path.

I have to change  `"canonical" = "/api/v1/api_resource/"` to this one  `"canonical" = "/api/v1/api_resource"`

Once I removed the forward slash from the path, the API is response as expected when you request `mydomain.com/api/v1/api_resource?_format=json`

---
Tags: 9
---


# Question
Title: Why does Drupal harden permissions of the /web/sites/default directory and files?
I understand that Drupal hardens permissions of the `/web/sites/default` directory and its files, each time that the `system_requirements()` function is called, typically after each `composer require` operation.
The particular hardening is removing the `write` permission from the `user` of the Drupal file tree, and to soften that hardening one would have to do `chmod u+w web/sites/default`.

If I understand correctly, why does Drupal remove the `write` permission from the `user` of the Drupal file tree?
What typical problem does it prevent, or solve?

# Answer
> The settings.php file contains the database password and username in plain text and, once created, must be set so that only appropriate users can read it. That usually means removing read permissions for the "other" user.

https://www.drupal.org/docs/administering-a-drupal-site/security-in-drupal/securing-file-permissions-and-ownership

It is not particularly clear in this question if you are asking about files or about the sites/default directory. In the case of hardening permissions on the sites/default directory itself, that is to prevent the addition of files.

The original reasoning is in this seventeen-year-old issue.

> The general approach here is that, because we do not know the security setup of the webserver, we apply our permission changes to all three digits of the file permission (i.e. user, group and all).

Power users who understand filesystem details may wish disable these protection via a documented configuration in settings.php.
> 4 votes

---
Tags: security
---


title: Ckeditor strips <i> tags

text:
# Question
Title: Ckeditor strips <i> tags
CKeditor strips the `<i>` tags, and I can't find where in config.js I can put this code.

```
CKEDITOR.dtd.$removeEmpty['i'] = false

```

This is a solution for Drupal 7 and the CKEditor module.

# Answer
Add an empty space -

```
<i class="fa fa-drupal"> </i>

```
> 9 votes

# Answer
I suggest the following.

```
<i class="icon icon-classname"></i>

```

`` is the HTML entity for the zero-width non-joiner character, which avoids playing with left-padding/left-margin.
> 6 votes

# Answer
I am on Drupal 8.6.1, Fontawesome module 8.x-2.6 and had a similar problem with CKEditor stripping module inserted icons. I also tried manually typing in “i“ icons in “Source” editing mode. It failed even after I added &nsp at the end and inserted “i” in Filter tags for CKEditor.

For some reason, it all worked when I changed the Fontawesome Admin\>Configuration\>Font Awesome settings\>Font Awesome Tag from “i” to “span” and added “span” tags to CKEditor Filter.
> 4 votes

# Answer
Adding a hex symbol in the i tag doesn't work for everyone and not everyone is a php developer who can just whip up a small module for a solution.

Here is a quick js fix, specifically for font awesome.

* navigate to /admin/config/content/formats/manage/basic\_html
* add `span.fontAwesome | Icon` to the CKEditor plugin settings
* select "Limit allowed HTML tags and correct faulty HTML"
* add `<i class="">` to the allowed tags in the filter settings
* You'll need to add a custom javascript file, the font awesome library and the jquery library.
* paste the following into your theme.libraries.yml file:

```
global-js:
  js:
    js/custom_js_file.js: {}
  dependencies:
    - core/jquery

font-awesome:
  remote: https://fortawesome.github.io/Font-Awesome/
  version: 4.5.0
  license:
  name: MIT
  url: https://fortawesome.github.io/Font-Awesome/license/
  gpl-compatible: true
css:
  theme:
    https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css: { type: external, minified: true }`

```
* in the theme.info.yml file paste the following:

```
libraries:
  - theme/global-js
  - theme/font-awesome

```
* Paste the following into the custom javascript file.

`(function ($) {
 $.fn.awesomeIcon = function(){
 $(this).each(function(i, el) {
 $('span').replaceWith(function(){
 return $('<i class="fa ' + $(el).text() + '">');
 });
 })
 }
 $('.fontAwesome').awesomeIcon()
})(jQuery);`

* Refresh the cache
* create some new content
* in the CKEditor, paste the class name of a fontAwesome icon e.g.fa-thumbs-o-up
* highlight it and select icon from the styles dropdown.
* publish the post

If all goes well the fontawesome icon should appear in the node on the front end.
> 0 votes

# Answer
For reasons unknown to me, none of the solutions here worked until I tried something like:

`<em class="bi bi-arrow-right-circle-fill me-2 fs-2"> </em>`.

And that did the trick.
> 0 votes

# Answer
Use ` ` and add style word-spacing, because spacer move content to the left

```
<p><i class="fa fa-drupal" style="word-spacing: -1em;"> </i><br />
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
</p>

```
> -1 votes

---
Tags: 8, wysiwyg
---


# Question
Title: Is there a way to stop Commerce from hiding the customer address info when adding a user?
We are using Phone 7.x-1.0-beta1 only because it is required to perform API calls to our ERP. After upgrading to Commerce 7.x-1.16 the address info under add user is collapsed by default. Since the phone module puts the phone number in the same section of the form it also becomes hidden. When the drop down arrow to expose the address info is clicked it complains that the phone number is invalid and refuses to expose the fields. We are forced to roll back to Commerce 7.x-1.15 so admins and customers can create accounts.

Is there an option to have the address fields exposed by default or do I need to create an issue?

# Answer
We were able to solve this issue. It was a combination of a change in Commerce 7.x-1.16 Issue 2274833 effecting our custom phone number validation script.

commerce\_customer.module::~1012

```
+      '#value' => t('Add @type', array(
+        '@type' => strtolower($profile_type['name']),
+      )),

```

Since they Changed 'name' from customer information to account information our code was broken.
> 0 votes

---
Tags: commerce
---


# Question
Title: How to override a contrib module's FieldType plugin?
I'm trying to override a FieldType plugin provided by the Field Encrypt module:

```
class EncryptedFieldStorageItem extends FieldItemBase {

```

I created my own class, `MyModuleEncryptedFieldStorageItem`, and put it in `my_module/src/Plugin/Field/FieldType/MyModuleEncryptedFieldStorageItem.php`.

Now I need to inform Drupal that I want to override the Field Encrypt module's `EncryptedFieldStorageItem` class with my `MyModuleEncryptedFieldStorageItem` class, right? In the past, I've done this using `MyModuleServiceProvider` to set the class, but here, I don't want to override the field type plugin class; I want to override the class of one specific plugin. How can I do that?

# Answer
> 5 votes
The FieldType plugin manager provides an alter hook `mymodule_field_info_alter()`.

Example from the core language module:

```
/**
 * Implements hook_field_info_alter().
 */
function language_field_info_alter(&$info) {
  // Change the default behavior of language field.
  $info['language']['class'] = '\Drupal\language\DefaultLanguageItem';
}

```

---
Tags: plugins
---


title: How to localize your own contrib module

text:
# Question
Title: How to localize your own contrib module
Things have changed since I last localized a Drupal contrib module of mine. In D9/10, having a `translations` folder with `.po` files no longer seems to be the usual route. Yes, it can be done for local custom modules by specifying the location in the `info.yml` but I'm looking for a solution for regular, d.o hosted contrib modules. Right now I don't even need many languages, just one, the (Commerce) module in question applies to a single country, so the translation should obviously come directly for anybody installing the module.

I'm aware of this question but it's unanswered.

# Answer
With some perseverance, I succeeded. The required steps are partly as described in the linked other question, have your `.po` files in a `translations` folder inside your module. But instead of adding the fixed path to the `info.yml` file, use the following hook in your `.module`:

```
function MODULE_locale_translation_projects_alter(&$projects) {
  $folder = \Drupal::service('extension.list.module')->getPath('MODULE');
  $projects['MODULE'] = [
    'info' => [
      'interface translation server pattern' => $folder . '/translations/%language.po',
    ],
  ];
}

```

You may use a different naming scheme for the files, I decided the language code was enough for me.

This way, it will be loaded from the actual folder, no matter whether it's in `custom` or not.
> 2 votes

---
Tags: i18n-l10n
---


# Question
Title: How can I get data from ResultRow object in views template
I am trying to theme a Drupal 8 views. When I print the row variable using kint method I am getting below result. But I'm not sure how could I access the values in the object.

I tried below options. But nothing works.

* {{ row.\_entity.title.value }}
* {{ row.contents.get('title') }}
* {{ row.contents.contents.title }}

Could anyone please help me how could I iterate through row data in views twig template.

# Answer
> 5 votes
There are two question. First how to get the title in the kint dump?

`{{ row._entity.title.value }}` should work, also `{{ row._entity.gettitle }}` or `{{ row._entity.label }}`, because `getTitle()` and `label()` are methods of the node object.

Second, could anyone please help me how could I iterate through row data in views twig template?

In Views two steps are needed, first get the field and then use the method getValue() on the field providing the result row as parameter:

```
{{ view.field.field_name.value(view.result[0]) }}

```

# Answer
> 1 votes
If u want to edit classes for fields, u need to use template suggestion for

> views-view-fields.html.twig

more u can see in documentation.

# Answer
> 0 votes
I do not think from the given screen shot section you can access the value. Because we can not access the protected value. You need to search other alternative.

Below links may help you

https://api.drupal.org/api/drupal/core!modules!views!views.theme.inc/function/template\_preprocess\_views\_view\_fields/8.2.x

How to get each field value in views-views-unformatted--view-machine-name.html.twig?

# Answer
> 0 votes
It seems drupal 8 changed the row to rows and added arrays before the row contents. I wanted to get the value of the row ex: title if I used the code above it showing null values. I also tried this {{kint(rows.content)}} to dig digger but still showing null values on {{kint(rows)}} works.

# Answer
> 0 votes
Whatever variable you are using to print out the Drupal/views/ResultRow may need \[0\] added so you can get a level down. In my case I was using {{ view.result }} and it took me forever to realize I needed to use {{ view.result\[0\].nid }} (to in my case print the node id)

{{ view.result\[0\].\_entity.title.value }} might work for you here

# Answer
> -1 votes
{# The template name is "views-view--agenda.html.twig" #} {# /\**

* @file
* Theme override to display a view of unformatted rows.
*
* Available variables:
* + title: The title of this group of rows. May be empty.
* + rows: A list of the view's row items.
* + attributes: The row's HTML attributes.
* + content: The row's content.
* + view: The view object.
* + default\_row\_class: A flag indicating whether default classes should be
* used on rows.
*
* @see template\_preprocess\_views\_view\_unformatted() \*/ #} {% if title %}

### {{ title }}

{% endif %}

{% for row in rows %} {% set row\_classes = \[ default\_row\_class ? 'views-row', \] %} {% endfor %}

\<div{{ row.attributes.addClass(row\_classes) }}\>

```
{# for each row  ('agenda' is the content-type, on which we do the view) #}

{% set items = view.result %}
 {% for item in items %}

        {{ item._entity.field_fist_name.value }}

        {{ item._entity.field_name.value }}

        <img src="{{ file_url(item._entity.field_image.entity.uri.value|image_style('medium')) }}"/>

        {{ item._entity.field_job.value }}

        {{ item._entity.field_selected_list.value }}

        {{ item._entity.field_agency_name.value }}

        {{ item._entity.field_description.value }}

        {{ item._entity.field_date_text_format.value }}

        {{ item._entity.field_hour_text_format.value }}

        {# {{ item._entity.field_weight.value }} #}

{% endfor %}

```

---
Tags: views, theming, 8
---


# Question
Title: Views Data Export: Plaintext field contains HTML entities
I have a CSV export which is done by the "views\_data\_export" module. When exporting, a plain text field which contains a double quote ends up with a " HTML entitity in the CSV file. This doesn't make sense, and when Im importing this file, this leads to problems.

I'm actually working with Drupal 9.5.10 and different entities, but was able to reproduce this with a fresh Drupal 10.1 installation. I hope I didn't forget any important step in the description.

## Steps to reproduce

* Install Drupal 10.1 (10.1.3-dev)
* Install the modules "drupal/views" and "drupal/views\_data\_export"
* Create an Article node and set the title as \>\>Test "Hello" Test\<\<
* Create a view "article export" and set the following:
    + Add a display of type "data export"
    + Set the content type filter to match Article nodes
    + Under Format \> Settings choose "csv". Expand the "CSV Settings" section and uncheck "Strip HTML".
    + Make sure the "title" field is selected and the formatter is set to "Plain text". Uncheck "Link to the content".
    + Set the path and the filename to "all\_articles.csv"
    + Save the view and call the path

## Expected

A CSV file with this content:

```
title
"Test ""Hello"" Test"

```

## Actual

A CSV file with this content:

```
title
"Test "Hello" Test"

```

Any ideas on how to get the HTML out of there? Simply activating "Strip HTML" is not good enough, since the real-world example also contains fields which are supposed to contain HTML. The export is coupled with an import, so that users can modify the CSV file and reimport it. So the HTML fields need to contai HTML and the other fields should not contain HTML.

# Answer
> 0 votes
In your view, go to Format and click "Settings" for your Data export.

Then, uncheck "Strip HTML"

That should give you full HTML output in your export.

This is the return:

---
Tags: views
---


title: Loading webform in modal is too slow

text:
# Question
Title: Loading webform in modal is too slow
I have webform with near 130 fields (text, entity checkboxes, radios, composite, etc)

Use it in modal:

```
<a href="/my-form?title={{node.id}}" class="webform-dialog" data-dialog-options="{"width":465,"resizable":"false","hide":"fadeOut"}">click to open</a>

```

It tooks near 9 seconds to load it.

Interal and Dynamic page cache enabled. Js and css aggregation enabled.

Opens webform on it's own page and if page is cached then it tooks 2 sec to load (all page, not only form).

So I think the problem is in cache.

How can I cache ajax response or how to solve this issue?

Thanks in advance.

# Answer
The core team is working on cacheable Ajax requests. The first project using it is Views. Modals might be next.

Until then you could deliver the hidden webform together with the cached page and unhide it with javascript, like jQuery Modal or Bootstrap's modal component.

Alternatively, make a custom jQuery.ajax() call pointing at your own controller which returns the rendered web form in a cacheable response.
> 2 votes

---
Tags: webforms, ajax, 9
---


# Question
Title: Why is the Cache-Control always "no-cache" and "X-Drupal-Dynamic-Cache" UNCACHEABLE on this site?
I have a production website for quite a long time now. By digging, we found that the *Cache-Control* was always to "*no-cache*" and "*X-Drupal-Dynamic-Cache*" is *UNCACHEABLE*

My settings.prod.php look like this

```
# ================================================================
# Performance settings
# ================================================================
$config['system.logging']['error_level'] = ERROR_REPORTING_HIDE;
$config['system.performance']['cache']['page']['max_age'] = 86400;
$config['system.performance']['css']['preprocess'] = TRUE;
$config['system.performance']['css']['gzip'] = TRUE;
$config['system.performance']['js']['preprocess'] = TRUE;
$config['system.performance']['js']['gzip'] = TRUE;

```

And this is my services.prod.yml

```
parameters:
  http.response.debug_cacheability_headers: false
  twig.config:
    debug: false
    auto_reload: false
    cache: true

```

I have both `dynamic_page_cache` and `page_cache` enable on the website, because we have both anonymous and logged users.

Furthermore, the config settings is not display in the backend `System > Development > Performance`, is the cache really activated like this ?

# Answer
I've uninstall `page_cache` and keept `dynamic_page_cache` to have a `max-age=3600` enabled.

I've also remove a remaining `killswitch` which causes issue with custom block.

As it is a `context user website` (drupal commerce), when the user is adding a product, **x-dynamic-cache** became **uncacheable**
> 1 votes

---
Tags: 9, caching, performance
---


# Question
Title: Switching from table to graph give wrong data
I'm using the Drupal Commerce Report module as a base for my stats. I have a table which give me data about my sales per month.

I'd like to use graph instead of table, to make it easier to compare. For some reason, the coma is gone, so all my sales reports are wrong

I tried to alter data in a pre\_render, in a preprocess (by checking the format, test with a dot instead of a coma) but still having the wrong result

# Answer
This was caused because the value where rewritted in the view (thousand separator, number after coma...). Reverted to initial configuration solved the problem.
> 0 votes

---
Tags: commerce, charts
---


# Question
Title: How can I avoid forms are saved as drafts?
I used Drupal 9 webform module to create forms , Each form has Submit button and Save as draft button, Below is the configuration for the form ,  When I submit the form it save as draft ,

>

But when I open it from result section and submit it saved properly without save as a draft . Is there any setting to stop that? Is it because of some configuration ?

# Answer
> 1 votes
There is a section called *submission draft settings* in the form's settings tab

`/admin/structure/webform/manage/<YOUR_WEBFORM_ID>/settings/submissions`

---
Tags: webforms
---


# Question
Title: Override the page title with a value from an API response
I built a custom Drupal module. The module fetches data from a 3rd-party API and builds a block. I need to use a value from the API response to override the title (and head\_title) of the page that the block is placed on.

I tried saving the value to the node in the Block controller:

```
$node = $this->getContextValue('node');
$node->page_title_override = $apiValue;

```

And then using that from `hook_preprocess_html()`.

```
function myModule_preprocess_html(&$variables) {
  $pageTitleOverride = $node->page_title_override;
  $variables['head_title']['title'] = $pageTitleOverride;
}

```

It appears that the preprocess hook executes before the block controller, so `$pageTitleOverride` is empty.

Do you have any idea on a better approach?

# Answer
You are saving the value to the node in the Block controller only temporary, but blocks are not necessarily rendered in the same request. The block could have been cached a long time ago before the page is built or, if the block is not cacheable, it can be cached in the page as a placeholder so that the preprocess hook runs in a later request.

So what you can do depends on how cacheable the block and the title are. The module metatag provides more tools to set the page title dynamically, either through attached html\_head metadata or tokens.
> 0 votes

---
Tags: hooks, 10
---


# Question
Title: Change Workbench state from Draft to Published programatically
I would like to do a bulk operation and change nodes from a state of Draft to Published. I created a new revision from a previous change, but all revisions default to Draft. Now I would like to basically just publish the new revision. (I am using the Workbench module.)

I have tried doing things like the below, but none of them seem to work:

```
$node->workbench_moderation['current']->published = "1";

```

or

```
$node->workbench_moderation['current']->from_state = "draft";
$node->workbench_moderation['current']->state = "published";
$node->workbench_moderation['current']->published = "1";

$node->workbench_moderation['published']->from_state = "draft";
$node->workbench_moderation['published']->state = "published";
$node->workbench_moderation['published']->published = "1";

$node->workbench_moderation['my_revision']->from_state = "draft";
$node->workbench_moderation['my_revision']->state = "published";
$node->workbench_moderation['my_revision']->published = "1";
$node->workbench_moderation['my_revision']->current = TRUE;

```

or

```
workbench_moderation_moderate($node, 'published');

```

I've tried saving using the below rather than `node_save` as well, thinking maybe the `node_save` triggered a new draft.

```
workbench_moderation_node_update($node);

```

**I just want to simply load the node, publish the draft, then save it again.**

Any idea what I am doing wrong?

# Answer
> 11 votes
There are two solutions which I have found will work:

**The First:**

```
$nid = 1234;
$node = node_load($nid);
$node->body['und'][0]['value'] = 'new body';
$node->revision = 1;
$node->log = 'State Changed to published';
node_save($node);
workbench_moderation_moderate($node, 'published');

```

*NOTE:* I intentionally put `workbench_moderation_moderate()` after `node_save()` because in my case `node_save()` will trigger a new draft. After the draft is created, I publish that draft.

**The second:**

```
$nid = 1234;
$node = node_load($nid);
$node->body['und'][0]['value'] = 'new body';
$node->workbench_moderation_state_new = workbench_moderation_state_published();
$node->revision = 1;
$node->log = 'State Changed to published';
node_save($node);

```

I am going with the first solution over the second solution because of the status messages. The first shows the two messages under the current revision:

```
From Draft --> Published on...
From Published --> Draft on...

```

whereas the second solution only shows one message which doesn't really make much sense:

```
From Published --> Published on...

```

# Answer
> 0 votes
@Keven

The second solution is the correct one! You just have to load the most recent revision with node\_load. node\_save() triggers the workbench\_moderation\_moderate() function so you don't have to do it after node\_save() manually!

```
$query = db_select('workbench_moderation_node_history', 'wmnh');
$query->addField('wmnh', 'vid');
$query->condition('wmnh.nid', $nid);
$query->condition('wmnh.current', 1);
$current = $query->execute()->fetchField();

// or you can get the latest revision id by loading the node without revision id:
$node = node_load($nid);
// Altough you can get node revision id from node object itself i prefer using the workbench_moderation property.
// $current = $node->vid;
$current = $node->workbench_moderation['current']->vid;

$node = node_load($nid, $current);
$node->workbench_moderation_state_new = workbench_moderation_state_published();
$node->revision = 1;
node_save($node);

```

# Answer
> 0 votes
For reference, in Workbench Moderation 7.x-2.x-dev, this worked to unpublish a node:

```
$node = node_load(218821);
$node->status = NODE_NOT_PUBLISHED;
$node->event = 'to_unpublished';
node_save($node);

```

---
Tags: workbench
---


# Question
Title: Internal 500 after upgrading the server to Debian 10 with PHP 8.2
I haven't dealt with Drupal before, but I needed to upgrade the server from Debian 10 with PHP 7.3 to Debian 12 with PHP 8.2. The website throws 500 errors.

I added debugging lines on the *index.php* file and I got these errors.

> Deprecated: Return type of DrupalCacheArray::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #\[\ReturnTypeWillChange\] attribute should be used to temporarily suppress the notice in /var/www/clients/web/includes/bootstrap.inc on line 362

> Deprecated: Return type of DrupalCacheArray::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #\[\ReturnTypeWillChange\] attribute should be used to temporarily suppress the notice in /var/www/clients/web/includes/bootstrap.inc on line 369

> Deprecated: Return type of DrupalCacheArray::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #\[\ReturnTypeWillChange\] attribute should be used to temporarily suppress the notice in /var/www/clients/web/includes/bootstrap.inc on line 381

> Deprecated: Return type of DrupalCacheArray::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #\[\ReturnTypeWillChange\] attribute should be used to temporarily suppress the notice in /var/www/clients/web/includes/bootstrap.inc on line 388

> Fatal error: During inheritance of PDO: Uncaught ArgumentCountError: Too few arguments to function \_drupal\_error\_handler(), 4 passed in /var/www/clients/web/includes/bootstrap.inc on line 2754 and exactly 5 expected in /var/www/clients/web/includes/bootstrap.inc:2601 Stack trace: #0 /var/www/clients/web/includes/bootstrap.inc(2754): \_drupal\_error\_handler(8192, 'Return type of ...', '/var/www/client...', 1317) #1 /var/www/clients/web/includes/bootstrap.inc(2754): require\_once() #2 /var/www/clients/web/includes/bootstrap.inc(2528): \_drupal\_bootstrap\_database() #3 /var/www/clients/web/includes/bootstrap.inc(2673): drupal\_bootstrap(3, false) #4 /var/www/clients/web/includes/bootstrap.inc(2524): \_drupal\_bootstrap\_page\_cache() #5 /var/www/clients/web/index.php(24): drupal\_bootstrap(7) #6 {main} in /var/www/clients/web/includes/database/database.inc on line 0

How can I fix these errors?

I am using Drupal 7.73.

# Answer
> 2 votes
Drupal 7 is not fully compatible with PHP 8.2. See this issue. But if Drupal core will be compatible, a lot of legacy contrib modules don't work with PHP 8. You can try to use PHP 8.1

Before upgrade PHP version you need to upgrade Drupal core to the latest version (Today it is 7.98), because 7.73 is really old.

# Answer
> 1 votes
Drupal 7 is not yet full compatible with PHP 8.2. \[META\] Make Drupal 7 core compatible with PHP 8.2, a meta issue created to follow that change, is not yet closed as fixed, although many of its child issues (the ones created for effectively changing the Drupal 7 code) are already closed as fixed.

Fixing the compatibility with PHP 8.2 on Drupal core could require some time. In some cases, the issue is on a contributed project, and they need to verify if the issue is caused by Drupal core (and fix Drupal core) or by a contributed project (and in this case, the time necessary to fix the issue depends from that project's maintainers, not from Drupal core maintainers).

PHP requirements for Drupal 7 shows that PHP 8.2 is supported starting from Drupal 7.94. Drupal 7.73 does not support PHP 8, but Drupal 7.4.

| PHP version | Supported by Drupal | Recommended for Drupal 7? |
| --- | --- | --- |
| 7.4 | Yes, as of Drupal 7.71 | No |
| 8.0 | Yes, as of Drupal 7.79 | Yes |
| 8.1 | Yes, as of Drupal 7.92 | Yes |
| 8.2 | Yes, as of Drupal 7.94 | Yes |
| 8.3 | No | No |

That is still what Drupal core supports. What supported by contributed project varies from project to project.

> How can I fix these errors?

Assuming those errors are caused by Drupal core code, you just need to wait PHP 8.1 is fully supported by Drupal core. If those errors are caused by contributed modules, you need to wait those modules fully support PHP 8.1.

---
Tags: 7
---


# Question
Title: What is the correct way to handle caching with custom modules?
I'm experimenting with creating a custom module in Drupal 8. I have created a module that has some custom database tables. One of these tables, "mymodule\_tickets" gets populated via admin forms that I have created within the module.

On the public side of the website, I have another custom page setup ('/booking'), which displays a form containing the available 'tickets'. For the mostpart, this works really well, but I am having some trouble understanding caching.

The '/booking' page uses the drupal form api to create a 'number' field for each available ticket. The '#title' of each form field is the name of the ticket as setup in the admin area. When anonymous users view the /booking page, the titles of these form fields cache. If I change the title of the ticket in my admin area, this does not get reflected on the public site for anonymous users.

My first attempt at remedying this was to add this when building the form:

```
$form['#cache']['max-age'] = 0;

```

But unfortunately this did not make any difference. Changes to the titles of form elements were still not reflected to the user.

In the end I had to add the following to my routing file:

```
  options:
    no_cache: TRUE

```

While this did work and stopped the form titles from caching, it feels like a very heavy-handed way to fix the problem. To me the correct solution would be to cache these pages for anonymous users, but to correctly invalidate the cache after making changes in the admin area.

Are there any guides or code snippets or articles about how to do this? From searching the web I haven't been able to find any relevant information or examples.

# Answer
In your page controller for /bookings, set a cache tag in the build array:

```
$build['#cache'] = [
  'tags' => [
    'booking_page_settings',
  ],
];

```

Or since it's a form:

```
$form['#cache'] = [
  'tags' => [
    'booking_page_settings',
  ],
];

```

Then when you submit the admin form that has the settings for the page, invalidate the tag:

```
Cache::invalidateTags(['booking_page_settings']);

```

You can also add to your cache tags the nodes that display on your booking page, such as 'node:123', or you can add 'node\_list' to invalidate the caching when any node is updated.
> 3 votes

# Answer
This is a bit adjacent to this specific question, but if folks land here from search engines looking for information on how to cache custom data, I've created a module to help with that: https://www.drupal.org/project/cache\_register
> 0 votes

---
Tags: 8, caching
---


# Question
Title: How can I alter the value returned from a hook?
I installed the Two-factor Authentication (TFA) and the TFA Basic plugins modules.

I want to alter the value returned from `tfa_basic_tfa_ready_require()`, which is a hook implementation, in a custom module.

```
/**
 * Implements hook_tfa_ready_require().
 */
function tfa_basic_tfa_ready_require($account) {
  if (tfa_basic_tfa_required($account)) {
    drupal_set_message(t('Login disallowed. You are required to set up two-factor authentication. Please contact a site administrator.'), 'error');
    return TRUE;
  }
  return FALSE;
}

```

I tried the following code in the custom\_tfa.module file, but it does not work.

```
function custom_tfa_tfa_basic_tfa_ready_require_alter($account) {
  drupal_set_message(t('TEST'), 'warning');
  return FALSE;
}

```

How can I alter the value returned from a hook?

# Answer
Since `tfa_basic_tfa_ready_require()` shows a message when it returns `TRUE`, altering the value returned from that hook is not sufficient. It would not make sense to show *Login disallowed. You are required to set up two-factor authentication. Please contact a site administrator.* when the login is allowed.

To avoid Drupal core invokes `tfa_basic_tfa_ready_require()`, it is necessary to implement `hook_module_implements_alter()`.

```
function custom_tfa_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'tfa_ready_require') {
    unset($implementations['tfa_basic']);
  }
}

```

Then, the module can implement its own `hook_tfa_ready_require()`.

```
function custom_tfa_tfa_ready_require($account) {
  return FALSE;
}

```

As a side note, `custom_tfa_tfa_basic_tfa_ready_require_alter()` would eventually be an alter hook implemented by the *custom\_tfa* module for the `hook_tfa_basic_tfa_ready_require()` hook implementations. Leaving out the fact alter hooks get different parameters, `hook_tfa_basic_tfa_ready_require()` is not the hook implemented from `tfa_basic_tfa_ready_require()`.

As a further note, alter hooks are invoked when the module that uses them calls `drupal_alter()`. Usually, for `hook_HOOK_TYPE()`, `hook_HOOK_TYPE_alter()` is invoked too; that is not always the case, though. In the cases where `hook_HOOK_TYPE()` is invoked, but `hook_HOOK_TYPE_alter()` is **not** invoked, implementing `hook_module_implements_alter()` is the solution, although it requires to duplicate code from the other module and to keep the new hook implementation updated each time the other module's hook is updated.
> 0 votes

---
Tags: hooks
---


title: Can't find the cause of this error

text:
# Question
Title: Can't find the cause of this error
I am working through a Drupal 8 module building exercise from YouTube and I am not able to figure out what is causing an error. The relevant page loads and displays the form, but I get the following error message.

> Notice: Trying to get property of non-object in Drupal\rsvplist\Form\RSVPForm-\>buildForm() (line 29 of modules/custom/rsvplist/src/Form/RSVPForm.php).
> Drupal\rsvplist\Form\RSVPForm-\>buildForm(Array, Object) call\_user\_func\_array(Array, Array) (Line: 518)
> Drupal\Core\Form\FormBuilder-\>retrieveForm('rsvplist\_email\_form', Object) (Line: 275)
> Drupal\Core\Form\FormBuilder-\>buildForm('rsvplist\_email\_form', Object) (Line: 93)
> Drupal\Core\Controller\FormController-\>getContentResult(Object, Object) call\_user\_func\_array(Array, Array) (Line: 123)
> Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-\>Drupal\Core\EventSubscriber{closure}() (Line: 582)
> Drupal\Core\Render\Renderer-\>executeInRenderContext(Object, Object) (Line: 124)
> Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-\>wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
> Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-\>Drupal\Core\EventSubscriber{closure}() (Line: 151)
> Symfony\Component\HttpKernel\HttpKernel-\>handleRaw(Object, 1) (Line: 68)
> Symfony\Component\HttpKernel\HttpKernel-\>handle(Object, 1, 1) (Line: 57)
> Drupal\Core\StackMiddleware\Session-\>handle(Object, 1, 1) (Line: 47)
> Drupal\Core\StackMiddleware\KernelPreHandle-\>handle(Object, 1, 1) (Line: 99)
> Drupal\page\_cache\StackMiddleware\PageCache-\>pass(Object, 1, 1) (Line: 78)
> Drupal\page\_cache\StackMiddleware\PageCache-\>handle(Object, 1, 1) (Line: 47)
> Drupal\Core\StackMiddleware\ReverseProxyMiddleware-\>handle(Object, 1, 1) (Line: 38)
> Drupal\webprofiler\StackMiddleware\WebprofilerMiddleware-\>handle(Object, 1, 1) (Line: 52)
> Drupal\Core\StackMiddleware\NegotiationMiddleware-\>handle(Object, 1, 1) (Line: 23)
> Stack\StackedHttpKernel-\>handle(Object, 1, 1) (Line: 693)
> Drupal\Core\DrupalKernel-\>handle(Object) (Line: 19)

The code for the form is the following.

```
/**
 *@file
 *Contains \Drupal\rsvplist\Form\RSVPForm
 */
namespace Drupal\rsvplist\Form;

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

/**
 * Provides an RSVP email form
 */
class RSVPForm extends FormBase {

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

  /**
   * (@inheritdoc)
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $node = \Drupal::routeMatch()->getParameter('node');
    $nid = $node->nid->value;
    $form['email'] = array(
      '#title' => t('email address'),
      '#type' => 'textfield',
      '#size' => 25,
      '#description' => t("We will send updates to the email address you provide"),
      '#required' => TRUE,
    );

    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('RSVP'),
    );

    $form['nid'] = array(
      '#type' => 'hidden',
      '#value' => $nid,
    );

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    drupal_set_message(t('The form is working'));
  }

}

```

I am using Drupal 8.6.15 which runs on PHP 7.0.15.

Can anyone spot an error I am missing?

# Answer
> 0 votes
Line line 29:

$nid = $node-\>nid-\>value;

Try this solution:

```
$node->id();

```

Very useful thing "Drupal 8 Entity API cheat sheet": https://www.metaltoad.com/blog/drupal-8-entity-api-cheat-sheet

# Answer
> 0 votes
Someone else had the same problem - this is the reason:

"In the video the form shows the form with no warnings, but when I try it shows the following warning: Notice: Trying to get property 'nid' of non-object in Drupal\rsvplist\Form\RSVPForm-\>buildForm()

This is caused by getting $node = \Drupal::routeMatch()-\>getParameter('node'); in a page with any node. So it returns NULL and fails trying to get the nid from NULL.

So the code should be updated to provide a default nid when $node is NULL. I guess this form will be displayed just on node pages, so the route /rsvplist will not be used. So keep watching the videos."

# Answer
> 0 votes
Here is what you should add to your code to avoid the error you have when you're not on a node page (I have improved as well to the latest standards, you might have to adjust since you're using D8 and PHP7) :

```
$node = \Drupal::routeMatch()->getParameter('node');
$nid = 0;
if ($node instanceof NodeInterface) {
  $nid = $node->id();
}

```

Full code below :

```
<?php

/**
 *@file
 *Contains \Drupal\rsvplist\Form\RSVPForm
 */
namespace Drupal\rsvplist\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\node\NodeInterface;

/**
 *Provides an RSVP email form
 */

class RSVPForm extends FormBase {

  use StringTranslationTrait;

  /**
   * (@inheritdoc)
   */
  public function getFormId(): string {
    return 'rsvplist_email_form';
  }

  /**
   * (@inheritdoc)
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $node = \Drupal::routeMatch()->getParameter('node');
    $nid = 0;
    if ($node instanceof NodeInterface) {
      $nid = $node->id();
    }
    $form['email'] = array(
      '#title' => $this->t('email address'),
      '#type' => 'textfield',
      '#size' => 25,
      '#description' => $this->t("We will send updates to the email address you provide"),
      '#required' => TRUE,
    );
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('RSVP'),
    );
    $form['nid'] = array(
      '#type' => 'hidden',
      '#value' => $nid,
    );

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $this->messenger()->addMessage($this->t('The form is working'));
  }

}

```

---
Tags: 8, forms
---


# Question
Title: How do you override a module's template from another module?
I'm trying to override an email template of the webform module. The project is headless so we don't have a custom theme, and we'd like to stick with the Adminimal contrib theme. However, we do have a custom module named `app` in `web/modules/app`.

Here are the default template suggestions shown in the email source:

```
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'webform_email_html' -->
<!-- FILE NAME SUGGESTIONS:
   * webform-email-html--contact--email--email-notification.html.twig
   * webform-email-html--contact--email.html.twig
   * webform-email-html--contact.html.twig
   x webform-email-html.html.twig
-->
<!-- BEGIN OUTPUT from 'modules/contrib/webform/templates/webform-email-html.html.twig' -->

```

If I just create a `web/modules/app/templates/webform-email-html.html.twig` file (or any of the other suggestions), the template override doesn't work: the template of the webform module is used.

# Answer
> 2 votes
The only way I found to get template override to work is to:

1. add a template suggestion:
```
// in web/modules/app/app.module
function app_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  $suggestions[] = $hook . '--' . 'custom';
}

```
2. force the template used to render the `webform_email_html--custom` template suggestion:
```
// in web/modules/app/app.module
function app_theme($existing, $type, $theme, $path) {
  return [
    'webform_email_html--custom' => [
      'template' => 'webform-email-html--custom',
    ],
  ];
}

```
3. create the `web/modules/app/templates/webform-email-html.html.twig` file

I'm not marking this answer as accepted on purpose: please tell me there's a better way, this feels overly complicated! There doesn't seem to have a better way…

# Answer
> 1 votes
Thanks for this! I wanted to clean up the answer a little bit. This is essentially the same with a couple changes:

1. Instead of creating a new theme suggestion/hook for every hook already in the system, we create one only for the hook we want to create a new template for. This is a much less heavy handed approach.
2. As 4uk4 pointed out, dashes have been replaced with underscores.
3. As 4uk4 pointed out, we use `base hook` instead of `template` in our `hook_theme()` implementation.
4. We add `path` in our `hook_theme()` implementation, allowing us to sort templates within our module. In this case we put the template in `templates/webform`.

```
// In web/modules/app/app.module

/**
 * Implements hook_theme_suggestions_alter().
 */
function app_theme_suggestions_alter(array &$suggestions, array $variables, $hook) {
  // Use switch so we can easily add another hook in the future.
  switch ($hook) {
    case 'webform_email_html':
      $suggestions[] = $hook . '__' . 'custom';
      break;
  }
}

```

```
// In web/modules/app/app.module

/**
 * Implements hook_theme().
 */
function app_theme($existing, $type, $theme, $path) {
  return [
    'webform_email_html__custom' => [
      'base hook' => 'webform_email_html',
      'path' => $path . '/templates/webform',
    ],
  ];
}

```

---
Tags: theming, webforms, 9
---


# Question
Title: Routing with optional parameters for webform is just giving page not found
I created my webform to accept parameters via a standard `$_GET` and this works fine but is quite unsecure I am told and should rather use clean URL's via Drupal 8 built in Routing.

As such I set up a module to support my webform and contains only a `info.yml` and `routing.ynl`. The routing is as below, I got the format from Using parameters in routes but suspect I just haven't grasped it.

```
abc_enquire_form_routing.webform:
  path: /form/enquire/{type}/{region}/{destination}
  requirements:
    _permission: 'access content'
  defaults:
    type: 'tailor-made-holidays'

```

Normal form access is via http://abcsite.localhost/form/enquire

Form access with parameters as a get (For illustration) was: http://abcsite.localhost/form/enquire?type=tailor-made-holidays&region=asia&destination=48

Module name is: `abc_enquire_form_routing`

Trying to access the form with the module enabled with the above routing through http://abcsite.localhost/form/enquire/tailor-made-holidays is simply giving me a p **"The requested page could not be found."** error. So I can only assume I am doing the routing wrong.

What I am trying to achieve is three optional parameters after the "http://abcsite.localhost/form/enquire" page of the url, e.g. http://abcsite.localhost/form/enquire/tailor-made-holidays/asia/49

Can anyone point me in the direction of a good example of doing this with webforms module ?

# Answer
> 0 votes
I found really weird the response from *jrockowitz*. Because what you are asking **is indeed possible**.

If someone else needs a proper response for this question, then you can easily do this:

```
abc_enquire_form_routing.webform:
  path: /form/enquire/{type?}/{region?}/{destination?}
  requirements:
    _permission: 'access content'
  defaults:
    type: 'tailor-made-holidays'

```

That way if **don't** add the last three parameters you won't receive any error at all.

And of course you can use them as you want in your controller :)

Btw, you can also remove the **defaults key** if you don't need it:

```
 abc_enquire_form_routing.webform:
  path: /form/enquire/{type?}/{region?}/{destination?}
  requirements:
    _permission: 'access content'

```

Remember to **clear your cache** after this implementation.

---
Tags: 8, routes, webforms
---


# Question
Title: I have deleted Redirect module and have lost alias-to-alias redirects as well as the ability to show aliases in some nodes
I uninstalled and removed the Redirect module using these commands.

```
vendor/bin/drush un redirect
composer remove drupal/redirect

```

This caused me to lose about 15 alias-to-alias redirects.
I have also noticed that now, if I visit /node/1 and click on a link to /node/2, its path alias (/node/my-second-node) is not used.

Would re-installing the Redirect module be enough, or must I retrieve data from a backup as well?

# Answer
Restore the site from a backup or replace the redirects manually after reinstalling the module.
> 0 votes

---
Tags: redirection
---


# Question
Title: How to display taxonomy field value in paragraph twig file?
How to display role taxonomy field value in `paragraph--user-category.html.twig` file? Field structure: field\_role-\> role taxonomy field.

I can print by `{{ content.field_role | raw }}` But I need to display value text only.

I tried below the code and not working. Please advise. `{{ paragraph.field_role.entity.value }}`

Printed value: `{{ dump(paragraph.field_role) }}`

# Answer
> I tried below the code and not working. Please advise.
>
> `{{ paragraph.field_role.entity.value }}`

You say you need to display a value text only, but the referenced taxonomy term entity `paragraph.field_role.entity` doesn't have a `.value`. Taxonomy terms have a name:

```
{{ paragraph.field_role.entity.getname }}

```

You can get the `.id` as well and any field value `.field_foo.value`.

## Translation

If you have a multilingual site you need to translate the referenced entities:

```
{{ paragraph.field_role.entity|translation.getname }}

```

Install Twig Tweak in this case.

See https://git.drupalcode.org/project/twig\_tweak/-/blob/3.x/docs/cheat-sheet.md#entity-translation
> 1 votes

---
Tags: 9
---


# Question
Title: How to pass and receive an http request body in GET?
I have two Drupal sites within one project.

I want to send a GET request but I need to pass a lot of parameters. So instead of passing them in the query (which will lead to an extremely long URL), I want to include them in the request's body.

I know that using POST is preferable in this case but I cannot change this due to the specification of the project.

So my question is how exactly can this be done?

I am using a code like this on the sending side:

```
$options['query']['parameters'] = 'my parameters';
$options['body'] = 'the body';
\GuzzleHttp\Client::request('GET', $uri, $options);

```

On the receiving side I use this code:

```
$parameters = \Drupal::request()->get('parameters');

```

So how can I catch `$options['body']` on the receiving side too?

# Answer
> 2 votes
I don't know if this is allowed by spec, see the comment from @Hudri and https://stackoverflow.com/questions/978061/http-get-with-request-body, but it works.

When adding a body in a Guzzle GET request it ends up in a Drupal controller:

```
public function build(Request $request) {
  $body = $request->getContent();
  return ['#markup' => $body];
}

```

# Answer
> 0 votes
You can get the body content using Request-\>getContent() method.

Next I leave a full running example:

```
<?php

namespace Drupal\test_api\Plugin\rest\resource;

use Drupal\Core\Session\AccountProxyInterface;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpFoundation\Request;
use Psr\Log\LoggerInterface;
use Drupal\node\Entity\Node;

/**
 * Launches the given game
 *
 * @RestResource(
 *   id = "test_sample",
 *   label = @Translation("Test Sample"),
 *   uri_paths = {
 *     "canonical" = "/test/api/v1/sample"
 *   }
 * )
 */
class GameLaunchResource extends ResourceBase {

  /**
   *  A curent user instance.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $currentRequest;

  /**
   * Constructs a Drupal\rest\Plugin\ResourceBase object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param array $serializer_formats
   *   The available serialization formats.
   * @param \Psr\Log\LoggerInterface $logger
   *   A logger instance.
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   *   The current user instance.
   * @param Symfony\Component\HttpFoundation\Request $current_request
   *   The current request
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    array $serializer_formats,
    LoggerInterface $logger,
    AccountProxyInterface $current_user,
    Request $current_request
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
    $this->currentUser = $current_user;
    $this->currentRequest = $current_request;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->getParameter('serializer.formats'),
      $container->get('logger.factory')->get('sample_api'),
      $container->get('current_user'),
      $container->get('request_stack')->getCurrentRequest()
    );
  }

  /**
   * Responds to entity GET requests.
   *
   * @return \Drupal\rest\ResourceResponse
   */
  public function get() {
    $json = '';
    $content = $this->currentRequest->getContent();
    if (!empty($content)) {
      $json = json_decode($content);
    }

    return new ResourceResponse($json);
  }
}

```

About general specifications for GET, there is no specification for the BODY. So you can use it or not, accordingly to your needs. For example, when I have to retrieve a collection filtered by complex conditions I usually send all the conditions in the body, as the URI doesn't have room enough for all the data I need to send.

About specific specifications for GET in Drupal, it's not considered by default, but as I showed in previous example, you can get it through the Request object.

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