title: Entity Reference returns blank content

text:
# Question
Title: Entity Reference returns blank content
I thought that omitting code and being more graphic was going to improve the question, but that only made it score negative hehehe. So I'm going to put in some code to make it look clearer. Here is the second version of my question.

---

I am developing a customized module, to implement a series of entities, with the following model:

In blue, the Drupal core entity (User) and in white, the ones I have defined (Member, Calendar and Attendance). Except for User, all other fields are literal. I have only omitted UUID in my entities.

Here is the code that defines the Member entity: Member entity: **Annotation**

```
 * @ContentEntityType(
 *   id = "ita_member",
 *   label = @Translation("Miembro"),
 *   label_collection = @Translation("Miembros"),
 *   label_singular = @Translation("miembro"),
 *   label_plural = @Translation("miembros"),
 *   label_count = @PluralTranslation(
 *     singular = "@count miembro",
 *     plural = "@count miembros",
 *   ),
 *   base_table = "ita_members",
 *   handlers = {
 *     "route_provider" = {
 *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
 *     },
 *     "form" = {
 *       "default" = "Drupal\ita\Form\RegistrationForm",
 *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
 *     },
 *     "list_builder" = "Drupal\ita\Entity\Handler\MemberListBuilder",
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "views_data" = "Drupal\views\EntityViewsData",
 *   },
 *   entity_keys = {
 *      "id" = "id",
 *      "uuid" = "uuid",
 *   },
 *   links = {
 *     "add-form" = "/ita/add",
 *     "canonical" = "/ita/{ita_member}",
 *     "collection" = "/admin/content/itas",
 *     "delete-form" = "/ita/{ita_member}/delete",
 *     "edit-form" = "/ita/{ita_member}/edit",
 *   },
 *   admin_permission = "administer members",
 *   fieldable = TRUE,
 *   field_ui_base_route = "entity.ita_member.settings",
 *   common_reference_target = TRUE,
 * )

```

Member entity: **baseFieldDefinitions**

```
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
      $fields = parent::baseFieldDefinitions($entity_type);

      // User
      $fields['user'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Usuario'))
      ->setDescription(t('Identificador del usuario del sistema asignado a este miembro.'))
      ->setSetting('target_type', 'user')
      ->setRequired(TRUE)
      ->setDisplayOptions('view', [
        'label' => 'visible',
        'type' => 'string',
        'weight' => 2,
      ])
      ->setDisplayOptions('form', [
        'type' => 'entity_reference_autocomplete',
        'weight' => 2,
        'settings' => [
          'match_operator' => 'CONTAINS',
          'size' => '25',
          'placeholder' => 'Teclee el nombre del usuario',
        ],
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
      ->addConstraint('UniqueField');

      return $fields;
  }

```

Calendar entity: **Annotation**

```
 * @ContentEntityType(
 *   id = "ita_calendar",
 *   label = @Translation("Calendario de asistencias"),
 *   label_collection = @Translation("Calendarios"),
 *   label_singular = @Translation("Calendario"),
 *   label_plural = @Translation("Calendario de asistencias"),
 *   label_count = @PluralTranslation(
 *     singular = "@count Calendario",
 *     plural = "@count Calendarios",
 *   ),
 *   base_table = "ita_calendar",
 *   handlers = {
 *     "route_provider" = {
 *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
 *     },
 *     "form" = {
 *       "default" = "Drupal\ita\Form\CalendarForm",
 *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
 *     },
 *     "list_builder" = "Drupal\ita\Entity\Handler\CalendarListBuilder",
 *     "views_data" = "Drupal\ita\Entity\Handler\CalendarViewsData",
 *   },
 *   fieldable = TRUE,
 *   entity_keys = {
 *      "id" = "id",
 *      "uuid" = "uuid",
 *   },
 *   links = {
 *     "add-form" = "/calendar/add",
 *     "canonical" = "/calendar/{ita_calendar}",
 *     "collection" = "/admin/content/calendar",
 *     "delete-form" = "/calendar/{ita_calendar}/delete",
 *     "edit-form" = "/calendar/{ita_calendar}/edit",
 *   },
 *   admin_permission = "administer calendar",
 *   field_ui_base_route = "entity.ita_calendar.settings",
 *   common_reference_target = TRUE,
 * )

```

Calendar entity: **baseFieldDefinitions**

```
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
      $fields = parent::baseFieldDefinitions($entity_type);

      // Date Attendance
      $fields['date'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('Fecha de asistencia'))
      ->setDescription(t('Fecha en la que se va a pasar lista de asistencia.'))
      ->setRevisionable(FALSE)
      ->setRequired(TRUE)

      ->setSettings([
        'datetime_type' => 'date',
      ])

      ->setDisplayOptions('view', [
        'label' => 'above',
        'type' => 'datetime_default',
        'settings' => [
          'format_type' => 'd/m/Y',
        ],
        'weight' => 0,
      ])
      ->setDisplayOptions('form', [
        'type' => 'datetime_default',
        'weight' => 0,
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
      ->addConstraint('UniqueField');

      // Type Attendance
      $fields['type'] = BaseFieldDefinition::create('list_string')
      ->setLabel(t('Tipo de asistencia'))
      ->setDescription(t('Tipo de asistencia (Obligatoria, Voluntaria o Anulada) para esta fecha.'))
      ->setRequired(TRUE)
      ->setSettings([
        'max_length', '3',
        'allowed_values' => [
          'anu' => 'Anulada',
          'obl' => 'Obligatoria',
          'vol' => 'Voluntaria',
          ],
        ])
      ->setDefaultValue('obl')
      ->setDisplayOptions('view', [
          'label' => 'above',
          'type' => 'string',
          'weight' => 1,
        ])
      ->setDisplayOptions('form', [
          'type' => 'options_select',
          'weight' => 1,
        ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

      return $fields;
  }

```

Attendance entity: **Annotation**

```
 * @ContentEntityType(
 *   id = "ita_attendance",
 *   label = @Translation("Registro de asistencia"),
 *   label_collection = @Translation("Asistencias"),
 *   label_singular = @Translation("Asistencia"),
 *   label_plural = @Translation("Asistencias"),
 *   label_count = @PluralTranslation(
 *     singular = "@count Asistencia",
 *     plural = "@count Asistencias",
 *   ),
 *   base_table = "ita_attendances",
 *   handlers = {
 *     "route_provider" = {
 *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
 *     },
 *     "form" = {
 *       "default" = "Drupal\Core\Entity\ContentEntityForm",
 *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
 *     },
 *     "views_data" = "Drupal\views\EntityViewsData",
 *   },
 *   fieldable = TRUE,
 *   entity_keys = {
 *      "id" = "id",
 *      "uuid" = "uuid",
 *   },
 *   links = {
 *     "add-form" = "/attendance/add",
 *     "canonical" = "/attendance/{ita_attendance}",
 *     "collection" = "/admin/content/attendance",
 *     "delete-form" = "/attendance/{ita_attendance}/delete",
 *     "edit-form" = "/attendance/{ita_attendance}/edit",
 *   },
 *   admin_permission = "administer attendance",
 *   field_ui_base_route = "entity.ita_attendance.settings",
 * )

```

Attendance entity: **baseFieldDefinitions**

```
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
      $fields = parent::baseFieldDefinitions($entity_type);

      // Date Attendance
      $fields['date'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Fecha'))
      ->setDescription(t('Fecha en la que se desea registrar la asistencia.'))
      ->setSetting('target_type', 'ita_calendar')
      ->setSettings([
        'handler', 'views',
        'handler_settings', [
          'view' => [
            'view_name' => 'Listado de fechas',
            'display_name' => 'default',
          ],
        ],
        'auto_create' => FALSE,
      ])
      ->setRequired(TRUE)
      ->setDisplayOptions('view', [
        'label' => 'visible',
        'type' => 'string',
        'weight' => 1,
      ])
      ->setDisplayOptions('form', [
        'type' => 'options_select',
        'weight' => 1,
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

      // Member
      $fields['user'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Usuario'))
      ->setDescription(t('Miembro al que se le va a pasar lista.'))
      ->setSetting('target_type', 'ita_member')
      ->setRequired(TRUE)
      ->setDisplayOptions('view', [
        'label' => 'visible',
        'type' => 'entity_reference_label',
        'settings' => [
          'link' => TRUE,
        ],
        'weight' => 1,
      ])
      ->setDisplayOptions('form', [
        'type' => 'options_select',
        'weight' => 1,
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

      return $fields;
  }

```

The foreign keys are entity reference type fields. The user field in the Member entity works perfectly. The ones that don't work are the two from the Attendance entity. In this case, I use a "select list" widget to verify it, it is observed that there is information, but nothing else is seen. The content appears, but empty (blank content). This is the output I have in the form to add new attendances.

And as you can see from above, here I only use the standard handlers.

```
handlers = {
 *     "route_provider" = {
 *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
 *     },
 *     "form" = {
 *       "default" = "Drupal\Core\Entity\ContentEntityForm",
 *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
 *     },
 *     "views_data" = "Drupal\views\EntityViewsData",

```

I am doing all this programmatically, so I have created the member field, for example, by hand and the result is the same. However, if the field I create by hand, I attach a view of type "Entity Reference" does work. I think that I have to customize something so that the autocomplete or the select list of a custom entity returns the data correctly. I believe that the problem is in that I have not defined the habitual fields of an entity type node, as it is the title, for example. I hope that it has been clear the problem and can exist, sure that yes, a solution. I have my suspicions that the solution is to implement the ViewsData or ViewsListBuilder handlers, but honestly, I have no idea.

# Answer
As Kevin mentioned in the comments, your entity types don't have a `label` set for `entity_keys`, and presumably you haven't overridden `EntityBase::label` in any of them. This means that when the system requests a label for an entity, it gets `NULL`, and you see a blank string.

If your entity type has a string field you can use for the title, set it in the annotation:

```
*  entity_keys = {
*    "id" = "id",
*    "uuid" = "uuid",
*    "label" = "title",
*  },

```

If not, override the `label` method in the entity class:

```
public function label() {
  return $this->user->entity->name;
}

```
> 1 votes

---
Tags: views, entities
---


# Question
Title: List module releases that are "Recommended by the project’s maintainer."
On the project page of a Drupal module there is a list of releases. The project owner can set for each one whether it is recommended, and the page displays that fact. For example if there are releases 2.0 and 3.0, it's possible for either one to be recommended or both.

I would like to know which releases are recommended **without** having to visit the project page of each module one-by-one. I would be interested in any type of answer: GUI, command line, API, etc.

