title: Limit size of cachetags table

text:
# Question
Title: Limit size of cachetags table
One of the site has fairly large cachetags table at over 418K records. Is there a way to limit the size of this table.

This table is not cleared on cache clear.

Since Drupal 8.4 there has been a way to limit the size of cache tables, as noted in change record. However, these settings do not affect the size of cachetags table. I tried adding the following to the settings.php file, but these don't work.

```
$settings['database_cache_max_rows']['cachetags'] = 50000;
$settings['database_cache_max_rows']['bins']['cachetags'] = 50000;

```
1. Is it safe to limit or purge the cachetags table?
2. Is there a way to limit the size of cachetags table without resorting to manually truncating the table?

# Answer
We just ended up writing a more general solution to purge PHP and Database cache's used by Drupal Core. This module provides three ways to truncate cachetags and other cache\_\* database tables via

* Web browser user interface
* Curl commands
* Drush commands

The Cache Utility module is available on Drupal.org

With this module I can set a cron job to periodically purge the cachetags table to keep database sizes sane.
> 1 votes

# Answer
So it appears that Drupal core neither limits the size of cachetags table and not it provides a mechanism to limit it via a setting, like it offers for other cache bins.

Cachetags table is not cleared on cache reset, neither via web browser no via drush.

There is another issue noted in Drupal core that cachetags table can grow endlessly as has been the case that I have come across.

So a blunt method or periodically cleaning the cachetags need to be performed. Something like follows with drush or direct sql statement via mysql cli client or php-myadmin.

```
drush sqlq "TRUNCATE cachetags;" -l <uri> --no-interaction

```
> 0 votes

---
Tags: 8, database, caching
---


title: How to update the node status?

text:
# Question
Title: How to update the node status?
I'm using data from JSON to create new nodes or update fields on existing if node exist on my Drupal 8 website. So, when I use method to update nodes, I need to save in array node id of updated nodes and keys of fields with changed values in this node.

After update is finished I need to print table with all nodes of this content type where fields of updated nodes need to have different style (color, background, etc).

So if my old node have `body = "body1"` and `description = "description 1"` and new node have `body = "body2"`and `description = "description 1"` after update is finished i need to get output like this:

Here is an example:

```
$node = \Drupal\node\Entity\Node::load($nid);
$node->set("body", 'New body text');
$node->set("description", 'New value');
$node->save();

```

Any suggestion?

**Note**: when I use `$node->save();` if all updated values is same nothing is changed (date of node in content from admin panel is same as before update), but if values is different I need to store node id, keys and values only of changed fields in array.

# Answer
> 10 votes
To set the status you can use the setPublished() method:

> **public function Node::setPublished**
>
> Sets the published status of a node..
>
> **Parameters**
>
> ***bool $published***: **TRUE** to set this node to published, **FALSE** to set it to unpublished.

In your case:

```
$node = \Drupal\node\Entity\Node::load($nid);
$node->set("body", 'New body text');
$node->set("field_name", 'New value');
$node->setPublished(TRUE);

```

# Answer
> 3 votes
Don't forget the node-\>save() or your node changes will be ignored.

```
$node = \Drupal\node\Entity\Node::load($nid);
$node->set("body", 'New body text');
$node->set("field_name", 'New value');
$node->setPublished(TRUE);
$node->save();

```

# Answer
> 2 votes
Do you save a new revision of the updated node? Maybe you can use the diff module to see the changes between the current & previous node? This is not an in depth solution, but maybe could be useful pointer for you.

# Answer
> -2 votes
you can un publish by setting status to 0

```
          $node = \Drupal\node\Entity\Node::load($nids);
          //set Unpublishing node
          $node->status = 0;
          //save to update node
          $node->save();

```

---
Tags: 8, nodes, entities
---


# Question
Title: How to add the current title to the breadcrumb without preprocess function?
I'm trying to get the title into my breadcrumb path without using a preprocess function. Drupal 8 Add the current title to the breadcrumb shows how to do it with preprocess function which is not what I'm trying to do.

I want my output be like this:

Here is what have been trying and have not work yet.

**breadcrumb.html.twig**

```
{#
/**
 * @file
 * Theme override for a breadcrumb trail.
 *
 * Available variables:
 * - breadcrumb: Breadcrumb trail items.
 */
#}
{% if breadcrumb %}
    <nav class="breadcrumb" role="navigation" aria-labelledby="system-breadcrumb">
        <h2 id="system-breadcrumb" class="visually-hidden">{{ 'Breadcrumb'|t }}</h2>
        <ol>{{ 'You are here:'|t }}
            {% for item in breadcrumb %}
                <li>
                    {% if item.url %}

                        <a href="{{ item.url }}">{{ item.text }}</a>
                    {% else %}
                        {{ item.text }}
                    {% endif %}
                </li>
                {{ '>'|t }} {{title}}
            {% endfor %}
        </ol>
    </nav>
{% endif %}

```

And this is what I'm getting:

For some reason the title is not been display when I use `{{ title }}`.

What am I doing wrong?

Why is my title not being displayed on my breadcrumb title?

# Answer
No matter what I will need to use preprocess function because `{{title}}` was not part of the **breadcrumb.html.twig**. I ended up doing this to achieve this my output:

**mytheme.theme**

```
<?php

function mytheme_preprocess_breadcrumb(&$variables){

        if(($node = \Drupal::routeMatch()->getParameter('node')) && $variables['breadcrumb']){
    // Adding the a divider of between home an the title of the page.
            $variables['breadcrumb'][] = array(
                'text' => '>'
            );
    // Adding the title of the page in the breadcrumb
            $variables['breadcrumb'][] = array(
                'text' => $node->getTitle(),
                'url' => $node->URL()
            );

        }
    }

```

**breadcrumb.html.twig**

```
{#
/**
 * @file
 * Theme override for a breadcrumb trail.
 *
 * Available variables:
 * - breadcrumb: Breadcrumb trail items.
 */
#}
{% if breadcrumb %}
    <nav class="breadcrumb" role="navigation" aria-labelledby="system-breadcrumb">
        <h2 id="system-breadcrumb" class="visually-hidden">{{ 'Breadcrumb'|t }}</h2>
        {{ 'You are here:'|t }}
        <div class="breadcrumb">
            {% for item in breadcrumb %}
                <span>
                    {% if item.url %}
                            <a href="{{ item.url }}">{{ item.text }}</a>
                    {% else %}
                        {{ item.text }}
                    {% endif %}
                </span>
            {% endfor %}
        </div>
    </nav>
{% endif %}

```

For more information about my solving this issue you can visit - Light Skeleton - Breadcrumb D8 Port
> 2 votes

# Answer
There is also an alter hook for breadcrumbs, where you can alter them in a non-theme specific way, in case the breadcrumbs are also used somewhere else.

I've implemented this in a project:

```
/**
 * Implements hook_system_breadcrumb_alter().
 */
function yourmodule_system_breadcrumb_alter(array &$breadcrumb, RouteMatchInterface $route_match, array $context) {
  // Append the current page title to the breadcrumb for non-admin routes.
  if ($breadcrumb && !\Drupal::service('router.admin_context')->isAdminRoute()) {

    $title = \Drupal::service('title_resolver')
      ->getTitle($request, $route_match->getRouteObject());
    if (!empty($title)) {
      breadcrumb->addLink(Link::createFromRoute($title, '<none>'));
    }
  }
}

```

EDIT for Drupal 8.2.x

I add a lot of error with this code, which I believe is the best approach for altering the breadcrumb has seen on Drupal API. So here is the code for Drupal 8.2.x

```
/**
 * Implements hook_system_breadcrumb_alter().
 */
function YOURMODULE_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$breadcrumb, \Drupal\Core\Routing\RouteMatchInterface $route_match, array $context) {
  // Append the current page title to the breadcrumb for non-admin routes.
  if ($breadcrumb && !\Drupal::service('router.admin_context')->isAdminRoute()) {

    $title = \Drupal::service('title_resolver')->getTitle(\Drupal::request(), $route_match->getRouteObject());
    if (!empty($title)) {
      $breadcrumb->addLink(\Drupal\Core\Link::createFromRoute($title, '<none>'));
    }
  }
}

```
> 8 votes

# Answer
By default, the variable {{title}} will not avaliable to breadcrumb.html.twig. You have to to use HOOK\_preprocess\_breadcrumb in your .theme file.

P.S: In D8, it is bad practice only if you try to display the data from preprocesser function. It is nothing wrong of you try to add extra variable in preprocesser. Here more clarification https://www.drupal.org/node/1920746

In YOUYTHEME.theme file

```
function YOURTHEME_preprocess_breadcrumb(&$variables) {
  $request = \Drupal::request();
  $route_match = \Drupal::routeMatch();
  $page_title = \Drupal::service('title_resolver')->getTitle($request, $route_match->getRouteObject());

  //this variable will avaliable in twig file.
  $variables['breadcrumb'][] = array(
    'text' => $page_title
  );
}

```
> 5 votes

# Answer
Some of the suggested solutions may have troubles with cache because the logic happens in the preprocess (`YOURTHEME_preprocess_breadcrumb(&$variables)`). I would recommend using some contrib modules or implement their solutions:

Easy breadcrumbs: Replaces core breadcrumbs with configurable breadcrumbs that follow Breadcrumb best-practices.

Current page crumb: Extends the Drupal 8 core system breadcrumbs to append the current page title as a text only breadcrumb.
> 2 votes

# Answer
There is a new module called Current Page Crumb that can help you.

> Current Page Crumb extends the Drupal 8 core system breadcrumbs to append the current page title as a text only breadcrumb. Admin paths are left unmodified. The module has no configuration.

And the author has made a blog post talking about the solution.
> 2 votes

# Answer
The preprocess function for breadcrumbs in core is:

```
function template_preprocess_breadcrumb(&$variables) {
  $variables['breadcrumb'] = array();
  /** @var \Drupal\Core\Link $link */
  foreach ($variables['links'] as $key => $link) {
    $variables['breadcrumb'][$key] = array('text' => $link->getText(), 'url' => $link->getUrl()->toString());
  }
}

```

It only provides the breadcrumbs, nothing else. So if you want to use other variables, you have to put them into the variables array in your own preprocess function.
> 1 votes

# Answer
To achieve this, use below code in your custom module or create a new custom module. I assume you already have understanding on how to create a custom module for Drupal 8/9. Create your services file mymodule.services.yml and add below code,

```
  mymodule.breadcrumb_nodes:
    class: Drupal\mymodule\Breadcrumb\MyModuleBreadcrumbBuilder
    tags:
      - { name: breadcrumb_builder, priority: 10001 }

```

You could set key as above like breadcrumb\_nodes or breadcrumb or breadcrumb\_terms etc as per your needs. Then create breadcrumb builder file under mymodule/src/Breadcrumb/ directory named as MyModuleBreadcrumbBuilder.php and add below code

