# Question
Title: How to enable IMCE in a field of a custom block
I have module that generates a plugin block with a field of type managed\_file.

```
public function blockForm($form, FormStateInterface $form_state){
    $config = $this->getConfiguration();
    // todo make this IMCE
    $form['background'] = array(
      '#type' => 'managed_file',
      '#title' => $this->t('Background'),
      '#description' => $this->t('Enter background image'),
      '#default_value' => isset($config['background'])?$config['background']:'',
      '#upload_location' => 'public://backgrounds',
      '#weight' => '2',
    );
}

```

I guess I have to create a `module.schema.yml` file to do that but I don't know how to enable the IMCE.

```
block.settings.stingray_basic_block:
  type: block_settings
  label: 'Stingray basic block'
  mapping:
    body:
      type: text
      label: 'Body'
      translatable: true
    background:
      type: managed_file
      labe: 'Background'
      ??? MAKE IT IMCE ???

```

Usually this boolean appears in the `core.entity_form_display...yml` file as a third party settings structure:

```
content:
  field_background:
    weight: 1
    settings:
      preview_image_style: thumbnail
      progress_indicator: throbber
    third_party_settings:
      imce:
        enabled: true
    type: image_image

```

...but I don't know if it can be set in the `schema.yml` file nor how.

Anyone has info on this?

ref: https://www.drupal.org/node/2821710

# Answer
You can provide an alternative URL input(type=text) for IMCE integration.

You just need to include drupal.imce.input library and set the input class name as "imce-url-input". Also see imce.input.js file

```
if (\Drupal::moduleHandler()->moduleExists('imce') && \Drupal\imce\Imce::access()) {
  $form['background'] = array(
    '#type' => 'textfield',
    '#title' => $this->t('Background URL'),
    '#attached' => array('library' => array('imce/drupal.imce.input')),
    '#attributes' => array('class' => array('imce-url-input')),
    '#default_value' => isset($this->configuration['background']) ? $this->configuration['background'] : '',
  );
}

```
> 1 votes

# Answer
Most solutions i've found suggest adding a textfield which means you then have to get the FID from the URI in order to update the file field manually which is much too fussy.

To add the IMCE file browser to an existing managed file field in a custom form, adding the following to the element works for me in Drupal 10:

```
$form['existing_managed_file_field']['#process'][] = ['Drupal\imce\ImceFileField', 'processWidget'];
$form['existing_managed_file_field']['#file_value_callbacks'][] = ['Drupal\imce\ImceFileField', 'setWidgetValue'];
$form['existing_managed_file_field']['#scheme'] = 'public';

```
> 0 votes

---
Tags: blocks, files, plugins, 8
---


# Question
Title: Hook for hiding menu links based on user access
I have a Drupal 7 module that `uses hook_preprocess_menu_link()` to hide menu links based on user access. I am in the process of migrating to Drupal 9, and it seems that `hook_preprocess_menu_link()` might not be available or suitable in Drupal 9.

```
/**
 * Implements hook_preprocess_menu_link().
 */
function my_menu_access_preprocess_menu_link(&$vars) {
  global $user;
  $vars_href = $vars['element']['#href'];

  // get facilities the user is associated with.
  $user_facilities = user_facilities($user);

  // hidden class is added to hide the menu link from user.
  if (strpos($vars_href, 'some-menu-path') !== false) {
    $resource_facility_nid = get_facility_nid_from_resource_path($vars_href);
    if (!in_array('administrator', $user->roles) &&
      !in_array($resource_facility_nid, $user_facilities)) {
      $vars['element']['#attributes']['class'] = array('hidden');
    }
  }

  if (strpos($vars_href, 'other-menu-path') !== false) {
    $outage_facility_nid = get_facility_nid_from_outage_path($vars_href);
    if (!in_array('administrator', $user->roles) &&
      !in_array($outage_facility_nid, $user_facilities)) {
      $vars['element']['#attributes']['class'] = array('hidden');
    }
  }
}

```

# Answer
I prefer controlling this behavior via access to the entity rather than at the menu level because it means that anyone with a direct link to the entity won't have access AND if a user does not have access to a page (via Drupal permissions / access) then the menu link will be hidden by default (it won't be rendered at all, rather than simply hidden via JS or CSS).

One way that you could do this is via hook\_ENTITY\_TYPE\_access() and a custom permission. I would define my own permission, something like `view own facilities` or something similar. (See How do you create a custom permission to administer a custom module?.)

Assuming I've defined my custom permission as `view own facilities` (and a bonus `view all facilities` permission for administrators) and configured roles appropriately, I could define my access hook something like:

```
function mymodule_ENTITY_TYPE_access(EntityInterface $entity, string $operation, AccountInterface $account) {
  if ($entity->bundle() == 'facility' && $operation === 'view') {
    if ($account->hasPermission('view all facilities')) {
      return AccessResult::allowed()
        ->cachePerPermissions();
    }

    // The operation we care about, and the user has the permission we care
    // about, so we now just need to check if they should have access to the
    // particular facility. Whether they do or not, any results at this level
    // should be cached per user since each user can reference different
    // facilities.
    if ($account->hasPermission('view own facilities')) {
      // user_has_facility is a custom function you should write that takes a
      // user ID and a facility ID and returns TRUE if the user references, i.e.
      // has access to, the particular facility.
      if (user_has_facility($account->id(), $entity->id())) {
        // Here we allow access because the user has the correct permission AND
        // they have access to this specific facility.
        return AccessResult::allowed()
          ->cachePerPermissions()
          ->cachePerUser();
      }
      else {
        // The user has the correct permission, but is missing access to this
        // specific facility. We return neutral so some other mechanism could
        // grant access if that other mechanism deems appropriate.
        return AccessResult::neutral()
          ->cachePerPermissions()
          ->cachePerUser();
      }
    }
    // The operation we care about, but the user does not have the permission we
    // care about, so return neutral (so some other mecahnism could grant access
    // if the other mechanism deems appropriate), but since this decision is based
    // on a permission, make sure we cache the result per permissions.
    else {
      return AccessResult::neutral()
        ->cachePerPermissions();
    }
  }

  // No opinion: some other operation we're not interacting with.
  return AccessResult::neutral();
}

```
> 1 votes

---
Tags: hooks, 9, navigation
---


title: How do I access the login page?

text:
# Question
Title: How do I access the login page?
I am using the Drupal UI to make changes to a site, and I want to update the page that a user sees when they are not logged in. Is that a view I need to create?

# Answer
> 0 votes
If the purpose is allowing visitors to log in from any page they could visit, it is sufficient to show the login block on every page.

There is no need to create a view for that. It is sufficient to visit /admin/structure/block, choose in which region the login block should be shown, and click on the *Place block* button for that region. In my case, I will place it on the *Sidebar* region.

>

After I clicked on that button, I look for *User login* on the list of blocks, and click on the *Place block* button to its right.

>

Then, on the dialog box that appears, I click on *Save block*.

>

Anonymous users will now see the login block on any page they visit; logged-in users will not see the login block.

>

>

---
Tags: views
---


# Question
Title: Commerce Paypal Order for Goods and Services
I'm helping a non-profit set up an order page on their website that would allow users to order physical products. I have commerce integrated with their paypal account and I can successfully collect order information with a webform and process their payment with paypal.

The client, however, wants to be able to print a shipping label for that order directly from paypal. As far as I can tell, the only way the "Buy Shipping Label" option appears on paypal transactions is if the order's payment type is marked as "Goods and Services."

Is there a way to specify the payment type within the commerce module? The payments that I'm collecting now all show up in paypal with "Checkout" as the payment type.

The modules I'm using for this setup include, webform\_product (3.0.4), commerce\_paypal (8.x-1.4), and commerce (8.x-2.36) along with its related modules (cart, checkout, number pattern, order, payment, price, product, and store).

# Answer
> 0 votes
For anyone else who runs into this issue, I found a few lines in the commerce\_paypal module code that reference the shipping module. Apparently, the presence of this module affects how a payment is sent to paypal. The code is in: `commerce_paypal/src/Plugin/Commerce/PaymentGateway/ExpressCheckout.php` starting on line 509.

After enabling this module, all the payments I sent to paypal were marked as goods and services and I was able to print a shipping label directly from paypal. I don't ~think~ I did any other configuration to make this happen althought I was testing with the checkout flow the module added titled "shipping" but I didn't end up using that flow. Regardless, hope this helps someone.

---
Tags: commerce, webforms
---


# Question
Title: mkdir permission denied error when running Browser based test
I've wrote a browser based test for the contributed module, code can be seen here, when I run test in terminal I get following error

```
./vendor/bin/phpunit   --configuration /home/sharique/Projects/drupal/d8/d8contrib/core/phpunit.xml --filter "/::testReadOnlyModeEnabled( .*)?$/" Drupal\Tests\readonlymode\Functional\ReadOnlyModeTest /home/sharique/Projects/drupal/d8/d8contrib/modules/porting/readonlymode/tests/src/Functional/ReadonlymodeTest.php -v
PHPUnit 4.8.36 by Sebastian Bergmann and contributors.

Runtime:        PHP 7.1.10 with Xdebug 2.5.5
Configuration:  /home/sharique/Projects/drupal/d8/d8contrib/core/phpunit.xml

Testing Drupal\Tests\readonlymode\Functional\ReadOnlyModeTest
E

Time: 2 minutes, Memory: 6.00MB

There was 1 error:

1) Drupal\Tests\readonlymode\Functional\ReadOnlyModeTest::testReadOnlyModeEnabled
Exception: User warning: mkdir(): Permission Denied
Drupal\Component\PhpStorage\FileStorage->createDirectory()() (Line: 173)

/home/sharique/Projects/drupal/d8/d8contrib/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php:44
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/Promise.php:203
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/Promise.php:156
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/TaskQueue.php:47
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/Promise.php:246
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/Promise.php:223
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/Promise.php:267
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/Promise.php:225
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/promises/src/Promise.php:62
/home/sharique/Projects/drupal/d8/d8contrib/vendor/guzzlehttp/guzzle/src/Client.php:131
/home/sharique/Projects/drupal/d8/d8contrib/vendor/fabpot/goutte/Goutte/Client.php:155
/home/sharique/Projects/drupal/d8/d8contrib/vendor/symfony/browser-kit/Client.php:315
/home/sharique/Projects/drupal/d8/d8contrib/vendor/behat/mink-browserkit-driver/src/BrowserKitDriver.php:144
/home/sharique/Projects/drupal/d8/d8contrib/vendor/behat/mink/src/Session.php:148
/home/sharique/Projects/drupal/d8/d8contrib/core/tests/Drupal/Tests/BrowserTestBase.php:333
/home/sharique/Projects/drupal/d8/d8contrib/core/tests/Drupal/Tests/BrowserTestBase.php:472

FAILURES!
Tests: 1, Assertions: 1, Errors: 1.

```