I have already tried

* The GUI (/admin/reports/updates). It lists releases that are "also available" but does not indicate which are recommended.
* composer. It seems to have no idea of recommended. With my settings, it appears to pick the newer release except if it is less stable.
* drush. In drush 8, the rl command lists recommended releases but seems to be broken with current Drupal 8. Newer drush does not have this command.
* Code. The return value of update\_get\_available() or update\_calculate\_project\_data() don't seem to contain this information.

# Answer
> 1 votes
As described in Update status XML, Drupal.org returns information about project releases, including the recommended major version, as XML output. For example, the first XML elements returned from https://updates.drupal.org/release-history/imagemagick/8.x are the following one.

```
<title>ImageMagick</title>
<short_name>imagemagick</short_name>
<dc:creator>sun</dc:creator>
<type>project_module</type>
<api_version>8.x</api_version>
<recommended_major>3</recommended_major>
<supported_majors>3</supported_majors>
<default_major>3</default_major>
<project_status>published</project_status>

```

`<recommended_major>3</recommended_major>` is referring to any version matching 8.x-3.\*.

Unfortunately, that information isn't returned from https://updates.drupal.org/release-history/imagemagick/current or any URL matching `https://updates.drupal.org/release-history/*/current`.

```
<title>ImageMagick</title>
<short_name>imagemagick</short_name>
<dc:creator>sun</dc:creator>
<type>project_module</type>
<supported_branches>8.x-3.</supported_branches>
<project_status>published</project_status>
<link>https://www.drupal.org/project/imagemagick</link>

```

---
Tags: updating, community-official-site
---


# Question
Title: Is it possible to pass variables as arguments to *.libraries.yml?
Say I have a foo.libraries.yml defined as so:

```
external.bc.js:
  version: 1.x
  js:
    //players.brightcove.net/{{variable here}}/{{variable here}}/index.min.js: { type: external, minified: true}

```

Where `{{ variable here }}` is where I want to insert values when I attach the library

Then, in a `hook_ENTITY_TYPE_view()` I am running:

`$build['#attached']['library'][] = 'brightcove/external.bc.js';`

Which is where I'd also like the pass those variables. Is that possible?

# Answer
> 1 votes
Instead of defining the library in the .libraries.yml file, you should add it using `hook_library_info_build()`, which in fact is described using the following sentences.

> Modules may implement this hook to add dynamic library definitions. Static libraries, which do not depend on any runtime information, should be declared in a modulename.libraries.yml file instead.

```
function mymodule_library_info_build() {
  $libraries = [];

  $js_path = 'the dynamic path to the external JavaScript file';
  $libraries['external.bc.js'] = [
    'version' => '1.x',
    'js' => [
      $js_path => ['type' => 'external', 'minified' => TRUE]
    ],
  ];

  return $libraries;
}

```

If the library has been defined from another module, the hook to use is `hook_library_info_alter()`.

---
Tags: 8, javascript
---


# Question
Title: Extra fields for edit form as opposed to front end
`hook_entity_extra_field_info()` allows adding arbitrary elements to the **Manage display** tab that also appear on the rendered node.

I want to add some section headings that appear on the node edit form and can be re-ordered on the **Manage form display** tab.

Is there a hook like `hook_entity_extra_field_info()` but that adds an element to the edit form as opposed to the front end?

I realise that I could achieve something like this with field group but would rather use a lighter approach with less overhead.

# Answer
> 2 votes
`hook_entity_extra_field_info()` is invoked when either an entity is rendered, or when an entity form is shown to users. See `user_entity_extra_field_info()` as example.

```
function user_entity_extra_field_info() {
  $fields['user']['user']['form']['account'] = [
    'label' => t('User name and password'),
    'description' => t('User module account form elements.'),
    'weight' => -10,
  ];
  $fields['user']['user']['form']['language'] = [
    'label' => t('Language settings'),
    'description' => t('User module form element.'),
    'weight' => 0,
  ];
  if (\Drupal::config('system.date')->get('timezone.user.configurable')) {
    $fields['user']['user']['form']['timezone'] = [
      'label' => t('Timezone'),
      'description' => t('System module form element.'),
      'weight' => 6,
    ];
  }
  $fields['user']['user']['display']['member_for'] = [
    'label' => t('Member for'),
    'description' => t("User module 'member for' view element."),
    'weight' => 5,
  ];
  return $fields;
}

```

Any field that is part of the `$fields['user']['user']['display']` array is shown when the User entity is rendered and can be re-orderer from /admin/config/people/accounts/display. (*Member for* is the label used from the code I previously shown.)

>

Any field that is part of the `$fields['user']['user']['form']` array is added to the entity form and can be re-ordered from /admin/config/people/accounts/form-display. (*User name and password*, *Language settings*, and *Timezone* are the labels used from the code I previously shown.)

>

In the case of nodes, it's not different. You just need to remember that instead of `$fields['user']['user']['form']` you need to use `$fields['node']['content type']['form']`, and replace `'content type'` with the effective content type for which you need to add fields to the entity form. In the case you need to add fields to the entity form of every content type, you should use code similar to the one used in `node_entity_extra_field_info()`.

```
foreach (NodeType::loadMultiple() as $bundle) {
  // Add the description for the extra fields.
  // $extra['node'][$bundle->id()][...] = ...
}

```

---
Tags: 8, forms
---


# Question
Title: What does it mean if expire is set to null in a cache table?
I am looking at the documentation for the expire field in the cache tables and the documentation in CacheBackendInterface.php says:

> @param int `$expire`
> One of the following values:
>
> * CacheBackendInterface::CACHE\_PERMANENT: Indicates that the item should not be removed unless it is deleted explicitly.
> * A Unix timestamp: Indicates that the item will be considered invalid after this time, i.e. it will not be returned by `get()` unless `$allow_invalid` has been set to `TRUE`. When the item has expired, it may be permanently deleted by the garbage collector at any time.

When I look in a cache table, for example *cache\_render*, I see that many entries have NULL in the *expire* column and I noticed it only get clear on a complete cache clear, such as after running `drush cr`.

What does a null value set for the *expire* column in a cache table mean?

# Answer
> 1 votes
Any value for the *expire* column that is different from `CacheBackendInterface::CACHE_PERMANENT` (-1) is considered a timestamp, indicating when the cache entry could be deleted. In the case of `NULL`, the value means the cache entry could be deleted in any moment.
As @4k4 said in his comment, data in cache tables are deleted when cron tasks run, and that doesn't necessarily means immediately.

The only issue with `NULL` is whether a module is using a not initialized variable which is expected to contain the expiration time. In that case, the cached value is kept in cache less than required.

---
Tags: 8, caching
---


# Question
Title: 403 Error - Unable to create Paragraphs via REST with ?_format=hal_json
Trying to add paragraphs via REST to the earlier created node.

I've installed the *Paragraphs Type Permissions* module, enabled the following permissions for my REST user's role

* Text: Create content
* Video: Create content

*See:* https://www.drupal.org/project/paragraphs/issues/3012600#comment-12851834

but still getting an error 403 and {"message":""} in response while trying to add some paragraphs to the node created earlier.

Error log:

```
Type        access denied
Date        Monday, December 28, 2020 - 20:40
User        restadmin
Location    https://drupal-8.site/entity/paragraph?_format=hal_json
Referrer
Message     Path: /entity/paragraph?_format=hal_json. Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: in Drupal\Core\Routing\AccessAwareRouter->checkAccess() (line 120 of /var/www/core/lib/Drupal/Core/Routing/AccessAwareRouter.php).
Severity    Warning
Hostname    77.139.170.139
Operations

```

Here JSON for the Text Paragraph:

```
   {
        "field_text": [
            {
                "value": text,
                "format": "full_html",
                "processed": text
            }
        ],
        "parent_id": [
            {
                "value": str(parent_id)
            }
        ],
        "parent_type": [
            {
                "value": "node"
            }
        ],
        "parent_field_name": [
            {
                "value": "field_paragraphs"
            }
        ],
        "type": [
            {
                "target_id": "text"
            }
        ],
        "_links": {
            "type": {
                "href": base_url + REST_TYPE_PARAGRAPH_TEXT
            }
        }
    }

```

Here JSON for the Video paragraph:

```
{
        "field_video": {
            "value": "video:" + str(video_id)
        },
        "parent_id": [
            {
                "value": str(parent_id)
            }
        ],
        "parent_type": [
            {
                "value": "node"
            }
        ],
        "parent_field_name": [
            {
                "value": "field_paragraphs"
            }
        ],
        "type": [
            {
                "target_id": "video"
            }
        ],
        "_links": {
            "type": {
                "href": base_url + REST_TYPE_PARAGRAPH_VIDEO
            }
        }
    }

```

What permission am I missing here?

# Answer
> 0 votes
Check on permission **Paragraphs Type Permissions -\> Bypass Paragraphs type content access control** was missing here.

There was also a problem with the JSON request payload of the video paragraph, here the correct version:

```
    {
        "field_video": [
            {
                "target_id": video_id
            }
        ],
        "parent_id": [
            {
                "value": parent_id
            }
        ],
        "parent_type": [
            {
                "value": "node"
            }
        ],
        "parent_field_name": [
            {
                "value": "field_paragraphs"
            }
        ],
        "type": [
            {
                "target_id": "video"
            }
        ],
        "_links": {
            "type": {
                "href": base_url + REST_TYPE_PARAGRAPH_VIDEO
            },
            base_url +  REST_RELATION_PARAGRAPH_VIDEO_FIELD_VIDEO: [
                {
                    "href": base_url + "/media/%d/edit" % video_id + FORMAT_HAL_JSON,
                    "lang": "en"
                }
            ]
        }
    }

```

And a correct/working version of the text paragraph JSON payload:

```
    {
        "field_text": [
            {
                "value": text,
                #"format": "full_html" - getting error "full_html" not recognized
            }
        ],
        "parent_id": [
            {
                "value": str(parent_id)
            }
        ],
        "parent_type": [
            {
                "value": "node"
            }
        ],
        "parent_field_name": [
            {
                "value": "field_paragraphs"
            }
        ],
        "type": [
            {
                "target_id": "text"
            }
        ],
        "_links": {
            "type": {
                "href": base_url + REST_TYPE_PARAGRAPH_TEXT
            }
        }
    }

```

---
Tags: security, paragraphs, 8
---


