# Question
Title: Uncaught TypeError: $(...).dialog is not a function: How do I include dialog?
I have added this code in my JavaScript file.

```
$( "#sponsor_dialog" ).dialog({
      autoOpen: false,
      height: 'auto',
      width:  520, resizable: false,
      show: {
        effect: "blind",
        duration: 1000
      },
      hide: {
        effect: "explode",
        duration: 1000
      }
    });

    $( "#sponsor_opener" ).click(function() {
      $( "#sponsor_dialog" ).dialog( "open" );
    });

```

I get the following error:

> Uncaught TypeError: $(...).dialog is not a function

In the module\_name.libraries.yml I have added this.

```
sponsor_form:
  version: 1.x
  js:
    # For some reason, you need to put the js directly under 'js'.
    js/sponsor_form.js: {}
  dependencies:
   - core/jquery
   - core/drupal.ajax
   - core/drupal
   - core/drupalSettings
   - core/jquery.once

```

I am checking it when a user is logged out. Does this affect it in any way? I have the same problem when I am logged in, though.

# Answer
> 5 votes
Drupal does not assign "$" to jQuery. That is because there may be libraries, which want to do something different with "$".

So you have to do this yourself:

```
(function ($) {
$( "#sponsor_dialog" ).dialog({
      autoOpen: false,
      height: 'auto',
      width:  520, resizable: false,
      show: {
        effect: "blind",
        duration: 1000
      },
      hide: {
        effect: "explode",
        duration: 1000
      }
    });

    $( "#sponsor_opener" ).click(function() {
      $( "#sponsor_dialog" ).dialog( "open" );
    });
})(jQuery);

```

# Answer
> 4 votes
In your module\_name.libraries.yml folder, you need to add `core/drupal.dialog` as a dependency.

```
sponsor_form:
  version: 1.x
  js:
    # For some reason, you need to put the js directly under 'js'.
    js/sponsor_form.js: {}
  dependencies:
   - core/jquery
   - core/drupal.ajax
   - core/drupal
   - core/drupalSettings
   - core/drupal.dialog
   - core/jquery.once

```

# Answer
> 0 votes
Adding `- core/drupal.dialog` under `dependencies:` of my library in my \[theme\].libraries.yml file fixed this issue for me.

---
Tags: 8
---


# Question
Title: Rules scheduler reacting on last comment?
I have a content type with comments activated and would like to have a rule that triggers a component when there is no new comments posted after a week. The component works as designed with rules scheduler, but I am having problems with creating a rule.

I have tried to create a rule that reacts on the event "After saving new comment". However, without proper conditions every comment will be scheduled to trigger the component one week after is is posted. The rule needs to overwrite existing scheduled actions if a new comment is posted on the same node. How can I achieve this?

# Answer
> 2 votes
To my knowledge, there is nothing in Rules to "*overwrite existing scheduled actions*" (as in your question). However, by every time attempting to perform an appropriate delete of an already scheduled rule, prior to scheduling a new rule, you achieve a similar result. And such attempt just gets ignored if there was no scheduled rule yet. Read on for more details ...

Have a look at my answer to "Rule to store user's last post date and scheduled rule based 30 day reminder" for an illustration about how to delete scheduled tasks, using the "`schedule_delete`". As explain in that answer: the `schedule_delete` that is part of this rule is to ensure that previously "scheduled" reminders will get removed when updating the data field (so that it only triggers 1 reminder, and with the most recent date).

To make this work (that you actually indicate the exact scheduled task to be deleted), you need to specify an appropriate "`identifier`", like "`[account:name]`" in my example. To understand how I know what in my case the identifier is of the task to be deleted, look at the way I specified my (new) scheduled task to be created: it is `"identifier" : "[account:name]"`, which is what I used as my identifier to schedule a task.

In your case, I think using the `node's ID` as part of the identifier would be a pretty good choice for such identifier.

# Answer
> 2 votes
> The rule needs to overwrite existing scheduled actions if a new comment is posted on the same node.

Yes, you can do this! And you don't have to delete any scheduled tasks. The key here is to use the scheduler action's `identifier` parameter correctly. There can only be one scheduled component per identifier, so if your identifiers are all the same (for example, a static string) you will only ever have one scheduled at a time. If your identifies uses the comment id (I think this is what you do now?) then each new comment will schedule a distinct new task. But if you make your identifiers contain the node id of the node that's being commented on, then each node can and will have at most one scheduled component. By using `"identifier" : "Reminder - [node:nid] has not had any comments for one week"` you will have at most one scheduled reminder component per node. If another comment is posted on that node within the week that will trigger the rule again and the newly-scheduled component will take the place of / overwrite the previously scheduled component for that node because it will have the same identifier.

Thus, every time a new comment is created it will trigger your rule which will schedule your reminder component for +7 days from now. If another comment is added to that same node, it will again trigger your rule and will schedule the reminder task with the same `identifier` so it overwrites the old reminder and resets the time to +7 days from the second comment. The reminder component will then only be executed if there has not been any new comments on that node for seven days.

***Disclosure***: I'm the Rules maintainer.

---
Tags: rules, comments
---


# Question
Title: How do I create and apply a configuration schema for an existing custom module?
I have a custom module, already running for a longer while, but I did not take into account that the configuration would have to support translation. I have had no config/schema/module\_name.schema.yml file at the time of installation.

I created the schema file, looked into implementing `hook_update()`. I was just about to start implementing it, but I checked the output of `\Drupal::service('config.typed')->getDefinition(DrupalHooks::CONFIG_KEY);` just in case. The schema file was automagically absorbed by either `drush cr`, or loaded by the code snippet itself.

I don't find my module listed on the admin/config/regional/config-translation page. Also, the other modules shown in that list seem to always have a *Translate* tab on their configuration page. My module doesn't get that either.

What am I supposed to do to make it translatable? Is there any hook I should implement, or am I missing something else?

# Answer
> 2 votes
To have the "Translate" tab listed on your module's configuration page you additionally need to provide a `module_name.config_translation.yml` in your module's root.

```
module_name.settings:
  title: 'Module Name'
  base_route_name: module_name.admin_settings
  names:
    - module_name.settings

```

Look for existing `module_name.config_translation.yml` file in core and contrib and you'll get the pattern no problem.

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


# Question
Title: Image Upload Issues Same Image Different File Name Always Receive This Error
We are currently working on fine tuning and updating the dev backend of our CMS we're rolling out for a new site.

I was familiarizing myself with the new system and uploaded some images in error.
I then deleted said images using module *Reports \> Audit Files \> Managed not Used*.
Once I removed the file another user tried to upload the same file with a different name and we keep getting this error.
We've removed the file from the Database and the file server but still get the below error every time.

New to Drupal 8 and this forum... If you have solution or work around please let me know.

# Answer
> 0 votes
You may have the File Hash module installed, and the *Optional duplicate file protection* feature enabled. That configuration would result in exactly the error message you're seeing, but obviously you may have custom code that does this instead.

If you are using File Hash, and don't want that functionality, you can either disable it at /admin/config/media/filehash, or uninstall the module entirely.

---
Tags: 8, media
---


# Question
Title: How does routing order / matches effect performance?
I have all the following GET routes defined in `my_module.routing.yml`:

```
my_module.members_uid:
  path: 'users/{user}'

my_module.members_uid_gid:
  path: 'users/{user}/group/{group}'

my_module.user.content.view:
  path: 'users/{uid}/{bundle}/{gid}'

```

All of these have the same requirements and options except they upcast different data types, and each has it's own controller.

All of my controllers execute correctly, however **is there any benefit to a particular order?** Or is there **any extra overhead from two matching except one dynamic parameter?**

# Answer
The order doesn't matter, routes are stored indexed by name. The first and the second route have a different component count, so they can't interfere. The second route gets priority over the third, because it has one more fixed component. So in this case the route matching doesn't need any complex calculations. In general route matching rarely affects performance because successful matches are cached.
> 1 votes

---
Tags: 8, routes, performance
---


# Question
Title: How do I compare two strings in a template file?
The template file I am using contains the following code.

```
foo is '{{ foo }}'
item.url is '{{ item.url }}'
{% if item.url == foo %}
  equal
{% endif %}

```

I was expecting this code to output *foo is 'test' item.url is 'test' equal*, but instead it outputs *foo is 'test' item.url is 'test'*; the *equal* part doesn't appear.

The following code works.

```
{% if 'test' == 'test' %}

```

This code doesn't work.

```
{% if item.url == 'test' %}

```

Why doesn't the code I am using work?

# Answer
> 3 votes
This depends on the context, but most likely `item.url` is not a native string variable `test`, but a function or a render array with the string representation / render result `test`.

This is similar to Drupal's well known `content` variable: When you render `{{ content }}`, you will get the string representation like `<div class="something">content...</div>`. But when you do a `dump` or `kint`, you will see that content is an array, and doing a comparision `{% if content = '<div class="something">content...</div>' %}` will be false too.

I'd recommend to always avoid boolean operations with rendered representations, always head for the raw data. E.g. don't do `{% if content.field_something.0 == 'my_value' %}`, instead inspect the entity `{% if node.field_something.0.value == 'my_value' %}`.

If you have to compare to a render array, you could do somehting like `{% if some_var|render == 'my_string' %}`.

---
Tags: theming
---


# Question
Title: Converting the login / register / password reset tabs into three different pages?
I want to separate the user account menu tabs structure into an individual page layout.

For short I want to remove the tabs, I know that the pages are different.

Snapshot attached.

What I have done so far is trying to use the theme suggestions but couldn't get any closer.

I get to know that it's being rendered from:

> themes/bootstrap/templates/block/block--local-tasks-block.html.twig

# Answer
You could create different twig templates for that three pages and remove the local tasks from the display. Depending on your theme, it may also be sufficient to just disable the "tabs" block on these three pages. Then you'd create a custom menu (and block) with these three links in it and display it where you need it.
> 1 votes

# Answer
You have to extend page.html.twig in your theme/templates folder with the name suggestion that you get on enabling twig debug and remove the header section from it.

Remove this code:

```
 {# Header #}
      {% if page.header %}
        {% block header %}
          <div class="col-sm-12" role="heading">
            {{ page.header }}
          </div>
        {% endblock %}
      {% endif %}

```

By this the tabs will be removed.
> 0 votes

# Answer
You can try this:

