# Question
Title: How to load current user cart in Commerce 2?
In Commerce 2, how can I load the current user's cart? The current user may be either anonymous or logged in. The site has multiple stores and I won't know which store the user is currently on.

# Answer
> 8 votes
It depends what you need, really. If you just need all carts for all stores, the cart provider service can give you that:

```
$all_carts = \Drupal::service('commerce_cart.cart_provider')
  ->getCarts();

```

If you need a cart for a particular store based on context, it gets trickier. A reference to the "current" store can be found via the current store service:

```
$store = \Drupal::service('commerce_store.current_store')->getStore();

```

And the cart related to that store via the cart provider:

```
$cart = \Drupal::service('commerce_cart.cart_provider')
  ->getCart('default', $store);

```

(incidentally in all the above snippets, if you can inject those services into your current context instead of using the static methods, all the better).

The problem is in Commerce's definition of a "current" store. Out of the box that either comes from the order entity when viewing an order, or it's the default store. From your description neither of those will do the job, so you'll need to write a custom store resolver.

I don't know what context you have available when needing the cart entity, so here's a naive example based on a product page. Since a product can be in more than one store, it just returns the first in the array.

```
namespace Drupal\MODULE\Resolver;

use Drupal\commerce_product\Entity\ProductInterface;
use Drupal\commerce_store\Resolver\StoreResolverInterface;
use Drupal\Core\Routing\RouteMatchInterface;

class ProductPageStoreResolver implements StoreResolverInterface {

  protected $routeMatch;

  public function __construct(RouteMatchInterface $route_match) {
    $this->routeMatch = $route_match;
  }

  public function resolve() {
    $product = $this->routeMatch->getParameter('commerce_product');
    if ($product instanceof ProductInterface) {
      $stores = $product->getStores();
      return reset($stores);
    }
    return NULL;
  }
}

```

And the entry for MODULE.services.yml:

```
services:
  MODULE.product_page_store_resolver:
    class: Drupal\MODULE\Resolver\ProductPageStoreResolver
    arguments: ['@current_route_match']
    tags:
      - { name: commerce_store.store_resolver, priority: 100 }

```

Once you clear the cache, the first code snippet above will return the first store a product is assigned (when viewing it).

# Answer
> 4 votes
Just think maybe this could be useful, to load (last)cart order from specific user by id, use this.

```
$orders = \Drupal::entityTypeManager()
  ->getStorage('commerce_order')
  ->loadByProperties(['uid' => $user_id, 'cart' => '0']);

```

But to load cart for both logged in and anonymous user you should use this

```
$cart_provider = \Drupal::service('commerce_cart.cart_provider');
$carts = $cart_provider->getCarts();
$order = array_shift($carts);

```

# Answer
> 0 votes
to get current user's cart (if you only have 1 store):

```
  $store = \Drupal\commerce_store\Entity\Store::load(1);
  $order_type = 'default';
  $cart_provider = \Drupal::service('commerce_cart.cart_provider');
  $cart = $cart_provider->getCart($order_type, $store);

```

to get specific user's cart:

```
$cart = $cart_provider->getCart($order_type, $store, $account);

```

---
Tags: commerce
---


# Question
Title: How to override Breadcrumb theme template?
I have a custom theme that has `base theme: classy` setting in the `mytheme.info.yml` file. When we enable twig debugging locally, we find that the `<!-- BEGIN OUTPUT from 'themes/custom/mytheme/templates/navigation/breadcrumb.html.twig' -->` is displayed, but there are no theme suggestions available.

This is what displayed on the page.

**How can we create theme suggestions for breadcrumbs?**

We tried the following in the `mytheme.theme` file, but it did not print out the `ksm()` statements.

```
function mytheme_theme_suggestions_breadcrumb_alter(array &$suggestions, array $variables) {
  ksm($suggestions); // this returns empty
  ksm($variables); // this only returns theme_hook_suggestion and links array
}

```

The code is based off of what we can do for block suggestions alters.

```
function mytheme_theme_suggestions_block_alter(array &$suggestions, array $variables) {
  if (isset($variables['elements']['content']['#block_content'])) {
    $suggestions[] = 'block__' . $variables['elements']['content']['#block_content']->bundle();
  }
}

```

# Answer
> 0 votes
As mentioned by @Clive, breadcrumbs are not entities so I was not be able to get it done by adding a `mytheme_theme_suggestions_breadcrumb_alter`. Instead to solve the problem I had to do the following. On top of this, I ended up downloading and enabling Easy Breadcrumb to further modify the `Breadcrumb`

1. Copy the `breadcrumb.html.twig` file from the `Classy` theme into my `mytheme` directory
2. Clear cache
3. make any edits into the `sites/themes/custom/mytheme/templates/navigation/breadcrumb.html.twig` file
4. save and clear cache (if necessary)

---
Tags: 8, theming, hooks, breadcrumbs
---


# Question
Title: How to test a code where the config is involved as parameter?
I'm new to OOP concepts, also PHPUnit Testing is new for me. I want to get the configuration in my testcase.

**XYZFormResult.php**

```
namespace Drupal\xyz\XYZFormResult;

use Drupal\Core\Config\ConfigFactory;
use Drupal\webform\Entity\WebformSubmission;

/**
* Class XYZFormResult.
*
* @package Drupal\xyz\formgroup
*/
class XYZFormResult {

    /**
    * Defines the immutable configuration object.
    *
    * @var \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
    */
    private $config;

    /**
    * XYZFormResult constructor.
    *
    * @param \Drupal\Core\Config\ConfigFactory $config
    *   Inject ConfigFactory.
    */
    public function __construct(ConfigFactory $config) {
        $this->config = $config->getEditable('xyz.settings');
    }
}

```

**XYZFormTest.php**

```
namespace Drupal\Tests\xyz\Unit\XYZFormTest;

//use Drupal\Core\Config\ConfigFactory;
use Drupal\Tests\UnitTestCase;
use Drupal\xyz\formgroup\FormsGroupResult;
use Drupal\xyz\formgroup\XYZFormResult;
use Drupal\webform\Entity\WebformSubmission;

/**
* @coversDefaultClass \Drupal\xyz\formgroup\FormsGroupResult
* @group xyz
*/
class XYZFormTest extends UnitTestCase {
    /**
    *
    * @var \Drupal\Core\Config\ConfigFactory|\PHPUnit_Framework_MockObject_MockBuilder
    */
    protected $config;

    public function testxyz() {
        $this->XYZresult = new XYZFormResult($config);
    }
}

```

When I execute this XYZFormTest testcase, I need to pass a parameter for `XYZFormResult()`, how to pass config parameter?

If I pass any string in `XYZFormResult()`, I'm getting error this error:

```
__construct() must be an instance of Drupal\Core\Config\ConfigFactory, string given error

```

# Answer
> 2 votes
If you are using `KernelTestBase` (for "functional" tests that run on a bootstrapped Drupal and can use services), then you can use something the following:

```
class MyTest extends KernelTestBase {

  /**
   * Modules to enable.
   *
   * @var array
   */
  public static $modules = [
    'my_module',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    parent::setUp();

    // Set up our custom test config.
    $config = $this->config('my_module.settings');
    $config->set('my_setting_key', 'My setting value.');
    $config->save();
  }

  public function testMyThing() {
    // This config will be available in any service or place the config.factory
    // is injected as a dependency. Example:
    $config = $this->container->get('config.factory')->get('my_module.settings');
    $settingValue = $config->get('my_setting_key');
  }

}

```

A note: For this config to be usable, it needs to be defined in your module's schema at `my_module/config/schema/my_module.schema.yml`:

```
my_module.settings:
  type: config_object
  label: 'My Module settings'
  mapping:
    my_setting_key:
      type: string
      label: 'My Setting'

```

# Answer
> 2 votes
On a unit test, you can use getConfigFactoryStub():

```
namespace Drupal\Tests\my_module\Unit;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;

class MyModuleTest extends UnitTestCase {
  public function setUp() {
    parent::setUp();

    $config_map = [
      'my_module.settings' => [
        'setting_1' => 'value_1',
      ],
    ];

    // Get a stub for the config.factory service.
    $this->my_config_factory = $this->getConfigFactoryStub($config_map);

    $container = new ContainerBuilder();
    // Set the config.factory in the container also.
    $container->set('config.factory', $this->my_config_factory);

    \Drupal::setContainer($container);
  }

  public function testSomething() {
    $obj = new Something($this->my_config_factory);
    // ... asserts, etc.
}
}

```

# Answer
> 1 votes
You have the mock the dependencies. You can have a further look here.

Personally am using Prophecy for almost everything now, I like it better. In your case it would look like:

```
$config_prophecy = $this->prophesize(ConfigFactoryInterface::class);
$config_prophecy->getEditable('xyz.settings')->willReturn(['something'])->shouldBeCalled();
$this->XYZresult = new XYZFormResult($config_prophecy->reveal());

```

This says:

1. You make your mock look like the config factory interface.
2. You say that the 'getEditable' method is expected to call with the argument above and will return the data above.
3. Then you inject this dependency, but you must "reveal" it, means that it's translated into an implementation of the ConfigFactoryInterface.

The good thing about prophecies that if you put them in instance variables then you even if you injected it in the setup of your unit test you can change them anytime later on, which helps you to imitate the desirable behaviour of your dependency in a use case.

# Answer
> 1 votes
You need to mock your object. There is a good guide on how to create tests at Drupalize.me (is not free).

```
// Config factory mock.
$config_factory = $this->createMock('Drupal\Core\Config\ConfigFactoryInterface');
// Mocking getEditable method.
$config_factory->expects($this->any())
      ->method('getEditable')
      ->with('xyz.settings')
      ->willReturn($config);

$this->XYZresult = new XYZFormResult($config_factory);

```

