# Question
Title: Is it feasible to migrate by only migrating content?
I am preparing to do a Drupal 7 to Drupal 8 migration. This is not a pure like for like migration. Whilst many of the content types are similar there will be some differences between the Drupal 7 and Drupal 8 content types and paragraphs (i.e. site architecture improvements).

I would have thought that the easiest way to do the migration would be to completely rebuild the site in Drupal 8 and configure and customise it the way I want and then just migrate the content (e.g. users, taxonomy, nodes, etc.); however, according to the Drupal documentation one should not configure the site. From the Drupal "Preparing a site for upgrade to Drupal 8" page

> ### Do not configure the Drupal 8 site
>
> Keep in mind that the upgrade process will overwrite configuration on the Drupal 8 site, so do not do any configuration of the Drupal 8 site until after the upgrade process is complete. This means you do not have to create all the content types and fields manually before running this upgrade. The Migrate module will create them as a part of the migration process. In fact, it is a common best practice to install Drupal 8 using the Minimal install profile, because the Standard profile introduces its own configuration that you might not want to use.

Couldn't I just build and configure the Drupal 8 site just the way I like it and then just migrate the content being sure to customise the migration in order to adjust for any architectural changes? This idea of migrating all content and configuration and then making content changes afterwards doesn't make sense to me.

# Answer
**TL;DR: use Migrate and associated modules to do the heavy lifting, adding in your own code as needed.**

Yes, you absolutely can build your configuration first and then migrate content. I'd suggest the following outline approach (you'll still need to read the documentation for Migrate and these modules carefully):

1. Install the Migrate Tools and Migrate Upgrade modules.
2. Use migrate upgrade to generate prototype migration configuration, eg. `drush migrate-upgrade --legacy-db-url=mysql://user:pass@12.34.56.78/d6db --legacy-root=http://myd6site.com --configure-only`
3. Export the configuration and weed out any migrations that you don't need, such as content type and field definitions. Remove references to these from other migrations.
4. Edit the remaining configurations to your needs. This can be laborious and for some cases it may be easier to use custom hooks to manipulate data rather than configuring process plugins. However, the process plugins provided by core, supplemented by those from Migrate Plus, are very powerful once you understand them.

These modules will do much of the hard work for you so you can concentrate on the tougher problems you may face, such as dealing with embedded media tags that may require modules that are not ported to D8.

(If you are thinking of moving field collections to paragraphs, the D8 Paragraphs module has everything you need already in place).
> 2 votes

# Answer
The blurb you quote is re: *upgrading*. Upgrade has a specific meaning in the Drupal world. See Upgrading Drupal core.

> Upgrading a Drupal site means a change of a major version, for example from Drupal 6 to Drupal 8 or from Drupal 7 to Drupal 8.

Upgrading assumes you want to bring all of the site's structure to your new site, that you literally want the same site, but with a newer Drupal Core as the foundation. Conceptually, it doesn't make sense to make changes to the structure before upgrading. As a result, changes will be reverted or altered during the process.

However, its perfectly acceptable to build a new Drupal site and then migrate your old content to the new site where appropriate - I do this all the time. I usually hear this labeled a redesign or a rebuild, vs upgrade.

Whether you choose to Upgrade or Redesign/Rebuild and migrate content is a decision you'll have to make based on the pros and cons for your particular situation.
> 1 votes

---
Tags: 8, migrations
---


# Question
Title: How to allow multiple values in a single value textfield
I am using views\_conditional module for Drupal 7 and would like to use a comma separated array (i think this is called an array?) of values in the "This value" textfield.

For example, I would like to add a views conditional field that checks for:

**If this field...** \[type\] == Content Type

**Is...** Contains

**This value...** Apples, *(or)* Oranges, *(or)* Bananas

As it is right now, (unless I am missing something) I would need to add 3 separate conditional field. One for each content type (apples, oranges, and bananas) though they are all executing the same function.

(I think) The current definition for the value field is:

```
$form['equalto'] = array(
  '#type' => 'textfield',
  '#title' => t('This value'),
  '#description' => t('Input a value to compare the field against.  Replacement variables may be used'),
  '#default_value' => $this->options['equalto'],
);

```

I also think the logic for the "**Is...**" operator in this use case would technically need to be something like "*Contains Any*".

(I think) The "Contains" function is defined here:

```
      // Contains
  case 7:
    if (mb_stripos($r, $equalto) !== FALSE) {
      return $then;
    }
    else {
      return $or;
    }
    break;

```

Is there a way to simply write a couple of hooks to alter the form, or would i need a full blown module patch?

Any help or pointers would be greatly appreciated! I am pretty new to backend code. I also posted a support request at Drupal.org

# Answer
> 0 votes
There is a patch for this for anyone else looking for a solution.

https://www.drupal.org/project/views\_conditional/issues/2690167

---
Tags: 7, views, hooks
---


# Question
Title: How to allow the translation of menu links provided by my_module.links.menu.yml
I have the `Configuration Translation` module installed in a multilingual site and I am able to translate any menu created with the UI.... This is fine!!

I have a module which is creating some menus with the help of a yml static file: `my_module.links.menu.yml`

Unfortunately,

1-I couldn't translate any title/description (created in the yml) through in the UI as the translation tab is "locked" with this message : *This link is provided by the xxx module. The title and path cannot be edited.*

2-the **User interface translation** page (`/admin/config/regional/translate`) couldn't find the titles/descriptions (created in the yml) that I would like to translate

**More to add**: I have checked **Custom menu link** in the **Content language an translation** page (`/admin/config/regional/translate`) but this doesn't change anything... What is the purpose of this option?

...If someone can help me on this, I assume I will be able to use the provided solution to translate items created in other yml static files like `my_module.links.action.yml`

# Answer
Ensure you visited a page with these menu items at least once in the target language before trying to translate them at user interface translation. They need to be picked up first before appearing there and can only then be translated like any other UI string.
> 1 votes

---
Tags: i18n-l10n, navigation
---


# Question
Title: How to cache a view for all users of a role?
I have a view that displays a map. I need to display 7000 entries on the map. I have installed solar search API to index the content and have created a view using that. Still, the loading time for that view is around 1 minute for each user. After the first fetch, then it loads fast for that user since it fetches the data from the cache.

I was wondering whether I can cache the entire view for all users of a specific role. I tried installing the "Views Custom Cache Tags" module. But I am a bit lost on how to configure it. Also not sure whether this will solve my problem or not.

Suggestions, please.

# Answer
To answer the question title and the comment of @Leigh, without going into the details of the complexity of the specific View:

> How to cache a view for all users of a role?

Views are cached like any other rendered content. When rendered a View bubbles up the cacheable metadata of Views plugins, like filter or sorting plugins and the rendered content itself.

Additionally there are the three default contexts, as defined in the service container:

*core.services.yml:*

```
  required_cache_contexts: ['languages:language_interface', 'theme', 'user.permissions']

```

The context `user.permissions` is a hash of all of the user's permissions, which is the result of the roles assigned to a user.

So in the end a View is cached for user roles by default.
> 1 votes

---
Tags: 8, views, caching
---


# Question
Title: How do I create a table when a module is installed?
I want to add a custom table when a module I develop is installed. The code I am using doesn't seem to work, as the *post* table isn't created.

What is wrong with the code I am using?

```
/**
 * Installs the database schema.
 */
function mymodule_install() {
  drupal_install_schema('post');
}

/**
 * Uninstalls the database schema.
 */
function mymodule_uninstall() {
  drupal_uninstall_schema('post');
}

/**
* Creates the tables using the schema API.
*/
function mymodule_schema() {
  $schema['post'] = array(
    'description' => 'description pour la table post',
    'fields' => array(
      'pid' => array(
        'description' => 'post id',
        'type' => 'int',
        'not null' => TRUE,
      ),
      'title' => array(
        'description' => 'title',
        'type' => 'varchar',
        'not null' => TRUE,
      ),
      'body' => array(
        'description' => 'body',
        'type' => 'varchar',
        'not null' => TRUE,
      ),
      'created' => array(
              'description' => 'created',
              'not null' => TRUE,
              'mysql_type' => 'timestamp',
            ),
      'primary key' => array('pid'),
    ),
  );
}

```

# Answer
I see two problems with your `hook_schema` implementation.

1. You are missing a `return` statement at the end of your function to return the schema.
2. `primary_key` needs to be outside the fields array on the same level as the `fields` and the `description`.

---

```
/**
 * Implements hook_schema().
 */
function MYMODULE_schema() {
  $schema['post'] = [
    'description' => 'description pour la table post',
    'fields' => [
      'pid' => [
        'description' => 'post id',
        'type' => 'int',
        'not null' => TRUE,
      ],
      'title' => [
        'description' => 'title',
        'type' => 'varchar',
        'not null' => TRUE,
      ],
      'body' => [
        'description' => 'body',
        'type' => 'varchar',
        'not null' => TRUE,
      ],
      'created' => [
        'description' => 'created',
        'not null' => TRUE,
        'mysql_type' => 'timestamp',
      ],
    ],
    // primary_key needs to be outside the fields array.
    'primary key' => ['pid'],
  ];
  // Don't forget to return the schema.
  return $schema;
}

```
> 2 votes

---
Tags: 8, database, installation
---


# Question
Title: Programmatically change redirect after logout
I'm actually looking for a solution in Drupal 8 to change the redirection destination after visiting /user/logout page. I want to redirect the user on /user/login instead of home page.

Try this but not working, I'm still redirect on home page :

```
/**
 * @file
 * Contains my_module.module.
 */

use Symfony\Component\HttpFoundation\RedirectResponse;

function my_module_user_logout($account) {
  // We want to redirect user on logout.
  $response = new RedirectResponse("user/login");
  $response->send();
  return;
}

```

# Answer
The code is not correct for two reasons:

* The `RedirectResponse` class doesn't have a `send()` method. An object of that class is normally returned, but the function invoking `hook_user_logout()` doesn't use the value returned from that hook. (See the next point, which shows the code used to invoke `hook_user_logout()`.)
* In the case the code worked, it would redirect the user before the session for the current user is destroyed, which means the the currently logged-in user would not be logged in. In fact, the function invoking `hook_user_logout()` (`user_logout()`) contains the following code.

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

\Drupal::logger('user')->notice('Session closed for %name.', array('%name' => $user->getAccountName()));

\Drupal::moduleHandler()->invokeAll('user_logout', array($user));

