title: Get the HTML content from the database

text:
# Question
Title: Get the HTML content from the database
I have a copy of a Drupal 9 database from which I need to download all the pages.
I loaded the database in MySQL Workbench CE and connected to it via Python. There are many tables, but no views or stored procedures. I guess that some of those tables house the content, but I have no idea on how to pull them together to extract webpages.

block\_content\_body looks promising, but then what?

I assume it is a standard Drupal database. Is there a standard schema?

This what I have tried.

```
#connect to drupal db - done...
#copy to directory assigned.
#othercode config....

try:
    # Define the tables and columns to extract HTML content from
    tables_columns = [
        ('node_field_data', 'body_value'),
        ('block_content_field_data', 'body_value'),
        ('field_data_body', 'body_value'),
        ('field_data_[custom_field_name]', '[custom_field_column]'),
        ('paragraph__field_[custom_field_name]', '[custom_field_column]'),
        ('views_view', 'display_options')
        # Add additional tables and columns as needed

    # Iterate over the tables and columns and export HTML content to separate files
    for table, column in tables_columns:
        output_file = os.path.join(output_dir, f'{table}_{column}.html')
        query = f"SELECT {column} FROM {table}"
        cursor.execute(query)
        rows = cursor.fetchall()

        with open(output_file, 'w', encoding='utf-8') as file:
            for row in rows:
                html_content = row[0]
                file.write(html_content + '\n')

        print(f"HTML content from {table}.{column} exported to: {output_file}")

except mysql.connector.Error as error:
    print(f"Error retrieving data from MySQL: {error}")

finally:
    # Close the database connection
    if connection.is_connected():
        cursor.close()
        connection.close()

I still have to correct the field names but guess these are the html files some how joined together here?

Do you have suggestions, or is this just crazy talk?

```

# Answer
Drupal pages are generated in a complex way. Even the content stored in the database is often parsed by an input filter prior to processing. So you will need to use Drupal to generate each page you want a copy of and save that.

But... that's a pain, so there are some automated ways to do it. The downside is that it takes some work to set them up.

If you want to do this repeatedly, you can try the Tome module. This allows you to generate a static site from Drupal 8+ on demand.

Alternately, you could look into setting up Gatsby with Drupal.
> 1 votes

# Answer
The appropriate and documented way to do this is to run the Drupal website on a web server and then create a static archive of the website.
> 0 votes

# Answer
You can use Tome for that.

> Tome is a static site generator, and a static storage system for content.
>
> When Tome is enabled, any changes to config, content, or files will be automatically synced to your local filesystem. These exports can be used to fully rebuild the site from scratch, which removes the need for a persistent SQL database or filesystem. When you're ready to push to production, you can use Tome to generate a static HTML version of your site.
>
> Long story short, you can use Drupal in the same way you would use other static site generators like Jekyll or Hugo - everything lives in one repository, and Drupal only runs on your local machine.
> 0 votes

---
Tags: database
---


# Question
Title: Is there a way to sync file naming across environments?
I have 3 environments with version control. Dev, staging and production.

Now, say I create a new node in staging and create a corresponding file with the name: page--node--28.html.twig

On production environment users keep posting articles, so it will already have a node 28 which messes up the version control.

Is there any way to manage this seamlessly.

# Answer
Do not use node ID based templates at all in such scenarios. Instead create your own custom theme suggestions based on a logic that does not change between environments:

```
function THEME_NAME_theme_suggestions_page_alter(array &$suggestions, array $variables) {

  if ($node = \Drupal::routeMatch()->getParameter('node')) {
    $my_suggestion = $node->getSomethingThatWorksEverywhere();
    $suggestions[] = 'page__' . $my_suggestion;
  }
}

```
> 4 votes

---
Tags: version-control
---


title: Custom block not showing

text:
# Question
Title: Custom block not showing
I created a custom block module (nothing fancy, just an A-Z list and a taxonomy list for navigation), this worked fine in D8 & D9, now since upgrading to D10 it only shows when logged out, when logged in, it still writes a debug message to the Apache errorlog from the build() function, so I know the code is being called and I can dump the content to the log, I just get no display of the output. I have a few paths including . Log out and the block is displayed again.

All the answers I can find are for the block not displaying and requiring a login, this works fine until I login.

I'm outputting to the "hero" region and the region is displaying OK, just without my block content.

Any suggestions on what to look for?

# Answer
> 0 votes
Not entirely an answer, but I put the same block into claro theme and all was good, the theme in use was a temporary testing theme so will create new one via starterkit so issue is resolved, even if the actual question was not answered. Testing theme was a clone of Olivero taken from 9.4 using the work at https://github.com/mherchel/olivero-subtheme if that helps others.

---
Tags: blocks, 10
---


# Question
Title: Operations bulk form for custom content entity
There is a custom entity called organisation. I am trying to build a view to allow bulk delete of the entities.

I checked the view for display content and there is a field to display the checkbox(Node operations bulk form).

This field doesn't show up for the custom entity. Enabling the actions module does not help.

Adding a custom action for delete organisation does not help either. The new action shows up on the list of actions, but the "operations bulk form" does not show up on views for the entity.

Thanks in advance for your help

# Answer
You need both an **action plugin** and an **action config entity**

1. Create the plugin with drush: `drush generate plugin-action`
2. Create the action config entity: look at "system.action.comment\_delete\_action.yml" for an example.

After creating these, clear the cache and it should be available in views under the label "**Bulk update**".
> 6 votes

# Answer
It looks like as of 8.6.x, this *should* be possible by just specifying the delete-multiple-form link template and the delete-multiple-confirm form class for the entity type. For the form class, you can use the generic Drupal\Core\Entity\Form\DeleteMultipleForm.

Not managed to get it to work yet though!
> 1 votes

# Answer
After reading some tutorials and analyzing drupal code I figured out how to get this done in Drupal 9 or 10.

Here is a more detailed description what I have done:

# How To Add Bulk Actions to your Custom Entity

Therefore, it is necessary to create different items in Drupal 9/10 as code:

* Plugin Field `Bulk Action Form`: adds possibility to have checkboxes and action dropdown in your view (until now action dropdown is empty)
* Plugin Action `ActionBase`: add functionality to action dropdown entry
* config files `install/system.action.YOUR_ACTION.yml` and `scheme/YOUR_NAME.scheme.yml`: connect bulk form and ActionBase-Class via file and field names
* add an update hook into your module to activate new schema

## Plugin Field "Bulk Action Form"

* path: `my_module/src/Plugin/views/field/MyBulkForm.php`
* must extend from `Drupal\views\Plugin\views\field\BulkForm`
* id `my_bulk_form` in comment `@ViewsField` is necessary for later usage
* example code:
```
<?php

namespace Drupal\my_module\Plugin\views\field;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\views\Plugin\views\field\BulkForm;

/**
 * Defines a user operations bulk form element.
 *
 * @ViewsField("my_bulk_form")
 */
class MyBulkForm extends BulkForm {
  /**
   * {@inheritdoc}
   */
  protected function emptySelectedMessage(): string|TranslatableMarkup {
    return $this->t('Nothing selected.');
  }
}

```

## Plugin Action "ActionBase"

* path: `my_module/src/Plugin/Action/MyAction.php`
* must extend `Drupal\Core\Action\ActionBase`
* example code:
```
<?php
namespace Drupal\my_module\Plugin\Action;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Action\ActionBase;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Session\AccountInterface;
use Drupal\my_module\Entity\MyCustomEntityInterface;

/**
* My Action
*
* @Action(
*   id = "my_action_id",
*   label = @Translation("My Action shown in dropdown"),
*   type = "my_custom_entity_id"
* )
*/
class MyAction extends ActionBase {

  /**
   * @inheritDoc
   */
  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE): bool|AccessResultInterface {
    // TODO: Implement access() method.
    return true;
  }

  /**
   * @inheritDoc
   */
  public function execute(MyCustomEntityInterface $entity = NULL): void {
    if (isset($entity)) {
      try {
        $entity->delete();
      } catch (EntityStorageException $e) {
        \Drupal::logger('my_module')->error("Error while deleting custom entity: " . $e->getMessage());
      }
    }
  }
}

```

## config files

* config files somehow connect Action and Bulk Form, so in the Bulk From dropdown contains the desired action
* config install file:
    + path to install yml file: `my_module/config/install/system.action.my_action.yml`
    + example code:
```
langcode: en
status: true
dependencies:
module:
  - my_module
id: my_action_id # id used in annotation "id" of MyAction.php
label: 'My Action' # text shown in dropdown
type: my_custom_entity_id # id of your custom entity which is this action for
plugin: my_action_id
configuration: {  }

```
* config schema file:
    + path: `my_module/config/schema/somename.schema.yml`
    + example code:
```
action.configuration.my_action:
type: action_configuration_default
label: 'My Action'

```

## Update hook

* path: my\_module/my\_module.module
* code example:

```
function my_module_update_9501(&$sandbox){
  $config_installer = \Drupal::service('config.installer');
  $config_installer->installDefaultConfig('module', 'my_module');
}

```
> 0 votes

---
Tags: views, 8, actions
---


# Question
Title: How to access the node/term field-values in a cleaner way?
My code is filled with methods like these to access field values:

```
\Drupal::entityTypeManager()->getStorage('node')->get('field_name')->getValue()[0]['value'];
\Drupal\taxonomy\Entity\Term::load($tid)->get('field_name')->getValue()[0]['value'];
\Drupal::routeMatch()->getParameter('node')->get('field_name')->getValue()[0]['value'];
\Drupal::routeMatch()->getParameter('node')->get('field_entity')->getValue()[0]['target_id'];
\Drupal::routeMatch()->getParameter('node')->get('field_link')->getValue()[0]['title'];

```

And in twig templates:

```
content.field_name[0]['#context']['value']
item.entity.field_tech_spec_name.0.value
item.entity.field_image_link.0.url

```

Surely there has to be a more correct and aesthetic way to get these, which I am missing. Sorry for such a basic question.

# Answer
You can use magic getter methods like `$entity->field_name->database_column` to get the first value of a field:

```
$node->field_name->value;
$node->field_entity->target_id;
$node->field_link->title;

```

etc

This will get the first value of that field (and will not work with multi cardinality fields). If that is *"cleaner"*... there are people who claim magic getters are plain evil. A more practical downside is that your IDE's Intellisense/autocompletion will not work with magic getters.
> 3 votes

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


# Question
Title: How can I change the label of the title field "Name" of my taxonomy?
I want to customize the title label of my taxonomy, the name field. By default, its value is "Name".

I know I can use the `mymodule_form_alter` hook and do as followed:

```
$form['title']['widget'][0]['#title'] = t('My Custom Name');

```

But I want to do it in the UI and export the configurations like any other fields. Also, I want to be able to translate my custom name.

# Answer
Use the Base Field Override UI, go to "Structures" \> "Taxonomies" \> "Manage fields" and go to the new "Base Field Override" tab. You can override the "Name" field here and translate it.
> 2 votes