```
  function module_name_menu_local_tasks_alter(&$data, $route_name) {
  $routes = ['user.pass','user.login','user.register'];
  if (in_array($route_name, $routes)) {
    unset($data['tabs'][0]['user.login']);
    unset($data['tabs'][0]['user.pass']);
    unset($data['tabs'][0]['user.register']);
  }
}

```
> 0 votes

---
Tags: 8, theming, bootstrap-theme
---


# Question
Title: How do I make the same variable available to all my theme files?
In mytheme.theme I have the following:

```
function mytheme_preprocess(&$variables) {
 $current_path = \Drupal::service('path.current')->getPath();
 $result = \Drupal::service('path.alias_manager')->getAliasByPath($current_path);
 $variables['currenttab'] = explode('/', $result)[1];
}

```

This function is extracting the first dirname from my url, for example, httttp://server/dirname/pagename it sets currenttab to 'dirname'.

It is working reasonably well, but I notice that if I click around on my site in a specific way, occasionally I get a page where the sidebar template has the correct {{ currenttab }} but the navbar has the {{ currenttab }} value from an older page.

I thought this theme preprocess would make {{ currenttab }} be the same in all my theme templates, but that does not appear to be the case. Once this problem appears, I can reload the page many times and it persists. I think this is related to the order in which I change urls.

What is going on here?

# Answer
> 5 votes
You would have to add a cache context:

```
$variables['#cache']['contexts'][] = 'url.path';

```

Now you cache for each relative path a different version of the template.

However, it is not a good idea to add this context to all templates. Only add it to those templates you intend to use the variable, otherwise you fill up your cache with a lot of useless variations:

```
function mytheme_preprocess(&$variables, $hook) {
  if (in_array($hook, ['foo', 'bar'])) {
    $variables['#cache']['contexts'][] = 'url.path';
    // add variables depending on the relative url
  }
}

```

---
Tags: theming
---


# Question
Title: Changing position of the header in a view
I have the "Result summary" in the Header for my view however, it is being displayed at the top of the content. I would like it to be displayed in between the search form and the search results. I would like a detailed answer, since I am new to Drupal (8) - I have seen an answer about how to change the position of the header (or footer) using a template.

I can't obviously change it using the admin UI.

I am using Drupal 8.

Thanks!

# Answer
In your custom theme check if there is a `templates/views-view.html.twig` file

If not you you can get a copy from `core/themes/stable/templates/views/views-view.html.twig` and modify the position of `header` section to be below `exposed`

the content should look similar to the following after your change

```
...
{{ exposed }}
{% if header %}
  <header>
    {{ header }}
  </header>
{% endif %}
...

```

This will customize all views in your current installation

If you want to only modify a specific view you can name the file `templates/views-view--VIEWNAME.html.twig`

Here is more info on the template naming convention
> 2 votes

---
Tags: views
---


# Question
Title: How to show status messages in modal window?
Here, I tried many different ways to show status messages in pop window but was not able to get success in any way. So, basically i want to show all the status message of site in modal box whether it is configuration message or submit on site of form. Please give suggestion for this if any. Thank you

# Answer
The easiest would be by installing any from a few modules that do this out of the box

Two of the most used modules are nicemessages and better\_messages
> 0 votes

---
Tags: theming, status-messages
---


# Question
Title: Add Attachment to Rules Email - Drupal 8
I am trying to set up a simple rule in D8 that when a new node is created, an email is sent out that includes an attachment from the file system.

How can I accomplish this?

# Answer
> 1 votes
Drupal core does not provide a way to send HTML e-mail or to send e-mail with attachments. Thus, you will have to use a separate module which has this functionality AND which integrates with Rules. One such module is Mime Mail. Mime Mail does have a D8 port, but it's not complete. When it is complete, Rules in D8 is ready and able to use that functionality.

---
Tags: 8, rules
---


# Question
Title: Installing a module on a separate database
I currently have a Drupal 7 site with a big database. I have to install the Drupal Commerce module and I would like to install the module using a separate database.

I know I have to setup the second database in the settings.php file, but I don't know the next steps I should follow.

How can I tell Drupal to use a different database for a module I am installing?

# Answer
Drupal can be configured to use a different database for some of the tables. For example, with the following database settings, I would tell Drupal to use the *db2* database for the *users* table.

```
$databases['default']['default'] = array(
  'driver' => 'mysql',
  'database' => 'db1',
  'username' => 'username',
  'password' => 'password',
  'host' => 'localhost',
  'prefix' => array(
    'users' => 'db2.',
  ),
);

$databases['default']['db2'] = array(
  'driver' => 'mysql',
  'database' => 'db2',
  'username' => 'username',
  'password' => 'password',
  'host' => 'localhost',
  'prefix' => '',
);

```

It doesn't actually work for PostgreSQL because a bug in Drupal core, and it works for those database engines for which using a different schema means using a different database.

Doing so for every table used for a module is more problematic, since the prefix must be explicitly set for all the tables used for that module, which means:

* You need to know which tables are used for that module, including the tables Drupal creates for that module
* If a new version of the module uses tables the previous version didn't use, the prefix must be explicitly set before updating the module
* If a new version of Drupal uses tables for that module the previous version didn't use, the prefix must be explicitly set before updating Drupal
* If you plan to install another module that store data related to that module, the prefix for the new tables must be explicitly set before installing the new module

Furthermore, for data related to that module that are stored in a table that contains data from all the installed modules, storing that data in a separate table only for a module is probably impossible.

