# Question
Title: How can I safely move a module to another folder?
I created a module through Drupal Console, unfortunately it wasn't placed in a folder of its own, rather straight into `/modules/custom`. Before I noticed where it had gone, I enabled the module.

In Drupal 6/7, this was easy to fix - I could literally just put the files into the correct path, clear the cache (maybe rebuild the registry, it wasn't an exact science), and all was well.

The same isn't true for Drupal 8; I moved the files into a subfolder, rebuilt cache, and all requests tell me that Drupal is failing to include a required file. The particular file is a block class, and the path Drupal is trying to find it is where it *used* to be, not where I've moved it to.

The bit of code objecting is in Symfony's `ApcClassLoader`, so I guess I need to clear something that's slightly above Drupal's head to get this path reference updated.

How can I do that?

Uninstalling and re-installing the module does work, but once there's important data stored that's not going to be an option.

I was wrong, uninstalling and re-installing is *not* a viable option. After uninstalling and reinstalling, Drupal can no longer pick up the custom blocks the module defines. I'm guessing that reference is cached somewhere that isn't cleared when the module is uninstalled. Just need to find out where that is and how to clear it...

# Answer
Just restart apache. The APC cache will be rebuild then.

You can also try to hit rebuild.php or run drush cr. Those all attempt to explicitly clear the APC cache.
> 13 votes

# Answer
Moving modules to a different location without disabling it is a quite tricky process in Drupal 8. There's a lot of discussion about it but I coudn't find a proper solution so I've decided to digg a bit. In Drupal 7 it was easy, just put a module to new location, clear the cache and you're done, but D8 might be different. So, this is the quick step through without answering why you need to do this or that, I'll answer this later.

First of all, check if `apcu` extension is installed and enabled in your php. You should do it by visiting `/admin/reports/status/php`. Keep in mind there's no point to check it through the console as it might use different php.ini file. This needs to be done through browser.

### With APCU extension enabled.

1. Move your module code to desired location.
2. Clear drupal cache.
3. Call `apcu_clear_cache()` function, but it has to be triggered from browser. There's no way it'll work by calling it from console or drush, so keep in mind that `drush ev "apcu_clear_cache();"` will not work.
4. That's it, now your module should be available to use and it should not complaining by missing PHP classes or plugins.

### Without APCU extension enabled or installed.

1. Move your module to different location
2. Clear drupal cache.
3. Done

### A bit of explanation

Let's digg a bit and find the details, so we have some idea what's happning here.

In most answers you will find out that cleaning drupal cache or providing extra `class_loader_auto_detect` setting to FALSE will work for you. Sometimes it works, sometimes not. If you put your `class_loader_auto_detect` setting to FALSE it'll work but you will loose class caching mechanism. Is it really a good idea? Well, no. If it is an option and it's ready to use why would you? There's no point doing it. Instead let's use it.

So, let's assume that you do have `APCU` extension enabled. While drupal 8 is booting `DrupalKernel.php` boot method will use APCU by default unless it's disabled in you `settings.php` (`class_loader_auto_detect` settings set to FALSE) which can be found here:

https://github.com/drupal/drupal/blob/9.2.x/core/lib/Drupal/Core/DrupalKernel.php#L476

So, if the `class_loader_auto_detect` setting is not set just make it TRUE and use it - that's what's in code. When that happens we know that `APCU` extension is already used. But what exactly does it?

Well, it does walk through all of the php classes and cache its names, locations and namespaces. That's the reason your module is broken after the relocation.

### Example:

Let's assume you have a custom block defined at:

`/app/drupal/web/modules/custom/your_module/src/Plugin/Block/CustomBlock.php`

This block plugin class, namespace and its location is cached by `APCU`. Let's prove it. Just call `apcu_cache_info()` function which is part of `APCU` extension. Now, move your module into new location and for testing purposes, for example to:

`/app/drupal/web/modules/contrib/your_module/src/Plugin/Block/CustomBlock.php`

Now, call again apcu\_cache\_info() function. You can see that the location of block plugin class is still registered at:

`/app/drupal/web/modules/custom/your_module/src/Plugin/Block/CustomBlock.php`

So this is the old location. Now, try to clear drupal cache and call it again. It's still the same. It's not going to be changed as it's not part of drupal cache. What drupal cache does in terms of relocating modules is an entry in you cache\_container table. It contains information about location of your .module file and .yml file, but not about specific php classes.

So, what exactly happens when you try to display or load a block which has been relocated? Well, it'll throw a PluginException error, which happens here:

https://github.com/drupal/drupal/blob/9.2.x/core/lib/Drupal/Component/Plugin/Factory/DefaultFactory.php#L96

```
if (!class_exists($class)) {
  throw new PluginException(sprintf('Plugin (%s) instance class "%s" does not exist.', $plugin_id, $class));
}

```

It fails on class\_exists() function because it gets the name and namespace of class which is still registered in:

`/app/drupal/web/modules/custom/your_module/src/Plugin/Block/CustomBlock.php`

not

`/app/drupal/web/modules/contrib/your_module/src/Plugin/Block/CustomBlock.php`

location. That's what PHP gets.

### Solution

So, what can we do about it? Well, it seems like pretty simple task, we need to clear the APCU cache `apcu_clear_cache()`. But there is a catch, if you do it from console it'll not work, in short it's not hitting the same APC segment of your webserver (more details here: https://stackoverflow.com/a/43501450/567058). It needs to be triggered from browser. But keep in mind that it needs to be called at very early stage of drupal bootstrap or on any drupal page that actually loads without any issues. So, don't try to call it on broken block page in preprocess function or similar, because it'll never gets to preprocess functions. It'll fail way before and it'll never have a chance to clear apcu cache. The best solution is to use extra contrib module which brings APCU cache clear (I'll give you a link later on) option or call it on any non broken page, might be custom controller or just a preprocess\_html, up to you.

### Final thoughts

As you can see drupal 8 modules relocation might be really tricky. There's several things that needs to be checked. There might be modules that can be relocated by clearing drupal cache and that's enough, just because the module constis of .module and .info files, without any php custom classes and there's nothing to be cached by apcu and all the information (cache\_container table) are storred in DB, so it'll just work. There are cases where modules have custom classes and still can be relocated just becasue there's no apcu extension in your php instace or you have `class_loader_auto_detect` setting set to FALSE and uncommented. So, each case might be different and I think this is the reason why people are so confused about relocating modules and for some clearing the drupal cache will work and for other will not.
> 4 votes

# Answer
Drupal stores a cached version of the container at the cache\_container table. This table contains, among other things, the list of module paths.

For most cases running `drush cr` should be enough but if you see that even `drush cr` crashes then you will need to create a database update like this in an already installed module:

```
/**
 * Clears all caches after moving modules from modules to modules/contrib.
 */
function mymodule_update_8100(&$sandbox) {
  drupal_flush_all_caches();
}

```

And then run `drush updb -y`.
> 1 votes

# Answer
Another solution is put in your settings.php:

```
 /**
 * Class Loader.
 *
 * If the APC extension is detected, the Symfony APC class loader is used for
 * performance reasons. Detection can be prevented by setting
 * class_loader_auto_detect to false, as in the example below.
 */
$settings['class_loader_auto_detect'] = FALSE;

```
> 0 votes

# Answer
This worked for me By Admin UI Navigate to /admin/config/development/performance and click the button "Clear all caches".
> 0 votes

# Answer
None of the above solutions helped I had to visit `/update.php` which bypasses the drupal bootstrap. I suppose

```
drush updb

```

would do the same.
> 0 votes

# Answer
* drush cr didn't help for me.
* Restarting IIS didn't do anything, nor did restarting windows.
* drush ev "apcu\_clear\_cache();" and drush ev "drupal\_flush\_all\_caches();" both crashed, because it couldn't locate my info.yml. Same error message as accessing Drupal via a browser.

What finally helped was truncating all cache\_\* tables.
> 0 votes

---
Tags: 8
---


# Question
Title: Why does Ajax prevents managed_file to be displayed?
I have this form

created by this code:

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

    some initialisation code...

    $database = \Drupal::database();

    //  From database to populate $form['designation']
    $query_am = $database->select('member', 'am');
    $query_am->fields('am', ['id', 'designation']);
    $query_am->condition('status', [2, 3, 4], 'IN')
        ->orderBy('designation', 'ASC');
    $aMembers = $query_am->execute()->fetchAllKeyed();
    $aMembers = ["0" => ""] + $aMembers;

    $memberId = $form_state->getValue('designation');
    if ($memberId) {
        $query = $database->select('contract_subscription', 'cs')
            ->fields('cs')
            ->condition('contract_id', $contractId)
            ->condition('member_id', $memberId);
        $subscription = $query->execute()->fetchAssoc();
    }

    $wrapper = 'formWrapper';
    $form['#prefix'] = '<div id="' . $wrapper . '">';
    $form['#suffix'] = '</div>';

    $form['designation'] = [
        '#type' => 'select',
        '#options' => $aMembers,
        '#title' => $this->t('Member'),
        '#required' => TRUE,
        '#default_value' => $memberId,
        '#ajax' => [
            'callback' => '::memberCallback',
            'wrapper' => 'theSubscription',
        ],
    ];

    $form['theSubscription'] = [
        '#type' => 'container',
        '#attributes' => ['id' => 'theSubscription'],
        '#quantities' => $iNumberOfQuantities,
    ];

        $value = $subscription['quantity01'];
        $form['theSubscription']['quantity01'] = [
            '#type' => 'number',
            '#title' => $aContractTypeHeader[$i - 1],
            '#min' => 0.00,
            '#max' => 99.95,
            '#step' => 0.05,
            '#value' => $value,
        ];
    }

    $form['theSubscription']['comment'] = [
        '#type' => 'textarea',
        '#title' => t('Comment'),
        '#rows' => 1,
        '#value' => $subscription['comment'],
    ];

    $fileId = (int) $subscription['file__target_id'];
    $form['theSubscription']['file'] = [
        '#type' => 'managed_file',
        '#description' => $this->t('Limited to @size MB.', ['@size' => $upload_max_inMB]) . '<br>' . $this->t('Allowed types: pdf.'),
        '#upload_location' => 'private://contracts/subscriptions/',
        '#upload_validators' => [
            'file_validate_extensions' => ['pdf'],
            'file_validate_size' => [$upload_max],
        ],
        '#default_value' => [$fileId],
    ];

    if ($sContractIsOpenForSubscription) {
        $form['save'] = [
            '#type' => 'submit',
            '#name' => 'save',
            '#value' => $this->t('Save'),
            '#ajax' => [
                'wrapper' => $wrapper,
                'callback' => '::ajaxSave',
            ],
        ];
    }

    $form['leave'] = [
        '#type' => 'submit',
        '#name' => 'leave',
        '#value' => $this->t('Leave'),
    ];

    $form['#attached']['library'][] = 'amap/amap';

    return $form;
}

public function memberCallback($form, FormStateInterface $form_state) {
    return $form['theSubscription'];
}