# Question
Title: How can I add player parameters to a core oembed field for a youtube video?
For example, if I enter this url that contains the player parameters to remove controls and autoplay, oembed field on my media type does not allow it ("The given URL does not match any known oEmbed providers.".

```
https://youtu.be/9ot0rIlhbNE?autoplay=1&fs=0&controls=0&modestbranding=1

```

If I paste just the base url, then it works.

Any thoughts?

Edit: Based on Yuseferi answer, I have isolated the Youtube section if the providers.json.

```
{
    "provider_name": "YouTube",
    "provider_url": "https:\/\/www.youtube.com\/",
    "endpoints": [
        {
            "schemes": [
                "https:\/\/*.youtube.com\/watch*",
                "https:\/\/*.youtube.com\/v\/*",
                "https:\/\/youtu.be\/*"
            ],
            "url": "https:\/\/www.youtube.com\/oembed",
            "discovery": true
        }
    ]
}

```

# Answer
> 1 votes
I had the same problem before with a local provider. So I share the solution I used and hope it works for you too.

The Drupal core, fetch providers form https://oembed.com/providers.json automatically. So you need to change the provider to what you want.

Oembed Providers module helps to add custom providers too.

> * Add custom oEmbed providers via an admin user interface (providers are stored in configuration)
> * Global enable/disable of providers
> * Modify the provider list URL (which is \> defaulted to https://oembed.com/providers.json)
> * Disable the fetching of the provider list (useful in an instance where only custom providers are used)
> * Provides hook\_oembed\_providers\_alter() to alter provider definitions

**So, all you need is to add a new provider for your custom provider "youtu.be"** with your parameters too.

try it and let me know if you need more details.;)

Screenshots that shows it's working without any validation error:

**what I did, was just add "oembed\_providers" module and enabled it**

---
Tags: 9, media
---


# Question
Title: Limit amount of emails sent per time frame?
Is there a module which allows for the limiting of emails sent per hour using drupal mail system?

My server has a limit of how many emails can be sent per hour. Most of my users are online at the same time of the day, so it makes sense to spread the emails out over the day rather than sending all at once.

But the only mail modules I've found so far send all emails in one go rather than being able to limit the amount per hour.

How can I set Drupal to limit the amount of emails it sends per hour and all unsent emails are queued for the next hour?

Thanks

# Answer
There is an option, Queue mail module that queues all output emails in the queue ( you can define what email Ids queue). then set Cron to run each hour with ultimate\_cron module)

the only problem is that you can not define how many hours can be sent in a Cron run. you can just set how many seconds the Cron can be run ( Queue processing time) . I think with a couple of tries you find your desire time.
> 2 votes

---
Tags: 7, emails
---


# Question
Title: Adding search form in header and home page creates SAME HTML ID validation issue
I have added a search form in the header and content area of the home page from `block layout`. Forms are displayed fine and they are working well.

However, `w3.org` is flagging the HTML validation as having a duplicate ID.

The same thing is happening for my custom block which is added to the header and sidebar. I know I can remove `div ID` from custom block, but there must be a drupal way to fix this.

How do I avoid this?

**UPDATE** Looks like drupal cache is to blame. When cache is turned off it generates forms with id like this: `id="search-block-form"` and `id="search-block-form--2"`. But as soon as I enable the cache it just generates like this: `id="search-block-form"` to all of them.

**WORKAROUND Solution** I ended up loading the site after each cache clear in incognito mode or in a different browser as anonymous.

# Answer
> 1 votes
I've asked a similar question here and there's another related question here.

However, none of the solutions were particularly useful for me. In my case, this was a result of the form being cached too aggressively. I expect that's happening here too. For example, the form is first rendered in the header and the result is cached in the render cache. Then when the form is rendered the second time, e.g. in the main content region, the form is loaded from cache (rather than rebuilt) bypassing any core code to ensure a unique form id is generated.

Ultimately, you need to alter how the form's render result is cached so that each rendering rebuilds the form with a unique id. I found it difficult to generate unique cache information for the form without knowing the surrounding context so I used a workaround.

I implemented a hook\_form\_FORM\_ID\_alter() for the form in question and unset the cache keys property. While this prevents the form object from being cached as its own object, the form is still cached as part of its parent container with all of the form's cache metadata bubbling up. I found this approach allows my form to render with unique ids with only a very small performance hit.

```
function MY_MODULE_form_FORM_ID_alter(&$form, $form_state, $form_id) {
  // Ensure this form isn't cached as its own object, only with its parent.
  if (isset($form['#cache']['keys'])) {
    unset($form['#cache']['keys'];
  }
}

```

You can find more about the cacheability of render arrays on d.o.

# Answer
> -1 votes
Drupal core and its themes usually creates dynamic, unique IDs, so this should be coming from a custom module or theme. If you want to generate unique IDs in your own module/theme, you can use something like

```
<?php
$myUniqueButRandomId = \Drupal\Component\Utility\Html::getUniqueId();

```

Docs:

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Utility%21Html.php/function/Html%3A%3AgetUniqueId/8.2.x

---
Tags: 8
---


# Question
Title: Open Webform in a modal, but deny access to the form url
I have a Webform being opened in a modal from a menu link. I want to have the modal be the only way to access the form, meaning I don't want someone to type in '/form/(name)' to the URL and access it by page. Is there a way to support opening in a modal but denying page level access in Webform?

# Answer
Not sure if its the best way but I had something similar to do to allow viewing an entity only on a specified route and if some other conditions were met. I created an EventSubscriber which basically decides if the user is allowed to access the page or not.

```
<?php

namespace Drupal\MY_CUSTOM_MODULE\EventSubscriber;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Custom class RedirectSubscriber.
 */
class RedirectSubscriber implements EventSubscriberInterface {

  /**
   * Custom function to check if we should redirect.
   */
  public function checkForRedirection(GetResponseEvent $event) {

    $route = \Drupal::routeMatch()->getRouteName();

    // If route is group add form.
    if (isset($route) && $route == "entity.group.add_form") {
      if ("MY CONDITION IS NOT MET") {
        //REDIRECT OR DO SOMETHING ELSE
        $event->setResponse(new RedirectResponse('/random-page url'));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      KernelEvents::REQUEST => 'checkForRedirection',
    ];
  }

}

```

Also, if you decide to do this, don't forget to register your event subscriber in the services.yml file.

```
services:
  MY_CUSTOM_MODULE_redirect_event_subscriber:
    class: Drupal\MY_CUSTOM_MODULE\EventSubscriber\RedirectSubscriber
    tags:
      - {name: event_subscriber}

```
> 1 votes

---
Tags: 8, webforms
---


# Question
Title: How can I require a custom module hosted elsewhere with its contrib dependencies being downloaded too?
Hi I am trying to setup my new Drupal 8 site with composer, but I got few issues.

I tried to setup the site site by following the Guide from here and was able to setup the site successfully.

After that I tried to install a custom module which is hosted on Bitbucket and I am able to download the package using Composer, but the problem is the module has some other contributed module dependency but the dependency module is not downloaded along with the custom module.

I followed the guide from here and added composer.json file to my custom module along with the dependency, but after running `composer require custom/custom_module` only the custom module is installed but not the dependency.

My root directory composer.json file repositories section looks like this.

```
"repositories": [
    {
        "type": "composer",
        "url": "https://packages.drupal.org/8"
    },
    {
      "type": "package",
      "package": {
        "name": "custom/custom_module",
        "version": "master",
        "type": "drupal-custom-module",
        "source": {
          "type": "git",
          "url": "git@bitbucket.org:username/custom-module.git",
          "reference": "master"
        }
      }
    }
],

```

The composer.json file from the custom module is the following.

```
{
    "name": "custom/custom_module",
    "description": "This is a Custom Module with Different functionalities.",
    "type": "drupal-custom-module",
    "minimum-stability": "dev",
    "require": {
        "drupal/restui": "~1.16"
    }
}

```

I also chaged the line `"drupal/restui": "~1.16"` as `"drupal/restui": "^1.16"` but with no success.

I even tried running `composer update` in the custom module directory as I was not sure whether dependencies will be installed along with custom module. After running `composer update` in the custom module directory I got this error.

> Your requirements could not be resolved to an installable set of packages.

Problem 1

>

* The requested package drupal/restui could not be found in any version, there may be a typo in the package name.

> Potential causes:

> Read https://getcomposer.org/doc/articles/troubleshooting.md for further common problems.

On Drupal.org I can find the module with that version here.

**EDIT 1**

I have added below to the composer.json file from the custom module but still same issue.

```
"repositories": [
  {
    "type": "composer",
    "url": "https://packages.drupal.org/8"
  }
],

```

**EDIT 2** : Seems recursive package download is not possible with composer. Refer Why can't Composer load repositories recursively? and Add support for installing libraries via asset-packagist

# Answer
So after further looking into a way I was able to download required contributed modules while installing custom module. I am not sure if it is a correct way but it works to download dependencies.

By adding below snip to the root directory composer.json and executing

```
 composer require custom/custom_module

```

downloaded the required dependencies as well.

```
"extra": {
    "merge-plugin": {
        "include": [
            "core/composer.json",
            "modules/*/composer.json"
        ],
        "recurse": false,
        "replace": false,
        "merge-extra": false
    }
}

```

If anyone got better suggestions please suggest.

**Note** : The above method requires `wikimedia/composer-merge-plugin` which can be added by the below command.

```
composer require wikimedia/composer-merge-plugin

```
> 3 votes

# Answer
Just for this question I created a dummy module at https://github.com/leymannx/custom\_module which has a composer.json similar to yours with `drupal/restui` in the `"require"` section and `"type": "drupal-custom-module"`.

And then in a D8 project's composer.json I adjusted the `"repositories"` section to look like this:

```
"repositories": [
    {
        "type": "composer",
        "url": "https://packages.drupal.org/8"
    },
    {
        "type": "github",
        "url":  "https://github.com/leymannx/custom_module"
    }
],

```

In the `"installer-paths"` section I added:

```
 "web/modules/custom/{$name}": ["type:drupal-custom-module"]

```

I then simply ran `composer require leymannx/custom_module` and it downloaded the module and `drupal/restui` both to the right places. Of course you now can ignore the custom module with your repo's .gitignore file.

I guess the trick was to have the `"repositories"` section adjusted like above. And I guess you also can use proper versioning for the custom module when you tagged some releases. Right now it just downloads `dev-main`.
> 3 votes

---
Tags: 8, composer
---