This technique is named test double and you can read more about it at http://softpixel.com/~mradcliffe/files/dcp2016-mocking-drupal.pdf

---
Tags: 8, testing
---


# Question
Title: Conditionally display field based on comparison to other field
I have a content type Event that has a startdate (field\_eventdate) and an optional enddate (field\_eventend). Although it's optional, the enddate is often filled in by the users with the same date as the startdate. So I want to hide the enddate if it's equal to the startdate or display it on the same line as the startdate when it's different.

e.g.

```
2020-02-02 10:00
Here comes more text for a single day event

```

and

```
2020-02-02 10:00 - 2020-02-03 16:00
Here is more text for a multiday event

```

So far I managed to delete the enddate from the render array when it's equal:

```
function mytheme_preprocess_node__event(&$variables) {
  $startdate = $variables['content']['field_eventdate'][0]['#markup'];
  $enddate = $variables['content']['field_eventend'][0]['#markup'];

  if ($startdate === $enddate) {
    unset($variables['content']['field_eventend']);
  }
  else {
    // add an &em-dash; so the dates are nicely spaced
    $variables['content']['field_eventend'][0]['#markup'] = " — " . $enddate;
    // add float-left to the start date so they end up on the same line
    // TODO: what goes here?
  }
}

```

But I cannot find out how to notice in a twig template that I have a startdate and an enddate and therefore add 'float' css classes to put them in line.

I have tried to add a special attribute to the 'field\_eventdate' field, and add a 'float-left' class in the twig template for the field, but the custom attribute gets lost somewhere.

How can I solve this problem?

# Answer
> 1 votes
I finally solved the problem by adding a template for the content type. This allowed me to simplify the preprocess function:

```
function mytheme_preprocess_node__event(&$variables) {
  $startdate = $variables['content']['field_eventdate'][0]['#markup'];
  $enddate = $variables['content']['field_eventend'][0]['#markup'];

  if ($startdate === $enddate) {
    unset($variables['content']['field_eventend']);
  }
}

```

I then copied the `node.html.twig` template to `node--event.html.twig`. I only changed the main `{{ content }}` part into:

```
    {{ content.field_tags }}
    {{ content.field_eventlocation }}
    <div class="event_dates clearfix">
      {{ content.field_eventdate }}
      {% if content.field_eventend %}
         – {{ content.field_eventend }}
      {% endif %}
    </div>
    {{ content|without('field_tags', 'field_eventlocation', 'field_eventdate', 'field_eventend') }}

```

This replaced my attempt to create and modify `field--field-eventdate.html.twig` template.

Maybe this is not the best option, but at least it works.

---
Tags: 8, theming
---


title: How to remove webform error message?

text:
# Question
Title: How to remove webform error message?
How to remove webform error message? I need to be able to remove the error message form.

For instance, if I have an email field and for some reason did not pass the validation is not to show a message saying.

> The entered e-mail address "djhshsj" does not appear valid.

So my question is how I can remove that Drupal message?

**Update 1:** I had to render the error message below the button (I could not just move with CSS ). So I ended up doing my custom validation + error message. And even though I have my custom validation, webform still validate if that field is correct or not. However, all I want to do is to remove the message **NOT** the validation.

# Answer
> 0 votes
drupal\_get\_messages() returns all the messages set using `drupal_set_message`, which also includes error messages set during form validation. **This also clears the messages.**

You can then add a custom validate handler to the webform by altering it by implementing hook\_form\_alter or hook\_form\_FORM\_ID\_alter.

In your custom validate handler, call `drupal_get_messages()` to clear any error messages.

# Answer
> 0 votes
There is actually a Drupal module that gives you control over this. Its called Disable messages and can be found from the link below.

https://www.drupal.org/project/disable\_messages

You need to enter a regex of the type of messages you need to hide in the configuration form.

---
Tags: 7, webforms
---


title: Migrate user password hash

text:
# Question
Title: Migrate user password hash
We are migrating our old site from plain PHP to Drupal 8. Passwords are hashed with MD5 in the old site; I need to migrate them in Drupal.

I tried the following code, but it takes the password as plain text and calculates its SHA hash.

```
public function prepareRow(Row $row) {
    $password = $row->getSourceProperty('user_password');
    $hash = \Drupal::service('password')->hash($password);
    $row->setSourceProperty('user_password', $hash);
  }

```

This is the configuration file.

```
id: users
label: User migration
migration_group: mymodule_general_migration_groups
source:
  plugin: mymodule_migration_users
process:
  pass: user_password
  mail: user_email
  init: user_email
  status:
    plugin: default_value
    default_value: 1
  name:
    plugin: dedupe_entity
    source: username
    entity_type: user
    field: name
    postfix: _
  created:
    plugin: callback
    source: created
    callable: strtotime
  changed: user_regdate
  access: user_regdate
  login: user_lastvisit
destination:
  plugin: entity:user
  md5_password: true
migration_dependencies: {}
dependencies:
  enforced:
    module:
      - mymodule_migration

```

# Answer
> 1 votes
This simple code is working properly while migrating md5 password to drupal 8

```
$password_service = \Drupal::service('password');

  $password = $row->getSourceProperty('user_password'); // 'user_password' is the old db column which is in md5 format

  $hashed_password = 'U' . $password_service->hash($password); // U will indicate that the password needs rehashing.
  $row->setSourceProperty('hash_password', $hashed_password);

```

# Answer
> 3 votes
Since you don't know the password, only the hash, you can't migrate it directly. (MD5 is weak, but not that weak.) The whole purpose of hashing is that the password should be unknown to anyone except the user. There are 2 solutions to this.

* Reset all your users password and send a one-time-login password to them once they are migrated - as already suggested in the comments above.
* Write custom code that rehashes the password at login: "If the password is hashed with MD5, rehash it and store the hash when the user (successfully) logs in." This works because at login you have the user's password because they just entered it. And you know which hashing algorithm is used from the stored hash.Initially, you migrate the users with the MD5 password hash.

It turns out that Drupal does rehashing automatically (see `UserAuth::authenticate()`), but not for MD5 unless you modify the existing hash slightly by prefixing it with an "U". (Thanks, d70rr3s and Souvik Das.) See also user\_update\_7000.

---
Tags: 8, migrations
---


# Question
Title: Drupal not detecting the correct version number of a module?
I am trying to transfer a site over, and run update.php.

Drupal is telling me that my system and menus modules are out of date. This is not the case - they're both up-to-date, in fact I downloaded the most recent ones and uploaded them to my public\_html/sitename/modules folder.

Where is the version number stored, so that I can force Drupal to recognize that they are the correct module versions that Drupal is looking for?

Specifically for the menu and system modules.

This is in D7.

# Answer
> 4 votes
As Jimajamma in comment #2 pointed out it is worth to check whether there are older versions in renamed directories.

I had the same problem and error message with modules - after removing the backup below "sites/all/modules/old" the dependency check error in update.php was gone.

# Answer
> 0 votes
Not sure if it's related, but I had upgraded from drupal 7.27 to 7.31 and had an issue running update.php. So u ran drush updb instead.

I still ran into problems with the version being listed as 7.27 when checking it with "drush status". Turns out in the drupal root includes/bootstrap.inc there was a file that didn't cp over correctly. In which sets variables that set the version in the app itself and for the drush command.

I also verified that the database had the correct information in the systems table. Which was showing 7.31. : )

# Answer
> 0 votes
I had this problem on a D7 project that I took over. I tried all of the following:

* update.php
* registry rebuild
* refreshing update status at /admin/reports/updates
* manually truncate cache\_update

None of them worked. In the end, this is what fixed it:

* I went into PHPMyAdmin
* opened up the system table
* Downloaded the BLOB from the 'system' module
* Manually amended the version from 7.67 to 7.69
* Edited the row in PHPMyAdmin then uploaded the amended BLOB

Finally the update status message is suppressed

---
Tags: 7, updating
---


title: How do I set group fields in pairs?

text:
# Question
Title: How do I set group fields in pairs?
The code is taken from the "Form API examples" and supplemented. There must be a pair of first and last name fields. A button “Add more” should add a new pair of fields “name and surname” below the existing one. This works (a little later using css so that they are on the same line), but they are grouped incorrectly. They are displayed following this order.

* Name
* Name
* Name
* Surname
* Surname
* Surname

I need to get them in the following order. (Using CSS, I will inline them.)

* Name
* Surname
* Name
* Surname
* Name
* Surname

What am I doing wrong?

The code I am using is the following one.

```
public function buildForm(array $form, FormStateInterface $form_state) {
    $form['description'] = [
      '#type' => 'item',
      '#markup' => $this->t('This example shows an add-more and a remove-last button.'),
    ];

    // Gather the number of names in the form already.
    $num_names = $form_state->get('num_names');
    // We have to ensure that there is at least one name field.
    if ($num_names === NULL) {
      $name_field = $form_state->set('num_names', 1);
      $num_names = 1;
    }

    $form['#tree'] = TRUE;
    $form['names_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('People coming to picnic'),
      '#prefix' => '<div id="names-fieldset-wrapper">',
      '#suffix' => '</div>',
    ];

    for ($i = 0; $i < $num_names; $i++) {
      $form['names_fieldset']['name'][$i] = [
        '#type' => 'textfield',
        '#title' => $this->t('Name'),
      ];
      $form['names_fieldset']['surname'][$i] = [
        '#type' => 'textfield',
        '#title' => $this->t('Surname'),
      ];
    }

    $form['names_fieldset']['actions'] = [
      '#type' => 'actions',
    ];
    $form['names_fieldset']['actions']['add_name'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add one'),
      '#submit' => ['::addOne'],
      '#ajax' => [
        'callback' => '::addmoreCallback',
        'wrapper' => 'names-fieldset-wrapper',
      ],
    ];
    // If there is more than one name, add the remove button.
    if ($num_names > 1) {
      $form['names_fieldset']['actions']['remove_name'] = [
        '#type' => 'submit',
        '#value' => $this->t('Remove One'),
        '#submit' => ['::removeCallback'],
        '#ajax' => [
          'callback' => '::addmoreCallback',
          'wrapper' => 'names-fieldset-wrapper',
        ],
      ];
    }
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];

    return $form;

```