// Destroy the current session, and reset $user to the anonymous user.
// Note: In Symfony the session is intended to be destroyed with
// Session::invalidate(). Regrettably this method is currently broken and may
// lead to the creation of spurious session records in the database.
// @see https://github.com/symfony/symfony/issues/12375
\Drupal::service('session_manager')->destroy();
$user->setAccount(new AnonymousUserSession());

```

It's clear that `hook_user_logout()` is first invoked, and then the account for the logged-in user is replaced with the anonymous account. If you were to find a way to redirect the users inside `hook_user_logout()`, you would be actually stopping Drupal from logging out the users.

Redirecting the users to the login page seems useless to me, since the controller for user/logout route already redirects the users to the front page.

```
public function logout() {
  user_logout();
  return $this->redirect('<front>');
}

```

If you want to allow the users to login again, it is sufficient to make the login block visible on the front page.

If you really needed to redirect the users to the login page when they log out, you should replace the controller for the logout page with a different one that redirect users to the login page.

```
class MyModuleUserController extends ControllerBase {

  /**
   * Constructs a MyModuleUserController object.
   *
   */
  public function __construct() {}

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static();
  }

  /**
   * Logs the current user out.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   A redirection to home page.
   */
  public function logout() {
    user_logout();
    return $this->redirect('user.logout');
  }

}

```

Notice that `ControllerBase::redirect()` requires a route name, not a URI.

For how to alter an existing route, see Altering existing routes and adding new routes based on dynamic ones.
> 5 votes

# Answer
`hook_user_logout()` doesn't expect a redirect response object and won't respond to it.

One alternative here, if you don't need a programmatic forcing of redirection, is to use the `destination` query parameter. The path supplied in the parameter will be redirected to upon logout. For example: **http://example.com/user/logout?destination=user/login** will return a user to the login page following logout.
> 5 votes

# Answer
```
namespace Drupal\module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\RedirectResponse;

class ModuleLogoutController extends ControllerBase {

  public function logout($dest)
  {
    global $base_url;

    \Drupal::service('session_manager')->destroy();

    $response = new RedirectResponse($base_url . '/' . $dest);
    $response->send();

    return;
  }

}

```
> 1 votes

---
Tags: users, 8, redirection
---


# Question
Title: Form textfield AJAX validation "deletes" injected services to form
I'm trying to create a form that has two services injected (for access to an API) and a textfield with an AJAX callback. Here it is:

```
public function buildForm(array $form, FormStateInterface $form_state) {
    $form['vat_number'] = [
        '#title' => $this->t('VAT Number'),
        '#type' => 'textfield',
        '#default_value' => isset($address['vat_number']) ? $address['vat_number'] : '',
        '#states' => [
          'visible' => [
            ':input[name="is_business"]' => ['checked' => TRUE],
          ],
          'required' => [
            ':input[name="is_business"]' => ['checked' => TRUE],
          ],
        ],
        '#ajax' => [
          'callback' => '::validateVatAjax',
          'event' => 'change',
          'url' => Url::fromRoute('shop_product.digital_river_payment_form'),
          'options' => [
            'query' => [
              FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
            ],
          ],
        ],
        '#suffix' => '</div>',
      ];
    }
.....
}
public function validateVatAjax(array &$form, FormStateInterface $form_state) {$response = new AjaxResponse();
    $message = '<div id="errors" class="alert alert-danger" role="alert">';

    if (!$this->customerService->validateCustomerTaxFormat($form_state->getValue('vat_number'))) {
      $message .= $this->customerService->$schema['properties']['value']['description'];
      $message .= '</div>';
    }
    else {
      $message = '<div id="errors" class="alert alert-danger hide" role="alert"></div>';
    }
    $response->addCommand(new ReplaceCommand('#errors', $message));
    $form_state->setRebuild(FALSE);
    return $response;
  }

public function validateForm(array &$form, FormStateInterface $form_state) {
if ($form_state->getValue('is_business') == 1) {
        $vat_number = $form_state->getValue('vat_number');
        if (empty($vat_number)) {
          $form_state->setErrorByName('vat_number', $this->t('Please enter your tax number.'));
        }
        elseif (!$this->customerService->validateCustomerTaxFormat($form_state->getValue('vat_number'))) {
          $schema = $this->customerService->getSchema();
            $form_state->setErrorByName('vat_number', $schema['properties']['value']['description']);
          }
          else {
            $form_state->setErrorByName('vat_number', $this->t('Please enter your VAT number including the two letter country code.'));
          }
        }
      }
}

```

I omitted some of the code but my problem is that on the second AJAX call to the callback, it fails because the customerService is null. Aside from that, I don't understand why validateForm() is called on the textfield input change. Is this normal for Drupal?

Thanks in advance.

# Answer
> 1 votes
For anyone running into this problem or AJAX call that fails on the second call intermittently, check the properties used on your AJAX form class for the right access. It seems a trivial thing but change the properties of DInjected services to ***protected***. Refrain from using ***private*** as the dependency serialization from Drupal won't be able to get those for caching purposes.

Check this link for more information.

---
Tags: forms, ajax
---


# Question
Title: How to render a node on behalf of another user (as an admin or without accessCheck)
**Context** : I use the following code to replace a token by a rendered node.

The resulted text is sent by email

```
$renderable = $view_builder->view($node, 'token', $langcode);
$replacements[$original] = \Drupal::service('renderer')->renderPlain($renderable);

```

This is working fine except when **I am queuing the mails to be sent**

Because, in this case, the upper code runs in a queue and `NodeAccessControlHandler::checkAccess` and `NodeAccessControlHandler::checkFieldAccess` are called with an anonymous account (id=0).

This leads to an `AccessRessult::forbidden()` (because in my setup, anonymous can't see those fields and/or this node) and the rendered node is empty...

**Thus my question is**:

How to render a node (in a queue) "in behalf of" an admin user?

or

How to explain to my overrided `NodeAccessControlHandler` that we are in a queue and that it can safely give access (without security concerns)

# Answer
Thanks to the comment of **@No Sssweat** I could find a solution:

**Summary**: the problem appeared when emails were sent via a queue in a cron. The cron is running as an anonymous user, and, in this case, the drupal viewBuilder/Rendering system doesn't have enough permission to display some fields/nodes.

**Solution**: Adapt the `processItem` function of the QueueWorker in order to switch the current user into an admin user at the beginning of the process and switch back at the end.

I my use case, I overrode the QueueWorker provided by another module. Here is my code with the injection of the switcher service: (feel free to comment)

```
/**
 * The account switcher service.
 *
 * @var \Drupal\Core\Session\AccountSwitcherInterface
 */
protected $accountSwitcher;

public function __construct(array $configuration, $plugin_id, $plugin_definition, SubscribersInterface $subscribers, AccountSwitcherInterface $account_switcher)
{
    parent::__construct($configuration, $plugin_id, $plugin_definition, $subscribers);
    $this->accountSwitcher = $account_switcher;
}

public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition)
{
    return new static($configuration, $plugin_id, $plugin_definition, $container->get('message_subscribe.subscribers'), $container->get('account_switcher'));
}

public function processItem($data)
{
    $this->accountSwitcher->switchTo(new UserSession([
        'uid' => 1,
        'name' => 'cron_admin',
        'roles' => ['administrator'],
    ]));
    parent::processItem($data);
    $this->accountSwitcher->switchBack();
}

```
> 0 votes

---
Tags: entities
---


# Question
Title: Views + Search API not properly sorting by Commerce Price (seems random)
I have a search index View of product variations. The commerce\_price field is indexed and exposed as sort option. However, when sorting by the price it appears mostly in order (Asc or Desc) but some items are not in the proper order (see screenshot)

I've tried indexing the price field as an integer, decimal, and string but it always has the same effect.

There are no additional sort items. There are not any price adjustments or custom calculations. There is no custom code affecting the Views or pricing. I've tried wiping and rebuilding the index multiple times. The View is using Better Exposed Filters.

Any ideas how I can get the products to sort by price correctly?

# Answer
> 0 votes
Resolved. Not sure exactly what is/was going on but the price sorting is now working. There was another identically named commerce price field in Views. Adding that field and removing the first one fixed the issue. I know, something unusual appears to be going on but at least the sorting is working now.

---
Tags: commerce, search
---


# Question
Title: How to prevent a node being saved when using the Rules module?
Is it possible to prevent a node from being saved with Rules? This is what I do now:

* `Create a rule Before saving content of type ''.`

+ Condition: IF ...
        - TRUE =\> Redirect & set message
* `Create a rule After saving content of type ''.`

+ Calculate & set value

So when a condition is true before saving I want to redirect the user, show a message and DON'T save node.

When it's not true I want to save the node and do the actions in the `after saving content of type` rule.

The problem is that when the condition is true in the first rule, the redirect and set message is performed. But directly afterwards the node is saved and the actions in the other rule are executed.

How can I make sure that the second rule doesn't get executed? Can I do this without custom code?

# Answer
I would try to use the Conditional Rules module for this. Some more details about this module (from its project page):

> ... provides Rules plugins for conditionally altering execution flow directly inside a group of **actions**.

So create a rule in which you add these actions:

* **Conditional** (which you add via the 'Add conditional' link at the bottom)
* **If Condition** (which you add via the 'Add If' link to the right of the 'Conditional' action, and 'Condition' is what you mentioned in your first rule already).
* **Redirect & set message** (which you add via the 'Add Action' link to the right of the 'If' action, and 'Redirect & set message' is what you mentioned in your first rule already).
* **Else** (which you add via the 'Add Else' link to the right of the 'Conditional' action.
* **Calculate & set value** (which you add via the 'Add Action' link to the right of the 'Else' action, and 'Calculate & set value' is what you mentioned in your second rule already).

Here is a screenprint of a rule with an action that uses Conditional Rules (though only with an "if"-part here, no "else"):
> 2 votes

# Answer
You can use node form validation with the Rules Forms Support module.This will allow a node not to be saved when performing rules actions.
> 0 votes

# Answer
An easy solution that I use myself (no need for additional modules or php code), is to unpublish the node when the condition is not met. In that way, saving the node is not an issue, and the form data is still available in the unpublished node. Then redirect to the unpublished node and show the message.
> 0 votes

# Answer
You could hide the "save" button with jQuery based on the settings of the field that you want to check against with a simple `display:none;` CSS setting AND Use Page Manager to show a message in a panel, also with a simple `display:block;` It's not really waterproof but most users wouldn't go fiddling with the CSS. And together with the "unpublish" solution offered by Yuri, that should solve your issue.
> 0 votes

---
Tags: rules, redirection, nodes
---


# Question
Title: How do I translate the weekday in a date?
I created a view from a JSON file; the dates in that file follow the *2020-07-28 20:00* format. I do a rewrite of the date to `<span>{{ value_1|date("l d/m/Y") }}</span>` and I get *Tuesday 28/07/2020*, but I want to get the weekday in Dutch.

Is there code for this?

# Answer
> 2 votes
Use the below example as a temporal solution, I'm not sure if this is the proper way. The approach is to split the problem.

```
{{ value_1|date("l")|t }} {{ value_1|date("d/m/Y") }}