```
<?php

namespace Drupal\mymodule\Breadcrumb;

use Drupal;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;

class MyModuleBreadcrumbBuilder implements BreadcrumbBuilderInterface {

  /**
   * @inheritdoc
   *
   */
  public function applies(RouteMatchInterface $route_match) {
    // This breadcrumb will apply for all nodes.
    $parameters = $route_match->getParameters()->all();

    //Checking if node then only calling our builder otherwise loading default loader
    if (isset($parameters['node'])) {
     return TRUE;
    }

    return FALSE;
  }

  /**
   * @inheritdoc
   * Add your logic in below method
   */
  public function build(RouteMatchInterface $route_match) {

    $parameters = $route_match->getParameters()->all();

    $node = $parameters['node'];

    //Getting latest node revision
    $vid = \Drupal::entityTypeManager()->getStorage('node')->getLatestRevisionId($node->id());
    $node_new = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($vid);
    $node_array = $node_new->toArray();

    //Creating new Breadcrumb
    $breadcrumb = new \Drupal\Core\Breadcrumb\Breadcrumb();

    $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));

    $breadcrumb->addLink(Link::createFromRoute($node_array["title"][0]["value"], 'entity.node.canonical', ['node' => $node->id()]));

    //Adding cache control,otherwise all breadcrumb will be the same for all pages.
    //By setting a "cache context" to the "url", each requested URL gets it's
    //own cache. This way a single breadcrumb isn't cached for all pages on the
    //site.
    $breadcrumb->addCacheContexts(["url"]);
    $breadcrumb->addCacheTags(["node:{$node->id()}"]);

    return $breadcrumb;
  }
}

```

Hope this helps. Thanks!!
> 0 votes

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


# Question
Title: How to redirect to a page after submitting a form
I have a custom module that displays a form.

Upon submitting the form, I want to redirect the user to a different page.

How can I do that?

# Answer
> 33 votes
In the submit handler you do

Drupal 7:

```
$form_state['redirect'] = 'url';

```

Drupal 8:

```
$form_state->setRedirect('route', $args, $options);
$form_state->setRedirectUrl(\Drupal\Core\Url);

```

# Answer
> 20 votes
It should be noted there are several triggers that may prevent a redirection:

* **`$form_state['redirect'] === FALSE`**: If set, the form builder function or form validation/submit handler does not want a user to be redirected, which means that `drupal_goto()` is not invoked. For most forms, the redirection logic will be the same regardless of whether `$form_state['redirect']` is undefined or FALSE. However, in case it was not defined and the current request contains a 'destination' query string, `drupal_goto()` will redirect to that given destination instead. Only setting `$form_state['redirect']` to `FALSE` will prevent any redirection.
* **`$form_state['no_redirect'] === TRUE`**: When set, the callback that originally built the form explicitly disallows any redirection, regardless of the redirection value in `$form_state['redirect']`. For example, `ajax_get_form()` defines `$form_state['no_redirect']` when building a form in an AJAX callback to prevent any redirection. `$form_state['no_redirect']` should NOT be altered by form builder functions or form validation/submit handlers.
* **`$form_state['programmed'] === TRUE`**: means the form submission was usually invoked via `drupal_form_submit()`, so any redirection would break the script that invoked `drupal_form_submit()`.
* **`$form_state['rebuild'] === TRUE`**: means the form needs to be rebuilt without redirection.

# Answer
> 8 votes
For Drupal 7, I tried this on a custom module and it works. It can also be used in a theme:

```
function my_theme_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'contact_site_form') {
    $form['#submit'][] = 'contact_form_submit_handler';
  }
}

function contact_form_submit_handler(&$form, &$form_state) {
  $form_state['redirect'] = 'thank-you-page-alias';
}

```

BTW, I found this snippet here: https://gist.github.com/postrational/5768796