# Question
Title: The website encountered an unexpected error. Please try again later (WSOD). Debugging scenario
After updating Drupal using drush my website says 'The website encountered an unexpected error. Please try again later'. with white screen(WSOD).

Then when I tried to rebuild-cache using drush there was a drush fatal error originating with rules module. I got it rectified by replacing rules module with 3.x dev version.

I could rebuild the cache and update database using drush. But still the wsod is there

My next move was to enable error reporting. So I added the line

`$config['system.logging']['error_level'] = 'verbose';` it did not return any errors on the the screen. I like to know a debugging scenario for D8 as i faced this same issue for my another D8 installation but that was rectified after rebuilding the cache. I have came across posts by user with similar issues but reasons for their issues were different. So I strongly believe that there should be a debugging scenario that can apply to all.

# Answer
> 4 votes
1- Install Drush if you have not installed it already.

2- Clear cache using drush.

3- Still if you are facing issues start debugging with error logs as following.

Add the following lines to your settings.php

```
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);

```

While editing settings.php change its default file permission to writable. And you may also add following to your settings.php

```
$config['system.logging']['error_level'] = 'verbose';

```

Additional information is available here!

4- If you see any error related to any custom/contributed module after enabling error reporting service.You may overwrite the particular module folder with its latest release or even try with its dev release

5- You can read the server log messages for additional error informations. These log files may vary as per the server configurations. Some information about the server log file available here!

# Answer
> 0 votes
Add this $config\['system.logging'\]\['error\_level'\] = 'verbose'; to your settings.php file pinpoints where the issue is, it worked for me, it was a database error! username!

# Answer
> -1 votes
Simply run the below command to rebuild your site, when you encountered an issue "the website encountered an unexpected error. please try again later" after any new module installed with fatal error.

> drush cr

---
Tags: 8, debugging, wsod
---


title: How to create custom node edit form

text:
# Question
Title: How to create custom node edit form
```
  protected function alterRoutes(RouteCollection $collection) {
    if($route = $collection->get('entity.node.edit_form')) {
      $route->setDefault('_entity_form', '\Drupal\alerts\Form\EditAdvisoryForm');
    }
  }

```

Causes a permission error. The logs say

> Path: /node/1277957/edit?destination=/admin/content. Drupal\Core\Http\Exception\CacheableAccessDeniedHttpException: in Drupal\Core\Routing\AccessAwareRouter-\>checkAccess() (line 117 of /app/web/core/lib/Drupal/Core/Routing/AccessAwareRouter.php).

It doesn't seem to prefill the form with the editable info. This is also not content type specific.

Please advise. Other posts close to this do not have an answer.

# Answer
`_entity_form` doesn't accept a form class directly, only via a form handler. See https://www.drupal.org/docs/drupal-apis/routing-system/structure-of-routes

> \_entity\_form: It is similar to \_form, but it will provide an edit form for an entity. Entity form handlers are defined in the entity metadata (annotation). For example, \_entity\_form: node.default will display the default node form. "node" in node.default refers to the entity ID, and "default" refers to the form handler key.
> 1 votes

---
Tags: 8, routes
---


# Question
Title: JSON:API resources error: "This resource attempted to serve data that contains unsupported resource types."
I'm trying to make a custom JSON:API resource for flaggings using the JSON:API Resources module.

Right now, I simply want to return all the flaggings of a given bundle with an EntityQuery. (Later, I will customize the EntityQuery, which is why I am need to go beyond what JSON:API provides by default.)

My code is based on the module's example code.

**MYMODULE/src/Resource/MyQueue.php**

```
/**
 * Processes a request for a collection containing a user's article nodes.
 *
 * @internal
 */
class MyQueue extends EntityQueryResourceBase {

  /**
   * Process the resource request.
   *
   * Code example:
   * https://git.drupalcode.org/project/jsonapi_resources/tree/8.x-1.x/tests/modules/jsonapi_resources_test/src/Resource.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request.
   *
   * @return \Drupal\jsonapi\ResourceResponse
   *   The response.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function process(Request $request): ResourceResponse {

    $cacheability = new CacheableMetadata();

    $entity_type_id = 'flagging';
    $entity_type_bundle = 'MY_FLAGGING_TYPE';
    $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
    $entity_query = $this->getEntityQuery($entity_type_id)
      ->condition($entity_type->getKey('bundle'), $entity_type_bundle);

    $paginator = $this->getPaginatorForRequest($request);
    $paginator->applyToQuery($entity_query, $cacheability);

    $data = $this->loadResourceObjectDataFromEntityQuery($entity_query, $cacheability);

    $pagination_links = $paginator->getPaginationLinks($entity_query, $cacheability, TRUE);

    $response = $this->createJsonapiResponse($data, $request, 200, [], $pagination_links);
    $response->addCacheableDependency($cacheability);

    return $response;
  }

}

```

With this code, I'm getting the following error:

> LogicException: This resource attempted to serve data that contains unsupported resource types.

I don't understand why I'm getting this error, or what it means.

* If I set `$entity_type_id` to `node` and `$entity_type_bundle` to `page`, everything works as expected.
* If I set the `$entity_type_id` to 'custom\_content\_type\`, one of the content types I configured in the admin UI, it doesn't work; I get the same error.
* I tried to set `$entity_type_bundle` to all three flagging bundles on my site; none of them work.
* The `$entity_query` is correct for the flaggings. I can do `$entity_query->count->execute()` and I get the correct count.
* I am logged in as an administrator with all permissions.
* I can access the jsonapi in my browser as an admin at `/jsonapi/flagging/MY_FLAGGING_TYPE` and I see the flaggings as I expect.

# Answer
> 0 votes
This error is the result of not setting the `_jsonapi_resource` correctly in the routing file:

**MYMODULE.routing.yml**

```
# Defines a route where a user's flaggings can be found.
MYMODULE.user_flaggings:
  # %jsonapi% is a placeholder for the JSON:API base path, which can be
  # configured in a site's services.yml file.
  path: '/%jsonapi%/MYMODULE/queue'
  defaults:
    # Every JSON:API resource route must declare a _jsonapi_resource. The
    # value can either be a class or a service ID. Unlike the _controller
    # route default, it is not possible to declare a method name to be called.
    _jsonapi_resource: Drupal\MYMODULE\Resource\MyQueue
    _jsonapi_resource_types: ['node--page', 'flagging--MY_FLAGGING_TYPE']

```

---
Tags: 8
---


# Question
Title: After core update: Access denied after submitting form
We’re running on Drupal 7.73 and WebForm 7.x-3.30 – for a while now since the 7.75 to 7.77 Drupal release, we’ve been unable to update Drupal successfully.

As every time a user submits a form on the site, we’re getting an “Access Denied” message.

If you’re logged in as Admin it works. I believe it could have something to do with the “success message” that’s being displayed and that in theory, a redirect to a success page could fix it. However, as we have many forms across several sites, it is not practical to go this route.

For two years we have had no problem updating Drupal to latest and no issues with WebForm so this is a new issue.

Can you please assist in providing a solution for this as we are unable to update to implement latest security fixes?

# Answer
> 1 votes
Thanks Beebee. Doing a fresh install is not practical at the moment. But I will do it once I've run out of potential fixes to try. For now, I'll be attempting to implement this patch. Hopefully it works. https://www.drupal.org/project/webform\_service/issues/2048343#comment-9331515

---
Tags: 7, webforms
---


# Question
Title: How do I programmatically fix local menus to be shown only for a content type?
I am using the following lines in a links.task.yml file.

```
x.nodename_updates:
  route_name: view.great_view_name1.page_1
  base_route: entity.node.canonical
  title: 'Updates'
  weight: 50

x.nodename_subscriptions:
  route_name: view.great_view_name2.page_1
  base_route: entity.node.canonical
  title: 'Subscriptions'
  weight: 50

```

The submenus are shown on all nodes. I would like to show them for a single content type, but when I use the entity name in the base\_route such as entity.TYPE.canonical, it doesn't work. It works for other entities that are defined in classes with annotations.

I know it is possible to fix it through `hook_menu_local_task_alter()`, but this is something I believe can be fixed within the links.task.yml file.

# Answer
There's no way to do that entirely within *links.task.yml*.

If you see the documentation, you'll see that the only possible keys are:

> `route_name`: The machine name of the local task route - this also determines where it's displayed.
>
> `title`: The title of the local action. By default, it will be passed through t() and localized. Strings with spaces should use single quotes.
>
> `title_context` (optional): context for t()
>
> `base_route`: The route where the "root" tab (generally the top, leftmost one) is displayed and which serves to group a set of tabs.
>
> `parent_id` (optional): The plugin ID of the tab that is the parent - only relevant for 2nd level tabs. If this is set, base\_route should be omitted and will be supplied from the parent
>
> `weight`: (optional) The integer weight (lower weight tabs are further left, default is 0).

None of these keys will help you with what you're trying to do.

Your options are to use hook\_menu\_local\_task\_alter(), as you've noted, or create a deriver class to Dynamically Generate Local Tasks.

From that same documentation page, your yaml would look something like:

```
example.local_tasks:
  deriver: 'Drupal\example\Plugin\Derivative\DynamicLocalTasks'
  weight: 100

```

And a deriver class something like:

```
namespace Drupal\example\Plugin\Derivative;

use Drupal\Component\Plugin\Derivative\DeriverBase;

/**
 * Defines dynamic local tasks.
 */
class DynamicLocalTasks extends DeriverBase {

  /**
   * {@inheritdoc}
   */
  public function getDerivativeDefinitions($base_plugin_definition) {
    // Implement dynamic logic to provide values for the same keys as in example.links.task.yml.

    // Here you would check for your node canonical route and node bundle
    // to generate the task definition only if appropriate.
    $this->derivatives['example.task_id'] = $base_plugin_definition;
    $this->derivatives['example.task_id']['title'] = "I'm a tab";
    $this->derivatives['example.task_id']['route_name'] = 'example.route';

    return parent::getDerivativeDefinitions($base_plugin_definition);
  }

}

```
> 1 votes

# Answer
I don't konw if there's a better way to do it now but few years ago I did it using a custom access: https://stackoverflow.com/questions/36496998/drupal-8-how-to-add-task-and-contextual-links-for-specific-node-type/36636263#36636263

In my case it was easier because I was creating the routes in my module.

Since your routes are created by views you would need to implement a RouteSubscriber to alter the route, add the `_custom_access` and `_node_types` requirements.

**/!\ Warning:** I am not sure since I never tried it on views routes but it might conflicts or breaks the rules you've set from the views UI to access this view. It should be compatible with a `_permission` rule, maybe not with an `_entity_access` rule.