---
Tags: taxonomy-terms, 9
---


# Question
Title: Solr autocomplete does not work for Product Variations
I am trying to create a sitewide search using Solr. For this, I indexed Product Variations and Content entities as Rendered HTML Output. When I try to search for a content entity, the autocomplete works and gives me the results, but it fails to give the results for Product Variations. The search itself works both for Content and Commerce entities. I am using Search API Solr with version 4.2 and Search API Autocomplete with version 1.7.

# Answer
Search API autocomplete requires a canonical links for entities to build suggestions list. Even if there is a result from index server, if it can't build a link, this result will be ignored. In your case, product variation simply doesn't have a canonical link, see https://git.drupalcode.org/project/commerce/-/blob/8.x-2.x/modules/product/src/Entity/ProductVariation.php#L79-90 Adding a canonical link will fix the issue. I have found a patch here https://www.drupal.org/project/commerce/issues/3025860#comment-14597209
> 2 votes

---
Tags: commerce, search, 9
---


# Question
Title: How to know how many nodes my website has?
In `/admin/content` no specific number of nodes is available.

How to know how many nodes my website has, preferably without installing a module?

I want to know how many nodes I have in general, not of a specific content type.

* I didn't find any native Drush command.
* I personally would prefer `Bash` or JavaScript over PHP to count if I can.

# Answer
The default `/admin/content` list is just another view. You can configure that view and temporarily add a result summary widget plugin in the header, which you can configure to get the total (it's the thing you use to render the "Showing X of TOTAL").
> 3 votes

# Answer
Use an entity query:

```
$count = \Drupal::entityQuery('node')->accessCheck(FALSE)->count()->execute();

```

You can run this from a Bash shell with `drush ev "..."` or in an interactive PHP shell:

```
drush php
> \Drupal::entityQuery('node')->accessCheck(FALSE)->count()->execute();
= 123

```
> 2 votes

---
Tags: 9
---


title: How do I get a list of bundles?

text:
# Question
Title: How do I get a list of bundles?
In Drupal 8+, how do I programmatically get a list of bundles for an entity type, for example the list of content types. Specifically, I'm looking for the machine names.

# Answer
> 21 votes
To get the bundles for an entity type, use the *entity\_type.bundle.info* service.

```
$bundle_info = \Drupal::service('entity_type.bundle.info')->getBundleInfo($entity_type);

```

As usual, use dependency injection whenever possible.

See `EntityTypeBundleInfo::getBundleInfo()` for more information. In particular, see what the method returns.

> An array of bundle information where the outer array is keyed by the bundle name, or the entity type name if the entity does not have bundles. The inner arrays are associative arrays of bundle information, such as the label for the bundle.

As example of Drupal core code that uses that service, see `content_translation_entity_extra_field_info()`.

```
$extra = [];
$bundle_info_service = \Drupal::service('entity_type.bundle.info');
foreach (\Drupal::entityManager()->getDefinitions() as $entity_type => $info) {
  foreach ($bundle_info_service->getBundleInfo($entity_type) as $bundle => $bundle_info) {
    if (\Drupal::service('content_translation.manager')->isEnabled($entity_type, $bundle)) {
      $extra[$entity_type][$bundle]['form']['translation'] = [
        'label' => t('Translation'),
        'description' => t('Translation settings'),
        'weight' => 10,
      ];
    }
  }
}

return $extra;

```

# Answer
> 8 votes
If you want to get bundles of an entity type via drush the command is

```
drush php-eval "print_r(array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo('ENTITY_TYPE')));"

```

# Answer
> 0 votes
It´s basically the same answer as above, but the function returns an array with **all bundles** e.g all entity types and all their bundles , i´m still pasting this here for convenience in case anyone might find this useful.

```
 DI service-names:
  - '@entity_type.manager'
  - '@entity_field.manager'
  - '@entity_type.bundle.info'

```

---

```
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;

```

---

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

  /**
   * The entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * The entity type bundle info.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $entityTypeBundleInfo;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
    $this->entityTypeManager = $entity_type_manager;
    $this->entityFieldManager = $entity_field_manager;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
  }

```

---

```
  public function getEntityTypesWithBundles() {
    $types_with_bundles = [];
    foreach($this->entityTypeManager->getDefinitions() as $entity_name => $entity_definition) {
      $types_with_bundles[$entity_name] = [
        "machine_name" => $entity_name,
        "bundles" => []
      ];
    }
    foreach ($types_with_bundles as $entity_type_key => &$entity_type) {
      foreach ($this->entityTypeBundleInfo->getBundleInfo($entity_type_key) as $bundle => $bundle_info) {
        $entity_type['bundles'][] = $bundle;
      }
    }
    return $types_with_bundles;
  }

```

---
Tags: 8, entities
---


# Question
Title: How can I change allowed tags in CKEditor 5?
How do I add `<i>` in CKeditor 5 without hacking a core module?

In *Text formats and editor*, for the allowed HTML tags, the following text is shown-

> With CKEditor 5 this is a read-only field. The allowed HTML tags and attributes are determined by the CKEditor 5 configuration. Manually removing tags would break enabled functionality, and any manually added tags would be removed by CKEditor 5 on render.

Adding the `<i>` in Source editing to allow for it.

Using the newly added tag for font awesome just ends up stripping the tag out anyway.

# Answer
> 10 votes
Like in earlier Drupal versions WYSIWYG editor settings can be configured per text format. For example, under /admin/config/content/formats/manage/basic\_html you configure the editor used for the "Basic HTML" text format.

---

In CKEditor 5 the allowed HTML tags can now be found in the "Source editing" plugin settings where you add all HTML tags that are not already covered by any other enabled plugin.

---

If you want to use the `<i>` tag for italic text you can simply add the italics button to the active toolbar – done.

# Answer
> 0 votes
As I understand it the question is “how do you add a custom button to the CKEditor?”

*If that is the question,* that is documented: https://www.drupal.org/docs/core-modules-and-themes/core-modules/ckeditor-5-module/plugin-and-contrib-module-development

# Answer
> 0 votes
There no longer seems to be a source editing field. It's just this read-only field with the tooltip: "With CKEditor 5 this is a read-only field. The allowed HTML tags and attributes are determined by the CKEditor 5 configuration. Manually removing tags would break enabled functionality, and any manually added tags would be removed by CKEditor 5 on render" with no guidance whatsoever on how to update the allowed HTML tags with "CKEditor 5 configuration".

---
Tags: wysiwyg, 10
---


# Question
Title: How to display more than 10 items in link widget autocomplete?
This is a question about the Link module. Since with the Link module you can enter external or internal links both, we strongly rely on it.

Unfortunately the number of items to be displayed from its autocomplete field is limited to 10. We have a lot of nodes with nearly identical titles and so it comes that the node we are searching for doesn't get displayed in the autocomplete field when there are more than 10 matching titles.

The limit is hardcoded in `core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php`. Is there an elegant way to increase this little number from within a custom module? Do I have to extend `class EntityAutocompleteMatcher`? Where would I have to place my extension and how to ensure it gets executed from within the link widget?

# Answer
> 9 votes
I suppose overriding *EntityAutocompleteMatcher* will affect all autocomplete form elements on your site. So that I would create a new entity selection plugin instead because it is more granular approach. The plugin could be enabled per field. Here is an example of such a plugin. https://drupal.stackexchange.com/a/220136/433

In your case the implementation would be even more trivial:

File: *modules/example/src/Plugin/EntityReferenceSelection/ExampleSelection.php*

```
namespace Drupal\example\Plugin\EntityReferenceSelection;

use Drupal\node\Plugin\EntityReferenceSelection\NodeSelection;

/**
 * Entity reference selection.
 *
 * @EntityReferenceSelection(
 *   id = "example:node",
 *   label = @Translation("Example node"),
 *   group = "example",
 * )
 */
class ExampleSelection extends NodeSelection {

  /**
   * {@inheritdoc}
   */
  public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
   return parent::getReferenceableEntities($match, $match_operator, 25);
  }

}

```

Using NodeSelection as base class instead of DefaultSelection would allow you to filter referenced nodes by their status. Note that referencing other entity types is not supported yet.

Unlike entity reference link widget does not allow to specify selection plugin through user interface, therefore you need to set it programmatically using hook\_field\_widget\_WIDGET\_TYPE\_form\_alter().

```
/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function example_field_widget_link_default_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
  // Replace default selection handler to increase limit of displayed entities.
  $element['uri']['#selection_handler'] = 'example:node';
}

```

It is important that the plugin ID contains a semicolon.

# Answer
> 10 votes
If you can live with overriding all of the autocomplete limits, you can override a core service in Drupal 8;

The service you need to override is here in core.services.yml:

```
  entity.autocomplete_matcher:
    class: Drupal\Core\Entity\EntityAutocompleteMatcher
    arguments: ['@plugin.manager.entity_reference_selection']

```

In your custom module, add a class that implements ServiceModifierInterface

```
namespace Drupal\mymodule;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

class MyModuleServiceProvider implements ServiceModifierInterface {

  /**
   * Modifies existing service definitions.
   *
   * @param ContainerBuilder $container
   *   The ContainerBuilder whose service definitions can be altered.
   */
  public function alter(ContainerBuilder $container) {

    for ($id = 'entity.autocomplete_matcher'; $container->hasAlias($id); $id = (string) $container->getAlias($id));
    $definition = $container->getDefinition($id);
    $definition->setClass('Drupal\mymodule\Entity\EntityAutocompleteMatcherCustom');
    $container->setDefinition($id, $definition);
  }

}

```

Then copy EntityAutocompleteMatcher.php into your module at /src/Entity/EntityAutocompleteMatcherCustom.php

Then update the hardcoded 10 to a 50, or whatever limit you'd like:

```
namespace Drupal\mymodule\Entity;

use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Tags;
use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface;
use Drupal\Core\Entity\EntityAutocompleteMatcher;

/**
 * Matcher class to get autocompletion results for entity reference.
 */
class EntityAutocompleteMatcherCustom extends EntityAutocompleteMatcher {

  /*
   * {@inheritdoc]
   */
  public function getMatches($target_type, $selection_handler, $selection_settings, $string = '') {

    $matches = array();

    $options = array(
      'target_type' => $target_type,
      'handler' => $selection_handler,
      'handler_settings' => $selection_settings,
    );
    $handler = $this->selectionManager->getInstance($options);

    if (isset($string)) {
      // Get an array of matching entities.
      $match_operator = !empty($selection_settings['match_operator']) ? $selection_settings['match_operator'] : 'CONTAINS';
      // Changing limit from 10 to 50.
      $entity_labels = $handler->getReferenceableEntities($string, $match_operator, 50);

      // Loop through the entities and convert them into autocomplete output.
      foreach ($entity_labels as $values) {
        foreach ($values as $entity_id => $label) {
          $key = "$label ($entity_id)";
          // Strip things like starting/trailing white spaces, line breaks and
          // tags.
          $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(Html::decodeEntities(strip_tags($key)))));
          // Names containing commas or quotes must be wrapped in quotes.
          $key = Tags::encode($key);
          $matches[] = array('value' => $key, 'label' => $label);
        }
      }
    }

    return $matches;
  }

}