# Answer
> 5 votes
On D8 i did like this (but this won't work... see below):

```
/**
* Implements hook_form_FORM_ID_alter().
*/
function MYMODULE_form_FORM_ID_form_alter( array &$form, FormStateInterface $form_state, $form_id ) {

   // Force redirect to "/thankyou" page
   $url = "/thankyou";
   $path = \Drupal::service('path.alias_manager')->getPathByAlias($url);
   if(preg_match('/node\/(\d+)/', $path, $matches)) {
     $form_state->setRedirect('entity.node.canonical',
       array('node' => $matches[1])
     );
   }

}

```

Edit/

I was missing that setRedirect/setRedirectUrl works AFTER the module is submitted, so this is my working solution on D8:

```
use Drupal\Core\Url;

/**
 * Implements hook_form_FORM_ID_alter().
 */
function MYMODULE_form_FORM_ID_form_alter( array &$form, FormStateInterface $form_state, $form_id ) {
  $form['actions']['submit']['#submit'][] = 'MYFORM_redirect_handler';
}

function MYFORM_redirect_handler($form, FormStateInterface $form_state) {
  // Force redirect to "/sent"
  $dest_url = "/sent";
  $url = Url::fromUri('internal:' . $dest_url);
  $form_state->setRedirectUrl( $url );
}

```

Hope this could help

# Answer
> 4 votes
To redirect to an external URL in Drupal 8, use the `TrustedRedirectResponse` class, as in the following code.

```
$response = new TrustedRedirectResponse('http://google.co.in');
$form_state->setResponse($response);

```

# Answer
> 1 votes
For **drupal 7** if you want to redirect to url with params like `someurl?param1=1&param2=2`

```
$query = array(
  'param1' => '1',
   'param2' => '2',
 );
$form_state['redirect'] = array(
    'someurl',
    array(
      'query'    => $query,
      'fragment' => 'hash_fragment',
    ),
  );

```

# Answer
> -3 votes
```
    $urlfind = Url::fromRoute('moduleName.show');
    $urlfindstring = $urlfind->toString();
    $redirect = new RedirectResponse($urlfindstring);
    $redirect->send();

```

under the formRoute write the route of your page and by this code it will redirect the form to that perticular page

---
Tags: forms
---


# Question
Title: How to get the file ID using managed_file on custom form?
In Drupal 8, I have a custom form that I built using the Form API in a custom module. I am trying to upload a file using managed\_file field. For some reason I can't get it to give me the file ID no matter what code I try. The file *does* indeed get uploaded and saved, but only as a temporary file.

Please see below for the code I am using. The value of the form field is always NULL.

buildForm:

```
public function buildForm(array $form, FormStateInterface $form_state, $event = NULL) {
  $validators = array(
    'file_validate_extensions' => array('jpg jpeg png gif'),
  );
  $form['event_image'] = array(
    '#type' => 'managed_file',
    '#name' => 'event_image',
    '#title' => t('Event Image'),
    '#upload_validators' => $validators,
    '#upload_location' => 'public://event-images/',
  );

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

  return $form;
}

```

submitForm:

```
public function submitForm(array &$form, FormStateInterface $form_state) {
  $event_image = $form_state->getValue('event_image');
  if ($event_image) {
    $file = File::load(reset($event_image));
    $file->setPermanent();
    drupal_set_message('Filename: ' . $file->getFilename());
  }
  ksm($event_image); // Returns empty array??
}

```

# Answer
I think you need to save the file :

```
public function submitForm(array &$form, FormStateInterface $form_state) {
  $event_image = $form_state->getValue('event_image');
  if ($event_image) {
    $file = File::load(reset($event_image));
    $file->setPermanent();
    $file->save();
    drupal_set_message('Filename: ' . $file->getFilename());
  }
}

```
> 0 votes

---
Tags: 8, forms
---


# Question
Title: Why ConfigFormBase does not goes through custom construct() when using managed_file?
First I want to state that this is a question. My Form is working, but I had, strangely, to add clauses for the case when my `CustomForm` extending `ConfigFormBase` did not goes as expected throught the `__construct()`

I created a `config` property in the `__construct()`. Then, I could access it from any function, and it worked fine.

As soon as I added a `managed_file`, things went wrong. Specifically, `$this->config` was `null` in `validateForm` and `submitForm`. I could restore the property easily by calling the factory again (and that's what I end up doing), but I'm confused.

What I see is the `managed_file` module send the form in XHR when updating the `managed_file` input. So when I'm validating the form, maybe there is a cache version or something that gets loaded, or the `callback_func` works differently. Anyway, the `__construct()` is executed on the XHR request (I checked with xdebug) but not after when I'm (re) submitting the form with the button.

I compared the stack when $this-\>config is null and when it's not, and did not spot any difference.

Maybe it's part of a multi-part Form functionality ?

I'm sure I'm getting it wrong somewhere.

Relevant parts as follow :

```
  /**
   * Constructs a \Drupal\system\ConfigFormBase object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The factory for configuration objects.
   */
  public function __construct(ConfigFactoryInterface $config_factory) {
    $this->setConfigFactory($config_factory);
    $this->config = $this->config('custom.settings');

    parent::__construct($config_factory);
  }

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

     }

/**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state): array {

    $form['section5'][self::TAB_IMAGE] = [
      '#type' => 'managed_file',
      '#title' => $this->t("Image de l'onglet"),
      '#default_value' => ($this->config->get(self::TAB_IMAGE)) ? [$this->config->get(self::TAB_IMAGE)] : NULL,
      '#upload_location' => 'public://',
      '#upload_validators' => [
        'file_validate_extensions' => ['gif png jpg jpeg'],
        'file_validate_size' => [Bytes::toInt(Environment::getUploadMaxSize())],
        'file_validate_image_resolution' => ['300x300'],
      ],
    ];
}

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // When submitting a Form with managed_file, weirdly no __construct().
    if (!$this->config) {
      $this->config = $this->config('custom.settings');
    }

```

# Answer
The difference could be that managed\_file is using Ajax which is caching the form object.

If you want to have this property cached you would need to declare it as protected property:

```
class CustomForm extends ConfigFormBase {

  protected $config;

```

Normally `$this->config()` is the method FormBase::config as the main entry point to the config API, not a property you populate when constructing the form object. Using the same name could be quite confusing and it's also recommended to use the mentioned method to retrieve the config and declare the config in `ConfigFormBase::getEditableConfigNames()` if you intend to save it.
> 1 votes

---
Tags: 8, forms
---


# Question
Title: How to add anchor to a single block displayed on specific pages within the same page?
I have a basic layout for a Drupal 8 site, created two blocks with block 1 containing menu with static content and links to pages, and block 2 for subscription form, The block 1 and block 2 are called on specific pages/nodes. for the menu subscribe in block 1, I gave the anchor link to the block 2 with an id (#subcription), since the block 1 and block 2 are called on specific pages, if the user is on home page and clicks on the subscribe menu it anchors to the home page block 2 which is fine, however when a user is on page 1 or page 2 and clicks on the subscribe menu the block does not anchor to the same page but directed to the homepage block 2 instead, how do we get the block 2 to anchor on the same page the user is in?

# Answer
> 0 votes
You can anchor to a part of a page by entering just the ID into the menu item Link, without the initial `/`:

`#subscription`

This link will always jump within the current page, unless there is no such element in it, then it does nothing.

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


# Question
Title: how to call handler on every ajax request
I have created a handler for every submit request using $form\['#submit'\]\[\] = 'MYMODULE\_form\_submit\_handler' now the problem is this doesnt works on Ajax submit, or page call backs functions. i want to log everything that is happening on every insert,update/delete in admin area

```
$form['button'] = array(
    '#type' => 'button',
    '#value' => t('Save'),
    '#attributes' => array(
        'onclick' => 'return false;',
        'class' => array('form-submit', 'rights-form-submit')
    ),
);

```

Where 'rights-form-submit' is a class that directs this button to AJAX call from javascript. i want to call hook on success / failure of request

# Answer
> 0 votes
Setting a form element to type `button` prevents submit handlers from being executed. You'll need to change the type to `submit` if you want your submit handlers to be called.

---
Tags: 7, hooks, ajax
---


# Question
Title: Programmatically load and submit the user form
I want to programmatically load the user profile form for a particular user and re-submit it without changing any of the existing values. The reasons are complex but I am dependent on gathering data during the form submit phase.

I can see functions to build an empty form ( `drupal_get_form` ) and to submit a new form ( `drupal_form_submit` ), but I can't see how to load the form prepopulated with the correct `$form_state`.

# Answer
> 1 votes
To load the user form with all data :

```
$user = $GLOBALS['user'];
$uid = $user->uid;
$account = user_load($uid);

$form = drupal_get_form("user_profile_form", $account);

```

But you need to include page handler first

```
    // Include page handler for node_add()
    module_load_include('inc', 'user', 'user.pages');

```

So your code will be:

```
module_load_include('inc', 'user', 'user.pages');
$user = $GLOBALS['user'];
$uid = $user->uid;
$account = user_load($uid);

$form = drupal_get_form("user_profile_form", $account);

```

# Answer
> 0 votes
You can try to prepoulate value of any form programmatically & submit like this

`$form_state = array();
$form_id = 'invite_form';
$form_state['values']['email'] = 'abc@xyz.com';
drupal_form_submit($form_id, $form_state);`

If you want to gather data during user save as mention in question use hook\_user\_presave.

---
Tags: 7, forms
---


# Question
Title: How do I pass a context filter to a block loaded by ajax?
There is a block created in views that displays the values of the taxonomy term fields. This block should be loaded when selecting a term from the select field in a custom form. Accordingly, the block needs to somehow pass the tid of the term selected in the form. The Select field in the form is formed as follows:

```
$form['rq_program'] = array(
       '#type' => 'select',
       '#title' => t('Program'),
       '#options' => GetProgramNameArray(),
       '#required'=> TRUE,
       '#ajax' => array(
          'callback' => 'GetTermInfo',
          'wrapper' => 'form-ajax-content',
          'method' => 'html',
          'effect' => 'fade',
        ),
    );

```

callback function:

```
function GetTermInfo($form, $form_state) {
    $tid=$form_state['values']['rq_program']; //value from select

    $block = block_load('views', 'views_program_block');
    $content = _block_get_renderable_array(_block_render_blocks(array($block)));
    $output = drupal_render($content);
    return render($output);
}

```

I can't understand how to pass $tid to the block, how to set up a context filter in this block to receive this $tid?

# Answer
If the block you generated uses a contextual filter, maybe this could be the answer: https://drupal.stackexchange.com/a/205731/98697
> 0 votes

---
Tags: forms, ajax
---


# Question
Title: The website encountered an unexpected error. Please try again later. unable to debug
I have just moved a Drupal 7 site to a new server. The website loads ok but if I log in as an admin person and click on any of the admin menu options I get the error

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

I have edited the index.php file and added the following lines

> error\_reporting(E\_ALL); ini\_set('display\_errors', TRUE); ini\_set('display\_startup\_errors', TRUE);

but still no errors show. There are also no errors in the httpd error log. In the php.ini I have the following lines:

> error\_reporting = E\_ALL
> display\_errors = On display\_startup\_errors = On log\_errors = On

so no errors show on screen or in the log. I haven't used Drupal before and I have no idea where to try next

I have searched for answers to this question but they all say to edit the index.php file as above and the errors will show on screen and they don't. Or they say to go to the admin menu and change settings which I can't as I can't load any of the admin menu options

# Answer
Problem solved. I discovered there was another admin account and when I login using that, I can see everything I need. I am currently doing a Drupal 7 course so hopefully, I will learn all these things I need :)
> 0 votes

---
Tags: 7, debugging
---


title: can you search database for page values

text:
# Question
Title: can you search database for page values
I have taken over a Drupal 7 site which used to be on a different server and has now moved to ours. I have discovered that on lots of Pages, there are images which point to the wrong server name, the name being hard coded on the page. To save me having to load up each page to test (there are 1000's of them), I thought I could search the database for the value I wish to change. I can see page information is stored in the node table but thats just the page title, created at, type etc. Which table is the text on the page stored in? I have checked the settings.php file and the correct server name is in there. If I edit a page, I can see the html for the images that don't show on the page point to a completely different server

# Answer
Here's a SQL-centric explainer: each field in Drupal 7 has two storage tables associated with it:

* field\_data\_{name-of-field}
* field\_revision\_{name-of-field}

In both cases, the field contents will be in a column like `{name-of-field}_value`. You can run a MYSQL UPDATE with a REPLACE function to bulk update URLs in these tables.

So if you find that the text you need to update is in the 'field\_body' table:

```
UPDATE field_data_field_body SET field_body_value = REPLACE(field_body_value, 'oldurl.com', 'newurl.com');
UPDATE field_revision_field_body SET field_body_value = REPLACE(field_body_value, 'oldurl.com', 'newurl.com');

```

Immediately after running these queries, you must clear the Drupal cache. This is best done from the "Performance" admin page in the Drupal UI. If you insist on SQL-only remedies, you can clear the particular relevant cache with this:

```
TRUNCATE TABLE cache_field;

```

The regular caveats apply:

* Have a backup of your database ready, and verify that the backup you have restores correctly!
* Be judicious about your REPLACE functions, that you don't accidentally replace more than what you thought you were targeting.
* Yes, you should perform the REPLACE against both the data and the revision tables.
> 1 votes

---
Tags: 7, database
---


# Question
Title: How to pass a field value as contextual filter argument using Twig Tweak drupal_view?
In Drupal 8, I'm using Twig Tweak to embed a view. I have a contextual filter set to one of the node's fields, `field_project_id`. If I use a literal for the third argument, it works. If I try to reference the value of the current node's project ID, no luck.

Works:

```
{{ drupal_view('my_view', 'block_1', '2011-40054-000') }}

```

Doesn't work:

```
{{ drupal_view('my_view', 'block_1', content.field_project_id) }},
{{ drupal_view('my_view', 'block_1', content.field_project_id.value) }},
{{ drupal_view('my_view', 'block_1', content.field_project_id.0) }},
{{ drupal_view('my_view', 'block_1', content.field_project_id.0.value) }},

```

etc.

What's the proper way to do this?

# Answer
> 0 votes
First of all check `drupal_view` implementation but I think that the arguments parameter (contextual filters) is an array, though the function wraps scalars into an array you should pass an array (robustness). Said that everything looks fine in your template perhaps you should do `{{ vardumper(content) }}` to see what actually is getting to your template variable. In order to use the **vardumper** function you need to install the VarDumper module.

# Answer
> 0 votes
You're treating {{ content }} as if it were an entity leveraging Entity API, but it's not - it's a render array.

It sounds like you're doing this in a node template, so you do actually have the entity as {{ node }} which is accessible using Entity API conventions. So this should probably work:

```
{{ drupal_view('my_view', 'block_1', node.field_project_id.value) }}

```

---
Tags: 8, theming
---


# Question
Title: How can I get a custom module's file path in a preprocess function?
I've got default images located in a custom module directory and I'd like to load them using `hook_preprocess_node()`. I then will pass the images to the template file.

In the screenshot, I'm loading an image into `$default_image`, which renders correctly when passed to the template file.

Instead of loading the image from an entity field, I want to read the image directly from the directory in the custom module. Clearly, the path I manually built into `$premier_tech_image` is incorrect.

>

The problem is NOT how to access the file. For example, we use code like this for JSON feeds.

```
$module_handler = $this->moduleHandler;
$module_path = $module_handler->getModule('my_custom_module')->getPath();
$resource = $module_path . '/resources/countries.json';

```

How do I correctly pass the reference to an image located in the directory of a custom module to the template file?

# Answer
> 5 votes
A Drupal URI starts with a stream wrapper like "public://" that indicates to Drupal how to handle that resource. Typically, the "public" stream wrapper is defined as "treat this resource as a local file within sites/default/files."

Your module assets are not located within sites/default/files, so they cannot use the "public" stream wrapper.

Drupal doesn't actually come out-of-the-box with a registered stream wrapper for module or theme assets. You might try installing https://www.drupal.org/project/system\_stream\_wrapper, which would then allow you to make a URI like `module://tableau_partners_sync/images/premier-technology.png`.

# Answer
> 3 votes
Try letting Drupal generate the module path:

```
$modulePath = \Drupal::service('module_handler')->getModule('MYMODULE')->getPath();
$imagePath = $modulePath . "/images/my-image.jpg";

```

# Answer
> 0 votes
Drupal 8 still has `drupal_get_path()`, which is used from Drupal core modules and third-party modules for the path of files contained in modules directories. (See the code for `ckeditor_ckeditor_css_alter()` or the example code given in `hook_js_alter()`.

```
function hook_js_alter(&$javascript, \Drupal\Core\Asset\AttachedAssetsInterface $assets) {
  $javascript['core/assets/vendor/jquery/jquery.min.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
}

```

Deprecate drupal\_get\_path() and drupal\_get\_filename() and replace with ExtensionList::getPath() and ExtensionList::getPathname() aims to deprecate the function.
At the moment I am writing this answer, its status is still *Needs work* (for Drupal 9.3.x). When it's marked as fixed, instead of `drupal_get_path('module', $module_name)`, modules will use `\Drupal::service('extension.list.module')->getPath($module_name)`.

For example, the previous example hook could be rewritten in this way.

```
function hook_js_alter(&$javascript, \Drupal\Core\Asset\AttachedAssetsInterface $assets) {
  $javascript['core/assets/vendor/jquery/jquery.min.js']['data'] = \Drupal::service('extension.list.module')->getPath('jquery_update') . '/jquery.js';
}

```

Alternatively, `\Drupal::service('extension.path.resolver')->getPath('module', $module_name)` could be used, which is what drupal\_get\_path() and drupal\_get\_filename() have been deprecated in favor of extension listing services suggests to use in the case the extension type is dynamically specified.

---
Tags: 8, media
---


# Question
Title: blocked due to MIME type (“application/octet-stream”) mismatch
I've been troubleshooting a memcache issue on our Drupal 7 site and in the process the front end CSS broke, meaning all content was unstyled.

The Chrome console has a message:

> The resource from “/sites/all/themes/mbm/css/style.scss?qktcrf” was blocked due to MIME type (“application/octet-stream”) mismatch (X-Content-Type-Options: nosniff).

Should Drupal be using a `.scss` file on the front end?

If not, how would I determine where the breakdown of the `.scss` being converted to a `.css` file occurs?

Help appreciated. Steve

# Answer
> 0 votes
Pretty sure that the scss files should be in a scss folder, and not the css folder.

```
/sites/all/themes/mbm/css/style.scss?qktcrf

```

# Answer
> 0 votes
Seems to me like the requested file cannot be found ("masked" HTTP 404) ..

And yes - there should no .scss file be requested at all.

# Answer
> 0 votes
No, scss files cannot be used by the browser as css. Sounds like something is declaring that as an asset or mistakenly adding it via drupal\_add\_css.

---
Tags: theming
---


# Question
Title: drush config:import "There are no changes to import." for "content" view
On a Drupal 8.7.14 system with Drush 9.7.2, I modified the "content" view and now want to roll it back to the previous version that was exported with `drush cex`.

Unfortunately, drupal does not roll it back to the previous state. `drush config:import` only says:

> There are no changes to import.

---

I did then delete the "content" view, and the import said:

> Operation create für views.view.content: "view" entity with ID "content" already exists.

To circumvent that, I created the view manually and tried to import the original configuration. Again, drupal thinks that:

> There are no changes to import.

Why is that? What can I do to force Drupal to restore the original configuration?

# Answer
> 1 votes
The problem's source was the configuration file that configured the database as cache on CLI, while using redis when served via http.

This caused all kind of confusion, since clearing the cache in the browser did not do that for CLI :/

---
Tags: 8, drush, configuration
---


# Question
Title: How do I reference an image inside my custom module directory?
I want to ship a default image in my custom module. I know I can reference images in the files directory with public://, but how can I properly reference my module's URL path?

Update: I need to pass this URI to image\_style so a raw path to the module directory won't be enough:

```
  $render_image = [
    '#theme' => 'image_style',
    '#style_name' => 'blah',
    '#uri' => $uri,
    ...
  ];

```

# Answer
Drupal needs a URI (not just a URL or filepath) to generate an image style derivative. All URIs begin with a stream wrapper like "public://" or "private://". The stream wrapper tells Drupal how to handle the resource; for example, "public" typically means "treat this resource as a local file within sites/default/files."

You won't be able to use the "public" stream wrapper for assets in a module directory, because that module does not live in sites/default/files.

Drupal doesn't come with a stream wrapper for module or theme assets, but there's a contributed module to add that functionality at https://www.drupal.org/project/system\_stream\_wrapper.
> 1 votes

# Answer
The value passed as `#uri` can be either the image URI or an image relative path. `template_preprocess_image_style()` passes the value of `$variables['uri']` to `ImageStyle::buildUrl()` which as first parameter accepts either the image relative path or its URI.

```
  $style = ImageStyle::load($variables['style_name']);

  // Determine the dimensions of the styled image.
  $dimensions = [
    'width' => $variables['width'],
    'height' => $variables['height'],
  ];
  $style->transformDimensions($dimensions, $variables['uri']);
  $variables['image'] = [
    '#theme' => 'image',
    '#width' => $dimensions['width'],
    '#height' => $dimensions['height'],
    '#attributes' => $variables['attributes'],
    '#style_name' => $variables['style_name'],
  ];

  // If the current image toolkit supports this file type, prepare the URI for
  // the derivative image. If not, just use the original image resized to the
  // dimensions specified by the style.
  if ($style->supportsUri($variables['uri'])) {
    $variables['image']['#uri'] = $style->buildUrl($variables['uri']);
  }

```

To get the module path, both `drupal_get_path('module', $module_name)`, which is still implemented even in Drupal 9.3.x, and `\Drupal::moduleHandler()->getModule($module_name)->getPath()` return the same value. Deprecate drupal\_get\_path() and drupal\_get\_filename() and replace with ExtensionList::getPath() and ExtensionList::getPathname() and drupal\_get\_path() and drupal\_get\_filename() have been deprecated in favor of extension listing services (the associated change record) suggest to use either `\Drupal::service('extension.list.module')->getPath($module_name)` or `\Drupal::service('extension.path.resolver')->getPath('module', $module_name)`, to get a module path.
> 1 votes

# Answer
The \Drupal class has many useful static functions such as moduleHandler. I recommend (for future issues) to first search there, then in the core.services.yml & system.services.yml files for a service or a method that could help.

```
\Drupal::moduleHandler()->getModule('foo')->getPath()

```
> 0 votes

# Answer
I think following is easy method to do this

Create private file path

> $settings\['file\_private\_path'\] = 'give path to you /private-files'; \Drupal::service('file\_system')-\>realpath("private://");

Now you can use this to upload your module related file also custom file for custom form.

Ref: https://www.drupal.org/docs/8/modules/skilling/installation/set-up-a-private-file-path
> 0 votes

---
Tags: 8, uri
---


# Question
Title: Why put a different machine name for the same field?
I have an image field for my article content type with the machine name field\_image

I created a new type of content for cooking recipes. Should I use the existing image control or create an image control with a new machine name?

I don't understand the difference.

Why put a different machine name for a field of the same type?

# Answer
Content types can have different categorization of images. For example, one content type may have a field image that is an image to represent that node. Another content type, say for a song, may have an image for 'album cover'. These are both image types, but other than that there isn't any relation between the data contained. So it wouldn't make sense to re-use the machine name in this case. However, if your other content type also is using an image to represent the node, then you could re-use the field.

\[Edit - adding Leymannx's link that explains in much better detail\] https://www.ostraining.com/blog/drupal/re-using-drupal-fields/
> 2 votes

---
Tags: entities
---


# Question
Title: Adding more variables to menu for use in menu.html.twig
I'm attempting to give menus more variables to work with besides the default menu\_name,items, and attributes. This is because making a variable in the preprocess menu hook does not allow it to be accessible in the menu.html.twig template.

My ultimate goal is to be able to add menu items that contain the user id in the path.

I believe I need to add the var to menu by using hook\_theme\_registry\_alter and follow the format of https://api.drupal.org/api/drupal/core%21includes%21theme.inc/function/drupal\_common\_theme/8.2.x

So I attempted to add a variable to menu in my .theme file like so

```
function mytheme_theme_registry_alter(&$theme_registry){
    $theme_registry['menu']['variables']['test_var'] = 'testing theme registry alter';
}

```

But when I do so nothing appears when I alter menu.html.twig like so

```
<nav {{ attributes.addClass(navClasses) }} aria-label="MyWPT Menu Mobile" role="navigation" style="display:none;">
    {{ menus.menu_links(items, attributes, 0) }}
{#     {% macro menu_links(items, attributes, menu_level) %} #}
    {% macro menu_links(items, attributes, menu_level) %}
    {% import _self as menus %}
    {% if items %}
    {% if menu_level == 0 %}
    <ul class="vertical menu" data-drilldown>
        {% else %}
        <ul class="vertical menu">
            {% endif %}
            {% for item in items %}
                {% if item.below %}
                    <li class="is-dropdown-submenu-parents">
                {% else %}
                    <li{{ item.attributes }}>
                {% endif %}
                {{ link(item.title, item.url) }}
                {% if item.below %}
                    {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
                {% endif %}
                </li>
            {% endfor %}

            <li><a href="/">{{ test_var }}</a></li>
        </ul>
        {% endif %}
        {% endmacro %}

```

How would I add more menu variables for use in menu.html.twig ?

UPDATE: I also tried {{menus.test\_var}} but that just broke the page

UPDATE 2: Using {{ kint() }} the test\_var did not appear anywhere

# Answer
> 3 votes
Here is an example from a real project I had done:

### mytheme.theme:

```
/**
 * Implements hook_theme_registry_alter().
 * @param $theme_registry
 */
function mytheme_theme_registry_alter(&$theme_registry) {
  $theme_registry['menu']['variables']['top_parent'] = [];
}

/**
 * Implements hook_preprocess_block__menu_block().
 * @param $variables
 */
function mytheme_preprocess_block__menu_block(&$variables) {
  // set the top parent on the left nav
  if ($variables['elements']['#id'] == 'left_navigation' && !empty($variables['elements']['content']['#items'])) {
    // code removed

    $variables['content']['#top_parent'] = [
      'title' => $menu_content->getTitle(),
      'url' => $menu_content->getUrlObject(),
      'is_current' => ($current_path == $item_path)
    ];
  }

  // code removed
  }
}

```

### In Twig:

```
  {% if menu_level == 0 %}
    <li class="left-nav__item active-trail is-active {% if top_parent.is_current %}is-current{% endif %}">
      {{ link(top_parent.title, top_parent.url) }}
    </li>
  {% endif %}

```

You are likely missing the part where you add `test_var` key to the content array:

`$variables['content']['#test_var'] = "whatever";`

With exception to flagging `is-current`, it looks like you're trying to do the same thing I did. You should strive to use the `link` function in Twig instead of a hard coded anchor unless there is no way around it.

# Answer
> 0 votes
be careful to the name of your menu for example if you want to assign a new variables to main menu you must do something like this

```
function mytheme_theme_registry_alter(&$theme_registry) {
  $theme_registry['menu__main']['variables']['top_parent'] = [];
}

```

# Answer
> 0 votes
Sometimes theme hooks are specific so you might have `node` and `node__mytype`

Therefore, the theme registry array key to change is `$theme_registry['node__mytype']` in addition to the normal one.

Here is a function to effect all variations.

```
/**
 * Implements hook_theme_registry_alter().
 */
function mythemename_theme_registry_alter(&$theme_registry) {
  $target_theme_hook = 'node';
  $target_theme_hooks = [];
  foreach (array_keys($theme_registry) as $theme_hook) {
    // Is target theme hook.
    if ($target_theme_hook === $theme_hook) {
      $target_theme_hooks[] = $theme_hook;
      continue;
    }
    // Is more specific version of the target theme hook.
    if (strpos($theme_hook, "{$target_theme_hook}__") === 0) {
      $target_theme_hooks[] = $theme_hook;
      continue;
    }
  }
  // Add $new_var as a variable to the 'node' theme hook(s) we
  // collected eailer. Set its default value to be an
  // empty string.
  foreach ($target_theme_hooks as $target_theme_hook) {
    $theme_registry[$target_theme_hook]['variables']['new_var'] = '';
  }
}

```

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


# Question
Title: Strange Page not Found, Permissions, Clear cache
On my D7.80 I have developed a custom module:

```
    function wrong_answer_menu() {
    dd('it entered in hook menu');
  $items['wrong-answer/%id'] = array(
    'title' => t('Wrong Answer Dashboard'),
    'page callback' => 'wrong_answer_dashboard',
    'page arguments' => array(1),
    'access callback' => TRUE,
    'type' => MENU_LOCAL_TASK,
  );

  return $items;
}

/**
 * Callback: hook_menu.
 */
function wrong_answer_dashboard($node_param=NULL) {
dd('it entered in dashboard');
....
}

```

Everything was fine, I was developing the menu nicely accessing the mydomain.com/wrong-answer and everything was fine.

Then I wanted to add permissions to my custom module, so that only the admin can access this page hence I added the wrong\_answer\_permission function and in the dashboard function I checked if the user had permission to access the page

```
/**
 * Implements hook_permission().
 */
function wrong_answer_permission() {
  return array(
    'wrong_answer_' => array(
      'title' => t('View the wrong answer'),
    ),
  );
}

    function wrong_answer_dashboard($node_param=NULL) {
     dd('it entered in dashboard');
     if (!user_access('wrong_answer_admin')) {
      return;
     }
    ....
    }

```

At this stage, when I accessed the page mydomain.com/wrong-answer I could still access it even though I did not assign the permission to it. Then I cleared the cache from the Performance menu via the admin/config/development/performance, and then I got the error message

```
The requested page "/wrong-answer/717" could not be found.

```

I get the same error for acessing just mydomain.com/wrong-answer.

Then I thought it was all fine, I added the permission wrong\_answer\_admin to the admin role, but then I still got the same error "The requested page .... could not be found.

Afterwards, I:

* cleared the cached
* removed the code that I had added on the permission and checking the user access
* rebuild the registry\_file by emptying the table and running the update.php
* assigned the permission to the wrong\_answer\_admin to all the roles, including anonymous role
* deleted the wrong\_answer\_admin row in the permissions table in the database
* disabled and re-enabled by custom module

but nothing worked, I still get the error "The requested page cannot be found".

Then I noticed the strangest thing, that whenever I would clear the cache at, I would would get an entry in the drupal\_debug.txt

```
it entered in hook menu

```

I do not get this entry in the drupal\_debug.txt when accessing the wrong-answer page, I only get it when clearing the cache.

Could you please help me understand what is going on? why can't I access the wrong-answer page anymore?

Many thanks

# Answer
> 0 votes
An answer to part of your question:

> Then I noticed the strangest thing, that whenever I would clear the cache at, I would would get an entry in the drupal\_debug.txt
>
> `it entered in hook menu`
>
> I do not get this entry in the drupal\_debug.txt when accessing the wrong-answer page, I only get it when clearing the cache.

If Drupal built the menu for every page load, it would result in heavier page loads. As such, hook\_menu() is only called after the cache is cleared, as the menu cache is rebuilt the first time it is needed and no cache exists. Once it's been cached, hook\_menu() does not get called anymore.

# Answer
> 0 votes
It seems like that the problem will be in the menu item definition:

```
$items['wrong-answer/%id'] = array(

```

I do not think you can use random string in the wildcard placeholder. According to the documentation, you can:

1. Use plain wildcard (%) - this will pass the ID directly to your function.
2. Use auto-loader wildcard (for example %node) - but the name must reference an existing loading function. In this case the node\_load() function will be called and the node object will be passed to your function.
3. Define %wildcard\_to\_arg() function (see documentation).

It is very likely that you do not have `id_load()` function in your code, so this should be the reason why this is not working. From the documentation:

```
... if a node with a node ID of 999 does not exist,
the menu routing system will return a 404 error in this case...

```

If you change it to this, it should work correctly:

```
$items['wrong-answer/%'] = array(

```

See hook\_menu documentation for additional information: https://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook\_menu/7.x

---
Tags: 7, debugging
---


title: Download Single Webform Submission CSV

text:
# Question
Title: Download Single Webform Submission CSV
I would like to download the webform submissions one by one.

Currently the core of Webform owns to download all submission data to a CSV.

***Webform -\> Result -\> Download***

How to download one submission data (by submisisons id for example) to a single CSV ?

# Answer
> 2 votes
Under 'Download options' you can limit the CSV to a submission id.

---
Tags: 8, files, webforms, importing-exporting
---


title: How do I pass variables to JavaScript?

text:
# Question
Title: How do I pass variables to JavaScript?
In your MODULENAME.module file:

```
$testVariable = 'himanshu';
drupal_add_js(array('MODULENAME' => array('testvar' => $testVariable)), array('type' => 'setting'));
drupal_add_js(drupal_get_path('module', 'MODULENAME') . '/MODULENAME.js');

```

In MODULENAME.js file:

```
(function($) {
  Drupal.behaviors.MODULENAME = {
    attach: function (context, settings) {
      alert(settings.MODULENAME.testvar);
    }
  };
})(jQuery);

```

this way you can pass your php variable in drupal javascript file and use the variable :)

How can I implement the above in Drupal 8?

# Answer
Instead of `drupal_add_js(array('MODULENAME' => array('testvar' => $testVariable)), array('type' => 'setting'));` you use `$build['#attached']['drupalSettings']['testvar'] = $testVariable;`. Replace `$build` with the variable containing the form or the render array to which the settings are attached; in a form builder or `hook_form_alter()`, that would be `$form`.

The JavaScript code to attach to the page should then be defined as library, which is the only way to attach JavaScript and CSS to a page or a form.
It is explained in Adding stylesheets (CSS) and JavaScript (JS) to a Drupal 8 module, so I will not repeat it here. I will just make notice that the library needs to declare at least two dependencies:

* core/jquery, if the JavaScript code uses jQuery
* core/drupalSettings, since the JavaScript code uses Drupal settings
> 21 votes

# Answer
For Drupal 8 you can do.

```
 /**
 * Implements hook_page_attachments().
 */
function mymodule_page_attachments(array &$page) {
  $page['#attached']['drupalSettings']['myname'] = 'himanshu';
}

(function ($, Drupal, drupalSettings) {
  /**
   * @namespace
   */
  Drupal.behaviors.mymoduleAccessData = {
    attach: function (context) {
      var data = drupalSettings.myname;
    }
  };
})(jQuery, Drupal, drupalSettings);

```
> 5 votes

# Answer
## Drupal 8 <sup>(update)</sup>

```
/**
 * Implements hook_page_attachments().
 */
function myModule_page_attachments(array &$attachments) {
  $attachments['#attached']['drupalSettings']['myModule'] = [
    'basePath' => base_path(),
  ];
}

```

This variable would then be referenced from JS side like:

```
console.log( drupalSettings.myModule.basePath );

```

Or:

```
(function ($) {
  Drupal.behaviors.myModuleAccessData = {
    attach: function (context) {
      var data = drupalSettings.myModule.basePath;
    }
  };
})(jQuery);

```

## Old answer

Another way to do it (as mentiond in JS-standards) would be:

```
$element['#attached']['js'][] = array(
  'data' => array('myModule' => array('basePath' => base_path())),
  'type' => 'setting',
);

```

This variable would then be referenced from JS side like:

```
console.log( Drupal.settings.myModule.basePath );

```
> 3 votes

---
Tags: javascript, 8
---


title: How do I generate URL by term_id

text:
# Question
Title: How do I generate URL by term_id
I have a **taxonomy term ID** that I would like to generate the the URL alias for. In other words, instead of `/taxonomy/term/{id}` I would like to get the alias I have defined for this, eg: `/some/path/myawesometerm`.

How can I accomplish this?

# Answer
What you are calling "URL aliases" are referred to by Drupal 8 as "path aliases."

The `path.alias_manager` service (`\Drupal\Core\Path\AliasManager`) allows to lookup path aliases.

```
$aliasManager = \Drupal::service('path.alias_manager');
// The second argument to getAliasByPath is a language code such as "en" or LanguageInterface::DEFAULT_LANGUAGE.
$alias = $aliasManager->getAliasByPath('/taxonomy/term/' . $term_id);

```

But what use is a path alias? The end result is probably to put it into a link render element. `\Drupal\Core\Url::fromRoute` should also be a valid option as that will translate into any path alias anyway. It is not exactly clear from the API documentation that it does this, but it does.

```
$link = [
  '#type' => 'link',
  '#title' => 'Taxonomy term ' . $term_id,
  // Passing in 'language' key as the third option is preferable here so that a language-dependent alias can be found.
  '#url' => Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $term_id])
];

```
> 9 votes

# Answer
Maybe to combine the answers of @Kevin and this article, you can directly do it in twig without the need of further logic:

```
<a href="{{ path('entity.taxonomy_term.canonical', {'taxonomy_term': term_id}) }}">
  <span>{{ your_label }}</span>
</a>

```
> 0 votes

---
Tags: 8, taxonomy-terms, uri
---


# Question
Title: Remove UUID, Created, ID, etc fields from "HTML Table" Export
I want to know how can i remove the fields from the module "Scheduled Tasks" for Webform, so the exported Excel file doesn't show the fields "Created" "UUID" "Serial Number" "Completed" etc. I can make it when i export manually but in scheduled tasks it sends all that information. I don't have a clue how to make it.

# Answer
In Webform 6, this function already exists. In the *Result submission* page of each webform, there is a *Customize* button that allows to customize the submissions table, and un-select the fields you don't want to export.
> 0 votes

---
Tags: webforms
---


title: CSS styles aren't applied to the pages

text:
# Question
Title: CSS styles aren't applied to the pages
On my site, CSS styles aren't applied to pages. The site is working and I have no clue why this is happening.

>

I have installed Nginx and php70-fpm on macOS El Capitan. I am using the configuration from drupal.org with a slight change.

```
server {
    server_name drupal.mac;
    root /Users/fabriziomazzoni1/nginx/drupal/;
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Very rarely should these ever be accessed outside of your lan
    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

    location ~ \..*/.*\.php$ {
        return 403;
    }

    location ~ ^/sites/.*/private/ {
        return 403;
    }

    # Allow "Well-Known URIs" as per RFC 5785
    location ~* ^/.well-known/ {
        allow all;
    }

    # Block access to "hidden" files and directories whose names begin with a
    # period. This includes directories used by version control systems such
    # as Subversion or Git to store control files.
    location ~ (^|/)\. {
        return 403;
    }

    location / {
        # try_files $uri @rewrite; # For Drupal <= 6
        try_files $uri /index.php?$query_string; # For Drupal >= 7
    }

    location @rewrite {
        rewrite ^/(.*)$ /index.php?q=$1;
    }

    # Don't allow direct access to PHP files in the vendor directory.
    location ~ /vendor/.*\.php$ {
        deny all;
        return 404;
    }

    # controllers other than update.php in a future release.
    location ~ '\.php$|^/update.php' {
       root /Users/fabriziomazzoni1/nginx/drupal/;
       fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
       #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
       include fastcgi.conf;
       $document_root$fastcgi_script_name;
       fastcgi_param PATH_INFO $fastcgi_path_info;
       fastcgi_intercept_errors on;
       fastcgi_index index.php;
       fastcgi_pass 127.0.0.1:9000;
   }

    # Fighting with Styles? This little gem is amazing.
    # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
    location ~ ^/sites/.*/files/styles/ { # For Drupal >= 7
        try_files $uri @rewrite;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }
}

```

The server name is also set in the */etc/hosts* file in my local computer.

# Answer
> 0 votes
I had the same Problem. Deactivating Aggregation by drush and clearing all caches finally solved my problem.

`drush -y config-set system.performance css.preprocess 0`

`drush -y config-set system.performance js.preprocess 0`

`drush cr`

Anyway, I think the problem is some wrong Nginx-Config detail.

---
Tags: 7
---


# Question
Title: PHP Script taking up way more memory than expected
We have a script that is meant to clean up some user data. Essentially, we 1) load all user ids and loop through them. For each user we 1) load the user object then 2) alter some data and finally 3) we save the user.