```

When I select an item in the select box, Ajax `memberCallback`is called, `$database->select('contract_subscription', 'cs')` is executed and the form is updated with the values retrieved from the database.
That works for all the fields except for the file which is never displayed (only the default empty managed\_file field shows up):

I wanted to check and I executed the form with `$memberId = 64;` hardcoded to force a first display without using Ajax and it works!

What is wrong with my code?

# Answer
**Tried to use field name of file like this:**

```
$form['theSubscription']['file'][$fileId]
or either
$form['theSubscription'][$fileId]

```

**instead of**

```
 $form['theSubscription']['file']

```

Analysis: By passing "$fileId" variable in field name , it makes field name dynamic & cache 'll not maintain of rendering "file\_widget" hooks, it 'll render dynamic value of "managed\_file" field on ajax call.
> 0 votes

---
Tags: forms, ajax, 9
---


# Question
Title: Nginx: block access to extensionless LICENSE files
The Drupal Nginx recipe doesn't block access to extensionless files (such as files named "LICENSE"), and it also allows access to LICENSE.md and other files that can be checked to see what modules are in use on a Drupal site.

As an example, if I have a running Drupal site and in my browser go to mydrupalsite.example.com/modules/contrib/ckeditor/vendor/LICENSE.md, and a file is downloaded, I know that the CKEdtior 4 contrib module is used. By checking files of popular modules like this, and checking the content of the files, someone could try to figure out specific versions of modules on Drupal sites, looking for vulnerable versions.

The best solution is to keep everything up-to-date, of course. Still, I'm wondering if the Drupal Nginx recipe can be improved to mitigate this method of finding what modules and dependencies are used, without blocking access to markdown files that have been uploaded to the site, as I want to support that.

Specifically, I want to block access to extensionless files altogether, as well as markdown files that come with the installed modules/dependencies and weren't uploaded by users.

# Answer
One way to "block access" is to delete the files. I know you asked about how to block the files with nginx, so consider this an indirect answer to your question.

In my CD pipeline, I have a bash script, `clean-repo-for-cloud.sh`. I execute this script every build to delete the unnecessary files from my deploy images.

Here's the relevant part of my script:

```
#!/bin/bash

# Show every command with variables expanded for debugging.
# set -x
# Abort on failure.
set -eo pipefail

# Set the script directory.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# Change to the script directory so that relative paths work.
cd "$SCRIPT_DIR" || exit

git_root="$SCRIPT_DIR/../../"
drupal_core_path="$git_root/web/core"

function remove_unnecessary_drupal_files {
  # Delete Drupal test directories.
  # https://unix.stackexchange.com/a/89937
  find . -type d -name tests -exec rm -rf {} +
  # Delete testing and demo profiles.
  drupal_core_profiles_path="$drupal_core_path/profiles"
  # Use -print to show what is deleted.
  find "$drupal_core_profiles_path" -type d -name 'testing*' -exec rm -rf {} +
  # find "$drupal_core_profiles_path" -type d -name 'testing*' -exec rm -rf {} + -print
  find "$drupal_core_profiles_path" -type d -name 'nightwatch_testing' -exec rm -rf {} +
  # find "$drupal_core_profiles_path" -type d -name 'nightwatch_testing' -exec rm -rf {} + -print
  find "$drupal_core_profiles_path" -type d -name 'demo_umami' -exec rm -rf {} +
  # find "$drupal_core_profiles_path" -type d -name 'demo_umami' -exec rm -rf {} + -print
  # Delete README files.
  find . -type f -name 'README*' -delete
  # find . -type f -name 'README*' -delete -print
  find . -type f -name 'CHANGELOG*' -delete
  # find . -type f -name 'CHANGELOG*' -delete -print
  # Delete patch records.
  find . -type f -name 'PATCHES.txt' -delete
  # find . -type f -name 'PATCHES.txt' -delete -print
  # Delete markdown files except licenses.
  find web -type f -name "*.md" -not -name "LICENSE*" -delete
  # find web -type f -name "*.md" -not -name "LICENSE*" -delete -print
  # Delete txt files except licenses.
  find web -type f -name "*.txt" -not -name "LICENSE*" -not -name "COPYRIGHT*" -delete
  # find web -type f -name "*.txt" -not -name "LICENSE*" -not -name "COPYRIGHT*" -delete -print

}

remove_unnecessary_drupal_files

```

In your case, you would want to delete the licenses, too.
> 2 votes

---
Tags: files
---


# Question
Title: Config import conflict, how to remove lock
I am trying to import config on my staging site, and I repeatedly get the following message:

> Another request may be synchronizing configuration already.

I know that there are no other processes currently importing config, so there is some rogue lock.

I am using config\_split module on the site, but both methods of config import report the lock. I have updated the site to Drupal 8.6.1 but the issue may have existed prior to the update.

Question: How can I remove the lock using Drush or some other method?

# Answer
My specific issue was that Redis module update to 1.0 brought with it new `redis.services.yml` file in the module. Updating my site's Redis services file, in sites/default/, resolved the issue.

What was happening was that the `alreadyImporting()` method of ConfigImporter defaults to true, when in fact my mis-configuration would have been returning an error I think.

This issue pointed me in the right direction: https://www.drupal.org/project/redis/issues/2996655

If it had been a simple lock issue the following should have worked I think:

```
drush ev "\Drupal::lock()->release('config_importer');"

```
> 7 votes

# Answer
I had a `memcache.yml` file in `sites/default` that was switching the default lock backend with a memcache implementation. Since I did not have memcache running, I was unable to import the configuration.
> 0 votes

# Answer
Run `drush cr`, wait for 10 seconds, and try again. The import will work.
> -1 votes

---
Tags: 8, configuration
---


# Question
Title: How to return failure with an event subscriber?
I have an event subscriber that deducts a credit when someone makes a booking. If there are no credits left, how do I return a failure and stop the booking being made?

The subscriber is acting on ENTITY\_INSERT.

```
public static function getSubscribedEvents(): array {
  return [
    EntityHookEvents::ENTITY_INSERT => [
      'redeemTicket',
      -20,
    ],
  ];
}

```

I've tried

```
throw new AccessDeniedHttpException('This booking needs a valid ticket!');

```

Although this results in a 'white screen'

```
Drupal\Core\Entity\EntityStorageException: This booking needs a valid ticket! in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (

```

Following the drupal event documentation.

# Answer
Yes, it's better to stop the save operation as soon as possible, but in this case, storing a content entity via SQL, the result is the same. Both hooks are in one SQL transaction, only that in the original code the SQL database has more to rollback. It might be a better idea to check the condition when validating the input data and only throw exceptions in database operations if anything unexpected happens.

BTW this is not a Symfony topic because you are using events dispatched from Drupal hooks. So it's the same as if you would put the code directly in these hooks. The referenced documentation is about events dispatched by the Symfony kernel.
> 1 votes

---
Tags: event-subscribers
---


# Question
Title: How can I improve speed when developing in localhost
I'm looking for tips from other Drupal developers to make Drupal faster when developing (specially Drupal 7), taking in consideration that during development you don't want cache, so you can see the result of changes in code PHP/CSS/JavaScript. (See some answers about flushing cache / disabling cache permanently.)

Googling for "drupal slow localhost" will give some tips. but I want yours.

# Answer
You can probably get further by changing how you work instead of making Drupal faster on page loads.

The main thing here is using Drush to do stuff like clearing the cache (Even when disabling the page cache, there is still dozens of different caches involved, for example for hook implementations), installing/re-installing modules and so on.

And of course, APC should be installed, yes. You could even think about using http://drupal.org/project/apc to store parts of the cache in APC. This will however conflict with drush (you can't clear the APC cache by using drush) and will require additionaly RAM.
> 3 votes

# Answer
The best tip you can use (this really change my life) is adding a line in your `my.cnf` file:

```
innodb_flush_log_at_trx_commit = 0

```

You can find this file in your wamp folder or if your on linux server: `/etc/mysql/my.cnf`

Regards
> 5 votes

# Answer
Install and enable APC. As I tested in Drupal 7, this will make your local site faster.
> 3 votes

# Answer
I updated this Drupal Tutorial with some of the solutions I found:

*Speed up page loading time on localhost:* http://drupal.org/node/961012
> 1 votes

# Answer
Thought I'd post my experience which may help future readers. I struggled with for over 24 months with a really slow Drupal 7.3x stack on an Ubuntu 15.04 desktop (I just couldn't be bothered to with more pain and just carried on!). Today, I took a stab at installing MySQL Workbench 6.1 and it now flies by! Unbelievable!! I hope any future readers will consider this first as none the suggestions offered really solved my issues. The machine I use is a fair decent spec (16g RAM/dual core/2TB/Dual-head etc), so buying/getting 'another computer', I don't believe is the true answer. In all, if you are running Drupal on a desktop then try the above Workbench install first. To date, I've found I need to run Workbench in the background (or on another screen), still my whole Drupal experience has now improved immensely. Maybe I have just been luck today? Anyway, hope this helps future readers.
> 1 votes

# Answer
**IMPORTANT!!!** If you want to use this solution **do it with caution** and provide a constant that can flag the caching code on/off.

The solution I show here is not of settings or tuning of some settings, but do some change in the code of the core in order to make **Drupal 7** works much faster.

During development I noticed that many request, even the most simply ones has a latency of 5 seconds. This is frustrating, especially when you need to do lots of settings such as editing views.

At first I thought that the problem is related with general issue found by many developers when working with Apace on local host, but changing one solution after another didn't changed the slow behavior.

I decided to debug, and then step by step I narrowed down the code section where most of the delay (4 seconds) occur.

I an using with ECK module to create entities for business-logic. And I have quite few entities. The latency in my case was caused here:

**eck.module** :: **eck\_entity\_info** and especially in the foreach loop when collecting entity info from all hooks into one array:

```
  foreach (EntityType::loadAll() as $entity_type) {
    // eck__entity_info creates the entity_info for each entity type.
    $info = array_merge($info, eck__entity_type__info($entity_type));
  }

```

I took some measurements and noticed that there is no one single module that cause the delay but few modules create a compound time of 4 seconds added to each new request that use this **entity\_get\_info** function.

What I did is to create a caching file with serialized result of the foreach loop. The file is created once and deleted by the eck\_flush\_caches hook implementation. This solution eliminated the latency caused by this section in the code. Now a simple GET request that took 7 seconds has become 2.4 seconds.

I took this solution one step ahead and instead of caching only the result for eck\_entity\_info, I moved the caching to the top level when all entity info from all modules is collected in file: **common.inc**. Now the request time was reduced to 1.3 second!!! Using Drupal is fun again.

Note: I am not saying that this solution is good for all but in the case that you are using many entities and the settings for these entities are not dynamically change every request, you may want to consider this solution.

I am attaching two changes made in **common.inc** file:

```
function entity_get_info($entity_type = NULL) {
  global $language;

  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['entity_info'] = &drupal_static(__FUNCTION__);
  }
  $entity_info = &$drupal_static_fast['entity_info'];

  // hook_entity_info() includes translated strings, so each language is cached
  // separately.
  $langcode = $language->language;

  if (empty($entity_info)) {
    if ($cache = cache_get("entity_info:$langcode")) {
      $entity_info = $cache->data;
    }
    else {
       if (defined("CACHE_GET_ENTITY_INFO") && CACHE_GET_ENTITY_INFO && defined("CACHE_DIR")) {
          $cacheFile = CACHE_DIR . "/entity_get_info.phps";
          $cachedData = file_exists($cacheFile) ? file_get_contents($cacheFile) : false;
          if(! $cachedData) {
              $entity_info = module_invoke_all('entity_info');
              file_put_contents($cacheFile, serialize($entity_info));
          } else {
              $entity_info = unserialize($cachedData);
          }
      } else {
          $entity_info = module_invoke_all('entity_info');
      }

      // Merge in default values.
      foreach ($entity_info as $name => $data) {
        $entity_info[$name] += array(
          'fieldable' => FALSE,
          'controller class' => 'DrupalDefaultEntityController',
          'static cache' => TRUE,
          'field cache' => TRUE,
          'load hook' => $name . '_load',
          'bundles' => array(),
          'view modes' => array(),
          'entity keys' => array(),
          'translation' => array(),
        );
        $entity_info[$name]['entity keys'] += array(
          'revision' => '',
          'bundle' => '',
        );
        foreach ($entity_info[$name]['view modes'] as $view_mode => $view_mode_info) {
          $entity_info[$name]['view modes'][$view_mode] += array(
            'custom settings' => FALSE,
          );
        }
        // If no bundle key is provided, assume a single bundle, named after
        // the entity type.
        if (empty($entity_info[$name]['entity keys']['bundle']) && empty($entity_info[$name]['bundles'])) {
          $entity_info[$name]['bundles'] = array($name => array('label' => $entity_info[$name]['label']));
        }
        // Prepare entity schema fields SQL info for
        // DrupalEntityControllerInterface::buildQuery().
        if (isset($entity_info[$name]['base table'])) {
          $entity_info[$name]['base table field types'] = drupal_schema_field_types($entity_info[$name]['base table']);
          $entity_info[$name]['schema_fields_sql']['base table'] = drupal_schema_fields_sql($entity_info[$name]['base table']);
          if (isset($entity_info[$name]['revision table'])) {
            $entity_info[$name]['schema_fields_sql']['revision table'] = drupal_schema_fields_sql($entity_info[$name]['revision table']);
          }
        }
      }
      // Let other modules alter the entity info.
      drupal_alter('entity_info', $entity_info);
      cache_set("entity_info:$langcode", $entity_info);
    }
  }

  if (empty($entity_type)) {
    return $entity_info;
  }
  elseif (isset($entity_info[$entity_type])) {
    return $entity_info[$entity_type];
  }
}