Same error when running from PhpStorm

# Answer
> 6 votes
Maybe the *Permission problems* section of Running PHPUnit tests can help you:

> Note: functional tests have to be invoked with a user in the same group as the web server user. You can either configure Apache (or nginx) to run as your own system user or run tests as a privileged user instead.
>
> To develop locally, a straightforward - but also less secure - approach is to run tests as your own system user. To achieve that, change the default Apache user to run as your system user. Typically, you'd need to modify `/etc/apache2/envvars` on Linux or `/etc/apache2/httpd.conf` on Mac.
>
> Example for Linux:

```
export APACHE_RUN_USER=<your-user>
export APACHE_RUN_GROUP=<your-group>

```

> If the default user is e.g. `www-data`, the above functional tests will have to be invoked with `sudo` instead:

```
export SIMPLETEST_DB='mysql://root@localhost/dev_d8'
export SIMPLETEST_BASE_URL='http://d8.dev'
sudo -u www-data -E ./vendor/bin/phpunit -c core --testsuite functional
sudo -u www-data -E ./vendor/bin/phpunit -c core --testsuite functional-javascript

```

# Answer
> 0 votes
The other answer didn't help me. I had the simpletests folder with `777` permissions. I ran the tests as `root`, or as `www-data`. It didn't matter. The only fix that worked for me was found at the end of `core/tests/README.md`:

> If you have permission problems accessing files after running tests, try putting
>
> ```
> $settings['file_chmod_directory'] = 02775;
>
> ```
>
> in your settings.php or local.settings.php file.

That fixed it for me, finally. Then, for example, I can run

```
/var/www/html$ ./vendor/bin/phpunit -c core/phpunit.xml core/path/to/test/some/file.php

```

Since it's for running tests in a local development environment set up inside a Docker image, the most important thing is getting it all to run successfully, and this is what got it to work for me.

---
Tags: 8, testing
---


title: Migration of content with an UI

text:
# Question
Title: Migration of content with an UI
My goal is to import data of customers from a csv file to my custom entity. For that I wrote a migration with the migrate\_source\_csv module as source plugin. This works fine, but the problem is, that the import is just possible with drush. But it should work with an UI where a user can upload a file and run the import.

Is there any way to execute the import without drush?

# Answer
The Wordpress Migrate module is a great example of how to implement a UI to upload a file and create a migration for it. Once you have that, it shouldn't be too difficult to run the actual migration via code.

Create Migration configuration from information and file provided to your Wizard Form. Then the following should work.

```
$migration = Migration::create($configuration);
$executable = new MigrateExecutable($migration, new MigrateMessage());
$executable->import();

```
> 0 votes

# Answer
The Migrate Source UI module might also be useful for this purpose.

It offers: "User interface for importing data from JSON, CSV or XML sources. Work with migrate tools and other migrate modules to allow someone to upload the source file."
> 0 votes

---
Tags: 8, drush, migrations, importing-exporting
---


title: Migrate taxonomy with depth

text:
# Question
Title: Migrate taxonomy with depth
I need to migrate a CSV file of 3000 Taxonomy terms with depth of 5 levels deep. This is a small sample of the CSV comma-separated values file.

```
About Us
About Us, Our Programs
About Us, Our History, Timeline
Mission
Mission, Community

```

I want these values to be inserted into a Vocabulary, It should have the depth and it should ignore parent terms it has already created. It should look just like this in Drupal

```
About Us
-Our Programs
-Our History
--Timeline
Mission
-Community

```

I created a simple migrate yml file that can do this but I had to restructure the CSV file a lot and it is too much manual work. Can regex or something search for the comma delimiter and make the term after a comma a child of the term in front of it? And can it skip or ignore parent terms it already created? Here is my migration and csv file.

```
id: vocab
label: Migrate terms from the source CSV to taxonomy terms
migration_group: migrated_terms
source:
   plugin: csv
   path: 'public://csv/vocab.csv'
   header_row_count: 1
   keys:
      - uuid
   column_names:
     0:
       uuid: UUID
     1:
       vid: VID
     2:
       name: NAME
     3:
       parent: PARENT
destination:
   plugin: entity:taxonomy_term
process:
   vid: vid
   name: name
   parent:
      plugin: migration
      migration: vocab
      source: parent

```

csv file

```
"uuid","vid","name","parent"
"100","myvocab","About Us"
"101","myvocab","Our Programs","100"
"102","myvocab","Our History","100"
"103","myvocab","Mission"
"104","myvocab","Community","103"

```

# Answer
> 0 votes
Have a look at the example in web/core/modules/taxonomy/migrations/d7\_taxonomy\_term.yml

It sets a term parent\_id by looking it up in the same migration:

```
  parent_id:
    -
      plugin: skip_on_empty
      method: process
      source: parent
    -
      plugin: migration_lookup
      migration: d7_taxonomy_term
  parent:
    plugin: default_value
    default_value: 0
    source: '@parent_id'

```

For your case you only need to change the migration name:

```
    plugin: migration_lookup
    migration: vocab

```

You can use the Migrate Devel module to inspect the migrations while working on them.

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


# Question
Title: What is the calling method of validateForm callback of a FormInterface subclass
i just want to know where in the drupal code the validateForm method is called from the FormBuilder.

In the doValidateForm of FormValidator class i don't see the callback being called !

Can you give me some hints?

# Answer
It's not called directly. When preparing a form build array the FormBuilder adds it as #validate callback

*FormBuilder::prepareForm()*

```
$form['#validate'][] = '::validateForm';
$form['#submit'][] = '::submitForm';

```

which is then executed later like any other validate or submit callback.
> 2 votes

---
Tags: forms
---


title: Migrating 2 fields into a link field

text:
# Question
Title: Migrating 2 fields into a link field
I'm looking to migrate two fields on D7 (one a link field, the other a text field) into a single link field on D10.

The meat of the migration is here:

```
source:
  plugin: d7_paragraphs_item
  bundle: BUNDLE
process:
  d10_link_field:
    plugin: field_link
    source: d7_link_field
  d10_link_field/title: d7_title_field/value

```

This is resulting in a title of NULL in the d10\_link\_field.

Any pointers would be greatly appreciated.

# Answer
Custom process is the answer (as it usually is):

Migration:

```
source:
  plugin: d7_paragraphs_item
  bundle: BUNDLE
process:
  d10_link_field:
    plugin: field_link_custom
    source: d7_link_field
    title_source: d7_title_field

```

And the plugin:

```
<?php

namespace Drupal\MODULE_migrate\Plugin\migrate\process;

use Drupal\link\Plugin\migrate\process\FieldLink;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;

/**
 * Extension of the field_link plugin to handle multiple source fields.
 *
 * Add to the process section of the migration YML:
 *
 * @code
 * field_destination:
 *   plugin: field_link_custom
 *   source: field_source
 *   title_source: field_title_source
 * @endcode
 *
 * @MigrateProcessPlugin(
 *   id = "field_link_custom",
 *   handle_multiples = TRUE
 * )
 */
class FieldLinkCustom extends FieldLink {

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    $route = parent::transform($value[0], $migrate_executable, $row, $destination_property);
    $route['title'] = $row->getSourceProperty($this->configuration['title_source'])[0]['value'];
    return $route;
  }

}

```
> 0 votes

# Answer
You should be able to do something like this, without any custom process plugin:

```
process:
  'd10_link_field/uri': d7_link_field/0/url
  'd10_link_field/title': d7_title_field/0/value

```

Most custom D7 fields are multivalue by default, so you need the **/0/** to access its first value. D7 Link and Text fields have a different structure so you need to check whether the value is in a **value** or **url** subfield.

You can use the Migrate Devel module to inspect the migrations while working on them.
> 0 votes

---
Tags: migrations, 10
---


# Question
Title: Can we migrate and keep the same user, taxonomy, and node IDs?
When we are migrating a Drupal 7 site to Drupal 10, we have some custom tables which store taxonomy, node, user, and role IDs.

Is their a way to migrate a content type preserving the IDs?

# Answer
> 0 votes
The default is to migrate and keep the same ID. Look at web/core/modules/node/migrations/d7\_node.yml, and you can see the `nid: tnid` line.

```
id: d7_node
label: Nodes
audit: true
migration_tags:
  - Drupal 7
  - Content
deriver: Drupal\node\Plugin\migrate\D7NodeDeriver
source:
  plugin: d7_node
process:
  # If you are using this file to build a custom migration consider removing
  # the nid and vid fields to allow incremental migrations.
  # In D7, nodes always have a tnid, but it's zero for untranslated nodes.
  # We normalize it to equal the nid in that case.
  # @see \Drupal\node\Plugin\migrate\source\d7\Node::prepareRow().
  nid: tnid
  vid: vid
  langcode:
    plugin: default_value
    source: language
    default_value: "und"
  title: title
  uid: node_uid
  status: status
  created: created
  changed: changed
  promote: promote
  sticky: sticky
  revision_uid: revision_uid
  revision_log: log
  revision_timestamp: timestamp
destination:
  plugin: entity:node
migration_dependencies:
  required:
    - d7_user
    - d7_node_type
  optional:
    - d7_field_instance
    - d7_comment_field_instance

```

You can also look at d7\_user.yml, d7\_taxonomy\_term.yml, and d7\_user\_role.yml.

If you do end up needing to customize them, create a custom module, copy the YAML file into my\_module/config/install/d7\_node.yml and modify it.

# Answer
> 0 votes
As others have already said: yes you can keep this. And it is the default if you use the core migration templates. It is even mentioned in the inline documentation there.

The examples for user and taxonomy term migrations are a bit cleare than the ones for nodes.

See for example in the core user migration template web/core/modules/user/migrations/d7\_user.yml :

```
process:
  # If you are using this file to build a custom migration consider removing
  # the uid field to allow incremental migrations.
  uid: uid

```

And the taxonomy example in web/core/modules/taxonomy/migrations/d7\_taxonomy\_term.yml :

```
process:
  # If you are using this file to build a custom migration consider removing
  # the tid field to allow incremental migrations.
  tid: tid

```

---
Tags: migrations, 10
---


# Question
Title: How to replace the search submit button with a Font Awesome character?
I would like to replace the search submit button with a *Font Awesome* character like the *Magnifier (Search Icon)* character, and put *Search the site* inside the search box.

How can I achieve something like this?

>

# Answer
> 12 votes
In order to add the new form button, I used hook\_form\_FORM\_ID\_alter in my template.theme file in my theme folder (Notice:replace ThemeName with the name of your theme in below code):

**ThemeName.theme:**

```
**
 * Replace the Search Submit Button with a Font Awesome Character.
 */