We originally did all of this in one script file but we were running into memory issues about 15% of the way through processing all the users and weren't certain why. So we've tried the following:

1. Unset any variable instanced in the for-loop at the end of the for-loop using `unset`
2. Any variable instanced in the for-loop is set to `NULL` at the end of the for-loop
3. Loading, Altering, and Saving the user object functionality was extracted to a service method that the script will call

The hope for attempted fixes 1 and 2 would be that the memory would be deallocated and php's garbage collector would clear up memory, but it did not

The hope for attempted fix 3 was that the memory from the user object and all that would be cleaned up after the service function finished since, I believe, it should run on a different process.

I'm very confused as I don't know what variable(s) are taking up so much memory, if anything, the list of user ids should be the largest variable taking up memory but it doesn't even take up that much... In our D7 project, I had many scripts that ran through each user and did some work and saved the user and it had no issues, but in this D8 version I'm having memory issues.

Here is the code we have now, and I simply cannot find anything here that would suggest something continually to take up memory...

**Script**

```
<?php
use Drupal\user\Entity\User;

$user_service = \Drupal::service('my_user.my_user_service');

$uids = \Drupal::entityQuery('user')
                ->condition('status', '1')
                ->execute();
$total_users = count($uids);
$user_index = 0;

foreach($uids as $uid) {
  $user_index += 1;

  $ytp_user_service->cleanUp($uid);

  $percent_complete = ($user_index / $total_users) * 100;
  $percent_complete_formatted = number_format($percent_complete, 2, '.', ' ');
  $memory =  memory_get_usage()/1000000;
  print_r("\r\033[KUSER: {$uid} | COMPLETION: {$percent_complete_formatted}% | MEMORY:  {$memory} MB");
  $start_memory = memory_get_usage();
}

```