```

The section of code where cache file is create is this:

```

if (defined("CACHE_GET_ENTITY_INFO") && CACHE_GET_ENTITY_INFO && defined("CACHE_DIR")) {
          $cacheFile = CACHE_DIR . "/entity_get_info.phps";
          $cachedData = file_exists($cacheFile) ? file_get_contents($cacheFile) : false;
          if(! $cachedData) {
              $entity_info = module_invoke_all('entity_info');
              file_put_contents($cacheFile, serialize($entity_info));
          } else {
              $entity_info = unserialize($cachedData);
          }
      } else {
          $entity_info = module_invoke_all('entity_info');
      }

```

The constant "**CACHE\_DIR**" is a constant that refer to cache directory in my solution. Make the adjustments for this as necessary.

Then the cleanup if the cache file:

```
function entity_info_cache_clear() {
  drupal_static_reset('entity_get_info');
  // Clear all languages.
  cache_clear_all('entity_info:', 'cache', TRUE);

  //Gilad: clearing the cached data of entity info
  if (defined("CACHE_GET_ENTITY_INFO") && CACHE_GET_ENTITY_INFO && defined("CACHE_DIR")) {
     $cacheFile = CACHE_DIR . "/entity_get_info.phps";
     if (file_exists(CACHE_DIR . "/entity_get_info.phps")) {
         unlink($cacheFile);
     }
  }
}

```

Thoughts for future... Taking this solution for the next level would be adding caching in the level of \**function module\_invoke\_all($hook) \**

One of the great features of Durpal is the flexibility provided by allowing hooks to extend the CMS logic. However the same feature may be a major cause for performance issue. Basically if you have an algorithm that build setting, but running this algorithm again and again for each request produces the same result, one may want to consider caching the result produced by algorithm and serve it from file.
Therefore adding an ability to cache the result produced by running hooks on many modules cab speed up business logic dramatically.

Here is a **conceptual** solution:

```
function module_invoke_all($hook) {
  $args = func_get_args();
  // Remove $hook from the arguments.
  unset($args[0]);
  $return = array();

  $doCaching = $is_hook_result_to_be_cached($hook);
  if($doCaching) {
      $cacheFile = CACHE_DIR . "/{$hook}_cache.phps";
      $cachedData = file_exists($cacheFile) ? file_get_contents($cacheFile) : false;
  }

  if( $cachedData) {
      return unserialize($cachedData);

}

  foreach (module_implements($hook) as $module) {
    $function = $module . '_' . $hook;
    if (function_exists($function)) {
      $result = call_user_func_array($function, $args);
      if (isset($result) && is_array($result)) {
        $return = array_merge_recursive($return, $result);
      }
      elseif (isset($result)) {
        $return[] = $result;
      }
    }
  }

  if($doCaching) {
     $cacheFile = CACHE_DIR . "/{$hook}_cache.phps";
     file_put_contents($cacheFile, serialize($entity_info));
  }

  return $return;
}

```

Of course the function **$is\_hook\_result\_to\_be\_cached($hook)** need to be created and defined, maybe involve some settings level in the admin section.

P.S. consider that all hosts are running today with electronic discs (and P.C uses SSD), therefore using file caching is a good and available solution. Of course other ways for caching can also be considered.
> 0 votes

---
Tags: 7
---


# Question
Title: how can I debug theme.theme file in my theme using phpstorm?
I want to set breakpoints in the `theme.theme` file and debug some variables but I cannot do that as this file isn't a `php` file. How can I debug this file?

# Answer
> 6 votes
1. Go to Preferences -\> Editor -\> File Types
2. Scroll down the *Recognized File Types* list until you find PHP; select it
3. In *Registered Patterns* add \*.theme
4. Save

You can now set breakpoints in \*.theme files.

# Answer
> 1 votes
Also make sure you are on the correct theme to trigger debugger.

A common mistake you could be doing:

Lets say you want to debug a hook\_form\_alter that is in the YOUR\_THEME.theme file, you did everything, but it doesn't break. What could be wrong? Make sure when you are visiting your form, you are using the YOUR\_THEME theme and not the administration theme which will load by default if you are an administrator and you may end up confused why debugger doesn't stop at your break line.

# Answer
> 0 votes
For me disabling cache helped as my preprocess mytheme\_preprocess\_paragraph() function was not triggered because of cache.

# Answer
> -1 votes
Actually you may want full drupal integration with phpstorm. Here you can read how to achieve this.

---
Tags: theming, debugging
---


# Question
Title: Form states API configuration first page load not working
I would like to show a text field when a checkbox is checked and a specific option is selected in a select list

The form works fine when there are no values in and the form is loaded but doesn't work if I pass in existing values when the form is rendered.

For example if the checkbox is checked and select list item 1 is selected when the form first loads then when I select list item 3 then the the textfield does not show. If I select another option and then select 3 again it does show.

```
 // Get value of field_price_list from current node.
$price_list = $node->get('field_fulfil_price_list')->getValue();
$price_list_enabled = FALSE;
$price_list_value = NULL;
if (!empty($price_list)) {
  $price_list_value = $price_list[0]['key'];
  $price_list_enabled = TRUE;
}

// Switch catalogue on or off.
$form['list_enabled'] = [
  '#type' => 'checkbox',
  '#title' => $this->t('Synchronise stock levels with Fulfil.io'),
  '#default_value' => $price_list_enabled,
];

// Select list with FF price lists.
$form['price_list'] = [
  '#type' => 'select',
  '#title' => $this->t('Select price list'),
  "#empty_value" => "",
  '#options' => [
    '1' => $this->t('Retail'),
    '2' => $this->t('Trade'),
    '3' => $this->t('Create new'),
  ],
  '#options_attributes' => [
    '2' => ['disabled' => 'disabled'],
  ],
  '#value' => $price_list_value,
  '#states' => [
    'visible' => [
      ':input[name="list_enabled"]' => ['checked' => TRUE],
    ],
  ],
];

// Label for new item if "Create new" is selected.
$form['new_price_list'] = [
  '#type' => 'textfield',
  '#title' => $this->t('New list name'),
  '#states' => [
    'visible' => [
      ':input[name="list_enabled"]' => ['checked' => TRUE],
      ':input[name="price_list"]' => ['value' => '3'],
    ],
  ],
];
$form = parent::buildForm($form, $form_state);

// Change submit label.
$form['actions']['submit']['#value'] = $this->t('Save');

return $form;

```

# Answer
> 0 votes
**Try to use condition in the field like this:**

```
$form['new_price_list'] = [
  '#type' => 'textfield',
  '#title' => $this->t('New list name'),
  '#states' => [
    'visible' => [
      ':input[name="price_list"]' => ['value' => '3'],
    ],
  ],
];

```

**Note:** It 'll cover with or without default value scenario, I removed the below additional condition : **':input\[name="list\_enabled"\]' =\> \['checked' =\> TRUE\],**

Analysis: As here you are using already hierarchy of condition like: select display only if checkbox field checked Textfield display only if value 3 selected from select box

But due to adding double condition in your code on textfield , Conditional form API logic not work as per expectation specially in case of if default value pass to checkbox

---
Tags: forms
---


# Question
Title: A complicated question about views, pls help~
May I ask how to achieve this requirement? There is a task content type, which has an applicant field, which is multi-valued (that is, a task allows multiple people to apply at the same time), which refers to the paragraph type applicant, and the paragraph type applicant has an applicant (referring to the user entity) field and an application status field, both of which are single values. It is expected that when the applicant requests a task, the task will disappear from the applicant's (currently logged in user) task list view, how to implement this.

# Answer
> 1 votes
The way it SHOULD work is to create a view to list Work items. Then add a contextual filter for the Applicants field. In that filter under "When the filter is not available" set to "Provide default" and select "User ID from logged in user".

As this is, this will give you ALL the Work items which the user is added to, but you want the opposite of this. Now scroll to the bottom of the filter settings and under More, select Exclude.

This should give you what you want, but on my test D9.5 site it does not work. I would suggest this is a core bug.

---
Tags: views
---


# Question
Title: Order is not geting created, but transition is happening in cart
I am doing an `Offsite redirection` payment with Drupal Commerce. I have a custom payment workflow defined in `my_module.workflow.yml` as follows:

```
order_linktypeplus_validation:
  id: order_linktypeplus_validation
  group: commerce_order
  label: 'linktypeplus order workflow'
  states:
    draft:
      label: Draft
    pending:
      label: Pending
    completed:
      label: Completed
    canceled:
      label: Canceled
  transitions:
    place:
      label: 'Place order'
      from: [draft]
      to: pending
    fulfill:
      label: 'Fulfill order'
      from: [draft, pending]
      to: completed
    cancel:
      label: 'Cancel order'
      from: [draft, pending]
      to: canceled