```

Obviously override core services has some risks, but it's cool that you can do this.

**What are the risks of overriding a core service?**

1) You may lose the benefits of updates when you update core. If there is a critical security fix in the service, and your altered copy has the security hole, you will not benefit from the community updating that code.

2) Other modules you install may have dependencies to the original service with its original feature set. So let's say there is some code in another module that will break if the number of autocomplete entries are greater than or less than 10, you won't know about it, until it affects you.

3) It makes your codebase harder to maintain. You have to remember that you are not using core Drupal, but an extended version. Other developers who join your project after you left may have a hard time figuring out why a service is behaving in a non-standard way.

**Is this hacking core?**

Depends on how you look at it. It's not going into the core module and changing code. It's not even creating a patch and applying it and tracking it with a package manager such as composer. It's more of a one-off customization that alters a sites core behavior, similiar to an ALTER hook. It's more self-contained that a core hack, because it's within your own custom module on your site. So core updates to the original service will not be affected, the same way as if you patched or hacked the original service code.

But it does have some of the same risks as hacking core, as mentioned above.

In the original question, the issue was the node titles are not unique enough. The better solution, other than changing the limit globally on drop downs would be solve the uniqueness problem.

What I would suggest is to add a new field field\_display\_title and use that on the page, and if you need it another field field\_teaser\_title for display on list pages where you need a shorter title. Then the actual title that gets pulled into entity reference select dropdown can be useful to your editors and be unique, such as "My Article (page 1)" if the issue is each page has the same title. Then you don't have to override a core service.

When you come across a problem with Drupal, try to find the solution that requires the least amount of custom code. This makes your site more stable, easier to maintain and saves you time.

# Answer
> 5 votes
An other easy way to modify the number of results is to alter the range value in the query:

```
/**
 * Implements hook_query_TAG_alter() for entity reference selection handlers.
 *
 * We like tho show always 30 results instead of the 10 definied in EntityAutocompleteMatcher::getMatches()
 */
function MODULE_query_entity_reference_alter(AlterableInterface $query) {
  $query->range(0, 30);
}

```

# Answer
> 5 votes
It looks like a proper fix for this has been added to the latest version of core, 8.8+, see #2863188 Hardcoded result size limit in the entity reference autocomplete widget.

# Answer
> 3 votes
@Weri, I would avoid doing that, having just implemeted your suggestion and spent the best part of a day trying to fix another issue.

The query alter you suggest also affects entiry reference when linking paragraphs to nodes. A node I was woking on had 80+ paragraph item before I added the alter. Once added I was unable to save the node. Removing/Commenting out the alter fixed the issue.

**Update**

Wrapping the $query-\>range() in a route check fixes the issue for me, example,

```
function mymodule_query_entity_reference_alter($query) {
  $routeMatch = \Drupal::routeMatch();
  if ($routeMatch->getRouteName() == 'system.entity_autocomplete') {
    $query->range(0, 20);
  }
}

```

# Answer
> 1 votes
There is an issue on Drupal.org to extend link widget to have limit and operator settings the same way as for entity reference autocomplete widget https://www.drupal.org/project/drupal/issues/3341689#comment-15141098

---
Tags: 8, navigation, ajax
---


# Question
Title: Deleting entities using Batch API without a form or user interface
In a custom Drupal 9 module, I need to delete entities using Batch API without a form or user interface. The list of entity IDs are generated and the batch is built in hook\_views\_post\_execute(). When the View path is accessed, I can confirm the batch is successfully created by noting the new record in the "batch" database table. However, the batch is never processed and none of the entities are deleted. Running cron has no effect.

I'm obviously missing the mechanism to execute the batch. How does the batch get processed repeatedly until all the entities are deleted?

Again, I just want the batch to process transparently. For this reason, I suspect the batch message properties don't need to be defined.

```
use Drupal\views\ViewExecutable;
use Drupal\Core\Batch\BatchBuilder;

/**
 * Implements hook_views_post_execute().
 */
function custom_views_post_execute(ViewExecutable $view) {
  if ($view->id() == 'results_delete_by_teacher' && $view->current_display == 'results_delete') {
    if (count($view->result)) {

      // Create a new batch.
      $batchBuilder = new BatchBuilder();
      $batchBuilder->setTitle('Deleting entities')
        ->setFinishCallback('custom_batch_delete_entities_finished')
        ->setInitMessage('Starting to delete entities.')
        ->setProgressMessage('Deleted @current out of @total entities.')
        ->setErrorMessage('An error occurred while deleting entities.');

      foreach ($view->result as $id => $result) {
        $batchBuilder->addOperation('custom_batch_delete_entity', ['result', $result->id]);
        $batchBuilder->addOperation('custom_batch_delete_entity', ['file', $result->result_field_data_id]);
      }

      // Start the batch.
      batch_set($batchBuilder->toArray());
      return batch_process('user');
    }
  }
}

/**
 * Batch operation callback to delete an entity.
 */
function custom_batch_delete_entity($type, $entity_id, &$context) {
  // Load and delete the result entity.
  $entity = \Drupal::entityTypeManager()->getStorage($type)->load($entity_id);
  $entity->delete();

  // Update the progress information.
  $context['message'] = t('Deleted entity with ID @id', ['@id' => $entity_id]);
  $context['results'][] = $entity_id;
}

/**
 * Batch finished callback.
 */
function custom_batch_delete_entities_finished($success, $results, $operations) {
  if ($success) {
    \Drupal::logger('custom')->notice('All entities deleted successfully.');
  }
  else {
    \Drupal::logger('custom')->error('An error occurred during entity deletion.');
  }
}

```

# Answer
Without a page (which could also contain a form) rendered in a browser, the batch API operations do not work, since it is the browser that calls the URL which makes the batch progress.

As the comments said, the way to go is using the queue API via a *@QueueWorker* plugin, which is invoked when cron tasks run. This means you cannot expect that all the items in the queue are quickly handled, especially when there are many queued items, but this does not depend from a browser that initializes the batch API operations and stay connected to the server for all the time required from the batch API operations. (If the browser loses the connection with the server, the batch API operations are not completed.)

This requires to define a plugin class that uses the `@QueueWorker` annotation, which must use the `Drupal\[module_machine_name]\Plugin\QueueWorker` namespace (`[module_machine_name]` must be replaced by the module machine name, for example `aggregator` for the Aggregator module). The plugin class, which usually extends `Drupal\Core\Queue\QueueWorkerBase`, must define the `processItem()` method, as requested by `Drupal\Core\Queue\QueueWorkerInterface`, which receives the items added to the queue, one at time. The plugin ID is also the ID for the queue used for the items.

The hook that adds items to the queue just needs to get the queue with `$queue = \Drupal::queue('[queue_name]');` (replace `'[queue_name]'` with the string containing the queue name) and add items to the queue with `$queue->createItem($object_or_array);`.

As concrete example, see what the Aggregator module does. It adds items in the queue in a `hook_cron()` implementation, but that can be done on any hook implementation, or even a method or a function that is not a hook implementation.

### aggregator.module

```
function aggregator_cron() {
  $queue = \Drupal::queue('aggregator_feeds');
  $request_time = \Drupal::time()->getRequestTime();
  $ids = \Drupal::entityTypeManager()->getStorage('aggregator_feed')->getFeedIdsToRefresh();
  foreach (Feed::loadMultiple($ids) as $feed) {
    if ($queue->createItem($feed)) {
      $feed->setQueuedTime($request_time);
      $feed->save();
    }
  }

  $ids = \Drupal::entityQuery('aggregator_feed')
    ->accessCheck(FALSE)
    ->condition('queued', $request_time - 3600 * 6, '<')
    ->execute();
  if ($ids) {
    $feeds = Feed::loadMultiple($ids);
    foreach ($feeds as $feed) {
      $feed->setQueuedTime(0);
      $feed->save();
    }
  }
}

```

### core/modules/aggregator/src/Plugin/QueueWorker/AggregatorRefresh.php

```
namespace Drupal\aggregator\Plugin\QueueWorker;

use Drupal\aggregator\FeedInterface;
use Drupal\Core\Queue\QueueWorkerBase;

/**
 * Updates a feed's items.
 *
 * @QueueWorker(
 *   id = "aggregator_feeds",
 *   title = @Translation("Aggregator refresh"),
 *   cron = {"time" = 60}
 * )
 */
class AggregatorRefresh extends QueueWorkerBase {

  /**
   * {@inheritdoc}
   */
  public function processItem($data) {
    if ($data instanceof FeedInterface) {
      $data->refreshItems();
    }
  }

}

```

As clear from the code, items added to the queue can also be objects. The `processItem()` method will receive them in its `$data` parameter, and it will be able to call any public method they have.
> 3 votes

# Answer
Thanks to @apaderno for his explanation of Queue API.

Here's the working code for my particular need, which is queuing entities for deletion from Views results. In my case, I want to delete a custom entity and the file entity reference. Once the View has executed, the "queue" database table contains the corresponding number of results. Running cron will proceed to delete the records and physical files as expected.

**modules/custom/custom/custom.module**

```
/**
 * Implements hook_views_post_execute().
 */
function custom_views_post_execute(ViewExecutable $view) {
  if ($view->id() == 'results_delete_by_teacher' && $view->current_display == 'results_delete') {
    if (count($view->result)) {
      $queue = \Drupal::queue('custom_entity_delete');

      foreach ($view->result as $id => $result) {
        // Add the entities to the deletion queue.
        $queue->createItem([
          'entity_type' => 'result',
          'entity_id' => $result->id,
        ]);
        $queue->createItem([
          'entity_type' => 'file',
          'entity_id' => $result->result_field_data_id,
        ]);
      }

      \Drupal::logger('custom')->notice('Queued @count result entities for deletion.', ['@count' => count($view->result)]);
    }
  }
}

```

**modules/custom/custom/src/Plugin/QueueWorker/customEntityDelete.php**

```
namespace Drupal\custom\Plugin\QueueWorker;

use Drupal\Core\Queue\QueueWorkerBase;

/**
 * Provides a QueueWorker for deleting entities.
 *
 * @QueueWorker(
 *   id = "custom_entity_delete",
 *   title = @Translation("Entity delete queue"),
 *   cron = {"time" = 60}
 * )
 */
class customEntityDelete extends QueueWorkerBase {

  /**
   * {@inheritdoc}
   */
  public function processItem($data) {
    // Load and delete the entity.
    $entity = \Drupal::entityTypeManager()->getStorage($data['entity_type'])->load($data['entity_id']);

    if ($entity) {
      $entity->delete();
      \Drupal::logger('custom')->notice('Deleted entity @type with ID: @id', ['@type' => $data['entity_type'], '@id' => $data['entity_id']]);
    }
  }
}