**Service Method**

```
  function cleanUp($uid) {
    $today = new DateTime();
    $entityManager = \Drupal::service('entity_field.manager');
    $fields = $entityManager->getFieldStorageDefinitions('user', 'user');
    $countries = options_allowed_values($fields['field_country']);
    $lower_case_countries = array_map('strtolower', $countries);
    $formatted_date = date('Y-m-d\TH:i:s', time());

    $user = User::load($uid);
    $username = $user->getUsername();
    $roles = $user->getRoles();
    if (in_array('administrator', $roles) || in_array('advisor', $roles)) {
      return;
    }

    // Convert Birthdate to age and update ages (Can be done during migrations)
    // Subtract year of birth from Registration date
    // Ex: Registration Date: June 1st, 2020
    // Year of birth: 2005
    // Age: 15 (June 1st, 2020 – June 1st 2005)
    $age = $user->get('field_age')->value ?? '';
    $reg_timestamp = $user->getCreatedTime();
    $birthdate = strtotime($user->get('field_birthdate')->value) ?? '';
    if(!$age && $birthdate) {
      $reg_month = date('m', $reg_timestamp);
      $reg_day = date('d', $reg_timestamp);
      $birth_year = date('Y', $birthdate);
      $new_birthday = $birth_year.'-'.$reg_month.'-'.$reg_day;
      $birth_date_time = new DateTime($new_birthday);
      $diff = $today->diff($birth_date_time);
      $user->set('field_age', $diff->y);
    } else if ($age) {
      $reg_date = date('Y-m-d', $reg_timestamp);
      $diff = $today->diff(new DateTime($reg_date));
      $new_age = $age + $diff->y;
      $user->set('field_age', $new_age);
    }

    // Add Country of Residence to people who don't have them
    // Only if their Nationality is Emirati or they have an emirate of Residence and they don't have a country
    // get country options
    // compare country to options
    // if it is not in options make it other
    $country = $user->get('field_new_residence')->value;
    $nationality = strtolower(trim($user->get('field_nationality')->value));
    $emirate = $user->get('field_country_residence')->value ?? '';
    if (($nationality === 'uae/emirati citizen' || $emirate) && !$country) {
      $user->set('field_country', 'United Arab Emirates');
    } else if (!in_array(trim(strtolower($country)), $lower_case_countries)) {
      $user->set('field_country', 'Other');
    } else {
      $user->set('field_country', trim(ucwords($country)));
    }

    // Remove hashtags from existing registration codes entered by users
    $reg_code = $user->get('field_workshop_code')->value;
    if($reg_code) {
      $user->set('field_workshop_code', strtolower(str_replace ('#', '', $reg_code)));
    }

    // Levels tasks
    // task 1_1
    // complete me3 and match 3 careers
    $task_1_1 = $user->get('field_task_1_1')->value;
    $matched_degs = $user->get('field_matched_degrees')->getValue();
    if(!$task_1_1 && count($matched_degs) >= 3) {
      $user->set('field_task_1_1', 1);
      $user->set('field_task_1_1_date', $formatted_date);
    }

    // task 1_2
    // enroll in one course
    $task_1_2 = $user->get('field_task_1_2')->value;
    $enrolled_courses = $user->get('field_current_courses')->getValue();
    if(!$task_1_2 && count($enrolled_courses)) {
      $user->set('field_task_1_2', 1);
      $user->set('field_task_1_2_date', $formatted_date);
    }

    // task 2_1
    // complete 1 one course
    $task_2_1 = $user->get('field_task_2_1')->value;
    $completed_courses = $user->get('field_completed_courses')->getValue();
    if(!$task_1_2 && count($completed_courses)) {
      $user->set('field_task_2_1', 1);
      $user->set('field_task_2_1_date', $formatted_date);

    }

    // task 2_2
    // request certificate
    $task_2_2 = $user->get('field_task_2_2')->value;
    $certificates = $user->get('field_course_certificates')->getValue();
    foreach($certificates as $cert_string) {
      $decoded_data = json_decode($cert_string['value']);
      if(is_null($cert_data)) {
        continue;
      } else {
        $cert_data = reset($decoded_data);
      }
      if ($cert_data->grading->certificate->download_url) {
        $user->set('field_task_2_2', 1);
        $user->set('field_task_2_2_date', $formatted_date);
        break;
      }
    }

    // task 3_2
    // complete 3 online courses
    $task_3_2 = $user->get('field_task_3_2')->value;
    if(!$task_3_2 && count($completed_courses) >= 3) {
      $user->set('field_task_3_2', 1);
      $user->set('field_task_3_2_date', $formatted_date);
    }

    // Save User
    $user->save();
  }

```