function ThemeName_form_search_block_form_alter(&$form, &$form_state) {
  $form['keys']['#attributes']['placeholder'][] = t('Search');
  $form['actions']['submit']['#value'] = html_entity_decode('');
  $form['actions']['submit']['#attributes']['class'][] = 'search-button';
}

```

Remeber use `html_entity_decode()` to parse the Unicode code.
and CSS:

```
.search-button input[type="submit"]{
    font-family: FontAwesome;
    color: #fff !important;
    display: inline;
    font-size: 18px;
}

```

# Answer
> 6 votes
1. To convert the label to a placeholder text, you need to use `hook_form_alter` in your custom theme in Drupal. The form id for the search box is `seach_block_form`, so you can use the following code to do this:

```
/**
 * Implements hook_form_alter().
 */
function hook_form_search_block_form_alter(&$form, &$form_state) {
  $form['keys']['#attributes']['placeholder'][] = t('Search');
}

```
2. To change the look and feel of the search button, you can simply use CSS. What I usually do is to set the background to an the icon and use text-indent to hide the text.

# Answer
> 4 votes
I've done the following in a preprocess function to add font-awesome icons. It's a bit difficult with the search input because the only thing that identifies the search button is the label. Then hide the element with the selector `.button--text` in CSS.

```
function MYTHEME_preprocess_input(&$variables) {
  $element = &$variables['element'];
  // Ugh :(
  if ($element['#type'] === 'submit' && $element['#value']->__toString() === 'Search') {
    $variables['children'] = $element['#children'];
    $variables['children'][] = [
      '#theme' => 'html_tag',
      '#tag' => 'i',
      '#attributes' => ['class' => ['fa', 'fa-search']],
    ];
  }
}

```

# Answer
> 1 votes
**Instructions for Drupal 8 / FontAwesome 5**

Create a YOUR\_THEME\_NAME\_HERE.THEME file and place it in your themes directory (ie. your\_site\_name/themes/your\_theme\_name)

Paste this into the file, it is PHP code to find the Search Block and change the value to the UNICODE for the FontAwesome icon. You can find other characters at this link https://fontawesome.com/cheatsheet.

```
<?php
function YOUR_THEME_NAME_HERE_form_search_block_form_alter(&$form, &$form_state) {
  $form['keys']['#attributes']['placeholder'][] = t('Search');
  $form['actions']['submit']['#value'] = html_entity_decode('');
}
?>

```

Open the CSS file of your theme (ie. your\_site\_name/themes/your\_theme\_name/css/styles.css) and then paste this in which will change all input submit text to FontAwesome. Not sure if this will work if you also want to add text in the input button though for just an icon it is fine.

Make sure you import FontAwesome, add this at the top of the CSS file

```
@import url('https://use.fontawesome.com/releases/v5.0.9/css/all.css');

```

then add this in the CSS

```
input#edit-submit {
    font-family: 'Font Awesome\ 5 Free';
    background-color: transparent;
    border: 0;
}

```

**FLUSH ALL CACHES AND IT SHOULD WORK FINE**

***Add Google Font Effects***

If you are using Google Web Fonts as well you can add also add effects to the icon (see more here https://developers.google.com/fonts/docs/getting\_started#enabling\_font\_effects\_beta). You need to import a Google Web Font including the effect(s) you would like to use first in the CSS so it will be

```
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,800&effect=3d-float');
@import url('https://use.fontawesome.com/releases/v5.0.9/css/all.css');

```

Then go back to your .THEME file and add the class for the 3D Float Effect so the code will now add a class to the input. There are different effects available. So just choose the effect you like, change the CSS for the font import and the change the value FONT-EFFECT-3D-FLOAT int the code below to font-effect-WHATEVER\_EFFECT\_HERE. Not effects are still in Beta and don't work in all browsers so read here before you try it https://developers.google.com/fonts/docs/getting\_started#enabling\_font\_effects\_beta

```
<?php
function YOUR_THEME_NAME_HERE_form_search_block_form_alter(&$form, &$form_state) {
  $form['keys']['#attributes']['placeholder'][] = t('Search');
  $form['actions']['submit']['#value'] = html_entity_decode('');
  $form['actions']['submit']['#attributes']['class'][] = 'font-effect-3d-float';
}
?>

```

# Answer
> 1 votes
For **Drupal 8 / FontAwesome 5** (other similar solutions above did not work)

If you have the fontawesome module already installed you can add to your `THEMENAME.theme` file

```
use Drupal\Component\Render\FormattableMarkup;

function THEMENAME_form_search_block_form_alter(&$form, &$form_state) {
    $form['keys']['#attributes']['placeholder'][] = t('Search');
    $value = new FormattableMarkup('<i class="fas fa-search"></i>@text', ['@text' => '',]);
    $form['actions']['submit']['#value'] = $value;
}

```

# Answer
> 0 votes
Changes must be made in the yourtheme.theme file in your yourtheme directory. The following changes the submit button text.

```
function yourtheme_form_search_block_form_alter(&$form, &$form_state) {
  $form['actions']['submit']['#value'] = t('Zoeken');
}

```

# Answer
> 0 votes
If you use boostrap subtheme and drupal you can remove glyphicon in settings theme for all buttons BUT you can remove glyphicon for specific button with this hook in your TEMPLATE.theme https://drupal-bootstrap.org/api/bootstrap/bootstrap.api.php/function/hook\_bootstrap\_iconize\_text\_alter/7

```
function YOURTEMPLATENAME_bootstrap_iconize_text_alter(array &$texts) {
  // use ksm($form) OR other dump($form) functions
  if($texts['contains']['YOURTEXT']) {
    unset($texts['contains']['YOURTEXT']);
  }
}

```

if you want to show the title of the button, you must copy the file bootstrap/src/Plugin/Form/SearchForm.php into your SUBTHEME

YOURSUBTHEME/src/Plugin/Form/SearchForm.php copy and paste the content of the file into your file and edit the content like that :

```
<?php
...
use Drupal\bootstrap\Plugin\Form\FormBase;
...

  public function alterFormElement(Element $form, FormStateInterface $form_state, $form_id = NULL) {
    $form->advanced->setProperty('collapsible', TRUE);
    $form->advanced->setProperty('collapsed', TRUE);
    $form->basic->removeClass('container-inline');
    $form->basic->submit->setProperty('icon_only', FALSE);
    $form->basic->keys->setProperty('input_group_button', TRUE);
  }
}

