# Question
Title: Is it possible to Migrate data directly into the paragraph entity?
Posted this in Drupal Paragraphs issue queue, but no response. Trying here.

Drupal core 9.4.5. Paragraphs 8.x-1.2

Every tutorial on Drupal 8/9 paragraphs migration uses the destination plugin: `entity_reference_revisions:paragraph`. As I understand it, the reason for this is:

> This plugin is actually provided by the Entity Reference Revisions module. It is very important to note that paragraphs entities are revisioned. This means that when you want to create a reference to them, you need to provide two IDs: \`target\_id\` and \`target\_revision\_id\`. Regular entity reference fields like files, images, and taxonomy terms only require the \`target\_id\`.

See: https://understanddrupal.com/lessons/introduction-paragraphs-migrations-drupal/

I intend to migrate Drupal 7 book content using a custom SQL source plugin. With this method, I can provide most of the Paragraph entity field requirements, including the **revision id**.

My question is, could I then, in my migration yaml file, use:

`destination:
plugin: 'entity:paragraph'`

And migrate my D7 book data directly into the D9 paragraph entity?

I can create a custom SQL source plugin that has all the node and book fields I need for each book. I have attached a sample PDF of SQL code and resulting data elements. These would be the fields returned from my source plugin: `n.nid, n.vid, n.type, n.language, n.title, n.uid, n.status, n.created, n.changed, b.mlid, b.bid, ml.menu_name, ml.plid, ml.link_path, ml.module, ml.has_children, ml.depth, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9`

According to the Paragraph Entity definition, I can supply almost all the the required destination fields from my source output:

```
Paragraph entity
Module: Paragraphs module
Class: Drupal\paragraphs\Entity\Paragraph
Related article: Introduction to paragraphs migrations in Drupal

List of base field definitions:

id: (integer) ID.
uuid: (uuid) UUID.
revision_id: (integer) Revision ID.
langcode: (language) The paragraphs entity language code.
type: (entity_reference to paragraphs_type) Paragraph type.
status: (boolean) Published.
created: (created) The time that the Paragraph was created.
parent_id: (string) The ID of the parent entity of which this entity is referenced.
parent_type: (string) The entity parent type to which this entity is referenced.
parent_field_name: (string) The entity parent field name to which this entity is referenced.
behavior_settings: (string_long) The behavior plugin settings
default_langcode: (boolean) A flag indicating whether this is the default translation.
revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.
List of field storage configurations:

field_reusable_paragraph: entity_reference field.

```

The process and destination sections of my YAML migration file would then look *something* like this:

```
process:
    id: nid
        UUID: (unknown)
    revision_id: vid (this is the book node's revision id)
    langcode: (either language or default to 'en')
    type: (default to 'agenda_section')
    status: status
    created: created
    parent_id: (have to figure out how to get nid of plid)
    parent_type: ('node' or 'paragraph')
    parent_field_name: (default to 'field_body1' or 'field_body2' depending on whether parent is node or paragraph)
    behavior_settings: (unknown)
    default_langcode: (default 'true')
    revision_default: (default 'true')
    revision_translation_affected: (unknown)
    workspace: (unknown)
destination:
  plugin: 'entity:paragraph'
  default_bundle: agenda_section
  migration_dependencies: null

```

I would need more information on UUID, behavior\_settings, revision\_translation\_affected and workspace to determine what should go there. If I can safely leave them blank, all the better.

I would probably have to run a separate migrations for:

1. The top level nodes (which would migrate as nodes)
2. First level Paragraphs (parent is always node)
3. Level 1+ Paragraphs (parent is always paragraph)

I do not know if it is possible to migrate directly into paragraph entity. But if it isn't, it would be nice if we could. Most of the paragraph entity fields are listed in the Drupal database paragraph tables:

`select pi.id, pi.revision_id, pi.type, pifd.parent_id, pifd.parent_type, pifd.parent_field_name, pfd.field_content_value, pfd.field_content_format, pfd.bundle, pifd.status, pifd.langcode, pi.uuid, pifd.created, pifd.default_langcode, pifd.behavior_settings, pifd.revision_translation_affected from paragraphs_item pi inner join paragraphs_item_field_data pifd on pi.id = pifd.id inner join paragraph__field_content pfd on pi.id = pfd.entity_id`

* id
* revision\_id
* type
* parent\_id
* parent\_type
* parent\_field\_name
* field\_content\_value
* field\_content\_format
* bundle
* status
* langcode
* uuid
* created
* default\_langcode
* behavior\_settings
* revision\_translation\_affected

So, theoretically, I should be able to write a program that simply inserts the source values into the destination fields in the appropriate destination tables. But, in doing so, I lose the migration "rollback" feature. So, I would prefer to do this within the migration framework.

Instead of only being able to migrate paragraphs into *entity\_reference\_revisions:paragraph*, we have option to migrate into *entity:paragraph*. This gives more flexibility when migrating from various sources (other than Drupal database).

# Answer
No, it is not possible.

Paragraphs can only be migrated using plugin: entity\_reference\_revisions:paragraph at this time.
> 0 votes

---
Tags: migrations, paragraphs
---


# Question
Title: Is there a way to see the date of when webforms were opened and closed?
I'm using Drupal 9 and would like to know when a webform was closed to check that we haven't had a security breach and received submissions after the form was closed.

# Answer
> 1 votes
No, there is not, Webforms are config and config elements don't store revision information. If you have the database logging module enabled, you might find a DB log entry though when a webform config was saved (see `/admin/reports/dblog`). But this log doesn't say which field (or if any field at all) has been changed, it just means "the save button was clicked".

(And if you have a security breach, this info would be untrustworthy anyways, because all those logs can be manipulated programmatically from within Drupal too.)

---
Tags: webforms
---


# Question
Title: How to install a theme with the command line?
I am trying to install the theme Adaptivetheme.

I have tried this

```
composer require drupal/adaptivetheme

```

and then:

```
vendor/bin/drush theme:enable adaptivetheme

```

But I got:

> Unknown themes: adaptivetheme.

How to install a theme with the command line?

# Answer
Read the documentation. The only provided theme in the package is at\_core but its description is:

> Base theme only - do not set to default. Use the AT Theme Generator to generate or clone a theme to get started.
> 0 votes

---
Tags: drush, 9, installation
---


# Question
Title: How to create a view of the most popular nodes?
How to create a view of the most popular nodes?

I went through the filter criteria looking for something such as "most read" or "most visited" or "most popular" but I didn't find such a thing.

# Answer
Drupal needs a way to collect information from usage of a site to determine which content is popular and then a way to expose this data to other modules. The included Statistics module provides this functionality.
> 0 votes

---
Tags: views, 9
---


# Question
Title: How can I make route parameters optional in a routing callback?
I needed to create a route in which the path of the route would be completely dynamic and so I created a routing callback.

```
<?php

namespace Drupal\uber_affiliate\Routing;

use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

/**
 * Class EntityOverview
 *
 * @package Drupal\uber_affiliate\Routing
 */
class AffiliateRoute {

  /**
   * Dynamically generate the routes for the entity details.
   *
   * @return \Symfony\Component\Routing\RouteCollection
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function routes() {

    $affiliate_menu_path = \Drupal::state()->get('affiliate_module_affiliate_menu_path', 'affiliate');
    $routes = [];
    $routes['affiliate'] = new Route(
      $affiliate_menu_path . '/' .   '{aff_id}' . '/' . '{dest_path}' . '/' . '{tracker_id}',
      [
        '_controller' => 'Drupal\uber_affiliate\Controller\UberAffiliate::affiliate_page',
      ],
      [
        '_permission'  => 'track affiliate clicks for this role',
      ],
      );

    return $routes;
  }
}

```

I need {dest\_path} and {tracker\_id} to be optional. How do I make them optional?

# Answer
You can do so by providing a default value for those parameters.

```
path: '/foo/bar/{baz}'
defaults:
  ...
  baz: 'fallback-value'

```

With your example, it should be something like:

```
$routes['affiliate'] = new Route(
  "{$affiliate_menu_path}/{aff_id}/{dest_path}/{tracker_id}",
  [
    '_controller' => 'Drupal\uber_affiliate\Controller\UberAffiliate::affiliate_page',
    'dest_path' => 'fallback',
    'tracker_id' => 'fallback',
  ],
  [
    '_permission'  => 'track affiliate clicks for this role',
  ]
);

```

I assume there is a reason why you want them as route parameters and not as query string parameters (i.e. `?destination=foo&tracker-id=bar`).

See Optional parameters for more info.
> 4 votes

---
Tags: 8, routes
---


title: Custom module block doesn't work

text:
# Question
Title: Custom module block doesn't work
I have a custom module where its only purpose is going to be serving up a block. I basically used these instructions: https://www.drupal.org/docs/creating-custom-modules/creating-custom-blocks/create-a-custom-block

These are my files' content.

### modules/cat\_custom/cat\_custom.info.yml

```
name: Cat Custom
type: module
description: Custom functionality for Cat Custom
core_version_requirement: ^9
dependencies:
  - drupal:block

```

### modules/cat\_custom/src/Plugin/Block/CatCounterBlock.php

```
namespace Drupal\cat_custom\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Provides a 'Cat Counter' Block.
 *
 * @Block(
 *   id = "cat_counter_block",
 *   admin_label = @Translation("Cat Counter Block"),
 * )
 */
class CatCounterBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    return [
      '#markup' => $this->t('Hello, World!'),
    ];
  }
}