What am I missing here that is causing the script build up so much memory as it processes items?

**UPDATE**

Updated the code to the suggested existing answer in the comments, but it still seems to gradually grow in memory usage in a similar rate as before.

```
$chunks = array_chunk($uids, 100);

foreach($chunks as $chunk) {
  $users = User::loadMultiple($chunk);

  foreach($users as $user) {
    // instead of using the `cleanUp` service method, we directly modify and save the user here now
  }

  Drupal::entityTypeManager()->getStorage('user')->resetCache($chunk);
}

```

**UPDATE 2**

I commented out the `$user->save()` in the user for-loop and it performed well and memory didn't creep up... Is there a different storage cache I need to reset aside from 'user' when I save on the records?

# Answer
I would use a Queue. You can check https://api.drupal.org/api/drupal/core!core.api.php/group/queue/8.9.x for more information.

The point is each item will be processed one at a time, by timed chunks (30 seconds in my example). So the queue will process as many items it could in a 30 seconds span (or less, or more, you can adapt this in the annotation), then the process will stop and will restart next time the cron is run.

Over time, the queue will be treated. Caveat is if you absolutely need to have all users updated at once : with queue you can't tell how much time it will take - in my experience it's reliable - but eventually every user will be updated. We use it with a 5-minutes cron interval.

If you throw an `\Exception` in the `processItem()` function in the `QueueWorker`, the item will stay in the queue and will be reprocessed. Otherwise, the item will be delete from the queue.

You could use the `__construct()` method of the `QueueWorker` to use dependency injection to load services.

This is a pseudo/partial implementation :

* Create a queue (Worker) in your namespace `\Drupal\mymodule\Plugin\QueueWorker` This Worker will implement updating/saving user part (either in the body function or by using your user service).

```
    namespace Drupal\mymodule\Plugin\QueueWorker;

    /**
     * Executes queue tasks.
     *
     * @QueueWorker(
     *   id = "mymodule.user.queue",
     *   title = @Translation("Deal user"),
     *   cron = {"time" = 30}
     * )
     */
    class UserUpdateWorker extends QueueWorkerBase implements ContainerFactoryPluginInterface {

  /**
   * Update user.
   *
   * @param string $data
   *   What was injected : User ID.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   * @throws \Exception
   */
  public function processItem($data): void {
    $user = User::load($uid);
    // What you need to do.
  }

```
* Create a queue (service) like this in your mymodule.services.yml

```
mymodule.user.queue.service:
  class: Drupal\Core\Queue\QueueInterface
  factory: queue:get
  arguments: ['mymodule.user.queue'] // this is the annotation Worker ID.

```
* Use a (drush || cron || post\_update hook) function to get the list of all users and send each ID in a the queue you created.

$queue = \Drupal::service('mymodule.user.queue.service');

$uids = \Drupal::entityQuery('user')
                ->condition('status', '1')
                ->execute();

foreach($uids as $uid) {
   $queue->createItem($uid);
}```

The queue will process items at the next cron.
> 1 votes

---
Tags: 8
---


# Question
Title: How to display View contents in a drop down select list?
I have a View which display the `title` field of content of the type `Partners`. However, I want to format the results in a drop-down select list, so when a user selects one of the titles, it will automatically redirect the user to the content page. How can I achieve this?

# Answer
Sure this is all possible:

1. If you just want a select list assure you have the Ctools module installed on your site and use the `Jump Menu` views `style` output for your Partners content type. Alternatively use the Jump Menu module which you may find more helpful.
2. Want this embedded into a block you say? Use the Views Field View module to place your output of (1) into a second view that is a block. If you go this route you likely want to enable caching in your Views.

Be sure to see the project page(s) for these modules.
> 3 votes

# Answer
That is very conditionnal, select is mean to be into a form element... If you wanted a block without a form, then a custom block would definitly be the best flexible solution as @j\_reynolds suggest.

Anyway in views, you can create "form". When creating a page, just expose one of your filter criteria to user. And magic it create a form. It more look like a search page, not really what you asked.

But maybe you could consider to create a view that list all the teaser of your partner and add exposed filter on the name/title ?
> 0 votes

# Answer
For Drupal 8 or Drupal 9, you can create a view (block for example) that lists the titles of your content. Then, if the machine name of your view is `my_view`, you can create a twig template `views-view-list--my-view.html.twig` in which you include a dropdown.

Example with Bootstrap 4 dropdown (or you can use your own markup):

```
<div class="dropdown">
    <a class="btn dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
        Lorem
    </a>

    <div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
        {% for row in rows %}
            <a class="dropdown-item" href="#">{{ row.content }}</a>
        {% endfor %}
    </div>