```

with this you will see the text "search" only and no glyphicon on your search button

don't forget to flush the cache !

# Answer
> 0 votes
You can do it inside a twig template `YOURTHEME/templates/input/input--button.html.twig`

Add this above the lines where `<button>` is rendered:

```
{# replace Glyphicon with FontAwesome for Search #}
{% if icon and icon['#attributes']['class']|join matches '/search/' %}
  {% set icon = {
    '#type': 'html_tag',
    '#tag': 'i',
    '#attributes': {
      'class': [
        'fa', 'fa-search'
      ],
      'aria-hidden': 'true'
    },
  } %}
{% endif %}

```

It will replace the default `icon` object, adding an `<i>` tag with FontAwesome CSS classes.

You can check the `icon` object defaults using `dump`:

```
{{ dump(icon) }}

```

---
Tags: 8, search, forms
---


# Question
Title: How can I have multiple module configs depending on environment?
I have a Drupal site that I build locally and pull to the staging and production servers using git. Normally, my workflow is to run `drush cex` to export the configs from local, and `drush deploy` to deploy my changes on the staging and production servers.

So far, my module config has been the same across all environments and this has been working great, however I am now using the SAML Auth module which will not have the same configuration in the staging and production environment. For example, the entity id, key, and cert change, as well as a few other minor details. The problem is when I run `drush cex` locally, the local config is later deployed to staging & production, overwriting this module.

Is there a way to tell Drush to ignore this module when exporting and importing configs, or to maintain separate configs for certain modules depending on which environment the site is on?

# Answer
If these are only minor details you can do this without additional modules by overriding config values in settings.php directly.

This example changes the number of items displayed on the front page if, hypothetically, locally it should be different than in production:

Local settings.php:

```
$config['views.view.frontpage']['display']['default']['display_options']['pager']['options']['items_per_page'] = 10;

```

You can override almost any config value you see in the exported config. The overrides don't get deployed. In this example, you still see the original value when editing the View and you can save a different value for deployment. The same would be the case for the contrib module you've mentioned. You manage the production config in UI and override the local auth parameters in settings.php.
> 4 votes

# Answer
The Configuration Split module was created for exactly the scenario you describe:

> This module allows to define sets of configuration that will get exported to separate directories when exporting, and get merged together when importing. It is possible to define in settings.php which of these sets should be active and considered for the export and import.

All you need to do is set up the relevant splits, then add code to settings.php which enables/disables those splits in the appropriate environments.
> 3 votes

---
Tags: drush, configuration
---


title: Import a single yml configuration file

text:
# Question
Title: Import a single yml configuration file
Is it possible to import one single configuration file by specifying its path, or a group of Yaml files contained in a specific module?

# Answer
You can use

```
$ drush cim --partial --source=only-few-configs/

```

Your help says:

```
$ drush cim --help
Import config from a config directory.

Examples:
 drush config-import --partial             Import configuration; do not remove missing configuration.

Arguments:
 label                                     A config directory label (i.e. a key in $config_directories array in
                                           settings.php). Defaults to 'sync'

Options:
 --partial                                 Allows for partial config imports from the source directory. Only updates and new
                                           configs will be processed with this flag (missing configs will not be deleted).
 --preview=<list>                          Format for displaying proposed changes. Recognized values: list, diff. Defaults
                                           to list.
 --source                                  An arbitrary directory that holds the configuration files. An alternative to
                                           label argument

Aliases: cim

```
> 32 votes

# Answer
You can import one configuration by running the following command:

```
 drupal config:import:single

```

If you are trying to run multiple import you can create a chain for that.

Command Documentation - config:import:single
> 22 votes

# Answer
In case you don't have Drush or Drupal console installed, please use the following steps (executed successfully in D 8.0.1):

1. Go to Administration-\>Configuration-\>Configuration Synchronization. Configuration can be exported for a single item or for entire site. I did for a single user.mail.yml file. Export the required configuration.
    2. Modify the changes to the exported configuration.
    3. Import the modified configuration
    4. Once import is successful, ensure that you clear the existing data from config and cache\_config tables(Extract a dump of the database and search for the configuration keywords. That way you will know the tables where the entry is present.)

Note - Always take a backup.
> 4 votes

# Answer
Even though this was asked 7 years ago, it came up first in a google search for "import config item via drush", so here's yet another way to solve the problem. This will allow you to import a config item using Drush for a config item that is not in the filesystem.

In Acquia environments, the command `drush config:set (cset)` can be used to import an entire config yml file if you first create a temporary yaml file in the /tmp directory.

1. Create a tmp file at /tmp/tempfile.yml and paste in the contents of the config item. (In this example it is a search\_api server config that does not exist in the filesystem, but needed to be present to get past a race condition error during the config import.) The /tmp directory is writable in Acquia servers, so this is a way to import config that is different from the current code deployment.
2. This command imports the config from the file: `cat /tmp/tempfile.yml | drush cset -y --input-format=yaml search_api.server.acquia_search_server ? -`

The `search_api.server.acquia_search_server` is the name of the config. The `-` indicates that the values should be read from the piped input, and the `?` specifies that multiple individual settings/keys are present in the piped contents.

To answer the question exactly, one could also specify the path to the config file in the config directory instead of the /tmp directory, in order to import just one config item (if the file already exists in the config directory). Ex: `cat /var/www/html/config/default/search_api.server.acquia_search_server.yml | drush cset -y --input-format=yaml search_api.server.acquia_search_server ? -`
> 0 votes

# Answer
You could run `drush config-edit [config-file-without-yml-extension]`, and then replace the contents with what you have in the file. Seems to work well enough for development.
> 0 votes

---
Tags: 8, configuration
---


# Question
Title: Url-aliases or redirect without language prefix
How can I use url-aliases in additional languages without the language prefix?

From his old homebrew-CMS, my client has the following URLs:

* example.com/english-page =\> redirecting to example.com/en/node/1
* example.com/deutsche-seite =\> redirecting to example.com/de/node/1

I use Drupal 9.5.9, Redirect 8.x-1.8 and Pathauto 8.x-1.11. Default Language is German (de)

node 1 in German has url-alias '/deutsche-seite'
node 1 in its English Translation has url-alias '/english-page'

Opening the Site with the following URLs leads to different Results:

* example.com/en/english-page =\> OK, opens in english
* example.com/de/deutsche-seite =\> OK, opens in german
* example.com/deutsche-seite =\> OK. Redirects to /de/deutsche-seite which opens in german.
* example.com/english-page =\> Not OK, throws a 404.

How can I achieve that example.com/english-page redirects to example.com/en/english-page or renders the english translation of node 1? I did not find any settings on pathauto or languages, and if I try to create an Redirect manually, the redirect-module does not allow me to enter a path without language prefix (https://www.drupal.org/project/redirect/issues/3208013)

Thanks a lot for any hint... Kind regards, mullzk

# Answer
> 0 votes
Two ways to solve problem 1sy is patch for 9.x, 10.x branch. Dont working for me, but you can try link: https://www.drupal.org/project/drupal/issues/2689459

Second is lang neutral aliases module. It works for me ok https://www.drupal.org/project/language\_neutral\_aliases

---
Tags: i18n-l10n, path-aliases, redirection
---


title: How to override REST error message

text:
# Question
Title: How to override REST error message
After installing "RESTful Web Services" module, if I execute this API request:

```
curl --request GET \
  --url 'http://localhost/resourceNotFound?_format=json'

```

I got following error (which is expected):

```
{
    "message": "No route found for \"GET http:\/\/localhost\/resourceNotFound\""
}

```

Let's say I would like to change that error to:

```
{
  "code": 60,
  "message": "Resource not found",
  "description": "The requested URI or the requested resource does not exist."
}

```

How to do that?

# Answer
> 3 votes
You don't want to override the exception messages when they are thrown in routing or elsewhere. Better use an exception handler to catch all JSON 404 exceptions:

*/src/EventSubscriber/MymoduleExceptionSubscriber.php*

```
<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Cache\CacheableJsonResponse;
use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;

class MymoduleExceptionSubscriber extends HttpExceptionSubscriberBase {

  protected static function getPriority() {
    // handle the exceptions we want for JSON before
    // core subscribers do this with priority -70/-75
    return -69;
  }

  protected function getHandledFormats() {
    return ['json'];
  }

  public function on404(ExceptionEvent $event) {
    /** @var \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $exception */
    $exception = $event->getThrowable();

    $content = [
      'code' => 60,
      'message' => 'Resource not found',
      'description' => 'The requested URI or the requested resource does not exist.',
    ];

    // If the exception is cacheable, generate a cacheable response.
    if ($exception instanceof CacheableDependencyInterface) {
      $response = new CacheableJsonResponse($content, 404, $exception->getHeaders());
      $response->addCacheableDependency($exception);
    }
    else {
      $response = new JsonResponse($content, 404, $exception->getHeaders());
    }

    $event->setResponse($response);
  }

}

```

*mymodule.services.yml*

```
services:
  mymodule.404_subscriber:
    class: Drupal\mymodule\EventSubscriber\MymoduleExceptionSubscriber
    tags:
      - { name: event_subscriber }

```

---
Tags: 9
---


# Question
Title: Mismatched entity and/or field definitions on "Address Field" after upgrade
After upgrading from Drupal 9 to Drupal 10 the status page shows the following Entity/field definitions error:

```
 Mismatched entity and/or field definitions
The following changes were detected in the entity type and field definitions.
**Order report**

    The Address field needs to be updated.

```

Normally running "drush entup" fixes field definition errors but doing so here doesn't work and processes the following error:

```
 The SQL storage cannot change the schema for an existing field (billing_address in commerce_order_report entity) with data.

```

# Answer
> 0 votes
`drush entup` is no longer supported, use `drush updb` instead. See https://www.drupal.org/node/3034742

This is rather an update error of the Address module which can be updated independently from core, it is compatible with Drupal 9 and 10 simultaneously.

The previous version had update hooks which are no longer present in the current version, but you need to run all update hooks via `drush updb` in the correct order. Roll back the module version and catch up drush updb for the previous version and then again for the current version because this has a schema change as well.

---
Tags: 10, upgrading
---


title: Entity reference to role

text:
# Question
Title: Entity reference to role
I want to add an Entity Reference field to a Group Type entity, referencing User Roles. When I add a Entity Reference \> Other \> Roles field, the creation/edition form of this Group Type throws the attached errors:

Despite they're not usual, does Entity Reference fields to user roles work properly?

# Answer
It seems that there is a bug in Opigno LMS about configuring entity forms for groups, so the error I reported previously is not related to the reference field.

Just for completion, I reported the bug for OpignoLMS here: https://www.drupal.org/project/opigno\_lms/issues/3414721
> 0 votes

---
Tags: 9, group, entities
---


# Question
Title: How can I execute Drush commands programmatically?
I'm working on a Drupal 8 site, and part of the requirement is giving the client a page where they can click a button to do a particular task. I am able to do this using a Drush command from the command line, but I want to do it from a module.

I had seen code using either `php_exec()` or `drush_invoke_process()`. How can I use this function?

# Answer
> 7 votes
Just start it from the other side. Imagine that every Drush command executes some PHP code. Then check the code of the Drush command you want to run. And then refactor it into the submit function of your button.

Doing it like suggested in your question doesn't seem to be very sustainable, taking into account that not every host has Drush installed. So you better make that functionality work independently from its environment.

---

Found one possible way: How to run Drupal console command from code? using Symfony's `Process` and flagged question as possible duplicate. And regarding `drush_invoke_process()`, as how I understand it so far, it seems to be callable only from within other Drush commands.

---

Next thing that came to my attention: In the comments to your question you are saying that you are trying to execute `/vendor/bin/drush/drush status` which would mean you have the vendor folder at the root of your machine. Which very probably is wrong and you just need to fix that path.

# Answer
> 12 votes
From Drush 9 and higher drush commands are symfony services, so you can load them as other services though the services container. example:

```
if (PHP_SAPI === 'cli') {
  $command = \Drupal::service('migrate_tools.commands');
  $command->import('my_migration', ['update' => TRUE, 'sync' => TRUE]);
}

```

# Answer
> 1 votes
On **Drupal 9.5.11**, I wanted to call the command from a contrib module (search\_api) to get more control over it. This is how I did :

```
$self = Drush::aliasManager()->getSelf();
$finished = FALSE;
// These are the options of the drush command
$options = ['limit' => '100', 'batch-size' => '50'];
while (!$finished) {
  // You can specify an index id in the 3rd argument, ex : ['index']
  $process = $this->processManager()->drush($self, 'search-api:index', [], $options);
  // We capture the output to print it here and check if it finished.
  $process->run($process->showRealtime()->hideStdout());
  if (!$process->isSuccessful() || empty($process->getOutput())) {
    $finished = TRUE;
  }
  else {
    // \Drupal::logger('YourModule')->notice($process->getOutput(), []);
  }
}

```

You can check the command `drush search-api:index` to identify the argument and the options of it, and how there are dealt with in this code.

# Answer
> -2 votes
run `updb` from other drush command class

```
    public function updateDB() {
        $updb = new \Drush\Commands\core\UpdateDBCommands();
        $updb->setProcessManager($this->processManager());
        $updb->setConfig($this->getConfig());
        $updb->setLogger($this->logger());
        $updb->setSiteAliasManager($this->siteAliasManager());
        $updb->input()->setOption('yes', true);
        $updb->setOutput($this->output());
        $updb->updatedb(['cache-clear' => true, 'entity-updates' => false, 'post-updates' => true]);

    }

```

---
Tags: 8, drush
---


title: Change the state of a checkboxes field

text:
# Question
Title: Change the state of a checkboxes field
I know how to use conditions with Form API for fields like text-field, checkbox, for example, showing or hiding a field when a checkbox is checked.

```
$form['lorem'] = [
  '#type' => 'checkbox',
  '#attributes' => [
    'name' => 'field_lorem',
  ]
];

$form['ipsum'] = [
  '#type' => 'checkbox',
  '#states' => [
    'visible' => [
      ':input[name="field_lorem"]' => ['checked' => true]
    ],
  ],
];

```

However, I can't manage to do it with a checkboxes field.

```
// This code does not work.
$form['lorem'] = [
  '#type' => 'checkbox',
  '#attributes' => [
    'name' => 'field_lorem',
  ]
];

$options = [
  'test_1' => 'Test 1',
  'test_2' => 'Test 2',
];

$form['ipsum'] = [
  '#type' => 'checkboxes',
  '#options' => $options,
  '#states' => [
    'visible' => [
      ':input[name="field_lorem"]' => array('checked' => true)
    ],
    // Ideally, I would like to have all the checkboxes checked but the problem is mainly at the state level
    'checked' => [
      ':input[name="field_lorem"]' => ['checked' => TRUE],
    ],
  ],
];

```

I can do it with custom JavaScript code, but I ideally wanted to do it with the form API.

What `#states` property do I need to achieve this?

# Answer
> 0 votes
You need to add `#states` to every checkbox.

```
$form['select_all'] = [
  '#title' => $this->t('Select all'),
  '#type' => 'checkbox',
  '#attributes' => [
    'name' => 'all'
  ]
];

$options = [
 'item_0' => 'value',
 'item_1' => 'value',
 'item_2' => 'value',
];

$form['my_checkboxes'] = [
 '#type' => 'checkboxes',
 '#options' => $options,
 'item_0' => [
    '#states' => [
      'checked' => [
        ':input[name="all"]' => [
          'checked' => TRUE
        ]
      ]
    ]
  ]
];

foreach ($options as $key => $item) {
  $form['my_checkboxes'][$key]['#states']['checked'][':input[name="all"]']['checked'] = TRUE;
}

```

# Answer
> 0 votes
You can wrap the checkboxes in a details (fieldset).

```
$form['controlling_checkbox'] = [
  '#type' => 'checkbox',
  '#title' => ['Switch me on and off'],
];
$options = ['a' => 'b', 'c' => 'd'];
$form['wrapper'] = [
  '#type' => 'details',
  '#title' => 'Wrap me up',
  '#collapsible' => TRUE,
  '#open' => TRUE,
  '#states' => [
    'disabled' => [
      ':input[name="controlling_checkbox"]' => [
          ['checked' => TRUE],
      ],
    ],
  ]
];
$form['wrapper']['lots_of_boxes'] = [
  '#type' => 'checkboxes',
  '#options' => $options,
];

```

---
Tags: forms, 9
---


# Question
Title: Why can I not push code on the project I created?
I have created a project on drupal.org. *The repository for this project is empty* message is shown on the repository page.

>

I used to get the Git push instructions on previous days.

I tried to clone the repository using either the *git@git.drupal.org:project/* or the *https://git.drupalcode.org/project/* link, but I get this error when I run `git push -u origin master`.

> remote:
> remote: You are not allowed to push code to this project. remote:
> remote:
> remote:
> fatal: Could not read from remote repository.

I also added the SSH key.

>

I have also checked to see if my ssh key works or not by running the following command:

```
ssh -T git@git.drupal.org

```

and it is showing welcome message. Why cannot I push code on the project I created?

# Answer
> 1 votes
I had this error message when pushing to a branch for an issue. My solution was to just go to the project's issue page in drupal.org and click in the button "Get push access"! Now I have push access.

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


# Question
Title: Migrate process plugin entity_lookup: value_key: field with multiple values
The field "field\_erp\_code" has multiple values, but it seems that migrate only looks at delta 0 of that field. Can this be done by with the entity\_lookup plugin?

```
 field_product_category:
    plugin: entity_lookup
    source: Product category
    entity_type: taxonomy_term
    bundle_key: vid
    bundle: product_category
    value_key: field_erp_code

```

# Answer
The `entity_lookup` plugin from the `migrate_plus` module already supports multi-valued fields. But you can specify manually the `operator: IN` if necessary.

See \Drupal\migrate\_plus\Plugin\migrate\process\EntityLookup.

Try to debug this plugin and see what comes as the value.
> 2 votes

---
Tags: migrations, 10
---


# Question
Title: How to create a view of hierarchical taxonomy terms and their nodes?
I'd like to create an HTML sitemap viewable by a human. I mention that I'd like to keep the hierarchy (tree structure of categories with subcategories) like the following:

```
- TERM_A
  - Node a
  - Node b
- TERM B
  - TERM_B1
    - Node c
    - Node d
  - TERM_B2
    - Node e
    - Node f

```

For example, is it possible to display the results as grouped categories and sub-categories, by managing the order or results (relate to taxonomy term, sort by term weight and nesting level)?

# Answer
> 2 votes
You can do it using the grouping fields feature inside Views.

Create Views listing your nodes (titles), add a Field showing terms they're tagged with (sub-term).

Then add a Relationship for that same Field (the Taxonomy term reference Field). Add another Relationship to introduce Parent term, use the first Relationship here.

Now add another Term name Field and set it to use the second Relationship, this way the Field will show the first level Taxonomy hierarchy for a node.

Now edit your `Format` settings and set the **Grouping field Nr.1** to use the Parent Field, and set the **Grouping field Nr.2** the usual (sub-term) Field.

If you need further control of the output you can overwrite to change HTML, and use CSS to emphasize the hierarchy visually.

# Answer
> 0 votes
Have you looked into the XML Sitemap module?

It creates a sitemap page for you and it comes with XML Sitemap Taxonomy as a submodule that you can enable and configure.

If you want to reorder the way they appear, I'd assume you would edit the taxonomy itself and have that reflected in the sitemap output.

# Answer
> 0 votes
This can be achieved with the Views field view module which allows you to embed one view into another view and pass arguments along.

Ref: https://www.drupal.org/project/views\_field\_view

# Answer
> 0 votes
There's https://www.drupal.org/project/views\_term\_hierarchy\_weight\_field which might be useful.

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


# Question
Title: What is the purpose of the "Menu language" widget?
When the Content Translation module is enabled, a "Menu language" widget appears in the form for editing menus:

What is the purpose of this widget? What does it do?

It does not seem to affect my site at all when I change the dropdown to a different language, or to "Not specified" or "Not applicable."

# Answer
This is the original language for the label and the description. After saving the menu in the original language you can click on the tab above (admin/structure/menu/manage/main/translate) and translate the two text fields into other languages.
> 1 votes

---
Tags: i18n-l10n, 10
---


# Question
Title: Is there a Drupal way to make a menu horizontal and responsive and leveled (similar in style and behavior to a main navigation menu)?
I have added a menu to a block in a full width region but my problem is that this menu appears vertical and I didn't find a way in Drupal to make it horizontal, similar in style and behavior to a main navigation menu.

I don't want to develop CSS to make the menu horizontal and responsive and leveled from scratch if I can somehow do it with Drupal so it would be styled and behave more or less like the main navigation menu of my core theme Olivero or possibly of another core theme like Stark or Classy or Stable; I assume that I might indeed be able to somehow **apply** the exact same class system of some main navigation menu for that menu in a single quick action and voilà! the menu will become horizontal and responsive and leveled.
By "leveled" I mean that each menu item can have at least one menu-item-child.

Is there a Drupal way to make a menu horizontal and responsive and leveled (similar in style and behavior to a main navigation menu)?

# Answer
Unfortunately it is not as simple as adding one single class and everything is automagically responsive and collapsable. It is definitely possible, and Olivero's main menu is a great template, but you can't duplicate it without writing your own custom CSS **and** JS (or PHP preprocessing).

You might get some no-code solutions from contrib modules though, try goolging for e.g. "drupal mega menu".
> 0 votes

---
Tags: theming, blocks, navigation, 10
---


# Question
Title: How can I add a CASE statement in a WHERE clause?
I need to add a WHERE clause to the query altered by a `hook_views_query_alter()` implementation. The WHERE clause needs to contain the following CASE statement.

```
$sql = "(CASE WHEN node_field_data.type IN ('course', 'events') AND ((node__field_event_start_date.field_event_start_date_value > today) OR (node__field_event_start_time.field_event_start_time_value > 0 AND node__field_event_start_time.field_event_start_time_value > current_timestamp)) THEN 1 WHEN node_field_data.type = 'insight' THEN 1 ELSE 0 END) = 1";

$query->addWhere(2, $sql, 1, '=');

```

I tried to use `addWhere()`, but it removes all the spaces from the condition and causes the following error.

> Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '."field\_event\_start\_time\_value0ANDnode\__field\_event\_start\_time"."field\_event\_sta' at line 6

How can I make this work?

# Answer
> 2 votes
Resolved it by adding additional AND OR condition groups. Sharing this in case anyone needs it in future.

```
    $start_date_configuration = [
      'table' => 'node__field_event_start_date',
      'field' => 'entity_id',
      'left_table' => 'node_field_data',
      'left_field' => 'nid',
      'operator' => '=',
    ];
    $join = Views::pluginManager('join')->createInstance('standard', $start_date_configuration);
    $query->addRelationship('node__field_event_start_date', $join, 'node_field_data');

    $start_time_configuration = [
      'table' => 'node__field_event_start_time',
      'field' => 'entity_id',
      'left_table' => 'node_field_data',
      'left_field' => 'nid',
      'operator' => '=',
    ];
    $join = Views::pluginManager('join')->createInstance('standard', $start_time_configuration);
    $query->addRelationship('node__field_event_start_time', $join, 'node_field_data');

    $current_timestamp = (new DrupalDateTime())->getTimestamp();

    $query->setWhereGroup('OR', 3);
    $query->addWhere(3, 'node_field_data.type', 'insight');
    $query->addWhere(3, (
      $query->getConnection()->condition('AND'))
      ->condition('node_field_data.type', ['course', 'events'], 'IN')
      ->condition(
        $query->getConnection()->condition('OR')
          ->condition('node__field_event_start_date.field_event_start_date_value', date('Y-m-d'), '>=')
          ->condition(
          $query->getConnection()->condition('AND')
            ->condition('node__field_event_start_date.field_event_start_date_value', NULL, 'IS NULL')
            ->condition('node__field_event_start_time.field_event_start_time_value', $current_timestamp, '>=')
        )
      )
    );

```

Thanks.

# Answer
> 1 votes
You can accomplish this with `$query->addWhereExpression()`.
https://api.drupal.org/api/drupal/core%21modules%21views%21src%21Plugin%21views%21query%21Sql.php/9
For example: `$query->addWhereExpression($group, 'Expression with CASE', [$arguments]);`

---
Tags: views, hooks, 9
---


title: Custom validation of route parameters

text:
# Question
Title: Custom validation of route parameters
I have something like the following on my `.routing.yml` file:

```
my.path:
  path: '/my-path/{node}'
  defaults:
    _form: 'Drupal\mymodule\Form\MyForm'
  requirements:
    _entity_access: 'node.update'
    node: \d+

```

This works fine, it checks that the user has permissions to edit the node and all. Now, I want to restrict this route to work only for nodes of a certain content type. Ideally, something like this as the final line:

```
    node.bundle: 'article'   # this doesn't work, of course

```

How can I do this?

# Answer
> 18 votes
I could find three possible ways. Supposing your module name is *example* and content type to check is *article*.

**1. Validating the argument in the form builder**

It is the simplest way.

First define your route as usual:

*example.routing.yml*

```
 example.node.edit_form:
  path: /example/{node}/edit
  defaults:
    _form: 'Drupal\example\Form\ExampleNodeForm'
  options:
    _node_operation_route: TRUE
    parameters:
      node:
        type: entity:node
  requirements:
    _permission: 'edit any article content'

```

Then simply put these lines to *Drupal\example\Form\ExampleNodeForm::buildForm* before the other code.

```
if ($node->getType() != 'article') {
  throw new AccessDeniedHttpException();
}

```

**2. Validate the argument using custom access callback**

The route definition is the same as above except *custom\_access* option under the requirements section.

*example.routing.yml*

```
 example.node.edit_form:
  path: /example/{node}/edit
  defaults:
    _form: 'Drupal\example\Form\ExampleNodeForm'
  options:
    _node_operation_route: TRUE
    parameters:
      node:
        type: entity:node
  requirements:
    _permission: 'edit any article content'
    _custom_access:  'Drupal\example\Form\ExampleNodeForm::access'

```

Drupal\example\Form\ExampleNodeForm::access() should return instance of *Drupal\Core\Access\AccessResult*. This can be done as follows.

```
return AccessResult::allowedIf($node->getType() == 'article');

```

**3. Validation the argument with access checker**

*example.routing.yml*

```
 example.node.edit_form:
  path: /example/{node}/edit
  defaults:
    _form: 'Drupal\example\Form\ExampleNodeForm'
  options:
    _node_operation_route: TRUE
    parameters:
      node:
        type: entity:node
  requirements:
    _permission: 'edit any article content'
    _content_type:  'article'

```

As you can see this includes *\_content\_type* requirement. To make it work you need to implement custom access check service.

*example.services.yml*

```
services:
  example.content_type_access_checker:
    class: Drupal\example\Access\ContentTypeAccessCheck
    tags:
      - { name: access_check, applies_to: _content_type }

```

*Drupal\example\src\Access\ContentTypeAccessCheck.php*

```
namespace Drupal\example\Access;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\Routing\Route;

/**
 * Checks if node type matches the one provided in the route configuration.
 */
class ContentTypeAccessCheck implements AccessInterface {

  /**
   * Access callback.
   */
  public function access(Route $route, NodeInterface $node) {
    return AccessResult::allowedIf($node->getType() == $route->getRequirement('_content_type'));
  }
}

```

The last approach can be helpful if you want to reuse access control code accross multiple routes.

Documentation: https://www.drupal.org/docs/8/api/routing-system/access-checking-on-routes.

# Answer
> 1 votes
Huge apologies for posting an answer *years* later, but I just wanted to say that this is possible in Drupal core now (since version 9.2.0.)

You can define a route like this:

```
example.route:
  path: foo/{example}
  options:
    parameters:
      example:
        type: entity:node
        bundle:
          - article
          - news

```

As per: https://www.drupal.org/node/3155569

---
Tags: 8, routes
---


# Question
Title: "Declaration of Monolog\Logger::emergency() must be compatible with Psr\Log\LoggerInterface::emergency()"
I'm using **PHP 8.1.2-1ubuntu2.14**, **Drush 8.4.12** (latest), and **Drupal 7.98** (not yet updated).

I'm having a problem with a Drush command which uses Google APIs, Google Auth, and Google services. I get the following error.

> PHP Fatal error: Declaration of Monolog\Logger::emergency(Stringable|string $message, array $context = \[\]): void must be compatible with Psr\Log\LoggerInterface::emergency($message, array $context = \[\]) in /home/eliosh/PhpstormProjects/Mega7/sources/vendor/monolog/monolog/src/Monolog/Logger.php on line 681
> Drush command terminated abnormally due to an unrecoverable error.
> Error: Declaration of Monolog\Logger::emergency(Stringable|string $message, array $context = \[\]): void must be compatible with Psr\Log\LoggerInterface::emergency($message, array $context = \[\]) in /home/eliosh/PhpstormProjects/Mega7/sources/vendor/monolog/monolog/src/Monolog/Logger.php, line 681

Following this comment in the monolog repo, I've added the following code before the call to the "problematic" function.

```
var_dump(class_exists('Psr\Log\LoggerInterface'),
  (new \ReflectionClass('Psr\Log\LoggerInterface'))->getFileName()
);

```

The output is the following

```
bool(false)
string(71) "phar:///usr/local/bin/drush8/vendor/psr/log/Psr/Log/LoggerInterface.php"

```

This is the output of `composer show`.

```
composer/ca-bundle               1.4.0     Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.
dg/twitter-php                   v3.8      Small and easy Twitter library for PHP
domnikl/statsd                   2.10.0    a PHP client for statsd
donatj/simplecalendar            v0.6.2    A light, easy to use calendar rendering library
exads/exads-api-client-php       v1.3.1    Exads API client
fastglass/sendgrid               2.0.6     This library allows you to send emails through SendGrid using PHP and Guzzle 6.x.
firebase/php-jwt                 v6.10.0   A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.
geoip2/geoip2                    v2.13.0   MaxMind GeoIP2 PHP API
giggsey/libphonenumber-for-php   7.7.5     PHP Port of Google's libphonenumber
giggsey/locale                   1.9       Locale functions required by libphonenumber-for-php
google/apiclient                 v2.15.3   Client library for Google APIs
google/apiclient-services        v0.331.0  Client library for Google APIs
google/auth                      v1.34.0   Google Auth Library for PHP
guzzlehttp/guzzle                7.8.1     Guzzle is a PHP HTTP client library
guzzlehttp/promises              2.0.2     Guzzle promises library
guzzlehttp/psr7                  2.6.2     PSR-7 message implementation that also provides common utility methods
intervention/image               2.7.2     Image handling and manipulation library with support for Laravel integration
james-heinrich/getid3            v1.9.23   PHP script that extracts useful information from popular multimedia file formats
jean85/pretty-package-versions   2.0.5     A library to get pretty versions strings of installed dependencies
jenssegers/imagehash             v0.9.0    Perceptual image hashing for PHP
maxmind-db/reader                v1.11.1   MaxMind DB Reader API
maxmind/web-service-common       v0.9.0    Internal MaxMind Web Service API
mongodb/mongodb                  1.11.0    MongoDB driver library
monolog/monolog                  3.5.0     Sends your logs to files, sockets, inboxes, databases and various web services
paragonie/constant_time_encoding v2.6.3    Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)
paragonie/random_compat          v9.99.100 PHP 5.x polyfill for random_bytes() and random_int() from PHP 7
phpseclib/phpseclib              3.0.35    PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.
psr/cache                        3.0.0     Common interface for caching libraries
psr/http-client                  1.0.3     Common interface for HTTP clients
psr/http-factory                 1.0.2     Common interfaces for PSR-7 HTTP message factories
psr/http-message                 2.0       Common interface for HTTP messages
psr/log                          3.0.0     Common interface for logging libraries
ralouphie/getallheaders          3.0.3     A polyfill for getallheaders.
starkbank/ecdsa                  0.0.4     fast openSSL-compatible implementation of the Elliptic Curve Digital Signature Algorithm (ECDSA)
symfony/deprecation-contracts    v3.4.0    A generic function and convention to trigger deprecation notices
symfony/polyfill-php80           v1.28.0   Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions

```

This is the output of `composer show -p`.

```
composer                   2.6.2     Composer package
composer-plugin-api        2.6.0     The Composer Plugin API
composer-runtime-api       2.2.2     The Composer Runtime API
ext-apcu                   5.1.21    The apcu PHP extension
ext-bcmath                 8.1.2     The bcmath PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-calendar               8.1.2     The calendar PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-ctype                  8.1.2     The ctype PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-curl                   8.1.2     The curl PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-date                   8.1.2     The date PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-dom                    20031129  The dom PHP extension
ext-exif                   8.1.2     The exif PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-ffi                    8.1.2     The FFI PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-fileinfo               8.1.2     The fileinfo PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-filter                 8.1.2     The filter PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-ftp                    8.1.2     The ftp PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-gd                     8.1.2     The gd PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-gettext                8.1.2     The gettext PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-gmp                    8.1.2     The gmp PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-hash                   8.1.2     The hash PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-iconv                  8.1.2     The iconv PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-igbinary               3.2.6     The igbinary PHP extension
ext-imagick                3.6.0     The imagick PHP extension
ext-json                   8.1.2     The json PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-libxml                 8.1.2     The libxml PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-mbstring               8.1.2     The mbstring PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-memcached              3.1.5     The memcached PHP extension
ext-mongodb                1.12.0    The mongodb PHP extension
ext-msgpack                2.2.0RC1  The msgpack PHP extension
ext-mysqli                 8.1.2     The mysqli PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-mysqlnd                0         The mysqlnd PHP extension (actual version: mysqlnd 8.1.2-1ubuntu2.14)
ext-openssl                8.1.2     The openssl PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-pcntl                  8.1.2     The pcntl PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-pcre                   8.1.2     The pcre PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-pdo                    8.1.2     The PDO PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-pdo_mysql              8.1.2     The pdo_mysql PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-pdo_sqlite             8.1.2     The pdo_sqlite PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-pdo_sqlsrv             5.11.0    The pdo_sqlsrv PHP extension
ext-phar                   8.1.2     The Phar PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-phash                  0.9.6     The pHash PHP extension
ext-posix                  8.1.2     The posix PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-readline               8.1.2     The readline PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-redis                  5.3.5     The redis PHP extension
ext-reflection             8.1.2     The Reflection PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-session                8.1.2     The session PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-shmop                  8.1.2     The shmop PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-simplexml              8.1.2     The SimpleXML PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-sockets                8.1.2     The sockets PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-sodium                 8.1.2     The sodium PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-spl                    8.1.2     The SPL PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-sqlite3                8.1.2     The sqlite3 PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-sqlsrv                 5.11.0    The sqlsrv PHP extension
ext-sysvmsg                8.1.2     The sysvmsg PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-sysvsem                8.1.2     The sysvsem PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-sysvshm                8.1.2     The sysvshm PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-tokenizer              8.1.2     The tokenizer PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-uploadprogress         2.0.2     The uploadprogress PHP extension
ext-xdebug                 3.1.2     The xdebug PHP extension
ext-xml                    8.1.2     The xml PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-xmlreader              8.1.2     The xmlreader PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-xmlwriter              8.1.2     The xmlwriter PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-xsl                    8.1.2     The xsl PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-zend-opcache           8.1.2     The Zend OPcache PHP extension (actual version: 8.1.2-1ubuntu2.14)
ext-zip                    1.19.5    The zip PHP extension
ext-zlib                   8.1.2     The zlib PHP extension (actual version: 8.1.2-1ubuntu2.14)
lib-curl                   7.81.0    The curl library
lib-curl-libssh            0.9.6     curl libssh version
lib-curl-openssl           3.0.2     curl OpenSSL version (3.0.2)
lib-curl-zlib              1.2.11    curl zlib version
lib-date-timelib           2021.11   date timelib version
lib-date-zoneinfo          0         zoneinfo ("Olson") database for date
lib-fileinfo-libmagic      540       fileinfo libmagic version
lib-gd                     2.3.0     The gd library
lib-gmp                    6.2.1     The gmp library
lib-iconv                  2.35      The iconv library
lib-imagick-imagemagick    6.9.11.60 The imagick-imagemagick library
lib-libsodium              1.0.18    The libsodium library
lib-libxml                 2.9.13    libxml library version
lib-libxslt                1.1.34    The libxslt library
lib-libxslt-libxml         2.9.13    libxml version libxslt is compiled against
lib-mbstring-libmbfl       1.3.2     mbstring libmbfl version
lib-mbstring-oniguruma     6.9.7     mbstring oniguruma version
lib-memcached-libmemcached 1.0.18    libmemcached version
lib-mongodb-libbson        1.20.0    libbson version of mongodb
lib-mongodb-libmongoc      1.20.0    libmongoc version of mongodb
lib-openssl                3.0.2     OpenSSL 3.0.2 15 Mar 2022
lib-pcre                   10.39     The pcre library
lib-pcre-unicode           14.0.0    PCRE Unicode version support
lib-pdo_sqlite-sqlite      3.37.2    The pdo_sqlite-sqlite library
lib-sqlite3-sqlite         3.37.2    The sqlite3-sqlite library
lib-zip-libzip             1.7.3     The zip-libzip library
lib-zlib                   1.2.11    The zlib library
php                        8.1.2     The PHP interpreter
php-64bit                  8.1.2     The PHP interpreter, 64bit
php-ipv6                   8.1.2     The PHP interpreter, with IPv6 support