```

**modules/custom/custom/custom.services.yml**

```
services:
  custom.entitiy_delete:
    class: Drupal\custom\Plugin\QueueWorker\customEntityDelete
    tags:
      - { name: queue_worker }

```
> 0 votes

---
Tags: views, hooks, batch-operations
---


# Question
Title: How can I use the core link field widget with title and URL in a custom form?
I want to add a link field to my custom form.
Below is the code that I have been trying to use but no success. So can anyone let me know how to use core link field in a custom form in Drupal8?
The below code works for Drupal7 but not for Drupal8. I have also tried using #type =\> 'link' in the below code.

```
$form['cta'] = [
  '#type' => 'link_field',
  '#field_name' => 'link_field',
  '#field_parents' => array(),
  '#delta' => 0,
];
return $form;

```

# Answer
Thanks for the comments, both of you have actually redirected me in the right direction. Below are the actual steps that I took to achieve this:

* Create a link field (field\_url) in one of the content types using admin UI. and use the below code to use that field widget in your custom form or custom block.

```
$form['#parents'] = [];
// Create an empty representative entity.
$node = \Drupal::service('entity_type.manager')->getStorage('node')->create([
  'type' => 'upcoming_webinar',
]
);
// Get the EntityFormDisplay (i.e. the default Form Display) of this content type.
$entity_form_display = \Drupal::service('entity_type.manager')->getStorage('entity_form_display')
  ->load('node.upcoming_webinar.default');
// Get the body field widget and add it to the form.
// Returns the widget class.
if ($widget = $entity_form_display->getRenderer('field_url')) {
  // Returns the FieldItemsList interface.
  $items = $node->get('field_url');
  $items->filterEmptyItems();
  // Builds the widget form and attach it to your form.
  $form['field_url'] = $widget->form($items, $form, $form_state);
  $form['field_url']['#access'] = $items->access('edit');
}

```
> 0 votes

# Answer
To make: Custom Custom url field behave similar like as core link widget's url field(that add from backend) : then can add additional attributes: 'element\_validate', 'attributes' etc

Code:

```
$form['resource_fieldset']['design_tool_link'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  '#title' => $this->t('Design Tool Link'),
  '#description' => $this->t('Select Design Tool Link'),
  '#required' => TRUE,
  '#element_validate' => [
    [
      'Drupal\link\Plugin\Field\FieldWidget\LinkWidget',
      'validateUriElement',
    ],
  ],
  '#attributes' => [
    'data-autocomplete-first-character-blacklist' => '/#?',
  ],
  '#process_default_value' => FALSE,
  '#default_value' => $design_tool_link ?? : '',
];

```

Note: by adding #element\_validate attribute :

* Custom Url field 'll accept external & internal links as default core link widget's URL field do
* Also validation of core link 'll applied instead of writing same validation again
> 1 votes

# Answer
I think you have to create two seperate form fields to do this in Drupal 8.

You can use `textfield` for the title and `url` for the URL field, like this:

```
$form['cta_title'] = [
  '#type' => 'textfield',
  '#title' => t('CTA Title'),
];

$form['cta_url'] = [
  '#type' => 'url',
  '#title' => t('CTA Url'),
];

return $form;

```

Another solution is to pull the widget out from an entity display. There is a guide how to do that here, https://www.webomelette.com/how-render-entity-field-widgets-inside-custom-form-drupal-8.

Basically you load the entity display,

```
$entity = $this->entityTypeManager->getStorage('node')->create(['type' => 'article']);
$form_display = $this->entityTypeManager->getStorage('entity_form_display')->load('node.article.custom_form_display');

```

And then you pull out the widgets and add them to your form,

```
foreach ($form_display->getComponents() as $name => $component) {
  $widget = $form_display->getRenderer($name);
  if (!$widget) {
    continue;
  }

  $items = $entity->get($name);
  $items->filterEmptyItems();
  $form[$name] = $widget->form($items, $form, $form_state);
  $form[$name]['#access'] = $items->access('edit');
}

```
> 0 votes

# Answer
If you have a link field attached to any entity like a node bundle, or user or ... then you can use a code like this:

```
// Create an empty representative entity.
$node = \Drupal::service('entity_type.manager')
  ->getStorage('node')->create(['type' => 'article']);

// Get the EntityFormDisplay (i.e. the default Form Display) of this content
// type.
$entity_form_display = \Drupal::service('entity_type.manager')
  ->getStorage('entity_form_display')->load('node.article.default');

// Get the body field widget and add it to the form.
if ($widget = $entity_form_display->getRenderer('body')) { // Returns the widget class.
  $items = $node->get('body'); // Returns the FieldItemsList interface.
  $items->filterEmptyItems();
  $form['body'] = $widget->form($items, $form, $form_state); // Builds the widget form and attach it to your form.
  $form['body']['#access'] = $items->access('edit');
}

```
> 0 votes

# Answer
Core's link field actually uses a `'#type' => 'url'` form element as base and if the field is configured to support internal links it switches to `'#type' => 'entity_autocomplete'`. See /core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php L186-203

So if you just want to be able to select entities go for `'#type' => 'entity_autocomplete'`.

```
$form['cta'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
];

```

And if you want to be able to type external URLs there as well you need to override the element validation yourself. Nonetheless you need to add your own simple `'#type' => 'textfield'` element to pick up a user entered title. Same as the link widget does it.
> 0 votes

---
Tags: 8, forms
---


# Question
Title: How can I copy a field to another field?
I have an *Article* content type for which I want to change the machine name of its fields. I created new fields with a different machine name.

How do I copy the old fields to the new fields?

# Answer
> 2 votes
You can run this, in hook\_update\_N():

```
$storage = \Drupal::entityTypeManager()->getStorage('node');
// Load all the nodes IDs for nodes that don't have the new value set.
$nids = $storage->getQuery()
  // Load all nodes for which the new field has no value.
  ->notExists('new_field_name')
  ->execute();

// Loop through the nodes.
foreach ($nids as $nid) {
  // Load the current node.
  $node = $storage->load($nid);
  // Set the new field name to the old field name and save.
  $node->set('new_field_name', $node->get('old_field_name')->value)
    ->save();
}

```

---
Tags: nodes, 10
---


# Question
Title: Database addExpression SUM: Call to a member function execute() on string
I need to get the `sum` of all `points` values of the user with `uid` 1 from the `test_sum_expression` table. But when I try to `execute` I get this message `Error: Call to a member function execute() on string`.

If I don't execute, I get the count 6 of the word points, as if it were counting the characters from the string points.

```
$queryPoints = $connection->select('test_sum_expression', 'n')
    ->fields('n', ['uid', 'points'])
    ->condition('n.uid', 1, '=')
    ->groupBy('n.uid')
    ->addExpression('SUM(n.points)', 'points')
    ->execute();

dpm($queryPoints);

```

# Answer
> 3 votes
This is because `addExpression()` returns the unique alias assigned to the expression, and *not* the query. You can fix this by adjusting your code as follows:

```
$query = $connection->select('test_sum_expression', 'n')
    ->fields('n', ['uid', 'points'])
    ->condition('n.uid', 1, '=')
    ->groupBy('n.uid');
$query->addExpression('COUNT(n.points)', 'points');
$queryPoints = $query->execute();

```

---
Tags: database
---


# Question
Title: Is Drupal Commerce compatible with Drupal 10?
Don't see this answered anywhere. I have Drupal 10 installed, as a dev site cohabiting with a live Drupal 7 on the same server. I don't use composer for the D7 install, but can't get it to work on the D10 install since the "php.composer.phar" (in an attempt to make modules installs and updates) command jumps to server root over which I have no control & can't update. If commerce isn't compatible maybe I'm wasting my time.

# Answer
Seems to be more of an issue of being on a compatible host server than D10.

You'll want an up to date composer too as well as being on PHP 8.1.

You should be using composer with D9/10, unless you want a world of pain.

If you are doing development, then I'd be starting on a local /staging stack.

I'd probably target D9 with CKeditor 5 to begin with. Just to save you some hassle with dealing with compatible modules. There's still a lot of D10 patches that need to be put into releases.

Using CKeditor 5, will enable a simpler D10 upgrade.

I'm using Commerce on D9 + composer no issues.
> 1 votes

# Answer
Commerce 8.x-2.36 is marked as Drupal 10 compatible: https://www.drupal.org/project/commerce
> 1 votes

---
Tags: commerce, composer
---


# Question
Title: How do I get a media entity image's url/src in a block twig file?
I have a custom block type that has a media entity field that is an image. I want to extract that image url and set it as a div background image in the html.twig file, but I can't get it to work. The twig file is block--inline-block--hero-w-title.html.twig If I do

> {{ content.field\_hero\_image\[0\] }}

it will display the rendered image with all the divs and stuff, but I can't figure out how to get the image url from content.field\_hero\_image. I have googled it in every way I can think of, and tried everything I have seen but can't figure out why nothing is working.

Do any of y'all know how to get the image url from media entity content.field\_hero\_image?

I have tried the listed and more so far:

```
content.field_hero_image|file_uri (twig_tweak. Failed due to sending an array when it was expecting object?)
content.field_hero_image|file_url (twig_tweak: returned null)
content.field_hero_image.entity.field_media_image.entity.uri.value (returned null)
content.field_hero_image.entity.uri.value (returned null)

```

# Answer
> 1 votes
The last lines look very promising for an image field nested in a media entity, you only have to start with the block content entity:

```
{{ elements.content['#block_content'].field_hero_image.entity.field_media_image.entity.uri.value }}