**yourmodule/yourmodule.services.yml**

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

```

**yourmodule/src/Routing/RouteSubscriber.php**

```
<?php

namespace Drupal\yourmodule\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('view.great_view_name1.page_1')) {
      $requirements = $route->getRequirements();
      $requirements['_custom_access'] = '\Drupal\yourmodule\Access\ByNodeTypeAccessCheck::access';
      // Replace 'my_node_type' with the name of the node type you want.
      // Since it's an array, you can add more than one node type.
      $requirements['_node_types'] = ['my_node_type'];
      $requirements['node'] = '\d+';
      $route->setRequirements($requirements);

      $options = $route->getOptions();
      $options['parameters'] = $options['parameters'] ?? [];
      $options['parameters']['node'] = [
        'type' => [
          'entity:node',
        ],
      ];
      $route->setOptions($options);
    }
  }

}

```

**yourmdule/src/Access/ByNodeTypeAccessCheck.php**

```
namespace Drupal\yourmdule\Access;

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

/**
 * Check the access to a node task based on the node type.
 */
class ByNodeTypeAccessCheck implements AccessCheckInterface {

  /**
   * {@inheritdoc}
   */
  public function applies(Route $route) {
    return NULL;
  }

  /**
   * A custom access check.
   *
   * @param \Drupal\node\NodeInterface $node
   *   Run access checks for this node.
   */
  public function access(Route $route, NodeInterface $node) {
    if ($route->hasRequirement('_node_types')) {
      $allowed_node_types = $route->getRequirement('_node_types');
      if (in_array($node->getType(), $allowed_node_types)) {
        return AccessResult::allowed();
      }
    }
    return AccessResult::forbidden();
  }

}

```
> 1 votes

---
Tags: 8, navigation
---


# Question
Title: How do you programmatically get the shipping information from a placed order?
So far I have a working piece of code that sends me an email ($to variable) when a new order has been placed on my drupal 8 commerce. This is not the email the person that places the order gets.

As part of the body of the email, i was able to find and use variables like a custom attribute, sku, quantity, product name etc...

I realize that in the orderCompleteHandler(), i might have to change what i send as a parameter, instead of $items having to possibly send $order.

But where can i find/how can i get the shipping information, like shipping address, shipping date and the user's that placed the order name : I would like to add them to the email i send.

More importantly is also: how do i find all this info and others by myself? i tried to kint($order) and it either freezes or runs out of memory. I tried dpm($order) and i get 10K lines of info but nothing that is obvious. I tried to look in those 10k lines for some unique data that i knew was part of the shipping info but it wont show up, most likely because that value will be the return value of a get function.

Basically, how should i look and where should i look if i want various information from the order placed variable aka $order?

Any help in debugging and pointing me in the right direction would be appreciated.

```
public function orderCompleteHandler(WorkflowTransitionEvent $event) {

        // @var \Drupal\commerce_order\Entity\OrderInterface $order
        $order = $event->getEntity();
        $items = $order->getItems();

        $mail_manager = \Drupal::service('plugin.manager.mail');
        $to = 'myEmail@gmail.com';
        $langcode = \Drupal::currentUser()->getPreferredLangcode();
        $type = 'order_placed';

        $mail_manager->mail('my_custom_order', $type, $to, $langcode, $items, NULL, TRUE);

    }

/**
 * Implements hook_mail()
 * Prepares emails sent by the MailHandler service.
 * Emails are sent within the OrderComplete Event Subscriber.
 */
function my_custom_order_mail($key, &$message, $params) {
    switch($key) {
        case 'order_placed':
            $options = array(
                'langcode' => $message['langcode'],
            );
            // Creating an html formatted email.
            $message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed; delsp=yes';
            $message['from'] = 'staff@myCompany';
            $message['subject'] = t('Order @order_number confirmed', array('@order_number' => $params[0]->getOrderId()), $options);

            $entire_email_display = '';
            foreach ($params as $product) {
                // Get the Custom Location.
                $productLocation = $product->getPurchasedEntity()->getAttributeValueIds()['attribute_custom_location'];
                $order_item['sku'] = $product->getPurchasedEntity()->getSku();
                $order_item['quantity'] = (int)$product->getQuantity();
                $order_item['product_name'] = $product->getPurchasedEntity()->getTitle();

                // HERE I BUILT an entire email body and stored in the $entire_email_display.
            }

            $message['body'][] = $entire_email_display;
    }
}

```

# Answer
You can have the shipping information with :

> $shippement = $order-\>shipments-\>first()-\>entity;
>
> $shipping\_profile = $shippement-\>shipping\_profile-\>first()-\>entity;
> 4 votes

---
Tags: 8, commerce
---


# Question
Title: Changing column names for CSV export in Webform results download page
This should be very basic. Unfortunately I couldn't find any page that provides specific instructions on how to do this. If anyone can point me in the right direction, much obliged.

Basically I just need to automatically rearrange and change the names of a few columns when I go to the submissions results download page in Webforms. That way, when I export in CSV, I get the column names I want instead of the ones I created in the actual webform.

I'm aware you can do this via a view, but I would like more specific instructions... Anyone know of any guide that can point me in a right direction?

Thanks.

# Answer
If you want to change the column title of an exported element, the simplest solution is to specify an 'Admin title' via the element edit form's 'Advanced' tab under the 'Administration' detail widget.
> 0 votes

---
Tags: 8, webforms
---


title: check for multiple roles

text:
# Question
Title: check for multiple roles
This code I use when checking if user has a role

```
if (in_array('administrator', array_values($user->roles)))

```

How to check for multiple roles? I tried something like this

```
if (!in_array('administrator', 'operator',  array_values($user->roles))

```

I made it work like this

```
if (in_array('administrator', array_values($user->roles)) && in_array('operator', array_values($user->roles)))

```

but there must be some less code solution. but it is not working. Thank you.

# Answer
Look at PHP's array\_diff() function:

http://php.net/manual/en/function.array-diff.php

This will compare an array of the roles you're checking for against the array of the user's roles, and return an array containing the leftovers.

```
<?php
$roles_to_check_for = array('administrator', 'operator');
$users_roles = array_values($user->roles);

if (array_diff($roles_to_check_for, $users_roles)) {
  // User does not have all of the $roles_to_check_for.
}
else {
  // User has all of the $roles_to_check_for.
}

```
> 1 votes

# Answer
Here is what I found from http://drupal-howtos.blogspot.com/. I do not have a drupal 6 setup so could not verify but the solution seems reasonable. Try the foreach part and see if it helps.

```
<?php
  global $user;

  // You can traverse through the array
  // and check if user has the role you want
  foreach($user->roles as $rid => $role){
    if($role == "role_i_want"){
      // Do something
    }
  }
?>

```
> 0 votes

# Answer
This is what I use for Drupal 8.

```
use Drupal\Core\Session\AccountInterface;

     /**
     * Utility function that checks for single or multiple roles.
     *
     * @param string or array $roles
     *   The role(s) to check.
     *
     * @param AccountInterface $account
     *   The user to check
     *
     * @return bool
     *   Whether the account has the role(s)
     *
     */

    function _user_has_roles($roles, AccountInterface $account) {
        // checks if the account has role(s)
        $roles = is_array($roles) ? $roles : [$roles];
        return !!count(array_intersect($roles, array_values($account->getRoles()));
    };

```

For example:

```
$isGeek = _user_has_roles(['maker', 'baker'], \Drupal::currentUser());
$isBaker = _user_has_roles('baker', \Drupal::currentUser());

```
> 0 votes

---
Tags: 6
---


# Question
Title: Add a custom action on admin content page
I want to add a custom action to the dropdown on the admin content page (/admin/content) as shown in the screenshot below using Drupal 9. The views module is enabled so that form is part of the view.

I have found that actions are now plugins so I should just need to create a new plugin for my custom action.

I've used the actions found in `/core/lib/Drupal/Core/Action/Plugin/Action/` as an example for my new action so just created a new plugin that extends `EntityActionBase` add added the relevant methods.

I have a custom module called `shop_scrape`. I created the file `shop_scrape/src/Plugin/Action/ScrapeAction.php`

That file contains:

```
<?php

/**
 * @file
 * Contains \Drupal\shop_scrape\Plugin\Action\ScrapeAction.
 */

namespace Drupal\shop_scrape\Plugin\Action;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Action\Plugin\Action\EntityActionBase;
use Drupal\Core\Annotation\Action;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Scrape a page.
 *
 * @Action(
 *   id = "entity:scrape_action",
 *   label = @Translation("Scrape a page"),
 *   deriver = "Drupal\shop_scrape\Plugin\Action\EntityScrapeActionDeriver",
 * )
 */
class ScrapeAction extends EntityActionBase
{

  /**'
   * ScrapeAction constructor.
   * @param array $configuration
   * @param $plugin_id
   * @param $plugin_definition
   * @param EntityTypeManagerInterface $entity_type_manager
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager)
  {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition)
  {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function executeMultiple(array $entities)
  {
    foreach ($entities as $entity) {
      \Drupal::messenger()->addMessage('Scrape ' . $entity->id());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function execute($object = NULL)
  {
    $this->executeMultiple([$object]);
  }

  /**
   * {@inheritdoc}
   */
  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE)
  {
    $access = AccessResult::allowed();
    return $return_as_object ? $access : $access->isAllowed();
  }

}

```

Then I also created a `EntityScrapeActionDeriver` that for now just returns true:

```

<?php

namespace Drupal\shop_scrape\Plugin\Action;

use Drupal\Core\Entity\EntityTypeInterface;

/**
 * Provides an action deriver that finds scrapable entity types.
 *
 * @see \Drupal\Core\Action\Plugin\Action\PublishAction
 * @see \Drupal\Core\Action\Plugin\Action\UnpublishAction
 */
class EntityScrapeActionDeriver extends EntityActionDeriverBase {

  /**
   * {@inheritdoc}
   */
  protected function isApplicable(EntityTypeInterface $entity_type) {
    return true;
    //return $entity_type->getLabel() == 'page';
  }

}

```

But my custom action is not appearing. Are there other steps I need to take or have I done something wrong?

# Answer
> 2 votes
Here is a sample code which creates a custom action plugin which modifies node title.

**action\_plugin\_examples/src/Plugin/Action/ArchiveNode.php**

```
<?php

namespace Drupal\action_plugin_examples\Plugin\Action;

use Drupal\Core\Action\ActionBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\pathauto\PathautoState;

/**
 * Provides an Archive Node Action.
 *
 * @Action(
 *   id = "action_plugin_examples_archive_node",
 *   label = @Translation("Archive Node"),
 *   type = "node",
 *   category = @Translation("Custom")
 * )
 */
class ArchiveNode extends ActionBase implements ContainerFactoryPluginInterface {

  /**
   * The Messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * Logger service.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $logger;

  /**
   * The path alias manager.
   *
   * @var \Drupal\path_alias\AliasManagerInterface
   */
  protected $aliasManager;

  /**
   * Language manager for retrieving the default Langcode.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = new static($configuration, $plugin_id, $plugin_definition);
    $instance->logger = $container->get('logger.factory')->get('action_plugin_examples');
    $instance->messenger = $container->get('messenger');
    $instance->aliasManager = $container->get('path_alias.manager');
    $instance->languageManager = $container->get('language_manager');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function access($node, AccountInterface $account = NULL, $return_as_object = FALSE) {
    /** @var \Drupal\node\NodeInterface $node */
    $access = $node->access('update', $account, TRUE)
      ->andIf($node->title->access('edit', $account, TRUE));
    return $return_as_object ? $access : $access->isAllowed();
  }

  /**
   * {@inheritdoc}
   */
  public function execute($node = NULL) {

    /** @var \Drupal\node\NodeInterface $node */

    $language = $this->languageManager->getCurrentLanguage()->getId();

    $old_alias = $this->aliasManager->getAliasByPath('/node/' . $node->id(), $language);

    $title = $node->getTitle();
    $date = $node->created->value;
    $year = date('Y', $date);
    // $old_alias = $node->path->alias;
    $new_title = $this->t('[Archive] | @title', ['@title' => $title]);
    $node->setTitle($new_title);
    $node->setSticky(FALSE);
    $node->setPromoted(FALSE);

    $new_alias = '/archive/' . $year . $old_alias;
    $node->set("path", [
      'alias' => $new_alias,
      'langcode' => $language,
      'pathauto' => PathautoState::SKIP,
    ]);

    $node->save();

    $message = $this->t('Node with NID : @id Archived.', ['@id' => $node->id()]);

    $this->logger->notice($message);
    $this->messenger->addMessage($message);

  }

}