The form is rendered as in this screenshot.

>

The second part of the code where the code is processed

```
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values_1 = $form_state->getValue(['names_fieldset', 'name']);
    $values_2 = $form_state->getValue(['names_fieldset', 'surname']);

    for ($i = 0; $i < count($values_1); $i++) {
      $arr[] = $values_1[$i] . ' ' . $values_2[$i];
    }

    $output = $this->t('These people are coming to the picnic: @names', [
      '@names' => implode(', ', $arr),
    ]
    );
    $this->messenger()->addMessage($output);
  }

```

# Answer
> 0 votes
You could add a fieldset for each person, something like this should work:

```
for ($i = 0; $i < $num_names; $i++) {
  $form['names_fieldset']['person_' . $i] = [
    '#type' => 'fieldset',
    '#title' => $this->t('Person ' . $i),
  ];

  $form['names_fieldset']['person_' . $i]['name'] = [
    '#type' => 'textfield',
    '#title' => $this->t('Name'),
  ];
  $form['names_fieldset']['person_' . $i]['surname'] = [
    '#type' => 'textfield',
    '#title' => $this->t('Surname'),
  ];
}

```

And then alter your remove callback and a few other bits to match

---
Tags: 8, forms
---


# Question
Title: Write complex access control in a reusable way
We deal with nodes representing humans with two important properties: mother and father.

Your parents as well as your aunts and uncles should get extra permissions, like to see you in a certain view mode, or to see your private images.

**Where should I place this complex access control in a way that I can easily call it in several controllers and hooks?**

**Is there a name for the kind of feature I'm going to program?**

If there's no better idea, I would go with a **validation**. We could put the access control in a validator that we use like this:

```
$errors = $family_access_validator->validate($node);
if (count($errors) > 0) {
    throw new AccessDeniedHttpException();
}

```

However, I'm not sure whether this is the correct approach. When we use validation, we are always interested in the message **why** the data is rejected. Here, we are only interested in OK or not OK.

# Answer
For access control on routes, you can write a service which implements `AccessInterface`. At its simplest, this is just a class placed in a module's `src/Access` folder with a single method `public function access(AccountInterface $account)`, returning a flavour of `AccessResult`. Then you simply register your class in the module's services.yml, annotate the route to use that access checker and Drupal will do the rest. Relevant documentation

The documentation suggests that if the route being access-checked has an upcasted parameter like `{node}`, then you can add `$node` to function's arguments - i.e. `public function access(AccountInterface $account, Node $node)` and it will be automatically supplied. I haven't actually tried that part myself though. Assuming it works, you can then access the node's fields as normal in order to compare the entity ids of the mother/father fields with the user to which the `$account` belongs.

I'm not sure if there are similar ways to automatically invoke this same access check for displaying entities with different view modes, but at the end of the day it is just a service like any other, so you could always request it from the container or inject it into whatever other controllers / services / hooks you need. In these contexts you will of course have to 'manually' supply the current user `$account` and relevant `$node` to check.
> 5 votes

# Answer
> Where should I place this complex access control in a way that I can easily call it in several controllers and hooks?
>
> Is there a name for the kind of feature I'm going to program?

The term/concept you're looking for is a Service:

> Drupal 8 introduces the concept of services to decouple reusable functionality and makes these services pluggable and replaceable by registering them with a service container. As a developer, it is best practice to access any of the services provided by Drupal via the service container to ensure the decoupled nature of these systems is respected.

The above link describes in detail how to create services, and how to access them via the service container, both statically and via dependency injection.

Once you know these methods, you'll be able to easily re-use your functionality in controllers, hooks, plugins, other services, and beyond.
> 4 votes

---
Tags: 8, users, hooks, routes
---


# Question
Title: How to properly use a JS library that inserts content into existing DIV?
As with many JS libs i need an existing DIV for the lib to insert its content. I am trying to use the Chart.js library to inset a chart on a custom drupalgap page.

I eventually discovered the menu item page handlers and did this:

```
items['qleva_start_auth'] = {
  title: 'Home Auth',
  page_callback: 'qleva_start_auth',
  pageshow: 'qleva_start_auth_show',
};

```

in my hook\_menu.

qleva\_start\_auth now only has the required empty DOM element:

```
function qleva_start_auth() {
  var content = {};
  content['my_stuff'] = {
    markup: '<canvas id="myChart" width="100" height="100"></canvas>'
  };
  return content;
}

```

and the pageshow callback has the code to set up the chart.

This seems to work great except that my chart is now on every page; added to the bottom of the content for that page.

What am i doing wrong?

# Answer
> 0 votes
You can likely use drupalgap\_add\_js() at the beginning of your `pageshow` implementation to add the `Chart.js` library:

```
function qleva_start_auth() {
  drupalgap_add_js('Chart.js');
  // ...
}

```

---
Tags: javascript
---


# Question
Title: How do I use hook_search_api_solr_search_results_alter() to alter search results?
I want to alter the results of a Drupal 8.x search\_api\_solr search using hook\_search\_api\_solr\_search\_results():

```
function sbn_search_api_solr_search_results_alter(\Drupal\search_api\Query\ResultSetInterface $result_set,
                                                     \Drupal\search_api\Query\QueryInterface $query,
                                                       \Solarium\QueryType\Select\Result\Result $result) {
 $resultset_data = $result->getData();
  // Get docs in response results
  $results = $resultset_data['response']['docs'];
  foreach ($results as $id => &$item) {
    // get the doc and array id
  }
}

```

I know that the docs I seek are in the search results:

```
dsm($result);

```

returns

```
stdClass Object
(
    [__CLASS__] => Solarium\QueryType\Select\Result\Result
    [numfound:protected] => 5
    [maxscore:protected] => 1.8644972
    [nextcursormark:protected] =>
    [documents:protected] => Array
        (
            [0] => stdClass Object
                (
                    [__CLASS__] => Solarium\QueryType\Select\Result\Document
                    [fields:protected] => Array
                        (
                            [ss_search_api_id] => entity:node/47:en
                            [ss_search_api_language] => en
                            [score] => 1.8644972
                        )

 ...
    [data:protected] => Array
        (
            [response] => Array
                (
                    [numFound] => 5
                    [start] => 0
                    [maxScore] => 1.8644972
                    [docs] => Array
                        (
                            [0] => Array
                                (
                                    [ss_search_api_id] => entity:node/47:en
                                    [ss_search_api_language] => en
                                    [score] => 1.8644972
                                )

                            [1] => Array
                                (
                                    [ss_search_api_id] => entity:file/85:en
                                    [ss_search_api_language] => en
                                    [score] => 1.784599
                                )

```

Let's say that the doc in question that I want to remove from `$result` object is:

```
$resultset_data['response']['docs'][$id]

```

How do I alter the `$result` object to remove this doc from results? Every attempt I have made to access the `$result` object as an array has resulted in these types of errors:

> Error: Cannot use object of type Solarium\QueryType\Select\Result\Result as array

> Error: Cannot access protected property Solarium\QueryType\Select\Result\Result::$response

Any suggestions or documentation on this would be highly appreciated.

# Answer
> 2 votes
I have installed search\_api, search\_api\_solr and search\_api\_attachments. The View that I am reading with the hook is a Solr indexed view returning solr index extracts.

I discovered this was how to read the result rows:

```
  $result_items = $result_set->getResultItems();
  // Iterate through doc ids
  foreach ($result_items as $docid => $value) {
    // process info from $docid and/or $value
  }

```

**$docid** will be the Solr document id, i.e.: **entity:node/47:en**

In my case, all the information I need, *entity type* and *entity id*, are in the document id.

If I want to remove the result row:

```
unset($result_items[$docid]);

```

And at the end of the hook:

```
$result_set->setResultItems($result_items);

```

---
Tags: 8, search
---


# Question
Title: Remember/cache 'user role' for portal: how to configure?
I plan on setting up a different 'portal' for each user type, i.e. Student, Staff Member, etc. I want to prompt the user to select which type they are, and then cache that info in the future so that they don't have to select their type every time. The next time they go to my website, they are shown (redirected to?) their specific portal with links/info pertinent to them. The portal should contain a full menu structure, which may be different for each user type, but a lot of the content will be the same for multiple user types.

I don't want users to have to log in, so using roles within Drupal doesn't make sense. How can I go about doing this? I am planning on adding a taxonomy field to each node to specify which user types the node applies to so perhaps something with that?

This is Drupal 7, and use of existing modules is preferred.

# Answer
> 0 votes
You can probably do this with some javascript on your home page. By default, the page would be your select your type form. This could be a manually created form that call JS to create a Cookie with the user's choice. This should be hidden by default.

When a user comes to the site, if they do not have the cookie, show the form. If they have the cookie set, redirect to the appropriate page.

---
Tags: 7
---


# Question
Title: Composer cannot find drupal/commerce in a specific module
I'm attempting to update the dependencies of a specific module in my site. I've downloaded the module with git and navigated inside. If I run `composer validate` it says `./composer.json is valid`.
However if I run `composer update` or `composer require drupal/commerce:2.16` I get the error :

```
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - The requested package drupal/commerce could not be found in any version, there may be a typo in the package name.
  Problem 2
    - The requested package drupal/search_api could not be found in any version, there may be a typo in the package name.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see <https://getcomposer.org/doc/04-schema.md#minimum-stability> for more details.
 - It's a private package and you forgot to add a custom repository to find it

```

I cannot figure out what is the legit issue here.
This is the current require of my `composer.json`