</div>

```
> 0 votes

---
Tags: views
---


# Question
Title: Add custom form to content type (Basic Page or any) using custom extesnion
I am new to Drupal. Actually, I have to add a custom form to the content type and it will be visible to the frontend user where they can submit their response. So I have created the form and save the response in the DB. Currently, that form is not linked with the content type. It is working on a separate URL. but I am not able to achieve how can I add that form to the specific content type?

I am using drupal 8.

Please help me with this. Thanks!

# Answer
This is exactly what something like the Webform module can do for you. Create a form with these fields and then you can use webform nodes and the block system to place the webform as a block within the node page, and the form can capture the node it was submitted from.
> 0 votes

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


# Question
Title: Ajax Callback only works after second click
I created a custom form with a textbox and a button. When the user clicks on that button, an ajax call should take place.

When I click on that button for the first time, a page refresh takes place. Only when I click on the button for the second time, my ajax-function is called.

I don't know what I'm doing wrong, so I would be greatful for any suggestion.

```

function buildForm(array $form, FormStateInterface $form_state)
{
    //Oorspronkelijk staat van formpost:
    $_SESSION['formpost'] == 'rrn_nok';

    array_push($form['#attributes']['class'], 'col-12');

    $form["foutmeldingen"] = array(
        '#type' => 'container',
        '#prefix' => '<div id="edit-foutmeldingen" class="webform-messages">',
        '#suffix' => '</div>',
    );

    $form['group_rrn'] = array(
        '#type' => 'container',
        '#prefix' => '<div id="controle-rrn">',
        '#suffix' => '</div>',
    );

    $form['group_rrn']['rijksregisternummer'] = [
        '#type' => 'textfield',
        '#required' => TRUE,
        '#title' => 'Rijksregisternummer',
        '#attributes' => [
          'data-inputmask-mask' => '999999-999-99',
          'class' => ['js-webform-input-mask'],
        ],
    ];
    $form['group_rrn']['rijksregisternummer']['#attached']['library'][] = 'webform/webform.element.inputmask';

    $form['group_rrn']['actions'] = array(
        '#type' => 'button',
        '#value' => 'Ga verder',
        '#attributes' => array('class' => array('btn', 'btn-primary')),
        '#ajax' => [
            'callback' => '::ajaxRijksregisternummer',
            'event' => 'click',
            'wrapper' => 'aanvraag',
            'progress' => array(
                'type' => 'throbber',
                'message' => 'Even geduld',
            ),
        ],
    );

    $form['group_form'] = array(
      '#type' => 'container',
      '#prefix' => '<div id="aanvraag">',
      '#suffix' => '</div>',
  );

    $form['group_form']['landen'] = array(
      '#type' => 'textfield',
      '#title' => 'Kies land(en)',
      '#autocomplete_route_name' => 'tools.reisdocumentenautocomplete',
      '#autocomplete_route_parameters' => array(),
      '#description' => "Typ de beginletters van het land en kies uit de lijst. Voor meerdere landen typ je een ',' en herhaal dezelfde werkwijze.",
    );

    $form['group_form']['startdatum'] = [
      '#type' => 'date',
      '#title' => 'Kies startdatum',
      '#date_format' => 'd-m-Y',
      '#attributes' => [
        'min' => format_date(strtotime("+7 day", time()), 'html_date'),
        'data-inputmask-mask' => '99-99-9999',
        'class' => ['js-webform-input-mask'],
      ],
    ];

    $form['group_form']['einddatum'] = [
      '#type' => 'date',
      '#title' => 'Kies einddatum',
      '#date_format' => 'd-m-Y',
      '#attributes' => [
        'min' => format_date(strtotime("+7 day", time()), 'html_date'),
        'data-inputmask-mask' => '99-99-9999',
        'class' => ['js-webform-input-mask'],
      ],
    ];

    $form['group_form']['bestelling'] = array(
      '#type' => 'checkboxes',
      '#options' => array(
        'Dit Rijksregisternummer' => 'Dit Rijksregisternummer',
        'Partner' => 'Partner',
        'Kinderen' => 'Kinderen',
        'Andere PTL' => 'Andere personen ten laste'),
      '#title' => 'Bestelling',
    );

    $form['group_form']['email'] = array(
      '#type' => 'email',
      '#title' => 'Jouw e-mailadres',
    );

    $form['group_form']['telefoon'] = array(
      '#type' => 'textfield',
      '#title' => 'Jouw telefoonnummer',
      '#maxlength' => 10,
    );

    $form['group_form']['partner_rrn'] = array(
      '#type' => 'hidden',
      '#attributes' => array('id' => 'edit-partner-rrn'),
    );
    $form['group_form']['fed'] = array(
      '#type' => 'hidden',
      '#attributes' => array('id' => 'edit-fed'),
    );

    $form['group_form']['actions'] = array(
      '#type' => 'button',
      '#value' => 'Verzenden',
      '#attributes' => array('class' => array('btn', 'btn-primary')),
      '#ajax' => [
        'callback' => '::ajaxSubmit',
        'event' => 'click',
        'progress' => array(
            'type' => 'throbber',
            'message' => 'Even geduld',
        ),
        '#validate' => array('myformname__do_validate'),
    ],

  );

    return $form;
}

```

This is the CallBack function:

```
function ajaxRijksregisternummer($form, $form_state) {
    $response = new AjaxResponse();
    $rijksregisternummer = $form_state->getValue('rijksregisternummer');
    if(ReisdocumentenForm::isCorrectRijksregisternummer($rijksregisternummer)){
        $member = '';
        if(ReisdocumentenForm::isMemberApiCall($rijksregisternummer, $member)){
          $_SESSION['formpost'] = 'rrn_ok';
          $form['group_form']['email']['#required'] = TRUE;
          $response->addCommand(new CssCommand('#controle-rrn', ['display' => 'none']));
          $hasPartner = $member['hasPartner'];
          $federatie = $member['federation'];
          $partner = '';
          if($hasPartner == 'true'){
            $partner = $member['partnerInfo'];
          }
          $response->addCommand(new InvokeCommand(NULL, 'AjaxCallBackShowAanvraag', [$hasPartner, $partner, $federatie]));
        } else {
            $markup = '<div data-drupal-messages-fallback="" class="hidden"></div><div data-drupal-messages=""><div role="contentinfo" aria-label="Foutmelding"><div role="alert"><h2 class="visually-hidden">Foutmelding</h2>Dit formulier is enkel voor leden van ons ziekenfonds.</div></div></div>';
            $response->addCommand(new AppendCommand('#edit-foutmeldingen', $markup));
        }
    }
    else {
        $markup = '<div data-drupal-messages-fallback="" class="hidden"></div><div data-drupal-messages=""><div role="contentinfo" aria-label="Foutmelding"><div role="alert"><h2 class="visually-hidden">Foutmelding</h2>Geen correct rijksregisternummer.</div></div></div>';
        $response->addCommand(new AppendCommand('#edit-foutmeldingen', $markup));
    }
    return $response;
}

```

Kind regards!

# Answer
> 0 votes
I found the solution for my problem. It was not the form, but the block in which the form was loaded, that was the problem. I disabled the caching and now it works as expected.

```
/**
 * Provides a 'ReisdocumentenBlock' block.
 *
 * @Block(
 *   id = "ReisdocumentenBlock_block",
 *   admin_label = @Translation("ReisdocumentenBlock socmut"),
 *   category = @Translation("socmut")
 * )
 */
class ReisdocumentenBlock extends BlockBase implements BlockPluginInterface
{
    /**
     * {@inheritdoc}
     */
    public function build()
    {
        $form = \Drupal::formBuilder()->getForm('Drupal\tools\Form\ReisdocumentenForm');
        return $form;
        }
    }

    /**
     * Disable caching for ajax problem with form
     */
    public function getCacheMaxAge() {
        return 0;
    }
}

```

I'm still curious to know that maybee I can solve this with a certain cache context instead of disableing all the cache?

---
Tags: 8, ajax
---


# Question
Title: How can I add a pattern attribute to a phone field?
I am trying add `pattern` `attribute` to phone field of `drupal`'s core feedback form. I am trying to do like this in `mytheme.theme`

```
function mytheme_form_alter(array &$form, FormStateInterface $form_state, $form_id) {

  if('contact_message_feedback_form' == $form_id){
    $form['field_phone']['#attributes'][] = ['pattern' => '\+[0-9]?()[0-9](\s|\S)(\d[0-9]{9})'];
   }
}