```

When I first enable the module, I can see the block in the *Add block* list. When I run `drush cr`, it disappears from that list. If I visit */admin/config/development/performance* and click on *Clear all caches*, it re-appears. As soon as I run `drush cr`, it disappears again.

If I place it when it's showing up, it works as expected initially. When I run `drush cr`, the block's text gets replaced with the following message.

> This block is broken or missing. You may be missing content or you might need to enable the original module.

I enabled and tried the block example from https://www.drupal.org/project/examples; it works as expected, even after a `drush cr`.

What am I missing or doing wrong?

# Answer
I went into the database and did a `TRUNCATE` on all tables with prefix `cache_`. That's seemed to fix the problem for me. I can clear all caches in the Performance page and use `drush cr` without issue.

One thing I noted while trying things was that after removing and uninstalling my custom module, if I moved it in the directory structure and re-installed it, it would give errors when trying to place the block again. It seems like something gets cached and it continues looking for the original reference.

For example, moving it from `/modules/cat_custom` to `/modules/custom/cat_custom` or `/sites/mysite.com/modules/cat_custom` would lead to errors when placing the block again. These errors are viewable in watchdog and just show that it's looking in the wrong directory.

I'm not exactly sure what the problem was, but hope truncating cache tables helps someone else!
> 0 votes

---
Tags: blocks
---


# Question
Title: JSON:API fundamental permissions and access restriction question
# Intro

JSON:API is declared as a must-have for decoupled Drupal websites.

While I completely (well, I hope so) understand the built-in Drupal permissions/access restriction system, I have a specific use-case and I would like to understand how can I implement what I need with so much advertised JSON:API approach taking into account potential security issues described below.

# Current implementation

So far I was only able to accomplish the task using Views REST display, disabling default JSON:API endpoints and creating my own JSON:API resources, because Views allow me to have hard server-side restrictions while filtering the content and custom JSON:API resource gives me control over the content I deliver.

# Disposition

Well, so there are 2 sections on my website:

1. There is a public section with Articles. Any logged-in user can see all the published articles. I can deliver this page using Views as a separate page, Views REST or JSON:API to some PWA, doesn't matter. So far so good.
2. There is a restricted section on the website (kind of dashboard) with the list of the articles created by the currently logged in user. Not only the User is able to see the publicly available fields, but some private fields too. User should not be able to see the other users' articles. For the purpose of this question, let's say that seeing all the articles in general via \[1\] route is not a problem from security standpoint, but seeing all the articles *per user* is a problem. In general, I do not what the users to know who is the author of each article.

# Problem

We need to somehow separate an access restrictions for (1) and (2), even though both operations are going as 'view entity'. But (1) delivers all the articles regardless of the author, (2) delivers articles owned by the currently logged in user only.

I can build a view for a public section, but I like to use a PWA for my dashboard, so the articles are delivered using JSON:API there.

# Problem from permissions standpoint

Now I can not use default permissions settings (i.e. adding/removing 'View Article' permission) because this breaks route (1) \[means: users without 'View Article' permission can not see the list anymore\] At the same time, I can not just rely on the query when returning the articles for the dashboard request (2) of some specific user, because let's say some advanced user sees the parameters I include in the request, he changes those parameters and - boom - sees the articles created by the other user, which is a security breach.

# Problem with different fields visibility

Same question applies to the fields. When I show the (1) route (all articles), I might need to output public fields only, while when I deliver the content to (2) \[per-user dashboard\], I need to deliver all the fields.

# Final question number one

So my question is: how can I solve this? How can I deliver same content using JSON:API with checking the owner server-side, not passing the owner as a parameter, and without restricting an access using built-in permissions system?

# \[EDIT\] Final question number two

Is there a way for me to declare a security context (read: declare needed permission to be checked against each entity) before actually outputting/processing the data using JSON:API? Good example would be custom route with custom permissions check, while JSONAPI, as far as I am concerned, only consider CRUD entity-related permissions based on GET/POST/PUT/DELETE method being used.

# Answer
> JSON:API is declared as a must-have for decoupled Drupal websites.

This is not true. Decoupled Drupal can take many forms, including

* REST
* JSON:API
* GraphQL

JSON:API is pretty great, but if it doesn't fit your use case, you can build a complete decoupled website and never touch it.

For a comparison of these solutions, see the book Decoupled Drupal by Preston So.

## How JSON:API handles access control

In Drupal, JSON:API respects whatever permissions/access control is set for users. The system was designed this way so that if you already have a functioning Drupal website with access control properly set up, then you can enable JSON:API and it will have the same access control with no additional work required.

> So my question is: How can I deliver same content using JSON:API with checking the owner server-side, not passing the owner as a parameter, and without restricting an access using built-in permissions system?

You need to use the built-in permissions system to restrict content with JSON:API. That's the way it is designed in Drupal. So the answer to "without restricting access using the built-in permission system" is "you can't."

If you want to make arbitrary rules for access, consider REST or GraphQL.

You could alternately use custom JSON:API Resources, but then whatever data you want to hide is probably exposed automatically by JSON:API, so you need to lock it down with JSON:API Extras, and then the question is why are you using JSON:API instead of REST for your particular use case?
> 1 votes

---
Tags: views
---


# Question
Title: Hook menu alter - Restrict access to edit block - wrong page is shown
I want to restrict the editing of a block to users whom have X or Y permissions.

I have tried `access arguments` and `access callback`.

```
function MYMODULE_menu_alter(&$items) {
  $items['admin/structure/block/manage/block/72/configure']['access arguments'] = ['X']; // ['X','Y'] uses AND not OR :(
}

```

I've attempted to add the 'Or' logic via a access callback function instead.

```
function _banner_block_access() {
    return user_access('X') || user_access('Y');
}

/**
 * Implements hook_menu_alter().
 */
function MYMODULE_menu_alter(&$items) {
  $items['admin/structure/block/manage/block/72/configure']['access callback'] = '_banner_block_access';
}

```

**The problem**

When the user has the correct permissions, they should see the block edit admin form.

What actually happens is the path `/admin/structure/block/manage/block/72/configure` shows the block index listing (`/admin/structure/block`) instead.

When the user doesn't have the right permission, a non authorised error is correctly displayed.

When the function returns `false` the view is correct and displays a not authorised message.

Is this a Drupal bug or am I doing something wrong?

# Answer
> 0 votes
None of the Drupal core modules defines a route for admin/structure/block/manage/block/72/configure.

The block module has a route for admin/structure/block/manage/%/%/configure, but since that is a default tab, it inherits its access permissions from its parent route, admin/structure/block/manage/%/%.

The correct code to alter that route would be similar to the following one.

```
/**
 * Implements hook_menu_alter().
 */
function mymodule_menu_alter(&$items) {
  if (isset($items['admin/structure/block/manage/%/%'])) {
    $items['admin/structure/block/manage/%/%']['access callback'] = '_banner_block_access';
    $items['admin/structure/block/manage/%/%']['access arguments'] = array(4, 5);
  }
}

function _banner_block_access($module, $block) {
  if ($module == 'block' && $block == 72) {
    return user_access('X') || user_access('Y');
  }

  // Use the default access for the other blocks.
  return user_access('administer blocks');
}