```

So as per this when the order is placed, First order will be moved to the `Pending` state (which is working fine). And for some orders, I need to get it completed without the pending state (ie. from draft to completed)

I was doing this in my controller after offsite payment had been successfully done and returned to the site:

```
 $order->unlock();
 $order->setData($paymentGateway, $data);
 if ($order->getState()->getId() != 'completed') {
      $order->getState()->applyTransitionById('fulfill');
  }
 $order->save();

```

When I checked in the cart tab next to orders, the item was still in the cart. but its status says `Order moved from Draft to Completed by the Fulfill order transition`. But the **order is not created**.

Any idea on how to resolve this issue?

# Answer
> But the order is not created.

What do you mean by that? The order in your screenshot has the completed state?
> 0 votes

---
Tags: commerce, 9
---


# Question
Title: How to move on to the next profile page in views after flagging a profile within the view?
I created a view that current user can use to search/view user profiles. The view lists user profiles and shows one at a time. A profile page can be either flagged “Like” or “Pass” (dating website style). I want the next profile to load after the current user flags the profile they are viewing.

# Answer
> 1 votes
You can add a is/is not flagged filter to the view. If you don't see this option, you need to add your flag as a relationship to the view to get the filter to appear.

So, if you have configured the view to only show unflagged users, then if you're using the AJAX flag widget, I'm pretty sure it will automatically refresh the view and jump to the next person.

If not, you will have to write code to get it to refresh after each flag action.

---
Tags: views, flags, 10
---


# Question
Title: Promotion options not visible to Editor role
I have a "Editor" Role with limited access rights. It can basically only create blog type nodes.

I'd like to expose to them the possibility to make to publish the node to the frontpage via the drupal core "publish to startpage" Promotion Option.

By which permission is this controlled? I tried all the node ones, but could not find it.

# Answer
> 0 votes
It turned out this is controled by the **administer content** permission. It has security implications, as it also exposes the ability to change the author and creation time of the node.

If you don't what that, you'd need to use the form\_alter hook to dissable the athor and creation time field for the **Editor** role.

For example:

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

  if (in_array('editor', Drupal::currentUser()->getRoles(), true)) {

    switch ($form_id) {
      case 'node_blog_edit_form':
      case 'node_blog_form':
         $form['author']['#access'] = false;
         break;
    }

  }
}

```

---
Tags: nodes, 9
---


# Question
Title: In Multisite setup the custom page '/speakers' should available on domain1 site only
I have Multi-site setup , want to make available custom page say '/speakers' on domain1 site but not on domain2 site

I have tried to figured out in routing.yml file to check is there way to pass any variable in route where I can define that route should available for specific domain only, even I tried with the alter routes approach as well but no luck.

**Note: Both sites has same custom module installed.**

# Answer
Just for record purpose, posting answer:

I used alter routes() approach in which used remove function w.r.t to domain condition:

```
  $collection->remove('route_name');

```

Created: module\_name.services.yml (root of custom module)

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

```

Created: RouteSubscriber.php (module\_name\src\Routing)

```
<?php
  namespace Drupal\module_name\Routing;
  use Drupal\Core\Routing\RouteSubscriberBase;
  use Symfony\Component\Routing\RouteCollection;

  class RouteSubscriber extends RouteSubscriberBase {

    protected function alterRoutes(RouteCollection $collection) {
      $domain = \Drupal::request()->getHost();
      // check domain
      if($domain == 'domain_name'){
        if ($collection->get('route_name')) {
          // remove route conditionally
          $collection->remove('route_name');
        }
      }
    }

  }

```

Info: I Choose this particular approach becoz I need to enabled same module for both sites

To get more info related to routes, visit to this documentation link on official site of DRUPAL
> 0 votes

---
Tags: routes, multi-sites
---


# Question
Title: Configuring dynamic PHPUnit environment variables
**Current State:**

I'm currently working on running PHPUnit Browser tests in Drupal, and I've successfully configured my phpunit.xml file with these environment variables:

```
<env name="SIMPLETEST_BASE_URL" value="https://site1.com"/>
<env name="SIMPLETEST_DB" value="mysql://db_sitte1:db_sitte1@db_sitte1"/>

```

These settings work well when I run my phpunit.

**Problem:**

Now, I'm working on a multisite project involving multiple sites (site1, site2, site3, site4), and I need to test the functionality on all four of these sites.

**Question:**

How can I dynamically change these two variables in my phpunit.xml file according to the testing code to accommodate a multisite project? like this:

```
<env name="SIMPLETEST_BASE_URL" value="{DYNAMIC_URL}"/>
<env name="SIMPLETEST_DB" value="{DYNAMIC_DB_CREDENTIALS}"/>

```

Or is there a way to alter this 2 varaible : **SIMPLETEST\_BASE\_URL** and **SIMPLETEST\_DB** insidethe setup() method ?

# Answer
1. Create a separate phpunit.xml file for each site.
2. Use phpunit's `--configuration` flag to specify a configuration file at runtime.
> 0 votes

---
Tags: multi-sites, testing
---


# Question
Title: How do I programmatically disable a filter from a text format?
Suppose I have a text format like `full_html` and I have an enabled filter with ID `my_filter_id`.

How can I disable the filter programmatically from `full_html`.

I needed to put this in an update hook.

Hopefully its a one-liner.

# Answer
I did find a solution thought it wasn't a one liner. This will remove the filter from all text formats.

```
use Drupal\filter\Entity\FilterFormat;

function MYMODULE_update_10000(&$sandbox) {
  $filters = filter_formats();
  foreach ($filters as $name => $filter) {

    /* @var $filter Drupal\filter\Entity\FilterFormat */
    // Instantiate the filter collection prior to removing the filters to
    // avoid fatal errors.
    $filter->filters();
    $filter->removeFilter('my_filter_id');
    $filter->save();
  }

}

```

I found the solution from Drupal.org
> 0 votes

---
Tags: input-formats, 10
---


title: Constantly creating new Anonymous users

text:
# Question
Title: Constantly creating new Anonymous users
I find that my instance of drupal is always "creating" new anonymous users.

I have an even on Create New User that simply logs the name to a file, and it is filled with entries like

```
2023-10-20T12:07:48-04:00,Anonymous <>,Drupal\nyc_custom_events\Event\UserCreateEvent,user created.
2023-10-20T12:07:49-04:00,Anonymous <>,Drupal\nyc_custom_events\Event\UserCreateEvent,user created.
2023-10-20T12:07:50-04:00,Anonymous <>,Drupal\nyc_custom_events\Event\UserCreateEvent,user created.
2023-10-20T12:07:50-04:00,Anonymous <>,Drupal\nyc_custom_events\Event\UserCreateEvent,user created.
2023-10-20T12:07:51-04:00,Anonymous <>,Drupal\nyc_custom_events\Event\UserCreateEvent,user created.

```

Thousands, as you can see one or two a second. The site is not even that heavily trafficked, though maybe it is robot traffic.

Is that normal?

The logging Event is simply fired during the function hook\_user\_create.

```
/**
 * Implements hook_user_login().
 * @see https://drupal.stackexchange.com/a/223380
 */
function nyc_custom_events_user_create(UserInterface $user) {
  $event = new UserCreateEvent($user);
  $event_dispatcher = \Drupal::service('event_dispatcher');
  $event_dispatcher->dispatch($event, UserCreateEvent::EVENT_NAME);
}

```

```
  /**
   * On user create.
   *  - log event
   *  - rebuild router
   *
   * @param \Drupal\Component\EventDispatcher\Event $event
   *   Generic event.
   */
  public function userCreate(UserCreateEvent $event) {
    $user = $event->user->getDisplayName().' <'.$event->user->getEmail().'>';
    $this->logger->write($user, get_class($event), 'user created.');
    // rebuild router so that user endpoints are created
    \Drupal::service('router.builder')->rebuild();
  }

```

# Answer
> 1 votes
You are misinterpreting the debugging results. This hook is for entity objects initialized in memory, for example, to render entity forms. A lot of entity forms rendered are never submitted. It's also quite common for other code to initialize entity objects and never intend to save them to the database.

You probably want to rebuild the router table when a new user is actually inserted into the database:

```
/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function mymodule_user_insert(UserInterface $entity) {
  \Drupal::service('router.builder')->setRebuildNeeded();
}

```

See https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21entity.api.php/group/entity\_crud/10

BTW I've also replaced the router rebuild method with a different method which delays the rebuild until the Drupal kernel is shut down. The rebuild process is very time-consuming and you don't want to have it in the middle of the request.

Or most times not at all when saving entities. You might want to reconsider your routing scheme not to depend on single entities. Like it is in Drupal out of the box.

---
Tags: users, hooks, event-subscribers
---


title: Configure new site automatically

text:
# Question
Title: Configure new site automatically
Is there a way for me to automate the form-filling steps on a brand new site's `/install.php`? I'm doing a bunch of experimenting where I set up a site inside a Docker container and try some stuff out, but filling out the installation forms dozens & dozens of times is getting pretty old.

My procedure for creating the Drupal site is:

```
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
composer create-project drupal-composer/drupal-project:7.x-dev my-drupal --no-interaction
cd my-drupal/web
cp sites/default/default.settings.php sites/default/settings.php && chmod 666 sites/default/settings.php
chmod 777 sites/default

```

and then I go to the web interface & start entering stuff.

# Answer
Drush site:install does exactly this.
> 3 votes

---
Tags: installation
---


# Question
Title: How to make the “last access time” field visible to anonymous users?
I have configured the user data display to show the last access information, but only me as I have the admin role can see it, anonymous users can not, nor even authenticated users: So my question is how can I make that information to be seen publicly.

To configure the user visualization I went to "/admin/config/people/accounts/display" and used the "Layout Builder"

Some place I have seen, although not sure, that the field displaying this info is `{{ access }}`

Following image is from an admin session:

And Following image is from a non-admin user (authenticated only)

# Answer
To make the *Last access time* field visible, you can use `hook_entity_field_access()`.

```
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResult;

function mymodule_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
  if ($field_definition->getName() == 'access' && $operation == 'view') {
    return AccessResult::Allowed();
  }

  return  AccessResult::neutral();
}

```
> 2 votes

---
Tags: users
---


# Question
Title: Inject a class as depency injection in a service
I just want to inject a custom module class A as a dependency injection for a custom service. I tried but I failed. Can any one please guide me. I'm using Drupal version 10.

Here is my code.

**moduleb.services.yml**

```
services:
  classb.brokeragency:
    class: Drupal\customb\Services\BrokerAgency
    arguments: [Twn\SoapClient\ClientBuilder]

```

**BrokerAgency.php**

```
<?php

namespace Drupal\customb\Services;

use \Twn\SoapClient\ClientBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;

class BrokerAgency implements BrokerAgencyInterface {