Using two multi-site instances—Drupal installations that use the same code base, are accessible from different URLs (for example, https://example.net instead of https://example.org, or https://example.com/commerce instead of https://example.com), and use different databases (which could also use different database engines)—where one of the instances has the Drupal Commerce module installed, you would resolve the problem to put all the Drupal Commerce tables in a different database.

You would not need to set which database is used for the Drupal Commerce module, as that is already set for each multi-site instance. This means that any change in the tables used for the Drupal Commerce module (which are created from the module itself, Drupal core, or any third-party module) would not require changes to the Drupal database settings. Even updating the Drupal Commerce module or Drupal core would not require extra work to change the Drupal database settings. It would work for any database engine supported by Drupal or from third-party modules.

Since the multi-site instances don't normally share any data, in the same way two different Drupal sites don't share any data, if you want that users with an account on the multi-site instance without the Drupal Commerce module are able to access also the multi-site instance with that module without creating an account, or be logged-in when they already logged in into the first instance, you need to implement SSO on both the multi-site instances. There would be other data duplicated between the two multi-site instances, but those data would probably be less than all the data stored for the Drupal Commerce module.
> 1 votes

---
Tags: 7, database, installation
---


# Question
Title: Should the Update Manager module be uninstalled when installing with Composer?
Drupal 8 is installed with Composer and I use it to update. So I uninstalled the Update Manager module provided by the core.

Now when I go to /admin/reports/status, I have the following warning.

>

Should the Update Manager module be uninstalled when Drupal is installed with Composer?

# Answer
> 0 votes
Personally, I have Update Manager installed on all my live sites.

While I use composer to manage all of my sites, I am do not blindly `composer update` and push out. I like to read changelogs and make sure I regression test thoroughly.

So, I have email notifications for updates turned on for all of my sites. Most are set for daily notification for all updates, but a handful of internal-only sites (as in behind the firewall) set for security updates only.

Then I can test and plan what updates go out when during my maintenance windows. Or for security updates, triage how critical they are to go out outside the normal windows.

---
Tags: 8, updating
---


# Question
Title: Javascript not working in body field. Using Full HTML
I have created a basic page. Inserted the following tripAdvisor your rating widget code in that which contains some javascript. Used Full HTML formatting. But instead of displaying the rating widget it's just displaying the TripAdvisor logo. How can we insert javascript in body?

```
<div id="TA_cdsratingsonlywide929" class="TA_cdsratingsonlywide"><ul id="4tBLqbUxyNxV" class="TA_links b9a34Zb66"><li id="UjhOoNfy" class="GDLP2q"><a target="_blank" href="https://www.tripadvisor.com/"><img src="https://www.tripadvisor.com/img/cdsi/img2/branding/tripadvisor_logo_transp_340x80-18034-2.png" alt="TripAdvisor"/></a></li></ul></div><script async src="https://www.jscache.com/wejs?wtype=cdsratingsonlywide&uniq=929&locationId=8678313&lang=en_US&border=true&backgroundColor=gray&display_version=2" data-loadtrk onload="this.loadtrk=true"></script>

```

Edit: I have tested the same code on another Drupal 8 Website and it's working without any issue in that.

The site on which the code is not working was upgraded to Drupal 8 from Drupal 7 and it's also configured on cloudflare. I tried to put cloudflare on development mode and also disabled the AdvAgg module but thats still not working.

Is there any settings in Drupal 8 which can disable javascripts scripts in Body field?

# Answer
Most likely , your FULL HTML content authoring text format settings are limiting the markup you can use, stripping out the script (that's default behavior).

You can either: 1. Modify the settings for the text format to not restrict markup 2. Create a new text format, without any of the filter options enabled; then switch the format on the body field in which you want to insert the script.

If these options still fail, you may have a theme where a preprocess hook or twig filter is stripping out the script.
> 1 votes

---
Tags: 8, javascript
---


# Question
Title: Adding an extra class to the last element of the navigation/tree menu
For one of my projects, I have to create a tree menu, with parents and children, that would be used to navigate through the website. The parents are collapsible. Below is the twig file that I am using to generate the menu:

```
{% macro menu_links(menu_tree, route_tid, current_depth, max_depth, collapsible) %}
{% import _self as macros %}
{% for item in menu_tree %}
  {%
    set liClass = [
      item.subitem and current_depth < max_depth ? 'menu-item menu-item--expanded block-taxonomymenu__menu-item block-taxonomymenu__menu-item--expanded' : 'menu-item block-taxonomymenu__menu-item',
      route_tid == item.tid ? 'menu-item--active block-taxonomymenu__menu-item--active' : ''
    ]
  %}

  <li class="{{ liClass|join(' ') }}">
    {% if item.image %}
      <img class="menu-item-image block-taxonomymenu__image" src="{{ item.image }}" {% if item.use_image_style == false %}height="{{ item.height }}" width="{{ item.width }}"{% endif %} />
    {% endif %}
    <span class="levels">
      <a href="{{ item.url }}" class="block-taxonomymenu__link {% if route_tid == item.tid %}active block-taxonomymenu__link--active{% endif %}">{{ item.name }}{% if item.show_count == true %} [{{ item.nodes|length }}]{% endif %}</a>
    </span>
    {% if item.subitem and current_depth < max_depth %}
      {% if item.interactive_parent %}
        <i class="far fa-plus-square parent-toggle" aria-hidden="true"></i>
      {% endif %}
      {% if collapsible == TRUE %}
        <ul class="menu block-taxonomymenu__submenu collapsed-submenu">
      {% else %}
        <ul class="menu block-taxonomymenu__submenu">
      {% endif %}
        {{ macros.menu_links(item.subitem, route_tid, current_depth + 1, max_depth, collapsible) }}
      </ul>
    {% endif %}
  </li>
{% endfor %}

```

{% endmacro %}

I wanted to know if it was possible to add an extra class to the last li class of the tree menu? I have actually tried to add **current\_depth == max\_depth ? 'item--last': ''** in the setliClass and **{% if current\_depth == max\_depth %}item--last{% endif %}"** in the li class="{{ liClass|join(' ') }}" part, but this is not working.

# Answer
> 0 votes
You should be able to apply an additional loop to iterate by specific menu\_level. Here is an example of a twig template that iterates over menu level variable: How to add classes to menu items in navigation twig template

Then use a condition to set the class within the for loop such as:

loop.last ? 'last'

See all the variables associated with for loops in twig here: https://twig.symfony.com/doc/2.x/tags/for.html

---
Tags: 8, theming, navigation
---


# Question
Title: what happen if i have the same route as path alias?
What if I have the following route in a custom module and a path alias that is equal to the route path?

```
mymodule.contact:
path: /contact
defaults:
    _controller: Drupal\mymodule\Controller\MyController::contact
requirements:
    _permission: 'access content'

```

# Answer
The alias gets priority over the route.
> 0 votes

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


# Question
Title: Why does this route work with a slash and not a dash?
I have defined a custom dynamic route that works, but isn't ideal:

```
/**
* Defines dynamic routes.
*/
class GuideUnitRoutes {

  /**
   * {@inheritdoc}
   */
  public function routes() {
    $route_collection = new RouteCollection();

    $route = new Route(
      "/guide_name/{guide_id}/{child}",
      [
        '_controller' => '\Drupal\guides\Controller\GuidesUnitController::view',
        '_title' => 'Hello',
      ],
      [
        'guide_id' => '\\w+',
        'child' => '\\w+',
        '_permission' => 'access content',
      ]
    );

    $route_collection->add("guide.child", $route);

    $route_collection->setMethods(['GET']);

    return $route_collection;
  }

}

```

If I define it to be ideal, it stops working:

```
/**
* Defines dynamic routes.
*/
class GuideUnitRoutes {

  /**
   * {@inheritdoc}
   */
  public function routes() {
    $route_collection = new RouteCollection();

    $route = new Route(
      "/guide_name-{guide_id}/{child}",
      [
        '_controller' => '\Drupal\guides\Controller\GuidesUnitController::view',
        '_title' => 'Hello',
      ],
      [
        'guide_id' => '\\w+',
        'child' => '\\w+',
        '_permission' => 'access content',
      ]
    );

    $route_collection->add("guide.child", $route);

    $route_collection->setMethods(['GET']);

    return $route_collection;
  }

}

```

The route that works is `guide_name/foo/bar` while `guide_name-foo/bar` doesn't work. I would like to know why.

Reading the Symfony docs it looks like this should be a problem. But for some reason Drupal isn't liking this. Is there an undocumented (or maybe a document that I missed) that forces tokens to be delimitated with `/`. right now if I change the `-` to a `/` and reload the same route it works.

# Answer
> 5 votes
The dash is not the problem, you could use a dash in the fixed part, but ...

> Unlike generic Symfony routes, Drupal requires that a slug occupies a complete path part - the portion between two slashes (or everything after the last slash).

https://www.drupal.org/docs/8/api/routing-system/parameters-in-routes/using-parameters-in-routes

Alternatively you can use path processing to rewrite the path to comply with the Drupal routing system. See Do new routes in Drupal 8 \*require\* a static first portion?

---
Tags: routes
---


# Question
Title: How to add separate class to menu link using hook
I want to add custom classes to the anchor tag in the main menu.

I implemented `hook_preprocess_menu()`, but it assigned the classes to the `<ul>` tag and I want to add the classes to the `<a>` tag.

The code I am using is the following one.

```
function menu_preprocess_menu(&$variables) {
  if ($variables['menu_name'] == 'main') {
    if (!isset($variables['attributes']['class'])) {
      $variables['attributes']['class'] = [];
    }
    $data = \Drupal::state()->get('my_data', 'bar');
    $variables['attributes']['class'][] = 'my-class';
  }
}

```

# Answer
Try to store your class in a variable out attributes:

```
function menu_preprocess_menu(&$variables) {
  if ($variables['menu_name'] == 'main') {
    $variables['my_magic_class'] = 'my-class';
  }
}

```

Now you have to override menu.html.twig template into your theme template folder

```
...
<a class="menu-item {{ my_magic_class }}" OTHER_LINK_ATTRIBUTES>LINK_TEXT</a>
...

```
> 0 votes

---
Tags: 8, theming
---


# Question
Title: Paginated form with ajax checkboxes throws "The specified #ajax callback is empty or not callable"
Using Drupal **8.7.7** I have a form which consists of a paginated table of users.

Each user row has a checkbox element in the form with an ajax event attached. This is essentially to allow me to store the selection in the users session as they select users and move to different pages.

The form works correctly on the first page, however when you move to the second page, only the first selection works. Any selection made after that throws the error:

> Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable. in Drupal\Core\Form\FormAjaxResponseBuilder-\>buildResponse() (line 67 of /var/www/html/web/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php).

Here is the buildForm contents:

```
public function buildForm(array $form, FormStateInterface $form_state) {
    /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
    $session = $this->requestStack->getCurrentRequest()->getSession();
    /** @var \Drupal\node\Entity\Node $node */
    $node = $this->requestStack->getCurrentRequest()->get('node');
    if (!$session->has($node->id().'_register_selection')) {
      $this->requestStack->getCurrentRequest()->getSession()->set($node->id().'_register_selection', []);
    } else {
      $selected = $session->get($node->id().'_register_selection');
    }

    $form['selected_users'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'selected-users'],
    ];

    $users = $form_state->getValue('user_list');
    if (!empty($users)) {
      foreach ($users as $user) {
        if ($user['check'] == TRUE) {
          $selected[$user['uid']] = $user['uid'];
        } elseif (array_key_exists($user['uid'], $users)) {
            unset($selected[$user['uid']]);
        }
        $session->set($node->id() . '_register_selection', $selected);
      }
    }

    if (!empty($selected)) {
      foreach ($selected as $item) {
        $form['selected_users'][$item]['user'] = [
          '#type' => 'item',
          '#markup' => t('user: @user', ['@user' => $item]),
          '#weight' => '0',
        ];
      }
    }

    $header = [
      ['data' => $form['user_list']['check_all'] = [
          '#type' => 'checkbox',
          '#title' => t('Select all'),
          '#return_value' => TRUE,
          '#wrapper_attributes' => [
            'class' =>['align-middle', 'm-0']
          ]
        ],
        'class'=> ['py-4']
      ],
      'uid' => ['data' => t('UID'), 'class'=> ['align-middle', 'py-4']],
      'username' => ['data' => t('Username'), 'class'=> ['align-middle', 'py-4']],
      'sits_id' => ['data' => t('SITS ID'), 'class'=> ['align-middle', 'py-4']],
      'name' => ['data' => t('Name'), 'class'=> ['align-middle', 'py-4']],
      'mail' => ['data' => t('Email'), 'class'=> ['align-middle', 'py-4']],
      'college' => ['data' => t('College'), 'class'=> ['align-middle', 'py-4']],
      'programme' => ['data' => t('Programme'), 'class'=> ['align-middle', 'py-4']],
      'course' => ['data' => t('Course'), 'class'=> ['align-middle', 'py-4']],
      'year' => ['data' => t('Year'), 'class'=> ['align-middle', 'py-4']],
    ];

    $form['user_list'] = [
      '#type' => 'table',
      '#header' => $header,
      '#empty' => t('No users found with the selected filters.'),
      '#prefix' => "<div class='table-responsive mt-3'>",
      '#suffix' => "</div>",
      '#attributes' => [
        'class' => ['table-sm'],
        'style' => 'font-size: .85rem',
      ]
    ];

    $query = $this->database->select('users_field_data', 'ufd');
    $query->leftJoin('profile', 'profile', 'profile.uid = ufd.uid');
    $query->leftJoin('profile__field_prof_sits_id', 'sitsid', 'sitsid.entity_id = profile.profile_id');
    $query->leftJoin('profile__field_prof_first_name', 'fname', 'fname.entity_id = profile.profile_id');
    $query->leftJoin('profile__field_prof_last_name', 'lname', 'lname.entity_id = profile.profile_id');
    $query->leftJoin('profile__field_prof_college', 'college', 'college.entity_id = profile.profile_id');
    $query->leftJoin('profile__field_prof_programme', 'programme', 'programme.entity_id = profile.profile_id');
    $query->leftJoin('profile__field_prof_course', 'course', 'course.entity_id = profile.profile_id');
    $query->leftJoin('profile__field_prof_sits_year', 'year', 'year.entity_id = profile.profile_id');
    $query->fields('ufd', ['uid','name', 'mail']);
    $query->addField('sitsid', 'field_prof_sits_id_value', 'sits_id');
    $query->addField('fname', 'field_prof_first_name_value', 'first_name');
    $query->addField('lname', 'field_prof_last_name_value', 'last_name');
    $query->addField('college', 'field_prof_college_target_id', 'college_gid');
    $query->addField('programme', 'field_prof_programme_target_id', 'programme_gid');
    $query->addField('course', 'field_prof_course_target_id', 'course_gid');
    $query->addField('year', 'field_prof_sits_year_value', 'year');
    $query->extend('Drupal\Core\Database\Query\TableSortExtender')->orderByHeader($header);
    $pager = $query->extend('Drupal\Core\Database\Query\PagerSelectExtender')->limit(10);

    $results = $pager->execute()->fetchAll();
    if ($results) {
      foreach ($results as $data) {
        $form['user_list'][$data->uid]['check'] = [
          '#type' => 'checkbox',
          '#ajax' => [
            'callback' => '::processUser',
            'wrapper' => 'selected-users',
          ],
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0', 'p-0', 'text-align-center']
          ],
          '#attributes' => [
            'class' => ['m-0'],
            'style' => 'position:relative;',
          ],
          '#default_value' => isset($selected[$data->uid]) ? TRUE : FALSE,
        ];

        $form['user_list'][$data->uid]['uid'] = [
          '#type' => 'item',
          '#markup' => $data->uid,
          '#value' => $data->uid,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['username'] = [
          '#type' => 'item',
          '#markup' => $data->name,
          '#value' => $data->name,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['sits_id'] = [
          '#type' => 'item',
          '#markup' => $data->sits_id,
          '#value' => $data->sits_id,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['name'] = [
          '#type' => 'item',
          '#markup' => $data->first_name . ' ' . $data->last_name,
          '#value' => $data->first_name . ' ' . $data->last_name,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['mail'] = [
          '#type' => 'item',
          '#markup' => $data->mail,
          '#value' => $data->mail,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['college'] = [
          '#type' => 'item',
          '#markup' => $data->college_gid,
          '#value' => $data->college_gid,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['programme'] = [
          '#type' => 'item',
          '#markup' => $data->programme_gid,
          '#value' => $data->programme_gid,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['course'] = [
          '#type' => 'item',
          '#markup' => $data->course_gid,
          '#value' => $data->course_gid,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];

        $form['user_list'][$data->uid]['year'] = [
          '#type' => 'item',
          '#markup' => $data->year,
          '#value' => $data->year,
          '#weight' => '0',
          '#wrapper_attributes' => [
            'class' => ['align-middle', 'm-0']
          ]
        ];
      }
    }

    $form['actions'] = [
      '#type' => 'actions',
      '#attributes' => [
        'class' => ['mb-4', 'd-flex', 'justify-content-center']
      ]
    ];

    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Register'),
      '#name' => 'update',
    ];

    $form['pager'] = ['#type' => 'pager'];

    return $form;
  }
}

```

And the processUser callback:

```
  public function processUser(array &$form, FormStateInterface $form_state) {
    return $form['selected_users'];
  }

```

This seems to work correctly without pagination. Enabling pagination makes it break. Has anyone experienced this before?

# Answer
I have now found that if you use a different approach to pagination the ajax issue is no longer present.

I removed the pagination extender in the database query and have initialised the pager manually.

This code now works:

```
public function buildForm(array $form, FormStateInterface $form_state) {
  /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
  $session = $this->requestStack->getCurrentRequest()->getSession();
  /** @var \Drupal\node\Entity\Node $node */
  $node = $this->requestStack->getCurrentRequest()->get('node');
  if (!$session->has($node->id().'_register_selection')) {
    $this->requestStack->getCurrentRequest()->getSession()->set($node->id().'_register_selection', []);
  } else {
    $selected = $session->get($node->id().'_register_selection');
  }

  $form['selected_users'] = [
    '#type' => 'container',
    '#attributes' => ['id' => 'selected-users'],
  ];

  $users = $form_state->getValue('user_list');
  if (!empty($users)) {
    foreach ($users as $user) {
      if ($user['check'] == TRUE) {
        $selected[$user['uid']] = $user['uid'];
      } elseif (array_key_exists($user['uid'], $users)) {
        unset($selected[$user['uid']]);
      }
      $session->set($node->id() . '_register_selection', $selected);
    }
  }

  if (!empty($selected)) {
    foreach ($selected as $item) {
      $form['selected_users'][$item]['user'] = [
        '#type' => 'item',
        '#markup' => t('user: @user', ['@user' => $item]),
        '#weight' => '0',
      ];
    }
  }

  $header = [
    ['data' => $form['user_list']['check_all'] = [
      '#type' => 'checkbox',
      '#title' => t('Select all'),
      '#return_value' => TRUE,
      '#wrapper_attributes' => [
        'class' =>['align-middle', 'm-0']
      ]
    ],
      'class'=> ['py-4']
    ],
    'uid' => ['data' => t('UID'), 'class'=> ['align-middle', 'py-4']],
    'username' => ['data' => t('Username'), 'class'=> ['align-middle', 'py-4']],
    'sits_id' => ['data' => t('SITS ID'), 'class'=> ['align-middle', 'py-4']],
    'name' => ['data' => t('Name'), 'class'=> ['align-middle', 'py-4']],
    'mail' => ['data' => t('Email'), 'class'=> ['align-middle', 'py-4']],
    'college' => ['data' => t('College'), 'class'=> ['align-middle', 'py-4']],
    'programme' => ['data' => t('Programme'), 'class'=> ['align-middle', 'py-4']],
    'course' => ['data' => t('Course'), 'class'=> ['align-middle', 'py-4']],
    'year' => ['data' => t('Year'), 'class'=> ['align-middle', 'py-4']],
  ];

  $form['user_list'] = [
    '#type' => 'table',
    '#header' => $header,
    '#empty' => t('No users found with the selected filters.'),
    '#prefix' => "<div class='table-responsive mt-3'>",
    '#suffix' => "</div>",
    '#attributes' => [
      'class' => ['table-sm'],
      'style' => 'font-size: .85rem',
    ]
  ];

  $query = $this->database->select('users_field_data', 'ufd');
  $query->leftJoin('profile', 'profile', 'profile.uid = ufd.uid');
  $query->leftJoin('profile__field_prof_sits_id', 'sitsid', 'sitsid.entity_id = profile.profile_id');
  $query->leftJoin('profile__field_prof_first_name', 'fname', 'fname.entity_id = profile.profile_id');
  $query->leftJoin('profile__field_prof_last_name', 'lname', 'lname.entity_id = profile.profile_id');
  $query->leftJoin('profile__field_prof_college', 'college', 'college.entity_id = profile.profile_id');
  $query->leftJoin('profile__field_prof_programme', 'programme', 'programme.entity_id = profile.profile_id');
  $query->leftJoin('profile__field_prof_course', 'course', 'course.entity_id = profile.profile_id');
  $query->leftJoin('profile__field_prof_sits_year', 'year', 'year.entity_id = profile.profile_id');
  $query->fields('ufd', ['uid','name', 'mail']);
  $query->addField('sitsid', 'field_prof_sits_id_value', 'sits_id');
  $query->addField('fname', 'field_prof_first_name_value', 'first_name');
  $query->addField('lname', 'field_prof_last_name_value', 'last_name');
  $query->addField('college', 'field_prof_college_target_id', 'college_gid');
  $query->addField('programme', 'field_prof_programme_target_id', 'programme_gid');
  $query->addField('course', 'field_prof_course_target_id', 'course_gid');
  $query->addField('year', 'field_prof_sits_year_value', 'year');
  $query->extend('Drupal\Core\Database\Query\TableSortExtender')->orderByHeader($header);
  $results = $query->execute()->fetchAll();

  if ($results) {
    $page = pager_find_page();
    $num_per_page = 5;
    $offset = $num_per_page * $page;
    pager_default_initialize(count($results), $num_per_page);
    $i = 0;
    foreach ($results as $data) {
      if ($i++ < $offset) continue;
      if ($i > $offset + $num_per_page) break;

      $form['user_list'][$data->uid]['check'] = [
        '#type' => 'checkbox',
        '#ajax' => [
          'callback' => '::processUser',
          'wrapper' => 'selected-users',
        ],
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0', 'p-0', 'text-align-center']
        ],
        '#attributes' => [
          'class' => ['m-0'],
          'style' => 'position:relative;',
        ],
        '#default_value' => isset($selected[$data->uid]) ? TRUE : FALSE,
      ];

      $form['user_list'][$data->uid]['uid'] = [
        '#type' => 'item',
        '#markup' => $data->uid,
        '#value' => $data->uid,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['username'] = [
        '#type' => 'item',
        '#markup' => $data->name,
        '#value' => $data->name,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['sits_id'] = [
        '#type' => 'item',
        '#markup' => $data->sits_id,
        '#value' => $data->sits_id,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['name'] = [
        '#type' => 'item',
        '#markup' => $data->first_name . ' ' . $data->last_name,
        '#value' => $data->first_name . ' ' . $data->last_name,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['mail'] = [
        '#type' => 'item',
        '#markup' => $data->mail,
        '#value' => $data->mail,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['college'] = [
        '#type' => 'item',
        '#markup' => $data->college_gid,
        '#value' => $data->college_gid,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['programme'] = [
        '#type' => 'item',
        '#markup' => $data->programme_gid,
        '#value' => $data->programme_gid,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['course'] = [
        '#type' => 'item',
        '#markup' => $data->course_gid,
        '#value' => $data->course_gid,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];

      $form['user_list'][$data->uid]['year'] = [
        '#type' => 'item',
        '#markup' => $data->year,
        '#value' => $data->year,
        '#weight' => '0',
        '#wrapper_attributes' => [
          'class' => ['align-middle', 'm-0']
        ]
      ];
    }
  }

  $form['actions'] = [
    '#type' => 'actions',
    '#attributes' => [
      'class' => ['mb-4', 'd-flex', 'justify-content-center']
    ]
  ];

  $form['actions']['submit'] = [
    '#type' => 'submit',
    '#value' => $this->t('Register'),
    '#name' => 'update',
  ];

  $form[] = ['#type' => 'pager'];

  return $form;
}

```
> 1 votes

# Answer
When adding ajaxified form elements in a loop I always use unique array keys on the lowest level:

```
      foreach ($results as $data) {
        $form['user_list'][$data->uid]['check' . $data->uid] = [
          '#type' => 'checkbox',
          '#ajax' => [
            'callback' => '::processUser',
            'wrapper' => 'selected-users',
          ],
          ...

```
> 0 votes

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


# Question
Title: How to disable panel cache for user menu?
I have a panel page and this page is front-page of my site. This page is not for anonymous users and having a user menu with welcome message like. Welcome \[Username\], then other user related menus.

But sometime it shows wrong welcome user name. For example there is two users UserA and UserB. First time UserA logins into site and it shows "Welcome UserA" after logout UserA other user UserB logs in to the site then welcome message is stills showing with UserA which is not correct.

This is may be due to Drupal cache because when I clear the all cache then it shows the Welcome message for UserB.

I have set the **nocache** from the panels pan setting for user menu.

How can I disable the cache for that page?

Thanks in advance.

# Answer
> 1 votes
Drupal has a lot of caching levels so you might need to "peel" each one off to know which level is caching the results. Since you're authenticated, it's not the page cache. And since you mentioned that you set the panel to "No Cache", then it's not the panel cache either.

You're probably facing the block cache here. You can either modify the block caching definition in code using `hook_block_info_alter` (see `hook_block_info` for the different caching levels), or use Block Cache Alter module to do that same thing via the admin interface.

# Answer
> 0 votes
First, check if you have installed the panels\_page\_cache module. If so, you should go to the panel edition and delete the cache as shown in the image.

---
Tags: 7, panels, caching
---


# Question
Title: Output og:image:url if the og:image exists
I'm working on a website with Drupal 8 and the metatags module. I need to not output the metatag `og:image:url` if the `og:image` exists.

If it possible to do using the module? If not I would have to create a module for that?

# Answer
> 0 votes
I found a module that did something similar and just changed a bit:

```
function remove_generator_page_attachments_alter(array &$attachments) {

  $has_image = false;
  $index_to_remove = -1;

  foreach ($attachments['#attached']['html_head'] as $key => $attachment) {

    if ($attachment[1] == 'og_image_url_0' || $attachment[1] == 'og_image_url') {
      $index_to_remove = $key;
    }

    if ($attachment[1] == 'og_image_0' || $attachment[1] == 'og_image') {
      $has_image = true;
    }
  }

  if($has_image && $index_to_remove > -1) {
    unset($attachments['#attached']['html_head'][$index_to_remove]);
  }

}

```

---
Tags: 8, meta-tags
---


title: run a drush command with another user

text:
# Question
Title: run a drush command with another user
I am using drupalvm to manage my vagrant machines and I want to be able to be able to log into the vagrant machine and run drush to sync with the dev/stage/prod environments. I cannot do this without a bunch of extra setup to pass ssh keys and change usernames.

I would prefer to just pass the ssh username along with the drush command. Does drush have an argument that allows me to do this? I was unable to find it in the docs.

# Answer
> 2 votes
I haven't been using a vagrant setup for a while, but back when I did, I used aliases similar to the one below:

```
$aliases['ogm'] = array(
  'remote-host' => '127.0.0.1',
  'remote-user' => 'vagrant',
  'ssh-options' => '-p 2222 -i /home/ga/.vagrant.d/private_key',
  'root' => '/srv/www/ogm.postfix.local/drupal',
  'uri' => 'http://ogm.postfix.local',
);

```

Something like this should still work for your DrupalVM sites.

n.b. `remote-user` is the ssh username.

# Answer
> 1 votes
To expand Greg answer. Here is my Drush alias for one of my project.

Put this script in your host `~/.drush` folder and rename to something like `PROJECT.aliases.drushrc.php`.

```
<?php
/**
 * Requirements:
 *   Make sure to upload your ssh key to prod and staging.
 *
 * Uploading of ssh key:
 *   $ ssh-copy-id username@hostname
 */
// Site stage environment.
$aliases['stage'] = array(
  'parent' => '@parent',
  'site' => 'PROJECT',
  'env' => 'stage',
  'uri' => 'STAGING_URL',
  'root' => '/path/to/drupal',
  'remote-host' => 'STAGING_URL', // hostname
  'remote-user' => 'USERNAME', // ssh user
);
// Site prod environment
$aliases['prod'] = array(
  'parent' => '@parent',
  'site' => 'PROJECT',
  'env' => 'prod',
  'uri' => 'PROD_URL',
  'root' => '/path/to/drupal',
  'remote-host' => 'PROD_URL', // hostname
  'remote-user' => 'USERNAME', // ssh user
);
// For local
$aliases['local'] = array(
  'parent' => '@parent',
  'site' => 'PROJECT',
  'env' => 'local',
  'uri' => 'LOCAL_URL',
  'root' => '/path/to/drupal',
  'ssh-options' => '-p 2222 -i /home/HOST_USERNAME/.vagrant.d/private_key',
  'remote-host' => '127.0.0.1', // hostname or IP of Vagrant, default to loopback
  'remote-user' => 'vagrant', // vagrant username, default to vagrant
);

```

To use this against `stage` and `prod` servers you need to upload your ssh-key first by doing `ssh-copy-id user@hostname`.

The to test if the script is working on your Vagrant machine.

`$ drush @PROJECT.local status` where `PROJECT` is the actual value of `site`.

To test on staging.

`$ drush @PROJECT.stage status`

And to test on prod.

`$ drush @PROJECT.prod status`

**NOTE**: You may need to clear your Drush cache first before running the above commands.

With Drush aliases you don't need to ssh on the target machine and execute Drush.

Hope this helps.

# Answer
> 1 votes
I have found a good number of ways to do this now.

First, to expand on @greg\_1\_anderson's answer. What I have done is install my remote aliases in my vagrant machine and then, using ssh agent forwarding, run drush from vagrant to connect to remotes. This only works because agent forwarding allows me to use my host keys on the vagrant machine and there is one modification to the alias that needs to be made:

```
$aliases['ogm'] = array(
   'ssh-options' => '-l frob',
);

```

Using ssh-option `-l frob` makes drush connect via ssh with my username which will match the key that is forwarded with ssh agent forwarding (this is default in DrupalVM now).

The second option is to set the username in the ssh-config on the vagrant guest.

In `~/.ssh/config`:

```
HOST *.example.com
  USER frob

```

This second option allows me to not modify the drush alias at all; all ssh connections to \*.example.com will use my host username as set in the ssh-config on the vagrant box.

---
Tags: drush, ssh
---


# Question
Title: How to redirect users after password reset from first time user
I am using hook function in my module to redirect users accordingly as below.

```
function mymodule_user_login($account) {
 if (!$account->getLastAccessedTime()) {
  // The user has never logged in before.
   return;
 }
 $response = new RedirectResponse('MyModuleFormUrl');
 $response->send();
}

```

First time users coming from their corresponding emails are getting redirected to change password page able to set new password and existing users are redirected to form page after successful login. But the problem is how to redirect users after successfully setting their password to my module form. From the code above I thought it should happen automatically but it isn't. Can anyone suggest some ideas.

Edit to the Question: So as suggested below I tried both the ways but still after the new user clicks save button on password reset page(setting his new password), he is not getting redirected to mymodule form page. Below are the codes I tried.

Method 1:

```
    function MyModule_form_alter(&$form, &$form_state, $form_id){
    if($_SESSION['first_time_login']==TRUE)
    {
       $_SESSION['first_time_login']==FALSE;
       $form_state->setRedirect('url');
    }

```

Method 2:

```
    function mymodule_user_form_alter(&$form,
    \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
    {
       foreach (array_keys($form['actions']) as $action) {
        if (isset($form['actions'][$action]['#type']) && $form['actions']
        [$action]['#type'] === 'submit') {
        $form['actions'][$action]['#submit'][] = 'mymodule_form_submit';
         }
       }
    }

    function mymodule_form_submit(array $form, FormStateInterface
     $form_state){
         $form_state['redirect'] = 'url';
     }

```

Final function which worked for me:

```
    function MyModule_form_alter(&$form, &$form_state, $form_id){
      if($form_id == 'user_form')
      {
        foreach (array_keys($form['actions']) as $action) {
           if (isset($form['actions'][$action]['#type']) && $form['actions']
           [$action]['#type'] === 'submit')
           {
            $form['actions'][$action]['#submit'][] =
               '_MyModule_user_profile_submit';
           }
       }
     }

      function _MyModule_user_profile_submit($form, &$form_state)
      {
           $response = new RedirectResponse('url');
           $response->send();
      }

```

# Answer
It's actually pretty easy, the user module adds `user_pass_reset` to the `form_state` all you need to do is check for that value:

```
function MyModule_form_user_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if ($form_state->get('user_pass_reset')) {
    $form['actions']['submit']['#submit'][] = '_MyModule_user_profile_submit';
  }
}

```
> 3 votes

# Answer
In your case you also need to alter the user form to add a handler after editing the user pass, e.g.

```
/**
 * Implements hook_form_FORM_ID_alter().
 */
function MYMODULE_form_user_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id)
{
  foreach (array_keys($form['actions']) as $action) {
    if (isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {
      $form['actions'][$action]['#submit'][] = '_mymodule_form_submit';
    }
  }
}

function _mymodule_form_submit(array $form, FormStateInterface $form_state){
  //Add logic for checking is this is first time logged in User
  $form_state->setRedirect('ROUTE_NAME');
}

```

UPDATE: I updated the code to reflect the correct redirection method. I tested it on a Drupal installation and it works. You should replate `ROUTE_NAME` with a defined and working route.
The only thing remaining for you is to add the logic to detect if this is the first time this User is logged in.
Hope that helps.
> 2 votes

# Answer
Let the system know that the user is logged in the first time.

```
function mymodule_user_login($account) {
  if (!$account->getLastAccessedTime()) {
   // The user has never logged in before.
   $_SESSION['first_time_login'] = TRUE;
  }
}

```

Then using hook\_form\_alter you can provide additional submit handler for reset pass form and check if first\_time\_login exists in the session, if so just use $form\_state-\>setRedirect(...) and then remove the value from your session.

Good luck.
> 0 votes

---
Tags: 8
---


# Question
Title: How to deny access if url is changed manually?
Maybe the way I'm doing this is not the correct one but here it goes.

I have a page in my site where I have a form. In that form I have a select list that I fill with user ids from a query.

So for example, my site has 10 users and the list will be filled with only user 3 and 7.

When I submit the form, the url is changed to have the uid as a parameter: &user=3 or &user=7

My problem is that I can change the url manually to other user I want and I'm not denied the access.

How can I deny access in this case?

# Answer
I've managed to solve this.

In my hook\_form I have:

```
$querystring = drupal_get_query_parameters();

```

So for this case I just need to check if the user in the url is in the array of users allowed. If not, I can deny the access to the page (I still don't know how to deny the access though)
> 0 votes

---
Tags: forms
---


# Question
Title: how to have a different page from the front page?
In my site, all my pages are the same as the front page. For example, I have our team block and price table on the front page, but I also see them in blog posts or article pages.

Why is this happening? How do I have a different page from the front page?

# Answer
When placing the block, you can set the block visibility conditions.

To get a block to show up only on the home page, you would set `<front>` and `Show for the listed pages` under the pages visibility section.
> 1 votes

---
Tags: blocks
---


# Question
Title: How to update a field on menu_link_content (added using menu_item_extras module) entity from node form
I have a checkbox field added to one of the menus using Menu Item Extras module. By default, the checkbox is checked and works as expected when I create a menu item via menu admin UI. however, when I create a menu item via node, the field doesn't get the default behavior (checkbox checked). I also checked the table (`menu_link_content__[field_name]`) and there is no entry for the menu item added via `node/add` form.

# Answer
> 2 votes
There are couple of problems here:

1. The node form has the menu fields hardcoded. See `menu_ui_form_node_form_alter()` and `menu_ui_form_node_form_submit()` for more details.
2. Turns out the root cause of the field issue is that the `Menu Item Extras` module updates the bundle value to menu name which happens on pre\_save hook of menu\_link\_content entity. Without menu\_name as bundle, the entity wouldn't have any fields associated.

One way to solve this issue is to implement a `hook_form_node_form_alter()` hook and update the bundle details before trying to update the custom field. Here is the code:

**1. mymodule/mymodule.module**

```

/**
 * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
 */
function mymodule_form_node_form_alter(&$form, FormStateInterface $form_state) {
  foreach (array_keys($form['actions']) as $action) {
    if ($action != 'preview' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {
      $form['actions'][$action]['#submit'][] = [
        \Drupal::service('mymodule.menu_link_content_helper'),
        'nodeSubmit',
      ];
    }
  }
}

```

**2. mymodule/src/MenuLinkContentService.php**

```
<?php

namespace Drupal\mymodule\Services;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\menu_link_content\Entity\MenuLinkContent;

/**
 * Class MenuLinkContentService
 *
 * @package Drupal\mymodule\Service
 */
class MenuLinkContentService  {

  /**
   * Entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * MenuLinkContentHelper constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   Entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * Form submission handler for menu item field on the node form.
   *
   * @param array $form
   *   Form array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function nodeSubmit(array $form, FormStateInterface $form_state) {
    if (!$form_state->isValueEmpty('menu')) {
      $values = $form_state->getValue('menu');
      if (!empty($values['entity_id'])) {
        // There is no bundle by default for menu_link_content entity.
        $menu_name = 'menu_link_content';
        if (!empty($values['menu_parent'])) {
          list($menu_name) = explode(':', $values['menu_parent'], 2);
        }
        $entity = $this->nodeSaveMenuLinkContent($values['entity_id'], $menu_name);
        // If no  menu item with given bundle, load and update bundle.
        if (!$entity) {
          $entity = MenuLinkContent::load($values['entity_id']);
          $entity->set('bundle', $menu_name)->save();
          $this->nodeSaveMenuLinkContent($entity->id(), $menu_name);
        }
      }
    }
  }

  /**
   * Updates additional field on menu link content entity.
   *
   * @param int $entity_id
   *   Entity ID.
   * @param string $menu_name
   *   Menu name.
   *
   * @return \Drupal\Core\Entity\EntityInterface|mixed|null
   *   An Entity. NULL, if no entity with given ID and bundle found.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  protected function nodeSaveMenuLinkContent($entity_id, $menu_name) {
    $storage = $this->entityTypeManager->getStorage('menu_link_content');
    // Using loadByProperties() as loading without bundle wouldn't bring the
    // custom field.
    $entities = $storage->loadByProperties([
      'bundle' => $menu_name,
      'id' => $entity_id,
    ]);
    $entity = reset($entities);
    if ($entity) {
      $entity->set('field_searchable', TRUE);
      $entity->save();
      return $entity;
    }
    else {
      return NULL;
    }
  }

}

```

Note: my checkbox field is `field_searchable`.

---
Tags: 8, nodes
---


# Question
Title: Added menu link not showed in menu configuration
I have a very weird problem. If I add a new menu item, I can do it without any error in the menu configuration page, but the item isn't showed in the menu in this page neither in the menu. If I check menu tables in mysql, the items are added. If I try to add another item, I can create a child of the other in the menu structure, but the item isn't showed.

# Answer
There are a couple possibilities for why your menu link isnt showing.

1. Have you checked that the menu being rendered is the same as the one you added the link? Typically, menus are rendered via Drupal's block layout settings. (Admin \> structure \> block layout) You can check that the menu rendered on your site is the same as the one you are adding the links to.
2. If using the Menu Block module, check that your menu block settings aren't set to display a fixed level of the menu or fixed trail.
3. Is the link you've added to a page or view on the site that has permission restrictions? This sometimes happens when trying to add custom admin routes.

If the settings above are correct, try flushing the drupal caches when updating menu links before checking on the front end.

In the case none of the above works, and you are on a development instance of the site, try switching to a standard theme (like Bartik) to quickly determine if somethingin your theme is preventing the links from rendering.
> 0 votes

---
Tags: 8, navigation
---


title: Aggregating Javascript files breaks JS

text:
# Question
Title: Aggregating Javascript files breaks JS
On my d8 site I have `AdvAgg CSS/JS Validator`, `AdvAgg Minify CSS`, `AdvAgg Minify JavaScript`, `AdvAgg Modifier` and `Advanced CSS/JS Aggregation` enabled.

I have standard settings used in the AdvAgg config. For JS specifically, I am using JSmin + and delivering gzip'd assets.

Under `admin/config/development/performance`, if `Aggregate JavaScript files` is unchecked, my JS files are delivered from the `js/optimized/` folder and JS runs correctly. When I check `Aggregate JavaScript files` on, assets are now placed from /js/ and javascript is broken.

Further, when I paste the optimized file name in `admin/config/development/performance/advagg/info`, for e.g.: `js_nrTZ3IQttmDSsRueLl0pyxRvunHefp0r1WyIh5cFezg.js` AdvAgg cannot find the file (but it can when aggregation is turned off).

Perhaps this all makes sense since aggregating JS files is a Drupal feature, but I've been down every related question/comment thread on google (changing .htaccess, adding tmp folders, changing folder permissions etc) and cannot find a fix for: AdvAgg is on with standard config, Aggregating JS files is on and javascript is broken. There are no obvious errors in the javascript console or drupal error log either.

**EDIT**

Here is what the file paths look like with aggregation on: `<script src="/sites/energyforum/files/js/js_tvBcOK6c8zbgb2_h2fxvH7fqhBBhGUnfOtQvWyXg1AM.js"></script>`

The files are actually there, e.g.:

Here is what they look like with aggregation turned off

`<script src="/sites/energyforum/files/js/optimized/js_dxIVcwvQ00owLGoUGPTfRYXU-T5rnj8Xi0cXfb3Kn58.0EvW5goc0mi1CLAZ226j56yYkdNjFXiaCYoOaoBMbKg.js?v=3.2.1"></script>`

And, of course, there are many more of them (and javascript works)

# Answer
> 1 votes
This is commonly a result of loading theme javascript before it's dependencies.

If your theme lists multiple external js dependencies, or just has multiple custo. Javascript files, you may need to assign weights to establish a load order. Refer to https://www.drupal.org/docs/8/theming/adding-stylesheets-css-and-javascript-js-to-a-drupal-8-theme

Likewise, if your theme depends on other javascript provided by other modules, be sure to list those dependencies in your theme.info.yml file.

After making any of the above changes, clear Drupal caches with aggregation turned on and retest.

---
Tags: 8, css-js-aggregation
---


# Question
Title: Need to alter "No Paragraph added yet. Select a Paragraph type and press the button below to add one." message - Paragraph Module
I am using paragraph bundle and I want to alter this message with my custom text "Please click on below button to add data".

# Answer
> 0 votes
You need to patch the contrib module. Patch here works for me.

---
Tags: 7, paragraphs
---


title: Share nodes to Slack

text:
# Question
Title: Share nodes to Slack
i want to share link of post in social media i find module addtoAny and module social media for sharing poste butI didn't find to share post to slack.

Any help?

# Answer
There are two modules, I didn't try them myself and I'm not sure what is your use case:
Drupal to Slack and Slack. Are these provide the functionality you want?

---

## Update

Ok, there are other modules for adding share buttons like Simple Addthis or the dev version of the original Addthis Module
> 0 votes

---
Tags: social-network
---


# Question
Title: How to pass rendered form results to page
Drupal 8.7.x

I have a custom form that currently replaces the form with the output of the form like so:

CalculationForm.php

```
  public function submitForm(array &$form, FormStateInterface $form_state) {

    ...

    // Result overview.
    $result = [
      '#theme' => 'THEME_calculation_overview',
      '#name' => !empty($values['company_name']) ? $values['company_name'] : $form_state->getValue('firstname') . ' ' . $form_state->getValue('surname'),
      '#product' => $product,
      '#address' => $address,
      '#results' => $result_clean,
      '#urls' => $product_urls,
    ];

    // Bundle (rendered) results.
    $results_overview .= render($result);

    // Show rendered results.
    $this->response->addCommand(new ReplaceCommand('#form-calculation-container', $results_overview));
}

```

Currently the form submission makes an ajaxcall that replaces the container which holds the form with the rendered output (Replacecommand). Because we can't track the form submission with GTM I'm switching over to a normal form submission which redirects to a page.

My question is, how can I pass $results\_overview to the redirect page and make it render as part of the content variable.

Thanks in advance

# Answer
> 3 votes
in your submitForm function you need to set rebuilt to true (the default is false) on the FormStateInterface then add the result as a value to the form\_state. And in the buildForm function you need to check for the presence of the results variable and accordingly you can add it to the form. Something like this:

```
  public function buildForm(array $form, FormStateInterface $form_state) {

    ...

    $result = $form_state->getValue('result');
    if($result){
      $form['calculation'] = $result;
    }

    ...

    return $form;
  }

```

and

```
public function submitForm(array &$form, FormStateInterface $form_state) {

  ...

  // Result overview.
  $result = [
    '#theme' => 'THEME_calculation_overview',
    '#name' => !empty($values['company_name']) ? $values['company_name'] : $form_state->getValue('firstname') . ' ' . $form_state->getValue('surname'),
    '#product' => $product,
    '#address' => $address,
    '#results' => $result_clean,
    '#urls' => $product_urls,
  ];

  $form_state->setRebuild();
  $form_state->setValue('result', $result);

}

```

---
Tags: forms
---


# Question
Title: Why does not the preview of the loaded image appear?
When I load an image into a Drupal 8 form, JS errors appear in the console and the file link is not displayed. I have a limit of 10 MB per file in Drupal. If I load an image of 1 MB or less, it works. If I load an image of more than 1MB, it does not load and there are errors in the consoles :

I load an image of less than 1 MB, it works:

I load an image of more than 1 MB, it is a failure (errors in the console and no warning) :

The form fields and my server are correctly configured :

The server and Drupal seem to me correctly set. How can I fix this ?

# Answer
> 0 votes
do you have access to the nginx configuration for this website? If so, you can add the following to the configuration and see what happens. It might set already to 1m:

```
http {
    #...
    client_max_body_size 10m;
    #...
}

```

---
Tags: 8, javascript
---


# Question
Title: Moving "vendor/" in a different location and symlinking it breaks drush
I'd like to have `vendor/` moved out of the Drupal 8 root and symlink it. Composer doesn't have any problem with that (all commands work) but when I issue any `drush` command, even `drush --version`, it breaks.

Steps to reproduce:

```
$ composer create-project drupal-composer/drupal-project:8.x-dev website --stability dev --no-interaction --prefer-dist
$ cd website
$ mv vendor ..
$ ln -s ../vendor vendor
$ drush --version

PHP Warning:  require(/tmp/test1/vendor/composer/../../load.environment.php): failed to open stream: No such file or directory in /tmp/test1/vendor/composer/autoload_real.php on line 70
PHP Fatal error:  require(): Failed opening required '/tmp/test1/vendor/composer/../../load.environment.php' (include_path='/tmp/test1/vendor/pear/archive_tar:/tmp/test1/vendor/pear/console_getopt:/tmp/test1/vendor/pear/pear-core-minimal/src:/tmp/test1/vendor/pear/pear_exception:.:/usr/share/php') in /tmp/test1/vendor/composer/autoload_real.php on line 70

```

Full log: https://pastebin.com/raw/eMDgkdHV

Can I achieve this somehow? Even if I need to temporarily edit some path in an autoloader php script.

I need to do this on the vagrant based dev environment where I'd like to pull `vendor/` out of the synced folder which is very very slow.

# Answer
> 1 votes
I managed to solve it via specifying an absolute path in the `vendor-dir` configuration of `composer.json`: https://getcomposer.org/doc/06-config.md#vendor-dir

---
Tags: 8, drush, composer
---


title: How can I add an age validator page?

text:
# Question
Title: How can I add an age validator page?
To access the site, all users (except the logged-in users) need to pass through an age gate. They can only leave the welcome page if they are 18 years or older.

I started by adding a session to my custom theme.theme file.

```
<?php

function scottishleader_preprocess(&$variables, $hook) {
  static $hooks;

  $route_name = \Drupal::routeMatch()->getRouteName();
  $response = new\Symfony\Component\HttpFoundation\RedirectResponse('/welcome');
  $session = \Drupal::request()->getSession();
  $session->set('initialSession', 'initial');

  if ($session->get('ageGate') == 'passed') {
    $session->remove('initialSession');
  }
  if ($route_name != 'agegate.route' && $session->get('initialSession') == 'initial') {
    $response->send();
  }
  if ($route_name == 'agegate.route' && $session->get('ageGate') == 'passed') {
    $homeRoute = new\Symfony\Component\HttpFoundation\RedirectResponse('/');

    $homeRoute->send();
  }
}

```

Next, I created a custom module for the age gate and the routing.yml looks like the following.

```
agegate.route:
  path: '/welcome'
  defaults:
    _controller: '\Drupal\agegate\Controller\AgeGateController::content'
    _form: '\Drupal\agegate\Form\AgeGateForm'
  requirements:
    _permission: 'access content'

```

The `AgeGateController` class renders a form.

```
class AgeGateController extends ControllerBase {
  public function content(){
    return \Drupal::formBuilder()->getForm('Drupal\agegate\Form\AgeGateForm');
  }
}

```

It was all working fine until I realized that, if I am logged and I try to access the front page, I get redirected infinite times!

So, for some reason, my code only works on users that aren't logged-in.

How can I create this age gate functionality?

# Answer
> 1 votes
Implement the redirect in a module. Either in a kernel request subscriber, see this change record https://www.drupal.org/node/2013014 or in a kernel response subscriber, see https://git.drupalcode.org/project/age\_verification/blob/8.x/src/EventSubscriber/pathGate.php.

The second example is from a contrib module you can try as it is. I don't have first-hand experience with this module, so I can't recommend or not recommend it, but this would be off-topic here anyway.

# Answer
> 0 votes
As others have pointed out, this logic belongs in a module, not in the theme.

In D7, you could do something like this using `hook_boot()` and `hook_init()`, but in D8 you'll use a route subscriber.

This article may be helpful:

https://chromatichq.com/blog/replacing-hookboot-and-hookinit-functionality-drupal-8

---
Tags: routes
---


# Question
Title: How to remove nodes with the same title from views listing?
Just this, how to remove nodes with the same tilte from views listing?

These nodes are NOT duplicated node, they only have the same title.

# Answer
> 1 votes
You can achieve this goal via using Views Distinct Module.

For more information go through the project documentation.

# Answer
> 0 votes
Download Views Distinct Module and follow the following steps. Click on the filed title -\> under VIEWS DISTINCT SETTINGS select filter repeats from Filter/Aggregate this field dropdown

---
Tags: views
---


# Question
Title: How do I change the description of a view?
I have some existing views for which I have written a developer guide description. Now I duplicated the views for some other task, Duplication is successful but I didn't find any possibilities to change the description of the view. I check advanced section of the view but not successful. The only way is to create a new view but it will take a lot of time and I already have it done in the existing views a few changes are required. But the description is different from the existing one.

# Answer
> 1 votes
When you edit a view, on the top right corner there is an *Edit view name/description* button.

>

---
Tags: views, 8
---


title: How to load a node based on its title?

text:
# Question
Title: How to load a node based on its title?
I only know the title of a node, and I want to load the node using `node_load()`.

How do I do that?

# Answer
In Drupal 6, you can use the following code.

```
$node = node_load(array('title' => 'node title'));

```

If you know the node's type as well, then you can use the following code.

```
$node = node_load(array('title' => 'node title', 'type' => 'page'));

```

node\_load() always returns a single node. That is because the function doesn't loop over the database query result resource returned from db\_query().

```
  if ($revision) {
    array_unshift($arguments, $revision);
    $node = db_fetch_object(db_query('SELECT ' . $fields . ' FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = %d WHERE ' . $cond, $arguments));
  }
  else {
    $node = db_fetch_object(db_query('SELECT ' . $fields . ' FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE ' . $cond, $arguments));
  }

```
> 17 votes

# Answer
In Drupal 7, the parameters for `node_load()` has been changed. To get the nodes that match some conditions, you should use the EntityFieldQuery class.

```
$query = new EntityFieldQuery();

 $entities = $query->entityCondition('entity_type', 'node')
  ->propertyCondition('type', 'your_node_type')
  ->propertyCondition('title', 'your node title')
  ->propertyCondition('status', 1)
  ->range(0,1)
  ->execute();

  if (!empty($entities['node'])) {
    $node = node_load(array_shift(array_keys($entities['node'])));
  }

```
> 50 votes

# Answer
### Drupal 7

Here is a simpler way (as already suggested by Clive and at SO):

```
$nodes = node_load_multiple(NULL, array("title" => "Foo Bar"));
$node = current($nodes);

```

and much easier to remember than using EntityFieldQuery class.

See also: Programmatically getting nodes by title in Drupal 7 at SO
> 14 votes

# Answer
In Drupal 7, you can use code similar to the following one.

```
$result = db_query("SELECT n.nid FROM {node} n WHERE n.title = :title AND n.type = :type", array(":title"=> $title, ":type"=> $type));
$nid = $result->fetchField();

```
> 11 votes

# Answer
In Drupal 8, run this:

```
$nodes = \Drupal::entityTypeManager()
  ->getStorage('node')
  ->loadByProperties(['title' => $title]);
foreach ( $nodes as $node ) {
  $node->doSomething(...);
}

```

`$node` will be a fully instantiated node object.
> 11 votes

# Answer
**Also in Drupal 8**

```
$nids = \Drupal::entityQuery('node')
->condition('title', 'YourNodeTitle')
->sort('nid', 'DESC')
->execute();

```

and next:

```
$node = \Drupal\node\Entity\Node::load(HEREYOUNODEID);

```

Dont forget you need

```
use Drupal\node\Entity\Node;

```
> 6 votes

---
Tags: nodes
---


# Question
Title: Changing an inner join to a left join in views 3.3?
Using views 3.3, I have a view in Drupal 7 where I am showing two content types. I have a filter criteria based on the value of a field that is attached only to one of the content types. So long as I have that field criteria, views is doing an `INNER JOIN`, which causes it not to return views of the first content type which doesn't have that field attached.

I copied the query from the view, changed the `INNER` to a `LEFT` join, pasted it into the mysql shell, and I got all the rows that I expected to get. But I don't know how to make those changes in the view editor.

I was playing around in the 'relationship' block on the view editor, but I didn't see where I could change the join type.

Am I able to change how views 3.3 does joins?

# Answer
I used `hook_views_query_alter()` to change it. It takes a reference to the $view and $query objects. I checked the name of the view to see if it was the one I wanted, and then changed the join type in the query object for the table of interest:

```
function my_module_views_query_alter(&$view, &$query) {
  if($view->name == 'my_view') {
    $query->table_queue['field_data_field_my_field']['join']->type = "LEFT";
  }
}

```
> 11 votes

# Answer
I found clicking on the `reduce duplicates` checkbox converted my `INNER JOINs` to `LEFT JOINs`:

Before I was getting something akin to the following injected into my query:

```
INNER JOIN {field_data_field_random_field field_data_field_random_field}
        ON node.nid = field_data_field_random_field.entity_id
       AND (field_data_field_random_field.entity_type = 'node'
       AND field_data_field_random_field.deleted = '0')

```

These inner joins were being caused by simple taxonomy filters, so sadly I didn't have any relationships to unrequire. Checking this box however doesn't seem to have altered my query in any other way, save for removing the inner joins, which is perfect for me; and may help someone else out there in this vast monkey adventure called life.
> 21 votes

# Answer
When you go to Relationships tab in the views you will find a check box titled "Require this relationship".

1. If you select this checkbox it means : Make an inner join
2. If you uncheck this checkbox it means : Make a left join
> 5 votes

# Answer
Just adding some information for completeness for those using AND/OR groups in their view.

I have a Filter Criteria which if I switch the last two conditions it changes it between an inner join and a left join.

To explain my current Filter Criteria is basically this:

```
(Published = "Yes" AND Content Type = "Blog) AND ((Blog Type = "X") OR (Blog Type IS NULL))

```

Which uses an INNER JOIN and doesn't give me the results I want. If I just swap the last two conditions in the OR it changes the JOIN type:

```
(Published = "Yes" AND Content Type = "Blog) AND ((Blog Type IS NULL) OR (Blog Type = "X"))

```

This uses a LEFT JOIN. Go figure, but could be useful for someone else.
> 1 votes

# Answer
Depending on your view filters, you might need the patch at https://www.drupal.org/node/1766338
> 0 votes

---
Tags: 7, views, database
---


title: What is "Sticky to top of lists" value?

text:
# Question
Title: What is "Sticky to top of lists" value?
I'm creating a view, and I've pulled in the *sticky to top of lists* field, as well as a view conditional field. I want to determine if "sticky" is true, and set a value (so I can add it to a custom field as a css class, for styling purposes) i.e., "stickyitem" if true, nothing/null if false.

I can't seem to get that in the conditional field. I've tried:

* Not empty, which makes it show everywhere
* Equal to 1, which seems like the correct choice, but it doesn't work
* Equal to true
* Equal to yes

What else could it possibly be? Maybe using *equal to* is the wrong choice.

# Answer
oh dear lord.. Didn't dawn on me to make the field visible so I could see it.

The answer is "on"
> 1 votes

---
Tags: views, 8
---


title: Exporting a View CSV during Cron

text:
# Question
Title: Exporting a View CSV during Cron
I'm working on a drupal 7 site and my client would like to have a certain view export as a CSV once a day into a folder. My initial thought was to tie this functionality to our cron schedule, but I'm running into a wall. How can I add functionality to cron? And more specifically, how could I get a specific view to export as a CSV during cron?

Thanks!

# Answer
> 3 votes
You might want to look at the Views Data Export contrib module: https://www.drupal.org/project/views\_data\_export

This module exposes a drush command that can execute the view and save its results to a file.

`drush views-data-export [view-name] [display-id] [output-file]`

Since you can call this command via drush from the shell, you should also be able to add the drush command to the operating system crontab (not Drupal cron) so that it executes on a schedule:

https://www.ostechnix.com/a-beginners-guide-to-cron-jobs/

---
Tags: views, cron
---


# Question
Title: How to setup drupal multisite in cpanel?
I want to setup a drupal multisite but without success. I have followed this tutorials (and search in drupal answer):
\- 2 minutes multisite
\- 5 minutes multisite
\- Setting up a multisite
I have tried with subdomains and with alias. My first question is when I create the alias or subdomain in cPanel, should I create a redirec? Now, I've left it blank, but I'm not sure if I have to create a redirect.

I always get:

> The website encountered an unexpected error. Please try again later.

or

> CGI-Error. Sorry. The page you request is not available.

I don't know what else I could do. Could some one detail me the steps? Thanks.

# Answer
> 0 votes
I have found the problem. My settings.php file had redis configuration, and that was the problem. I found it because I added this line to settings.php file:

```
$config['system.logging']['error_level'] = 'verbose';

```

---
Tags: 8, multi-sites
---


# Question
Title: Get a calculated price from Product Variation
I created a promotion with offer type - `Fixed amount off each matching product` and applies to - `Specific product`. In my custom block I get the product entity and try to get the calculated price via `commerce_order.price_calculator` service.

```
commercePriceCalc = \Drupal::service('commerce_order.price_calculator');
$context = new Context(\Drupal::entityTypeManager()->getStorage('user')->load(1),
                     \Drupal::entityTypeManager()->getStorage('commerce_store')->load(1));
$prices = $commercePriceCalc->calculate($slide->field_product->entity, 1, $context);

```

So, `calculate` method returns me a `PriceCalculatorResult` object with 2 properties, `calculatedPrice` and `basePrice` but they are identical.

```
PriceCalculatorResult {#3311 ▼
  #calculatedPrice: Price {#3310 ▼
    #number: "1000.000000"
    #currencyCode: "UAH"
  }
  #basePrice: Price {#3310 ▼
    #number: "1000.000000"
    #currencyCode: "UAH"
  }
  #adjustments: []
}

```

As if the discount didn't apply.

# Answer
Solved this problem, by passing the 4th argument `$adjustment_types` to the `$commercePriceCalc->calculate` method.

```
$adjustment_types = array("promotion" => "promotion");

```

So, the final version of the code

```
$commercePriceCalc = \Drupal::service('commerce_order.price_calculator');
$context = new Context(\Drupal::currentUser(),
                     \Drupal::entityTypeManager()->getStorage('commerce_store')->load($store_id));
$prices = $commercePriceCalc->calculate($slide->field_product->entity, 1, $context, $adjustment_types);

```
> 0 votes

---
Tags: commerce
---


# Question
Title: How can I have profile edit pages displayed in admin theme?
Drupal 8- How to use admin theme for user profile edit page while editing the profile by an administrator.

Example: when admin takes the URL: www.mysite/profile/{id}/edit (This is the URL you get when admin edit a user profile from user profile list.) I need to show the edit form in admin theme

I am using below profile module

version: '8.x-1.0-rc6'

core: '8.x'

project: 'profile'

# Answer
The profile form is already designated as an admin route, so you just need to change the permissions for relevant roles so they can view that theme.

The specific permission you're looking for is:

> View the administration theme
> 1 votes

---
Tags: 8, theming
---


# Question
Title: Using entity_lookup inside an entity_generate migration process plugins
I'm trying to use an entity\_lookup process plugin inside an entity\_generate process plugin. The YML looks like this

```
field_validation:
    plugin: entity_generate
    access_check: false
    entity_type: node
    source: validation_name
    value_key: title
    bundle: validation
    ignore_case: true
    values:
      title: validation_name
      body: validation_description
      field_validation_type:
        plugin: entity_lookup
          access_check: false
          ignore_case: true
          source: validation_type

```

The error I'm getting is

> Uncaught PHP Exception Drupal\Core\Config\UnsupportedDataTypeConfigException: "Invalid data type in config xxxxxx, found in xxxxxx : A colon cannot be used in an unquoted mapping value at line 282 (near " source: validation\_type")." at xxxxxx line 117, referer: xxxxxx

Because I'm relatively new in using the Migrate/Migrate Plus modules, I'm not sure if the error is triggered because I'm doing something wrong with the syntax or just because I can't use entity\_lookup inside an entity\_generate. So, the question is: can I do something like this, or I'm forced to use a separate migration instead of entity\_generate and the call it with migration\_lookup?

\[later edit, just for context\]

my field definition:

```
-
 name: validation_type
 label: 'Validation Type'
 selector: $.Description.Validation[*].Type #item_selector is set to $.Schema[*]

```

the relevant part of the source JSON:

```
{
  "Schema": [
    {
      "Description": {
        "Validation": [
          {
            "Type": "CUSTOM_TYPE",
            "Description": "lorem ipsum"
          }
        ]
      }
    }
  ]
}

```

# Answer
It seems that you actually can use entity\_lookup inside entity\_generate. The problem here was with the wrong indentation bellow `plugin: entity_lookup`. Yup... it was that kind of "bug" (feeling embarrassed) :)
> 0 votes

---
Tags: 8, migrations
---


# Question
Title: View block with contextual filter on taxonomy term name in URL doesn't work
Say, I have taxonomy vocabulary 'fruit' with terms like 'apple', 'pear' and 'grape'. Through content type 'Healthy', 'Healthy' content is made using a entity reference field to choose a term from the 'fruit' vocabulary.

Now, on a page with path /food/good/apple, a views block is placed that should show content related to taxonomy term 'apple'. I've tried to make a contextual filter in the views block like this:

When the filter value is NOT available \> Provide default value \> 'raw value from URL' And for 'Path Component', I checked 3 (for the third position in the url, 'apple'). This however doesn't return any content. When I remove the contextual filter, the block shows all Fruit content items.

Can this even be accomplished without using contrib modules? Any help on how to get the right setup would be welcome!

# Answer
> 1 votes
Your contextual filter will be expecting the term ID rather than the term name. You'll need remove that contextual filter and then add a relationship to the taxonomy which will then allow you to add a contextual filter for the taxonomy term name rather than the term ID

---
Tags: views
---


# Question
Title: Reduce navbar min-height without modifying or adding css files
I have successfully installed and configured Drupal 8
I am using bootstrap project as theme
The height of the navigation region on the top is as default has a css `navbar` which has `min-height 50px` as default value

it is possible to override this without changing the css files

# Answer
> 0 votes
As per your question, if I understood correctly, you don't want to modify CSS files
If you don't want to manually add or change a CSS file inside the theme folder

you can use Drupal Asset Injector and type the CSS with the editor provided in the plugin

# Answer
> 0 votes
The best way to work using bootstrap theme is by creating a subtheme. In the subtheme, you can update the variables or overwrite the `navbar min-height`, but if you really don't want to change any css/scss at all, you can do it using JavaScript (not recommended).

Something like:

```
(function ($) {
  $(document).ready(function () {
    $('ul.navbar').css('min-height', '20px');
  });
})(jQuery);

```

---
Tags: 8, bootstrap-theme
---


# Question
Title: Forward authenticated user to user.page on /login uri
If an authenticated user navigates to /login on a Drupal 8 site, she gets the "access denied" error. I want the site to redirect that user to /user (route user.page) instead. Unfortunately my RouteSubscriber doesn't work:

```
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {

    /* @var \Symfony\Component\Routing\Route $route */
    if ($route = $collection->get('user.login')) {
      $route->setPath('/anmelden');
      $route->setRequirements([]);
      $route->setDefaults(array(
         '_controller' => '\Drupal\asdentbase\Controller\LogonController::login',
         '_title' => 'Anmelden'
       ));
    }

```

And my LogonController looks like

```
public function login() {

    if ($this->currentUser()->isAuthenticated()) {
      return $this->redirect('user.page');
    }

    $rc =
    ...

```

The route redirection to /anmelden works fine. But my LogonController::login function is never called for already authenticated users. There's seems to be any further magic in the core.

**More detail:**

I also have a route in mymodule.routing.yml like

```
asdentbase.login:
  path: '/anmelden'
  defaults:
    _controller: '\Drupal\asdentbase\Controller\LogonController::login'
    _title: 'Anmelden'

```

# Answer
You also need to register your class in the event subscriber serivce. Create a YML similar to this:

`asdentbase.services.yml`

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

```
> 0 votes

---
Tags: 8, users, routes, event-subscribers
---