```

but `pattern` attribute not showing up (also cleared caches). I am using `9.1.4`.

# Answer
> 1 votes
Maybe it's not an array, try to use a Attribute object :

```
use Drupal\Core\Template\Attribute;
if (empty($form['field_phone']['#attributes']) {
    $form['field_phone']['#attributes'] = new Attribute();
}

if (is_a($form['field_phone']['#attributes'], Attribute::class)) {
    $form['field_phone']['#attributes']->setAttribute('pattern', '\+[0-9]?()[0-9](\s|\S)(\d[0-9]{9})');
}
else {
    $form['field_phone']['#attributes'][] = ['pattern' => '\+[0-9]?()[0-9](\s|\S)(\d[0-9]{9})'];
}

```

Edit:

I checked on a D8 instance I got on my IDE and I managed to have it working with the following code :

```
$form['elements']['phone']['#attributes']['pattern'] = '#^+[0-9]?()[0-9](\s|\S)(\d[0-9]{9})$#';

```

You may need to replace 'phone' by the field name you set in the IDE.

---
Tags: forms, 9
---


# Question
Title: How to create custom search filter for entity list
I want to make my entity list/table searchable, but the docs are not helping. I created custom module that generates

My table:

I have entity Event and it has NAME variable. The result i want to get is like in domain/admin/people - Search by name

# Answer
> 6 votes
Not that complicated and you don't *need* `Views`. Most of the functionality is right there, built-in, you only need to add your own bits.

## Filtering

In addition to `EntityListBuilder`, create a form of the filter to be exposed. Just create a usual form extending `FormBase`, building whatever UI you need (eg. a dropdown with items to select from, with **Filter** and **Reset** buttons). Let's call it `DocumentFilterForm`, this is its form builder:

```
public function buildForm(array $form, FormStateInterface $form_state) {
  $request = \Drupal::request();

  $form['filter'] = [
    '#type' => 'container',
    '#attributes' => [
      'class' => ['form--inline', 'clearfix'],
    ],
  ];

  $form['filter']['foo'] = [
    '#type' => 'select',
    '#title' => 'Which foo?',
    '#options' => ...,
    '#default_value' => $request->get('foo') ?? 0,
  ];

  $form['filter']['bar'] = [
    '#type' => 'select',
    '#title' => 'Which bar?',
    '#options' => ...,
    '#default_value' => $request->get('bar') ?? 0,
  ];

  $form['actions']['wrapper'] = [
    '#type' => 'container',
    '#attributes' => ['class' => ['form-item']],
  ];

  $form['actions']['wrapper']['submit'] = [
    '#type' => 'submit',
    '#value' => 'Filter',
  ];

  if ($request->getQueryString()) {
    $form['actions']['wrapper']['reset'] = [
      '#type' => 'submit',
      '#value' => 'Reset',
      '#submit' => ['::resetForm'],
    ];
  }

  return $form;
}

```

We have two dropdowns, as per usual, with the two buttons. The **Reset** only appears when needed, just like with the standard Views displays. `submitForm()` redirects to the URL with the appropriate query (remember to change the route name), `resetForm()` redirects to the original URL.

```
public function submitForm(array &$form, FormStateInterface $form_state) {
  $query = [];

  $foo = $form_state->getValue('foo') ?? 0;
  if ($foo) {
    $query['foo'] = $foo;
  }

  $bar = $form_state->getValue('bar') ?? 0;
  if ($bar) {
    $query['bar'] = $bar;
  }

  $form_state->setRedirect('entity.document.collection', $query);
}

public function resetForm(array $form, FormStateInterface &$form_state) {
  $form_state->setRedirect('entity.document.collection');
}

```

Back in the list builder, we modify `getEntityIds()` to apply our filters, when present:

```
protected function getEntityIds() {
  $query = \Drupal::entityQuery($this->entityTypeId);
  $request = \Drupal::request();

  $foo = $request->get('foo') ?? 0;
  if ($foo) {
    $query->condition('foo', $foo);
  }

  $bar = $request->get('bar') ?? 0;
  if ($bar) {
    $query->condition('bar', $bar);
  }

  if ($this->limit) {
    $query->pager($this->limit);
  }

  return $query->execute();
}

```

And finally, to actually include the filter form on the page:

```
public function render() {
  $build['form'] = \Drupal::formBuilder()->getForm('Drupal\...\Form\DocumentFilterForm');
  $build += parent::render();
  return $build;
}

```

## Sorting

Sorting is even simpler, you only have to add to your list builder. First, set up the headers like with any other similar table:

```
public function buildHeader() {
  $header = [
    'foo' => [
      'data' => 'Foo',
      'field' => 't.foo',
    ],
    'bar' => [
      'data' => 'Bar',
      'field' => 't.bar',
      'sort' => 'asc',
    ],
  ];
  return $header + parent::buildHeader();
}

```

Second, add the following to your previous `getEntityIds()`:

```
protected function getEntityIds() {
  $query = \Drupal::entityQuery($this->entityTypeId);
  $request = \Drupal::request();

  // ...

  $order = $request->get('order');
  if ($order) {
    $sort = $request->get('sort');
    foreach ($this->buildHeader() as $name => $field) {
      if (is_array($field) && $field['data'] == $order) {
        $header = [$name => $field + [
          'specifier' => $name,
          'sort' => $sort ?? $field['sort'] ?? 'asc',
        ]];
      }
    }
    if ($header) {
      $query->tableSort($header);
    }
  }
  else {
    $query->sort('bar', 'asc');
  }

  return $query->execute();
}

```

Note that this relies on the `data` elements in the header being simple strings. If you use `t()`, you need to compare to `$field['data']->getUntranslatedString()` instead. It also assumes that your header items (`foo` and `bar`) use the same name as the underlying field. If not, modify accordingly. `tableSort()` requires a simple nested array that has a `specifier` pointing to the field name and a `sort` to describe the sort direction, you can create it however you wish, it will work.

# Answer
> 3 votes
You are using an entity list builder? There is no standard support for filters/sort, if you want to implement something you have to do it yourself.

All content lists that use filters like admin/people and admin/content are views, expose your entity type to views if it is a content entity type.

One special case is admin/structure/views, which is a config entity list builder that has support for filters. But that's actually a client-side implementation done with javascript.

---
Tags: 8, views
---


title: History of nodes viewed by a user

text:
# Question
Title: History of nodes viewed by a user
I'm developing a site using Drupal 8.2 and I have to create a page where the user can see which nodes he or she has viewed in the last 30 days. The goal is to provide a per user "browsing history" view with the recently read content ordered by date (ideally filtered by content type).

I've checked other similar questions about this topic and I've found the following suggested modules:

Unfortunately these modules don't have Drupal 8 releases at the time of writing this question (except the Message module which has a pre-release/alpha version).

I've also reviewed the official docs and found there's a core History module that tracks which nodes have been viewed by each user and when. I have this module enabled (it was enabled by default) and I've checked that it's actually collecting user interactions in the *history* table. According to the docs:

> In Drupal 8 and later, the History module is included in Drupal core. When enabled, the History module records which user has read which content.
>
> This only applies to authenticated users. Entities older than 1 month will always be shown as "read".
>
> There is no UI provided, but history data is exposed to the Views module. You can add history data as a field to show "new" or "updated" node marks. You can also use a filter to only show content that is new or updated.

this module provides some kind of interaction with Views, so I assume it should be posible to create a view to show a list with links to each node viewed by the user. I've reviewed all the options in Views (filters, contextual filters and so on) and haven't found anything related to this history.

Is it really posible to create such a view? Any pointers on how to do that? Is there any other way to do this? How would you implement this funcionality in Drupal 8?

Cheers.

# Answer
> 0 votes
In your views view you can add a filter "Content: Has new content" provided by History module. So the view is created per user and lists content what is new for the user (or updated).

---
Tags: 8
---


# Question
Title: How do I understand which version is supported by a module?
I want to use the APIs described in REST and other APIs to understand which Drupal versions are supported by a module.

So far, I tried with https://www.drupal.org/api-d7/node.json?field\_project\_machine\_name=ctools, but it doesn't return any information about the supported Drupal version.

How can I retrieve the Drupal version with which a module is compatible?

# Answer
> 1 votes
The Drupal versions with which a module like the *Chaos Tool Suite (ctools)* module is compatible is listed in https://updates.drupal.org/release-history/ctools/current, for each module releases. That API is described in Update status XML.

For example, the following XML tags are saying that release 8.x-3.6 is compatible with Drupal 8.8 and Drupal 9. The value is set from the project maintainers; it's not a value set by tools able to determine the Drupal versions with which a module is compatible.

```
<name>ctools 8.x-3.6</name>
<version>8.x-3.6</version>
<tag>8.x-3.6</tag>
<status>published</status>
<release_link>https://www.drupal.org/project/ctools/releases/8.x-3.6</release_link>
<download_link>https://ftp.drupal.org/files/projects/ctools-8.x-3.6.tar.gz</download_link>
<date>1620832812</date>
<security covered="1">Covered by Drupal's security advisory policy</security>
<core_compatibility>^8.8 || ^9</core_compatibility>

```

https://updates.drupal.org/release-history/ctools/current shows only the releases compatible with Drupal 8 or newer versions. For Drupal 7, the URL is https://updates.drupal.org/release-history/ctools/7.x, but that doesn't show the exact Drupal 7 version the module is compatible with.

```
<name>ctools 7.x-1.19</name>
<version>7.x-1.19</version>
<tag>7.x-1.19</tag>
<version_major>1</version_major>
<version_patch>19</version_patch>
<status>published</status>
<release_link>https://www.drupal.org/project/ctools/releases/7.x-1.19</release_link>
<download_link>https://ftp.drupal.org/files/projects/ctools-7.x-1.19.tar.gz</download_link>
<date>1611988841</date>
<mdhash>57a6bb37a3d69c51170212802e728951</mdhash>
<filesize>451495</filesize>
<security covered="1">Covered by Drupal's security advisory policy</security>

```

Since the release name starts with *7.x-*, that release is compatible with Drupal 7.

---
Tags: community-official-site
---


title: LIKE operator to load taxonomy term

text:
# Question
Title: LIKE operator to load taxonomy term
I want to retrieve a taxonomy term using this line:

```
$term = $this->entityTypeManager->getStorage('taxonomy_term')
        ->loadByProperties(['myfield' => 'mytext']);

```

How can I rather use the 'LIKE' operator we have in SQL, so that in case the 'myfield' contains a text and not a string in the database, it still works? Thanks for your help

# Answer
> 0 votes
I found the answer..I had to use the entity query then load term:

```
$result = \Drupal::entityQuery('taxonomy_term')
        ->condition('myfield', 'mytext', 'LIKE')
        ->execute();

$term = \Drupal::entityTypeManager()
        ->getStorage('taxonomy_term')
        ->loadMultiple($result);

```

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


# Question
Title: How to handle appendItem() when a list is full?
I'm creating a custom JSON:API Resource to store push notifications tokens.

The user account field where the tokens are stored has a limit of **5** items.

I am using appendItem() to add the value to field.

However, if the field already has 5 values, then `appendItem()` does nothing. In this case, instead of doing nothing, I want to bump the first item (the value saved first) from the array and then move all the other values up a place (last in last out).

I can code this myself but it occurred to me that this may be something Drupal already provides but I just don't know enough about the API to figure out where to look for it. Does Drupal provide some way to handle multi-value field values when the limit on the number of values has been reached?

Here's my code so far:

```
// Make sure we have a real token.
if (strlen($push_token) >= 100) {

  // Generate an array of the existing token values.
  $existing_tokens = $current_user->get('field_text_token_push')->getValue();
  $token_values = [];
  foreach($existing_tokens as $existing_token) {
    $token_values[] = $existing_token['value'];
  }

  // Check whether the token already exists.
  if (in_array($push_token, $token_values)) {
    $this->loggerFactory->notice("Push token: Did not add token for UID @uid because it already exists.", [
      '@uid' => $uid,
    ]);
    $return_bool = TRUE;
  } else {
    // Add the token.
    // Todo: If we have reached the field limit, automatically remove the earliest value and replace with the new value.
    $current_user->get('field_text_token_push')->appendItem($push_token);
    $current_user->save();
    $this->loggerFactory->notice("Push token: Added token for UID @uid.", [
      '@uid' => $uid,
    ]);
    $return_bool = TRUE;
  }
}

```

# Answer
> 2 votes
Broken these down into separate lines to help you pick and choose what you need.

```
$field = $current_user->get('field_text_token_push');
$field_definition = $field->getFieldDefinition();
$field_storage_definition = $field_definition->getFieldStorageDefinition();

// Upper limit.
$cardinality = $field_storage_definition->getCardinality();

// Number of current items.
$items = $field->count();

```

I don't know about this but I suspect that there isn't anything or any method that will automatically handle your use case (e.g. FIFO for multi value fields). You will probably have to code it yourself with a combination of the above and...

I guess with this then you could `$field->removeItem(0)->rekey()` if you've reached the maximum cardinality. Obviously handling excluding count comparisons where the cardinality is `FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED`

# Answer
> 2 votes
It should be no problem to bump the first item with array\_slice():

```
$values = $node->field_foo->getValue();
$values[] = ['value' => 'bar'];
$values = array_slice($values, -5);
$node->field_foo->setValue($values);
$node->save();

```

---
Tags: entities, 9
---