    protected ClientBuilder $clientBuilder;

    /**
     * @param ClientBuilder $client_builders
     *
     */
    public function __construct(ClientBuilder $client_builder)
    {
        $this->clientBuilder = $client_builder;
    }

    public static function create(ContainerInterface $container) {
        return new static(
          $client_builder
        );
    }
}

```

But this is giving following error.

Please help me to solve this issue. Thanks in advance.

PS - Does Drupal allow this ? If no, then is there any way to achieve. this.

# Answer
You need to create a service/ factory for `Twn\SoapClient\ClientBuilder` to create a new ClientBuilder object and use this service/ factory in your *services.yml*. To reference a service, you'll need to use the following notation.

```
services:
  classb.brokeragency:
    class: Drupal\customb\Services\BrokerAgency
    arguments: ['@my.client.builder']

```

See Services and dependency injection in Drupal 8+ for more examples and documentation.
> 3 votes

---
Tags: dependency-injection, symfony-services
---


# Question
Title: How to get the list of blocks for the current page?
I'm trying to get the list of all blocks for a certain page, but I can't figure how to do that.

How do I get the list of all the blocks that are rendered for a page, independently from the region where they are put?

# Answer
> 3 votes
To get all blocks in an array by region, you can do as follow

```
// Get the current theme used
$theme = \Drupal::theme()->getActiveTheme()->getName();

// And pass the theme name to get all the regions
$regions = system_region_list($theme, $show = REGIONS_ALL);

// This will give you all the regions in array format
$regions =  json_decode(json_encode(system_region_list(\Drupal::config('system.theme')->get('default'),$show = REGIONS_ALL)),true);

// Loop over each regions
foreach ($regions as $key => $region) {
  // Get the blocks in particular region
  $blocks[$key] = \Drupal::entityManager()
    ->getStorage('block')
    ->loadByProperties([
      'theme' =>  \Drupal::config('system.theme')->get('default'),
      'region'=> $key,
    ]);
}

```

# Answer
> 0 votes
This is a bit more concise and accomplishes the same thing:

```
\Drupal::service('block.repository')->getVisibleBlocksPerRegion()

```

---
Tags: 8, blocks
---


# Question
Title: How do I add a patch to patches in composer.json from the command line?
In https://drupal.stackexchange.com/a/297530/69441

> Third, add an "extras" section in composer with a patch:

How do I do this without an interactive editor?

# Answer
> 7 votes
```
composer config --merge --json extra.patches.drupal/tooltip_ckeditor '{"D10": "https://www.drupal.org/files/issues/2022-08-16/tooltip_ckeditor.4.0.1.rector.patch"}'

```

---
Tags: composer
---


# Question
Title: GET /sites/default/files/js/js_xxxxxx.js - No such file or directory
This is my first post, I just started to learn and use Drupal, and I wish to install a fresh new site on my local Windows machine using composer. The issue is that it has a file not found error from the path "/sites/default/files/js/js\_xxxx.js", I have searched through some forums and some of the users said that it is related to permission, but in my case, the file doesn't even exist in the directory. The problem now is, the site is able to start but when I enter the site, there is no style, all contents are displayed as plain text only. Have anyone faced this before? Thank you for helping!

I have also tried to reinstall it multiple times, but the issue remains. However, I am able to install and run it without a problem through XAMPP.

# Answer
I had the same problem with Drupal 10. You can try several things to check if this isn't what's causing the problem:

1. From the performance page ("admin/config/development/performance"), uncheck "Aggregate CSS files" and "Aggregate JavaScript files".
2. If it still doesn't work, check the permissions (chmod 777 -R of your sites/default/files folder to be sure, then give it back with the permission you want, as well as the user profile with ls -l).

UPDATE: The aggregation fix for people who have this problem with Drupal10 comes from a problem with Nginx (it solved that I had with aggregation)
> 0 votes

---
Tags: theming, files, installation
---


# Question
Title: Adding URL redirect showing path http instead of https in redirect
I have ssl enabled but Adding URL redirect showing path http instead of https in redirect. How we can changes http to https.

# Answer
> 1 votes
The prefix displayed in front of "Path" field is automatically generated according the current HTTP request with this code :

```
\Drupal::request()->getSchemeAndHttpHost()

```

If you try to access this page with "https" you will see "https" inside the field prefix : https://example.com/admin/config/search/redirect/add

The fact that you have "http" instead of "https" is therefore irrelevant, as the value stored is only the relative part of the URL. So whatever your environment (dev, preprod, prod) your redirection will always work.

---
Tags: 10
---


title: Stylesheets not loading

text:
# Question
Title: Stylesheets not loading
Has anyone successfully dealt with this kind of error? `[Error] Did not parse stylesheet at 'https://*****.***/core/assets/vendor/jquery.ui/themes/base/core.css?s2pf9q' because non CSS MIME types are not allowed in strict mode.` This shows up in the console. The site works fine with aggregation enabled, but none of the style sheets load when it is turned off. I get 56 errors like the one above. If I go directly to the URL mentioned in the error message, the css shows up.

This only happens on the production server, running Apache 2.4 on Ubuntu 20.04.6 LTS. The server is overprovisioned, and has plenty of resources. It works fine locally (ddev). This is a Drupal 9 site, with a theme based on ZURB Foundation 6 9.0.0-beta1. There are lots of references to this error on various support sites, but none of them are applicable to my situation.

# Answer
## Library declaration

First of all be sure to load your custom assets in the right way like describe in the Drupal documentation : Adding assets (CSS, JS) to a Drupal module via \*.libraries.yml

## Assets preprocessing

Fox fixing the problem you can try to disable the assets preprocessing from this page `/admin/config/development/performance` or with this commands and then clear cache :

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

```

## File permissions

Another reason to this error might be a file permission problem.

To be sure to have correct permissions you should run following commands (assuming you SSH user is `user`) :

```
cd /var/www/drupal/web
chown -R user:www-data .
find . -type d -exec chmod u=rwx,g=rx,o= '{}' \;
find . -type f -exec chmod u=rw,g=r,o= '{}' \;

cd /var/www/drupal/web/sites
find . -type d -name files -exec chmod ug=rwx,o= '{}' \;
find ./*/files -type d -exec chmod ug=rwx,o= '{}' \;
find ./*/files -type f -exec chmod ug=rw,o= '{}' \;

```

Go check the docs about that : Securing file permissions and ownership

## Apache configuration

Check Administrator -\> Configuration -\> Media -\> File System to personalize your tmp path (assuming `/tmp`). Make sure to use relative paths and have the right privileges for the Apache user (assuming `user`).

```
chown -R user:www-data /tmp
chmod 777 /tmp

```

In your Apache configuration be sure to disable `mod_userdir` and in your VirtualHost configuration or your HtAccess file set `AllowOverride All`.
> 0 votes

---
Tags: theming, 9
---


# Question
Title: How to hide a region in a node (most preferably without a module)?
I want to hide the sidebar region only in my homepage.

CSS `display:none` for the sidebar region is not enough because main content won't expand to cover the actual region so I think about using a Drupal PHP hook or some ugly PHP command, if there is either of these for that purpose.

How to hide a region in a node (most preferably without a module)?

# Answer
> 0 votes
You can use the default Drupal system of template hook that provide the possibility of overide any layout template according the current content type inside the template name.

For example if you want to overide the `page.html.twig` template for the front page you just have to create a new template file inside you front theme folder : `page--front.html.twig`

It's inside this template that you include the theme region so you can add only the regions you want inside it.

The default `page.html.twig` :

```
{{ page.header }}
{{ page.sidebar }}
{{ page.content }}
{{ page.footer }}

```

Your `page--front.html.twig` :

```
{{ page.header }}
{{ page.content }}
{{ page.footer }}

```

Be sure to clear your cache after with `drush cr` command.

---
Tags: theming, 10
---


# Question
Title: How can I get the human name from the machine name for an extension?
I want to get the human name from the machine name for an extension (i.e. a module or a theme).

I know that I can do this for a *module* by this call:

```
$human_name = \Drupal::service('extension.list.module')->getName('automated_cron');

```

This will return the human name for core **Automated Cron** module.

To do the same thing for a theme, I can invoke the service `'extension.list.theme'`.

Is there something that will provide this information and not care whether the extension is a module or a theme?

In my current implementation, I use this workaround:

```
$extension_name = 'automated_cron';
if (\Drupal::service('module_handler')->moduleExists($extension_name)) {
  $human_name = \Drupal::service('extension.list.module')->getName($extension_name);
}
else {
  $human_name = \Drupal::service('extension.list.theme')->getName($extension_name);
}
dpm($hunan_name, 'human name');

```

Is there a simpler way to get the desired result (i.e. without using an if-test)?

# Answer
Both extension.list.module and extension.list.theme services extends `ExtensionList` to get human name.

So you can replace your `if` statement by this one :

```
$name = 'automated_cron';
$extension = \Drupal::service('extension.list.module');
$human_name = ($extension->exists($name)) ? $extension->getName($name) : '';

```

Some useful sources :
> 0 votes

---
Tags: 10
---


title: Composer issues when trying to upgrade

text:
# Question
Title: Composer issues when trying to upgrade
I'm trying to upgrade from Drupal 9 to Drupal 10, and I'm running into errors from composer. Here's the command I'm using:

```
composer require drupal/core-composer-scaffold:10.1.5 drupal/core-recommended:10.1.5 -W

```

And here's the error I'm getting:

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

  Problem 1
    - Root composer.json requires drupal/core-recommended 10.1.5 -> satisfiable by drupal/core-recommended[10.1.5].
    - drupal/core-recommended 10.1.5 requires drupal/core 10.1.5 -> found drupal/core[10.1.5] but these were not loaded, likely because it conflicts with another require.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.
enter code here

```

And here's what `composer why-not drupal/core 10.1.5` says after I upgraded as many modules as I could:

```
drupal/core-recommended        9.5.11 requires         drupal/core (9.5.11)
drupal/csv_serialization       2.1.0  requires         drupal/core (^8 || ^9)
drupal/hook_event_dispatcher   3.3.4  requires         drupal/core (^9.3)
drupal/remove_http_headers     1.0.0  requires         drupal/core (^8.6||^9.0)

```

For those three modules, I've updated them in composer.json to look like this:

```
"drupal/csv_serialization": "^2.0 || ^3.0",
"drupal/hook_event_dispatcher": "^3.3 || ^4.0",
"drupal/remove_http_headers": "^1.0 || ^2.0",

```

Which in theory should allow those upgrades (which can't happen in D9) come along for the ride.

What else am I missing?

# Answer
To upgrade Drupal 9 to Drupal 10 be sure to follow the official guide and the Upgrading a Composer-based site procedure.

To avoid a chicken-and-egg problem with mutual dependencies use this command :

```
composer require 'drupal/core-recommended:^10' 'drupal/core-composer-scaffold:^10' 'drupal/core-project-message:^10' --update-with-dependencies --no-update

```

> Note that the `--no-update` option that is important here.

And then do the upgrade :

```
composer update