```

How can I solve this problem?

# Answer
> 1 votes
Global Drush installs are not supported when the codebase auto loads with Composer and this is the reason. Install and run Drush as documented.

# Answer
> 1 votes
The problem was that, with Drupal 7, you don't need to add drush as a requirement via composer.

The solution to this problem is to require drush via composer, but forcing the version "\<9", the only compatible with drupal 7.

In this way, composer downgraded "psr/log" and "monolog/monolog" packages and we can continue using global drush 8

Thanks a lot to everyone.

---
Tags: 7, drush, composer
---


title: I can't create new fields of type image

text:
# Question
Title: I can't create new fields of type image
Drupal v10.2+ has that new shiny admin UI for creating new fields. However, that new shiny page does not allow the creation of new image fields (the non-reuseable image files, NOT the reuseable media entity image bundle).

When visiting that page, I see the option "Media" (don't want that), "File upload" (this is plain file upload without image processing capabilities) and "Reference". Reference has sub options for "Content", "User", "Taxonomy term" and "Other", but once again no plain image fields. The "Other" option then lists all config entity types and all content entity types (including media entities and file fields), but no image fields.

So I can not create new image fields anywhere.

OTOH, the media entity bundle "image" still has the field "field\_media\_image" of type "Image", so it is there somehow.

I feel I'm missing something obvious, a new config setting maybe? How can I create new image fields in Drupal v10.2+ ?

# Answer
There seems to be a small bug in core as of v10.2.2

In the english UI, all works OK.

But when using a translated admin UI (my primary interface language is german), you have to enter a field name FIRST (this is important), and THEN select "File upload", and then the image field option appears below.
> 1 votes

---
Tags: media, 10
---


# Question
Title: How can I avoid a node is crawled and indexed by search engines in the tightest way possible?
I have a node whose path alias is /example, where I test JavaScript and often share it with fellow JavaScript programmers to consult about how best to do something.

I often need to post the URL for that node in forums and Q&A sites and I fear that it would cause SEO damage to my website because this webpage looks awful, doesn't have almost any logic, and may cause search engine crawlers to falsely signal that my website is "non qualitative."

To ensure that search engines never crawl and hence never index this webpage, I have added the following line to the *robots.txt* file.

```
Disallow: /example