```
  "require": {
    "drupal/commerce": "~2.8",
    "drupal/search_api": "~1.9",
    "picqer/php-barcode-generator": "^0.2.2",
    "cboden/ratchet": "^0.4.1"
  }

```

# Answer
> 1 votes
You need to add the Drupal repository to composer.json in your project.

```
"repositories": [
  {
    "type": "composer",
    "url": "https://packages.drupal.org/8"
  }
]

```

Note that after you do this and run composer require/update, it will create a vendor directory in your module folder. You'll want to delete this folder, as you only want your dependencies to be added when the module is added to your project, and your project's composer.json should install the dependencies in the correct directory.

---
Tags: 8, commerce, composer
---


# Question
Title: Route not found error when using webform_rest to upload files
I want to upload a file using webform\_rest API as described here. #2899902. But it gives me `415 Unsupported Media Type` error as you can see in the screenshot.

**Here is my code**

```
  methods: {
    addImage() {
      this.dropFiles = event.target.files[0];
    },

    submitResume() {
      const formData = new FormData();
      formData.append("image", this.dropFiles, this.dropFiles.name);

      axios
        .get("https://example.com/rest/session/token")
        .then(tokenResponce => {
          this.formToken = tokenResponce.data;
        });

      axios
        .post(
          "https://example.com/webform_rest/job_applications/upload/resume?_format=json",
          formData,
          {
            headers: {
              Accept: "json",
              "Content-Type": "application/hal+json",
              "Content-Disposition": "file; filename = full.pdf",
              "X-CSRF-Token": this.formToken
            }
          }
        )
        .then(response => {
          this.submitForm(response);
        });
    },

    async submitForm(response) {
      if (this.page === "singlejob") {
        var position = this.jobs.title;
      } else {
        var position = this.position;
      }

      let config = {
        headers: {
          Accept: "json",
          "Content-Type": "application/hal+json"
        }
      };

      this.isLoading = true;

      axios
        .post(
          `https://example.com/webform_rest/submit?_format=json`,
          {
            webform_id: "job_applications",
            name: this.name,
            email: this.email,
            position: position,
            resume: response.data.fid[0].value
          },
          config
        )
        .then(response => {
          this.isLoading = false;
          if (response.data.sid) {
            this.$router.push({
              path: "/thank-you"
            });
          }
        })
        .catch(error => (this.isLoading = false));
    }
  }

```

Need help here. Thanks

# Answer
I got it working. two things I was missing.

1. Make sure you accept all the operations / JSON requests from here /admin/config/services/jsonapi
2. I was confused with "binary file data". So basically you don't have to do anything with the file. No formData, No base64, just pass your file variable as it is.

And it worked.

Thanks
> 0 votes

---
Tags: webforms
---


# Question
Title: How do I per-variation add to cart button In Views with no selection?
I have a table that displays rows of products with there attributes, the last item on each row has the variation add to cart form. The view's self sorts on the product id to display all the variations for the product.

The issue is it can't select the variation for each row automatically, it always expects the user to choose the right variation from a dropdown.

Any changes that do not have the drop-down displayed **defaults** to only the **first product item in the table**. I have tried the relationship to the product and product id and variation cart form modules but these also failed to deliver.

I there a way in views to add a per-variation add to cart button with no selection in views table?

# Answer
> 1 votes
I finally found the answer from help on this post. here Although, I still had a few issues and mine ended up being slightly different, so I will lay out what I did to achieve this.

I am using a view table but really any sort of display using fields with grids should work the same.

1. Install the module Add to cart link
2. Create a new display on your product variation called what you like I am using 'view' with only the **add to cart link** field.
3. In your view add the **display** type you require.
4. Add Relationship: **variations** (Relate each Product with a variations set to the product variation.)
5. Add Relationship: **Product**
6. Add contextual filter: **Product: ID** \- Provide default value Product ID from URL
7. Add Field **Rendered entity** \- Product variation
8. Select your display from the view mode.
9. Save, add your view and output your view to your product page.

Now you will see all the Add to cart buttons displayed for each variation on the product with the right token add to cart link for each.

# Answer
> 2 votes
You can also be done using the Drupal module Direct Checkout

You can then build your own Drupal commerce buy now link or button in any view using the global custom text, by simply adding the following code.

```
<a href="/direct-checkout-by-url/products={{ sku }}" class="btn btn-default">Add to cart</a>

```

---
Tags: views, 8, commerce
---


# Question
Title: How to get a field in a exposed filter criteria as an autocomplete?
In a view the field which has widget autocomplete does not get an option to select as dropdown or autocomplete in exposed filter criteria. I have a field in a content type which has following properties.
Type : **entity reference**
widget : **autocomplete**
How can I set a exposed filter criteria field as autocomplete ?

# Answer
You can use Views Autocomplete Filter for getting autocomplete exposed filter in views. Module page says :

```
Add autocomplete functionality to the views filter text fields.

 - It works for node titles or cck text fields.
 - The autocomplete results are actually the view results, so they are view related.

```

But the field which you will expose & use autocomplete should be in the views result fields as well.
> 4 votes

# Answer
This drupal.stackexchange post shows that a current patch that needs review and is slated for 1.0 release adds this functionality to Views:

View with entityreference: make exposed filter autocomplete

The related issue queue request is here:

https://drupal.org/node/1492260

The answer to your question is to apply the patch found in the issue queue. If you dont know how to do that -- now is a great time to learn something new about patch files, Linux, DrushMake or Git.
> 1 votes

# Answer
For Drupal 8, apply the patch from Generalize TaxonomyIndexTid filter to be available for all entity reference fields.
> 0 votes

---
Tags: 7, views, entities, ajax
---


# Question
Title: how disable edit for a certain content type, and a certain role,
in a drupal 7 site i have been given to maintain, it seems that permissions are not working as expected. I check and uncheck the buttons for a certain user role, but that user role always has the right to edit any node that belongs to this particular type. 1. What could be the cause for this? 2. If this is not working from the gui, how i could achieve something similar with code? I would appreciate an example

# Answer
In `/admin/people/permissions` Under "Node" category you can uncheck the permission "Edit content X" for your desired role.

I would recommend using this module if your site has a lot of modules/permissions since due max upload vars limitation by PHP could led to not storing your chages when submitting the form.

Also by code you can implement `hook_node_access` and put there some logic. Take a look on how core does it.

```
/**
 * Implements hook_node_access().
 */
function node_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : $node->type;

  if (in_array($type, node_permissions_get_configured_types())) {
    if ($op == 'create' && user_access('create ' . $type . ' content', $account)) {
      return NODE_ACCESS_ALLOW;
    }

    if ($op == 'update') {
      if (user_access('edit any ' . $type . ' content', $account) || (user_access('edit own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
        return NODE_ACCESS_ALLOW;
      }
    }

    if ($op == 'delete') {
      if (user_access('delete any ' . $type . ' content', $account) || (user_access('delete own ' . $type . ' content', $account) && ($account->uid == $node->uid))) {
        return NODE_ACCESS_ALLOW;
      }
    }
  }

  return NODE_ACCESS_IGNORE;
}

```
> 1 votes

# Answer
In answer to your first question, this existing answer about debugging access permissions should be able to help you uncover what is causing this unexpected behavior.

https://drupal.stackexchange.com/a/17435/34061
> 0 votes

---
Tags: 7, nodes
---


# Question
Title: Multiple versions of the same menu, based on associated term?
I am trying to create a site with different portals. Each portal displays content filtered to that person's user tag, i.e. Student, Staff, etc. It's easy to create a view that displays nodes with that user tag (taxonomy term), but I am looking to have a user tag-specific menu. Many items in my menu structure apply to multiple user tags, some to only one or the other. How can I have the portal page display a menu that only contains nodes with the appropriate tag?

I know that if I used actual Drupal roles I could give permissions to the pages, and then when someone is logged in with the appropriate role, they only see the pages that they have permission to see. This is the same idea, but I don't want to require users to log in. Only access the menu through a specific portal.

Hopefully I described that well enough, thanks for any suggestions!

# Answer
I've done this just recently by implementing a single menu that shows different links depending on the context (in your case the context is a portal). The one menu will have all the links for all portals, and is set to rebuild itself on each context containing the relevant links for that context. You can do this as follows.

1. Implement hook\_node\_access\_records() and hook\_node\_grants() to create viewing access records on the nodes that only allows for them to be viewed on the portal to which they belong.
2. Alter the canonical route for nodes to provide a custom access callback. This access callback will include a check on whether the user has viewing access to the node. This will ensure that nodes only show up in the menu when on the portal to which they belong.
3. Create a custom cache context for your portal, so that the menu can be set to vary by portal.
4. Set your menu block to have the portal cache context, so that the menu is rebuilt for each portal, showing the correct menu items for the given portal.

# 1) Implement node grants

Node grants involve two hooks, hook\_node\_access\_records() and hook\_node\_grants().

First, hook\_node\_access\_records(). This hook is called upon node save. In it you perform calculations to determine upon which portals the node will be accessible. For your setup, you will set a record for each portal the node can be accessed at. Example:

```
function hook_node_access_records(NodeInterface $node) {
  $grants = [];

  // A grant needs to be added for each portal on which the node should be accessible.
  $grants[] = [
    // This will always be the same.
    'realm' => 'portal',
    // This will be the identifier of the portal.
    'gid' => 'portal_1,
    'grant_view' => 1
    'grant_update' => 0,
    'grant_delete' => 0,
  ];

  return $grants;
}

```

How you get the GID (the portal ID) of the node will depend on how your system is set up. It sounds like your portals are set up using taxonomy terms. If that's the case, in hook\_node\_access\_records() you can query that field to get the values from the taxonomy field and set your grants accordingly.

Next is hook\_node\_grants(). This hook is called anytime a node is accessed. This check will check if the user is on a portal, and add a grant for the current portal.

```
function hook_node_grants(AccountInterface $account, $op) {
  if ($op == 'view') {
    if ($portal = some_function_that_gets_the_current_portal_id()) {
      $grants = [];
      $grants['portal'] = $portal;
      return $grants;
    }
  }
}

```

This code will return a grant for the current portal. If the node being accessed also belongs to the current portal (by matching a grant set in hook\_node\_access\_records()), viewing permission will be shown.

# 2) Alter canonical node paths with a custom access callback.

With the above two hooks implemented, viewing access permissions for the node have been taken care of. However, the route is still accessible, as access permissions on the route only check if the user has 'access content' permission, and doesn't include a check on whether user has permission to access the node the route displays. When building menus, route permissions are checked, not access permissions on the node. So the next permission is to override the route, and provide a custom access callback that also checks whether the user has viewing access on the node. This way, due to the node grants set in steps one and two, when the menu is rebuilt, it will only add items to the menu if the user is on the portal the items belong to.

To do this, first an event subscriber is created to alter the routes:

```
namespace Drupal\my_module\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('entity.node.canonical')) {
      $route->setRequirement('_custom_access', 'Drupal\my_module\Access\PortalNode::access');
    }
  }

}