```

In case of rare ultimate bad luck where this is not working :

* Uninstall the modules that are causing problems
* Do the upgrade with composer
* Reinstall the modules in the Drupal 10 version compatible
> 1 votes

# Answer
I see that you have "drupal/core" in direct/indirect dependencies, 'drupal/core-recommended' is now default package for projects created from sometime, you need to remove "drupal/core", I also run into similar issue, manually deleting "drupal/core" from composer.json file and then running

```
composer require 'drupal/core-recommended:^10' 'drupal/core-composer-scaffold:^10' 'drupal/core-project-message:^10' --update-with-dependencies --no-update

```

solved the problem for me. You can check more details here drupal/core vs. drupal/core-recommended
> 0 votes

---
Tags: composer, 10
---


# Question
Title: Authentication required (git.drupalcode.org)
On Drupal 9, I want to install the Taxonomy menu module using Composer, but I get the following error.

> Using version ^3.4 for drupal/taxonomy\_menu
> ./composer.json has been updated
> Loading composer repositories with package information
> Updating dependencies (including require-dev)
> Package operations: 1 install, 0 updates, 0 removals
>
> * Installing drupal/taxonomy\_menu (dev-3.x e89d1e8): Authentication required (git.drupalcode.org): Username:

The command is waiting for a Git username/password, but two days ago the installation ran smoothly.

How can I ask for a stable version of the module?
On the project's page they write that, as of 21 May 2019, Taxonomy menu 8.x-3.x-dev is already fully compatible with Drupal 9.

This must be why `composer require` initially proposed 3.4 version and ultimately tried to install the *dev-3.x* version.

# Answer
> 1 votes
> How can I ask for a stable version of the module?

You can't install a stable version of Taxonomy Menu module for Drupal 9 at the moment because no such version exists.

If you look at the project page, you see the latest version is 3.4 which is marked **Requires Drupal: 8.x**.

>

So, if you want to use a stable version, you have to stay with Drupal 8 for now.

To use the dev version on Drupal 9, you can do this in `composer.json`:

```
    "drupal/taxonomy_menu": "3.x-dev",

```

Normally you should not need to authenticate to git. It's probably a proxy issue; you might find some hints in this discussion.

# Answer
> 0 votes
In a similar situation inside a lando (docker local developement environment) I was able to overcome this problem by getting a new `personal_access_tokens` from https://gitlab.com/-/profile/personal\_access\_tokens

and running

```
lando composer config -g gitlab-oauth.gitlab.com glpat-XXXXXXXXXXXXXXXXXXXXX

```

# Answer
> 0 votes
This issue also happens if the WSL clock is wrong. Run `date` to check. The WSL clock will become out of sync with Windows if you put your computer to sleep with Modern Standby, which is the default in Windows 11, I think.

There are some workarounds, such as restarting WSL, or running `sudo hwclock -s`

---
Tags: composer, 9
---


title: Add paragraph fields to a view

text:
# Question
Title: Add paragraph fields to a view
I have a content type "view" that has a paragraph attached to it, giving the ability to add a body, image, file, block, etc. I need to create a view for the blog listing that will show the title, thumbnail of image, and the summary for the body. But I guess it's been too long since I've done this, as I can't seem to figure out how to get the paragraph fields added to the view.

I've been searching like crazy, but oddly can't seem to find the answer. Lots on more complex stuff, but not just adding the field. I thought I did a relationship and then added the fields, but I just get an empty result.

We're on Drupal 9.5.11.

# Answer
Add paragraph field in view through relationship

1. You need to get paragraph reference(Paragraph referenced from 'field\_name'in content\_type) field that in content type in the relationship
2. After adding relation, when you try to add field it should start display the field that exist in the referenced paragraph
> 2 votes

---
Tags: views, paragraphs
---


# Question
Title: Email send not working after symfony_mailer upgrade
I'm trying to upgrade symfony\_mailer from 1.x to 4.x. The upgrade went smoothly and the test email button works, but the code we use to send emails is giving this error:

```
TypeError: Unsupported operand types: null + array in Drupal\symfony_mailer\Plugin\EmailBuilder\LegacyEmailBuilder->build() (line 107 of modules/contrib/symfony_mailer/src/Plugin/EmailBuilder/LegacyEmailBuilder.php)

```

Here's the relevant code snippet:

```
  $to = new Address($to, $toname, $language->getId());
  $from = new Address($from, $fromname, $language->getId());
  $htmlMessage = $payload->getMessage();
  $converter = new Html2Text($htmlMessage, ['do_links' => 'table']);
  $textMessage = $converter->getText();
  $result = $this->mailer2->newTypedEmail($module, $key)
    ->setTo($to)
    ->setFrom($from)
    ->setReplyTo($reply)
    ->setBody([
      '#markup' => $htmlMessage,
    ])
    ->setTextBody($textMessage)
    ->setSubject($payload->getSubject())
    ->send();

```

It seems I need to define "legacy\_message" somewhere, but adding a setParam('legacy\_message', $htmlMessage) doesn't work because setParam isn't valid at that "phase".

# Answer
Looks like I needed to change the code to this:

```
  $mail = $this->mailer2->newTypedEmail($module, $key, [
    'id' => $module,
    'send' => TRUE,
    'module' => $module,
    'key' => $key,
    'subject' => $payload->getSubject(),
    'body' => [Markup::create($htmlMessage)],
  ]);
  $to = new Address($to, $toname, $language->getId());
  $from = new Address($from, $fromname, $language->getId());
  $mail->setTo($to);
  $mail->setFrom($from);
  $mail->setReplyTo($reply);
  $mail->setTextBody($textMessage);
  $result = $mail->send();