```

Regarding the next link, the proper use of translation on twig is using "t" filter. How do I translate strings in Twig templates?

---
Tags: views, i18n-l10n, datetime
---


title: Webform variants as blocks

text:
# Question
Title: Webform variants as blocks
Drupal 8.9, Webforms 5.x

I have a load of forms that are all basically the same, except for the confirmation URL (a download link, essentially) and some minor tweaks to the handlers.

In an effort to reduce duplication, I've been looking into the possibility of using variants for this. I can create all the variants easily enough, but I'm at a loss as to how to include these on the correct pages.

The form itself is included in the layout of the content type as a block and I can specify a specific variant there via default submission data (as per image) but that's a single variant for the whole content type rather than a specific variant for a single page.

What's the best way to do this? Is it actually possible with variants at all? Or perhaps there's some other solution I've missed

# Answer
> 0 votes
So the eventual answer wasn't variants at all, but webform nodes. Inserting a webform block into the content type's layout enabled me to use the `[webform-submission:source-entity:foo]` tokens, which were exactly what I wanted.

Important to note that you have to enable the "Webforms Node" extension for this (I've not seen this mentioned anywhere, so was confused about where the "References" tab was)

# Answer
> 0 votes
You could create a hidden redirect URL element, which is then used as the confirmation redirect URL. The hidden redirect URL element can be populated using the 'Default webform submission data.'

---
Tags: 8, webforms
---


# Question
Title: Views exposed filters without "Apply" button
I have created a view with exposed filters of term select list. How can I make the select list to work directly on selecting an item, instead of clicking on the "Apply" button?

# Answer
Under advanced portion of view choose following

```
**Exposed form**

 Exposed form style: Basic | Settings

```

Then Choose autosubmit in Settings as shown below

This will hide the Apply button and the select list to work directly on selecting an item, instead of clicking on the Apply button.
> 26 votes

# Answer
For Drupal 8/9, You need the following module: https://www.drupal.org/project/views\_autosubmit
> 3 votes

# Answer
If you're using **Drupal 8**. Choose **Exposed form style** as **Autosubmit** and then in **Settings** check Hide **submit button checkbox**.
> 0 votes

---
Tags: 7, views
---


# Question
Title: How do I redirect a domain but keep the URL structure?
I have example.com and example.co.uk. They both point to the same Drupal installation on my server, so both domains load the exact same site.

I am now trying to redirect the .co.uk to the .com domain. I have tried using the following lines in the .htaccess file, but it always redirects to /index.php.

```
RewriteCond %{HTTP_HOST} ^example.co.uk
RewriteRule ^(.*) https://example.com/$1 [P]

```

The following lines didn't work either.

```
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example\.co.uk$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]

```

The site redirects. but it doesn't keep the URL structure as it should. If I go to example.co.uk, I get redirected to example.com. If I go to example.co.uk/node/1, I get redirect to example.com/index.

How can I set up the correct redirect?

# Answer
Your second variant is close to the goal. But it needs some edits. Firstly, you should escape all dots in RewriteCond, so it will be

```
RewriteCond %{HTTP_HOST} ^example\.co\.uk$ [NC]

```

Secondly you need to edit RewriteRule to change regular expression and append request uri:

```
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

```

It also matters where you place the code. Your second variant is right. It's best to place code just after `RewriteEngine on`

Final code will be:

```
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example\.co\.uk$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

```
> 3 votes

---
Tags: 7, redirection, .htaccess
---


# Question
Title: where in database is renamed login for 'Rename Admin Paths"
A little embarrassing - I've lost/forgotten the login page for a Drupal 8.9 website. It was renamed using the module "Rename Admin Paths."

I've gone to the module page at drupal.org and looked through issues and comments, but none of the solutions I found will work.

This site is unable to install Composer or Drush at this time, so I can't use any method there. Another suggestion was to search the 'variables' table - but that was specific to D7, I believe. I don't see that table.

I've commented within their page hoping to find the answer, but maybe someone here happens to know the answer?

# Answer
Look in the `config` and `key_value` tables for "rename\_admin\_paths.settings"
> 1 votes

---
Tags: 8, database
---


# Question
Title: Set Default Value for Image Field contain Multiple Images
I've added a multiple image field to the user account that uses the `multiupload_imagefield_widget` and it works when I edit the account.

On the other hand, I have a custom module with a form that I would like to edit just this field (I have a submit handler to update the user data). I call `user_load` to display the data and I can see the data is there in the debugger, but no images are displayed on the form.

What do I have to do to make them show up?

Here's my code:

```
$user_data = user_load($user->uid);
$form['my_imageGallery'] = array(
  '#type'             => 'image',
  '#title'            => t('Image Gallery'),
  '#default_value'    => isset($user_data->field_galeria) ? $user_data->field_galeria : null,
  '#upload_location'  => 'public://user_galleries/',
  '#upload_validators' => array('file_validate_extensions' => array('png jpg gif')),
);

```

# Answer
> 0 votes
I think you need to use a `managed_file` form element.

```
$user_data = user_load($user->uid);
$form['my_imageGallery'] = array(
  '#type'             => 'managed_file',
  '#title'            => t('Image Gallery'),
  '#default_value'    => isset($user_data->field_galeria) ? $user_data->field_galeria : null,
  '#upload_location'  => 'public://user_galleries/',
  '#upload_validators' => array('file_validate_extensions' => array('png jpg gif')),
);

```

---
Tags: 7, forms
---


# Question
Title: Why does the login form become unusable after I removed all content from input.html.twig?
Actually I am stuck in a big problem . i am using input.html.twig file and i remove all the content from that and then when i see my default registration form and user login form which is prebuild in drupal 8 . i didn't see any input fields and so that due to this i don't login in drupal site. so anyone please help me what can i do All fields was dissapear there is no buttoon no input fields. someone please give me some idea about this. i am working on my local.  I use drush command in terminal but it says that drush command not found. so how i clear the cache . And also i put the original file in the folder and replace previous file but not working.

# Answer
> 2 votes
> Why does the login form become unusable

Because `input.html.twig` is "Default theme implementation for an 'input' #type form element". If it's empty, there will be empty string in place of all `<input>` tags.

If you have cleared content form `input.html.twig` placed in your custom theme, just completely remove input.html.twig file and clear the cache. In that case Drupal will use corresponing core template file, so functionallity will be restored.

If you have cleared content of `input.html.twig` in core or contrib theme folder (which is strongly not recommended), you should restore it's original content. Which can be taken at corresponding project page at Drupal.org from archive or found at repository git.drupalcode.org. For example here https://git.drupalcode.org/project/bootstrap if you use Bootstrap theme.

**To clear the cache** in your case without access to admin interface or drush there is one extra method:

Add to sites/default/settings.php

```
$settings['rebuild_access'] = TRUE;

```

Open in browser `http://yoursite.com/core/rebuild.php`

More info here https://www.drupal.org/docs/user\_guide/en/prevent-cache-clear.html#s-using-the-rebuild-script

Don't forget to remove `$settings['rebuild_access'] = TRUE;` from settings.php after clearing the cache.

---
Tags: 8, theming
---


title: Make node only accesible by path alias

text:
# Question
Title: Make node only accesible by path alias
I was wondering if it's possible to make nodes without path alias not accessible. By this I mean that visiting /node/$nid/ users will not be able to see its content, but if that node has an path alias (e.g. /myarticle/my-article-name/) the node will be visible using the path alias.

Is it possible to achieve it with code?

By researching, I found that I can do this in `hook_menu()` with either `$items['node/%node']['page callback'] = 'drupal_not_found';` or `$items['node/%node']['access'] = FALSE;`.

The problem is that I can't access with /node/$nid/ and without /myarticle/my-article-name/, it raises permission denied.

# Answer
> 0 votes
`hook_menu()` is not the hook to alter the routes defined from other modules, but in this case not even `hook_menu_alter()` would help.

When users access a page using a path alias, Drupal gets the normal path (i.e. the path to which the path alias points) before rendering the page. So, for Drupal, users are always visiting /node/$nid, not /myarticle/my-article-name/. In fact, `drupal_path_initialize()` (called at bootstrap time) contains the following code.

```
  if (empty($_GET['q'])) {
    $_GET['q'] = variable_get('site_frontpage', 'node');
  }
  $_GET['q'] = drupal_get_normal_path($_GET['q']);

```

`drupal_get_normal_path()` is the function converting the path alias in the internal path.

In this case, a redirect from /node/$nid to /myarticle/my-article-name/ is, IMO, the solution. The Global Redirect module already does that, as the project page describes.

> 1. Checks the current URL for an alias and does a 301 redirect to it if it is not being used.
> 2. Checks the current URL for a trailing slash, removes it if present and repeats check 1 with the new request.

Also, notice the *Why?* section on that page.

> Once enabled, an alias provides a nice clean URL for a path on a site. However Drupal does not remove the old path (eg node/1234). The problem is that you now have two URLs representing the same content. This is dangerous territory for duplicate pages which can get you sandboxed by the search engines!

# Answer
> 0 votes
I have searched all over, and pretty much in all cases, no one understands the problem. I don't have the answer, but can only provide more clarity for the problem, and a suggestion for the best place for a solution ...

THE PROBLEM