```

I am not sure if that's enough, though. Not all search engines will necessarily respect robots.txt. I could add a `noindex` tag to that node somehow.

How can I avoid a node is crawled and indexed by search engines in the tightest way possible?
Does Drupal have its own mechanism for that, to add a `noindex` tag or any other thing I might have missed?

# Answer
> 1 votes
Yes, Drupal has a mechanism to block all crawlers in the “tightest way possible”: authentication.

---
Tags: nodes, 10
---


# Question
Title: creating a webform block that can be used in Layout Builder
My problem is I've created a webform block type, and I can access it from Layout Builder, but when I place the block on a page in Layout Builder, I'm warned "This block is reusable! Any changes made will be applied globally." And it does. If I drop a form on another page and select a different form, both it and the first page display the same form. How do I make the block such that it can put a unique instance of a form every time I use it and not globally change all block instances to the currently selected form?

# Answer
I finally found a module called “Block List Override” on the site I was working on that had a list under “Layout Builder List Regex”. I named my block type following a pattern in that list, added a field for the webform reference, deleted the body field, hid the title of the webform field from the display, and then the block appeared as a choice in Layout Builder when I clicked on “Create Content Block”.

Creating a custom block after creating the block type was unnecessary and it created the issue I was having above where trying to use a custom block in more than one place meant that whatever change I made to one block instance affected all of them.

Essentially, I needed to learn the differences between a block type and a custom block.
> 0 votes

---
Tags: blocks, webforms, layout-builder
---


title: How do I delete files the correct way?

text:
# Question
Title: How do I delete files the correct way?
I have added a file attachment field to my basic pages.

Now for instance I want to delete a certain file from a page, how should I approach this?

I know deleting it from the file system isn't the correct way to go as it would still keep a database record of it.

However, if I remove it on the basic page 'Edit' page, it will also keep a record in the database.

How do I clean-up the database for files that don't exist or aren't used anymore?

I am using Drupal 8.

# Answer
> 6 votes
> However if I remove it on the basic page 'Edit' page, it will also still keep a record in the database.

That's correct. However, after editing, the file *status* should be set to 0, unless the same file is used elsewhere. Drupal has a built in system that should automatically clean up these stale files both from the filesystem and the database, which you can configure on /admin/config/media/file-system. The default time is set to 6 hours (depending on when cron runs this could take up to the next cron run).

Be aware though that there are known issues with this automated deletion. See the *File usage tracking causes unexpected file deletion* section in the Drupal 8.3.2 release notes.

# Answer
> 2 votes
Contributed Drupal module Views Bulk Operations has initial D8 Alpha release which can help to delete orphaned file entities through UI.

Install the module, edit Files view, add "Views bulk operations" global field and configure it to include "Delete selected entities" action.

The module is currently limited from an Admin point of view as it only allows the person that uploaded the file to execute the delete. Trying to do it as anyone else (including user-1) will fail (with log error message). Hopefully this limitation will be fixed in releases to come.

# Answer
> 1 votes
As of Drupal 10.1, it is now possible to properly delete files through the UI. You can do this by visiting the Files admin page.

See more at the Deleting Files documentation.

---
Tags: files
---


# Question
Title: How do I delete files using the Content > Files interface?
I got a ticket from our stakeholders that certain outdated PDFs are googlable, and this is causing problems with people going on old information.

Navigating to `admin/content/files`, I am able to find entities(?) for the files, by searching on their filename and extension (MIME type). There is also a seemingly handy column "Used In". However, when I click through the values in the "Used In" column (e.g. "2 places"), the paths are like render elements or something similiar: `{Content Type} > Paragraphs (previous revision) > Column Content (previous revision) > Column Wrapper Content (previous revision) > Accordion Section (previous revision) > Accordion Section Body`.

From this information, I am not able to navigate to the page where the file resides, in order to remove it.

Furthermore, one of the files is used in 0 places, and there appears to be no interface that allows me to delete it. I am able to open the PDF from the file path link in an incognito window, so I conclude that, even though a user can't discover this PDF by navigating on our site, they still might get to it through a google search.

One proposed solution might be to google for the files, and find out where on our site they are from Google's search results, but the top search results are direct links to the PDFs themselves. I want to know how to delete these files through Drupal, so in a future case, where I can't find them through googling, I still have a way to delete them.

How do I delete these files, listed in the "Files" tab of the admin content screen?

My question is different from How do I delete files the correct way? because, in that question, the asker already knows which node it is that contains the file they want to delete. In this case, I don't know where on the website the file is actually attached. I'm trying to get that information.

# Answer
> 2 votes
There are a couple of approaches; if you'd rather manage the deletion a bit more tightly, you can use the API to get a list of node (and/or other "thing") IDs that reference a particular file:

```
$usage = \Drupal::service('file.usage')
  ->listUsage(\Drupal\file\Entity\File::load($fid));