```

The above class will alter the `entity.node.canonical` route, giving it a custom access callback. The next thing to do is create `Drupal\my_module\Access\PortalNode::access()` and include the check on viewing permissions for the node. This class will look like:

```
namespace Drupal\example\Access;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class PortalNode implements ContainerInjectionInterface {

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * Constructs a PortalNode instance.
   *
   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
   *   The current user.
   */
  public function __construct(
    AccountProxyInterface $currentUser
  ) {
    $this->currentUser = $currentUser;
  }

  /**
   * {@inheritdoc}
   */
   public static function create(ContainerInterface $container) {
    return new static(
      $container->get('current_user')
    );
  }

  /**
   * Custom access callback for node canonical routes.
   *
   * @param \Drupal\node\NodeInterface
   *   The node whose canonical route is being accessed.
   *
   * @return \Drupal\Core\Access\AccessResult
   *   An access result that either provides or denies access.
   */
  public function access(NodeInterface $node) {
    // Allow access if the user has 'access content' permission (the default)
    // as well as viewing permission on the given node.
    return AccessResult::allowedIf(
      $this->currentUser->hasPermission('access content')
      &&
      $node->access('view')
    );
  }

}

```

Finally, the event subscriber needs to be registered in my\_module.service.yml so it is picked up, and the route is altered:

```
services:
  my_module.route_subscriber:
    class: Drupal\my_module\Routing\RouteSubscriber
    tags:
      - { name: event_subscriber }

```

# 3) Add a custom cache context for portals.

As your menu will need to differ by portal, it must have a cache context set for portal. There may already be a cache context you can use that matches the Drupal functionality behind your portals. You can check existing cache contexts here: https://www.drupal.org/docs/8/api/cache-api/cache-contexts#core-contexts

If the cache context you need does not exist, you'll need to create a custom cache context. Here's an example: https://medium.com/@joshirohit100/cache-context-drupal-8-part-2-10088f67012e

# 4) Set the menu block to vary by the portal cache context

At this point everything is mostly set up, however, the first time the menu is built, that version of the menu will be shown the same on all portals, as it has not been set to vary by portal cache context. Your system needs to have the menu block vary by portal - ie. variations of the menu must exist for each portal, since each portal will have a different list of links in the menu.

To do this, you'll implement hook\_block\_alter() in order to add a custom cache context on the menu block. You'll need to get the ID of the menu from your system. Let's assume it's "portal-administration".

```
/**
 * Implements hook_block_alter().
 */
function my_module_block_alter(array &$definitions) {
  $definitions['system_menu_block:portal-administration']['class'] = 'Drupal\my_module\Plugin\Block\PortalAdministrationMenuBlock';
}

```

Finally, the class defined in hook\_block\_alter() is created. It's extends the system default menu class, and adds the portal cache context to the menu block:

```
namespace Drupal\my_module\Plugin\Block;

use Drupal\system\Plugin\Block\SystemMenuBlock;

class PortalAdministrationMenuBlock extends SystemMenuBlock {

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    $cache_contexts = parent::getCacheContexts();
    $cache_contexts[] = 'portal';

    return $cache_contexts;
  }
}

```
> 1 votes

---
Tags: 7, navigation
---


# Question
Title: Issues while Updating drupa/slack to 8.x-1.2
The site I am working on is using drupal/slack ^1.2 in composer.json file but the module present in the instance and that in composer.lock is the dev version.

I ran a

```
lando composer require drupal/slack:^1.2

```

However, the module is not changing and neither is the composer.lock file.

FYI, The site is running inside lando.

How do I debug this problem?

Additional info

```
"prefer-stable": true,

```

Also the problem only seems to effect the slack module. The others seem to work fine.

# Answer
I figured out the problem. There was a custom module that had it's own composer.json listing the dev version of slack as a dependency.

This seems to have been overriding the root package version. I got to know this after removing the drupal slack as suggested here but the module remained on the web directory. So figured that some other package was listing it as a dependency.

Doing a grep led me to the file and updating the version in that composer.json and running lando composer update drupal/slack solved the problem.

Thanks for everyone's help.
> 1 votes

---
Tags: 8, composer
---


# Question
Title: \Drupal::database()->select with Expression used as Condition
I am trying to execute this query:

```
'SELECT sd.entity_id AS entity_id, WEEK(node__field_start_date.field_start_date_value) AS week, YEAR(node__field_start_date.field_start_date_value) AS year
FROM
{node__field_start_date} sd
INNER JOIN {node__field_plane_reservation} pr ON sd.entity_id = pr.entity_id
WHERE (sd.bundle = :db_condition_placeholder_0) AND (pr.field_plane_reservation_target_id = :db_condition_placeholder_1) AND (week = :db_condition_placeholder_2) AND (year = :db_condition_placeholder_3)'

```

And I am using this piece of code:

```
    $database = \Drupal::database();
    $query = $database->select('node__field_start_date', 'sd')
  ->fields('sd', ['entity_id']);

    // Expressions
    $query->addExpression('WEEK(sd.field_start_date_value)', 'week');
    $query->addExpression('YEAR(sd.field_start_date_value)', 'year');

    // Conditions
    $query
  ->condition('sd.bundle', 'reservation', '=')
  ->condition('pr.field_plane_reservation_target_id', $refPlane, '=')
  ->condition('week', $weekNo, '=')
  ->condition('year', $weekYr, '=');

    // Join Tables
    $query->join('node__field_plane_reservation', 'pr', 'sd.entity_id = pr.entity_id');

```

And whenever I execute it, it give me the error: Unknown Column 'week' in query or Unknown column 'year'. How do I use a condition with a pseudo column created with an expression?

# Answer
> 1 votes
```
 // Where Expressions
    $query->where('WEEK(sd.field_start_date_value) = :weekNo', array(':weekNo' => $weekNo));
    $query->where('WEEK(sd.field_start_date_value) = :weekYr', array(':weekYr' => $weekYr));

```

Apparently this can be achieved with $query-\>where();

---
Tags: database
---


# Question
Title: Can we get the title by node ID in a template file?
Is it possible to retrieve the title by node ID, based on the interface language.
I found `drupal_url('/node/101', {absolute: true})`.
I wish to have a similar function that returns a title passing a node ID.

# Answer
> 0 votes
Anyway I had to do this in preprocess function

```
function template_preprocess_field(&$variables) {
    $lang = \Drupal::languageManager()->getCurrentLanguage()->getId();
    $variables['node_101'] = \Drupal\node\Entity\Node::load(101)->getTranslation($lang)->getTitle();
    $variables['node_75'] = \Drupal\node\Entity\Node::load(75)->getTranslation($lang)->getTitle();
    $variables['node_103'] = \Drupal\node\Entity\Node::load(103)->getTranslation($lang)->getTitle();
}

```

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


# Question
Title: Copy data from Webform submission to a node?
I have pre-existing **node** authored by each user. However, for presentation purposes, I use a **Webform** to collect data from the user.

### Existing Node: Assessment

* field\_question1
* field\_question2
* field\_question3

### Webform

* field\_question1
* field\_question2
* field\_question3

On submit, I would like to compare "the user submitting the Webform" with the author of existing nodes, then set the field values of the submitter's existing node with the new values from the submitted webform.

This worked well in Drupal 7, but in Drupal 8 I don't seem to understand the syntax, nor do I see a place to set up or pass variables.

Can this be done in the current state of Drupal 8 Rules?

# Answer
> 1 votes
> Can this be done in the current state of Drupal 8 Rules?

To my knowledge the answer to your question is **No** (it's part of what this is all about).

If you're in for getting a better understanding about all this, then have a look at these links:

*One never realizes what **has been** done, only what **remains to be** done ...*

# Answer
> 1 votes
Here's a simple Rule that will react on a webform submission and create a new node of type "Article" with the article title set to the submission time to show how webform submission values may be used to set node values. This Rule assumes you have the default webform type "Contact" enabled.

Use the Rules 8.x-3.x-dev version and you can import this Rule and try it out for yourself.

```
langcode: en
status: true
dependencies: {  }
id: create_a_new_node_after_webform_submission
label: 'Create a new node after webform submission'
events:
  -
    event_name: 'rules_entity_insert:webform_submission--contact'