```

**action\_plugin\_examples/config/optional/system.action.action\_plugin\_examples\_archive\_node.yml**

```
langcode: en
status: true
dependencies:
  enforced:
    module:
      - action_plugin_examples
  module:
    - node
    - pathauto
id: action_plugin_examples_archive_node
label: 'Archive Node'
type: node
plugin: action_plugin_examples_archive_node
configuration: {  }

```

**Note** : plugin **yml** file needs to be in the below format.

> system.action.\<plugin\_id\>.yml

---
Tags: entities, actions
---


# Question
Title: What version of jQuery does Drupal 8 use?
How can I find out what version of jQuery a particular release of Drupal 8 core is using?

# Answer
If you want to save some time, you can go to the Javascript console and type `jQuery.fn.jquery` which works on any site using jQuery, not only Drupal sites.

At the moment Drupal 8 core uses jQuery 2.1.4, but it looks like jQuery 3 has been implemented in Drupal 8.4.x.

https://www.drupal.org/node/2533498
> 11 votes

# Answer
This is probably not the best question because the answer could change over time based on the specific version of Drupal.

The most accurate way to find what version of a JavaScript library is used by Drupal core is to look directly at the `core/core.libraries.yml` file for a given version of Drupal. One of the easiest ways to do this is to browse Drupal's git repository online:

https://git.drupalcode.org/project/drupal/blob/HEAD/core/core.libraries.yml#n334

```
jquery:
  remote: https://github.com/jquery/jquery
  version: VERSION_HERE
  license:
    name: MIT
    url: https://github.com/jquery/jquery/blob/VERSION_HERE/MIT-LICENSE.txt
    gpl-compatible: true
  js:
    assets/vendor/jquery/jquery.min.js: { minified: true, weight: -20 }

```

For Drupal 6-7, without jquery\_update module installed, the version of Drupal can be most easily discovered by going into the `misc/` directory, and looking at the top of the jquery.js file. This is v1.2.6 and v1.4.4 respectively.

For Drupal 5, the version of jquery is not readily apparent, but the handy `git blame misc/jquery.js` reveals the commit 0d57bae updated jQuery to v1.0.4.
> 9 votes

# Answer
In Drupal 8.9.x the version being used is 3.5.1 as you will see here https://git.drupalcode.org/project/drupal/-/blob/8.9.x/core/core.libraries.yml#L365
> 0 votes

---
Tags: 8, javascript
---


# Question
Title: How do I show an already hidden field of a custom content type to a specific authenticated user?
I have a custom content type whose fields are *Name*, *Description*, and *URL* which is hidden by default. I want to show the latter field to the authenticated users who have flagged the node containing it. (I installed the *Flag* module for the flags.)
The flagging and displaying the flagged items are working fine. The only thing I am having trouble with is the hidden URL.

Can anyone guide me on how I can do this?

I looked into using the Rules and the Conditional Fields modules, but I don't think they would help and they seem to be an overkill for this particular task. I also looked into implementing `hook_page_alter()`, but that didn't help either.

# Answer
> 1 votes
It's possible to hide/show an entity field when an entity is rendered, but a hidden field is automatically removed from the base class used to implement an entity view, the `EntityDisplayBase` class. Its constructor calls `EntityDisplayBase::init()`, which contains the following code.

```
// @todo Remove handling of 'type' in https://www.drupal.org/node/2799641.
if (!isset($options['region']) && !empty($options['type']) && $options['type'] === 'hidden') {
  $options['region'] = 'hidden';
  @trigger_error("Support for using 'type' => 'hidden' in a component is deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. Use 'region' => 'hidden' instead. See https://www.drupal.org/node/2801513", E_USER_DEPRECATED);
}
if (!empty($options['region']) && $options['region'] === 'hidden') {
  $this
    ->removeComponent($name);
}

```

Since that code is executed when the entity display class is build, every hook running before the entity is rendered would not get those hidden components (which are entity fields and extra fields).

Rather than setting an entity field as hidden by default, and then show it when some conditions are met (which would not be possible), you can set the field as visible by default, and hide it when some conditions are met. Which hook to use depends also from when that field needs to be hidden.

If the entity field needs to be hidden only when specific view modes (a.k.a. entity display modes) are used, then `hook_entity_view_display_alter()` can be implemented.

```
use \Drupal\Core\Entity\Display\EntityViewDisplayInterface;

function mymodule_entity_view_display_alter(EntityViewDisplayInterface $display, array $context) {
  // Leave field labels out of the search index.
  if ($context['entity_type'] == 'node' && $context['view_mode'] == 'the view module you are interested to') {
    $components = $display->getComponents();
    $name = 'The machine name of the field you want to hide.'
    if (isset($components[$name])) {
      $options = $components[$name];
      // Verify the conditions to hide the field are met.
      $options['region'] = 'hidden';
      $display->setComponent($name, $options);
      }
    }
  }
}

```

The code I shown assumes you are using at least Drupal 8.3; otherwise, it needs to be changed. (Instead of `$options['region']`, it needs set `$options['type'] to` 'hidden'\`.)

If you need to hide the field independently from the view mode used to render the node, then the hook to implement is `hook_entity_field_access()`.

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

function mymodule_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
  if ($field_definition->getName() == 'the field you are interested to' && $operation == 'view') {
    // Verify the conditions to hide the field are met.
    // Return AccessResult::forbidden() if the conditions are met.
    return AccessResult::forbidden();
  }
  // Otherwise, return AccessResult::neutral(), which lets Drupal core
  // or third-party modules decide.
  return AccessResult::neutral();
}

```

I used `AccessResult::forbidden()` just as example. You could also verify the account passed to the hook has a specific permission with `AccessResult::allowedIfHasPermission($account, 'permission to check')`, or verify the account has one or more permissions with `AccessResult::allowedIfHasPermissions($account, ['list', 'of', 'permissions'], 'OR')`.

Keep in mind that, implementing `hook_entity_field_access()`, you would also avoid the field is indexed by the Search module. If you want the field to be indexed by the Search module, you need to implement `hook_entity_view_display_alter()` and leave the field visible when `$context['view_mode']` is equal to `'search_index'`.

As alternative, you could create a view mode that is similar to the view mode used to show the node, but where the hidden field is visible. Implementing `hook_entity_view_mode_alter()` you can alter the view mode to use the one you created.

```
use Drupal\Core\Entity\EntityInterface;

function mymodule_entity_view_mode_alter(&$view_mode, EntityInterface $entity, $context) {
  // For nodes, change the view mode when it is teaser.
  if ($entity->getEntityTypeId() == 'node' && ($view_mode == 'full' || $view_mode == 'teaser')) {
    // Verify the conditions are met.
    $view_mode = 'my_custom_view_mode';
  }
}

```

# Answer
> 0 votes
With Drupal 7, I would still set the field to be visible by default and hide it when some conditions are met, but differently from Drupal 8, I would implement `hook_node_view_alter()`. (In the following code, replace *field\_of\_interest* with the machine name of the field you need to hide.)

```
function mymodule_node_view_alter(&$build) {
  if ($build['#view_mode'] == 'full' && isset($build['field_of_interest'])) {
    // Make the field not accessible to the current user, if you need to
    // hide it to the current user.
    $build['field_of_interest']['#access'] = FALSE;
  }
}

```

The code checks the view mode to avoid altering the view mode Drupal core or third-party modules use in particular occasions, for example *search\_index* which is used when a node is indexed by the Search module, *feed* which is used when a node is rendered for RSS feed, or *print* which is used from the Book module when the content of a book is exported as HTML.

Alternatively, as with Drupal 8, it's still possible to avoid the currently logged-in user has access to the field when viewing the node containing it. In this case, the field would be hidden independently from the view mode used to render the node. The hook to implement is `hook_field_access()`.

```
function mymodule_field_access($op, $field, $entity_type, $entity, $account) {
  if ($field['field_name'] == 'field_of_interest' && $op == 'view') {
    // Check the conditions are met, and return FALSE when the field must be hidden.
  }
  return TRUE;
}

```

Alternatively, you could set a custom view mode where the field is hidden by default, and tell Drupal to use your custom view mode when some conditions you check are met. The hook to implement in this case is `hook_entity_view_mode_alter()`.