```

In a standard entity template, you would start with the name of the entity like `{{ node.` or `{{ paragraph.`. The block content entity doesn't have an entity template and in the block plugin template you need to look in the render element build array `elements` for the entity object.

Then use file\_url() to transform the URI to a URL.

---
Tags: media
---


# Question
Title: DBTNG sentence that sums a column from all rows of a specific user and dpm the total
This is my table `test_sum_expression` with columns:

`uid` (int) Stores the UID of the user.
`points` (int) Stores a number.

I have this SQL sentence which `SUMS` all `points` from user with `uid` 1.

```
SELECT uid, SUM(points) AS total_points
FROM `test_sum_expression`
WHERE uid = 1
GROUP BY UID;

```

Which produces

How can I produce this same sentence in DBTNG (Database: The Next Generation) format? I mean something like this: `$query = $connection->select('test_sum_expression', 'n')...`

I have tried this

```
$query = $connection->select('test_sum_expression', 'n')
  ->fields('n', ['uid', 'points'])
  ->condition('n.uid', 1, '=')
  ->groupBy('n.uid');
$query->addExpression('SUM(n.points)', 'total_points');
$queryPoints = $query->execute();

dpm($queryPoints);

```

But without success, it produces `$queryPoints Drupal\Core\Database\StatementWrapper#456238 (3)`. I need to be able to get the total\_points.

# Answer
> 1 votes
`$query->execute()` returns an object that implements `StatementInterface`. To get the table columns matching that query you need to either loop over that object or call one of the methods defined from that interface.

Since you are only interested to the sum of the points, I would use the following code.

```
$query = $connection->select('test_sum_expression')
  ->condition('uid', 1);

$query->addExpression('SUM(points)', 'total_points');

$total_points = $query->execute()->fetchField();

```

---
Tags: database
---


# Question
Title: Adding template suggestions for a view with display ID
I need to have suggestions for views to create dedicated template. Actually I've this in my .theme:

```
function starter_d9_2022_theme_suggestions_views_view_alter(array &$suggestions, array $variables) {
  $suggestions[] = 'views_view__' . $variables['view']->id();
}
function starter_d9_2022_theme_suggestions_views_view_unformatted_alter(array &$suggestions, array $variables) {
  $suggestions[] = 'views_view_unformatted__' . $variables['view']->id();
}
function starter_d9_2022_theme_suggestions_views_view_list_alter(array &$suggestions, array $variables) {
  $suggestions[] = 'views_view_list__' . $variables['view']->id();
}

```

This provide:

```
<!-- FILE NAME SUGGESTIONS:
   x views-view--acces-rubriques-2019.html.twig
   x views-view--acces-rubriques-2019.html.twig
   x views-view--acces-rubriques-2019.html.twig
   * views-view.html.twig
-->

```

File is working,but code inside doesn't display views content. Anyway, I would to use a more specific template, by display like:

```
views-view--acces-rubriques-2019--list--block-1.html.twig

```

How can I add this to my actual code ? Regards

# Answer
> 0 votes
This looks like a simple task. To achieve your desired template suggestion, you can add another suggestion that concatenates the display ID of the view. Here's how you can modify your code:

```
function starter_d9_2022_theme_suggestions_views_view_alter(array &$suggestions, array $variables) {
  $view = $variables['view'];
  $suggestions[] = sprintf('views_view__%s', $view->id());
  // Add a more specific template suggestion for the list display.
  $suggestions[] = sprintf('views_view__%s__%s', $view->id(), $view->getDisplay()->display['id']);
}

function starter_d9_2022_theme_suggestions_views_view_list_alter(array &$suggestions, array $variables) {
  $view = $variables['view'];
  $suggestions[] = sprintf('views_view_list__%s', $view->id());
  // Add a more specific template suggestion for the list display.
  $suggestions[] = sprintf('views_view_list__%s__%s', $view->id(), $view->getDisplay()->display['id']);
}

```

The template suggestion will follow the pattern views-view--\<view\_id\>--\<display\_id\>.html.twig and views-view-list--\<view\_id\>--\<display\_id\>.html.twig as example.

Don't forget to clear the Drupal cache after making these changes so that the new template suggestions can take effect.

I hope this helps!

---
Tags: views, theming, 9
---


# Question
Title: How to prevent empty field wrapper from rendering in views
In views I display fields for specific content types. One field is referenced to taxonomy term. Not every node has the term reference. I need to style this field with paddings and colours so I would want it not to be rendered at all if term reference is missing. I have chosen under "no result behaviour" in field settings in views to "hide if empty" and "hide rewriting if empty". However, the two divs still get rendered in HTML at empty fields.. (.views-field and inside .field-content).

Is this expected behaviour? I tried to fix it with twig template (views-view-fields), but I can't seem to find solution of how to check for empty content (null or empty don't work on field.content as it returns length\>0, I suppose the html is already in field.content)

# Answer
> 1 votes
It may seem a bit ugly solution, but if you wanna avoid a template override you can archive this effect simply by using the css selector `:empty` on the divs, something like:

```
div.class:empty {
  display: none;
}

```

---
Tags: views
---


title: Can I set default access settings?

text:
# Question
Title: Can I set default access settings?
The Webform module defaults to allowing anonymous and authenticated users to submit a form.

The vast majority of the webforms we use are for internal staff that have a particular Drupal role.

Is there a setting for defaulting to a particular role/roles when creating a new form? There seems to be for everything else.

We are using Drupal 9.5.x and Webform 6.1.x.

# Answer
> 3 votes
Looking at webform.api.php there is a specific hook for that:

```
/**
 * Implements hook_webform_access_rules_alter().
 */
function mymodule_webform_access_rules_alter(array &$access_rules) {
  if (isset($access_rules['create'])) {
    $access_rules['create']['roles'] = ['editor', 'moderator'];
  }
}

```

---
Tags: webforms, 9
---


# Question
Title: How can I prevent a specific node type from caching for anonymous users (when using hook_node_access)?
I am using `hook_node_access` to decide the whether a node should be visible to anonymous users based on their IP address. To prevent this being cached I am using `\Drupal::service('page_cache_kill_switch')->trigger()` within `hook_node_view_alter`, but if access is forbidden then `hook_node_view_alter` is not run and so the cache is not killed.

Where should I put `\Drupal::service('page_cache_kill_switch')->trigger()`? Is there a better way to do this?

# Answer
> 1 votes
I wouldn't use hook\_node\_access, it's rather static and with additional caching layers because it's called a lot of times, not only for incoming routes. IP-based code is best placed in a middleware or a request event subscriber with a higher priority. If you want to try the hook solution then put both, the kill switch and the access denied exception, in the same hook\_node\_view\_alter and add a cache max age as well:

```
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

  if ($node->getType() == 'article') {
    $build['#cache']['max-age'] = 0;
    \Drupal::service('page_cache_kill_switch')->trigger();
    if (...) {
      throw new AccessDeniedHttpException();
    }
  }

```

---
Tags: caching
---


# Question
Title: If conditions in twig to check if field has a value
I have used this below code to check if the field has a value

```
{% if content.field_title is not empty %}
    <p>{{ content.field_title }}</p>
{% endif %}

```

But p tag is rendering even though the field doesn't have a value. Same happening for `{% if content.field_title is not null %}` as well and `{{ dump(content.field_title) }}` is not an empty array if the field has no value. So how to check empty condition in twig for a field.

Edited: Trying to use the content object instead node/paragraph/term object. Here Verify a field is not empty used node object.

Thanks in advance!

# Answer
Quite a few ways to check. For content fields in Twig I generally prefer:

```
{% if content.field_title['#items'].getValue() %}

```
> 0 votes

---
Tags: theming
---


# Question
Title: How to write EntityQuery so that it checks user's access to nodes?
How do I write the following Drupal 8 EntityQuery so that it only returns nodes that the current user has access to?

```
$query = \Drupal::entityQuery('node')
  ->condition('type', 'article');

```

The above query will return all nodes, even unpublished ones. Depending on how you use the results (like a list of nodes), users could see titles or other information from unpublished nodes.

```
$query = \Drupal::entityQuery('node')
  ->condition('type', 'article')
  ->condition('status', 1);

```

When I add the "status" condition, I now get a list of only published nodes. But I would like people with administer nodes permission to see all the nodes.

Basically, is there a way to simulate the "admin or published" filter, like on Views?

# Answer
> 3 votes
Entity queries by default consider the node grants system, you actually have to opt out of that to get everything *when* using node grants.

The problem is that drupal core doesn't actually implement that API for the status, that only becomes relevant when using modules that do.

So unfortunately, the only way to simulate "admin or published" is to do it yourself. Check the permission, if the user doesn't have it, add the status = 1 condition. Note that views uses "administer nodes" but technically, that's actuallly wrong, "bypass node access" would make more sense, that would be consistent with what is being checked when trying to access node/ID of an unpublished node. But in your own code, you can use whatever makes sense for you, including a custom permission.

Alternatively, you could use a module like https://www.drupal.org/project/view\_unpublished, which does populate grant records and your entity query will just work. In fact, I just closed a bug report where someone reported the behavior you want as a bug when using that module: https://www.drupal.org/project/view\_unpublished/issues/2871272.

# Answer
> 2 votes
As of Drupal 9.2.0, you do it using the following:

```
// This gets all articles the current user can view.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(TRUE)
  ->condition('type', 'article')
  ->execute();

// This gets all articles that exist regardless of access.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(FALSE)
  ->condition('type', 'article')
  ->execute();

```

From https://www.drupal.org/node/3201242.

---
Tags: 8, entities
---


title: Verify a field is not empty

text:
# Question
Title: Verify a field is not empty
What is the best method to check if a field is empty in a node template.

In node--example.html.twig we can use "content" variable.

I can't use check like checking a block

```
{% if content.field_example  %}

```

I can use something like this:

```
{% if content.field_example['#object'] is defined  %}

```

But what is the best method?

# Answer
> 32 votes
Like I also wrote in How can you render fields from an entity reference in node templates? \[Drupal 8\], content is a render array that contains data prepared for displaying.

If you want to check or compare something, use the values instead, which are available on the node object.

`{% if node.field_example.value %}`.

Note that the property depends on the field type. If it's a reference field, you need to use target\_id instead. The referenced question links to a entity field API cheat sheet that lists common field types and their properties.

# Answer
> 20 votes
You can't be sure about the structure of the render array inside of content, so this is possible not the best method.

This may be a better solution:

```
{% if content.field_example|render|striptags|trim %}
  <p>field is not empty</p>
{% endif %}

```

This checks if rendering the field generates any output.

But this depends, how you have configured the field format and what you try to do. For example, you could have configured to display a label if the field is empty. Then you have to adjust this. If you don't depend on the rendered output and only want to check, if the field has a value in the database, use the node object. See Berdir's answer.

# Answer
> 10 votes
```
{% if not (node.field_whatever.isEmpty ?? true) and content.field_whatever is defined %}
  <div class="whatever_markup">
    {{ content.field_whatever }}
  </div>
{% endif %}

```

This solution is quite bullet-proof and even working in reusealbe and/or shared templates (e.g. a shared `node--teaser.html.twig` accross multiple bundles) because

* it works for all field types
* it checks if the field exists
* it checks if the field is not empty
* it checks if the field is not hidden in display mode

This should work for any entity template, e.g. you can simply replace `node.field_whatever` with `paragraph.field_whatever` in a `paragraph.html.twig` template file.

# Answer
> 6 votes
Check if field is not empty in Twig templating (**Field Collection**)
*Template*: field-collection-item--field-services.html.twig

Install Field Twig Value Module to get the value using "**|field\_value**", followed by "**is not empty**"

```
{% if content.field_work|field_value is not empty %}

       ...

{% endif %}

```

# Answer
> 1 votes
Option for content fields:

```
{% if content.field_name['#items'].getValue() %}

```

---
Tags: theming, 8
---


# Question
Title: How to use bundle classes with config entities (vocabularies)?
I'd like to use bundle classes with taxonomy vocabularies. Vocabularies are bundleable config entities inheriting from EntityBase just like nodes, term and other content entities. The doc states bundle classes should work with all entities that are a subclass of the base entity class, but I can't get it to work with config entities.

works:

```
// in my module file
function foo_entity_bundle_info_alter(&$bundles) {
  if (isset($bundles['taxonomy_term']['foo'])) {
    $bundles['taxonomy_term']['foo']['class'] = TermFoo::class;
  }
}

// ...somewhere else in my code...
// this correctly returns instanceof TermFoo
\Drupal::entityTypeManager()->getStorage('taxonomy_term')->load(123)

```

does not work:

```
// in my module file
function bar_entity_bundle_info_alter(&$bundles) {
  if (isset($bundles['taxonomy_vocabulary']['bar'])) {
    $bundles['taxonomy_vocabulary']['bar']['class'] = VocabularyBar::class;
  }
}

// ...somewhere else in my code...
// this returns instanceof \Drupal\taxonomy\Entity\Vocabulary
// but I want instanceof \Drupal\bar\Entity\VocabularyBar
\Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary')->load('bar')

```

During debugging I noticed that the hook's parameter `$bundles['taxonomy_term']` had all bundles as sub-keys, matching the recommended if-statement.

But `$bundles['taxonomy_vocabulary']` was missing all bundles, it only had a single sub-key `$bundles['taxonomy_vocabulary']['taxonomy_vocabulary']`, no bundles as keys anywhere, so the bundle class was never injected.

I then tried some dumb things in good faith like

```
function bar_entity_bundle_info_alter(&$bundles) {
  // remove guarding if clause
  //if (isset($bundles['taxonomy_vocabulary']['bar'])) {
    $bundles['taxonomy_vocabulary']['bar']['class'] = VocabularyBar::class;
  //
}

```

or

```
function bar_entity_bundle_info_alter(&$bundles) {
  // add extra nesting
  if (isset($bundles['taxonomy_vocabulary']['bar'])) {
    $bundles['taxonomy_vocabulary']['taxonomy_vocabulary']['bar']['class'] = VocabularyBar::class;
  }
}

```

but of course this did not work.

Is the doc simply incorrect or what am I missing to use bundle classes with config entities?

# Answer
> 1 votes
> Is the doc simply incorrect or what am I missing to use bundle classes with config entities?

The issue you are experiencing is that the bundle *Vocabulary* is only a bundle in relation to the content entity *Term*. The bundle metadata is stored as config entity items. This doesn't mean that this config entity is now bundleable only because it stores bundle metadata of another entity.

If you want to test this you first need a bundleable config entity type. I don't know if there is a use case for this or if this is even possible, but for the doc this doesn't matter. You could construct an entity out of the entity base class which is not content/config but a new variant needing bundles but not the features of content/config entities.

---
Tags: entities
---


# Question
Title: how to make a custom entity multilingual
I made a custom entity (ty drupal console). but i would also like to make this entity translatable. I enabled all 4 multilingual core modules but i don't see the "translate" tab in my entity nor can i enable translation form the "admin/config/regional/content-language" page (it says N/A), but i can show the language selector which as no real effect.

is it possible to translate custom entity, if so, how? what am i missing?

# Answer
You need the `translatable = TRUE` line in your `@ContentEntityType` annotation. You also need the `setTranslatable(TRUE)` line in your `BaseFieldDefinition::create` fields.
> 10 votes

# Answer
Refer this link for translating custom content entities - https://www.drupal.org/docs/develop/translating-custom-entities

Make sure to enable translation support for your custom entity under 'Content Language' configuration.
> 0 votes

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


title: Why do I get this exception?

text:
# Question
Title: Why do I get this exception?
I'm getting this error constantly and I can't quite figure out what's wrong.

> TypeError: strpos(): Argument #1 ($haystack) must be of type string, array given in strpos() (line 126 of core/lib/Drupal/Core/Extension/Dependency.php).
> strpos(Array, ':') (Line: 126)
> Drupal\Core\Extension\Dependency::createFromString(Array) (Line: 228)
> Drupal\Core\Extension\ModuleHandler-\>buildModuleDependencies(Array) (Line: 169)
> Drupal\Core\Extension\ModuleExtensionList-\>doList() (Line: 282)
> Drupal\Core\Extension\ExtensionList-\>getList() (Line: 143)
> Drupal\update\UpdateManager-\>getProjects() (Line: 283)
> update\_get\_available() (Line: 38)
> update\_requirements('runtime') (Line: 96)
> update\_page\_top(Array) (Line: 356)
> Drupal\Core\Render\MainContent\HtmlRenderer-\>Drupal\Core\Render\MainContent{closure}(Object, 'update') (Line: 405)
> Drupal\Core\Extension\ModuleHandler-\>invokeAllWith('page\_top', Object) (Line: 357)
> Drupal\Core\Render\MainContent\HtmlRenderer-\>buildPageTopAndBottom(Array) (Line: 150)
> Drupal\Core\Render\MainContent\HtmlRenderer-\>renderResponse(Array, Object, Object) (Line: 90)
> Drupal\Core\EventSubscriber\MainContentViewSubscriber-\>onViewRenderArray(Object, 'kernel.view', Object) call\_user\_func(Array, Object, 'kernel.view', Object) (Line: 142)
> Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher-\>dispatch(Object, 'kernel.view') (Line: 174)
> Symfony\Component\HttpKernel\HttpKernel-\>handleRaw(Object, 1) (Line: 81)
> Symfony\Component\HttpKernel\HttpKernel-\>handle(Object, 1, 1) (Line: 58)
> Drupal\Core\StackMiddleware\Session-\>handle(Object, 1, 1) (Line: 48)
> Drupal\Core\StackMiddleware\KernelPreHandle-\>handle(Object, 1, 1) (Line: 106)
> Drupal\page\_cache\StackMiddleware\PageCache-\>pass(Object, 1, 1) (Line: 85)
> Drupal\page\_cache\StackMiddleware\PageCache-\>handle(Object, 1, 1) (Line: 48)
> Drupal\Core\StackMiddleware\ReverseProxyMiddleware-\>handle(Object, 1, 1) (Line: 51)
> Drupal\Core\StackMiddleware\NegotiationMiddleware-\>handle(Object, 1, 1) (Line: 23)
> Stack\StackedHttpKernel-\>handle(Object, 1, 1) (Line: 718)
> Drupal\Core\DrupalKernel-\>handle(Object) (Line: 19)

# Answer
> 1 votes
This error is caused by an incorrect \*.info.yml file.

A correct example would be:

*media.info.yml*

```
name: Media
description: 'Manages the creation, configuration, and display of media items.'
type: module
package: Core
version: VERSION
dependencies:
  - drupal:file
  - drupal:image
  - drupal:user
configure: media.settings

```

Where you can see that in `dependencies` each value is a string. You have installed a module where the \*.info.yml file contains a subarray instead.

---
Tags: debugging
---


# Question
Title: My custom module shows up on the modules list but I cannot enable it, why?
I've written a custom module (*custom\_data\_import*) with a .info.yml file and .module files, but the module only shows up in my list of modules and I cannot enable it. Moreover, the .module file seems to act like a plain text file. Can someone please help?

The content of the *custom\_data\_import.info.yml* file is the following.

```
name: 'Custom Data Import'
type: module
description: 'Custom module to import JSON data'
package: Custom
core_version_requirement: ^8 || ^9
dependencies:
  - drupal: node
  - drupal: http_client

```

# Answer
> 3 votes
The dependencies are not correct. The Http Client module is not a Drupal core module; that means it can be declared as dependency as `http_client:http_client`, not `drupal:http_client`. (There must be no space before or after colons.)

The dependency format is `<project machine name>:<module machine name>`. The project machine name is the last part in the project page URL, `https://www.drupal.org/project/http_client` for the *Http Client* module and `https://www.drupal.org/project/drupal` for Drupal core.

Since you are defining the dependency as `drupal:http_client`, and since Drupal doesn't find any Drupal core module with that machine name, Drupal does not allow you to install your custom module because one of the dependencies is missing. (As far as I recall, it should show a note about the missing dependency in the module description.)

---
Tags: .info
---


# Question
Title: How can I hide the active language in the language switcher block?
I have a site with two languages, but it's pointless to show the name of the currently selected language in the language switcher block. How can I hide it?

# Answer
> 5 votes
The links generated by the Language API are alterable via `hook_language_switch_links_alter()`, so you can do this:

```
/**
 * Implements hook_language_switch_links_alter().
 */
function MYMODULE_language_switch_links_alter(array &$links, $type, $path) {
  global $language;

  unset($links[$language->language]);
}

```

# Answer
> 1 votes
A cleaner way is to do the following:

```
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;

/**
 * Implements hook_language_switch_links_alter().
 */
function MYMODULE_general_language_switch_links_alter(array &$links, $type, Url $url): void {
  $current_language = \Drupal::languageManager()->getCurrentLanguage();

  // Make sure the language is instance of language interface.
  if (!$current_language instanceof LanguageInterface) {
    return;
  }

  // Make sure the language option exists.
  if (isset($links[$current_language->getId()])) {
    unset($links[$current_language->getId()]);
  }
}

```

# Answer
> 0 votes
**\[Drupal 8\]:**

Implement hook\_language\_switch\_links\_alter in a custom module like this:

```
 /**
 * Perform alterations on language switcher links.
 *
 * A language switcher link may need to point to a different path or use a
 * translated link text before going through the link generator, which will
 * just handle the path aliases.
 *
 * @param array $links
 *   Nested array of links keyed by language code.
 * @param string $type
 *   The language type the links will switch.
 * @param \Drupal\Core\Url $url
 *   The URL the switch links will be relative to.
 */
function hook_language_switch_links_alter(array &$links, $type, \Drupal\Core\Url $url) {
  $language_interface = \Drupal::languageManager()->getCurrentLanguage();
  $current_language_id = $language_interface->getId();
  unset($links[$current_language_id]);
}

```

---
Tags: i18n-l10n
---


# Question
Title: Search API autocomplete view mode template
I got search api autocomplete setup and using the live results feature I was able to set it to use my `Search Autocomplete` view mode. I am trying to figure out what the twig template name would be. Any ideas? I don't see the twig debug suggestions. Guessing because its coming in via ajax.

# Answer
never mind, this was easier than I thought. Its `node--view-mode.html.twig` as you normally would. Not sure why I thought it'd be different. In my case this was `node--search-autocomplete.html.twig`. I will leave this here for anyone else wondering how to do this.
> 0 votes

---
Tags: 8, search
---


title: Media library vs entity browser

text:
# Question
Title: Media library vs entity browser
I am creating a brand new multilingual drupal 10 site and I have to choose between Media library and Entity browser for the manage form display of my media reference fields. I have searched all over the web but I can't find a clear comparison between the two. From what I noticed from testing, media library has a better UX/UI comparing to entity browser. However, it doesn't add an "edit" button for the media on the node edit page. So if I want to change the alt or the title or modify any extra field that I've added to my media, I can't do this from the article node edit page, I have to go to /media/mediaID/edit. I think It is not that bad it the website doesn't change a lot. But in my case the website is multilingual, so the user will have to changge the alt and the title at least once ( when he creates the article's english version) so I guess it is not practical for me to use media library, it is better to use entity browser that provides the edit button but still I have to apply this patch https://www.drupal.org/project/entity\_browser/issues/2721665 . On the other hand, when we have a field that can reference to media of type video Or media of type image (both of them), the media library provides better UX to select a video or image, but I know this is possible too in Entity browser if I add new widget for ImageAndVideo. Could someone help me confirm entity browser is the most convenient in my case ? Or give me some more scenarios to test ?

# Answer
> 2 votes
They both do essentially the same thing, but media library only allows for the selection of Media entities, whereas Entity Browser can allow for the selection of any type of entity.

Media library is easier to set up and works better out of the box. Entity browsers take a bit of work to learn exactly how to set them up, with a lot of trial and error and sometimes confusing failures.

I personally use Entity Browser, even with its difficulties, as it provides a consistent interface between entity types, rather than having one browser for Media entities and another for other entities. That said, if a site only needed a browser for Media and not other entity types, I'd probably only use the Media library.

---
Tags: media
---


# Question
Title: Am I hardening the permissions in settings.php correctly?
Last month, I encountered an issue where I could not edit `settings.php` as it was read-only.

I asked this question and learned how to change the permissions to edit the file, and then harden them again. The result was that vim would warn me a file is read-only until I used `chmod a+w settings.php`. After this, vim would no longer warn me about this and I could make the changes I need. Finally, I used `chmod go-w settings.php` to harden the permissions again, and once again, vim gave me a warning that it is read-only.

Today I created two more Drupal sites and have to edit multiple `settings.php` files. I repeated the same process, but this time I noticed that I no longer got the warning from vim that the file is read-only after hardening the permissions. Furthermore, I could edit the files freely.

I started digging to see why the permissions weren't blocking me from editing the file and discovered that the file permissions are `-rw--r--r--` so that I, as the owner, could edit the file. This is different from the default permissions on the `settings.php` file that instead look like `-r--r--r--`. I asked about this on the unix stack exchange and was informed that this is the expected outcome of the `chmod go-w settings.php` command.

My main concern now is if this poses the same security risk for the site as having a writable `settings.php` file? Should I instead be using `chmod a-w settings.php` to get `-r--r--r--` permissions, or is `-rw--r--r--` sufficiently secure for a live Drupal site?

# Answer
> 0 votes
This is covered in the docs:

> After the installation script has run, Drupal tries to set the permissions automatically to:
>
> 555 (read-execute) \[dr-xr-xr-x\] for the sites/default folder. and 444 (read-only) \[-r--r--r--\] for the settings.php

> If not, you will need to manually set them:
>
> ```
> chmod 555 sites/default
> chmod 444 sites/default/settings.php
>
> ```
>
> **These permissions are correct, and should not be changed, because changing these opens up a security risk.**

Emphasis mine, that last paragraph is essentially the answer to your question - Drupal recommends that you remove owner write permissions from the settings.php file.

In reality, if you’re sysadmin, there’s every chance you might know better than this for your setup, and can take a different approach. But if you don’t know better, it would be advisable to stick to the recommendations and remove the owner’s ability to write.

# Answer
> 0 votes
> Should I instead be using chmod a-w settings.php to get -r--r--r-- permissions, or is -rw--r--r-- sufficiently secure for a live Drupal site?

As long as the process used to run PHP or the web server is not able to write the settings.php file all is fine.
When the system account that owns the file is different from the system account used to run PHP or the web server, the *-rw--r--r--* permissions do not give write access to that file to neither PHP nor the web server, since those permissions mean:

* Read and write access for the owner
* Read access for the system accounts on the same group as the owner
* Read access to all the other system accounts

When the *settings.php* file is owned from the same system account used to run PHP or the web server, then the *-r---r--r--* permissions are necessary.

---
Tags: security, 10
---


# Question
Title: Email multiple addresses from a composite element in a webform
I need to email multiple addresses from a composite element in a webform. Using a Computed Twig element with this code:

```
{% for m in data.member_information %}
{{ m.email }}
{% endfor %}

```

The email addresses are listed line by line in Results.

```
test@test.com
random@random.com

```

I guess that means they're in an array, but I'm not sure. Here's the configuration of the composite element:

```
id: member_information
uuid: 591d262f-998d-4ade-8e40-56d8119592dd
status: true
label: 'Member Information'
elements: |
  first_name:
    '#type': textfield
    '#required': true
    '#title': 'First Name'
  middle_name:
    '#type': textfield
    '#title': 'Middle Name'
  last_name:
    '#type': textfield
    '#required': true
    '#title': 'Last Name'
  phone:
    '#type': tel
    '#required': true
    '#title': Phone
  cell_phone:
    '#type': tel
    '#title': 'Cell Phone'
  email:
    '#type': email
    '#required': true
    '#title': Email
description: 'Group Nomination composite.'
langcode: en
dependencies: {  }

```

The configuration uses the webform composite module.

In the handler, the email addresses need to be a comma separated list in the To email field, like this:

```
test@test.com,random@random.com

```

I've tried

```
{% for m in data.member_information %}
{{ m.email|join(',') }}
{% endfor %}

```

In Results, email addresses are still listed line by line.

How do I convert the line separated list to a comma separated string in the twig template?

# Answer
> 2 votes
You don't have an array of email addresses, you have an array of composite field items.

So loop over the field items, build the array of emails

```
{% set emails = [] %}
{% for m in data.member_information %}
  {% set emails = emails|merge([m.email]) %}
{% endfor %}

```

and then output the joined array:

```
{{ emails|join(',') }}

```

---
Tags: webforms, 9
---


title: Define key for html email

text:
# Question
Title: Define key for html email
I'm using Symfony Mailer to send HTML emails in my site.

This requires 'module' and 'key' to find my email twig template file.

How do I find or define 'key' for my email handler in my Webform settings?

# Answer
> 1 votes
Solved after lots of experimenting.

Select 'Twig template' as the Body type in the email handler.

Name your twig file as 'webform-email-message-html--WEBFORM-ID.html.twig'.

---
Tags: webforms
---


# Question
Title: How do I deal with the problem of stale cookies breaking logins on a migrated site?
I just finished the migration of a D7 site into D9.

Unfortunately, as I kept the same domain, before the first time I login to the new D9 site, I have to remove my domain's cookies from within my browser. If I don't remove the cookies, I can't login. (I assume there is some kind of conflict between the D7 cookies and the D9 login process)

My idea is to create a form with a submit button which will remove the D7 cookies.

Here is my code:

```
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $cookies = \Drupal::request()->cookies;
    foreach ($cookies as $cookie) {
      setcookie($cookie, "", time() - 3600);
    }
  }

```

I am not sure If I need to remove all cookies... which one should be deleted? Also, this code fail because some cookie name have coma like `eF8gbELtR4DO6pRrsjgk1J,XFZlXH83j28-5ssIcvBPz,zsw`

# Answer
This is a known bug when migrating from Drupal 7. Use one of the patches on that issue. In the current form these patches work by introducing an optional `session_suffix` session service configuration. By configuring that value in services.yml with a short string you will effectively invalidate all session cookies.
> 2 votes

---
Tags: cookies
---


# Question
Title: How can I create a sitemap for each content type?
How can I create a sitemap for each content type?

# Answer
> 1 votes
There's now the module to do that: XML Sitemap per node type

> The XML Sitemap Per Node Type module provides the additional context for XML sitemap module that allows creating sitemaps per content type.

# Answer
> 0 votes
The XML Sitemap doesn't support creating multiple arbitrary sitemaps (e.g. *a sitemap with only content type X*) . What it does support is different *contexts* in which it makes sense to have a isolated content sitemap (e.g. a Google News sitemap or sitemap in a different language). This needs to be supported at a module level however.

What you can do is exclude content types from inclusion (under the content type edit page on **admin/structure/types/manage**) in the default sitemap.

# Answer
> 0 votes
In Drupal 8+, the Simple XML Sitemap module supports the creation of multiple sitemaps out of the box.

It supports most entity types, and it can be extended relatively easily with custom code.

---
Tags: xml-sitemap
---


# Question
Title: Is it safe to remove all untranslated strings?
I have a site which contains thousand of unused (and not translated) strings.

I would like to remove them to light up my database.

For the records,those strings where created because the original language of the source files has changed and because of some ugly code like `t("$variable" bla bla")`

My idea is to remove all the untranslated strings (which will contain used string) because the used strings will be auto-repopulated when needed. Here is the code I plan to use:

```
  $locale_storage = \Drupal::service('locale.storage');
  $strings = $locale_storage->getStrings(['translated' => FALSE);
  foreach ($strings as $string){
    $string_to_del = $locale_storage->findString(['source' => $string->getString()]);
    $locale_storage->delete($string_to_del);
  }

```

Is it safe?

# Answer
> 1 votes
Instead of a one-time deletion, I would periodically export your important strings to code. This is easy to script and means you will always have a backup if deletion goes wrong or a translator makes a mistake. Drush makes it easy.

## Export strings as PO files with Drush

You can remove all untranslated strings with a DB command but I would back up your translated strings first, specifically your customized strings:

Use drush locale:export to export strings to a PO file for each language:

```
drush locale:export ja --types=customized > translations/en.po

```

You could try keeping the `not-customized` strings as well, but since those are imported from drupal.org, you probably don't need to back them up.

You can then commit these `.po` files to your git repo to have a backup of the strings in the database.

## Wipe all strings

See how to bulk delete translation strings.

## Re-import the customized strings

Use drush locale:import:

```
drush locale:import en translations/en.po --type=customized --override=customized

```

## Additional resource

If the drush locale commands aren't sufficient, the Drush language commands module adds some more useful stuff.

---
Tags: location
---


title: Backup files very different size

text:
# Question
Title: Backup files very different size
for a Drupal website, backup is done via databack/mysql-backup (https://hub.docker.com/r/databack/mysql-backup) container.
Drupal version: 9.5.10.
The backup is created.
The created backup file is uploaded to AWS, which works objection free.
But, as visible on the picture, the backup files have very different size!

Does anyone have any idea why the backup files have such different size?

# Answer
> 1 votes
The only real way to know why they are different sizes is to decompress the files and compare them.

If the backups all restore correctly, the difference is that you are probably backing up the cache tables in the larger files.

Instead of using a generic MySQL backup solution, I would use Drush and the drush sql:dump command, which can be used to exclude the cache tables.

An alternative is to use the Backup and Migrate module.

---
Tags: 9, backups
---


# Question
Title: Is it possible to select all results in Views bulk actions form?
By all results I mean even those that are not displayed on the current page(if there is paging).

# Answer
The simple bulk action support in Drupal 8 core does not currently support this feature.
> 2 votes

# Answer
The issue about Port Views Bulk Operations to Drupal 8 is closed (completed) now.

If somebody has problem with it, try to use /admin/yourpath in views, then you use admin theme and select/deselect all button should work.
> 0 votes

# Answer
If you need "select all" you can use the module VBO. Then you can replace the field "Node: Views bulk operation" with the "Global: Views bulk operations" which supports selecting all rows.
> 0 votes

# Answer
This page explains how to enable the "Select All" function: https://www.drupal.org/docs/contributed-modules/views-bulk-operations-vbo/setting-up-site-administrators

TL;DR with VBO enabled, go to the view and replace the `User: Bulk update` or `Content: Node operations bulk form` with the `Global: Views bulk operations` field.
> 0 votes

---
Tags: views, 8, actions
---


title: disable the registration form

text:
# Question
Title: disable the registration form
How can I remove the *Registration* tab in Drupal 9?

>

Previously, this was possible by changing the user settings.

# Answer
To configure this:

1. Log in as an administrator.
2. Browse to /admin/config/people/accounts.
3. In the "Registration and cancellation" section, find the "Who can register accounts?" option.
4. Set the option to "Administrators only".
5. Save the configuration.
> 1 votes

---
Tags: 9
---


# Question
Title: Redirect directly to the payment provider page
I'm building a store with Drupal Commerce and creating my own off-site payment gateway. On the review page, after selecting payment method, the user can click the button to pay and finish the order. After that he's redirected to a page that tells him to wait to be redirected to the payment provider.

Is there a way to redirect the user to the payment provider without needing to go to this useless page ?

Thank you.

# Answer
> 0 votes
If you already have a redirect link and doensn't need a page to have hidden values in a form, you can use the `self::REDIRECT_GET` instead of `self::REDIRECT_POST` in the `buildConfigurationForm` function of your payment method.

---
Tags: commerce, redirection, payment-gateways
---


# Question
Title: How to render the image or several images in the table render element?
I have a form. In the last step of the form, I display in the table what was saved in the fields in the previous steps.

Where there is a comment in the code, I need to render the all images from the `$taxonomy_pms_color` that was saved in the previous steps.

```
$quote_printing_pms_colors = $quote_print_location->get('field_pms_colors')->getValue();
$pms_colors = '';

foreach ($quote_printing_pms_colors as $pms_color_value) {
  $taxonomy_pms_color_target_id = $pms_color_value['target_id'];
  $taxonomy_pms_color = $this->entityTypeManager->getStorage('taxonomy_term')->load($taxonomy_pms_color_target_id);
  $image_uri = $taxonomy_pms_color->get('field_image')->entity->getFileUri();
}

$print_locations_rows[] = [
  'pms_colors' => [
    'data' => [
      //Here should be the rendered images
    ],
  ],
];

}

if (!empty($print_locations_rows)) {
  $print_locations_header = [
    'col1' => $this->t('PMS Colors'),
  ];

  $form['confirm_quote']['designs_and_finishing_wrapper']['design_wrapper'][$key]['print_location_table'] = [
    '#type' => 'table',
    '#header' => $print_locations_header,
    '#rows' => $print_locations_rows,
    '#attributes' => [
      'class' => ['my-class'],
    ],
  ];

```

# Answer
Since I have several images I can render the images like this:

```
$rednered_image = [];

$rednered_image[] = [
  '#theme' => 'image_style',
  '#uri' => $image_uri,
  '#style_name' => 'thumbnail',
];

```

I can pass the images to the `<td>` of the table as follows:

```
'thread_colors' => [
  'data' => [
    'images' => $rednered_image,
  ],
],

```

The updated code will look like this:

```
$quote_printing_pms_colors = $quote_print_location->get('field_pms_colors')->getValue();
$pms_colors_name = '';
$rednered_image = [];

foreach ($quote_printing_pms_colors as $pms_color_value) {
  $taxonomy_pms_color_target_id = $pms_color_value['target_id'];
  $taxonomy_pms_color = $this->entityTypeManager->getStorage('taxonomy_term')->load($taxonomy_pms_color_target_id);

  $taxonomy_pms_color_name = $taxonomy_pms_color->getName();
  $pms_colors_name .= '<span>' . $taxonomy_pms_color_name . ' ' . '</span>';

  if ($taxonomy_pms_color->get('field_image')->entity) {
    $image_uri = $taxonomy_pms_color->get('field_image')->entity->getFileUri();
    $rednered_image[] = [
      '#theme' => 'image_style',
      '#uri' => $image_uri,
      '#style_name' => 'thumbnail',
    ];
  }

}

$print_locations_rows[] = [
  'thread_colors' => [
    'data' => [
      'images' => $rednered_image,
    ],
  ],
];

if (!empty($print_locations_rows)) {
  $print_locations_header = [
    'col1' => $this->t('PMS Colors'),
  ];

  $form['confirm_quote']['designs_and_finishing_wrapper']['design_wrapper'][$key]['print_location_table'] = [
    '#type' => 'table',
    '#header' => $print_locations_header,
    '#rows' => $print_locations_rows,
    '#attributes' => [
      'class' => ['my-class'],
    ],
  ];

}

```
> -1 votes

---
Tags: taxonomy-terms, 9
---


# Question
Title: jQuery selector does not find the view content after document.ready event
I am applying some jQuery to make a slick carousel from a Drupal view.
The carrousel does not work erratically on page load; sometimes, it does, sometime it doesn't.

```
jQuery(($) => {
  $(document).ready(() => {
    console.log('ready');
    if ($('.view-carrousel .view-content').length) {
      console.log('content?'); //enters here erratically
    }
  }
}

```

Do you have any explanation?

Is it cache bubbling? I added `{{ content|without('field_article_visuel', 'links') }}` to the template.

Is it loading order? I added the following lines.

```
js/amu_slider.js: {}
dependencies:
  - core/views.module

```

# Answer
> -1 votes
meanwhile this seems to fix it

```
js/amu_slider.js: {}
  dependencies:
    - views/views.module

```

---
Tags: views, javascript
---


# Question
Title: File Field client side validation not working
I am on Drupal 9.3.x

I just discovered that File Field in node entity form which is marked as required, not showing client side validation fail message. Rather it submitting the form and then showing the validation fail message.

This is causing issue for my modal form. I am loading the entity form's custom form mode into modal. The file field is marked as required, actually its a media field which is linked with a field field. So when user submitting the form, its not validating that, file is not uploaded and submitting the form, getting out of modal window and showing the validation fail message.

Searched in the net a lot, getting no clue. The following things tried:

* Added an another test file field (not media field), its the same results
* Added a custom managed file field using hook\_form\_alter, its the same results
* Tried to submit the form through ajax, I see no form error reported for media field field

I am not sure if the as designed by Drupal or if there is any fix for it.

One more thing, field is added inside commerce product and field is showing inside inline entity form in simple mode.

Please help. :(

# Answer
> 0 votes
I don't have a complete answer for you but I have run into the same issue. The root of the problem appears to be that Drupal doesn't support client side validation of a "managed\_file". However if you switch your field type to "file" it should work. It appears this is an issue for many people but no true fix I've found yet. https://www.drupal.org/project/drupal/issues/2938441 https://www.drupal.org/project/drupal/issues/2301527

---
Tags: commerce, ajax
---


# Question
Title: Set error message only on errornous field(s) when validating multiple instances of the same field
* I have a form where the users can add one or more "units".
* I want to validate and return an error message on the problematic field when the unit does not have a value "leader"
* With the below code, an error message appears under *all* unit fields even if some inputs do not have error.

How can I add the error message only to the problematic field? Here's my attempt so far.

```

    // Foreach $values['unit'], check if this field has the key
    // "leader". If not, add an error message and require the user
    // to select a sub field which has area leaders.
    if ($values['unit']) {
      foreach ($values['unit'] as $unit) {
        if (empty($unit["leader"])) {
          $form_state->setErrorByName('unit',
            new TranslatableMarkup('Please select a unit with a leader.'));
          break;
        }
      }
    }

```

# Answer
Assuming the code is a form validation handler, you should be able to do something like this:

```
if ($values['unit']) {
  foreach ($values['unit'] as $index => $unit) {
    if (empty($unit['leader'])) {
      $form_state->setError($form['unit']['widget'][$index],t('Please select a unit with a leader.'));
    }
  }
}

```

However, if the `unit` element of the form is a child of a tree, then the first argument to `setError()` must be updated to the actual location of the element within the `$form` array.
> 2 votes

---
Tags: forms
---


# Question
Title: How can I get the user UUID using the JSON API?
I tried the following JSON API query strings to get the UUID, but I keep getting a 404 error.

* `{url}/jsonapi/user/user?filter[uid][value]={uid}`
* `{url}/jsonapi/user/user/{uid}`
* `{url}/jsonapi/user/user?filter%5Banon%5D%5Bcondition%5D%5Bpath%5D=uid&filter%5Banon%5D%5Bcondition%5D%5Bvalue%5D=0&filter%5Banon%5D%5Bcondition%5D%5Boperator%5D=%3C%3E`

EDIT:

Forgot to include this route: `{url}/user/{uid}`

# Answer
> 0 votes
I'm confused whether you want the UUID as suggested in the question title or the UID as suggested in your code.

## UID

By default, it's `drupal_internal__uid`, not `uid`.

You can confirm this by visiting `/jsonapi/user/user` and checking the output.

For example:

`https://example.ddev.site/jsonapi/user/user?&filter[drupal_internal__uid]=3`

If you want to shorten `drupal_internal__uid` to `uid`, you can install the JSON:API Extras module and configure an override for the User resource.

## UUID

In JSON:API, the UUID is always `id` regardless of what kind of entity you have:

`https://example.ddev.site/jsonapi/user/user?&filter[id]=2e5bcb94-574d-424b-98a7-2dd450c51a2c`

## Finding out the names of stuff in JSON:API

You can use the JSON:API Explorer module to check out the JSON output visually.

---
Tags: 9
---


title: Why is the cURL extension needed?

text:
# Question
Title: Why is the cURL extension needed?
PHP requirements contains the following text.

> The PHP cURL extension is required for automated testing in Drupal 9 and higher, as well as Aggregator and some contributed modules.
> Many Linux distributions and development stacks will have it enabled by default, but if your system doesn't either enable it in php.ini (typically on Windows) or install it using your package manager (typically on Linux).

I don't program in PHP but I do use Bash where I use `curl` to download things. What does it download in Drupal? For example, what does Aggregator or the Drupal testing system do with it?

# Answer
Drupal is a framework. It uses Guzzle under the hood. Guzzle is an HTTP client that can make requests. Guzzle uses cURL under the hood. Any module may use the HTTP client to make requests. Because Drupal is a framework, it provides tools for modules to use.

I am not sure if core explicitly uses it for any given processes, but the tool is there to be used.

If you are wondering if it is safe to disable, due to every Drupal instance being a unique build, that can't be answered in a blanket statement, so the best thing to do is disable cURL, then test to see if everything still works on your server.
> 3 votes

---
Tags: installation
---