1. BLOCK access for anonymous users using /node/{nid} in the PATH
2. Still render the page for anonymous users USING THE ALIAS for the node
3. AGAIN, 1. BLOCK access for anonymous users (NOT ALL USERS) using /node/{nid} (stating this again, because most solutions are about redirecting, and that does not block.
4. Make sure that authenticates users can still edit the node, which will contain /node/{nid} in the path

WHY DO WE WANT TO BLOCK access to the node using /node/{nid} in the path? Because, it is easy for anyone to get access to information by just modifying the path ... going /node/1, then /node/2, then /node/3, etc. With pathauto, the alias are shown, but the content is found. And what is the use of a complex pathauto, if there are 2 ways to get to the content ... not just for SEO, but also for just not simply wanting to give people easy access to all info. E.g. when usign pathauto with hash alias for the content.

PROPOSED SOLUTION

1. A modification of PathAuto will be the best solution as it handles the redirect from node/{nid} to alias and alias to /node/{nid}
2. PathAuto requires a feature/setting whereby admin can indicate that the internal path needs to be CLOAKED for anonymous users (by pattern, or specific to a node).
3. If internal path is CLOAKED, then requests from anonymous users using /node/{nid} must redirect to a defined node indicating whatever, e.g. NO ACCESS, or just defining the node as the FRONT PAGE. This will effectively BLOCK access using /node/{nid}.
4. If the request uses the alias in the path, then all good to access the node - regardless of user role.

SOLUTIONS THAT WILL NOT WORK

1. Any .htaccess solution - because htaccess does not know if the user is anonymous or authenticated in Drupal.
2. Any global redirect solution to the alias - because redirect does NOT BLOCK the content when using /node/{nid} in the path
3. Any other module used together with PathAuto, as they will have conflicting logic, and this usage scenario is a modification of how pathauto should handle redirects for anonymous users.

Hoping that this helps you and others to eventually get a solution. It is a pretty simple and anoying problem with Drupal - 2 accesses to the content, and 1 giving a particularly easy way for people to dig through info on your site, when you need just a slight bit of hiding, especially when the use case scenario does not warrant authentication overhead.

# Answer
> 0 votes
I've created a module and is busy adding it to Drupal site. The code is available here for download.

https://github.com/hornlp/drupal\_path\_guard

The intended use of the module is to redirect GUEST / ANONYMOUS users when they access content in Drupal using URL /node/{id}. Many sites make use of URL ALIAS and don't want users necessarily to scan content out of context using /node/{id}.

The module simply "hooks" into / subscribes to kernel.request and matches the request uri with a regular expression that is configured (default is '~/node/d\*~i'). If there is a match, and the user is ANONYMOUS, it will route the user to a route that has been configured (default set to '/home').

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


# Question
Title: Updating drupal/core using composer: "[RuntimeException] Could not delete web/core" (using Lando)
Trying to update Drupal 8 core.

```
composer require drupal/core:~8.9.2 --no-update

```

This works fine.

```
composer -vvv update

```

It fails with the following:

```
  - Updating drupal/core (8.8.5 => 8.9.2):     Update failed (Could not delete web/core: )
Would you like to try reinstalling the package instead [yes]? yes
  - Removing drupal/core (8.8.5)

[RuntimeException]
Could not delete web/core:

```

What's the easiest and/or correct way to resolve this?

(This has happened to me before but can't remember what I did to fix it)

# Answer
> 1 votes
OK - so composer does not have read/write access to the folder. I've also seen some people mentioning composer timeouts being the problem.

In my case I am using Lando for my dev environment ands listed `web/core` as one of the excludes:

```
excludes:
  - web/core

```

This meant the core files were not available to the container. If I remove core from the excludes then it works fine.

---
Tags: 8, composer
---


# Question
Title: Change workbench moderation state with VBO does not work properly
I have two workbench moderation states `draft` and `publihsed`

When I try to change the state of a node from `draft` to `published` using VBO's `set moderation state` action, It actually republish the `published` revision. While it should publish the draft revision.

In the screenshot, it move the `draft` to `published` with revision `4` and that should be the published revision. But it is pointing to the revision 3 that this is the published revision.

Is there any workaround for this issue?

Any hint where to look?

# Answer
> 0 votes
The patch in https://www.drupal.org/project/workbench\_moderation/issues/3160301#comment-13758806 fixes the issue.

---
Tags: 7, views, workbench, actions
---


# Question
Title: How do you implement a custom submit handler in hook_form_alter()?
I've been updating one of my Drupal 7 modules to 8 and I'm having an issue with my form alter. I'm adding a validation function and a submit handler. The validation function is getting called just fine, but the submit function is not getting fired. I'm wondering if this means there is a Symfony-style approach that needs to be taken to adding submit handlers to existing forms. I've done a lot of searching and I can't find any examples. Also looked through some work-in-progress D8 modules but I haven't really found any working examples there either.

Does anyone have any idea what the correct Drupal 8 way to do this is?

# Answer
> 16 votes
According to the example in the documentation it's the same as for Drupal 7:

```
$form['actions']['submit']['#submit'][] = 'mymodule_upload_enabled_types_submit';

```

You can find similar (working) logic in

And a few others besides.

# Answer
> 6 votes
You can add how many submit handler you want using the following code:

```
 $form['actions']['submit']['#submit'][] = 'mymodule_what_ever_function';

```

If you want to add a submit handler **after** the default submit handler, (a submit handler that will be called after the submit callback), you can use the following.

```
$form['#submit'][1] = test_function;

```

To remove the submit handler:

```
unset($form["actions"]['submit']);

```

# Answer
> 3 votes
The behavior is either changed or differs from case to case. With the Node Delete Multiple confirmation form

```
$form['actions']['submit']['#submit'][] = 'mymodule_upload_enabled_types_submit';

```

@Clive's code causes Drupal to ignore the main handler. In this case add the handler to the `$form['#submit']` section:

```
$form['#submit'][] = 'mymodule_upload_enabled_types_submit';

```

# Answer
> 1 votes
Here's how to attach a custom submit handler to the article node add/edit form in Drupal 8:

```
<?php

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_alter().
 */
function my_module_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Use this to reveal the form id.
  //drupal_set_message($form_id);

  // Use this with the devel module to inspect the button action(s).
  //kint($form['actions']);

  switch ($form_id) {

    case 'node_article_form':      // New article nodes.
    case 'node_article_edit_form': // Existing article nodes.

      // Attach our custom submit handler.
      $form['actions']['publish']['#submit'][] = 'my_module_node_article_form_submit';
      break;

  }

}

function my_module_node_article_form_submit($form, FormStateInterface $form_state) {
  drupal_set_message('Running custom submit handler...');
}

```

I was not able to successfully append a custom submit handler to `$form['#submit']` and have the function fire properly. I *had* to explicitly attach it to the **Save and publish** button when creating a new article, and attach it to the **Save and keep published** button when editing an existing article.

Besides `publish`, here are some of the other button actions available:

```
unpublish
preview
delete

```

# Answer
> 0 votes
To replace/override the existing handler in Drupal 9 this worked for me:

```
**
 * Implements hook_form_FORM_ID_alter()
 */
function MODULE_NAME_form_FORM_ID_alter(&$form, $form_state, $form_id) {

  $form['submit']['#submit'][] = 'custom_submit';
}

function custom_submit($form, $form_state) {
  \Drupal::messenger()->addStatus(t('Submit overriden by custom_submit!'));
}

```

---
Tags: forms, 8
---


# Question
Title: How do I change the current language in a Kernel test?
I'm writing a test for something that returns a Url from an entity. This should be language-aware, so the test needs to change the current language.

I started off writing a Kernel test for this, because they're faster, but I can't figure out how to make the test code change the current language:

```
  public static $modules = [
    'system',
    'user',
    'language',
    'content_translation',
    [SNIP]
  ];

  protected function setUp() {
    parent::setUp();

    $this->installConfig(['language']);
    $this->installEntitySchema('configurable_language');

    $this->languages['de'] = ConfigurableLanguage::createFromLangcode('de');
    $this->languages['de']->save();

    $config = $this->config('language.negotiation');
    $config->set('url.prefixes', [
      'en' => 'en',
      'de' => 'de',
    ])->save();

    \Drupal::service('kernel')->rebuildContainer();
    \Drupal::service('router.builder')->rebuild();
    $this->languageManager = $this->container->get('language_manager');
    $this->languageManager->reset();

    [SNIP]
  }

  public function testCurrentLanguageChange() {
    // Change the site's current language.
    dump(\Drupal::languageManager()->getCurrentLanguage());

    \Drupal::service('language.default')->set($this->languages['de']);

    dump(\Drupal::languageManager()->getCurrentLanguage());
  }

}

```

In the test code above, both dump() calls output the 'English' language object.

# Answer
> 2 votes
Looks like I needed to call:

```
    \Drupal::languageManager()->reset();

```

No, wait, that doesn't seem to be the whole story.... ARGH.

EDIT:

For the entity to be treated as translatable and so return the right URL, I also needed to set the bundle as translatable:

```
    $this->entityTypeManager->getStorage('language_content_settings')->create([
      'target_entity_type_id' => 'node',
      'target_bundle' => 'page',
    ])->save();
    $this->container->get('content_translation.manager')->setEnabled('node', 'page', TRUE);

```

---
Tags: i18n-l10n, testing
---


title: How to save an image resource

text:
# Question
Title: How to save an image resource
I have brought an image in from an API and cropped it using imagecrop in a custom module. I now have an image resource. But I cannot figure out how to turn the resource into a file I can save in Drupal or just save the resource directly as a file through Drupal. I have tried variations of file\_get\_contents and file\_save\_data. Any help would be appreciated.

When I use the following:

```
$cropped_image = imagecrop($image_resource, $rect);
$final_file = file_save_data($cropped_image);
$type = array('type' => $content_type);
$node = \Drupal::entityTypeManager()
  ->getStorage('node')
  ->create($type);
$node->field_image = array(
  'target_id' => $image_file->id(),
);
$node->save();

```

I get the error "Call to a member function id() on bool in" on the $node-\>field\_image line. That has made me think that the resource is not getting saved into a file with file\_save\_data() (obviously, not exactly sure what is happening).

When I included a file\_get\_contents($cropped\_image) and then process that through file\_save\_data (as I do when I bring in an image from a URL), I end up with an error that the system is unable to handle the request in nothing in the recent log messages.

I have tried various other methods as well with no joy.

# Answer
> -1 votes
I may have had the code correct at some time yesterday, but I was running out of memory on my localhost. I ended up rewriting some of the code and - once I realized I was having memory issues - moved everything onto the server, where it all worked like a charm. Sorry for asking the question. And, thanks, Simon, for provoking me to question everything anew with your comment.

Here is my final code;

```
            $cropped_image = imagecrop($precrop_resource, $rect);
            imagedestroy($precrop_resource);

            $file_path = \Drupal::service('file_system')->realpath('public://');
            imagejpeg($cropped_image, $file_path . '/temp-image.jpg');

            // load the image
            $cropped_data = file_get_contents($file_path . '/temp-image.jpg');
            $cropped_file = file_save_data($cropped_data);
            unset($cropped_data);

```

Then I added the image to the node object and saved the node.

EDIT:

I eventually realized a couple issues with the above code. First, it was not just my memory on the localhost; processing 10MB+ jpegs would exhaust the memory on the server as well because the GD2 image tools process everything in uncompressed format. Second, the files were saving without .jpg on their filenames, so using them could be a problem.

So, I ended up using the ImageMagick to process things and added another variable to the file\_save\_data function call.

Here is my new and improved final code:

```
            // crop the image
            $precropped_image = new Imagick($precrop_file->getFileUri());
            $precropped_image->cropImage($rect['width'], $rect['height'], $rect['x'], $rect['y']);
            $precropped_image->writeImage($file_path . '/temp-image.jpg');

            // save the cropped image in the Drupal DB
            $cropped_data = file_get_contents($file_path . '/temp-image.jpg');
            $cropped_file = file_save_data($cropped_data, 'public://' . $image_title . '-og.jpg');

```

---
Tags: 9
---


# Question
Title: How to change the name of site only for the developers?
I am new on Drupal 8 , in order to change the site name and the slogan , I want to change the site name just for the developers used my website

is there any way to do that?

I have implemented a code but I want to do it for just developers , is there any hook any way to do that?

```
$config = \Drupal::service('config.factory')->getEditable('system.site');
$config->set('name', "XXXXXXX");
$config->save();

```

# Answer
The most common way to use a settings.local.php file that is outside of your git repo. Each developer can use this to setup their local environment with local DB, etc.

I tend to have a settings.local.php.example file in the repo that dev can copy to their settings.local.php file.

This file can contain any Drupal overrides you want, e.g.: As Leymannx said: `$config['system.site']['name'] = 'Foobar'`.

See the docs on overrides for some details.

Drupal also has an example of settings.local.php.

You can also use this to do things like turn off caching and security checks locally.

NOTE: I think the current settings.php files automatically include a test / load for the settings.local.php file. If not, just search for how to make sure it gets loaded.
> 2 votes

---
Tags: 8, configuration
---


# Question
Title: Runtime Exception - no weight or dimension field after importing
Drupal 8 - Commerce 2 has its import from Ubercart now in the Commerce Migrate module. Field text data was left behind, and it is its own issue - see below

At admin/commerce/config/product-variation-types for what did import was the product types and products themselves, and if I try to edit the imported "Product", Product\_kit" or "uc\_recurring" variation to make it shippable with dimensions a Runtime Exception error is thrown that no "dimension" or "weight" field exists.

> RuntimeException: The field "dimensions" does not exist on bundle "product" of entity type "commerce\_product\_variation". in Drupal\commerce\ConfigurableFieldManager-\>hasData() (line 119 of modules/commerce/src/ConfigurableFieldManager.php). Drupal\commerce\EntityTraitManager-\>canUninstallTrait(Object, 'commerce\_product\_variation', 'product') (Line: 77) . . . . more (for Product)

and

> RuntimeException: The field "weight" does not exist on bundle "product\_kit" of entity type "commerce\_product\_variation". in Drupal\commerce\ConfigurableFieldManager-\>hasData() (line 119 of modules/commerce/src/ConfigurableFieldManager.php). Drupal\commerce\EntityTraitManager-\>canUninstallTrait(Object, 'commerce\_product\_variation', 'product\_kit') (Line: 77) . . . . more (for Product\_kit)

For "uc\_recurring" it throws the first one listed.

I did try adding the fields at /admin/commerce/config/product-variation-types/product\_kit/edit/fields it took them for "products" but stated duplicates could not be used for the others, so I stopped.

However, with Devel / product generate it does not work. The default variation works fine, but these are tied to the imported products and I personally don't know what to edit to add the missing values to get the form to work and the only way to try now anything else is to start over with a new database and import again via upgrade using Commerce Migrate - which never worked right in the first place - because it left the text data field behind and is a bug it appears in in itself.

See https://www.drupal.org/project/commerce\_migrate/issues/3044987.

Reference https://docs.drupalcommerce.org/commerce2/user-guide/shipping/enable-shipping-products

Does anyone know if there is a way to manually add these fields to these entities or otherwise fix this ??

# Answer
> 0 votes
A patch and code insert posted at comment 14 and 15 at https://www.drupal.org/project/commerce\_migrate/issues/3044987 partially solved this but for the text data field import still did not work to bring in the text

---
Tags: commerce, migrations
---


# Question
Title: how to apply a css code for a specific screen size
i am new in Drupal , in my case i have added a css code to implement it for just a specific width but in return i see it displayed for all screen size not the small or medium size it appears in all website's size, i wonder where is the problem here ? See the code below

libraries.yml

```
global-styling:
  version: VERSION
  js:
    js/popper.min.js: {}
    js/bootstrap.min.js: {}
    js/global.js: {}
  css:
    component:
      css/style.css: {}
      css/small.css: {breakpoint: small}
      css/medium.css: {breakpoint: medium}
  dependencies:
    - core/jquery
    - core/drupal

```

breakpoints.yml

```
mymodule.small:
  label: small
  mediaQuery: 'all and (min-width: 740px) and (min-device-width: 740px)'
  weight: 0
  multipliers:
    - 1x
mymodule.medium:
  label: medium
  mediaQuery: 'all and (min-width: 1300px)'
  weight: 1
  multipliers:
    - 1x

```

css code :

```
body {
  background: red !important;
}

```

# Answer
> 0 votes
I have never herd of "breakpoints.yml" and don't think you can do what you want like that

so i think you just need to make normal media queries in your css file "css/style.css" if you want you can break them out in to other files but really there is no need.

Example:

```
// Extra small devices (portrait phones, less than 576px)
@media (max-width: 575.98px) { ... }

// Small devices (landscape phones, 576px and up)
@media (min-width: 576px) and (max-width: 767.98px) { ... }

// Medium devices (tablets, 768px and up)
@media (min-width: 768px) and (max-width: 991.98px) { ... }

// Large devices (desktops, 992px and up)
@media (min-width: 992px) and (max-width: 1199.98px) { ... }

// Extra large devices (large desktops, 1200px and up)
@media (min-width: 1200px) { ... }

```

---
Tags: theming
---


title: Condition on current moderation state

text:
# Question
Title: Condition on current moderation state
I would like to show a message when content has changed moderation states from review to published. I set this up below but it does not work. Is there a rules debug log in Drupal 8?

**Event**: When content is update.

**Condition**: Data Comparison.

* node.moderation\_state
* Operator: ==
* data value: published

**Action**: Send System message, with

* The message type
* drupal\_get\_message(‘status’);

But this doesn’t work. I get this error:

> error php InvalidArgumentException: Cannot set a list with a non-array value. in Drupal\Core\TypedData\Plugin\DataType\ItemList-\>setValue() (line 59 of /var/www/html/d815/core/lib/Drupal/Core/TypedD

# Answer
### Part 1 - Understanding the problem

I'm not sure if you won't run into other problems in trying to get this to work in D8 (as per the current status of the Rules module for D8), but IMO the first issue you need to resolve is that "***...Cannot set a list with a non-array value ...***" (as contained in your error message).

It seems to me that you should use something like what in D7 is called "*List contains item*" as your Rules Condition. For way more details on that, refer to the answer to the (D7 related) question about "Loop through all entities with rules".

### Part 2 - More info that may help to get it to work

Your issue appears to be related to the (fixed) issue (= a task, not a bug ...), from Klausi, about "Support multiple contexts in the UI" which states:

> Currently we only use a simple textfield for contexts in conditions and actions. Conditions such as the UserHasRole condition have their Roles context defined as multiple, which means the user should specify more than one value in a text field. A default implementation could just display a textarea where one line is one item in the list.

The fix for this issue appears to be included in this pull request.

Disclaimer: I have not QA-reviewed this (yet) (but that's what I would go for to get it to work).
> 0 votes

# Answer
The following reaction rule will do what you asked. Import this configuration then enable the rule at /admin/config/workflow/rules

Note it is not sufficient just to check the current moderation state; if your goal is to show a message when the moderation state is *changed* to Published then you need to check the state before the update and compare it to the current state - you only want to send the message when the current state is Published *and* the previous state was NOT Published.

There IS a debug log now in D8 Rules, but it wasn't available when you asked your question.

In the future, please include an export of your Rule - it is impossible to know exactly what you configured wrong without seeing the export.

```
langcode: en
status: true
dependencies:
  module:
    - content_moderation
  enforced:
    module:
      - content_moderation
id: content_moderation_state_is_changed_to_published
label: 'Show a message when content moderation state is changed to Published'
events:
  -
    event_name: 'rules_entity_update:node'
description: 'This Reaction Rule displays a system message when the moderation state of any piece of content is changed to Published'
tags: {  }
config_version: '3'
expression:
  id: rules_rule
  uuid: 563de663-2c5a-4bad-892d-017e322b67ba
  weight: 0
  conditions:
    id: rules_and
    uuid: c65b7edb-5f6b-41b8-8775-8a880e66b8c0
    weight: 0
    conditions:
      -
        id: rules_condition
        uuid: 384eb508-4970-4210-b427-b9c2d09f25a4
        weight: 0
        context_values:
          operation: '=='
        context_mapping:
          data: node.moderation_state.value
          value: node_unchanged.moderation_state.value
        context_processors:
          operation:
            rules_tokens: {  }
        provides_mapping: {  }
        condition_id: rules_data_comparison
        negate: true
      -
        id: rules_condition
        uuid: 5528f7d4-302c-4a72-b583-943dacb4c117
        weight: 0
        context_values:
          operation: '=='
          value: published
        context_mapping:
          data: node.moderation_state.value
        context_processors:
          operation:
            rules_tokens: {  }
          value:
            rules_tokens: {  }
        provides_mapping: {  }
        condition_id: rules_data_comparison
        negate: false
  actions:
    id: rules_action_set
    uuid: 6cd47db2-335b-4647-8083-b0c0d90b63bf
    weight: 0
    actions:
      -
        id: rules_action
        uuid: 5520606c-4d0f-4af1-9c55-c95f910477ac
        weight: 0
        context_values:
          message: 'Content moderation state was changed to Published'
          type: status
          repeat: false
        context_mapping: {  }
        context_processors:
          message:
            rules_tokens: {  }
          type:
            rules_tokens: {  }
          repeat:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_system_message

```
> 0 votes

---
Tags: 8, rules
---


# Question
Title: How to update the below action for each view bulk operations?
I wants to delete the below folder every time only on each view bulk operations but currently it is getting deleted for each node selected in VBO. I am executing this action in rules module.

Please let men know how to run this only once for each VBO.

```
$pdfdir = "/var/www/websites/test/sites/default/files/pdffolder";
$directory = escapeshellarg($pdfdir);
shell_exec("rm -rf $directory");

```

This code is executed via the Rules module.

# Answer
> 0 votes
If you define a VBO event in rules that triggers on every node save, then it will happen once per node saved by VBO. VBO takes all the selected items in a view and runs them through a batch process, performing operations per item.

So, you need to change the rule event to something else.

If the goal is to run the code once per time, here is one lazy way to do it:

1. Set the event to be "page is viewed". (doing this from memory, actual event name is different)
2. Set a condition on the rule to be the path of the VBO page.
3. Use your execute PHP code as the action.

This will cause the code to execute whenever the VBO url is accessed. This is not exactly what you asked for, but hopefully this gives you an idea of how to use events and conditions in rules to get what you want.

---
Tags: 7, views
---


# Question
Title: Form in custom module using Controller: The HTML tag form isn't present in Twig
I'm trying to render limited user edit form on custom page using Drupal Controller. In the routing.yml I defined \_controller, I do not want to use \_form.

I want to display on the form e.g. only timezone field, but not the rest. And I'm not able to achieve it. I can render this field, other fields like form\_build\_id, form\_id, form\_token But form html tag is not rendered at all. It works only if I display the whole form with `{{ form.form }}`.

This is the content of the files I am using.

### my\_module.info.yml

```
name: 'My module'
type: module
description: 'my module'
core_version_requirement: ^8.8 || ^9

```

### my\_module.routing.yml

```
my_module.mymodule_controller_view::
  path: '/my-module'
  defaults:
    _controller: '\Drupal\my_module\Controller\MymoduleController::view'
    _title: 'My module'
  requirements:
    _permission: 'access content'

```

### my\_module.module

```
function my_module_theme($existing, $type, $theme, $path)
{
    $templates = array(
        'my_module_form' => [
            'render element' => 'form',
        ],
    );

    return $templates;
}

```

### MymoduleController.php

```
namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\user\Entity\User;

class MymoduleController extends ControllerBase
{

    public function view()
    {
        $data['header'] = [
            '#type' => 'markup',
            '#markup' => '<h1>HEADER</h1>',
        ];

        $user = User::load(\Drupal::currentUser()->id());
        $formObject = \Drupal::entityTypeManager()
            ->getFormObject('user', 'default')
            ->setEntity($user);

        $form = \Drupal::formBuilder()->getForm($formObject);

        $data['form'] = [
            '#theme' => 'my_module_form',
            'form' => $form,
        ];

        $data['footer'] = [
            '#type' => 'markup',
            '#markup' => '<h3>footer</h3>',
        ];

        return $data;
    }
}

```

### my-module-form.html.twig

```
<div>TWIG TEMPLATE</div>

{{ form.form.timezone }}
{{ form.form.form_build_id }}
{{ form.form.form_token }}
{{ form.form.form_id }}
{{ form.form.actions }}

```

# Answer
This is not working, you can't use a form template in a controller. You have to assign the template to `$form['#theme']` when building the form or in a form alter hook. Then it gets used by `formBuilder()->getForm()` automatically.

See for example seven\_form\_node\_form\_alter():

```
$form['#theme'] = ['node_edit_form'];

```

and the corresponding twig file for a two column layout:

*core/themes/seven/templates/node-edit-form.html.twig*

```
{#
/**
 * @file
 * Theme override for a node edit form.
 *
 * Two column template for the node add/edit form.
 *
 * This template will be used when a node edit form specifies 'node_edit_form'
 * as its #theme callback.  Otherwise, by default, node add/edit forms will be
 * themed by form.html.twig.
 *
 * Available variables:
 * - form: The node add/edit form.
 *
 * @see seven_form_node_form_alter()
 */
#}
<div class="layout-node-form clearfix">
  <div class="layout-region layout-region-node-main">
    {{ form|without('advanced', 'footer', 'actions') }}
  </div>
  <div class="layout-region layout-region-node-secondary">
    {{ form.advanced }}
  </div>
  <div class="layout-region layout-region-node-footer">
    <div class="layout-region-node-footer__content">
      {{ form.footer }}
      {{ form.actions }}
    </div>
  </div>
</div>

```

---

**Form modes**

A different approach would be to configure a form mode in UI containing only the field you want and then use it in your controller:

```
    $formObject = \Drupal::entityTypeManager()
        ->getFormObject('user', 'custom_form_mode')
        ->setEntity($user);

```

See How do I load a form with a specific form display (form mode)?
> 2 votes

---
Tags: theming, forms, hooks
---


title: How do I replace drush_set_error()?

text:
# Question
Title: How do I replace drush_set_error()?
Just updating a module for Drupal 9 and Drush 10 and `drush_set_error()` no longer appears as a function in the Drush code (as far as I can see). What should I be using instead?

# Answer
`drush_set_error()` has basically been deprecated in Drush 8 and has been removed in Drush 10. Hitting up Google for drush\_set\_error() will give you a blog post by one of the maintainers: Porting Commands to Drush 9. In there the following is stated.

> Replace `drush_set_error()` with `throw new \Exception()`

---

Now let's compare a sample command in Drush 8 and in Drush 10 – the `xkcd` command.

In Drush 8 there's the following line:

```
drush_set_error('DRUSH_XKCD_SEARCH_FAIL', dt('The search failed or produced no results.'));

```

In Drush 10 this line became:

```
throw new \Exception(dt('The search failed or produced no results.'));

```

---

One more.

When you search the pull requests for drush\_set\_error() you'll find the following: Replace drush\_set\_error() and drush\_log() via Drush::logger() #3810. In there `drush_set_error()` has been replaced by `Drush::logger()->error()`.

Now what's the difference between `Drush::logger()->error()` and `throw new \Exception()`?

* `throw new \Exception(dt('My error messsage.'));` is the last thing you do before Drush quits.
* `Drush::logger()->error(dt('My error message'));` gives you the chance to print out multiple error messages and let your code continue.
> 4 votes

---
Tags: drush, 9
---


# Question
Title: How to sort translation under Translate tab?
I need to sort these translated language names alphabetically. I want to sort these irrespective of these languages weight and hierarchy. How can I do that?

# Answer
Have you checked on "admin/config/regional/language"? There you can sort languages and the order is reflected throughout the system (e.g.: the language switcher block)
> 0 votes

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


# Question
Title: hook_form_alter add field after submit button to exposed view
I'm trying to add a field that would be displayed after the submit button in the rendered HTML in my hook\_form\_alter.

e.g.

```
$form['include_card'] = [
  '#type' => 'checkbox',
  '#title' => t('Include gift card'),
  '#weight' => 25,
];

```

Weight doesn't seem to have any bearing on it. How would you set that up?

# Answer
The submit button will likely be inside an Actions element, which has a default weight of 100.

You could add your field to the actions element:

```
$form['actions']['include_card'] = ...

```

At which point the weight of `include_card` will be relative to the buttons/etc that are inside the actions element (and 25 will probably work).

Another option would be to position your element directly after the actions:

```
$form['include_card'] = [
  '#type' => 'checkbox',
  '#title' => t('Include gift card'),
  '#weight' => $form['actions']['#weight'] + 1,
];

```
> 0 votes

---
Tags: 8, forms, hooks
---


# Question
Title: How can I split the body field to insert content between the first and the second paragraph?
I have a node which shows content from the body field. I want to add a another paragraph or a block between between the first and the second paragraph, after the first `</p>` and before the second `<p>` tag.

But in my template to output the body there's only `{{ content.body }}`.

Drupal 7 had something like block in block. How can I do the same in Drupal 8?

# Answer
I resolved my issue, using solution below

```
    {% set Paragraphs = node.body.value|split('</p>') %}
  {% set paragraphHalf = (Paragraphs|length / 2)|round %}

  {% if paragraphHalf %}
    {% for paragraph in Paragraphs %}
      {% if paragraphHalf == 1 or loop.index % paragraphHalf == 1 -%}

      {% endif %}
      {{ paragraph|raw }}

      {% if loop.last or loop.index % paragraphHalf == 0 -%}
      {{ insert item }}
      {% endif %}

    {% endfor %}

  {% endif %}

```
> 0 votes

---
Tags: 8, theming
---


title: "Broken pipe" between Nginx and PHP-FPM

text:
# Question
Title: "Broken pipe" between Nginx and PHP-FPM
On 6th January, I updated my Drupal 8 development system (`composer update`). The following `ls` listing shows the modules that were updated.

```
drwxr-xr-x  7 drupal8 www-data 4096 Jan  6 02:36 checklistapi
drwxr-xr-x  7 drupal8 www-data 4096 Jan  6 02:36 ctools
drwxr-xr-x  4 drupal8 www-data 4096 Jan  6 02:36 quick_node_clone
drwxr-xr-x  6 drupal8 www-data 4096 Jan  6 02:36 workbench_access
drwxr-xr-x  4 drupal8 www-data 4096 Jan  6 02:36 file_checker
drwxr-xr-x  6 drupal8 www-data 4096 Jan  6 02:36 eva
drwxr-xr-x  4 drupal8 www-data 4096 Jan  6 02:36 social_post_linkedin
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:36 term_csv_tree_import
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:35 memcache
drwxr-xr-x  6 drupal8 www-data 4096 Jan  6 02:35 feeds
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:35 easy_breadcrumb
drwxr-xr-x  7 drupal8 www-data 4096 Jan  6 02:35 fontawesome
drwxr-xr-x  3 drupal8 www-data 4096 Jan  6 02:34 term_csv_export_import
drwxr-xr-x  4 drupal8 www-data 4096 Jan  6 02:34 leaflet_more_maps
drwxr-xr-x 11 drupal8 www-data 4096 Jan  6 02:34 devel
drwxr-xr-x  4 drupal8 www-data 4096 Jan  6 02:34 typed_data
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:34 externalauth
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:34 libraries
drwxr-xr-x  4 drupal8 www-data 4096 Jan  6 02:34 social_post_twitter
drwxr-xr-x  4 drupal8 www-data 4096 Jan  6 02:34 auto_entitylabel
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:33 contentimport
drwxr-xr-x 11 drupal8 www-data 4096 Jan  6 02:33 paragraphs
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:33 telephone_validation
drwxr-xr-x  9 drupal8 www-data 4096 Jan  6 02:32 leaflet
drwxr-xr-x  9 drupal8 www-data 4096 Jan  6 02:32 entity_browser
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:32 workflow
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:32 config_update
drwxr-xr-x  5 drupal8 www-data 4096 Jan  6 02:32 entity
drwxr-xr-x  6 drupal8 www-data 4096 Jan  6 02:32 workbench
drwxr-xr-x  3 drupal8 www-data 4096 Jan  6 02:32 unique_field
drwxr-xr-x  3 drupal8 www-data 4096 Jan  6 02:32 entity_reference_display
drwxr-xr-x  6 drupal8 www-data 4096 Jan  6 02:31 ledger
drwxr-xr-x  8 drupal8 www-data 4096 Jan  6 02:31 eu_cookie_compliance
drwxr-xr-x  3 drupal8 www-data 4096 Jan  6 02:31 social_api
drwxr-xr-x  3 drupal8 www-data 4096 Jan  6 02:31 permissions_filter
drwxr-xr-x  3 drupal8 www-data 4096 Jan  6 02:30 social_post
drwxr-xr-x  6 drupal8 www-data 4096 Jan  6 02:30 gdpr_compliance

```

I then went to bed and carried on working at around 14:20. Since that time I have regular errors of the following kind in my `php7.2-fpm.log`:

```
[06-Jan-2019 14:37:21] WARNING: [pool www] child 1263 said into stderr: "There was a problem sending 4325 bytes on socket 5: Broken pipe"
[06-Jan-2019 14:37:22] WARNING: [pool www] child 1263 said into stderr: "There was a problem sending 178 bytes on socket 5: Broken pipe"
[06-Jan-2019 14:40:23] WARNING: [pool www] child 1232 said into stderr: "There was a problem sending 178 bytes on socket 5: Broken pipe"
[06-Jan-2019 14:43:55] WARNING: [pool www] child 6461 said into stderr: "There was a problem sending 178 bytes on socket 5: Broken pipe"

```

I have only just noticed this now whilst in pursuit of another problem. Does anyone know what might be causing it?

I'm running Drupal 8.6 on Ubuntu 18.04 with Nginx 1.14.0 and PHP 7.2.10 with FPM. The database is Postgresql 10.6.

I thought originally it might be a hardware problem, but the the immediacy of the problem after the Drupal update seems too obvious to ignore.

# Answer
> 0 votes
*An year and a half later ...*

Looks like it's xdebug: https://bugs.xdebug.org/bug\_view\_page.php?bug\_id=00001401

If you turn debugging on (so something is listening on port 9000), the error goes away.

*(Found this while searching for the same problem, so I thought I'd share)*

---
Tags: 8
---


# Question
Title: How to define an internal link as parent in mymodule.links.menu.yml?
How do I create a menu link programmatically to a node that I can use as a parent for other links?

In `MYMODULE.links.module`, I defined some links for my navbar:

```
MYMODULE.parent-fruits:
  title: 'Fruits'
  url: internal:/fruits
  weight: 0
  menu_name: food
MYMODULE.fruits-apple:
  title: 'Apple'
  parent: MYMODULE.parent-fruits
  route_name: view.fruits.apple
  weight: 5
  menu_name: food
MYMODULE.parent-vegetables:
  route_name: view.vegetables.page-main
  weight: 10
  menu_name: food
MYMODULE.vegetables-asparagus:
  parent: MYMODULE.parent-vegetables
  title: 'Asparagus'
  url: internal:/admin/structure/taxonomy/manage/card_group_private/add
  weight: 5
  menu_name: food

```

In this case, I expect to have a menu that looks like this:

* Fruits (child-\> Apple)
* Vegetables (child-\> asparagus)

When I go to the parent page, the link to the child should appear in the navbar menu (the parent tree should be expanded).

But what I actually get is:

* Fruits (**no children**)
* Vegetables (child-\> asparagus)

The problem is caused by defining the menu link with `url` instead of `route_name`. I know this because when I change the parent of `fruits-apple` to `parent: MYMODULE.parent-vegetables`, then I see `Apple` as a child of `Vegetables`.

When I remove `parent` from `Apple`, then it appears in the menu (without a parent), so I know the link is defined correctly.

I can also create the `Fruits` / `Apple` links in the menu UI, and those work correctly.

Regarding `parent:` the documentation says this:

> Determining the parent menu\_link name can be a little tricky at first. If you know the path of the parent menu item, you would need to search for it in all available \*.routing.yml files (most text editors and IDEs should allow you to search all files in a project) and find the route name for that path. Then, you would need to search for the route name in all available \*.links.menu.yml files. The menu\_link whose route\_name matches is your link. Alternatively, if you know which module is defining the parent menu link (or one of the parent menu link's children), you can go straight to that module and perform your search.

Since these are node links, I checked `node.routing.yml` in the core node module, but I couldn't find the route to node pages.

So: how do I create a menu link programmatically to a node that I can use as a parent for other links?

# Answer
I think changing from `url` to `route_name` is *the* solution, you normally use `url` only for external links.

You don't find entity routes in static yml files because they are created dynamically. You could use the Devel module and visit

```
/devel/routes

```

or from the command line with Drupal Console:

```
drupal debug:router

```

See https://drupalconsole.com/docs/en/commands/debug-router

Then when you have found the route name you have to add the entity id as route parameter.

Example:

*mymodule.links.menu.yml*

```
mymodule.node7:
  title: 'Node 7'
  route_name: 'entity.node.canonical'
  route_parameters: { node: '7' }

```
> 1 votes

---
Tags: 8, navigation
---


# Question
Title: Twig Template print field - if not node number
I can print an image field in my node template like this:

```
{{ content.field_big_image }}

```

But can I say "print this field but not if the node number is node/45" ?

# Answer
Yes. Sometimes themes will drop documentation when they override a template, but you can always check the original template file for the available variables and other info relevant for working with the template. If you check the *node.html.twig* template provided by the node module in core, you'll see the following documentation at the top of the file.

```
/**
 * @file
 * Default theme implementation to display a node.
 *
 * Available variables:
 * - node: The node entity with limited access to object properties and methods.
 *   Only method names starting with "get", "has", or "is" and a few common
 *   methods such as "id", "label", and "bundle" are available. For example:
 *   - node.getCreatedTime() will return the node creation timestamp.
 *   - node.hasField('field_example') returns TRUE if the node bundle includes
 *     field_example. (This does not indicate the presence of a value in this
 *     field.)
 *   - node.isPublished() will return whether the node is published or not.
 *
 * ... continued ...
 *
 */

```

Note the relevant info here:

> The node entity \[is available\] with limited access to object properties and methods. Only method names starting with "get", "has", or "is" and a few common methods such as "id", "label", and "bundle" are available.

This means you can access the node id with `node.id`.

So, you can print your field on nodes other than your specific node by wrapping your field in a conditional like:

```
{% if node.id != 45 %}
  {{ content.field_big_image }}
{% endif %}

```

or

```
{% if not node.id == 45 %}
  {{ content.field_big_image }}
{% endif %}

```

Either choice should produce the same result.
> 2 votes

---
Tags: theming
---


title: Drupal 8 CKEeditor license/pricing

text:
# Question
Title: Drupal 8 CKEeditor license/pricing
Drupal 8 ships with ckeditor as the default text editor. Drupal itself can be used free of charge without limitations. At least this is what I thought until now.

While CKEditor seems to be OpenSource, the website suggests there is a price depending on how it will be used. E.g. if a project has more than 2 developers, or more than 5 content editors. https://ckeditor.com/pricing/

How does this play together? What am I missing? Is there a special license when using CKEditor in a Drupal project?

# Answer
Both Drupal and CKEditor are licensed under GPL2+.

See https://github.com/ckeditor/ckeditor5/issues/991 and https://www.drupal.org/about/licensing.

CKEditor is not the only open source project offering commercial licensing. See the FAQ.
> 4 votes

---
Tags: 8, wysiwyg
---


# Question
Title: get value from content type B, in a view of content type A
i have a content type named songs. among other fields, it has a field named title of the song, which has as its field type the Node reference. i also have a second content type named songsTitles which keeps all songs' metadata, where there is for instance the duration of the song, the producer, etc. how can i retrieve in a view that i have created for the content type songs, instead of the node reference value, for each song, its duration instead? I would prefer to do it via the Views gui, since whatever i tried with code was not successful.

# Answer
> 1 votes
To retrieve information linked through ER fields you have to add the Relationship for the ER field.

The Relationship will open new options you can add to your Views.

You will be able to add the **Duration** Field to your Views after you add the Relationship. That field will use the Relationship by default (it wouldn't work without it).

---
Tags: 7, views
---


# Question
Title: List of parent and child taxonomies and related content
I would like to show in the front page a list of dishes. Like a real restaurant menu, I would like see:

```
Wines

 -Whites

  --Product 1

  --Product 2

 -Reds

  --Product 3

  --Product 4

Beers

 -Blondes

  --Product 5

 -Reds

  --Product 6

```

and so on.

To do so, I created a **taxonomy vocabulary** named **category** and then a list of terms and sub-terms like this:

Then in my custom type **Product** I created a relation field to the taxonomy category. But when I tried to create a custom view to list all the products by taxonomy terms and sub-terms, I only view the child one. How can I create the view to display the complete hierarchy list? Thanks

# Answer
There is more than one way of solving this.

If you start from your existing case of Content Views and listing your Products, you can add the Taxonomy ER Field. This field will show the Term that the node is directly linked to, the "child" in your Taxonomy hierarchy.

To get the "parent" Taxonomy term you have to add the Relationship for the ER field in question. Once you add that you will be able to access the Parent Field from the "Taxonomy term" Category.

You can then set Grouping under Format Settings. Set the first grouping to the "Parent" Field, and the second one to the "child" regular taxonomy field.

You can hide the taxonomy fields with `Exclude from display` since they'll appear in the grouping output.

Alternatively, you can add a second Relationship on top of the first one, for the Parent of the term, but that approach isn't necessary unless you have 3 levels of taxonomy hierarchy, and it can add to the performance strain.

---

You can also start from the Taxonomy term type Views, show hierachy with Depth, and use a Relationship to add the nodes/content into the View.
> 1 votes

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


# Question
Title: how to add attributes of the parent taxonomy in the DOM?
I am displaying a taxonomy "category" on a node, a view of that node ,and a search facet.

This taxonomy has 2 levels.

How can i add to the rendered HTMLs, i guess using preprocessing hooks, an attribute indicating the taxonomy parent id ?

I would need to apply CSS differently to the taxonomy buttons depending on the parent.

# Answer
> 1 votes
You can add the relevant Taxonomy parent Field to your Views, make it display the term ID. This way you get that information available as a token.

You can hide that field with `Exclude from display` and position it above all the other fields, so you can use it as a token in all of them without worrying about the position.

Then edit the `Style settings` of your "Parent" field that you want to style and enable the `Create a CSS class` option. You can enter the token for your parent TID in there.

Since css classes can't start with numbers make sure to enter a safe start for the class, for example: `myclass-{{ tid }}`

To find the list of tokens you'll have to temporarily enable the option `Rewrite results > Override the output of this field with custom text > Replacement patterns`.

You may need to `Customize field and label wrapper HTML` and/or `Use field template` depending on your particular configuration and output to get the class to show up.

---

Alternatively, you can construct the output of your field on your own with the `Override the output of this field with custom text` and enter what you want the HTML to show:

`<div class="myclass-{{ tid }}">{{ field_output }}</div>`

---
Tags: taxonomy-terms, hooks
---


# Question
Title: Retain Guzzle Session During Batch Operations
On a Drupal 7 site, I am using the Batch API to perform operations on many entities, one at a time. During a typical operation, the D7 site uses Guzzle to make a POST call to a Drupal 8 site. The D7 Batch callback looks like this:

```
function example_operation($foo, &$context) {

  // Login to Drupal 8.
  // ...

  // Make POST call to Drupal 8.
  // ...

  // Logout from Drupal 8.
  // ...

}

```

The D7 client uses a Guzzle client and cookie jar to authenticate with the D8 server (REST+cookies), with no issues. Great!

Now imagine running this on 100K+ entities, that's an awful lot of logging in and out unnecessarily, wasting a whole bunch of time and resources. So I figure, let's login once on the first operation, retain that session for each operation, then logout when finished. Sounds reasonable.

I thought I'd use D7 Batch API's `$context['results']` array to hang onto the cookie jar and D8 rest tokens, that way each operation would have access to them, no problem, *or so I thought*. Take a look at this attempt in the D7 Batch callbacks:

```
function example_operation($foo, &$context) {

  $jar = NULL;
  $csrfToken = NULL;

  // Login to Drupal 8 (first time only)
  if (!isset($context['results']['jar'])) {

    // Login to Drupal 8.
    // ...

    // Set aside cookie jar and tokens.
    $context['results']['jar'] = $jar;
    $context['results']['csrf_token'] = $csrfToken;
    $context['results']['logout_token'] = $logoutToken;

  }
  else {

    // We've already logged in, grab the cookie jar and token.
    $jar = $context['results']['jar'];
    $csrfToken = $context['results']['csrf_token'];

  }

  // Make POST call to Drupal 8 (using cookie jar and token).
  // ...

}

function example_finished($success, $results, $operations) {

  // Pull out cookie jar and tokens.
  $jar = $results['jar'];
  $csrfToken = $results['csrf_token'];
  $logoutToken = $results['logout_token'];

  // Logout from Drupal 8 (using cookie jar and tokens)
  // ...

}

```

This approach works fine on *the first operation only*. Then on the second operation, the tokens are available in `$context['results']` as expected, but the cookie jar always comes through as a **\__PHP\_Incomplete\_Class Object**, and then if I try using it with the Guzzle client a `cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface` is thrown.

**How do you retain a Guzzle session between batch operations in Drupal 7?**

* Perhaps `$context['results']` cannot contain "complex" class/objects like a Guzzle cookie jar
* I tried using the `cookies` request option when instantiating the Guzzle client, but that breaks *any* authenticated POST calls (including the first operation)
* Maybe the way D7's batch http requests work, it starts confusing the client/cookies/etc

# Answer
Between two batch runs, the data is saved in the database serialized. Before the second batch run, the data is taken from the database and unserialized. `__PHP_Incomplete_Class Object` tell us that, at the moment the data is unserializes, no `GuzzleHttp\Cookie\CookieJarInterface` class is available, and objects of that class cannot be unserialized.

To retain a Guzzle session between batch runs, you can save the data as array.

```
$context['results']['jar'] = $jar->toArray();

```

To get back the data, you can then use the following code.

```
$jar = CookieJar::fromArray($context['results']['jar'], 'domain.com');

```

If you save an object in `$context`, as in your case now, it would be available through all iterations at one batch run, but at the next run, an error is thrown.
If you still prefer to keep objects during iterations instead of arrays, to avoid errors you should check if `$context['results']['jar']` is an instance of `GuzzleHttp\Cookie\CookieJarInterface`.
> 1 votes

---
Tags: 7, batch-operations
---


# Question
Title: Update user email in custom module : validation API returns "Your current password is missing or incorrect"
Users can update their email and user name in a form (Form API) in a custom module. The reason is it also updates an external service.

It works well but I’ve noticed an error during our test if a user enter an existing email (which is forbidden).

So I’ve added a validation `$user->validate()`

Now, I have this error message :

> Your current password is missing or incorrect; it's required to change the email/.

I don’t know how to proceed. Should I retrieve the user password and send it again `$user->setPassword($password);` ? I've search on SO, Drupal Doc, etc. but I didn't find the correct way to do this.

Here is my code :

```
$uid = \Drupal::currentUser()->id();

// Get user storage object.
$user_storage = \Drupal::entityManager()->getStorage('user');

// Load user by their user ID
$user = $user_storage->load($uid);

 /**
 * Validation API
 * https://www.drupal.org/docs/8/api/entity-validation-api/entity-validation-api-overview
 */

  // Update email
  $user->setEmail($new_email);

  // Update username
  $user->setUsername($new_email);

  $violations_user = $user->validate();
  if ($violations_user->count() > 0) {
       $violation = $violations_user[0];
       drupal_set_message($violation->getMessage(), 'warning');
       // Here is the message "Your current password is missing or incorrect"
  } else {

      $user->save();
  }

```

# Answer
The violations you're seeing come from core's `ProtectedUserFieldConstraint`. The constraint is applied when the current user tries to update their account fields without supplying a password. The validator method has a built-in flag to disable this check when needed (e.g. when a user resets their password).

To set the flag, set the `_skipProtectedUserFieldConstraint` to `TRUE` (e.g. `$user->_skipProtectedUserFieldConstraint = TRUE;`) and the validator won't enforce supplying a password when changing the current user fields.
> 2 votes

---
Tags: 8, users
---


# Question
Title: Adding fields to content type edit form (not to the node itself)
In Drupal 8, how do you add fields to the content type edit form, i.e. where you define the content type? I know how to add fields to the content type that wind up on the node edit form, but I'm looking to add a field to the content type itself. Essentially, what I'm trying to do is add some data to content types that would allow me to group them together. To do this, I need to add some additional metadata to the content type beyond name and description.

# Answer
It sounds like you need to create custom entities.

Try reading Creating a content entity type in Drupal 8 and maybe this module can help: Entity API
> 0 votes

---
Tags: 8
---


# Question
Title: How can I style the Gutenberg module editor?
I'm trying to modify the CSS in the Gutenberg module to change the editor layout. Gutenberg uses SASS files to generate the CSS.

I tried editing the CSS files directly, which I recognize I shouldn't do with generated code. This ended up having no effect on the module's output, and the old CSS is somehow cached despite clearing all caches. I also tried instead modifying the SASS directly, but I don't know how to trigger a re-compile. I suspect the CSS is distributed pre-compiled.

What can I do to properly modify and update the SASS/generated/cached CSS?

# Answer
> 0 votes
There's no need to edit the CSS directly, as the module already allows for styling. To style the Gutenberg editor, follow these instructions:

> You can "inject" stylesheets and scripts into the editor using the libraries-edit at \[your\_theme\].gutenberg.yml configuration file. Example:

**my-theme.gutenberg.yml:**

```
libraries-edit:
  - my-theme/editor

```

**my-theme.libraries.yml:**

```
editor:
  css:
    theme:
      css/editor.css: {}
      css/some-component.css
  js:
    js/even-javascript.js

```

# Answer
> 3 votes
Another way to compile sass is to use `gulp`. There's a slightly dated general purpose tutorial here.

And there's a git gist for the Drulma theme I wrote here.

What gulp allows you to do is to chain various processes together, so you can, for example:

1. Compile the sass with `sass`
2. Minify the sass with cssnano
3. If you're using a framework like Bootstrap or Bulma, automatically delete the css rules included in the framework for stuff your site doesn't use using Uncss (to do this, you need to list all the possible CSS your site might use, which you can do with the Simple Styleguide module)
4. Compile and minify your js too

This is obviously more than just compiling SASS, but if you're going to go ahead and set up a workflow to compile sass, you might find it worth the investment in time to optimize the resulting files, too.

---
Tags: theming
---


# Question
Title: Build out a complete main nav menu for a module - not just adding one menu link
I've been finding a lot of info about how to add a menu link as part of a module. That works fine using the route/controller & links.menu.yml file.

But I am now trying to figure out how to add a complete main menu for my module (my module is a default data & structure module).

My goal is to have x level-1 menu items and each one of those will have varying numbers of sub-menus.

Any hints or references to guides/tutorials?

# Answer
> 0 votes
You can multiple links in the same way that you add one link.

This creates a front page link on a menu for anonymous users and a front page link on a menu for authenticated users, as well as a parent and child menu link (Fruits -\> Apple) for anonymous users.

`MYMODULE.links.yml`:

```
MYMODULE.anon-home:
  title: 'Home'
  route_name: 'entity.node.canonical'
  route_parameters: { node: '1' }
  weight: 0
  menu_name: main-navigation-anon
MYMODULE.anon-fruits:
  title: 'Fruits'
  route_name: 'entity.node.canonical'
  route_parameters: { node: '4' }
  weight: 10
  menu_name: main-navigation-anon-ja
MYMODULE.anon-apples:
  title: 'Apples'
  route_name: 'entity.node.canonical'
  route_parameters: { node: '6' }
  parent: MYMODULE.anon-fruits
  weight: 0
  menu_name: main-navigation-anon-ja
MYMODULE.auth-home:
  title: 'Home'
  route_name: 'entity.node.canonical'
  route_parameters: { node: '1' }
  weight: 0
  menu_name: main-navigation-auth

```

# Answer
> 0 votes
I've decided to go with the default\_content technique in which it is possible to save off the menu items to a 'custom\_module' then reload them into a new instance.

---
Tags: navigation
---