description: ''
tags: {  }
weight: 0
config_version: '3'
expression:
  id: rules_rule
  uuid: 55a23cf1-afbb-4801-87be-842423a008cf
  weight: 0
  conditions:
    id: rules_and
    uuid: 51465df7-ce1e-4e50-9ed6-34f7dba04355
    weight: 0
    conditions: {  }
  actions:
    id: rules_action_set
    uuid: e9b1732f-9d09-4b1f-965e-78a18288ed12
    weight: 0
    actions:
      -
        id: rules_action
        uuid: e0be8c6a-1ddc-45c9-8dc0-ae40d8f7451d
        weight: 0
        context_values:
          type: article
          title: '{{ webform_submission.created.value | format_date(''medium'') }}'
        context_mapping: {  }
        context_processors:
          type:
            rules_tokens: {  }
          title:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: 'rules_entity_create:node'
      -
        id: rules_action
        uuid: 4399f655-c6e7-4969-97a2-e8a7f8da8c7e
        weight: 0
        context_values:
          message: 'Article created: {{ webform_submission.created.value | format_date(''medium'') }}'
          type: warning
          repeat: false
        context_mapping: {  }
        context_processors:
          message:
            rules_tokens: {  }
          type:
            rules_tokens: {  }
          repeat:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_system_message

```

# Answer
> 0 votes
As far as I know, Rules can't create a node on a webform submission.

A better approach is to create a custom web form handler to produce the node for you. I submitted the recipe to do so in the following posting: How to create a node out of a webform submission?

---
Tags: 8, rules, webforms
---


# Question
Title: Getting Error : "You must declare "ids" as a unique array of fields in your source settings." while trying to migrate for paragraph in Drupal 8
I have created a yml configuration for migration from CSV source into drupal using composer. After running the "drush migrate:import mbe\_book\_paragharphs", I am getting the error as You must declare "ids" as a unique array of fields in your source settings.

I am using migrate\_source\_csv 8.x-3.1

```
id: mbe_book_paragharphs
migration_group: mbe_migrations
label: 'Import book paragraph'
source:
  plugin: csv
  path: '/var/www/html/drupal/author.csv'
  header_row_count: 1
  ids: [id]
process:
  field_mbe_title: Title
  field_mbe_author: Author
destination:
  plugin: 'entity_reference_revisions:paragraph'
  default_bundle: mbe_book
migration_dependencies: null

```

I need help on how to resolve this issue

In the YML configuration file, instead of "ids", i was using "keys" before but was getting the same error

# Answer
> 4 votes
As the error message suggests, `ids` needs to be an array, e.g.

```
source:
  plugin: csv
  path: '/var/www/html/drupal/author.csv'
  header_row_count: 1
  ids:
    id:
      type: integer

```

Do note that you're in a YML file here; it looks like you might have tried to use PHP array syntax.

---
Tags: 8, migrations
---


# Question
Title: How to add a custom attribute to the script tag via drupal_add_js?
As part of API implementation of Queue-it framework, I need to add extra custom attribute `data-queueit-c` into `script` tag, e.g.

```
<script
    data-queueit-c="MyClientID"
    type="text/javascript"
    src="//static.queue-it.net/script/queueconfigloader.min.js">
</script>

```

I'm aware you can add other attributes such as `defer`, however this one is custom.

I've tried the following code using `drupal_add_js`, but without luck:

```
drupal_add_js('//static.queue-it.net/script/queueconfigloader.min.js',
  [
    'type' => 'external',
    'data-queueit-c' => 'MyClientID',
  ]);

```

How this can be achieved?

# Answer
> 1 votes
It's old but I have the same problem (adding "crossorigin" attribute) and this is my answer :

* There is an issue about it here : https://www.drupal.org/project/drupal/issues/1664602
* @kenorb solution can't work because "drupal\_add\_js" add "script" tag automatically. But... you can try this workaround (a little dirty) : close the script tag and open yours without closing

.

```
drupal_add_js('//--><!]]></script><script src="//static.queue-it.net/script/queueconfigloader.min.js" data-queueit-c="MyClientID"><!--//--><![CDATA[//><!--', 'inline');

```

# Answer
> -1 votes
As for workaround, inline syntax can be used, e.g.

```
$js_code = "<script data-queueit-c='MyClientID' type='text/javascript' src='//static.queue-it.net/script/queueconfigloader.min.js'></script>";
drupal_add_js($js_code, 'inline');

```

---
Tags: 7, javascript
---


title: How to modify jsonapi response?

text:
# Question
Title: How to modify jsonapi response?
Hello Drupal community.

I have a “Product” content type with field\_alert\_date field.
The field date type is “Date only” so when I get jsonapi response
by accessing jsonapi/node/product I have the following output for this field:

```
"field_alert_date":"2020-02-22"

```

However, this response will be used by another program
and that program requires data in the following format:

```
"field_alert_date":"2020-02-22 0:00:00”

```

So I need to modify the jsonapi output to add “0:00:00” (or another time) without changing the field data type.
The program is not developed by me so I cannot change this requirement. I have to do something with the output of the jsonapi.

Could you please tell me if it is possible and how it can be implemented?

# Answer
> 4 votes
You can change the JSON output of a date field by implementing a custom Normalizer for date fields in a custom module. I got it to work using the following code. This is a bit of a hatchet job, so you'll want to clean up and stuff, but otherwise it should do the job:

/src/Normalizer/DateTimeCustomNormalizer.php:

```
<?php

namespace Drupal\custom_date_serializer\Normalizer;

use Drupal\serialization\Normalizer\DateTimeIso8601Normalizer;

/**
 * @internal
 */
class DateTimeCustomNormalizer extends DateTimeIso8601Normalizer {

  /**
   * {@inheritdoc}
   */
  protected $allowedFormats = [
    'RFC 3339' => \DateTime::RFC3339,
    'ISO 8601' => \DateTime::ISO8601,
    // used to be 'Y-m-d', so you can use any PHP date format you want
    // I just set it to this because it was easy to test
    'date-only' => \DateTime::ISO8601,
  ];
}

```

And /custom\_date\_serializer.services.yml:

```
services:
  custom_date_serializer.normalizer.datetimecustom:
    class: \Drupal\custom_date_serializer\Normalizer\DateTimeCustomNormalizer
    arguments: ['@config.factory']
    tags:
      # Priority must be higher than other datetime normalizers.
      - { name: normalizer, priority: 40 }

```

And you'll need an info.yml obviously.

---
Tags: 8
---


title: Nothing is saved in Account settings

text:
# Question
Title: Nothing is saved in Account settings
When I'm at this page "admin/config/people/accounts" I can't change anything of the settings. So I uncheck a checkbox or typ another value in an input. When I click the save button, the page reloads but the settings go back to the values before.

Anyone who knows the problem? Other pages does save my settings, it only appears on the "admin/config/people/accounts".

I use Drupal 8.

Thanks!

# Answer
In modules check for the `hook_user_admin_settings_alter`, check the form action and change it for the modules implementing those function

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

For reference sample forgot\_username module

Instead of this `$form['actions']['submit']['#submit'][] = 'forgot_username_user_admin_settings_submit';`,

use this `$form['#submit'][] = 'forgot_username_user_admin_settings_submit';`

In my case, forgot\_username module breaks the account savings.

Reference : https://www.drupal.org/project/private\_message/issues/2905184 Patch : https://www.drupal.org/files/issues/private\_message-admin\_settings\_submit\_handler\_beta18-2905184-3.patch
> -1 votes

---
Tags: 8
---


title: robots.txt encoding issue

text:
# Question
Title: robots.txt encoding issue
I'm in charge of a website for my company, which runs Drupal 7.66 (PHP 5.3.3), for a few years now. Since a few months, I discovered a strange behavior regarding the robots.txt file. In some case, the encoding is totally messed up.

Here is a brief description of the problem:

* If I am connected to the website: no problem, the robots.txt file is well displayed in the browser
* If I am NOT connected to the website (like all our users and the search engine robots): it randomly appears broken, and I identify that as an encoding issue. By “randomly”, I mean that sometimes when I check the robots.txt while not being connected, its ok, but sometimes it's broken. I can't find a pattern that will allow to reproduce the error.

The robots.txt is managed through admin/config/search/robotstxt thanks to the module RobotsTxt version 7.x-1.2

Here is a screenshot to illustrate the issue (I had to hide some parts of the images):

Of course, the webmarketing team noticed me that Google can't crawl the robots.txt file because of that issue:

I made quite a lot of searchs on drupal.org, Stackoverflow, Google... but couldn't find anything related. I am not a developer, but I work with a guy which is specialized in Drupal and he can not figure it out either.

Any idea? Of course if you need any further information, please let me know.

Thank you.

# Answer
> 1 votes
Problem solved.

Thanks to @hansfn comment, I found a similar issue on drupal.org: Doesn't work for anonymous users

I told about it to the developer I work with and he updated the RobotsTxt module from the version 7.x-1.2 to the version 7.x-1.4, and it solved the problem.

---
Tags: 7
---


title: Create "show all" link in Views pager

text:
# Question
Title: Create "show all" link in Views pager
I have created a view that displays titles of contents created by authenticated users. I have used pagination to display specified number of items per page. Besides this I want a "show all" link that when clicked displays all contents on single page I have enabled the views pager "more" link but this link redirects back to the same page besides displaying all the remaining contents.

How can I show a "show all" link in my pager?

# Answer
> 4 votes
The best way to achieve this is to create a separate page display for all content on a single page. Then add a Footer to the title display with a link to the full page display.

# Answer
> 1 votes
The "Include all items option" only works when the "Expose items per page" is checked. The "Expose items per page" creates an HTML form select list that will allow the user to select the number of items to display per page. Checking the "Include all items option" just adds an option to this HTML form select list to view all items but does not add a "View All" link to the pager. The only solutions I've had was to use a custom theme hook for the theme\_pager() within my theme's template.php file.

# Answer
> 0 votes
I run on the same problem not long ago ; it's because the **"more" link option only work with blocks**.

Under the advanced panel, there's an option "link display" which is displaying only with views blocks. There's an issue which is stated as won't fix, but some people still dicuss on it : https://www.drupal.org/node/1427854

In the mean time, you can simply add a "custom" more link in the footer.

Hope that help. Juda.

# Answer
> 0 votes
A contributed module is available for the same.

https://www.drupal.org/project/views\_extra\_pagers

---
Tags: views, paging
---


# Question
Title: How to route dynamic routes to a single node while keeping the urls?
I have a node `node/1` with the path alias `/path`. What I want is for `/path/*` to always behave like you went to `/path`, but not change the url. So going to `/path/test?something=1` should behave identically to going to `/path` but the url will still be `/path/test?something=1` in the user's browser.

Right now, I'm getting a redirect loop when I return the same url in the `processOutbound` method. If I just return `$path` in this method, the user gets redirected to `/path?something=1`.

My use case is a vue app that has it's own routing. But we need a node to allow the client to edit the content around the app.

Code below. Thanks!

```
<?php

namespace Drupal\gm_custom;

use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;

class PathSubscriber implements InboundPathProcessorInterface, OutboundPathProcessorInterface
{
    /**
     * Processes the inbound path.
     *
     * @param string $path
     *   The path to process, with a leading slash.
     * @param \Symfony\Component\HttpFoundation\Request $request
     *   The HttpRequest object representing the current request.
     *
     * @return string
     *   The processed path.
     */
    public function processInbound($path, Request $request)
    {
        if ($this->stringStartsWith('/plan/', strtolower($path))) {
            return '/node/1';
        }

        return $path;
    }

    public function processOutbound(
        $path,
        &$options = [],
        Request $request = null,
        BubbleableMetadata $bubbleable_metadata = null
    ) {
        $url = strtok($_SERVER[ "REQUEST_URI" ], '?');
        if ($this->stringStartsWith('/plan/', $_SERVER[ 'REQUEST_URI' ])) {
            return $url;
        }

        return $path;
    }

    protected function stringStartsWith($needle, $haystack)
    {
        return (substr($haystack, 0, strlen($needle)) === $needle);
    }
}