```
function mymodule_entity_view_mode_alter(&$view_mode, $context) {
  if ($context['entity_type'] == 'node' && $view_mode == 'full') {
    // Check the conditions are met and set the view mode to the custom one.
    $view_mode = 'my_custom_view_mode';
  }
}

```

---
Tags: 7, nodes
---


title: Altering commerce invoice mails fails

text:
# Question
Title: Altering commerce invoice mails fails
I'm altering different emails from my `hook_mail_alter(&$message)` function. But for some reason altering the email sent by commerce invoice module is not working. I'm trying to do it like:

```
switch($message['id']){
    case 'invoice_confirmation':
      $message['subject'] = 'Some other title';
      break;

```

I found the code that sends that email in invoice module:

```
  public function send(InvoiceInterface $invoice, $to = NULL, $bcc = NULL) {
    $to = isset($to) ? $to : $invoice->getEmail();
    if (!$to) {
      // The email should not be empty.
      return FALSE;
    }

    $subject = $this->t('Invoice #@number', ['@number' => $invoice->getInvoiceNumber()]);
    $body = [
      '#theme' => 'commerce_invoice_confirmation',
      '#invoice_entity' => $invoice,
      '#totals' => $this->invoiceTotalSummary->buildTotals($invoice),
    ];
    if ($billing_profile = $invoice->getBillingProfile()) {
      $body['#billing_information'] = $this->profileViewBuilder->view($billing_profile);
    }

    $params = [
      'id' => 'invoice_confirmation',
      'from' => $invoice->getStore()->getEmail(),
      'bcc' => $bcc,
      'invoice' => $invoice,
    ];
    $customer = $invoice->getCustomer();
    if ($customer->isAuthenticated()) {
      $params['langcode'] = $customer->getPreferredLangcode();
    }
    $file = $this->invoiceFileManager->getInvoiceFile($invoice);
    $attachment = [
      'filepath' => $file->getFileUri(),
      'filename' => $file->getFilename(),
      'filemime' => $file->getMimeType(),
    ];
    $params['attachments'][] = $attachment;

    return $this->mailHandler->sendMail($to, $subject, $body, $params);
  }

}

```

and there I saw that id should be `'invoice_confirmation'`, but like my hook function is never reached when this email is sent?! How to alter this email title?

# Answer
Solved the issue - id is actually 'commerce\_invoice\_confirmation'.

I was trying to print out $message\['id'\] and stop executing of code, but that never happened? So I assumed that my code was never called. Not sure why. So I used watchdog logger to log id value and found it out.
> 0 votes

---
Tags: 8, commerce, emails
---


# Question
Title: How do I implement bootstrap's panel component for a specific block / block region in my bootstrap (sub) theme?
I have a `bootstrap` sub-theme, and would like to render some of my blocks using Bootstrap's Panels components, so that the block would need to be wrapped something like this:

```
<div class="panel panel-default">
  <div class="panel-heading">
    {{ header }}
  </div>
  <div class="panel-body">
    {{ content }}
  </div>
</div>

```

So far I've tried to implement this via the following series of dirty hacks:

* Setting the `css-class` setting on the advanced settings of the view to `panel panel-default`
* wrapping the header of the view in a `<div class="panel-heading">` block
* setting the `row-class` parameter in the settings of the view's unformatted list format to `panel-body`

This *almost* works, but isn't quite right:

The issue is that the resulting classes aren't nested correctly:

If I manually modify the classes in my browser and set `view-header` to `panel-heading` and `view-content` to `panel-body` I get the desired effect:

So I know what I want, but how do I achieve this? I'm new to twig and I feel like there must be an easy solution to this out there, I just don't know what it is. Note that I don't want to make *every* block behave like this, just this one.

# Answer
Quick-and-dirty way: Uncheck all the boxes to display default classes in Views, and then use a twig template specifically for that views block to write the CSS exactly as you want.

You can find the Views twig templates in `/core/modules/views/templates`.

It depends on how you configured the view, but if it's an unformatted block, you want the unformatted template, `views-view-unformatted.html.twig`. Copy that file from the Views template directory into your subtheme's directory.

Next, you have to rename the file so that it only applies to the block. In Drupal 7, Views was nice and gave you the suggested theme hooks, but in Drupal 8, you have to figure them out yourself.

The rule is `TEMPLATE_NAME--VIEW_MACHINE_NAME--DISPLAY_MACHINE_NAME`.

If you go to edit the view in the admin UI, you can get this info from the URL.

`/admin/structure/views/view/VIEW_MACHINE_NAME/edit/DISPLAY_MACHINE_NAME`.

Once you rename the file, you will need to rebuild the cache to get Drupal to use it.

Sometimes you may need to customize other views templates as well (a single view can use multiple templates); you can do that in the same way as described above..
> 1 votes

---
Tags: 8, theming
---


# Question
Title: How do I get the public file URI for a media file from jsonapi?
I have an audio file that is stored as Media of type Audio.

Now I want to get the link to that file that is usually displayed to site users via jsonapi.

For example, when the media entity is rendered, this is the link:

```
<audio controls="" controlslist="nodownload"> <source src="/sites/default/files/coolstuff/audio/apples-bananas-pears.mp3" type="audio/mpeg"> </audio>

```

This `/sites/default/files/coolstuff/audio/apples-bananas-pears.mp3` path is what I want to get from jsonapi.

However, when I look at the output of `/jsonapi/media/audio`, all the URLs look like this:

```
http://mysite.com/jsonapi/media/audio/d741b59c-9617-4a24-a2e8-99005a76507b?resourceVersion=id%3A31"

```

None of them have the public-facing URI.

The documentation gives this example for a "article media entity reference field\_image url, uri by including references":

```
http://example.com/jsonapi/node/article/{{article_uuid}}?include=field_image&fields[file--file]=uri,url

```

I have media entity references, so I tried the same on my site:

```
http://mysite.com/jsonapi/node/MY_CONTENT_TYPE?include=field_ref_media_audio&fields[file--file]=uri,url

```

However, I do not get the regular media URI, just the jsonapi one.

How can I get the media public file URI (`/sites/default/files/coolstuff/audio/apples-bananas-pears.mp3`)?

# Answer
> 0 votes
Here's the correct path:

```
http://mysite.com/jsonapi/node/MY_CONTENT_TYPE?include=field_ref_media_audio.field_media_audio_file&fields[file--file]=uri,url

```

This results in a value for `uri` such as:

```
"value": "public:/sites/default/files/coolstuff/audio/apples-bananas-pears.mp3",

```

---
Tags: media, uri
---


# Question
Title: How do I fix this error caused by migrating from drupal-composer/drupal-scaffold to drupal/core-composer-scaffold?
I have to develop features for an old project stuck on drupal 8.5, so I figured out it would be great to update the core version to at least 8.8 for a start. The project is setup using composer and drush, so I started following the steps listed in https://www.drupal.org/docs/updating-drupal/migrating-the-composer-project-for-drupal-earlier-than-880 But I'm stucked with an error in "Migrating from drupal-composer/drupal-scaffold to drupal/core-composer-scaffold"

This is the initial composer.json

```
{
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],
    "require": {
        "composer/installers": "^1.2",
        "cweagans/composer-patches": "^1.6",
        "drupal-composer/drupal-scaffold": "^2.2",
        "drupal/admin_toolbar": "^1.23",
        "drupal/ajax_comments": "^1.0@beta",
        "drupal/allowed_formats": "^1.1",
        "drupal/better_exposed_filters": "^3.0@alpha",
        "drupal/colorbutton": "^1.1",
        "drupal/console": "^1.0.2",
        "drupal/core": "~8.5.3",
        "drupal/devel": "^1.2",
        "drupal/eu_cookie_compliance": "^1.0",
        "drupal/filefield_paths": "^1.0@beta",
        "drupal/google_analytics": "^3.0",
        "drupal/metatag": "^1.5",
        "drupal/paragraphs": "^1.3",
        "drupal/pathauto": "^1.2",
        "drupal/quick_node_clone": "^1.10",
        "drupal/simple_sitemap": "^2.12",
        "drupal/smtp": "^1.0@beta",
        "drupal/video_embed_field": "^2.4",
        "drupal/views_infinite_scroll": "^1.5",
        "drupal/viewsreference": "^1.2",
        "drupal/webform": "^5.0@RC",
        "drupal/yoast_seo": "2.0-alpha3",
        "drush/drush": "^9.0.0",
        "vlucas/phpdotenv": "^2.4",
        "webflo/drupal-finder": "^1.0.0",
        "webmozart/path-util": "^2.3"
    },
    "require-dev": {
        "webflo/drupal-core-require-dev": "~8.5.3"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "sort-packages": true
    },
    "autoload": {
        "classmap": [
            "scripts/composer/ScriptHandler.php"
        ],
        "files": ["load.environment.php"]
    },
    "scripts": {
        "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold",
        "pre-install-cmd": [
            "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
        ],
        "pre-update-cmd": [
            "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
        ],
        "post-install-cmd": [
            "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
        ],
        "post-update-cmd": [
            "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
        ]
    },
    "extra": {
        "installer-paths": {
            "web/core": ["type:drupal-core"],
            "web/libraries/{$name}": ["type:drupal-library"],
            "web/modules/contrib/{$name}": ["type:drupal-module"],
            "web/profiles/contrib/{$name}": ["type:drupal-profile"],
            "web/themes/contrib/{$name}": ["type:drupal-theme"],
            "drush/Commands/{$name}": ["type:drupal-drush"]
        }
    }
}

```

Running the first step (Migrating from webflo/drupal-core-require-dev to drupal/core-dev) was pretty strait forward but from the second I'm stuck with an error as I run `composer require drupal/core-composer-scaffold:^8.8`