```

---
Tags: 7, hooks
---


# Question
Title: How can I translate Olivero default search string?
In the default theme for Drupal 9 (Olivero) I have the following string in my search box field:

> Search by keyword or phrase.

I have tried to change it by going to `admin/config/regional/translate` (and searching `search`) and also `admin/config/regional/config-translation` but nowhere have I found where to change it.

How to change Olivero default search string?

# Answer
There is nothing special about this string. Here are the exact steps to translate it.

1. Ensure the **Search** and **Interface Translation** modules are enabled at `/admin/modules`.
2. Ensure the search block is set to be shown at `/admin/structure/block`.
3. Visit a page with the search block. If you never visit a page with the search block, the string will not be generated and will thus not be available for translation.
4. Go to `/admin/config/regional/translate` and search for "Search by" (case sensitive). The string will appear for translation.

Again, this process is the same for all strings. The most important point is that you need to view the string once as a user for it to be made available for translation.
> 0 votes

# Answer
It is a translatable string so translation tools should work.

Alternatively you could alter the `search_block_form` or `search_form` form (you did not specify which), and change `$form['keys']['#attributes']['placeholder']` or `$form['basic']['keys']['#attributes']['placeholder']`, respectively.
> 1 votes

---
Tags: search, i18n-l10n
---


# Question
Title: How to remove or hide the Subject field for comments?
I have added a comment field to a content type. It is of the default comment type.

I don't want my commenters to fill in a subject, rather, just a comment body.

Trying to remove the Subject field, I went to `admin/structure/comment/manage/comment/fields` but there I only find `comment_body`, not something like `comment_subject`.

How to remove or hide the Subject field for comments?
In earlier phrasing, how to not require a subject from commenters?

# Answer
> 2 votes
You can't remove the subject, but you can hide it so that it will be auto-generated and not displayed.

Go to Admin -\> Structure -\> Comment types -\> Default Comments -\> **Manage Form Display** tab (`/admin/structure/comment/manage/comment/form-display`) and then drag **Subject** to **Disabled**. Then save.

Note: If you only see the heading "Comments" but no name field and no comment field, and you are not logged in, then you need to give anonymous users permission to post comments.

---
Tags: 9, comments
---


title: How do I set up CORS?

text:
# Question
Title: How do I set up CORS?
Drupal 8 has RESTful web service in-built in core and since 8.2 we don't need cors module.

Now to use services we just enable and configure default.service.yml file as specified in here

However, I was not able to configure this setup to allow web service access over another domain.

My current service.yml setup for cors is:

```
cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: ['x-csrf-token,authorization,content-type,accept,origin,x-requested-with']
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: ['POST, GET, OPTIONS, DELETE, PUT']
    # Configure requests allowed from specific origins.
    allowedOrigins: ['*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: false
    # Sets the Access-Control-Max-Age header.
    maxAge: 1000
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: false

```

I googled to find further detailed configuration on this but could not find one.

I am creating this for test development across two different domains.

Using pantheon dev environment for web services and localhost custom .dev domain for consuming those services.

Service access working fine using chrome CORS extension.

# Answer
I ran into this fairly recently on Pantheon, and hopefully this helps if you haven't already solved it.

```
cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: ['x-csrf-token','authorization','content-type','accept','origin','x-requested-with', 'access-control-allow-origin','x-allowed-header','*']
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: ['*']
    # Configure requests allowed from specific origins.
    allowedOrigins: ['http://localhost/','http://localhost:3000','http://localhost:3001','http://localhost:3002','*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: false
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: true

```

A few things to note...

Regarding the location of the file on Pantheon, please make sure your service.yml file is in /sites/default vs just /sites. I was wrongly under the impression it would work from both places. It will only work if in the /sites/default directory.

Notice the comma separated list of allowedHeaders each in their own set of quotes. I originally had a single string like you do in your example above, and it failed countless times before I caught the subtle difference. I'm fairly certain allowedMethods works the same way if you specifically want to list out your methods.

Please also note that while my code snippet will work well for development against a Pantheon sandbox you will likely want to lock things down a bit more prior to going into production. With Pantheon offering HTTPS you will also want to make sure to use it if you are going to be passing information around through headers. Hope this helps either you if you are still having issues or someone else that stumbled upon it down the road.
> 29 votes

# Answer
Find: .../sites/default/default.services.yml

Make a copy and rename the copy to:

.../sites/default/services.yml

Find this part of the code: cors.config: enabled: false

and replace with the following - cors.config: enabled: true

Clear the cache.
> 14 votes

# Answer
The following setting working for me.

```
cors.config:
  enabled: true
  # Specify allowed headers, like 'x-allowed-header'.
  allowedHeaders: ['x-csrf-token','authorization','content-type','accept','origin','x-requested-with']
  # Specify allowed request methods, specify ['*'] to allow all possible ones.
  allowedMethods: ['*']
  # Configure requests allowed from specific origins.
  allowedOrigins: ['*']
  # Sets the Access-Control-Expose-Headers header.
  exposedHeaders: false
  # Sets the Access-Control-Max-Age header.
  maxAge: false
  # Sets the Access-Control-Allow-Credentials header.
  supportsCredentials: false

```
> 5 votes

# Answer
exposedHeaders: true is not valid and will cause Warning: implode(): Invalid arguments passed in Asm89\Stack\CorsService-\>addActualRequestHeaders() (line 94 of /vendor/asm89/stack-cors/src/Asm89/Stack/CorsService.php) #0 /web/core/includes/bootstrap.inc(584) It needs to be either false or an array with allowed headers to expose see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
> 1 votes

# Answer
Nothing of above worked for me. Finally I followed this article and installed this contrib module: https://www.drupal.org/project/advanced\_cors.

I cleared cache et voilà, I could get it working.
> 0 votes

---
Tags: 8, symfony-services
---


# Question
Title: How to remove a module with command line?
After uninstalling all relevant modules with `drush un` I have tried the following input and got the following output, but I don't think I did it correctly.

```
composer remove vendor/panels

```

> vendor/panels is not required in your composer.json and has not been removed ./composer.json has been updated
>
> Running composer update vendor/panels
>
> Loading composer repositories with package information
>
> Package "vendor/panels" listed for update is not locked.
>
> Updating dependencies
>
> Nothing to modify in lock file
>
> Installing dependencies from lock file (including require-dev)
>
> Nothing to install, update or remove
>
> Package doctrine/reflection is abandoned, you should avoid using it. Use roave/better-reflection instead.
>
> Package symfony/debug is abandoned, you should avoid using it. Use symfony/error-handler instead.
>
> Package webmozart/path-util is abandoned, you should avoid using it. Use symfony/filesystem instead.
>
> Generating autoload files 48 packages you are using are looking for funding.
>
> Use the `composer fund` command to find out more!

# Answer
> 1 votes
Check the `composer.json` for the actual package name. In this case, for the panels module, it should be `drupal/panels`, so the command is `composer remove drupal/panels`.

---
Tags: composer
---


# Question
Title: How can I encrypt user-submitted content per user for a content type?
Let's say I have a website where people keep a personal diary (**diary** content type). I have configured permissions so that each user can only read, write, and view his/her own diary.

Users can create and submit several different content types on the site; only the **diary** content type needs to be private.

I would like to encrypt diaries **per user**, ideally by tying the encryption to the user's name and password.

I surveyed the encryption modules available for Drupal, and here are the only ones with 300+ installs:

* Encrypt: makes use of Real AES module and the Key module
* Encryption: simpler to configure than Encrypt, single module
* Dbee, which encrypts just the email addresses in the database--nifty

In addition, there is the Pubkey Encrypt module, which is an abandoned Drupal 8 module that allows encryption of data per user role.

So, to get encryption per user, I guess I would have to write this myself.

**How can I encrypt content per user for a specific content type?**

If this is really hard to do, I would also like to hear an answer that simply explains why this problem is harder than I think it is.

# Answer
The problem here isn't the encryption itself, it's easy enough to symmetrically encrypt some data before saving it to the database, it's the decryption.

In order to decrypt the data you need the key, which means you need to keep the user's password somewhere in plain text, or ask them for their password every time they want to see their "diary". Or you could decrypt it on login and leave it decrypted for the session somehow.

The other issue here is that it's not true end to end encryption. At some point in the process you will know the user's key unless you do the encryption on their computer.
> 2 votes

# Answer
So ultimately I decided on implementing a less-secure but "better than nothing" approach.

I evaluated the Field Encrypt module but it can only use a single key to encrypt all fields, and I wanted per-user keys to encrypt each user's fields.

So, I stored each user's encryption key in a field, and then encrypted that field with Field Encrypt. (Because the encryption keys for users are stored in the db, this is not a high level of security, but encrypted db entries are better than "completely in the open", which is the Drupal default.)

The following is only example code to give the reader an idea of how to solve this.

Based on code in the dbee module, I generated a key per user:

```
  /**
   * Generate a Real AES encryption key.
   *
   * Adapted from the dbee module.
   *
   * @param int $bytes
   *   An integer, the number of bytes for the key. Default to 16 (=128bits).
   *
   * @return string
   *   The encryption key in hexadecimal.
   */
  private function generateEncryptionKey(int $bytes = 16): string {
    return bin2hex(random_bytes($bytes));
  }

```

Then, based on the Real AES module, I added encrypt and decrypt methods to my user bundle:

```
  /**
   * Returns the user's encryption key.
   *
   * @return \Defuse\Crypto\Key
   *   The user's encryption key.
   */
  public function getEncryptionKey(): Key {
    $user_key = 'abc'; // Add code to get from appropriate field.
    // Defuse PHP-Encryption requires a key object instead of a string.
    $checksummed_key = Encoding::saveBytesToChecksummedAsciiSafeString(Key::KEY_CURRENT_VERSION, $user_key);
    return Key::loadFromAsciiSafeString($checksummed_key);
  }

  public function encryptContent(string $text_to_encrypt): string {
    $key = $this->getEncryptionKey();
    return Crypto::encrypt($text_to_encrypt, $key);
  }

```

Then, in `hook_entity_presave()`, I call the `encryptContent()` function.

For decryption, I use `hook_entity_view()` to decrypt only when appropriate.
> 0 votes

---
Tags: users, 9, security
---


# Question
Title: How do I make the default content View filterable by multiple content types?
Below is a clip from the content list admin page in Drupal 9, showing the Content type field drop-list, allowing admin users to filter the content list by content type.

Is there any way to alter this form to allow the list to be filtered by more than one content type at once? ie turn the content type drop-list into a multi-select field or checkboxes?

# Answer
> 2 votes
Yes. This admin page is a Drupal View. Go to /admin/structure/views/view/content. Under **Filter Criteria**, click **Content: Content type (exposed)** and check the box that says **Allow multiple selections**. Save the setting then save the View.

---
Tags: views, 9
---


# Question
Title: mime type ('text/html') is not supported stylesheet MIME type, and strict MIME checking is enabled
Im just trying to add Fontawesome to my new custom theme in libraries.yml but im getting: mime type ('text/html') is not supported stylesheet MIME type, and strict MIME checking is enabled.

```
global-fontawesome:
  version: 6.2.0
  css:
    theme:
      fontawesome/css/fontawesome.min.css: {}

```

# Answer
> 1 votes
SOLVED:

Just adding attributes:

```
global-fontawesome:
  version: 6.2.0
  css:
    theme:
      fontawesome/css/fontawesome.min.css: {attributes:{type: "text/html"}}

```

---
Tags: theming
---


# Question
Title: Getting error "PHP files in the Drupal files directory can be executed." in Security Review v.7.x-1.3
I am on Drupal 7.92. When I run Security Review I get the error "PHP files in the Drupal files directory can be executed." in Security Review v.7.x-1.3. The sites/default/files directory is set to 770 apache:apache.

I run the following command in sites/default/files to find any PHP files:

```
find . -name "*.php"

```

It returns nothing. Why am I getting this error, and how do I fix it?

# Answer
Security Review actually places a PHP file in that directory and executes it, proving that PHP execution is possible. In addition Security Review checks for the existence and the contents of an `.htaccess` file in the files directory. On Apache web server a properly-configured `.htaccess` file there will prevent PHP execution.

So the most likely case is that `.htaccess` is missing or its contents are incorrect.
> 1 votes

---
Tags: 7, security
---


# Question
Title: Why does the site redirect from https to http when I do some modification?
Browsing through my site is working fine, but when I do some modification on my Drupal site, it goes to http instead of https, which gives "Connection timeout".

The Drupal site depend on drupal 9.4.5, nginx as web server, Cloudflare as DNS, Keycloak as SSO.

**Nginx site conf:**

```
server {
    server_name example.com www.example.com;
    root /var/www/www.example.com/web;
    listen 80;
    listen 443 ssl;
    listen [::]:443 ssl;
    include snippets/snakeoil.conf;
    client_max_body_size 10M;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

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

    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

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

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

    location ~ ^/sites/[^/]+/files/.*\.php$ {
        deny all;
    }

    location ~* ^/.well-known/ {
        allow all;
    }

    location ~ (^|/)\. {
        return 403;
    }

    location / {
        try_files $uri /index.php?$query_string;
    }

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

    location ~ /vendor/.*\.php$ {
        deny all;
        return 404;
    }

    location ~* \.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$ {
        deny all;
        return 404;
    }

    location ~ '\.php$|^/update.php' {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        try_files $fastcgi_script_name =404;
        include fastcgi_params;
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_intercept_errors on;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
    }

    location ~ ^/sites/.*/files/styles/ {
        try_files $uri @rewrite;
    }

    location ~ ^(/[a-z\-]+)?/system/files/ {
        try_files $uri /index.php?$query_string;
    }

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

    if ($request_uri ~* "^(.*/)index\.php(.*)") {
        return 307 $1$2;
    }
}

```

**Cloudflare DNS records:**

```
;; A Records
example.com.    1   IN  A   SERVER_IP_ADDRESS

;; CNAME Records
www.example.com.    1   IN  CNAME   example.com.

```

I'm not sure in which component should be this issue.

# Answer
Set `fastcgi_param HTTPS 'on';`.

Source: https://ma.ttias.be/setting-https-server-variables-in-php-fpm-with-nginx/
> 1 votes

---
Tags: 9
---


# Question
Title: Printing the node title instead of the file name from a field
I have a block view, which is an unformatted list which prints my content type. All content has a field\_file which I access using `views-view--download--field-file.html.twig`.

This prints a file link with the filename, like normal. But is it possible to replace for example `document.txt` with `Document node title`?

# Answer
> 1 votes
You can handle it directly from your View configuration using the "Rewrite results" option from field configuration.

* Edit your View
* Under the fields section, add your *Content: title* field, chexk "Exclude from display" and uncheck "Link to the content".
* then, add your file field *Content: my\_file\_field*, choose the formatter "URL to file" and expand the Rewrite results section. Check *Override the output of this field with custom text* and use the textarea to write the replacement text. It accepts HTML and, most importantly, tokens (you can see the list of available tokens under the "Replacement patterns" section). In the end, something like `<a href="{{ field_my_file_field }}">{{ title }}</a>` would do the trick.

---
Tags: 9
---


# Question
Title: How do I update existing Nodes field through Import without having to delete all content and re-importing everything?
We built an application for a client of ours to track appeals and cases of a legal case. There are currently over 2,000 entries in the system. After we built the app, it was requested we add four more fields for allocation amounts. We added the fields, but he would like to now import the content (which he has already put in a csv format, in proper order for an import).

We originally used Node Import module to import all of the content (I believe 1700 of the 2000 entries were entered through the initial import). However now that we have added extra fields, Node import does not have functionality to import into empty fields, mainly I believe because it does not have the ability to identiy unique identifiers and see that an entry already exists for that Node title.

Node Import Update module, from what I read in the description of the module should be able to do it. However after installing this module and doing the import again, it does not work, instead it creates duplicative entries.

In Node Import Update module's known issues page (http://drupal.org/node/813978), it says one needs to go in and update the node type you want to import. I do not know what value it is asking for here. The name of the Content Type in which the fields are in? This is what I currently have it set to. I know Title is correct - not sure about the node type:

Set custom data * These should/could be defined in admin * \*/ // Node title as unique identifier //$IMPORT\_UNIQUE\_ID\_NAME = 'title'; // Import field that holds the unique identifier //$IMPORT\_UNIQUE\_ID\_IS\_CCK = FALSE; // Is the identifier a CCK field?

```
// CCK field as unique identifier
$IMPORT_UNIQUE_ID_NAME   = 'title';  // Import field that holds the unique identifier
$IMPORT_UNIQUE_ID_IS_CCK = FALSE;    // Is the identifier a CCK field?

$IMPORT_NTYPE            = 'node';   // Node type to be imported
$IMPORT_UPDATE_DATETIME  = TRUE;        // Settting: update date/time value?

```

Sorry if it is long winded - however I wanted to ensure I was complete in describing the issue as I really need to get this wrapped up for my client. Thanks!!!

# Answer
I'm pretty sure you'll be happy with the excellent Feeds module, which does this every day for thousands of sites. More advanced/customizable techniques are available with Migrate module, which always requires code, but gives enormous flexibility. Both will allow you to update existing nodes. Had you used them for your initial import, you'd be done now. I think you still may be able to use them as long as you have a unique identifier on your existing nodes.
> 2 votes

# Answer
I'd suggest some custom code that does a SQL UPDATE to your node entries based on the unique ID, in your case the "title" field. I suspect your case is too specific for a general community contributed module. This is not a large task provided you know where to poke. Please post your solution if you get this working.
> 0 votes

# Answer
I have faced a similar situation before, it was in Drupal 8 though and i managed to resolve it by running this script on /devel/php. I was appending application numbers on records after they were created. Not exactly what you were looking for but I hope this will be helpful to someone in need.

```
#Script to be run to patch application numbers on applications
use Drupal\node\Entity\Node;
use Drupal\webform\Entity\Webform;
use Drupal\webform\Entity\WebformSubmission;
use Drupal\webform\WebformSubmissionForm;
use Drupal\Core\Database\Database;

$entityStorage = \Drupal::entityTypeManager()->getStorage('node');
$query = $entityStorage->getQuery();
$query->condition('type', 're_sponsorship_appl_processing');
$query->notExists('field_application_number_c');
$nids = $query->execute();
$nodes = $entityStorage->loadMultiple($nids);

foreach ($nodes as $node) {
    #append the data to the fields here
    try{

        $conn = Database::getConnection();
        $query = $conn->select('appldtefRe_sponsorship', 'a')
        ->condition('a.submissions', $node->get('field_progression_appl_submissio')->target_id, '=')
        ->fields('a', ['serial']);

        $result = $query->execute();
        foreach ($result as $record) {
            #only one record will be returned here, save number to variable
            $appl_postfix = $record->serial;
        }

        if($appl_postfix){
            $app_num = "SR/2022/" . str_pad($appl_postfix, 6, "0", STR_PAD_LEFT);
            $node->set('field_application_number_c', $app_num);
            $node->save();
        }

    } catch(Exception $ex){

        \Drupal::logger('test submission')->error($ex->getMessage());
    }
}

```
> 0 votes

---
Tags: importing-exporting, nodes
---


# Question
Title: Replacement for hook_user_presave() for saving values captured in the user form to the user profile
I am porting a module from Drupal 7 to Drupal 9. The code uses `hook_user_presave()` to save two fields on the fly into the user profile data.

```
/**
 * Implements hook_user_presave().
 */
function affiliate_user_presave(&$edit, $account, $category) {
  $edit['data']['affiliate_optin'] = isset($edit['affiliate_optin']) ? $edit['affiliate_optin'] : 0;
  $edit['data']['affiliate_homepage'] = isset($edit['affiliate_homepage']) ? $edit['affiliate_homepage'] : FALSE;
}

```

The similar one in Drupal 9 seems to be `hook_entity_presave()`.

```
/**
 * Implements hook_ENTITY_TYPE_presave() for user entities.
 */
function uber_affiliate_user_presave(UserInterface $account) {
  // code here
}

```

However there is only a single parameter to the function and so the edit values in the user profile form submit are not available here. So this means that there are better alternatives in Drupal 9.

I am thinking of writing an event subscriber, but it won't get the form submitted values.

# Answer
> 3 votes
As pointed out from @cilefen, the `$edit` parameter has been removed from the parameter passed to `hook_user_presave()`, which (starting from Drupal 8) is now documented under `hook_ENTITY_TYPE_presave()`. $edit argument removed from hook\_user\_update/insert/presave() is the relevant change record.

The only way to get the submitted form values is to add a form submission handler to the form with `hook_form_alter()` or `hook_form_FORM_ID_alter()`. Form submission handlers, like form validation handlers(), have access to the submitted values via `$form_state->getValue()`, to get a single submitted value, or `$form_state->getValues()`, to get an array containing all the submitted values.

Also, what that code saves in `$edit['data']` now needs to be saved with `UserData::set()`. Since that class is used to implement a service, the correct code to use it is similar to the following one.

```
$user_data = Drupal::service('user.data');
$user_data->set($module, $uid, $name, $value);

```

The parameters are the following.

* `$module`
the machine name of the module that is saving the data
* `$uid`
the user ID to which the data is associated
* `$name`
the name associated with the saved data
* `$data`
the data to save

To get the already saved data, or to check it has been already saved, there is `UserData::get()`. Passing `$module`, `$uid`, and `$name` that method will return `NULL` when the data hasn't been yet saved.

The change record that documents the new *user.data* service is users.data column replaced with user\_data API.

---
Tags: forms, users, hooks, 9
---


title: How to get checkboxes values in a form?

text:
# Question
Title: How to get checkboxes values in a form?
This is my code :

```
$form['how_many'] = [
  '#type' => 'checkboxes',
  '#required' => true,
  '#options' => [
     '1' => t('one'),
     '2' => t('two'),
     '3' => t('three')
  ],
  '#title' => t('How many')
];

```

I want to get the checkbox values.

When I do `$form_state->getValue('how_many');`, I get an array with filed value as well as non-filled as 0.

If i do `$form_state->getValue('how_many[1]');`, I get nothing and if I do `$form_state->getCheckedCheckboxes('how many')`, the page shows nothing.

# Answer
May be you can try this:

```
$result = $form_state->getValue('how_many');
$value = array_filter($result);

//print to check the value

print_r($value);

```
> 3 votes

# Answer
Sometimes when using `$form_state->getValue()` you can end up with the first checkbox as checked even if it isn't checked, `getUserInput()` is more accurate.

What you can do instead is this:

```
$selection = $form_state->getUserInput()['how_many'] ?? [];
foreach ($selection as $id => $box) {
  $checked = isset($box);
  // Do something here...
}

```

When something is checked, you'll get a value of 0, otherwise it'll be empty.
> 0 votes

---
Tags: forms, 8
---


# Question
Title: Unable to install theme: '…' due to unmet module dependencies: '1'
I have a weird error with a custom theme (called `uv_basic_theme`). It ran well under Drupal 8, and now I've upgraded the site to Drupal 9. (9.4.4)

After upgrade, the status report listed this error:

```
1 (required)
UV Basic Theme requires this module.

```

Yes, it says "1 (required)". What could it mean?

I already assumed some faulty line in the info.yml, but I can't see anything wrong:

```
name: UV Basic Theme
description: Boilerplate Theme for Drupal 8
type: theme
base theme: true
core: 8.x
core_version_requirement: ^8 || ^9
libraries:
  - uv_basic_theme/global-css
  - uv_basic_theme/global-js
stylesheets-remove:
  - core/themes/stable/css/views/views.module.css
  - core/themes/stable/css/system/components/align.module.css
regions:
  header: 'Header'
  highlighted: 'Highlighted'
  navigation: 'Main Navigation'
  content: 'Main Content'
dependencies: []
module_dependencies: []

```

Yes, I've added dependencies and module\_dependencies to see if it would fix it but no.

# Answer
OK, I just saw the culprit:

```
base theme: true

```

Instead, it has to be either `false`, or a theme name.
> 1 votes

---
Tags: theming, upgrading
---


# Question
Title: How can I compare two fields in a filter?
Since Drupal 9 no longer has the *Globals: Fields Comparison* option (as Drupal 7 did) in the view's filter section, how can I compare two fields?

# Answer
The patch here: https://www.drupal.org/project/drupal/issues/3155249 restores the field comparison functionality in views and solved my issue.
> 0 votes

---
Tags: views, 9
---


title: How to get S3 file path from URI?

text:
# Question
Title: How to get S3 file path from URI?
So inside my hook function I have URI of some file and I need to find it's S3 path (using s3fs module). How can I do that, to avoid manual string manipulation? Is there some helper function?

I found convertUriToKeyedPath() of S3fsStream class but it's protected and also it says "Converts a Drupal URI path into what is expected to be stored in S3" and that "expect is potentially dangerous.

# Answer
Use file\_url\_generator service:

```
$uri = 's3://bucket/file.ext';
$url = \Drupal::service('file_url_generator')->generateAbsoluteString($uri);

```

An old way (deprecated as of 9.3):

```
$http_url = file_create_url($uri);

```
> 0 votes

---
Tags: 8
---


# Question
Title: Removing Duplicates with hook_views_prerender
I have a view (filtering on content) that is returning duplicates. I am trying to used hook\_view\_prerender to remove those duplicates... but even after running this, I still get duplicates... Any ideas? Here's my function (and yes I know the function is running):

`function customedm_views_pre_render(&$view) {
 $used_nids = array();
 if ($view->name == 'new_resources'){
 echo ('hi');
 foreach ($view->result as $row){
 if (!in_array($row->nid, $used_nids)) {
 $new_view_result[] = $row;
 $used_nids[] = $row->nid;
 }
 }
 $view->result = $new_view_result;
 }
 }`

# Answer
You do not need to do this - simply use Distinct.

Edit the View, open the Advanced section -\> Query Settings -\> check the "Distinct" checkbox and save the view.

Edit: In case you do use Distinct already, there are some cases where this can occur. Here is an issue discussing this - https://www.drupal.org/node/1765730, and this one has a code example that manipulates the result similarly to what you are trying to do - https://www.drupal.org/node/1223448#comment-4757898
> 0 votes

# Answer
This is an old question, but someone might end up here (as I did) because distinct or even aggregation does not always remove all duplicates. In the specific example above, the $new\_view\_result array should have been declared outside of the loop(foreach). Here's code that would work in Drupal 8 / 9 / 10:

```
/**
 * Implements hook_views_pre_render().
 */
function customedm_views_pre_render(&$view) {
  if (
    $view->storage->id() == 'new_resources' &&
    $view->current_display == 'block_1'
  ) {
    $used_nids = [];
    $new_view_result = [];
    foreach ($view->result as $row) {
      if (!in_array($row->nid, $used_nids)) {
        $new_view_result[] = $row;
        $used_nids[] = $row->nid;
      }
    }
    $view->result = $new_view_result;
  }
}

```
> 1 votes

# Answer
This might help https://www.drupal.org/project/views\_distinct

The views distinct module has removed all duplicates from my views.
> 0 votes

---
Tags: views, hooks
---


# Question
Title: Without site aliases, "drush sql:sync" fails
I run into an issue that the use of an alias returns correct values, but without alias or from remote, I miss the DB connection. Furthermore, the root directory is wrong. The missing DB connection prevents a drush sql:sync run.

Alias file:

```
$drush sa
'@self.dev':
  root: /var/www/html/xyz
  uri: 'https://www.abcdef.com'
  ssh:
    options: '-i xyz.pem'
  paths:
    drush-script: /home/ubuntu/vendor/bin/drush
    files: themes
  command:
    core:
      rsync:
        options:
          mode: rlptz

```

running drush status somewhere:

```
$ drush st
PHP binary    : /usr/bin/php7.4
PHP config    : /etc/php/7.4/cli/php.ini
PHP OS        : Linux
Drush script  : /home/ubuntu/vendor/drush/drush/drush
Drush version : 10.6.2
Drush temp    : /tmp
Drush configs : /home/ubuntu/.drush/drush.yml
                /home/ubuntu/vendor/drush/drush/drush.yml

```

running drush status with alias:

```
$ drush @dev st
Drupal version   : 9.4.5
Site URI         : https://www.abcdef.com
DB driver        : mysql
DB hostname      : 127.0.0.1
DB port          : 3306
DB username      : qwertzy
DB name          : drupal
Database         : Connected
Drupal bootstrap : Successful
Default theme    : xyz
Admin theme      : seven
PHP binary       : /usr/bin/php7.4
PHP config       : /etc/php/7.4/cli/php.ini
PHP OS           : Linux
Drush script     : /var/www/html/xyz/vendor/drush/drush/drush
Drush version    : 10.6.2
Drush temp       : /tmp
Drush configs    : /home/ubuntu/.drush/drush.yml
                   /var/www/html/xyz/vendor/drush/drush/drush.yml
Install profile  : standard
Drupal root      : /var/www/html/xyz/web
Site path        : sites/default
Files, Public    : sites/default/files
Files, Private   : /var/private
Files, Temp      : /tmp

```

running drush status in the drupal root: ! Wrong drupal root returned

```
cd /var/www/html/xyz
$ drush st
PHP binary    : /usr/bin/php7.4
PHP config    : /etc/php/7.4/cli/php.ini
PHP OS        : Linux
Drush script  : /home/ubuntu/vendor/drush/drush/drush
Drush version : 10.6.2
Drush temp    : /tmp
Drush configs : /home/ubuntu/.drush/drush.yml
                /home/ubuntu/vendor/drush/drush/drush.yml
Drupal root   : /var/www/html/xyz/web/web

```

called from remote with alias: ! Again wrong drupal root returned

```
ubuntu@ip-172-26-13-167 ~ $ drush @dev st
PHP binary    : /usr/bin/php7.4
PHP config    : /etc/php/7.4/cli/php.ini
PHP OS        : Linux
Drush script  : /home/ubuntu/vendor/bin/drush
Drush version : 10.6.2
Drush temp    : /tmp
Drush configs : /home/ubuntu/.drush/drush.yml
                /home/ubuntu/vendor/drush/drush/drush.yml
Drupal root   : /var/www/html/xyz/web/web
Connection to 172.26.10.26 closed.

```

Any advice appreciated how to fix this.

# Answer
> 0 votes
I've commented because there are some things in your installation that don't add up. But the comments lead to nowhere so I try to make it more clear in an answer.

In a comment you say:

> Drush launcher is installed.

but then "running drush status somewhere" should result in:

```
The Drush launcher could not find a Drupal site to operate on. Please do *one* of the following:
  - Navigate to any where within your Drupal project and try again.
  - Add --root=/path/to/drupal so Drush knows where your site is located.

```

So the question is, what is this globally installed script which runs when you are in a Drupal root directory

```
/home/ubuntu/vendor/drush/drush/drush

```

when it is not the Drush Launcher?

---
Tags: drush
---


title: How to query webform submissions table

text:
# Question
Title: How to query webform submissions table
I have a webform which contains a field of visit\_date, and 3 fields of time selection visit\_time\_1,visit\_time\_2 and visit\_time\_3 which at least one must be filled and they cannot have same time with each other.

Upon submission I want to check whether another user has already submitted the same visit\_date and the same time of visit in any of the visit\_time\_1,visit\_time\_2 and visit\_time\_3 fields in case they are not null (e.g. I need to know whether visit\_time\_1=visit\_time\_2 etc).

For this reason I query the webform\_submission\_data which has the EAV model, therefore I tried to implement the solution found here. The query I have so far is this one

```
SELECT DISTINCT sid
 FROM webform_submission_data wsd
 WHERE wsd.webform_id = 'book_visit_form'
 AND sid IN (SELECT sid FROM webform_submission_data wsd2
              WHERE wsd2.value = '2022-10-20'
                AND wsd2.name = 'visit_date')
 AND (
  sid IN (SELECT sid FROM webform_submission_data wsd3
              WHERE wsd3.value IN ('15:00:00','16:00:00','17:00:00')
                AND wsd3.name = 'visit_time_1')
 OR sid IN (SELECT sid FROM webform_submission_data wsd4
              WHERE wsd4.value IN ('15:00:00','16:00:00','17:00:00')
                AND wsd4.name = 'visit_time_2')
 OR sid IN (SELECT sid FROM webform_submission_data wsd5
              WHERE wsd5.value IN ('15:00:00','16:00:00','17:00:00')
                AND wsd5.name = 'visit_time_3')
 )
                ;

```

So my question is whether my logic is correct or should I change something in my query in order to get the desired results.

# Answer
> 0 votes
You can probably reduce the three OR'd queries into one by using `AND wsd3.name LIKE 'visit_time_%'`

---
Tags: webforms
---


title: How do I alter the entity type class?

text:
# Question
Title: How do I alter the entity type class?
In Drupal 8 you can load an entity with:

```
$node = \Drupal::entityManager()->getStorage('node')->load(123);

```

This looks for the entity definitions and finds that *node* is defined by *Drupal\node\Entity\Node* \- so (I guess) *Drupal\node\NodeStorage* will instantiate a new *Drupal\node\Entity\Node* instance.

What I'd like to achieve is subclassing *Drupal\node\Entity\Node* and being able to instantiate this subclass when it's appropriate. For example if I have a node bundle article, there would be a class:

```
namespace Drupal\my_module\Entity\Article;
class Article extends Drupal\node\Entity\Node {
}

```

And I'd call:

```
$node = \Drupal::entityManager()->getStorage('node_article')->load(123);

```

And the return would be my `Article` subclass.

I can achieve this by creating a new entity type and wiring it back to another existing entity definitions, for example the node-article example would be this class:

```
namespace Drupal\my_module\Entity;
use Drupal\node\Entity\Node;
/**
 * @ContentEntityType(
 *   id = "node_article",
 *   label = @Translation("Content"),
 *   bundle_label = @Translation("Content type"),
 *   handlers = {
 *     "storage" = "Drupal\node\NodeStorage",
 *     "storage_schema" = "Drupal\node\NodeStorageSchema",
 *     "view_builder" = "Drupal\node\NodeViewBuilder",
 *     "access" = "Drupal\node\NodeAccessControlHandler",
 *     "views_data" = "Drupal\node\NodeViewsData",
 *     "form" = {
 *       "default" = "Drupal\node\NodeForm",
 *       "delete" = "Drupal\node\Form\NodeDeleteForm",
 *       "edit" = "Drupal\node\NodeForm"
 *     },
 *     "route_provider" = {
 *       "html" = "Drupal\node\Entity\NodeRouteProvider",
 *     },
 *     "list_builder" = "Drupal\node\NodeListBuilder",
 *     "translation" = "Drupal\node\NodeTranslationHandler"
 *   },
 *   base_table = "node",
 *   data_table = "node_field_data",
 *   revision_table = "node_revision",
 *   revision_data_table = "node_field_revision",
 *   translatable = TRUE,
 *   list_cache_contexts = { "user.node_grants:view" },
 *   entity_keys = {
 *     "id" = "nid",
 *     "revision" = "vid",
 *     "bundle" = "type",
 *     "label" = "title",
 *     "langcode" = "langcode",
 *     "uuid" = "uuid",
 *     "status" = "status",
 *     "uid" = "uid",
 *   },
 *   bundle_entity_type = "node_type",
 *   field_ui_base_route = "entity.node_type.edit_form",
 *   common_reference_target = TRUE,
 *   permission_granularity = "bundle",
 *   links = {
 *     "canonical" = "/node/{node}",
 *     "delete-form" = "/node/{node}/delete",
 *     "edit-form" = "/node/{node}/edit",
 *     "version-history" = "/node/{node}/revisions",
 *     "revision" = "/node/{node}/revisions/{node_revision}/view",
 *   }
 * )
 */
class Article extends Node { }

// Results my Article sub type.
$node = \Drupal::entityManager()->getStorage('node_article')->load(123);

```

This works fine (as much as I can see); however, it smells. It adds a new entity type, which is not true, and might cause other troubles in the future.

How do I define a subclass for an entity bundle so that loading the entity would return an object of that class?

# Answer
> 16 votes
Create a new class in your module that extends `\Drupal\node\Entity\Node`.

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

class MyNode extends BaseNode {
}

```

Implement `hook_entity_type_build()`.

```
use Drupal\Core\Entity\EntityTypeInterface;

/**
 * @param EntityTypeInterface[] $entity_types
 */
function my_module_entity_type_build(&$entity_types) {
  if (isset($entity_types['node'])) {
    $entity_types['node']->setClass('Drupal\my_module\Entity\MyNode');
  }
}

```

Remember to rebuild the cache.

It works fine when loading nodes via the entity type manager service and the node storage. It even works when you just use `Drupal\node\Entity\Node::load($nid)` thanks to the fact that this `load()` function it is just a static wrapper for the entity type manager service call provided by the `Entity` class which is extended from the `Node` class.

```
// Part of Entity class for reference
abstract class Entity implements EntityInterface {
  /**
   * Loads an entity.
   *
   * @param mixed $id
   *   The id of the entity to load.
   *
   * @return static
   *   The entity object or NULL if there is no entity with the given ID.
   */
  public static function load($id) {
    $entity_manager = \Drupal::entityManager();
    return $entity_manager->getStorage($entity_manager->getEntityTypeFromClass(get_called_class()))->load($id);
  }
}

```

This also works fine with the soon-to-be-removed `entity_load_multiple()` function, so I guess this covers all standard use cases for loading nodes.

Of course, if your module does this and another module does the same, you'll have a problem, but I guess it's not common scenario, and it makes sense only for very specific use cases.

# Answer
> 5 votes
From Drupal 9.3, there is support for entity bundle classes included in core.

So now you can subclass your entity bundles as much as you like without needing any contrib modules.

The core change record is extensive, but basically this:

```
use Drupal\mymodule\Entity\BasicPage;

function mymodule_entity_bundle_info_alter(array &$bundles): void {
  if (isset($bundles['node']['page'])) {
    $bundles['node']['page']['class'] = BasicPage::class;
  }
}

```

# Answer
> 3 votes
I experienced the same issue and decided to create a module that alter the entity type class of Drupal entities via the plugin system. Currently it supports altering the `Node`, `User` and `File` entity classes. When altering the `Node` entitiy you are able to alter the type class per node bundle.

Check out the module description for an example:

https://www.drupal.org/project/entity\_type\_class

The module uses hook\_entity\_type\_alter() to set a handler class on entities that you provide in your plugin annotation.

# Answer
> 3 votes
This module also gives you real bundle classes - https://github.com/amcgowanca/discoverable\_entity\_bundle\_classes

# Answer
> 1 votes
This is an old question, but the real answer should be:

If you need different behaviour across bundles, then you should be using different entity types, not different bundles.

Custom Content Entities are 1st class citizens in D8. In fact we estimate that it takes about 30 minutes to get a new custom content entity to the level that node is (which really just comes down to adding the Form UI to get the nice side panel, and the alias/revision fields.) This doesn't include adding the translation pages, but that isn't that much more.

If you haven't seen it, take a look at the Drupal Console's generate:custom:entity features.

---
Tags: 8, entities
---


# Question
Title: What is the difference between Platform CDN and Cloudflare?
The cloud provider I use(Acquia) has a set of API endpoints, and one of them is to clear caches, including Platform CDN + Varnish.

When I read Platform CDN, it gets me wonder where Cloudflare then sits as the CDN provider?

# Answer
Most of the big Drupal hosts now offer some kind of CDN:

* Acquia has Platform CDN (not sure what this is underneath)
* Pantheon has what they call a "Global CDN" but it is also rebranded Fastly
* PlatformSH offers Fastly on dedicated plans

The configuration for these CDNs is managed by the web host, so the layers are:

1. Your registar (for example.com), where you set nameservers to point to the host
2. Webhost's CDN
3. Webhost's webservers

Now, some people really like CloudFlare or they want to use a CloudFlare-only feature, like their Analytics or Page Rules or something. (We'll use CloudFlare as an example here, but it could be another CDN, too. There's nothing that makes this question CloudFlare-specific.)

In that case, you may add a separate CDN on top of the webhost's CDN, which would give you layers like this:

1. Your registrar, where you point the nameservers to CloudFlare
2. Cloudflare's CDN, which points to your webhost
3. Webhost's CDN
4. Webhost's webservers

This is generally overkill and makes things more complicated because now if you need to clear all caches, you need to clear CloudFlare plus the host's CDN cache plus your Drupal cache. In addition, you probably won't get much support from the host for this second CDN, so you'll likely need to write some custom code to make sure your site and the second CDN are working together properly.

But if you want to do it, it's possible.
> 2 votes

---
Tags: caching
---


# Question
Title: How can I have "minimum-stability": "stable" in my composer.json and install alpha version of a contrib module?
Trying to update Drupal core to 9.4.7 with `composer update "drupal/core-*" --with-all-dependencies`, I got 9.5.0-beta1 version.
Digging a little in Drupal Answers, I found 'Update installs a beta version' and 'How do I update from 9.0.10 to 9.1.0?'.
So I changed my composer.json to `"minimum-stability": "stable"`.
But then I had an issue with Mime Mail contrib module which only version for Drupal 9 is 8.x-1.0-alpha4.

The only solution I found was to

1. remove Mime Mail
2. update Drupal with composer
3. go back to `"minimum-stability": "dev"`
4. install Mime Mail with Composer

I'm pretty sure this is not the best way to do it...
Any advice on how to handle this situation?
Thanks in advance.

# Answer
> 2 votes
Answering the title:

> How can I have "minimum-stability": "stable" in my composer.json and install alpha version of a contrib module?

All you need to do is specify `version@alpha` for that module in `composer.json`.

For example, my `composer.json` has `minimum-stability: "beta"`, but I have the alpha version of the Field Tools module installed as a dev dependency:

```
  "drupal/field_tools": "^1@alpha",

```

---
Tags: 9, composer
---


# Question
Title: How to add additional drupalSettings to all pages with an event subscriber
I need to set the user timezone on all pages in the JS `drupalSettings` object, so that it can be accessed on any page. As `drupalSettings.user` is provided by core, I want to set `drupalSettings.user.timezone`, with the user timezone from the server.

While this can quickly and easily be done in hook\_page\_attachments(), I am trying to switch from using hooks, to using Event Subscribers, as Drupal hooks are the old paradigm, and event subscribers is the new paradigm.

Can someone explain how to add attached assets (a library, or drupalSettings) to all pages from an event subscriber?

### Additional Context

As mentioned by 4uk4 in the comments, this event is not dispatched by Drupal core, but rather by Symfony underneath the hood. This means it is not a true 'Drupal' methodology, as core maintainers have not chosen to dispatch an event that is equivalent to hook\_page\_attachments(). So which is better? The answer is 'neither' at this point, as core is ambivalent as to whether it invokes a hook or dispatches an event. It does however seem that core is moving towards creating events that match existing hooks, as can be seen in this issue: https://www.drupal.org/project/drupal/issues/2551893. And here is a discussion that considers the differences between hooks and events: https://www.previousnext.com.au/blog/alter-or-dispatch-drupal-8-events-versus-alter-hooks

# Answer
This can be done by acting upon the `Symfony\Component\HttpKernel\KernelEvents::RESPONSE` event. See the code below for an example (Note - you'll need to register the event subscriber, which is not shown here):

```
namespace Drupal\[MODULE]\EventSubscriber;

use Drupal\Core\Render\AttachmentsInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Adds the user's timezone to the drupalSettings JS object on all pages.
 */
class SetUserTimezoneToDrupalSettings implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      // Respond to KernelEvents::RESPONSE.
      KernelEvents::RESPONSE => ['onResponse', 1000],
    ];
  }

  /**
   * Event handler for KernelEvents::RESPONSE.
   */
  public function onResponse(\Symfony\Component\HttpKernel\Event\ResponseEvent $event) {
    // Only act upon the master request and not sub-requests.
    if ($event->isMasterRequest()) {
      $response = $event->getResponse();
      // Only act if the response is one that is able to have attachments.
      if ($response instanceof AttachmentsInterface) {
        // Get any existing attachments.
        $attachments = $response->getAttachments();
        // Set the user's timezone to the drupalSettings array.
        $attachments['drupalSettings']['user']['timezone'] = date_default_timezone_get();
        // Set the updated array back on the object.
        $response->setAttachments($attachments);
      }
    }
  }

}

```
> 3 votes

---
Tags: 9, event-subscribers
---


# Question
Title: drupal_render() is deprecated. What replaces it?
I have a render array and I want to convert it to HTML and place it in a WYSIWYG field. What is the generally accepted way to do that since drupal\_render() is deprecated?

# Answer
It was replaced with the renderer service.

```
$render_service = \Drupal::service('renderer');

```

As mpdonadio and 4k4 have pointed out in the comments, to prevent metadata from bubbling up to the main request, you should execute this in a new render context. You can do so by using the `renderPlain` method, rather than the usual `render` method (unless you're returning this from a controller, in which case use `renderRoot` instead).

```
$rendered = $render_service->renderPlain($build);

```
> 8 votes

# Answer
This documentation is the best place to have the most accurate/up-to-date documentation about the rendering pipeline and its methods - such as `drupal_render()` \- in Drupal 8+.
> 1 votes

---
Tags: wysiwyg, 8
---


# Question
Title: How do I convert a TranslatableMarkup instance to a string with PHP Strict mode?
In my ongoing quest to write better code, I have started experimenting with PHP strict mode (`declare(strict_types=1)`).

Apparently CKEditor5 module does this in core as well.

Using strict mode, I was able to fix several issues with my code, but there is one issue I don't understand how to fix properly.

For example, here is a standard custom form validator:

```
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);

    $code = $form_state->getValue('code');
    Assert::string($code, 'Invalid email verify code! %s');

    if (strlen($code) >= 4) {
      $form_state->setErrorByName('code', $this->t('The code is 3 numbers or less.'));
    }

```

PHPStan flags the line `$form_state->setErrorByName('code', $this->t('The code is 3 numbers or less.'));` with this error:

> 117 Parameter #2 $message of method Drupal\Core\Form\FormStateInterface::setErrorByName() expects string, Drupal\Core\StringTranslation\TranslatableMarkup given.

I can fix the error by casting to a string like this:

```
if (strlen($code) >= 4) {
  $translated_error_message = $this->t('The code is 3 numbers or less.');
  $form_state->setErrorByName('code', "$translated_error_message");
}

```

But this seems a bit ugly. What's the most efficient way to fix this?

# Answer
Casting a `TranslatableMarkup` instance to a class (or causing PHP to cast it to a string) means calling `TranslatableMarkup::__toString()` (a method implementing by `ToStringTrait`), which essentially calls `TranslatableMarkup::render()`). The code you are using isn't ugly. It's not efficent, as the documentation for `TranslatabeMarkup` says in the class description. (Emphasis is mine.)

> This object, when cast to a string, will return the formatted, translated string. Avoid casting it to a string yourself, because it is preferable to let the **rendering system do the cast as late as possible** in the rendering process, **so that this object itself can be put, untranslated, into render caches** and thus **the cache can be shared between different language contexts**.

I would ignore what reported by PHPStan, or set it to avoid that particular report. If I had to cast a `TranslatableMarkup` instance to a string, I would use the code you wrote, or similar one, at least because `__toString()` avoids some fatals, which is the reason why `ToStringTrait` is used by Drupal.
> 3 votes

# Answer
You can get the string value of TranslatableMarkup by rendering the value:

```
$form_state->setErrorByName('code', $this->t('The code is 3 numbers or less.')->render());

```
> 1 votes

# Answer
There is a placeholder issue for this in the `phpstan-drupal` repo: https://github.com/mglaman/phpstan-drupal/issues/422

So for now, you can ignore such issues in `phpstan.neon`:

```
parameters:
    ignoreErrors:
      # String casts should happen as late as possible. https://drupal.stackexchange.com/a/312254
      - "#expects string, Drupal\\\\Core\\\\StringTranslation\\\\TranslatableMarkup given#"

```
> 0 votes

---
Tags: 9
---


# Question
Title: Change the "add entity" page title on a custom content entity type using alterRoutes()?
I created a custom content entity type **dog** using `drush generate entity:content`.

When I go to www.example.com/dog/add, the page title (the one in the `<title>` tag, not the `<h1>` tag) is "Add dog". I want to change this to "Send a dog to outer space (and bring him back safely)".

It seems there is no place to set the title in the entity annotations, so I attempted to add an event subscriber:

**dog/src/Routing/DogRouteSubscriber.php**

```
class DogRouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('entity.dog.add_form')) {
      $route->setDefault('_title', 'Send a dog to outer space (and bring him back safely)');
    }
  }
}

```

**dog.services.yml**

```
services:
  dog.route_subscriber:
    class: Drupal\dog\Routing\DogRouteSubscriber
    tags:
      - { name: event_subscriber }

```

I am using `$route->setDefault('_title', 'Send a dog to outer space (and bring him back safely)'` based on code in this blog post, but even after rebuilding the cache, the page title isn't changed.

So: **Where do I alter (or set) the entity add form's page title?**

Similar but different questions:

# Answer
If your entity uses DefaultHtmlRouteProvider as route\_provider handler then it sets a title callback which has a higher priority than the static title. So you would need to remove this default in alterRoutes().

However, if this is your own entity, a more straightforward approach would be to edit the entity annotations and replace the route\_provider handler with your own class , which extends DefaultHtmlRouteProvider and overrides the method getAddPageRoute():

```
  protected function getAddPageRoute(EntityTypeInterface $entity_type) {
    if ($entity_type->hasLinkTemplate('add-page') && $entity_type->getKey('bundle')) {
      $route = new Route($entity_type->getLinkTemplate('add-page'));
      $route->setDefault('_controller', EntityController::class . '::addPage');
      $route->setDefault('_title_callback', EntityController::class . '::addTitle');
      $route->setDefault('entity_type_id', $entity_type->id());
      $route->setRequirement('_entity_create_any_access', $entity_type->id());

      return $route;
    }
  }

```

Or keep the dynamic controller method and return the static text from there.
> 1 votes

# Answer
Wow, this turned out to be way more complex than I thought.

In addition to the DogRouteSubscriber shown in the original question, I had to override `getAddFormRoute` (because the basic entity type generated with `drush generate` does not have an `add-page` route) with my own DogHtmlRouteProvider class (as described in 4uk4's answer):

```
class DogHtmlRouteProvider extends DefaultHtmlRouteProvider {

  /**
   * Gets the add-form route.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity type.
   *
   * @return \Symfony\Component\Routing\Route|null
   *   The generated route, if available.
   */
  protected function getAddFormRoute(EntityTypeInterface $entity_type) {
    if ($entity_type->hasLinkTemplate('add-form')) {
      $entity_type_id = $entity_type->id();
      $route = new Route($entity_type->getLinkTemplate('add-form'));
      // Use the add form handler, if available, otherwise default.
      $operation = 'default';
      if ($entity_type->getFormClass('add')) {
        $operation = 'add';
      }
      $route->setDefaults([
        '_entity_form' => "{$entity_type_id}.{$operation}",
        'entity_type_id' => $entity_type_id,
      ]);

      $route
        ->setRequirement('_entity_create_access', $entity_type_id);

      return $route;
    }
  }

```

Here, I removed the line `$route->setDefault('_title_callback', EntityController::class . '::addTitle');` I did not override this with another method because `_title_callback` apparently only accepts a method on a descendant of EntityController, and my module doesn't have such a controller.
> 0 votes

---
Tags: entities, routes, 9
---


# Question
Title: How to set the text format in BaseFieldDefinition::create()?
I'm creating a base field (`text_long`) on a content entity and I want to limit it the **Plain text** text format for all users at all times.

I know I can use the Allowed Formats module to limit the options, but is there a way to do this when using BaseFieldDefinition::create()?

Here's the definition:

```
$fields['message'] = BaseFieldDefinition::create('text_long')
  ->setLabel(t('Message'))
  ->setRequired(TRUE)
  ->setDisplayOptions('form', [
    'type' => 'text_textarea',
    'weight' => 10,
  ])
  ->setDisplayConfigurable('form', TRUE)
  ->setDisplayOptions('view', [
    'type' => 'text_default',
    'label' => 'above',
    'weight' => 10,
  ])
  ->setDisplayConfigurable('view', TRUE);

```

PHPDoc says:

> Refer to \Drupal\Core\Field\FieldDefinitionInterface::getDisplayOptions() for a list of supported keys. The options should include at least a 'weight', or specify 'region' = 'hidden'. The 'default\_widget' / 'default\_formatter' for the field type will be used if no 'type' is specified.

However, the documentation for FieldDefinitionInterface::getDisplayOptions() isn't enough information for me to figure out how to restrict this to **Plain text**.

# Answer
There is no documentation for the content of the display options because every plugin you add to the configuration can add their own structure. Also modules not providing field plugins can still add arbitrary data to the third party settings. If the module providing this data doesn't have documentation about the internal config settings, which they normally don't do, you could consider their UI options as documentation. Configure a temporary field in UI and export the configuration. Check the YAML files modified by your config actions for the display options you can put in the base field definition.
> 1 votes

# Answer
Based on 4uk4's answer, these are the concrete steps to answer my question.

Note that you need to use the Allowed Formats module for now until this core issue is committed (relatively soon?).

This is a YML export of Allowed Formats restricting a field to plain\_text only:

```
settings:
  allowed_formats:
    - plain_text

```

This is a setting, not a display option, so you need to use `setSetting`:

```
  ->setSetting('allowed_formats', [0 => 'plain_text'])

```

This removes CKEditor from the field and restricts input to plain text.
> 0 votes

---
Tags: entities, 9
---


# Question
Title: Why is node save extremely slow with two or more tags after migrating tags and restoring from backup?
**The problem**
Saving a node with one tag saves normally. With two or more, the save takes upwards of 40 seconds. The problem only occurs after migrating in a set of tags from csv, then creating a mysqldump backup of the database and restoring the database.

**Migration Details**
4,457 tags were migrated
No errors
The "csv" file is tab separated... so really TSV
The tsv file has two fields only: OldTID and name
The migrated tags are flat: no hierarchy

**Configuration Details**
Drupal 9.4.7 fresh install via Composer, standard profile
Default theme (Olivero)
Standard install modules only, except for these:

* migration
* migrate\_plus
* migrate\_tools
* migrate\_source\_csv

OS: Ubuntu 22.04 lts
Database server: 10.6.7-MariaDB-2ubuntu1.1 - Ubuntu 22.04
Webserver: nginx 1.18.0
PHP: 8.1.2

**Steps to reproduce**

* Install Drupal via Composer: 9.4.7 Standard profile
* No advanced options during install
* Add one field to tags taxonomy: field\_old\_id
* Install drush via Composer (11.2.1)
* Install migrate\_plus, migrate\_tools, migrate source csv
    + Import the config for tags.yml
    + Run migration from drush, importing 4457 tags, flat
    + Create test node, selecting two tags: save is normal, \< 2 seconds
    + *Backup db* using command line mysqldump
    + Create new db
    + *Restore db* using command line mysql dbname \< dumpfile.sql, no changes to codebase
    + Test resave of the same node (2 tags): slow, \>40 seconds
    + Test save with one tag: normal, \< 2 seconds

**The migration yaml config**

```
uuid: 1bcec3e7-0a49-4473-87a2-6dca09b91abax-tags
id: tags
label: Import tags from tsv to taxonomy
migration_group: taxonomy
source:
  plugin: 'csv'
  path: '/srv/imports/tags.tab'
  delimiter: "\t"
  enclosure: '"'
  header_offset: null
  ids: [OldTID]
  fields:
    0:
      name: OldTID
      label: 'Old tag ID'
    1:
      name: name
      label: 'Tagname'

process:
  name: name
  field_old_id: OldTID
destination:
  plugin: entity:taxonomy_term
  default_bundle: tags

```

# Answer
This is not a *complete* answer, because we still don't know what in particular misbehaved and why.
But the problem has something to do with that version of MariaDB.

After adding the repository, etc., I was able to upgrade the MariaDB to 10.8.5.

Following the set of steps above, the problem no longer occurs.
> 0 votes

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


title: Entity Reference of multiple types

text:
# Question
Title: Entity Reference of multiple types
I would like build out page content using entity references. The problem is I would like to reference multiple types of entities (nodes and terms) plus content that is not an entity (views.)

I've explored this and what I have now is a field for both Node Reference and Term Reference and another with a View Reference which is not a very user-centric. Is there a more succinct way to achieve this?

# Answer
While relation can handle multiple entity types in a single relation type it can't reference Views. It's a challenging problem for two reasons: the `view_id` is a string unlike say `nid` so a database schema made to refer numeric IDs won't be able to copy with views. Also, views is not stored in the database necessarily so the utility of such reference is limited.

It should be possible to maintain an entity in the database that has a numeric ID and all it contains is the Views ID. Your only problem becomes when someone changes the machine of a view that is maintained in code -- how do you plan to be notified of such a thing when it happens outside of Drupal?
> 4 votes

# Answer
In Drupal 9 and beyond, this use case is covered by the Dynamic Entity Reference module, which in its latest 4.x version allows you to reference all content entities as well as config entities.

This feature may eventually end up in core.
> 0 votes

# Answer
How about https://drupal.org/project/entityreference and https://drupal.org/project/entityreference\_view\_widget for nodes and terms and https://drupal.org/project/views\_field\_view for embedding views?

Entity reference has nice usage statistics. I quickly tested Entityreference view widget, and it looks convincing (see the inspirational screen capture https://drupal.org/files/images/view\_widget.png). Views field view I didn't test, but its usage is around 10 000.
> -1 votes

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


# Question
Title: Call #ajax when a checkbox is checked or unchecked
I have a Drupal 7 form that I want to be a single checkbox. When the checkbox is checked, I want to call an ajax request that hits an API to update the value, same for when I uncheck it. However, this event is happening only once, unless I refresh the page.

Form code:

```
function mymodule_autorenew_form($form, &$form_state, $account, $renew_state, $order_id) {
  if (!isset($form_state['user'])) {
    $form_state['user'] = $account;
  }

  $form_state['order_id'] = $order_id;
  $renew_default = FALSE;

  if (in_array($renew_state, ['scheduled', 'complete'])) {
    $renew_default = TRUE;
  }

  $form['autorenew'] = array(
    '#type' => 'checkbox',
    '#description' => t('Enable auto-renewal'),
    '#ajax' => [
      'event' => 'change',
      'callback' => '_mymodule_autorenew_update',
      'progress' => 'none',
    ],
    '#default_value' => $renew_default,
  );

  return $form;
}

```

AJAX callback:

```
function _mymodule_autorenew_update($form, &$form_state) {
  $client = new ApiClient();
  $autorenew = (bool) $form_state['values']['autorenew'];
  $order_id = $form_state['order_id'];
  $response = $client->setAutoRenewState($autorenew, $order_id);
  cache_clear_all('mymodule_member:' . $form_state['user']->uid . ':membership', 'cache');
  return $form['autorenew'];
}

```

The first time you tick the box, the callback works and the data goes through the API. However subsequent clicks do nothing at all. What am I missing? $form\_state\['rebuild'\] is already TRUE.

edit: No submit or submit button is desired. The end result should be a toggle checkbox without additional elements.

# Answer
Its been too long with 7 that I don't recall all the innerworkings of #ajax with forms, but I wound up just building a new form and returning that. Now it works every single time. Likely not the *best* approach but we just need this for a short term feature.

```
  $client->setAutoRenewState((bool) $form_state['values']['autorenew'], $form_state['order_id']);
  $new_form = drupal_get_form('mymodule_autorenew_form', $form_state['user'], $form_state['order_id']);
  $new_form = drupal_render($new_form);

  $commands = [];
  $commands[] = ajax_command_html('#autorenew-form', $new_form);
  return ['#type' => 'ajax', '#commands' => $commands];

```
> 0 votes

---
Tags: 7, forms
---


# Question
Title: While clearing cache i am getting 'Page isnt working'
Whenever i use classname extends FormBase the clear cache crashes and whenever i remove it it works again.

```

<?php

namespace Drupal\API_crud\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class ApiCrud extends FormBase {
    public function getFormId() {
        return 'api_form';
    }

    public function buidForm(array $form, FormStateInterface $form_state) {
        $form['title'] = [
            '#type' => 'textfield',
            '#title' => $this->t('API: '),
            '#required' => TRUE,
        ];
        $form['actions'] = [
            '#type' => 'actions',
        ];
        $form['actions']['submit'] = [
            '#type' => 'submit',
            '#value' => $this->t('Submit'),
        ];
        return $form;
    }

}

```

```
apiAuth.form:
  path: '/apiAuth'
  defaults:
    _form: '\Drupal\API_crud\Form\ApiCrud'
    # _controller: '\Drupal\API_crud\Controller\apiCrudController::Welcome'
    _title: 'API_Authentication'
  requirements:
    _permission: 'access content'

```

# Answer
As Clive is hinting in his comment some methods are missing in your class. You need to add at least the methods "buildForm" and "submitForm" to you class. (you also have a typo in buidForm)

This should work:

```
<?php

namespace Drupal\API_crud\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class ApiCrud extends FormBase {
  public function getFormId() {
    return 'api_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['title'] = [
      '#type' => 'textfield',
      '#title' => $this->t('API: '),
      '#required' => TRUE,
    ];
    $form['actions'] = [
      '#type' => 'actions',
    ];
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];
    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    // TODO: Implement submitForm() method.
  }

}

```
> 2 votes

---
Tags: forms
---


# Question
Title: Configuration changes that will not import?
I have some configuration that will not import. If I run `drush config-import --preview` I see the changes to be imported; I hit 'y' to import. When I run the same command, the changes are still there?

My guess is that when I run this command the config files should say to the database: 'hey, be like me'. Then when I run it again, Drupal should ask 'are the config files and database the same?' - they should be if they were synced - and Drupal should say 'cool, nothing to do, they match'. Right?

Am I missing something - if not, what can I do? Thanks.

```
$ drush config-import --preview
 Collection  Config                                            Operation
             core.entity_view_display.node.page.search_result  update
             core.entity_view_display.node.page.search_index   update
             core.entity_view_display.node.book.teaser         update
Import the listed configuration changes? (y/n): y
The configuration was imported successfully.                                                                                [success]
$ drush config-import --preview
 Collection  Config                                            Operation
             core.entity_view_display.node.page.search_result  update
             core.entity_view_display.node.page.search_index   update
             core.entity_view_display.node.book.teaser         update
Import the listed configuration changes? (y/n):

```

# Answer
> 0 votes
From what I can see this is a problem with how drush generates the temp files to compare against. It looks like drush is generating files with any comments removed as well as not adding qoutes around yaml strings that needs to be escaped.

```
+  # Set the node type to location
   type:
     plugin: default_value
     default_value: location
+  # set the location type to park
   field_location_type:
     plugin: default_value
     default_value:
       tid: 1
+  # Create the mappings from soap to drupal fields.
   title: abbreviatedName
   field_location_active_facilityid: ID
-  field_location_address/address_line1: address1
-  field_location_address/locality: city
-  field_location_address/administrative_area: state
-  field_location_address/postal_code: zipCode
-  field_location_address/country_code: country
-  field_location_parking_direction/format:
+  "field_location_address/address_line1": address1
+#  "field_location_address/address_line2": address2
+  "field_location_address/locality": city
+  "field_location_address/administrative_area": state
+  "field_location_address/postal_code": zipCode
+  "field_location_address/country_code": country
+#  "field_location_address/langcode":
+#    plugin: default_value
+#    default_value: en
+  "field_location_parking_direction/format":
     plugin: default_value
     default_value: basic_html
-  field_location_parking_direction/value: parkingCapacity
+  "field_location_parking_direction/value": parkingCapacity

```

# Answer
> 0 votes
I have seen this, too. Sometimes the configuration seems to be modified during or after the import thus there will be a difference between what is on disk and what is in the database.

It may be a module acting on the import event by adding its own default settings to the configs.

It could help to re-export the configuration and compare the result with the original files in order to understand what is going on.

---
Tags: 8, configuration
---


# Question
Title: Submissions of different webforms in one page without extra access
I searched a lot and did not find any good advice, so I ask support form community. please help !
.
Suppose this scenario and suggest me what should I do ?!
. I have three webform \> Webform A, Webform B, Webform C .
and have three Content type which referenced to those webforms :
Content type P ( Webform A )
Content type Q ( Webform B )
Content type T ( Webform C )
and also have three Roles : Role 1(Admin), Role 2(Content Creator), Role 3 (Submitter)
.
.
Users of Role 2 create nodes of those three Content types with those webforms. he/she can see submissions of each forms just from each nodes. \[ it's solvable. \]
.
now What should I do to create a page by `views` to gather all submissions of all webforms ( or even create a block ) and show them to users of Role 2 without giving access " Administer webform submissions " to them ?!
.
creating such a views is solvable but users of Role 2 have to access " Administer webform submissions " to see all submissions of all webforms in one place, otherwise he/she should see submissions just in it's referenced nodes!
thanks in advance.

# Answer
> 0 votes
You may grant per-form access controls to specific roles.

Just uncheck the "Administer webform submissions" site-wide permission. Then on each webform involved, go to the Settings tab, then the Access section. There, you can provide View access to specific roles by form.

---
Tags: views, webforms
---


# Question
Title: What is the standard way to hide a login button?
I have a website to which no user besides me should login.

What is the standard way to hide a login button?

Of course, one can use CSS or JavaScript or customize a Twig file but is there a standard or recommended way?

I didn't find a login block to remove in `structure/blocks`.

# Answer
Go to Admin -\> Configuration -\> People and for 'who can register accounts' choose 'administrators only'.
> 0 votes

# Answer
Here's some instruction to hide the login page. For the login button, if you mean the one in the menù, you may disable at `/admin/structure/menu/link/user.logout/edit`
> 2 votes

# Answer
I had to remove the "User account menu" block.

I figure that in Drupal 9.4.6 the login block was renamed from "Login" to "User account menu" or that the "User account menu" block now covers logging in as well.

It is recommended however to do what Jaypan suggested in his answer as well (disabling the ability of anonymous users to create account).
> 2 votes

---
Tags: 9
---


title: How can I set form values with Ajax?

text:
# Question
Title: How can I set form values with Ajax?
I want to set the value of a textfield based upon the selection of a field above. You can choose a template and the textfield would have it as a value.

This is the select field used to select the template with the ajax call

```
// Template Select field
$form['template'] = [
'#type' => 'select',
'#title' => $this->t('Template'),
'#options' => $event_templates_select,
'#required' => TRUE,
'#ajax' => [
    'callback' => '::changeOutputValue',
    'disable-refocus' => FALSE,
    element.
        'event' => 'change',
        'wrapper' => 'edit-output',
        'progress' =>[
            'type' => 'throbber',
            'message' => $this->t('Updating e-mail template'),
        ],
    ]
];

```

This is the textfield that I want to display the value. It's in a ckeditor.

```
// Textarea field
$form['output'] = [
'#type' => 'text_format',
'#format' => 'full_html',
'#required' => TRUE,
'#disabled' => FALSE,
'#value' => 'hallo',
'#prefix' => '<div id="edit-output" class="acceptform__output">',
'#suffix' => '</div>',
];

```

And finally, the ajax function

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

    $selected_option =  $form_state->getValue('template');
    if ($selected_option == 0){
        $output_text = '';
    } else {
        $template = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($selected_option);
        $tempate_content = $template->get('field_template')->getValue();
        $tempate_content = $tempate_content[0]['value'];
        $output_text = $tempate_content;
    }

    $form['output']['#value'] = $output_text;

    $response = new AjaxResponse();
    return $response;

  }
}

```

Can someone explain what I'm doing wrong. I was trying to follow the drupal 8 form api docs but I can't get it to work with a ckeditor field.

The select field contains a number of e-mail templates. Upon selecting one, I want to display the template in the output field with a ckeditor so the user can still make changes if necessary.

I'm using Drupal 8 with a custom module.

Thanks in advance.

# Answer
From the ajax callback, you only need to return the render array containing the data to be inserted into the div you have specified as the callback to your #ajax.

So in the ajax callback you can return this, rather than an AjaxResponse:

```
return $form['output'];

```
> 0 votes

# Answer
In case the radio button is **disabled** you can use the prop function instead of click as seen in the example below.

```
  $response = new AjaxResponse();
  $selector='#process-wrapper .fieldset-wrapper input[name=field_form_gasto_procedimiento][value='.$proc.']'; // A jQuery selector
  $method='prop'; // The name of a jQuery method to invoke.
  $arguments=['checked', true];
  $response->addCommand(new InvokeCommand($selector,$method,$arguments));
  return $response;

```
> 0 votes

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