```

**Edit** I've confirmed it's the redirect module is the issue. Simply installing it creates the above problem. Still looking for a solution.

# Answer
Alright got it working! The redirect module hooks into the `kernel.request` event and will redirect if you're doing wildcard routing like I am below.

You may want to split this up into two services since we're hooking into two events, but they're directly related so I chose to keep it simple. Basic explanation of methods in here is:

**PathSubscriber::processInbound** Check the incoming url and map it to a single node

**PathSubscriber::getSubscribedEvents** Register our callback for the `kernel.request` aka `KernelEvents::REQUEST` event so we can stop the redirect module from redirecting.

**PathSubscriber::stopRedirectIfOurRoute** Check the path and if it matches against our wildcard routing from `PathSubscriber::processInbound` then set the `_disable_route_normalizer` to `true` to disable the redirect module from redirecting to the node's alias. Leave our urls alone!

---

**mymodule/src/PathSubscriber.php**

```
namespace Drupal\mymodule;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpKernel\KernelEvents;

class PathSubscriber implements InboundPathProcessorInterface, EventSubscriberInterface
{
    /**
     * Processes the inbound path.
     *
     * @param string $path
     *   The path to process, with a leading slash.
     * @param \Symfony\Component\HttpFoundation\Request $request
     *   The HttpRequest object representing the current request.
     *
     * @return string
     *   The processed path.
     */
    public function processInbound($path, Request $request)
    {
        if (self::stringStartsWith('/plan/', strtolower($path))) {
            return '/node/1';
        }

        return $path;
    }

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        // register our event right before the redirect module redirects
        $events[ KernelEvents::REQUEST ][] = ['stopRedirectIfOurRoute', 31];

        return $events;
    }

    /**
     * ------------------------------------
     * From the redirect module (redirect/src/EventSubscriber/RouteNormalizerRequestSubscriber.php):
     *
     * The normalization can be disabled by setting the "_disable_route_normalizer"
     * request parameter to TRUE. However, this should be done before
     * onKernelRequestRedirect() method is executed.
     * ------------------------------------
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     *   The event to process.
     */
    public static function stopRedirectIfOurRoute(GetResponseEvent $event) {
        $path = $event->getRequest()->getPathInfo();

        if (self::stringStartsWith('/plan/', strtolower($path))) {
            $event->getRequest()->attributes->set('_disable_route_normalizer', true);
        }
    }

    public static function stringStartsWith($needle, $haystack)
    {
        return (substr($haystack, 0, strlen($needle)) === $needle);
    }
}

```

---

**mymodule.services.yml**

```
services:
  mymodule.path_subscriber:
    class: Drupal\mymodule\PathSubscriber
    tags:
     - { name: path_processor_inbound }
     - { name: event_subscriber }

```
> 4 votes

---
Tags: 8, routes, path-aliases
---


# Question
Title: Hide/remove js-view-dom-id in just one specific view
I found, that the div with the id "js-view-dom-id" comes from views-view.html.twig. As I want to render one view output without any of Drupals HTML markup, I already hunted down the contextual links, which I can turn of for a specific view. Then I set the view format to an unused format, and removed all unwanted HTML markup from this views template as well.

Now I get plain {{ content.field\_x.0 }}-output from this view. The only element left I need to get rid of is before mentioned "js-view-dom-id". I could remove this from views-view.html.twig, but then I would remove it from all views.

Is there any way to remove this markup for only one specific view? To be precise, I am using a custom content view mode, if that makes any difference.

Thank you very much in advance!

@edit:

Twig in views-view.html.twig looks like this:

```
{%
set classes = [
dom_id ? 'js-view-dom-id-' ~ dom_id,
]
%}
<div{{ attributes.addClass(classes) }}></div>

```

Is there any way to do something like:

```
{% if view mode is xy %}
// Do nothing
{%  else %}
<div{{ attributes.addClass(classes) }}>
{% endif %}

```

# Answer
Yes, you can easily create an override for `views-view.html.twig` which will only apply to a single View.

Taking the example from Views template files:

> View, named foobar. Style: unformatted. Row style: Fields. Display: Page.
>
> * views-view--foobar--page.html.twig
> * views-view--page.html.twig
> * views-view--foobar.html.twig
> * views-view.html.twig

So if your View is called "articles", you can use `views-view--articles.html.twig` to override the template for the whole View, `views-view--articles--page.html.twig` to target just a display named `page` for the same view, and so on.
> 2 votes

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


# Question
Title: How to match a Drupal path in Apache config
My D8 site uses the usual convention in .htaccess to rewrite non-file requests to index.php:

```
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*) index.php [L]

```

However, if I try to perform a location match in my Apache 2.4 httpd.conf virtualhost, it fails because it seems that REQUEST\_URI is set to index.php.

```
<Location /foo/bar>
  #Directives that should fire when accessing /foo/bar but don't
</Location>

<Location /index.php>
  #Directives that do fire when accessing /foo/bar
</Location>

```

Any ideas for getting this to work? I have tried:

```
<If "%{REQUEST_URI} =~ m#^/foo/bar#">
  #Directives that should fire when accessing /foo/bar but don't
</If>

<If "%{REQUEST_URI} =~ m#^/index\.php#">
  #Directives that do fire when accessing /foo/bar
</If>

```

# Answer
> 1 votes
The directive I was trying to insert was `Require all granted`. I managed to achieve the same effect by proxy-passing requests for /foo/bar to another virtual host running on the same machine, but unreachable from outside. That 2nd virtual host did not require auth, which achieved the same effect as `Require all granted`.

```
ProxyPass /foo/bar http://example.local/foo/bar
ProxyPassReverse /foo/bar http://example.local/foo/bar

```

---
Tags: 8
---


title: Drupal From Network File Share

text:
# Question
Title: Drupal From Network File Share
We are working on a primary/secondary server configuration for a Drupal 8 install. I have been asked to look at the option of running the Drupal install from a file share so the same instance of Drupal can be shared across both servers. I have concerns about doing this, and I am looking for input from anyone who has tried this configuration. First, I'm just wondering if this is considered a best practice. More importantly, I would like feedback on performance, technical issues and any surprises you may have encountered.

# Answer
> 2 votes
I used to help support a major medical health organisation's website. The sysadmin there had the site running on 3 separate machines across two datacenters. It was D7 but should work with D8.

The setup was that there were 2 'production' machines and 1 edit machine. The edit machine was only accessible from inside the firewall. The production machines were behind separate varnish cache servers, tied together via a load balancer. All admin commands were blocked for this in the apache config so the Production boxes were basically read only.

They were connected by a MySQL clustered database with each machine having a MySQL node. The code base was local and pulled in via git.

I think they tried to use NSF to share the user files but had some issues (may have been due to firewall issues between the different sites). So I think he was actually using a permanent rsync script running to copy files uploaded on the edit machine to the production machines.

It was nice for code rollouts. He would duplicate the production database and set the edit machine to use the duplicate. We would pull in the new code, sync settings via features, and run QA on it. Once it passed, he would take one server out of production, change it to use the new DB, code from Git, and sync files with the edit server.

The load balancer was swapped to use the new code (new code/features available in \< 2s). Then update the other server offline.

He had a lot of different custom scripts to manage this so it was not that bad.

Also, although he didn't use it for production, he was using Aegir to manage the development environment we had. Basically, senior devs could use it to do code pulls and push stuff to the dev QA boxes.

YMMV

---
Tags: installation
---


# Question
Title: Where and how to conditionally redirect old aliases to new aliases
We are replacing a website with a new version. The domain is the same, but URL aliases in the new website are different.

In many cases, I can use an old alias to calculate its corresponding new alias. There are many thousands of old aliases, so I don't want to just use the Redirect module. I know how to write the calculations and how to check if a calculated new alias exists.

I need to know at what point I can intercept each incoming URL to calculate a new alias.

I also need to know how to redirect to the calculated new alias if it exists.

Concrete example:

A book chapter on the old site is at `example.com/recent/secrets-to-success/10-knowing-when-to-quit`. This chapter on the new site is at `example.com/secrets-to-success/knowing-when-quit`. The difference is (a) we no longer add the `recent` subfolder, (b) we've removed chapter numbers from chapter titles, and (c) we've changed which words are ignored when an alias is auto-generated.

When someone uses an old alias, I want to intercept it, calculate the new alias, check if it exists, and redirect to it if it does. This is only one example. There are several other ways of calculating, so there's some trial and error involved. But I know how to take care of that.

# Answer
> 4 votes
This solution is based on a suggestion by @4k4 at Redirect from within controller always goes to home page.

My custom module is named `rsc`.

In `modules/custom/rsc` the file `rsc.services.yml` includes the following:

```
services:
  rsc.event.Redirect404:
    class: Drupal\rsc\EventSubscriber\rscRedirect404
    tags:
      - {name: event_subscriber}