```

Then you can edit the node/etc, find the offending reference (in your example it looks like that would be within a paragraph of a previous revision), and remove it.

If you just want an interface for deleting files, there's the fledgling Delete Files module. It will even degrade gracefully for deleted files that are still referenced:

> If a file you've deleted is managed by Drupal, this module replaces it with a new empty file to head off potential problems with dangling file references.

# Answer
> 1 votes
As of Drupal 10.1, it is now possible to properly delete files through the UI. You can do this by visiting the Files admin page.

See more at the Deleting Files documentation.

---
Tags: files
---


# Question
Title: Dependency issues do not allow to upgrade
I'm trying to upgrade a project to 10.2 but I should update my modules first. Running `composer update` throws this error.

```
Deprecation Notice: Using ${var} in strings is deprecated, use {$var} instead in phar:///usr/local/bin/composer/src/Composer/DependencyResolver/Problem.php:366
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - zendframework/zend-feed[2.11.0, ..., 2.12.0] require php ^5.6 || ^7.0 -> your php version (8.3.1) does not satisfy that requirement.
    - laminas/laminas-feed[2.12.0, ..., 2.12.3] require php ^5.6 || ^7.0 -> your php version (8.3.1) does not satisfy that requirement.
    - symfony-cmf/routing[1.4.0, ..., 1.4.1] require php ^5.3.9|^7.0 -> your php version (8.3.1) does not satisfy that requirement.
    - drupal/core[8.9.11, ..., 8.9.20] require php ^7.0.8 -> your php version (8.3.1) does not satisfy that requirement.
    - drupal/core[9.0.10, ..., 9.0.14] require php ^7.3 -> your php version (8.3.1) does not satisfy that requirement.
    - laminas/laminas-feed[2.13.0, ..., 2.14.1] require php ^7.3 || ~8.0.0 -> your php version (8.3.1) does not satisfy that requirement.
    - longwave/laminas-diactoros 2.14.1 requires php ^7.3 || ~8.0.0 || ~8.1.0 -> your php version (8.3.1) does not satisfy that requirement.
    - longwave/laminas-diactoros 2.14.2 requires php ^7.3 || ~8.0.0 || ~8.1.0 || ~8.2.0 -> your php version (8.3.1) does not satisfy that requirement.
    - Root composer.json requires drupal/ckeditor_entity_link ^1.3 -> satisfiable by drupal/ckeditor_entity_link[1.3.0].
    - drupal/core-recommended 10.2.2 requires drupal/core 10.2.2 -> satisfiable by drupal/core[10.2.2].
    - Conclusion: don't install drupal/core 10.2.2 (conflict analysis result)
    - drupal/core[8.4.0, ..., 8.9.10] require symfony-cmf/routing ^1.4 -> satisfiable by symfony-cmf/routing[1.4.0, 1.4.1].
    - drupal/core[8.2.0, ..., 8.3.9] require symfony-cmf/routing ~1.4 -> satisfiable by symfony-cmf/routing[1.4.0, 1.4.1].
    - drupal/core[8.8.0, ..., 8.8.12] require zendframework/zend-feed ^2.12 -> satisfiable by laminas/laminas-feed[2.12.0, ..., 2.19.0], zendframework/zend-feed[2.12.0].
    - drupal/core[9.4.15, ..., 9.5.11] require longwave/laminas-diactoros ^2.14 -> satisfiable by longwave/laminas-diactoros[2.14.1, 2.14.2].
    - drupal/core-recommended 10.2.1 requires drupal/core 10.2.1 -> satisfiable by drupal/core[10.2.1].
    - Conclusion: don't install drupal/core 10.2.1 (conflict analysis result)
    - drupal/ckeditor_entity_link 1.3.0 requires drupal/core ^8 || ^9 -> satisfiable by drupal/core[8.0.0, ..., 8.9.20, 9.0.0, ..., 9.5.11].
    - You can only install one version of a package, so only one of these can be installed: drupal/core[8.0.0, ..., 8.9.20, 9.0.0, ..., 9.5.11, 10.0.0, ..., 10.2.2].
    - You can only install one version of a package, so only one of these can be installed: drupal/core[8.1.2, ..., 8.9.20, 9.0.0, ..., 9.5.11, 10.0.0, ..., 10.2.2].
    - You can only install one version of a package, so only one of these can be installed: drupal/core[8.1.8, ..., 8.9.20, 9.0.0, ..., 9.5.11, 10.0.0, ..., 10.2.2].
    - You can only install one version of a package, so only one of these can be installed: drupal/core[8.7.0, ..., 8.9.20, 9.0.0, ..., 9.5.11, 10.0.0, ..., 10.2.2].
    - drupal/core-recommended 10.2.0 requires drupal/core 10.2.0 -> satisfiable by drupal/core[10.2.0].
    - Root composer.json requires drupal/core-recommended ^10.2 -> satisfiable by drupal/core-recommended[10.2.0, 10.2.1, 10.2.2].

```

The *composer.json* content is the following.

```
{
    "name": "drupal/recommended-project",
    "description": "Project template for Drupal 9 projects with a relocated document root",
    "type": "project",
    "license": "GPL-2.0-or-later",
    "homepage": "https://www.drupal.org/project/drupal",
    "support": {
        "docs": "https://www.drupal.org/docs/user_guide/en/index.html",
        "chat": "https://www.drupal.org/node/314178"
    },
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],
    "require": {
        "commerceguys/addressing": "^2.1",
        "composer/installers": "^2.2",
        "drupal/address": "^2.0",
        "drupal/admin_toolbar": "^3.4",
        "drupal/asset_injector": "^2.19",
        "drupal/blazy": "^2.22",
        "drupal/bootstrap": "^3.29",
        "drupal/bootstrap_barrio": "^5.5",
        "drupal/bootstrap_sass": "^5.0",
        "drupal/ckeditor_entity_link": "^1.3",
        "drupal/colorbox": "^2.0",
        "drupal/colorbox_inline": "^2.0",
        "drupal/core-composer-scaffold": "^10.2",
        "drupal/core-project-message": "^10.2",
        "drupal/core-recommended": "^10.2",
        "drupal/flexslider": "^2.0",
        "drupal/geocoder": "^4.18",
        "drupal/geofield": "^1.57",
        "drupal/geofield_map": "^3.0",
        "drupal/geolocation": "^3.12",
        "drupal/geophp": "^1.1",
        "drupal/leaflet": "^10.2",
        "drupal/redirect_after_login": "^3.0",
        "drupal/slick": "^2.10",
        "drupal/slick_lightbox": "^1.7",
        "drupal/slick_views": "^2.8",
        "drupal/taxonomy_manager": "^2.0",
        "drupal/views_slideshow": "^5.0",
        "drush/drush": "^12.4",
        "geocoder-php/free-geoip-provider": "^4.5"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "stable",
    "prefer-stable": true,
    "config": {
        "sort-packages": true,
        "allow-plugins": {
            "composer/installers": true,
            "drupal/core-composer-scaffold": true,
            "drupal/core-project-message": true,
            "php-http/discovery": true
        }
    },
    "extra": {
        "drupal-scaffold": {
            "locations": {
                "web-root": "web/"
            }
        },
        "installer-paths": {
            "web/core": [
                "type:drupal-core"
            ],
            "web/libraries/{$name}": [
                "type:drupal-library"
            ],
            "web/modules/contrib/{$name}": [
                "type:drupal-module"
            ],
            "web/profiles/contrib/{$name}": [
                "type:drupal-profile"
            ],
            "web/themes/contrib/{$name}": [
                "type:drupal-theme"
            ],
            "drush/Commands/contrib/{$name}": [
                "type:drupal-drush"
            ],
            "web/modules/custom/{$name}": [
                "type:drupal-custom-module"
            ],
            "web/profiles/custom/{$name}": [
                "type:drupal-custom-profile"
            ],
            "web/themes/custom/{$name}": [
                "type:drupal-custom-theme"
            ]
        },
        "drupal-core-project-message": {
            "include-keys": [
                "homepage",
                "support"
            ],
            "post-create-project-cmd-message": [
                "<bg=blue;fg=white>                                                         </>",
                "<bg=blue;fg=white>  Congratulations, you’ve installed the Drupal codebase  </>",
                "<bg=blue;fg=white>  from the drupal/recommended-project template!          </>",
                "<bg=blue;fg=white>                                                         </>",
                "",
                "<bg=yellow;fg=black>Next steps</>:",
                "  * Install the site: https://www.drupal.org/docs/8/install",
                "  * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html",
                "  * Get support: https://www.drupal.org/support",
                "  * Get involved with the Drupal community:",
                "      https://www.drupal.org/getting-involved",
                "  * Remove the plugin that prints this message:",
                "      composer remove drupal/core-project-message"
            ]
        }
    }
}

```

I don't understand why these Drupal 8 dependencies are there. Could someone point me towards the solution, please?

# Answer
> 2 votes
Your answer is in the composer output:

```
drupal/ckeditor_entity_link 1.3.0 requires drupal/core ^8 || ^9

```

ckeditor entity link doesn't support drupal 10, remove it.

---
Tags: composer, 10, upgrading
---