This is the full error message

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

  Problem 1
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.11
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.10
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.9
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.8
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.7
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.6
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.5
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.4
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.3
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.2
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.1
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.0
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.12
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.11
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.10
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.9
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.8
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.7
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.6
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.5
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.4
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.3
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.2
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.1
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.0
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.0-rc1
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.0-rc1
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.0-beta3
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.0-beta2
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.0-beta1
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.0-beta1
    - Conclusion: don't install drupal/core-composer-scaffold 8.8.0-alpha1
    - Conclusion: don't install drupal/core-composer-scaffold 8.9.x-dev
    - drupal/core-composer-scaffold 8.8.x-dev conflicts with drupal-composer/drupal-scaffold[2.5.4].
    - drupal/core-composer-scaffold 8.8.x-dev conflicts with drupal-composer/drupal-scaffold[2.5.4].
    - drupal/core-composer-scaffold 8.8.x-dev conflicts with drupal-composer/drupal-scaffold[2.5.4].
    - Installation request for drupal/core-composer-scaffold ^8.8 -> satisfiable by drupal/core-composer-scaffold[8.8.0, 8.8.0-alpha1, 8.8.0-beta1, 8.8.0-rc1, 8.8.1, 8.8.10, 8.8.11, 8.8.12, 8.8.2, 8.8.3, 8.8.4, 8.8.5, 8.8.6, 8.8.7, 8.8.8, 8.8.9, 8.8.x-dev, 8.9.0, 8.9.0-beta1, 8.9.0-beta2, 8.9.0-beta3, 8.9.0-rc1, 8.9.1, 8.9.10, 8.9.11, 8.9.2, 8.9.3, 8.9.4, 8.9.5, 8.9.6, 8.9.7, 8.9.8, 8.9.9, 8.9.x-dev].
    - Installation request for drupal-composer/drupal-scaffold (locked at 2.5.4) -> satisfiable by drupal-composer/drupal-scaffold[2.5.4].

```

I'm considering giving up on the upgrade since this is only the beginning and it should be the easy part since I don't have to handle the database yet.

How do I fix these errors?

# Answer
> 4 votes
The *Installation request for drupal-composer/drupal-scaffold (locked at 2.5.4) -\> satisfiable by drupal-composer/drupal-scaffold\[2.5.4\]* part means the composer.lock file contains a reference to that version of the *drupal-composer/drupal-scaffold* package.

Since you already ran `composer remove drupal-composer/drupal-scaffold`, remove the line referring to the *drupal-composer/drupal-scaffold* package from the composer.lock file, and run again `composer require drupal/core-composer-scaffold:^8.8`.

# Answer
> 3 votes
In the end running `composer remove drupal-composer/drupal-scaffold` instead of `composer remove drupal-composer/drupal-scaffold --no-update` solved the issue. No idea why the line specified in the doc has this --no-update.

---
Tags: 8, migrations
---


title: Translate view header

text:
# Question
Title: Translate view header
I add a simple text as view header but it is not exists in translatable text in admin/config/regional/translate.

In Drupal 7 we could even translate unformulated views header and footer with the following steps:

1. Go to admin/config/regional/i18n/strings
2. Check "full HTML" in "Translatable text formats" section
3. Go to admin/config/regional/translate/i18n\_string
4. Click on *Refresh strings*

Has this feature been removed form Drupal 8? (I don't think so.)
How can I translate view header and footer simple text?

# Answer
> 3 votes
1. Enable *"Configuration Translation"* core module
2. Go to your view edit and you will see a *"Translate view"* tab
3. You'll find your language in the list there. Then click on *"Edit"* next to the language
4. Expand panels and you will find your header text under the *"Header"* panel

# Answer
> 1 votes
If my previous answer doesn't work fine. Try with this solution.

1. In view add new field "Custom text" (Click checkbox Exclude from display)
2. In "Custom text" add code like this

```
    <div class="custom-title-and-subtitle">
    <h2>{% trans %}Contact us{% endtrans %}</h2>
    <p>{% trans %}Please contact us for UFME Inquiries only. For vocations and prayer requests, contact the Franciscans in your area.{% endtrans %}</p>
    </div>

```
3. In view header add "Unfiltered text" field
4. Click checkbox "Use replacement tokens from the first row"
5. Add REPLACEMENT PATTERNS in my case {{ nothing }}
6. Clear cache And after that you will be able find text in user interface translation "admin/config/regional/translate"

# Answer
> 0 votes
You need to use configuration for your language. Example

# Answer
> -1 votes
You can easy translate view header and footer text using the {% trans %} Twig tag in Drupal 8 Example:

```
{% trans %}
  Text for translate
{% endtrans %}

```

And after that you will be able find text in user interface translation "admin/config/regional/translate"

---
Tags: views, 8, i18n-l10n
---


# Question
Title: Add new field related with other (this field isentity reference) - Custom entity
Is it possible to add a new field related to the entity reference field?

Let me explain, I have one field called "student\_id" which is an entity reference type, so I need to assign one status for it. Is this possible? Can you support me?

# Answer
> 0 votes
It is possible for Fields to have Fields, although these types of structures are usually constructed through Paragraphs in D8.

Paragraphs are basically 2-level entity reference fields. First you create the Paragraph for the Student ID, then inside the Paragraph create two fields, one for the ID number or other info, another for the Status.

There are other ways of achieving similar results but generally speaking this might be the common way to solve it.

# Answer
> 0 votes
Did you define the custom entity in code? Then try this code for a custom field type:

```
/**
 * @FieldType(
 *   id = "entity_reference_quantity",
 *   label = @Translation("Entity reference quantity"),
 *   description = @Translation("An entity field containing an entity reference with a quantity."),
 *   category = @Translation("Reference"),
 *   default_widget = "entity_reference_autocomplete",
 *   default_formatter = "entity_reference_label",
 *   list_class = "\Drupal\Core\Field\EntityReferenceFieldItemList",
 * )
 */

class EntityReferenceQuantity extends EntityReferenceItem {

  public static function propertyDefinitions(FieldStorageDefinitionInterface
  $field_definition) {
    $properties = parent::propertyDefinitions($field_definition);
    $quantity_definition = DataDefinition::create('integer')
      ->setLabel(new TranslatableMarkup('Quantity'))
      ->setRequired(TRUE);
    $properties['quantity'] = $quantity_definition;
    return $properties;
  }

}

```

You need a custom widget and formater as well. See this blog post for the entire code which is also the source for the code I've posted https://www.lullabot.com/articles/extending-a-field-type-in-drupal-8

---
Tags: entities
---


# Question
Title: Can I add pagination to individual blog posts in my twig file?
I have a views page which has all the blog articles, and you can click on a link to bring you to a single blog page.

On that single blog page I want to be able to add buttons for Previous and Next post. Something like

```
<a class="white-btn" href="{{ previous.href }}">Previous Article</a>
 <a class="white-btn" href="{{ next.href }}">Next Article</a>

```

Is this possible?

# Answer
That is the exact feature of the Book module.

Book module overview

You can configure which types are allowed to be added as book pages. There is a Block you can place on Book pages to show Book navigation and Previous/Next links (it obeys the Book pages order).

---

Regular Views don't have a feature to center the Pager around a pagination placement.

A custom solution can be created to add that, but there are also modules you can check out that may help:
> 0 votes

---
Tags: theming, paging
---


title: Publish nodes with drush?

text:
# Question
Title: Publish nodes with drush?
I'm faced with the situation of needing to be able to publish content with Drush. Is there a way to use Drush to publish nodes? If there is, how can it be done?

# Answer
> 5 votes
I am not sure if that is available by default (found no result on searching), but one thing that you can do is declaring your own Drush command in 3 easy steps:

1. Creating the Command File:

> ( Give the right name to the command file and place it into a folder that Drush will look, That name must end with .drush.inc (in our case it will be publish.drush.inc) and must be placed either in the folder of a custom module on your site (will work for that site if the module is enabled) or in the .drush folder in your server’s root directory).
2. Declaring the Command Function: To declare a new Drush command you have to invoke hook\_drush\_command() in the file you created above and below the php opening tag. Example as below:

> function publish\_drush\_command() {
> $items = array();
> $items\['publish-content'\] = array(
> 'description' =\> 'Publish content',
> 'aliases' =\> array('pc'),
> 'arguments' =\> array(
> 'type' =\> 'Nodes of this type will be published',
> ),
> );
> return $items;
> }

Note: This command is declared in a file that has been placed in the .drush folder that resides in the VPS’s root folder.

Here we have declared a new command called publish-content (a new key in the $items array). The description and what’s included in the arguments key is what you will see when you run the drush help publish-content command. What’s actually helpful here is that you can also specify an alias (or shortcut) that can be run instead of the longer publish-content version. In this case, `drush publish-content` will equal `drush pc`.
3. Declare the Command Callback Function: Now you need to write the code that you want Drupal to perform when you run the custom command. The name of the function needs to be in the format: drush\_command\_name. (Note: dash in the command name becomes an underscore in the function name).

```
function drush_publish_content($type) {
  $nodes = node_load_multiple(array(), array('type' => $type));
  $count = 0;
  foreach ($nodes as $node) {
    if($node->status == 0) {
      $count++;
      $node->status = 1;
      node_save($node);
    }
  }
  if($count > 0) {
    drush_print($count . " nodes of the " . $type . " content type have been successfully published.");
  }

  else {
    drush_print("No nodes of the " . $type . " content type were published.");
  }
}

```

This callback function takes as argument the machine name of the content type of all the nodes we want published. This gets passed as a command argument like so (Example: pulish the contents of blog content-type):

> drush publish-content blogs

Drush will then print out how many nodes have been published (displaying only the number of nodes that have been in fact affected by the command).

References: https://www.digitalocean.com/community/articles/how-to-declare-your-own-drush-commands-with-your-vps
https://github.com/edvillan15/node-tools/blob/master/node\_tools.drush.inc

# Answer
> 3 votes
Publish a node in Drupal 8

```
drush php-eval '$node = node_load(123); $node->setPublished(true); $node->save();'

```

Publish a node node in Drupal 7

```
drush php-eval '$node = node_load(123); $node->status = 1; node_save($node);’

```

Publish all the nodes of a specific content type in Drupal 8

```
drush php-eval '$nodes = node_load_multiple(array(), array("type" => "here_the_type_name"));foreach($nodes as $node){ $node->setPublished(true); $node->save();}'

```

Publish all the nodes of a specific type in Drupal 7

```
drush php-eval '$nodes = node_load_multiple(array(), array("type" => "here_the_type_name")); foreach($nodes as $node){  $node->status = 1; node_save($node);}'

```

# Answer
> 1 votes
For drupal 8, this worked (via Dave Burns),

```
drush php-eval '$node = node_load(2); $node->setPublished(true); $node->save();'

```

# Answer
> 1 votes
In drupal 8 this can also be done via node name if the node id is unknown for some reason:

```
drush php-eval '$node=reset(\Drupal::entityTypeManager()->getStorage("node")->loadByProperties(["title"=>"Test Page"]));$node->setPublished(true);$node->save();'

```

# Answer
> 1 votes
Also in drupal 8, if you are using the core Content Moderation Module, replace:

```
$node->setPublished(true);

```

with

```
$node->set("moderation_state","published");

```

---
Tags: 7, drush
---