```

In `modules/custom/rsc/src/EventSubscriber` the file `rscRedirect404.php` contains the following:

```
<?php
namespace Drupal\rsc\EventSubscriber;

use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

class rscRedirect404 extends HttpExceptionSubscriberBase {

  protected function getHandledFormats() { // required
    return ['html'];
  }

  public function on404(GetResponseForExceptionEvent $event) {

    $path = \Drupal::request()->getPathInfo();
    $path = [code to modify the path from old site to new site]

    if (($url = \Drupal::service('path.validator')->getUrlIfValid($path))) {
      $event->setResponse(new RedirectResponse(URL::fromUserInput($path)->toString()));
    }
  }
}

```

With this in place, I see 404 redirects before they get passed to the default handler. If I do the `$event->setResponse()`, the user is redirected as I specify. If not, normal processing occurs.

In reality, the line that says `[code to modify the path from old site to new site]` is multiple lines where I do several trial-and-error tests to figure out the correct new URL, but everything else is just as I'm using it.

# Answer
> 3 votes
This has nothing to do with drupal. Need to edit the .htaccess file

```
RewriteEngine On
RewriteRule ^test/(.*)$ /new/$1 [R=301,L]

```

This will redirect `example.com/test/1` to `example.com/new/1`

# Answer
> 2 votes
> For example, what was example.com/old-style-alias might now be example.com/a-very-different-alias.

Redirect module is exactly what you need.

This can automatically add a redirect when you change the node's alias or you can manually add them to the redirect list, which gets saved to the DB.

---
Tags: 8, redirection, path-aliases
---


# Question
Title: How to disable the title field on the node edit form?
How can I hide or disable the title field on the node edit form?

If I do so from the content type Manage form display tab (`admin/structure/types/manage/CONTENT_TYPE_MACHINE_NAME/form-display`), then I get some integrity constraint errors in the log.

So I don't want to show default title field in Node edit form. If I hide the title field normally like other fields. Got white screen after node creation. And log says title field can't be null .... and so on ...

# Answer
You can use hook\_form\_alter() function to alter any form (including node edit form) and disable **Title** field. Check sample code below:

```
use Drupal\field_collection\Entity\FieldCollectionItem;

function [MODULE_NAME]_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  switch ($form_id) {
    case 'node_[CONTENT_TYPE]_edit_form':
      $form['title']['#disabled'] = 'disabled';
      break;
  }
}

```

If you're altering only one form you can check hook\_form\_FORM\_ID\_alter() function and change **FORM\_ID** with **node\_\[CONTENT\_TYPE\]\_edit\_form** where CONTENT\_TYPE is your node type form.

## EDIT :

To automatically set node title without allowing user to see title field, you can use Automatic Entity Label Module. The module is in dev version for D8, but we can give it a try if functioning properly.

If don't want to use Automatic Entity Label module, you can try doing same with custom code, check sample code here
> 7 votes

# Answer
tl;dr: **Specify a default title, and don't allow the user to change it.**

The D7→D8 change records state:

> **node\_type-\>has\_title removed in favor of entity form displays**
>
> Now that it is possible to configure the behavior of the node title widget using Entity form displays, the special flag to hide the title form element for nodes is no longer needed.
>
> To hide the title for a certain node type, use the "Manage form display" UI or hide it with a snippet like the following:
>
> ```
> $form_display = entity_get_form_display('node', 'article', 'default');
> $form_display->removeComponent('title');
> $form_display->save();
>
> ```

After reading that, I tried a few ways of doing it. Only the last one works, so this answer should serve as a warning of what *not* to try:

## Edit the entity\_form\_display config

If it is your own module, edit `core.entity_form_display.node.my_content_type.default.yml` and remove the `title` key from `content`. This works for fields, but if I remove the title or any of the other default things like promoted, created, etc., they are still displayed on the form at `/node/add/my_content_type`.

## Modify the entity\_form\_display in code

Add this code to `my_module_install` :

```
$form_display = entity_get_form_display('node', 'my_content_type', 'default');
$form_display->removeComponent('title');
$form_display->save();

```

This works visually, but there are three problems with this solution: \- It still causes the integrity constraint errors you refer to. \- It causes the config in the database to override the config in the file at install time, which is a bad idea, IMHO. \- `entity_get_form_display` is deprecated

## Hide it in the entity\_form\_display config

Hide it, but don't remove it. In `core.entity_form_display.node.my_content_type.default.yml`:

```
hidden:
  title: false

```

By trial and error, I found the logic to be reversed here. This, too, causes the integrity constraint errors you refer to.

## Hide it using CSS

I tried this, and it seems that empty strings are also disallowed for the title. So you either have to create your own entity type, which reimplements most of the code from the core node module, or...

## The only working solution I could find

Specify a default title, and don't allow the user to change it.

```
function my_module_form_node_my_content_type_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  $form['title']['#disabled'] = 'disabled';
  $form['title']['widget'][0]['value']['#default_value'] = 'none';
}

```

You could change `none` to `my_module`, a timestamp, or your favourite brand of peanut butter.
> 4 votes

# Answer
This is how I solve this issue in a project. At this moment Automatic Entity Label don't have a Drupal 8 version, if you see the code you will find only a info.yml file.

You always need to set the title, so in the creation of the entity you set the title.

```
use Drupal\node\NodeInterface;

/**
 * Implements hook_ENTITY_TYPE_create
 */
function YOUR_MODULE_node_create(NodeInterface $node) {
  switch ($node->getType()) {
    case 'CONTENT_TYPE_MACHINE_NAME':
      $node->title = 'Date: ' . date('Y-m-d G:i:s');
      break;
  }
}

```

And the other part is hide the title in the node form, to do this you can use:

```
/**
 * Implements hook_form_alter().
 */
function YOUR_MODULE_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  //With this you will know your form_id (see in the next function YOUR_FORM_ID)
  dpm($form_id);
}

```

And in this hook you will hide the title, with this you do the trick

```
/**
 * Implements hook_form_FORM_ID_alter().
 */
function YOUR_MODULE_form_YOUR_FORM_ID_alter(array &$form, FormStateInterface $form_state, $form_id) {
  $form['title']['#access'] = FALSE;
}

```
> 2 votes

# Answer
You could also use the automatic node title module. This will allow you to set the node title to whatever you want in the content type configuration, but will not display the field on add or edit.
> 1 votes

# Answer
I found the title to be useful in many ways in the layout builder: \- Show content preview \- Use it as block Id

My solution generates automatic titles by using the block type title and counting the number of blocks from the same type.

```
function [module]_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

  if ($form_id === 'layout_builder_add_block') {
    // Get the blocks plugins id counter.
    $bundle = $form['settings']['block_form']['#block']->bundle();
    $plugin_id = 'inline_block:' . $bundle;

    // Get the blocks plugins id count array.
    if ($node = $form_state->getTemporary()['gathered_contexts']['layout_builder.entity']->getContextData()->getEntity()) {
      $block_count = 0;
      foreach ($node->layout_builder__layout as $section) {
        $components = $section->section->getComponents();
        foreach ($components as $block) {
          if ($plugin_id === $block->getPluginId()) {
            $block_count += 1;
          }
        }
      }
    }

    // If not exist start from 0.
    // Insert default title.
    $form['settings']['label']['#default_value'] = t('%title-%title_id', [
      '%title' => $form['settings']['admin_label']['#plain_text'],
      '%title_id' => $block_count,
    ]);
    // Change title description.
    $form['settings']['label']['#title'] = t('Block id');
    $form['settings']['label']['#description'] = t('Automatic id generator. Can be modified by user but must be unique.');
    // Update and hide display title checkbox.
    // $form['settings']['label_display']['#default_value'] = FALSE;
    // $form['settings']['label_display']['#access'] = FALSE;
  }

  if ($form_id === 'layout_builder_update_block') {
    // Change title description.
    $form['settings']['label']['#title'] = t('Block id');
    $form['settings']['label']['#description'] = t('Automatic id generator. Can be modified by user but must be unique.');
    // Update and hide display title checkbox.
    // $form['settings']['label_display']['#default_value'] = FALSE;
    // $form['settings']['label_display']['#access'] = FALSE;
  }
}

/**
 * HOOK_preprocess_block.
 */
function [module]_preprocess_block(&$variables) {
  // Add id into block.
  $label = qfcc_structure_normaliseLabelToId($variables['label']);
  if (!$label) {
    $label = rand(100, 999);
  }
  $variables['attributes']['id'] = 'block-' . $label;
}

function [module]_normaliseLabelToId($text) {
  if (!$text) {
    return NULL;
  }

  $text = trim(strtolower($text));
  $text = str_replace(' ', '-', $text);
  $text = str_replace('_', '-', $text);
  $text = preg_replace('/[^a-z0-9\-]/', '', $text);
  return $text ?? NULL;
}

```
> 0 votes

---
Tags: 8, nodes, forms
---