```
> 0 votes

---
Tags: 10
---


# Question
Title: PDO::MYSQL_ATTR_USE_BUFFERED_QUERY error when using drush
This will be less about a question and more of a way to document things. I had been attempting to use drush (Drush 11 and 12) after installing a new copy of Drupal. It kept throwing Error: Undefined Constant PDO::MYSQL\_ATTR\_USE\_BUFFERED\_QUERY Yet the site worked fine. I checked php.net and Drupal Answers but to no avail. What did I need to do to get Drush working correctly?

# Answer
> 1 votes
The short answer is, always make sure the PHP you are using on your web server and the php-cli are the same version. My server was running 8.1 and the cli was running 8.2. Once I changed the cli to 8.1, drush worked like a charming do-it-all tool, it is meant to be.

---
Tags: drush
---


# Question
Title: Include html entities in dynamic menu links
I implemented a class *CopyrightMenuEntry* extending *MenuLinkDefault* which provides a custom menu entry (without link) with the current year and the site name.

```
class CopyrightMenuEntry extends MenuLinkDefault {
...
public function getTitle() {
  return "© " . $this->year . " " . $this->sitename;
}
publick function getRouteName() {
  return '<nolink>';
}

```

However, this renders as '**© 2023 Test**' instead of '**© 2023 Test**'. Can someone help how to include html entities in the title?

# Answer
~~I got one way to solve it:~~

~~```
return html_entity_decode('© ') . date('Y') . " " . \Drupal::config('system.site')->get('name');

```~~

~~see: https://api.drupal.org/api/drupal/core!lib!Drupal!Component!Utility!Html.php/function/Html%3A%3AdecodeEntities/8.2.x~~

Thanks @berliner for the hint at TranslatableMarkup:

```
public function getTitle() {
  return $this->t('© @year @sitename', [
    '@year' => date('Y');,
    '@ sitename' => \Drupal::config('system.site')->get('name')
  ]);
}

```

This seems like a better solution.
> 1 votes

---
Tags: navigation, 10
---


title: Check which database is used

text:
# Question
Title: Check which database is used
Is there a quick, easy, safe way to check what database a Drupal 8 install is using?

I'm trying to do a Drupal backup but when I look in phpmyadmin I see 5 different DBs listed on the left. I'd prefer to only backup the one I'm using because I've had issues before backing up and restoring the "under the hood" DBs like information\_schema.

I've searched a bit but none of the suggestions I've found seem to apply to Drupal 8. Everything I see like this, this, this, etc is from 5+ years ago and says to check the sites/default/setting.php for a `db_url` line, but I don't see that in that file for my site. Has the location of this info moved in Drupal 8?

FYI:

* I'm using Drupal 8.3.7 via Bitname WAMP
* I know there are some good backup modules - I've already backed everything up via the "Backup and Restore" module, but I'm paranoid and like to do a parallel manual backup in case something goes wrong with the module-based backup.

Thanks.

# Answer
> 8 votes
You can do it with `drush status`.

If you look for *Database name* line, you get that information.

You can also look in the Drupal settings file (*sites/default/settings.php*) and search for code similar to the following one.

```
$databases['default']['default'] = array(
  'database' => 'database_name',
);

```

# Answer
> 1 votes
Using the following code, you can get the connection information that is set in the *settings.php* file used by the site where the code is executed.

```
$connection = \Drupal::database();
$options = $connection->getConnectionOptions();
$database = $options['database'];
print $database . "\n";

```

# Answer
> 0 votes
You can go to /admin/reports/status and check there.

---
Tags: 8, database
---


# Question
Title: field_info_field() deprecated, what's the equivalent?
In Drupal 8, `field_info_field()` has been deprecated.

I tried using `\Drupal\field\Field::fieldInfo()->getField('field_address')` and `\Field::fieldInfo()->getField('field_address')`, but I get this error.

> Fatal error: Class 'Drupal\field\Field' not found in /var/www/drupal/modules/custom/foo/src/Controller/FooController.php

What am I missing?

# Answer
> 5 votes
According to the change record:

`field_info_field($entity_type, $field_name)` -\> `FieldStorageConfig::loadByName($entity_type, $field_name)`

So you should use `\Drupal\field\Entity\FieldStorageConfig::loadByName` from now on.

It's probably best to use change records and issues on Drupal.org itself for docs at the moment, rather than 3rd party websites - I think they have slightly more chance of being right and kept up to date when something changes.

# Answer
> 0 votes
Use this :

```
use Drupal\field\Entity\FieldStorageConfig;
$field = FieldStorageConfig::loadByName('node', $field_name);
$allowed_values = options_allowed_values($field);

```

# Answer
> 0 votes
For those looking for a D10 answer:

```
/** @var \Drupal\field\FieldStorageConfigInterface $field_config */
$field_config = \Drupal::entityTypeManager()
  ->getStorage('field_storage_config')
  ->load(implode('.', [$entity_type, $entity_bundle, $field]));

```

---
Tags: 8, entities
---


# Question
Title: How to add extra validate hook to the order information form?
I am trying to collect additional information on checkout to add to the order. I have added new fields to the order entity and then used hook\_form\_commerce\_checkout\_flow\_multistep\_default\_alter to add "fake" fields to the order\_information form. Then, using `hook_entity_presave()`, I take the values from the fake fields and set the real order fields. This all works as expected.

As some of these fake fields are conditionally required to be entered, I am trying to add a validate function. In the form alter I have added `$form['actions']['next']['#submit'][] = '_altpay_form_validate';` and for that function I have:

```
function _altpay_form_validate(&$form, $form_state) {
  $who_paying = $form_state->getValue('altpay');
  if (!$who_paying) {
    $form_state->setErrorByName('altpay', t('You must select who is paying for this order.'));
  }
}

```

Calling `setErrorByName()` crashes with the following exception.

> LogicException: Form errors cannot be set after form validation has finished.

I tried setting Validation Complete to `FALSE` and then `setErrorByName()` no longer crashes, but also does not prevent form submission.

I suspect this has something to do with the multi-step nature of this form.

Do you have any hint on what I am missing?

# Answer
> `$form['actions']['next']['#submit'][] = '_altpay_form_validate';`

You're actually adding it to the submit function. Which makes sense the errors that you're seeing since it's too late to do any form validation here.

Needs to be:

```
$form['actions']['next']['#validate'][] = '_altpay_form_validate';

```
> 1 votes

---
Tags: forms, commerce, 9
---


# Question
Title: How can I rebuild the cache for a specific route when a node of type foo is updated?
I created a page by a module and the cache of that page must be deleted if a node of node-type 'foo' is updated.

How do I do that?

I read https://www.drupal.org/docs/drupal-apis/cache-api/cache-tags

And tried:

mymodule.routing.yml

```
mymodule.foopage:
  path: '/myurl'
  defaults:
    _controller: '\Drupal\mymodule\MyClass::page'
    _title: 'Foo'
  options:
    _cache_tags:
      - 'node:foo'
  requirements:
    _permission: 'access content'

```

I tried also `_cache_tags` `node_list:foo`

But cache is not rebuild when I update a foo content.

`drupal_flush_all_caches` works fine, but it seems a bit to heavy.

# Answer
The cache tag `node_list:foo` is correct. But I've never seen that you can add it to a route like this. Normally the route controller returns the cache metadata in $build:

```
public function page() {
  // build $build
  $build['#cache']['tags'][] = 'node_list:foo';
  return $build;
}

```
> 3 votes

---
Tags: routes, caching, 10
---


# Question
Title: order of role and status on user edit page has changed with 9.5 upgrade
in our 9.3 drupal installation , on the user edit page, the role was before the status. now in 9.5 , the status is above the role. I would like the role to be on top of the status the way it was before and dont see that option in configuration. Can this be done?

# Answer
> 3 votes
Change order of status & role field of user:

```
function Mymodulename_form_alter(&$form, &$form_state, $form_id) {
  // user register & user edit form
  if($form_id == 'user_form' || $form_id == 'user_register_form'){
    // Alter the order of role & weight field
    $form['account']['roles']['#weight'] = 1;
    $form['account']['status']['#weight'] = 2;
  }
}

```

Note: The roles & status field inside the account array maintained for user entity, these variables can be alter using hook\_form\_alter()

---
Tags: users
---


# Question
Title: How to finally disable comments on content type?
I am trying to disable comments on webform. I tried all settings I could find, but:

* Link to comment form still appear
* Name field and submit button still appear on comment form

Could somebody give me any advice?

# Answer
> 11 votes
As juampy wrote, node\_revision should be updated as well. You need to execute 2 queries:

Step 1:

```
UPDATE node SET comment = 0 WHERE type = 'your_content_type'

```

Step 2:

```
UPDATE node_revision nrev
INNER JOIN node nd ON nrev.nid = nd.nid AND nd.type = 'your_content_type'
SET nrev.comment = 0

```

Step 3: Clear cache

# Answer
> 8 votes
Sometimes it's easiest to just use SQL. This, I think, is one of those cases.

```
UPDATE node SET comment = 0 WHERE type = 'nocommentsforthistype';

```

0 = disabled

1 = readonly

2 = read/write.

# Answer
> 7 votes
Changing the default comment settings for the content type, as suggested by uwe999 only changes the *default* settings for the content type. That means it won't retroactively change settings for existing content (as that could delete existing comments).

You will have to visit the node edit view for each existing node that you're trying to disable comments for and update the settings there. If you installed a module like the Node form columns module, which hides/removes elements from the node add/edit pages, then you will have to update its configuration the comment settings box appear for the nodes.

# Answer
> 3 votes
None of the above solutions worked for me. The comment form is still displayed in existing nodes unless you update node\_revision as well.

Here is the hook\_update\_N() implementation that worked for me:

```
/**
 * Implements hook_update_N().
 *
 * Disables comments in existing event nodes.
 */
function hook_update_7000(&$sandbox) {
  $content_type = 'event';

  // Update node table.
  db_update('node')
    ->fields(array('comment' => 1))
    ->condition('type', $content_type)
   ->execute();

  // Update node_revision table.
  $nids = db_select('node', 'n')
    ->fields('n', array('nid'))
    ->condition('type', $content_type)
    ->execute()
    ->fetchCol();
  db_update('node_revision')
    ->fields(array('comment' => 1))
    ->condition('nid', $nids)
    ->execute();
}

```

# Answer
> 2 votes
you disable comments in "structure / content types / \[name of type\] / edit / comment settings. Set "Default comment setting for new content" to hidden.

If you have existing comments you can delete them under "content /comments" or just unpublish them.

# Answer
> 1 votes
I'm not sure about your issue, but one dirty trick could be to create a special template for your content type and remove the comment parts.

# Answer
> 1 votes
Disable comments here first:

```
structure->content types->{node_type}->edit->comment settings

```

To update the nodes, unfortunately, you have to re-save each node. Use hook\_update below:

```
/**
 * Disable comments on node_type
 */
function hook_update_N(&$sandbox) {
  $content_type = 'node_type';

  // Initialize batch.
  if (!isset($sandbox['total'])) {
    $query = db_select('node');
    $query->addExpression('COUNT(*)');
    $query->condition('type', $content_type);

    $sandbox['total'] = $query->execute()->fetchField();
    $sandbox['progress'] = 0;

    if (empty($sandbox['total'])) {
      $sandbox['#finished'] = 1;
      return t('No %type nodes exist in database.', array('%type' => $content_type));
    }
  }

  // Get and update nodes.
  $nids = db_select('node')
    ->fields('node', array('nid'))
    ->condition('type', $content_type)
    ->range(0, 10)
    ->execute()
    ->fetchCol();

  if (!empty($nids)) {
    $nodes = node_load_multiple($nids, NULL, TRUE);

    foreach ($nodes as $node) {
      $node->comment = 1; // I set comments as 1 where value of 2 enables the comments.
      node_save($node);   // Re-save the node.
    }
  }

  // Increment & check progress.
  $sandbox['progress'] += count($nids);
  if (empty($nids) || $sandbox['progress'] >= $sandbox['total']) {
    $sandbox['#finished'] = 1;
    return t('Updated @count nodes.', array('@count' => $sandbox['progress']));
  }
  else {
    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['total'];
  }
}

```

Do not forget to replace **'node\_type'** to your node type.

# Answer
> 1 votes
The simplest way to **disable comments** in the **webform** is to simply go to **EDIT webform** and in the bottom of EDIT option there is an option of **Comments Settings**.

By **default its always OPEN** so make it **closed** and the **comment section** from the webform will **disappear**...

# Answer
> 1 votes
You could use CSS to hide the comments section so that retrospective comments don't show.

Add CSS code to the Admin \> Appearance \> Advanced \> Custom CSS tab. You would have to look at the class names of the divs for your specific site's page types. Here's an example from my test site which uses the News item page type (machine name "article"):

```
.node-article .comment-wrapper{
 visibility: hidden;
 display: none;
 }

```

# Answer
> 0 votes
Use Views Bulk Operations, with the default operation: "Modify / Change Entity Values". Here you can set commenting to closed to existing nodes.

# Answer
> 0 votes
It's pretty straight forward, follow below steps:

1. Navigate to Structure \> Content Types \> Webform
2. Then Edit the webform and Click on Comment Settings in left hand side settings.
3. Change the "Default comment setting for new content" value to 'Close' and save the setting.

Thanks

# Answer
> 0 votes
I had this happen to about 50,000 records I imported into 4 different content types. I didn't want to erase and reimport or mess around with SQL queries in the database. If you want to remove commenting functionality from all nodes, just disable the comments module.

# Answer
> 0 votes
To disable comments in Drupal X you need to remove the field from the entity type.

---
Tags: 7, webforms, comments
---


# Question
Title: Remove "read more" when there is no more text to read
I have just set up a new website with Drupal 8. I created a new content with a regular HTML that contains basic text. I promoted it to homepage, I see a "read more" link. But there is no "more" to read.

How can I remove "Read more" link if there is no more content to read?

I found some modules for Drupal 7 but I am following a certain solution for this general problem.

And also I am curious; isn't it obvious that there shouldn't be a "read more" link when there is no more content? Is it a bug or something?

# Answer
Neither of the other answers actually addresses the question, which is how to turn off "read more" **selectively** depending on whether there is more to read or not.

The standard read more link, as the comments in NodeViewBuilder say, is always displayed on a teaser by default because there is no (easy) way to know how the teaser content differs from the full view. Your content type might have several other text fields apart from the body which are only shown on the full page view.

However, it should be possible to implement a custom "read more" link that has the behaviour you seem to be asking for. I don't think anyone has implemented one yet, but the most fruitful approach would be a modest extension of the "summary or trimmed" field formatter, although you could probably also do something in a preprocess hook in your theme.

**Edit**: A demonstration module is up on github now. It's not perfect and I would like to refactor it and possibly make it more general-purpose but it works for the simplest case.
> 2 votes

# Answer
Well, in Drupal 8 it is quite simple to remove "Read more" link for some content type. In this example I took "Article" type.

Just navigate to "Structure" \> "Content types" in "OPERATIONS" column select "Manage display" for type you need to hide "Read more" link. Note which dispay type you are editing (Default, RSS, Teaser)...

So your URL will look like: `/admin/structure/types/manage/article/display/teaser` and from there drag "Links" row to "Disabled" area.

Clear cache. Done.
> 1 votes

# Answer
To remove the 'Read more' on Drupal 8 click on the following:-

Strucure, Views, Frontpage - edit, change 'Teaser' on dropdown to 'Default'.

Click 'save' = Job done :)

Please note there is no 'Read more module' in Drupal 8 as yet. Drupal 7 has one.
> 0 votes

# Answer
In Drupal X there is now a readmore flag in the node.html.twig template e.g.

```
 * - readmore: Flag for more state. Will be true if the teaser content of the
 *   node cannot hold the main body content.

```

It still appears to be output by default for the teaser as Alfred Armstrong mentioned. e.g.

```
/**
   * Build the default links (Read more) for a node.
   *
   * @param \Drupal\node\NodeInterface $entity
   *   The node object.
   * @param string $view_mode
   *   A view mode identifier.
   *
   * @return array
   *   An array that can be processed by drupal_pre_render_links().
   */
  protected static function buildLinks(NodeInterface $entity, $view_mode) {
    $links = [];

    // Always display a read more link on teasers because we have no way
    // to know when a teaser view is different than a full view.
    if ($view_mode == 'teaser') {
      $node_title_stripped = strip_tags($entity->label());
      $links['node-readmore'] = [
        'title' => t('Read more<span class="visually-hidden"> about @title</span>', [
          '@title' => $node_title_stripped,
        ]),
        'url' => $entity->toUrl(),
        'language' => $entity->language(),
        'attributes' => [
          'rel' => 'tag',
          'title' => $node_title_stripped,
        ],
      ];
    }

    return [
      '#theme' => 'links__node__node',
      '#links' => $links,
      '#attributes' => ['class' => ['links', 'inline']],
    ];
  }

```

Appears to be output as part of {{ content }}
> 0 votes

---
Tags: 8
---


title: Why doesn't my completion message show?

text:
# Question
Title: Why doesn't my completion message show?
I have this form to handle a custom content entity:  created by this code:

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

    Some code to inialize here...

    $wrapper = 'formWrapper';
    $form['#prefix'] = '<div id="' . $wrapper . '">';
    $form['#suffix'] = '</div>';

    $form['designation'] = [
      '#type' => 'select',
      '#options' => $aMembers,
      '#title' => $this->t('Member'),
      '#required' => TRUE,
      '#empty_option' => t('- Select member -'),
      '#default_value' => $memberId,
      '#ajax' => [
        'callback' => '::memberCallback',
        'wrapper' => 'theSubscription',
      ],
    ];

    $form['theSubscription'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'theSubscription'],
      '#quantities' => $iNumberOfQuantities,
    ];

        $value = $subscription['quantity01'];
    $form['theSubscription']['quantity01'] = [
            '#type' => 'number',
            '#title' => 'quantity01',
            '#min' => 0.00,
            '#max' => 99.95,
            '#step' => 0.05,
            '#value' => $value,
      ];
    }

    $sharedwith_id = $subscription['sharedwith_member_id'];
    $form['theSubscription']['sharedwith'] = [
      '#type' => 'select',
      '#title' => t('Shared with'),
      '#options' => $aMembersforsharing,
      '#value' => $sharedwith_id,
    ];

    $form['theSubscription']['comment'] = [
      '#type' => 'textarea',
      '#title' => t('Comment'),
      '#rows' => 1,
      '#value' => $subscription['comment'],
    ];

    $fileId = (int) $subscription['file__target_id'];
    $form['theSubscription'][$fileId] = [
      '#type' => 'managed_file',
      '#description' => $this->t('Limited to @size MB.', ['@size' => $upload_max_inMB]) . '<br>' . $this->t('Allowed types: pdf.'),
      '#upload_location' => 'private://contracts/subscriptions/',
      '#upload_validators' => [
        'file_validate_extensions' => ['pdf'],
        'file_validate_size' => [$upload_max],
      ],
      '#default_value' => [$fileId],
    ];

    if ($sContractIsOpenForSubscription) {
      $form['save'] = [
        '#type' => 'submit',
        '#name' => 'save',
        '#value' => $this->t('Save'),
      ];
    }

    $form['leave'] = [
      '#type' => 'button',
      '#name' => 'leave',
      '#value' => $this->t('Leave'),
      '#ajax' => [
        'callback' => '::leaveCallback',
      ],
      '#limit_validation_errors' => [],
    ];

    $form['#attached']['library'][] = 'amap/amap';

    return $form;
  }

```

There are two buttons: 'save' of type 'submit' and 'leave' of type 'button' with an Ajax calback.
Everything works fine: 'leave' quits the form properly and 'save' actually saves data content entity as expected before presenting the empty form for another possible update.
Except for that piece of code which doesn't work (it is executed just after entity update):

```
\Drupal::messenger()->addMessage($this->t('The changes have been saved for « %designation ».', ['%designation' => $form["designation"]["#options"][$result["designation"]]]));

```

By the way, I also tried this:

```
$response = new AjaxResponse();
$response->addCommand(new MessageCommand($this->t('The changes have been saved for « %designation ».', ['%designation' => $form["designation"]["#options"][$result["designation"]]])));
return $response;

```

without success.

What is wrong with this code?

\[Update\] code executed by the two buttons: leave (Quitter):

```
  public function leaveCallback($form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new \Drupal\Core\Ajax\RedirectCommand(Url::fromRoute('amap.contracts')
      ->toString()));
    return $response;
  }

```

save (Enregistrer): function submitForm(a

```
rray &$form, FormStateInterface $form_state) {

    if ($form_state->getTriggeringElement()['#name'] == 'save') {
      some code to prepare entity update...
      if ($hash != $result['hash']) { <-- Is there aniting to do?
        Code to update content entity...
        _export_amap_CSV('amap_contracts_subscriptions', 'rest_export_1', $contract); <-- Export content entity as CSV file
        \Drupal::messenger()->addMessage($this->t('The changes have been saved for « %designation ».', ['%designation' => $form["designation"]["#options"][$result["designation"]]]));
      }
    }
    else {
      $form_state->setRebuild();
    }
  }

```

# Answer
> 0 votes
It appears that it was some javascript in my library (`$form['#attached']['library'][] = 'amap/amap';`) which was interfering with sending the message...

---
Tags: forms, ajax, 9
---


# Question
Title: Should I migrate my site from Drupal 7 directly to Drupal 10, or via Drupal 9?
I have been working through some upgrade issues with a site migration from Drupal 7 to Drupal 10. In my tests I have been running migrations from Drupal 7 to Drupal 9. I wondered if there is any likely advantage in migrating content to Drupal 9 and then upgrading to 10, or if I should just go straight from 7 to 10 with the migration process?

# Answer
> 1 votes
In my case, due to incompatibilities with Field Collections and Drupal 10, I was not able to migrate directly from Drupal 7 to Drupal 10. I had success however in migrating to Drupal 9 and converting Field Collections to Paragraphs in the process. I anticipate the next step of updating to Drupal 10 from Drupal 9 will be relatively straightforward by comparison.

# Answer
> 1 votes
Drupal 9 loses all support in 11 days. It is not a safe target for any development activities at this time.

---
Tags: migrations, upgrading
---


# Question
Title: How do I find the max length of a field (e.g. title field)
I would like to retrieve the maximum length of a field programmatically, for instance the `$node->title` field .

I am writing a module that sets title and I don't really want to hard-code '255'. I am using Drupal 7.

# Answer
> 2 votes
The Drupal schema API has a function named drupal\_get\_schema (D7) or drupal\_get\_module\_schema (D8) that lets you inspect a schema programatically and retrieve field constraints.

For instance, to get the maxlength of the `title` field in the `{node}` table, you can use the following in D7:

```
$schema = drupal_get_schema('node');
$maxlength = $schema['fields']['title']['length'];

```

You can also inspect the max length of any field used by Drupal simply by looking at the database schema that defines that field. This will also tell you the names you need to use in the above PHP to get the right value in cases where you're unfamiliar with the schema.

For instance, if you are talking about the `title` field in the `{node}` table, you can see when looking at a scheme in a database inspection tool such *phpMyAdmin* that it is a `varchar` with a maximum length of 255 characters.

# Answer
> 0 votes
```
/**
 * Implements hook_form_alter().
 */
function custom_module_form_alter(&$form, FormStateInterface $form_state,
$form_id): void {
  if ($form['#form_id'] == 'node_event_form') {
    // Limit charset for the Event content type and add the description.
    $form['title']['widget'][0]['value']['#maxlength'] = 100;
    $form['title']['widget'][0]['value']['#description'] = t('The title is limited to 100 characters maximum.');
  }
}

```

---
Tags: entities, database
---


# Question
Title: How to get the Drupal webform submission changed value?
I'm trying to get the webform submission changed data when a form submission is updated in date format to be captured into a custom field. I'm able to get the webform completed value in a custom submission handler as below, `$custom_date = $webform_submission->getData();` `$completed_date = $webform_submission->completed->value;`

Also the below does not print the date format with am/pm. strtotime(date('DD/MM/Y g:i:s'))

How do I get the webform submission changed value in date format with am/pm?

# Answer
> 1 votes
To get webform submission data and manipulate it before the save you can use a `presave` hook. Hooks must be declared inside a `.module` file at the root of a custom module.

Here's an example for your use case :

```
<?php

use Drupal\webform\WebformSubmissionInterface;

/**
 * Implements hook_ENTITY_TYPE_presave() for webform_submission.
 */
function my_module_webform_submission_presave(WebformSubmissionInterface $webform_submission) {
  if ($webform_submission->getWebform()->id() != 'my_webform') {
    return;
  }
  // Webform data.
  $data = $webform_submission->getData();
  // Webform date field value is a string in Y-m-d H:i:s format.
  $value = $data['datetime'];
  // Feel free to transform it in any format you want.
  $datetime = new DateTime($value);
  // Like AM/PM as you need :
  $am_pm = $datetime->format('Y-m-d  H:i A');// 2023-10-27 07:29 AM
  // And then save it in your custom field.
  $data['custom_field'] = $am_pm;
  // And set the current Webform with new data.
  $webform_submission->setData($data);
}

```

> Note that, to manipulate Webform data it's recommended to use a **Webform handler**. You can find a lot of resources on the World Wide Web explaining that : How to create a drupal webform handler ?

---
Tags: hooks, webforms
---


# Question
Title: Is the libmysqlclient version core requirement actually required?
So it's been a while since I was doing things with Drupal. For a number of reasons, I decided to put my toe back in the water and install Drupal 10 on my hosting service. All went well, or I thought it did. The status report post-install showed this.

> 10.5.20-MariaDB-cll-lve-log
> The libmysqlclient driver version 3.1.21 is less than the minimum required version. Upgrade to libmysqlclient version 5.5.3 or up, or alternatively switch mysql drivers to MySQLnd version 5.0.9 or up.

Of course, I contacted my hosting service. Their reply was, essentially, that can't be upgraded on a Shared Service and I have to go to a VPS or Dedicated Hosting. They linked me to their installed software list for shared servers.

How much critical is the error in the status report?

* Litespeed: 6.0.12
* Codeguard: included to all Shared plans
* cPanel: 102
* cURL: 7.19.7
* CXS: installed on all Shared servers
* Git: enabled
* HTTP/2: supported
* Imagick module: 3.7.0
* IonCube PHP Loader: 12.0.2
* Mod\_Rewrite: enabled
* Mod\_Security: enabled
* MariaDB: 10.5
* Node.js: 6.17, 8.17, 9.11, 10.24, 11.15, 12.22, 14.20
* Mysqli Support: enabled
* Perl: 5.10.1
* PHP: 5.6, 7.0-7.4, 8.0, 8.1
* PostgreSQL: 8.4.20
* Python: 2.7, 3.3 - 3.9
* Rails: 2.3.18
* Ruby: 1.8 - 2.7
* ZendGuard Loader: 4.1

# Answer
> 4 votes
The issue was resolved and the error cleared by changing the PHP library from libmysqlclient to MySQLnd - that is, enabling nd\_pdo\_mysql instead of pdo\_mysql.

# Answer
> 0 votes
Tried changing the library to nd\_dpo\_mysql in CPanel as suggested, and got an error until I cleared all caches, including the LSCache for LiteSpeed. Perhaps obvious for some, but for those like me that do site maintenance infrequently, a useful reminder.

---
Tags: 10
---