# Question
Title: How to load field configurations in code
I have defined fields using the UI, and some more fields using YAML files in my custom module, e.g.:

The field storage is defined in `field.storage.node.my_heading`:

```
langcode: en
status: true
dependencies:
  enforced:
    module:
      - my_module
id: node.my_heading
field_name: my_heading
entity_type: node
type: string
settings: {  }
module: core
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: false
custom_storage: false

```

The field instance (which attaches a field to an entity) is defined in `field.field.node.my_content_type.my_heading`:

```
langcode: en
status: true
dependencies:
  config:
    - field.storage.node.my_heading
    - node.type.my_content_type
id: node.my_content_type.my_heading
field_name: my_heading
entity_type: node
bundle: my_content_type
label: 'Heading'
description: 'An optional heading'
required: false
translatable: true
default_value: {  }
default_value_callback: ''
settings: {  }
field_type: string

```

After installing this custom module, how do I get the field configuration in code?

# Answer
The terminology is a bit confusing (as usual with Drupal), but here goes:

Field storage configurations are defined by FieldStorageConfig. To load one, do this:

```
$field = Drupal::entityTypeManager()->getStorage('field_storage_config')->load('node.my_field');

```

Field instance configurations are defined by FieldConfig. To load one, do this:

```
$field_instance = Drupal::entityTypeManager()->getStorage('field_config')->load('node.my_content_type.my_field');

```
> 16 votes

# Answer
There is shorter version for @rudolfbyker's answer

For field storage:

```
use Drupal\field\Entity\FieldStorageConfig;

$field = FieldStorageConfig::loadByName('node', 'my_field');

```

For field instance:

```
use Drupal\field\Entity\FieldConfig;

$field_instance = FieldConfig::loadByName('node', 'my_content_type', 'my_field');

```

Those `loadByName()` static methods are actually wrappers to logic from @rudolfbyker's answer.
> 1 votes

---
Tags: 8, entities, configuration
---


# Question
Title: Dependency injection in create() method of block plugin with derivatives
I am trying to extend the `menu_block` module to allow it to work with domains (via the `domain` module). In order to do this I am extending the `MenuBlock` class, and trying to access the `domain.negotiator` service from within `getDerivativeID()`. I am using the `create()` method to inject the service and store it to a `$domainNegotiator` property as follows:

```
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->domainNegotiator = $container->get('domain.negotiator');
    return $instance;
  }

```

When I attempt to call `$this->domainNegotiator` from within `getDerivativeID()` I get an error stating the property doesn't exist and I therefore cannot access methods on it. In debugging I was able to trace the issue to `MenuBlock::defaultConfiguration()` calling `$this->getDerivativeID()`.

Default configuration is set in `__construct()` inside `BlockPluginTrait` (called in `BlockBase`), so ultimately it boils up to being called in my class's `create()` method.

I am able to work around this issue by using a non-injected version of the service in my `getDerivativeID()` method, however this isn't a great practice:

```
$active_domain = \Drupal::service('domain.negotiator')->getActiveDomain();

```

Is there a way to inject dependencies so they are available before calling `parent::create()` in my class's `create()` method?

# Answer
The Drupal plugin system has four levels. Plugin definition, derivatives, configuration and finally the run-time instance.

As you can see in your error message you configure a specific plugin definition or a derivative of the plugin definition. This definition is static and you can't change it after you have configured it.

Only the run-time instance of the plugin can react on dynamic conditions like the active domain.
> 3 votes

# Answer
I was unable to figure out how to extend `MenuBlock` using only `create()`. I had to change to a `__construct()` and `create()` system, and returned `static()` from within `create()` while manually injecting the dependencies from both the `MenuBlock` and `SystemMenuBlock` classes. This is a bit less robust in that it will break if the `MenuBlock` class ever changes dependencies, however it still accomplishes the intended behavior of using an injected dependency within `getDerivitiveId()`:

```
  public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail, MenuParentFormSelectorInterface $menu_parent_form_selector, EntityTypeManagerInterface $entity_type_manager, DomainNegotiatorInterface $domain_negotiator) {
    $this->domainNegotiator = $domain_negotiator;
    $this->menuParentFormSelector = $menu_parent_form_selector;
    $this->entityTypeManager = $entity_type_manager;
    parent::__construct($configuration, $plugin_id, $plugin_definition, $menu_tree, $menu_active_trail);
  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('menu.link_tree'),
      $container->get('menu.active_trail'),
      $container->get('menu.parent_form_selector'),
      $container->get('entity_type.manager'),
      $container->get('domain.negotiator'));
  }

```
> 1 votes

---
Tags: plugins, dependency-injection
---


# Question
Title: Perform entityQuery with multiple fields conditions on referenced fields
I have an article node type with a field referencing related articles. If an article has less than 4 references for that field, I need to search for other articles which

* are not the current node
* have been updated less than 2 years ago
* have a checkbox 'favorite' checked
* share at least one culture id (taxonomy reference) AND at least one theme id (taxonomy reference)

And I am actually wondering how to perform that last need... Based on Perform a query with an entity field condition with multiple values, I wrote the following code:

```
<?php

namespace Drupal\my_module\Preprocess;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Preprocess Node type Article.
 */
class MyArticle implements ContainerInjectionInterface {

  const MAX_RELATED_ARTICLES = 4;

  /**
   * Taxonomy term storage.
   *
   * @var \Drupal\node\NodeStorage
   */
  protected $nodeStorage;

  /**
   * Class constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->nodeStorage = $entity_type_manager->getStorage('node');
  }

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

  /**
   * Preprocess node type article.
   *
   * @param array $variables
   *   An array of variables used to render the node.
   */
  public function preprocess(array &$variables) {
    if ('full' === $variables['view_mode']) {
      $this->preprocessFull($variables);
    }
  }

  /**
   * Preprocess node type article in view mode full.
   *
   * @param array $variables
   *   An array of variables used to render the node.
   */
  protected function preprocessFull(array &$variables) {
    $node = $variables['node'];

    $related_articles = $node->get('related_articles')->referencedEntities();
    $themes = $node->get('themes')->referencedEntities();
    $cultures = $node->get('cultures')->referencedEntities();
    $themes_ids = $cultures_ids = [];
    foreach ($themes as $term) {
      $themes_ids[] = $term->id();
    }
    foreach ($cultures as $term) {
      $cultures_ids[] = $term->id();
    }
    $nb_related_articles = count($related_articles);

    if ($nb_related_articles < self::MAX_RELATED_ARTICLES) {
      $limit = self::MAX_RELATED_ARTICLES - $nb_related_articles;
      $changed_boundary = strtotime('-2 years');
      $query = $this->nodeStorage->getQuery()
        ->condition('type', 'article')
        ->condition('status', 1)
        ->condition('nid', $node->id(), '<>')
        ->condition('favorite', 1)
        ->condition('changed', $changed_boundary, '>=')
        ->range(0, $limit);
      $or_themes = $or_cultures = $query->orConditionGroup();
      foreach ($themes_ids as $tid) {
        $or_themes->condition('cultures', $tid);
      }
      foreach ($cultures_ids as $tid) {
        $or_cultures->condition('themes', $tid);
      }
      $and = $query->andConditionGroup()
        ->condition($or_themes);
      $query->condition($and);
      $and = $query->andConditionGroup()
        ->condition($or_cultures);
      $query->condition($and);
      $node_ids = $query->execute();
    }
  }

}

```

which gives me the following query:

```
SELECT "base_table"."vid" AS "vid", "base_table"."nid" AS "nid"
FROM "node" "base_table"
INNER JOIN "node_field_data" "node_field_data" ON "node_field_data"."nid" = "base_table"."nid"
INNER JOIN "node__favorite" "node__favorite" ON "node__favorite"."entity_id" = "base_table"."nid"
LEFT JOIN "node__cultures" "node__cultures" ON "node__cultures"."entity_id" = "base_table"."nid"
LEFT JOIN "node__themes" "node__themes" ON "node__themes"."entity_id" = "base_table"."nid"
LEFT JOIN "node__cultures" "node__cultures_2" ON "node__cultures_2"."entity_id" = "base_table"."nid"
LEFT JOIN "node__themes" "node__themes_2" ON "node__themes_2"."entity_id" = "base_table"."nid"
WHERE ("node_field_data"."type" = 'article')
AND ("node_field_data"."status" = 'NODE_PUBLISHED')
AND ("node_field_data"."nid" <> '19533')
AND ("node__favorite"."favorite_value" = '1')
AND ("node_field_data"."changed" >= '1583280325')
AND (("node__cultures"."cultures_target_id" = '5077') or ("node__themes"."themes_target_id" = '42') or ("node__themes"."themes_target_id" = '38'))
AND (("node__cultures_2"."cultures_target_id" = '5077') or ("node__themes_2"."themes_target_id" = '42') or ("node__themes_2"."themes_target_id" = '38'))
GROUP BY base_table.vid, base_table.nid
LIMIT 4 OFFSET 0

```

And it's not what I expected since I need a AND condition between culture ids and theme ids. I would need something like :

```
AND (("node__cultures"."cultures_target_id" = '5077') AND (("node__themes"."themes_target_id" = '42') or ("node__themes"."themes_target_id" = '38')))

```

instead of

```
AND (("node__cultures"."cultures_target_id" = '5077') or ("node__themes"."themes_target_id" = '42') or ("node__themes"."themes_target_id" = '38'))

```

So my question is: is there a way to aciheve this with the And/OrConditionGroup or should I use subqueries to match some specific ids for both themes and cultures?

# Answer
> 2 votes
One small thing is you're mismatching your ids and your fields here:

```
foreach ($themes_ids as $tid) {
  $or_themes->condition('cultures', $tid); // should use field 'themes'
}
foreach ($cultures_ids as $tid) {
  $or_cultures->condition('themes', $tid); // should use field 'cultures'
}

```

But the major issue is here:

```
$and = $query->andConditionGroup()
  ->condition($or_themes);
$query->condition($and);
$and = $query->andConditionGroup()
  ->condition($or_cultures);
$query->condition($and);

```

You're wrapping each OR condition in its own AND condition.

But what you want is one AND condition wrapping your two OR conditions:

```
$and = $query->andConditionGroup()
  ->condition($or_themes)
  ->condition($or_cultures);
$query->condition($and);

```

Additionally, as mentioned by @pmichelazzo, you can (should? I would) use IN instead of your OR condition groups, e.g.

```
$cultures_and_themes = $query->andConditionGroup()
  ->condition('cultures', $cultures_ids, 'IN')
  ->condition('themes', $themes_ids, 'IN');
$query->condition($cultures_and_themes);

```

# Answer
> 1 votes
Using the snippet that you provide (and expect to have), probably you could use the operator IN instead of AND:

`AND (("node__cultures"."cultures_target_id" = '5077') AND (("node__themes"."themes_target_id" IN ('42', '38'))`

On this way, you get the cultures with target ID 5077 (since it's the same for both), and the themes with target ID 42 OR 38.

---
Tags: entities, 9
---


# Question
Title: What can I use as a unique identifier between a node and its translation now that the "tnid" field is no longer available?
We are upgrading our site from D7 to D8 and a part of this includes sending data out to another resource, specifically, Nodes. When we send data to the 3rd party resource, it's expecting something like

```
[
  {
    "drupalId": 1,
    "title": "English Node",
    "tnid": 1
  },
  {
    "drupalId": 2,
    "title": "Translated Node",
    "tnid": 1

  }
}

```

This allows the 3rd party resource to store 2 separate nodes and then links them together using the `tnid`, and in this 3rd party resource, the Drupal Id is suppose to be unique. However, in D8, it appears that a node and it's translation has the same Drupal Node Id and there does not exist a 'tnid' value, like it was in D7. I assume this is just the change in how translations work in Drupal 8 now, which brings me to my issue:

What can I use as a unique identifier between a node and its translation now?

In D7, the Node Id was a unique identifier and the tnid was a "link" between a node and its translation. In D8, the Node Id is the "link" between a node and its translation, but what could I use to distinguish a Node from its Translation?

# Answer
For example in **hook\_entity\_presave** you can do this:

```
/**
 * Implements hook_entity_presave().
 */
function ci_manager_entity_presave($entity) {
  $entity_de = $entity->getTranslation('de');
  $entity_de->getTitle();
}

```

Reference documentation: https://api.drupal.org/api/drupal/core%21modules%21node%21src%21Entity%21Node.php/class/Node/9.2.x
> 0 votes

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


title: How do I post a PDF?

text:
# Question
Title: How do I post a PDF?
I followed these steps to post a PDF file to Drupal.

1. Enable JSON API to create at admin/config/services/jsonapi
2. Enable the media POST resource

```
Media /media/{media}/edit: GET, PATCH, DELETE
      /entity/media: POST

Methods: POST, formats: json: authentication: cookie

```
3. Create an Angular application and embed it in the Drupal page as a block

The Angular application captures the page using jspdf and embeds the image in the PDF. Instead of using an interceptor, I'm getting a token with each request.

```
this.certificateService.getCsrf().subscribe(token => {
  this.certificateService.uploadMedia(pdf.output('blob'), fileName, token).subscribe({
    complete: () => {
      console.log('posted media');
    }
  })
});

```

`getCsrf()` grabs the token as text.

```
getCsrf(): Observable<string> {
  const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');

  return this.httpClient.get(this.host + '/session/token',{ headers: headers, responseType: 'text'}).pipe(catchError(this.handleError<any>('token')))
}

```

`uploadMedia()` tries to post the PDF file to media to Drupal.

```
uploadMedia(pdf: Blob, name: string, token: string): Observable<any> {
  const formData: FormData = new FormData();
  formData.append('certificate', pdf, name);
  const headers = new HttpHeaders();
  headers.set('Accept', 'application/vnd.api+json');
  headers.set('X-CSRF-Token',token);
  // headers.set('Content-Type','application/octet-stream');
  headers.set('Content-Type','application/hal+json');
  headers.set('Content-Disposition',`file; filename=${name}`);

  return this.httpClient.post(this.host + '/entity/media', formData, {headers: headers})
    .pipe(
      catchError(this.handleError<any>('uploadMedia'))
    );
}

```

The error I get is *415 Unsupported media type*.

I am using Angular 13 and Drupal 9.

I looked at the Drupal error log; it reports the following exception.

> Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException: No route found that matches "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryYAzO5lNTfgLQwQq9" in Drupal\Core\Routing\ContentTypeHeaderMatcher-\>filter()

Just setting the Content-Type header does not always alter the content type header that is posted. e.g. With both axios and angular http if you post a *FormData* array you will get a multi-part form even though you the header at the call level is application/octet-stream

Using axios within angular as follows result in 'application/octet-stream':

```
import Axios from 'axios-observable';
Axios.defaults.headers.post['X-CSRF-Token'] = token;
return Axios.post(this.host + '/entity/media', pdf, {
  headers: {
    Accept: `application/json, text/plain, */*',
    Authorization: `Basic ${basic}`,
    Cookie: ${cookie}; XDEBUG_SESSION=13681',
    'Content-Type': 'application/octet-stream',
  }
});

```

Passing raw PDF data results in 'application/pdf'

```
const headers = new HttpHeaders();
headers.set('Content-Type', 'application/octet-stream');
return this.httpClient.post(this.host + '/entity/media', pdf, {headers: headers})
  .pipe(
    catchError(this.handleError<any>('uploadMedia'))
);

```

Reviewing the rest services page *admin/config/services/rest*, the allowed content format is 'json'

Debugging confirms that symfony is checking this value

Trying a REST interface i.e. '/jsonapi/media/document/field\_media\_document/'

Yes there is a 'bin' content type requirement in web/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php which

```
// Add the content type format access check. This will enforce that all
// incoming requests can only use the 'application/octet-stream'
// Content-Type header.

```

The */entity/media* JSON API request url does need a JSON request as per *web/core/lib/Drupal/Core/Routing/ContentTypeHeaderMatcher.php*

# Answer
> 0 votes
I use Angular, not React, but I'm pretty sure this part is wrong:

```
  // headers.set('Content-Type','application/octet-stream');
  headers.set('Content-Type','application/hal+json');

```

Files need to be posted as `application/octet-stream`. It's not a JSON object; it's a file.

Also, you may need to massage the PDF data into something that JSON:API understands. For example, here's the docs on doing this with axios/Node.js.

In my case, for image files, I had to read the file in as a blob (React code, but may provide an example):

```
// https://stackoverflow.com/a/46568146
function readFileBlob(fileBlob: Blob) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => {
      resolve(reader.result);
    };
    reader.onabort = () => Promise.reject(Error('file reading was aborted'));
    reader.onerror = () => Promise.reject(Error('file reading has failed'));
    reader.readAsArrayBuffer(fileBlob);
  });
}

// fileToPost is a string that contains a blob:
// blob:http://localhost:8100/00507d3e-7f6f-4f48-be80-b55c8bc20dd3
const postAuthFileBlob = async (
  fetchUrl: string,
  fileToPost: string,
  // Fetch might return anything.
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> => {
  const fileBlob = await fetch(fileToPost).then((res) => res.blob());
  const arrayStr = (await readFileBlob(fileBlob)) as ArrayBuffer;
  return postAuthFileBlobPart2(fetchUrl, arrayStr);
};

```

---
Tags: media, javascript
---


# Question
Title: How to remove subdir from base URL after installing site with Composer on a shared host?
I've managed to install drupal 8 using composer and following script:

composer create-project drupal-composer/drupal-project:8.x-dev my\_site\_name\_dir --stability dev --no-interaction

I decided to use composer since it seems to be the new way and you get all the dependencies with it.

But the structure is different then installing drupal by downloading it to the server. And that's my problem.

I'm using shared hosting and before composer everything landed in the folder public\_html. But with composer there's a folder called web inside public\_html that holds drupal itself (or at least it seems that way to me). So instead of having a url like www.mydomain.com I end up with www.mydomain.com/web to reach the site.

My question is how do I do to hide /web from the url? Or do I do something when installing via composer?

I've done a temporary solution that hides /web just from the frontpage. Had to create a new .htaccess in public\_html which included following:

RewriteRule ^$ web/$1 \[L\]
RewriteCond %{REQUEST\_FILENAME} !-d
RewriteCond %{REQUEST\_FILENAME} !-f
RewriteRule ^(.\*)$ /$1 \[L\]

But as soon as you click on a different page the /web is there again.

Any hints or of course answers are most welcome.

Thanks //Tobias

# Answer
> 5 votes
Me and my collegue managed to find a working solution.

In our public\_html folder we created a .htacess file with the following lines.

```
RewriteRule ^$ web/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ web/$1 [L]

```

We edited the .htaccess file in ~user/public\_html/web.

```
# Modify the RewriteBase if you are using Drupal in a subdirectory or in a
# VirtualDocumentRoot and the rewrite rules are not working properly.
# For example if your site is at http://example.com/drupal uncomment and
# modify the following line:
RewriteBase /web

```

In the ~/user/public\_html/web/sites/default/settings.php file, we added this code at the bottom.

```
if (isset($GLOBALS['request']) and
'/web/index.php' === $GLOBALS['request']->server->get('SCRIPT_NAME')) {
$GLOBALS['request']->server->set('SCRIPT_NAME', '/index.php');
}

```

We also changed `trusted_host_patterns` setting as well.

```
# will allow the site to run off of all variants of example.com and
# example.org, with all the sub-domains included.

$settings['trusted_host_patterns'] = array(
  '^DOMAIN.com$',
  '^.+.DOMAIN.com$',
  '^DOMAIN.com/web$',
  '^.+.DOMAIN.com/web$',
);

```

As I said, this is most likely not the correct way to do it, but it worked for us.

# Answer
> 1 votes
We're currently in a similar boat. We have dedicated hosting, and we're looking to start development of Drupal 8 sites with composers as a way to manage sites.

We took a different approach, we created a directory and adding therein the core, modules, and theme files. Then made a symlink between those files and the public\_html folder. It seems to work fine, but, like you, I am not sure what the best practices.

FYI: Here's how we created the symlink:

1. mv public\_html examplesite
2. ln -s public\_html examplesite/webfiles

That seemed to make it work for us.

Edit: I just ran across an article immediately after writing this. It says moving the files out of docroot adds additional security to your site. So, what we did, with the symlink, might be considered the better option.

https://www.drupal.org/node/2767907

# Answer
> 0 votes
Suppose you're in `mysite.com/public` and you want the `index.php` or drupal root should come directly under `mysite.com/public` then do this:

Then execute:

```
create-project drupal-composer/drupal-project:8.x-dev my_site_name_dir --stability dev --no-interaction --no-install

```

now go to `my_site_name_dir` and move everything including `*` and `.*` to under `mysite.com`

Then open `composer.json` under `mysite.com` and then replace "**web**" occurrences to "`public`" in `installer-paths`.

Now run `composer install` within `mysite.com`. It will work.

# Answer
> -1 votes
Everywhere I check the answer to this question of the 'web/' folder is always to reconfigure server and write rewrites, but I have a very simple way I solve this issue.

During initiating a new Drupal project, I would make what is called a 'modified install'. I would stop the project initiation half way to tell Composer what my web-root is. By default Composer assumes my web-root to be 'web/' but making a modified install allows me to tell Composer where it is. If on shared hosting it would be 'public\_html' and could be called anything in some other situation. So when I pause the installation process, I would tell Composer, 'hey don't go ahead to install Drupal in 'web', install it 'here' instead' and 'here' could even be a nested folder several steps away from pwd. When I tell Composer this, I then resume the installation process and finally Drupal would be installed wherever I told Composer.

I wrote the steps to do this in a blog post, How to install Drupal 9 with Composer on Cpanel. This post is about installing on a cPanel account but the process demonstrates making a modified install, and same principle can be used to install locally or in any folder structure.

---
Tags: 8, installation, composer
---


# Question
Title: Is there a way to redirect any 404 to the homepage?
I understand that Drupal doesn't have a core module to handle redirects and that's *normally* done by the Redirect module, or from the webserver.

But if I want to redirect **any** 404 to the homepage, due to say, a very content-varied site in which it's unlikely to find articles on the same topic, can this be done with Drupal core without editing webserver file?

# Answer
Under **Admin -\> Config -\> Basic site settings**, you can set the **Default 404 (not found) page**.

URL path: `/admin/config/system/site-information`
> 3 votes

---
Tags: redirection
---


# Question
Title: How do I capture bank account name, number, branch code, etc. in checkout for offline processing?
The Commerce Bank Transfer module claims this is part of Commerce 2.x, but I am not sure how to accomplish it. Any suggestions would be appreciated.

# Answer
> 0 votes
This is called "creating a manual payment gateway" in Commerce 2.

Unfortunately, the docs page is blank.

So, here's how I set up bank transfer payment collection for Japan.

1. Create a new payment gateway at `/admin/commerce/config/payment-gateways/add`.
2. Set the **Plugin** to **Manual**.
3. Fill in the rest of the info as needed for your setup.
4. Continue to configure your store in Commerce, and use the manual payment gateway (with any other payment gateways you require-- for example, I give users the option of bank transfer or credit card via Stripe).

---
Tags: 8, commerce, payment-gateways
---


title: How to implement a social media feed

text:
# Question
Title: How to implement a social media feed
I am creating a social media app and basically need a page that is a form with fields for the users to fill out and add a new post to their feed (form connects to the feed).

More detail: The form should be able to have an added entity reference to taxonomy terms, allowing users to upload text, image and video, and then select a taxonomy term for the above post to be posted to, basically categorizing posts. For example, a taxonomy term “Covid-19” exists (acting like a category) and a user wants to add a post (text, image, video, likes, comments) specifically about Covid-19. When filling out the form the user selects “covid-19” and submit post, now any user is able to find that new post under the “covid-19” category/taxonomy term.

My setup:

* Drupal 9 with Open Social (distribution)
* MAMP stack (LAMP on Mac) with DDEV

I’m still pretty new to Drupal so I apologize but here’s what I’ve tried so far:

* Setup taxonomy terms/ categories
* Created home page with a posts feed and added a filter on the page’s view to filter by taxonomy terms
* Created post page (as a dynamic page content type) with a single field that’s a reference to the taxonomy terms

What I thought would’ve worked:

* Adding fields to the content type but I couldn’t find any sort of form field (and the media field isn’t letting me add media/ what I’m calling a post)
* Adding fields to the pages view, but I got the same result

At this point I believe I just need to add those fields if I’m not wrong.

* How can I add/connect the form?
* And is the “media” field not the solution I need for what I’m calling a post (username, text, image, video, likes and comments)?
* If media is the solution but without the upload/ add video option, would the solution for adding video (or forms) be in another module? Or is the full solution already a module? (Keep in mind I’m already on the Open Social distribution if applicable)

Sorry again for the beginner question, I tried being as helpful as I could. Any help at all is GREATLY appreciated, thank you to anyone who reads this!

# Answer
> 0 votes
If you want to create a way for users to post content and organize that content by taxonomy terms, a content type is the way to go.

You don't attach a form to a content type; in Drupal, the content type IS the form.

Since you've already created the content type and added a taxonomy reference field for tags/categories, you can add the other fields.

Make sure you're adding the fields under `Admin -> Structure -> Content Types -> My Content Type -> Manage Fields`.

You said you want to add a username, text, image, video, likes and comments.

* Username: You don't need a field for this because Drupal already has the username because the user is logged in to post. (Unless you allow anonymous users to post, but I'll keep this short.)
* Text: You can add a standard textarea (Text (plain, long)).
* Image: There are several ways to do this, but in your case, to attach images to posts, I would tentatively recommend adding an Image reference. You should research this.
* Video: This can be a media reference to a video field. You'll need to make sure you have media enabled for video.
* Likes: Not sure how you would implement this; it's certainly possible but it's not supported in Drupal out of the box.
* Comments: Enable comments module and read the docs on how to set it up for your content type. But, Drupals comments are a little neglected and primitive compared to a lot of social media, so if you expect heavy commenting, you might look at a third-party solution too.

As you may have guessed, the scope of your question is way too broad for this site, so I couldn't give too many specific details, but hopefully these pointers show you the way to go about this.

---
Tags: entities, forms, feeds, social-network
---


title: Change default user tab

text:
# Question
Title: Change default user tab
After logging in, users would be redirected to their user profile page. I have added a new tab, *My dashboard* using `hook_menu()`. Everything functions well.

After the users log in, I would like they are redirected to *My dashboard*, but I can't make it work.

I tried with in two ways, which both have the same problem.

First I tried with this code.

```
function mymodule_menu() {
  $items['user/%user/dashboard'] = array(
    'title' => t('My dashboard'),
    'page callback' => 'mymodule_dashboard',
    'page arguments' => array(1),
    'access callback' => TRUE,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -20,
  );

  return $items;
}

function mymenu_menu_alter(&$items) {
  $items['user/%user/view'] = array(
    'type' => MENU_LOCAL_TASK,
  );

  return $items;
}

```

Then, I tried with the following code.

```
function mymodule_menu_alter(&$items) {
  $items['user/%user/dashboard'] = array(
    'title' => t('My dashboard'),
    'page callback' => 'mymodule_dashboard',
    'page arguments' => array(1),
    'access callback' => TRUE,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -20,
  );

  $items['user/%user/view'] = array(
    'type' => MENU_LOCAL_TASK,
  );

  return $items;
}

```

I also cleared the cache.

The problem is that after login, the *View* tab disappears as tab, "My Dashboard" is the active tab, but it has the content of the previous *View* tab.

>

The URL after the login is https://example.com/users/myusername1, which isn't the dashboard URL. When I click between the tabs, the *My dashboard* keeps this wrong URL and displays the content of the \*View tab.

I tried a few variations between `hook_menu()` and `hook_menu_alter()`, but I can't make it work.

How can I have *My dashboard* and its own content displayed as the default tab after login?

# Answer
You need a combination of hook\_user\_login() (called after the user logs in) and drupal\_goto() (redirects the user). I haven't worked with D7 for a few years, but going off memory you should be able to do something like this:

```
function hook_user_login(&$edit, $account) {
  drupal_goto('user/' . $account['id'] . '/dashboard');
  drupal_exit();
}

```
> 0 votes

# Answer
Changing the default tab shown for a page isn't the way to redirect users after they log in. It also works only when users are redirected to their user profile page after they log in. If they are redirected to a different page, altering the default tab for the /user/%user page won't achieve what you are trying to achieve.

To redirect users after they entered their credentials in the login form (whenever it's shown on the login page or in the login block) is to:

* Add a form submission handler to the login form
* In that submission handler, redirect users to the desired URL

```
function mymodule_form_user_login_alter(&$form, &$form_state) {
  $form['#submit'][] = 'mymodule_user_login_submit';
}

function mymodule_user_login_submit($form, &$form_state) {
  if (!empty($form_state['uid'])) {
    // The user was successfully logged in.
    // $form_state['uid'] is set by user_login_authenticate_validate() when the login credentials are correct.
    $form_state['redirect'] = "user/{$form_state['uid']}/dashboard";
  }
}

```

Since `hook_user_login()` implementations are invoked from `user_login_finalize()`, they aren't only invoked after users log in from the user interface; for example, they are invoked after a user followed the link to reset their password, which makes Drupal run `user_pass_reset()`, the function that contains the following code.

```
if ($action == 'login') {
  $user = $account;
  user_login_finalize();
  flood_clear_event('pass_reset_user', $account->uid);
  watchdog('user', 'User %name used one-time login link at time %timestamp.', array(
    '%name' => $account->name,
    '%timestamp' => $timestamp,
  ));
  drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
  $token = drupal_random_key();
  $_SESSION['pass_reset_' . $user->uid] = $token;
  drupal_goto('user/' . $user->uid . '/edit', array(
    'query' => array(
      'pass-reset-token' => $token,
    ),
  ));

```

Calling `drupal_goto()` inside `hook_user_login()` interferes with that and other cases, and it doesn't allow Drupal to invoke all the `hook_user_login()` implementations.

A `hook_user_login()` implementation could set `$edit['redirect']` to redirect the users.

```
function mymodule_user_login(&$edit, $account) {
  if (is_array($edit)) {
    $edit['redirect'] = "user/{$account->uid}/dashboard";
  }
}

```

`drupal_goto()`, called from `drupal_process_form()` (via `drupal_redirect_form()`) when a form is submitted without errors, uses the value of `$_GET['destination']` when its value is not an external URL. To be sure users are redirect to the desired path, the implementation could be similar to the following one.

```
function mymodule_user_login(&$edit, $account) {
  if (strpos(current_path(), 'user/reset/') !== 0) {
    // Avoid redirecting users who reset their password.
    $_GET['destination'] = "user/{$account->uid}/dashboard";
  }
}

```

The code should also check it's not redirecting users in cases it should not, and verify it doesn't cause issues with other installed modules, for example the Two-factor Authentication (TFA) module. For this reason, I would avoid setting `$_GET['destination']` and use one of the other solutions I described in this answer.

As for https://example.com/users/myusername1 appearing as URL, that is using a path alias. Modules that implement `hook_menu()` don't need to worry about path aliases, as Drupal uses the path alias to find the page to show and calls the page callback associated to that page.

If then you need to change the default tab shown on user/%user, for different reasons, I would use code similar to the following one.

```
function mymodule_menu_alter(&$items) {
  if (isset($items['user/%user'])) {
    $items['user/%user/view'] = array(
      'title' => 'View',
      'type' => MENU_LOCAL_TASK,
      'weight' => -10,
      'page callback' => 'user_view_page',
      'page arguments' => array(1),
      'access callback' => 'user_view_access',
      'access arguments' => array(1),
    );

    $items['user/%user'] = array(
      'title' => 'My account',
      'title callback' => 'user_page_title',
      'title arguments' => array(1),
      'page callback' => 'mymodule_dashboard',
      'page arguments' => array(1),
      'access callback' => 'user_view_access',
      'access arguments' => array(1),
      'menu_name' => 'navigation',
    );

    $items['user/%user/dashboard'] = array(
      'title' => 'My dashboard',
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -20,
    );
  }
}

```

The reason why `$items['user/%user/dashboard']` contains few items is that a `MENU_DEFAULT_LOCAL_TASK` menu item inherit page callback, page arguments, access callback, and access arguments from its parent menu item, in this case `$items['user/%user']`.
This is described in the `hook_menu()` documentation, and it's also the reason the following menu items, taken from Drupal core code, are defined in that way.

```
  $items['node/%node'] = array(
    'title callback' => 'node_page_title',
    'title arguments' => array(1),
    'page callback' => 'node_page_view',
    'page arguments' => array(1),
    'access callback' => 'node_access',
    'access arguments' => array('view', 1),
  );

  $items['node/%node/view'] = array(
    'title' => 'View',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );

```

```
  $items['admin/config/search/path'] = array(
    'title' => 'URL aliases',
    'description' => "Change your site's URL paths by aliasing them.",
    'page callback' => 'path_admin_overview',
    'access arguments' => array('administer url aliases'),
    'weight' => -5,
    'file' => 'path.admin.inc',
  );

  $items['admin/config/search/path/list'] = array(
    'title' => 'List',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );

```

```
  $items['admin'] = array(
    'title' => 'Administration',
    'access arguments' => array('access administration pages'),
    'page callback' => 'system_admin_menu_block_page',
    'weight' => 9,
    'menu_name' => 'management',
    'file' => 'system.admin.inc',
  );

  $items['admin/tasks'] = array(
    'title' => 'Tasks',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -20,
  );

```
> 0 votes

---
Tags: 7, hooks, navigation
---


# Question
Title: Devel Generate keeps generating files after uninstalling it
Some time ago I removed Devel from my site because it is in production now. However, when I look at the Content list I still see files being generated, like generateImage\_J4d7CV.png and nq3cv2oMx9.txt

I tried to reinstall and deinstall Devel from scratch, that didn't solve it. A Google search on the issue rendered no solution either.

What could I do to prevent further generation of useless files?

Edit: I noticed that files are being generated when the layout is saved of a content type.

# Answer
> 0 votes
After your edit this is not Devel then, this is the Layout Builder using sample content for the preview. These are marked as temporary and should be deleted by cron after the time configured here:

```
/admin/config/media/file-system

```

---
Tags: debugging
---


# Question
Title: How to get a rendered views field value programmatically?
Yes, I see there are many answers already posted here and elsewhere for this; but sadly they are all wrong. These answers include any of the following:

```
$view->style_plugin->getFieldValue($rid, 'field_myfield');

foreach ($view->result as $rid => $row) {
 foreach ($view->field as $fid => $field ) {
   $values[$rid][$fid . '-value'] = $field->getValue($row);
   $values[$rid][$fid . '-render'] = $field->render($row);
 }
}

$views->_entity->...

```

or a few others. These are all returning the field of the base entity returned by the view. These are entity field values. These are not the "fields of the view".

I know how to access these in a twig template (views-view-fields--\[viewname\]--\[displayname\].html.twig) but haven't been able to find out how to do this in a custom module.

## Answer:

From @4k4's tip below:

This works:

```
foreach ($view->result as $rid => $row) {
  $type[$row->nid] = $view->field['my_views_field']->advancedRender($row)->__toString();
}

```

# Answer
> 1 votes
From @4k4's answer above:

```
foreach ($view->result as $rid => $row) {
  $type[$row->nid] = $view->field['my_views_field']->advancedRender($row)->__toString();
}

```

---
Tags: 8, views
---


# Question
Title: How to make a checkbox read-only/disabled from list of user entity references
In my Content type, I add a field **Reference: User** with unlimited values, Reference method from a view of user managers, and widget checkboxes.

Basically when a user manager edit the node, he can only check the box with his own name. The other checkboxes are set to disabled. The node will be published if all managers check the box.

I've tried creating form\_alter function like below

```
function mymodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    if ($form_id === 'node_request_order_edit_form') {

        $field_approved_by = $form['field_approved_by']['widget']['#options'];

        foreach($field_approved_by as $key=>$val) {
            if($key != \Drupal::currentUser()->id()) {
                $form['field_approved_by']['widget']['#options'][$key]['#disabled'] = true;
            }
        }
    }
}

```

But I got error

```
Error: Cannot use object of type Drupal\Core\Field\FieldFilteredMarkup as array...

```

If I remove the checkboxes using unset,

```
    ...
    if($key != \Drupal::currentUser()->id()) {
        unset($form['field_approved_by']['widget']['#options'][$key]);
    }
    ...

```

The value get overwritten when different manager checks the box and save the node.

Thanks for any help.

**UPDATE 1:**

So, I kind of solve it by using JavaScript to disable these checkboxes. Here are the reference tutorials:

But I don't know whether the performance/stability is better or worse than the provided solution from the answers.

Basically I create a JS library file: spo\_core.libraries.yml

```
request_order_edit:
  js:
    js/request_order_edit.js: {}
  dependencies:
    - core/jquery
    - core/jquery.once
    - core/drupal
    - core/drupalSettings

```

Then in JS folder, create file: request\_order\_edit.js

```
(function ($) {
  'use strict';
  Drupal.behaviors.addLayer = {
    attach: function (context, settings) {
        console.log(drupalSettings.spo_core.current_uid);
        $('#edit-field-approved-by input:checkbox').each(function(){
            if(this.value != drupalSettings.spo_core.current_uid){
                this.disabled = true;
            }
        });

        /*enable the checkbox before submitting so the disabled checkbox can post value*/
        $("form#node-request-order-edit-form").submit(function() {
        $('#edit-field-approved-by.form-checkboxes input:checkbox').removeAttr("disabled");
    });
    }
  }
})(jQuery);

```

Then attach it in form alter like this

```
...
$form['#attached']['library'][] = 'spo_core/request_order_edit';
$form['#attached']['drupalSettings']['spo_core']['current_uid'] = \Drupal::currentUser()->id();
...

```

# Answer
> 4 votes
As far as I know, Drupal core does not provide this functionality out of the box - there's no way to add attributes to an element's individual options.

However, one way I've done this is with the help of the Form Options Attributes module.

> \[The Form Options Attributes\] module adds the ability to specify attributes for individual options on Drupal Form API elements of the types: select, checkboxes, and radios.

It's pretty easy to use. From the project page:

> To add attributes to a form element's options, add an #options\_attributes key to the form element definition. The #options\_attributes value should be an array with keys that match the keys in the #options value array. The values in the #options\_attributes array should be formatted like the main #attributes array.

For example:

```
$form['my_field'] = [
  '#options' => [
    '1' => 'User 1',
    '123' => 'User 123',
    '456' => 'User 456',
  ]
  '#options_attributes' => [
    // Disable this option.
    '1' => [
      'disabled' => 'disabled',
    ],
    // Allow this option.
    '123' => [],
    // Disable this option.
    '456' => [
      'disabled' => 'disabled',
    ],
  ],
];

```

Or see the module's README for more complete examples.

# Answer
> 2 votes
Do this:

```
function mymodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    if ($form_id === 'node_request_order_edit_form') {

        $field_approved_by = $form['field_approved_by']['widget']['#options'];

        foreach($field_approved_by as $key=>$val) {
            if($key != \Drupal::currentUser()->id()) {
                $form['field_approved_by']['widget'][$key]['#disabled'] = true;
            }
        }
    }
}

```

The key is that when you specify the attributes of the options, you work with the child element of 'widget', not of '#options'.

---
Tags: forms, hooks
---


title: Default product URL for a pager

text:
# Question
Title: Default product URL for a pager
Does anyone know how to get around the view error about the default product that doesn't have a URL?

The Commerce module has a default product and the view pager works without a *More* link, but it errors out with one.

# Answer
There is no way to do it it turns out. The workaround is to use the Products format as a Field instead of Rendered Entity and select the "link to this" feature and set the number of items to display to "zero" - nothing leave blank . . . and change Teaser to default and that will allow the pager to use next controls or a list at the bottom
> 0 votes

---
Tags: views, commerce, blocks
---


# Question
Title: How do I add the <noscript> tag in <head>?
If I want to add JavaScript in the head tag, I use `drupal_add_js($js, 'inline')`. This will add a `<script type="text/javascript">`.

How do I add the `<noscript>` tag? I want to add the following in `<head>` also.

```
<noscript>
  <meta http-equiv="refresh" content="5;url=<?php echo $file ?>" />
</noscript>

```

BTW, I'm using a simple module for this.

```
function custom_download_menu() {
    $items['download-code'] = array(
    'title callback' => 'custom_download_page_title',
    'page callback' => 'custom_download_view',
    'access arguments' => array('access content'),
    'access callback' => TRUE,
    );
    return $items;
  }

function custom_download_view() {
    $js = "var time_left = 5;
        var cinterval;

        function time_dec(){
            if(time_left > 0) time_left--;
            document.getElementById('countdown').innerHTML = 'Your download will start in ' + time_left + ' seconds...';
            if(time_left < 1){
                clearInterval(cinterval);
                window.location = '<?php echo $file ?>';
            }
        }

        cinterval = setInterval('time_dec()', 1000);";

    drupal_add_js($js, 'inline');
}

```

# Answer
> 10 votes
You can add elements to the `<head>` section of a web page using `drupal_add_html_head()`.

```
$target = url('enable-javascript', array('absolute' => TRUE));
$meta = array(
  '#theme' => 'html_tag',
  '#tag' => 'meta',
  '#attributes' => array(
    'http-equiv' => 'refresh',
    'content' => "2; url=$target"
  )
);
$noscript = array(
  '#theme' => 'html_tag',
  '#tag' => 'noscript',
  '#value' => drupal_render($meta)
);
drupal_add_html_head($noscript, 'noscript');

```

API Documentation

# Answer
> 0 votes
You can use this Noscript Tag contributed module.

URL: https://www.drupal.org/project/noscript\_tag

# Answer
> 0 votes
I was able to accomplish similar solution in Drupal 9 with this:

```
function my_custom_module_page_attachments(array &$attachments) {
$nid=20;
$alias = \Drupal::service('path_alias.manager')->getAliasByPath('/node/'.$nid);
 $noscript = [
  '#noscript' => TRUE,
  '#tag' => 'meta',
  '#attributes' => [
    'http-equiv' => 'refresh',
    'content' => "0; URL=/big_pipe/no-js?destination=$alias",
   ],
];

    $attachments['#attached']['html_head'][] = [$noscript, 'noscript'];

      return $attachments;
}

```

Hope this help someone in future

---
Tags: 7
---


# Question
Title: Render Submitted Fields of a Form to Email with Title + Value
I have a quite complex form based on `\Drupal\Core\Form\FormBase` with many (partially nested) fields and want to send the full contents in an email on submit.

Currently I have

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

   foreach ($form_state->getValues() as $key => $value) {
     if (!empty($form[$key]['#title']) && $key != 'images') {
       $values[$form[$key]['#title']->render()] = $value;
     }
   }
...
# later I will format the $values array as a HTML list

```

This would only show fields on the top-level of the form, but I have fields within groups.

Is there a nice and clean way to render all the field's values? Or do I have to iterate and parse manually over the `$form` array?

Could I even use a renderer for this?

EDIT:

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

    // ...

    $form['company'] = [
        '#type' => 'container',
    ];

    $form['company']['nameofcompany'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Name of Company'),
    ];

```

To sum it up:

How can I iterate over all the fields, including those which are in containers and get the values + the label (not only the technical name)? Are there some nice helpers for this or do I have to do it all manually?

# Answer
This is what I came up with, I am just wondering if there is a more elegant way, than this "low-level" parsing

```
/**
 * Return an array with labels as keys, submitted values as values, based on the original form
 *
 * @param FormStateInterface $form_state
 * @return array
 */
private function generateLabelsWithValues(FormStateInterface $form_state): array {
  $form = $form_state->getCompleteForm();
  $result = $this->iterateAndAddValues($form, $form_state);
  return $result;
}

/**
 * Iterate over form or container and add up the values
 */
private function iterateAndAddValues(array $formOrContainer, FormStateInterface $form_state, array $result = []) {
  foreach ($formOrContainer as $key => $element) {
    if ($key[0] === '#' || $key === 'form_build_id' || $key === 'form_id' || $key === 'submit') {
      continue;
    }
    if ($element['#type'] === 'container' || $element['#type'] === 'fieldset') {
      $result = $this->iterateAndAddValues($element, $form_state, $result);
      continue;
    }

    if ($value = $form_state->getValue($key)) {
      $result[(string)$element['#title']] = $value;
    }
  }

  return $result;
}

```
> 0 votes

---
Tags: 8, forms
---


# Question
Title: Any Context PHP Condition Plugin going forward
The context module relies on the now deprecated php filter module for the PHP conditions. Basically, if you want to write a context with condition based on PHP, you must install php filter.

Since php filter is now deprecated, is there any module replacing that?

# Answer
> 3 votes
I think the replacement is not another contrib module but extending the Context module itself with your own PHP code in a custom module.

The PHP Filter was removed from Drupal core to make it harder to make careless PHP mistakes that cause security issues with sites. This won't be replaced with another module because it's a bad idea.

So if you need to add custom PHP code, it should be written in your own custom module (extending the classes/plugins provided by Context).

# Answer
> 3 votes
The deprecated module you are mentioning simply implements a core condition plugin. You can use this as example and put your own PHP in the evaluate() method: https://git.drupalcode.org/project/php/-/blob/8.x-1.x/src/Plugin/Condition/Php.php

Or add the condition plugin to a custom module with Drush

```
drush generate plugin-condition

```

and you get a self-explanatory example working out-of-the-box.

---
Tags: 9
---


# Question
Title: entity_generate process plugin issue with node generation
I want to use use entity\_generate plugin to create a node for each row of source I'm migrating. I'm getting 'title' source field and want to create a node in some my\_content\_type, with that title. My migration looks like:

```
  # Field to populate
  my_content_type:

    plugin: entity_generate
    source: title
    entity_type: node
    bundle: my_content_type
    value_key: title
    bundle_key: nid
    values:
      title: title

```

So, I don't have field referencing that node I'm creating - I just want node to be created as a "side effect". But when I run migration I get the error:

**In ContentEntityStorageBase.php line 125:<br>Missing bundle for entity type node**

I basically tried to adjust example for tags from here: https://www.drupal.org/docs/8/api/migrate-api/migrate-process-plugins/contrib-process-plugin-entity\_generate

..but something isn't right there. Why it's complaining about missing "bundle" parameter, when I provided it?

# Answer
> 2 votes
Got help from @danflanagan8 on drupal slack channel. So, annotation for tags looks like:

```
*   entity_keys = {
*     "id" = "tid",
*     "revision" = "revision_id",
*     "bundle" = "vid",
*     "label" = "name",
*     "langcode" = "langcode",
*     "uuid" = "uuid",
*     "published" = "status",
*   },

```

and for nodes it's like this:

```
*   entity_keys = {
*     "id" = "nid",
*     "revision" = "vid",
*     "bundle" = "type",
*     "label" = "title",
*     "langcode" = "langcode",
*     "uuid" = "uuid",
*     "status" = "status",
*     "published" = "status",
*     "uid" = "uid",
*     "owner" = "uid",
*   },

```

So bundle for taxonomy terms is "vid" and for nodes is "type". In example migration file for taxonomy term **bundle\_key** field has value "**vid**" and by following that logic for node **bundle\_key** should have value "**type**".

---
Tags: migrations
---


# Question
Title: How can I load the transitions for a particular workflow?
I want to load the transition objects for a Workflow. In Drupal 8, I see a Workflow::getTransitions() method, however it seems this method was removed in Drupal 9.

# Answer
The easiest way to do this is through the workflow's type plugin, specifically the getTransitions() method.

```
// First load a workflow, for example:
$workflow = \Drupal::service('content_moderation.moderation_information')
  ->getWorkflowForEntity($entity);

// Then get the workflow's type plugin.
/** @var \Drupal\workflows\WorkflowTypeInterface $workflow_type_plugin */
$workflow_type_plugin = $workflow->getTypePlugin();

// Finally, load the transitions.
$workflow_transitions = $workflow_type_plugin->getTransitions();

```

Alternatively, it may be more useful to only get the valid transitions for an entity, i.e. only transitions allowed for the entity from its current state, for the current user. The getValidTransitions() method from the content\_moderation.state\_transition\_validation service does this.

```
/** @var \Drupal\content_moderation\StateTransitionValidationInterface $transition_validation */
$transition_validation = \Drupal::service('content_moderation.state_transition_validation');
$valid_transitions = $transition_validation
  ->getValidTransitions($entity, \Drupal::currentUser());

```
> 1 votes

---
Tags: 9, workflows
---


# Question
Title: Advagg with S3fs relative url() references inside of CSS files - broken image URL
**Background Images Paths are Changed when CSS Aggregation is On**

s3fs module with AdvAgg to store CSS/JS aggregates on the S3 stream wrapper

Without Aggregation (Works well). fetch from domain base url.

```
background-image: url(/themes/THEME/images/test.jpg);

```

Src of the image in CSS, which is pointing to the CNAME for S3

With Aggregation isn't working. Because, my CNAME is different from my DOMAIN name.

```
background-image: url(http://CNAME_DOMAIN/themes/THEME/images/test.jpg);

```

I disabled it all OBSCURE options(admin/config/development/performance/advagg). But No luck.

Everytime, the CSS file content url() fetching from the CNAME url.

# Answer
I found the same issue and it was the absolute path that broke things https://www.drupal.org/project/s3fs/issues/3241554

Had a very similar structure:

`background-image: url(/themes/THEME/images/test.jpg);`

Convert this to:

`background-image: url(/../images/test.jpg);`

(Or whatever relative path that makes sense) and it should work (thanks to @cmlara for the pointer!)
> 0 votes

---
Tags: 8, theming, css-js-aggregation
---


# Question
Title: Inline entity form complex widget not saving child entities
I'm using inline entity form on a node edit form. The target is a custom entity.

There are two possible form widgets to use: Simple or Complex.

With Simple (example) the child entity fields are just embedded in the parent form. It's not possible to collapse the child fields, nor is it possible to delete child entities, but it does save the child entities upon submitting the entire node edit form.

With Complex (example) the child entities fields are collapsible and the child entities can be deleted. However the child entity is only saved if the section of the form is not collapsed when the node edit form is submitted. Is this a bug?

I've discovered that using `hook_inline_entity_form_entity_form_alter` I can add a callback to the `$form['#entity_builders']` array that is called when the child entity sub form is collapsed (and is meant to be saved).

In this callback I've added some super generic code to just save the child entity.

E.g.

```
function save_ief_child_entity($entity_type, $entity, $entity_form, $form_state) {

  $delta = $entity_form['#ief_row_delta'];
  $field_name = $entity_form['#parents'][0];
  $values = $form_state->getValue($field_name);

  // The location of the entity values changes depending on if it's a new save
  // or an update.
  if(isset($values['form']['inline_entity_form']['entities'][$delta]['form'])) {
    $values = $values['form']['inline_entity_form']['entities'][$delta]['form'];
  }
  else {
    $values =& $values['form']['inline_entity_form'];
  }

  if(empty($values)) {
    return;
  }

  // Loop form values to update entity
  foreach($values as $key => $value) {

    // Images are in the wrong format for some reason - fix it.
    foreach($value as &$part) {
      if(is_array($part) && isset($part['fids'])) {
        $part['target_id'] = $part['fids'][0];
      }
    }

    $entity->{$key} = $value;

  }

  $entity->save();

  // IEF takes care of creating the relationship between parent and child when the main form is submitted
}

```

---

**Why do I have to do this / why doesn't IEF do this itself internally?**

# Answer
If anyone would stumble on the issue of saving child nodes (entity) at inline entity form (ief) - newly added/created node not saved, here is a quickfix for that (D8/9):

```
function MODULENAME_inline_entity_form_entity_form_alter(&$entity_form, FormStateInterface $form_state) {
    $entity_form['#save_entity'] = true;
}

```
> 1 votes

---
Tags: 8, forms, entities
---


# Question
Title: What is the token for an original image URL?
The is the token to get the url for a "large" image style:

```
[node:field_image:large:url]

```

What is the token that will give me the original file URL for the image? That is, not an image style preset, but the original image.

I have tried the following:

```
[node:field_image]
[node:field_image:url]
[node:field_image:default:url]
[node:field_image:original:url]
[node:field_image:none:url]

```

None of these work. I am trying to use the token in a field in the metatag config at admin/config/search/metatag/global. The help text for the field assumes we want to use an image style.

# Answer
Try this, this works for me:

```
[node:field_image:0:entity:url]

```
> 0 votes

---
Tags: 8, tokens, media
---


# Question
Title: how throw a custom exception in JSONAPI?
In D8 i'm trying to throw custom exceptions for extra validations that i need to do before the content is saved in my custom entity, but when i do the validations in the presave method and throw a normal Exception:

```
public function preSave(EntityStorageInterface $storage) {
  throw new \Exception("The content is duplicated", 409);
}

```

The response of JSONAPI is code 500 Internal Server Error and the response:

```
{
"jsonapi": {
    "version": "1.0",
    "meta": {
        "links": {
            "self": {
                "href": "http://jsonapi.org/format/1.0/"
            }
        }
    }
},
"errors": [
    {
        "title": "Internal Server Error",
        "status": "500",
        "detail": "The content is duplicated",
        "links": {
            "via": {
                "href": "http://site.docksal/jsonapi/content_entity/content_entity"
            },
            "info": {
                "href": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1"
            }
        }
    }
]

```

}

how can i control de error Code, title, status and detail.

# Answer
thanks @4k4, I solved it using customs constraints in my custom entity, JSONAPI mapping well the error and the admin UI works perfectly with that.

like @kiamlaluno said, i try to explain the solution using constraints:

I want to response in the JSONAPI Request that the content is already exists but with a different code, no 500. So when i use constraints i can validate if content already exist or not and response if is a valid request (TRUE / FALSE), this constraints works in the JSONAPI Responses and in the Drupal Admin UI.

So you need to define the constraint in the folder "my\_module/src/Plugin/Validation/Constraint" and create 2 files, for my example i need that the content is unique. so my files are:

UniqueProfileContentConstraint.php

```
<?php

namespace Drupal\my_module\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * Plugin implementation of the 'unique_entry_constraint'.
 *
 * @Constraint(
 *   id = "unique_profile_content_constraint",
 *   label = @Translation("Unique entry constraint", context = "Validation"),
 * )
 */
class UniqueProfileContentConstraint extends Constraint
{

    // The message that will be shown if the value is not unique.
    public $notUnique = 'This content already exists';

}

```

And the validator:

UniqueProfileContentConstraintValidator.php

```
<?php

namespace Drupal\ztv_content\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * Validates the UniqueInteger constraint.
 */
class UniqueProfileContentConstraintValidator extends ConstraintValidator
{

    /**
     * {@inheritdoc}
     */
    public function validate($entity, Constraint $constraint) {
      // Next check if the value is unique.
      if (!$this->isUnique($entity)) {
          $this->context->addViolation($constraint->notUnique);
      }
    }

    private function isUnique($entity)
    {
      if ($entity->isNew()) {
        $query = \Drupal::entityQuery('profile_content_entity')
          ->condition('profile_id', $entity->get('profile_id')->getString())
          ->condition('video_id', $entity->get('video_id')->value);
        $storageContent = $query->execute();
        if ($storageContent) {
          return FALSE;
        }
        return TRUE;
      }
    }

}

```

And finally in the Entity annotation you need to add the id of your constraint:

```
 *   constraints = {
 *      "unique_profile_content_constraint" = {}
 *   }
 * )
 */

```
> 2 votes

# Answer
A more straightforward solution is throwing a `HttpException`:

```
throw new Symfony\Component\HttpKernel\Exception\HttpException(
  409,                           // response code
  'The content is duplicated'    // "detail" property in JSON response
);

```
> 0 votes

---
Tags: 8
---


# Question
Title: Add simple config object as a cacheable dependency?
I am building a custom breadcrumb that has some admin settings from a module in Drupal 9. When that settings form is saved, I want any breadcrumb cache that was built with this builder to be invalidated.

I tried passing my config object into the builder as such:

```
$breadcrumb->addCacheableDependency($this->config);

```

Only when I save the form, the breadcrumb serves the cached version until I clear it. Then it shows the right breadcrumb. My constructor has:

```
  public function __construct(
    AdminContext $admin_context,
    AliasManagerInterface $alias_manager,
    EntityTypeManagerInterface $entity_type_manager,
    ConfigFactoryInterface $config_factory
  ) {
    $this->adminContext = $admin_context;
    $this->aliasManager = $alias_manager;
    $this->entityTypeManager = $entity_type_manager;
    $this->config = $config_factory->get('mymodule.settings');
  }

```

# Answer
To answer the question. Yes, this is the correct way.

You can check whether the cache tag `config:*` is passed to the block variables:

```
function mymodule_preprocess_block__system_breadcrumb_block(&$variables) {
  var_dump($variables['content']['#cache']);
}

```

Then it can only be a problem with the template not rendering the entire content of the `content` variable.
> 0 votes

---
Tags: caching, 9, configuration
---


# Question
Title: Properly storing an array in a config object
In a config object, I want to store an array of values. The keys matter. The stored value is coming from a checkboxes element, so the array would look something like:

```
['article' => 'article', 'page' => 'page']

```

Here is the config schema:

```
mymodule.settings:
  type: config_entity
  label: 'Mymodule Breadcrumb Settings'
  mapping:
    node_bundles:
      type: mapping
      label: 'Bundle machine names.'

```

This appears to work on the surface, but running a functional test results in:

```
Schema errors for mymodule.settings with the following errors: mymodule.settings:node_bundles.page missing schema

```

which makes me add:

```
protected $strictConfigSchema = FALSE;

```

then the tests pass - but then Drupal coding standards error is triggered.

What is the proper schema definition that I need?

# Answer
This is a case for using a `sequence`. Unlike a mapping, keys are optional and don't need to be described by the schema.

From Configuration schema/metadata:

> sequence: Property on the value of the sequence type, used to define an arbitrary list of defined values. In a sequence, keys are optional and may be integers or strings and are not explicitly mapped. Only the types of values must be defined in the schema.

Further down in that same documentation, we see examples for Sequence Defintions. The second example, Defining a new schema, looks a lot like your case.

Schema definition:

```
domain.language_negotiation:
  type: config_object
  label: 'Domain language negotiation'
  mapping:
    domain_language:
      type: sequence
      label: 'Domains'
      sequence:
        type: string
        label: 'Langcode mapping'

```

Example configuration supported by the above schema definition:

```
domain_language:
  example_local: en
  one_example_local: af
  two_example_local: af
  three_example_local: en
  four_example_local: en

```

For your specific case, you can update your schema definition like:

```
mymodule.settings:
  type: config_entity
  label: 'Mymodule Breadcrumb Settings'
  mapping:
    node_bundles:
      # Change from mapping to sequence
      type: sequence
      label: 'Bundle machine names.'
      # NEW: describe your sequence values.
      sequence:
        type: string
        label: 'whatever you would call the "values" of your node_bundles array'

```
> 5 votes

---
Tags: 9, configuration
---


# Question
Title: Twig Template - Div Element Being Inserted in Link URL
I have a link field type that I'm referencing in a Twig template. I'm using this code:

```
<div class="outlined">
<a href="{{content.field_3_column_image_link}}">{{content.field_3_column_image}}</a>
</div>

```

...BUT when I hover over the link I am seeing `https://nameofsite/<div>/node/1</div>` instead of `https://nameofsite/node/1`.

Can someone help me figure out why this is happening? Where are these divs coming from?

Thanks! Bryan

# Answer
> 1 votes
See the comment from Patrick Kenny; the link he referred me to had the answer: I just had to use this insted: `{{content.field_3_column_image_link.0}}`.

Apparently the `.0` at the end of the filed type name strips out everything but the raw value.

---
Tags: theming
---


title: How to remove user role temporarily?

text:
# Question
Title: How to remove user role temporarily?
I need to disable the "administrator" role from user accounts who log into my website from outside my network. For security, I only want users who have this role to be able to use it when they are on my network (determined by some custom PHP code I have).

I know I can remove a role from a user permanently using the appropriate entity methods like this:

```
<?php
use Drupal\user\Entity\User;

$user = User::load(\Drupal::currentUser()->id());
$user->removeRole('administrator');
$user->save();

```

But what about to do so temporarily, without updating the user permanently?

Looking at changes made to a user's roles in a custom module using `hook_user_login()` are permanent. In Drupal 7, I was able to achieve this by modifying the global `$user->roles` in various hooks.

I am also open to other ways Drupal allows me to meet my needs.

# Answer
> 3 votes
Instead of a Drupal 7 hook you can use the new AccountEvents::SET\_USER event:

*/src/EventSubscriber/SetAccountSubscriber.php*

```
<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\Session\AccountEvents;
use Drupal\Core\Session\AccountSetEvent;
use Drupal\Core\Session\UserSession;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * mymodule event subscriber.
 */
class SetAccountSubscriber implements EventSubscriberInterface {

  /**
   * Account set event handler.
   *
   * @param Drupal\Core\Session\AccountSetEvent $event
   *   Account set event.
   */
  public function onAccountSet(AccountSetEvent $event) {
    $account = $event->getAccount();
    if ($account->isAuthenticated()) {
      $roles = $account->getRoles();
      if (in_array('administrator', $roles)) {
        $roles = array_values(array_diff($roles, ['administrator']));
        $account = new UserSession([
          'uid' => $account->id(),
          'access' => $account->getLastAccessedTime(),
          'roles' => $roles,
          'name' => $account->getAccountName(),
          'preferred_langcode' => $account->getPreferredLangcode(),
          'preferred_admin_langcode' => $account->getPreferredAdminLangcode(),
          'mail' => $account->getEmail(),
          'timezone' => $account->getTimeZone(),
        ]);
        \Drupal::currentUser()->setAccount($account);
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      AccountEvents::SET_USER => ['onAccountSet'],
    ];
  }

}

```

*mymodule.services.yml*

```
services:
  mymodule.set_account_subscriber:
    class: Drupal\mymodule\EventSubscriber\SetAccountSubscriber
    tags:
      - { name: event_subscriber }

```

Be careful to avoid an infinite loop. The last line dispatches the event again and you need a condition preventing the line to be executed a second time, in this case through the removed role.

---
Tags: users, 9
---


# Question
Title: How to get the url of a file field of a given node?
`$node->field_file` gives me a FileFieldItemList while the first entry seems to be a FileItem.

`$node->field_file->getValue()` gives me an integer (I guess the file id). How can I actually get the downloadable file uri from that?

# Answer
> 25 votes
```
// Load the file.
$file = \Drupal\file\Entity\File::load($fid);
// Get the URL.
$url = \Drupal::service('file_url_generator')
  ->generateAbsoluteString($file->getFileUri());

```

Before Drupal 10, there was a different way of doing it using `file_create_url()`.

```
$url = file_create_url($file->getFileUri());

```

# Answer
> 13 votes
As of 9.3.0 file\_create\_url is deprecated and it will be removed from 10.0.0 version. The new way to do it:

```
$file_uri = $node->field_file->entity->getFileUri();
\Drupal::service('file_url_generator')->generateString($file_uri);

```

This service has the following functions:
`generate()` `generateString()` `generateAbsoluteString()` `transformRelative()`

# Answer
> 7 votes
It is also possible to do one-liner with magic method:

`$node->field_file->entity->getFileUri();`

Or to render as string

Option 1: `$node->field_file->entity->url();`

Option 2: `file_create_url($node->field_file->entity->getFileUri());`

# Answer
> 5 votes
For Drupal 9.3.0+ users, as mentionned :

* `File:url()` is deprecated as of 8.7.x.
* `file_create_url()` is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0

`$file->createFileUrl()` looks to be the new simplest solution.

It uses the `'file_url_generator'` service mentionned by golddragon007.

You'll find details in the File.php core's file.

# Answer
> -1 votes
> to get the file intity

`$file = \Drupal\file\Entity\File::load($fid);`
> to get the file url

`$url = $file->url();`

---
Tags: 8, nodes, files
---


title: Twig template for specific node view

text:
# Question
Title: Twig template for specific node view
I have a views-view--resources-filter.html.twig file. Within here I have a better exposed filters form and I loop through the resources (node) with the available `{{ rows }}` variable. My question is, what is the naming convention to make a node view for an unformatted list where I use fields to show? So basically that it only styles the nodes within this view. I've been looking for a solution all day, but couldn't find anything really related to my issue.

# Answer
> 1 votes
It will be something like

`views-view-unformatted--my-view-name--my-display-name.html`

For more info, turn on twig debugging and look in the Views module template folder at `/core/modules/views/templates/`.

---
Tags: 9
---


# Question
Title: Is there a way to default sort by date when no search keywords have been used, but default sort by relevance for all searches?
At present, my project has default search pages for sections of the site. They are per-content type. When the user goes the "search page" for the content type, they see a views-generated search result page unfiltered by any keywords. In other words, it displays all the items for that content type. The view:

has expose form in a block enabled settings on the exposed form has 'input required' disabled

**What I want to happen...**

I'd like users to

* see the unfiltered search result page sorted by newest first. At present, this page, if set to relevance, shows old content first.
* automatically switch to relevance sorting when they enter keywords and execute a search. At present, I've set the first sort to date, to solve the 'old content first' problem, so users have to manually change the sort to relevance when doing a search.

**Some options...** I could separate the list pages from the search result pages. My question is, is there a way to make an unfiltered "search result" views page show the newest content first, while having the default sort actually set to relevance, so nobody has to manually change it? How does that sort really work when there aren't any keywords to supply "relevance"?

My config basics...

* Drupal 9.3.7
* search\_api
* facets
* search\_api\_solr

# Answer
I think I have one solution. I remain interested in knowing if there is a better way. Here's what seems to be working so far:

In the sort section of the view, I have these fields, in this order:

* Relevance (descending): exposed
* Date field (descending): exposed
* Date field (same one, descending): not exposed

After clearing caches (important), the result seems to be that navigating to the search result page without doing a search, lists all the content (as filtered) by 'Date field' descending, but the search form and its exposed sort indicates Relevance. When I key in terms and launch the search, it comes back relevance sorted.

I'm not sure why this is working though. On the views config page the query without keywords looks like this:

```
Index: main_index
Keys: NULL
Conditions:
  [
    status = 1
  AND
    type IN array (
          'resource' => 'resource',
        )
  ]
Sorting: search_api_relevance DESC, field_display_date DESC
Options: array (
    'search_api_view' => 'object (Drupal\\views\\ViewExecutable)',
    'search_api_base_path' => 'search/resources',
  )

```

I may learn more from the mysql query log, but I admit: I'm never sure I understand what I'm seeing there.
> 1 votes

---
Tags: views, search
---


# Question
Title: Get field value from multiple entities at once
I have a Drupal site using paragraphs in which one of the content types, let's call it a `Group`, can contain any number of paragraphs, and each of these paragraphs, let's call them `Members`, contains a reference to a user. I want to get all the `uid`s of users which are `Members` of a given `Group`.

I could accomplish this with a query of the database like

```
SELECT field_user_target_id
FROM paragraph__field_user
WHERE entity_id = (
    SELECT field_members_target_id
    FROM node__field_members
    WHERE entity_id = <GroupID>
    LIMIT 1
);

```

for a given `GroupID`, but I'm wondering if there's a way to do this efficiently without directly querying the database. One option would be something like

```
$group = \Drupal\node\Entity\Node::load($groupID);
$uids = [];
foreach ($group->field_members->referencedEntities() as $member) {
    $uids[] = $member->field_user->target_id;
}

```

but is there a way to do this without having to loop through the `Members`?

# Answer
The foreach loop is how I would do it, but to your point, a query will usually be the most efficient. This technically applies in any situation where you have an API layer in between. If you would rather craft a query you can do so, but generally is not required. When profiling you application, if this area becomes a bottleneck, that is when I would start considering doing something like that. Note that using the API handles things like revisions and all that other stuff.

See Drupal 8: how can I "eager load" Entities referenced via EntityReferenceFieldItemList field for further details. In that post they explain that using `referencedEntities()` loads those entities into memory, so it is not like these are individual hits on the database.
> 3 votes

---
Tags: entities, 9
---


title: How do I add the noscript tag?

text:
# Question
Title: How do I add the noscript tag?
I've a drupal 8 website, where in every page, I would like to add a noscript tag for every script tag. In drupal 8, in html.html.twig, I saw the scripts variable in missing. So how do I do that in Drupal 8?

# Answer
I wound up just putting the `<noscript>` tag into my `html.html.twig` template. There is a NoScript Tag module, but I didn't feel like adding a module to my site for this purpose.
> -1 votes

# Answer
You can do it in a custom module (MYMODULE.module):

```
use Drupal\Core\Render\Markup;

function MYMODULE_page_attachments(array &$page) {
  $fallback = '<link href="fallback.css" rel="stylesheet" />';
  $noscript = array(
    '#tag' => 'noscript',
    '#value' => Markup::create($fallback),
  );
  $page['#attached']['html_head'][] = [$noscript, 'mymodule'];
}

```
> 3 votes

# Answer
Depending where exactly you need the tag to be placed, there's also `hook_page_top` and `hook_page_bottom` to add markup either after the opening `<body>` tag or right before the `<footer>` tag (or wherever your theme has `{{ page_top }}` and `{{ page_bottom }}` placed exactly inside `html.html.twig`).

Here's a sample that adds some marketing tool's `<script>` and `<noscript>` tags right after the opening `<body>` tag.

```
/**
 * Implements hook_page_top().
 */
function MYMODULE_page_top(array &$page_top) {

  if (\Drupal::currentUser()->isAnonymous()) {

    $foobar_script = [
      '#type' => 'html_tag',
      '#tag' => 'script',
      '#attributes' => ['src' => 'https://example.com/js/example.js'],
    ];
    $page_top['foobar_script'] = $foobar_script;

    $foobar_noscript = [
      '#type' => 'html_tag',
      '#tag' => 'noscript',
      '#value' => Markup::create('<img alt="" src="https://example.com/foobar.png" style="display:none;" />'),
    ];
    $page_top['foobar_noscript'] = $foobar_noscript;
  }
}

```
> 0 votes

---
Tags: 8
---


# Question
Title: How do I make links from views to be opened in modal popups without adding custom rewrite?
I was trying to find if there is a way to avoid writing custom rewrite for links to open in modal popups from a view.

Here is what I am rewriting a custom field for doing this now.

```
<a href="url/{{ field_value }}" target="_blank" class="use-ajax" data-dialog-type="modal" data-dialog-options='{"width":"60%", "title":"Popup title"}'>View</a>

```

The problem with this approach is that this would require me to do it in multiple views with the same rewrite for each of the links that need to be opened in a popup.

Wanted to know if I can do this without the rewrite being added for every field.

# Answer
You could write a custom field formatter that applies this, and then set that in the view instead of the manual rewrite. Either way, you are going to have to apply something to all of those links, no way to avoid setting that up initially.
> 0 votes

---
Tags: views, modal-dialogs
---


title: Conditional form validation by role

text:
# Question
Title: Conditional form validation by role
I'm lost on how to do this. I need guest users to have the form fully validated (using the client side validation module) upon creation, but not validating for an authenticated user.

tldr;

> The customer (always a guest) will be able to place an order for pickup on a particular date, that date cannot be earlier than 5 days from "today". The customer must always obey the validation rules. Easy, these are set up and working.

> When a staff member (always an authenticated user) places a phone order for a customer, they need to be able to override that date, even to one less than 5 days out, skipping the validation.

> Similarly, when the staff member edits/updates the webform, they need to be able to do so when it's less than the 5 days. The current client side validation module prohibits anyone from editing the form in less than five days, unless I have the date hidden from them.

I'm struggling to find a process or module that will make this work. Any ideas?

# Answer
> 0 votes
The simplest thing is to apply the validation as you normally would, and then write a hook\_form\_alter() that does the following:

1. Determine if the current user is logged in, or has a particular role.
2. If logged in, remove the validation pieces from the form render array of that particular field.

---
Tags: webforms
---


# Question
Title: Should installing local Drush and Drupal via Composer on my personal computer be any different than on hosting platform?
Should installing local Drush and corresponding Drupal via Composer on a personal computer with Ubuntu-Apache-MySQL-PHP be any different than on a shared hosting platform?

Should I just do the following in **both** environments?

```
cd web_application_root
composer create-project drupal/recommended-project my_site_name_dir
# PHP MYADMIN GUI
# GUI install
composer require drupal/metatag

```

# Answer
**Short answer**

When installing drupal and drush with composer, you can do it the same way on a shared hosting platform as you do locally-- assuming the shared hosting platform gives you access to the same command-line tools that you have available locally.

**Long answer: Use version control**

Generally speaking, you want to use composer with git, and you will check in your `composer.json` and `composer.lock` files into the git repo. You would then clone that repo to your local environment + your shared hosting environment.

This way, although you have multiple copies of `composer.json` and `composer.lock`, they are all managed via the git repo, so it is much easier to sync changes between your local environment and the shared hosting server.
> 0 votes

---
Tags: installation
---


# Question
Title: $node->save() fails when run in post_update
I have a simple hook\_post\_update function which fails with the following error:

> \[notice\] Update started: ssc\_custom\_post\_update\_9001
>
> > \[error\] LogicException: Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy\_builder/#pre\_render instead. in Drupal\Core\Render\Renderer-\>doRender() (line 244 of E:\www\myssc\html\core\lib\Drupal\Core\Render\Renderer.php). \[error\] Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy\_builder/#pre\_render instead. \[error\] Update failed: ssc\_custom\_post\_update\_9001
>
> In ProcessBase.php line 171:
>
> Unable to decode output into JSON: Syntax error
>
> \[ERROR\] \[node\] \[2022-03-12T04:58:35\] LogicException: Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy\_builder/#pre\_re nder instead. in Drupal\Core\Render\Renderer-\>doRender() (line 244 of E:\www\myssc\html\core\lib\Drupal\C ore\Render\Renderer.php). | uid: 0 | request-uri: http://default/ | refer: | ip: 127.0.0.1 | link:
> { "0": { "ssc\_custom": { "9001": { "#abort": { "success": false, "query": "Drupal\Core\Entity\EntityStorageException: Ren der context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use re nderPlain()/renderRoot() or #lazy\_builder/#pre\_render instead. in Drupal\Core\Ent
> ity\Sql\SqlContentEntityStorage-\>save() (line 810 of E:\www\myssc\html\core\lib\Drupal\Core\Entity\Sql\SqlContentEntityStorage.php)." } } }, "#abort": \[ "ssc\_custom\_post\_update\_9001" \] }, "drush\_batch\_process\_finished": true }

I have stripped the code down to the bare minimum:

```
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\NodeInterface;

function ssc_custom_post_update_9001(&$sandbox) {
  /** @var \Drupal\node\NodeStorageInterface $node_storage */
  $node_storage = \Drupal::entityTypeManager()->getStorage('node');

  // How many entities to processed per batch.
  $limit = 5;

  $node_ids = $node_storage->getQuery()
    ->accessCheck(FALSE)
    ->condition('type', 'article')
    ->range(0, $limit)
    ->execute();
  // Load entities.
  $nodes = $node_storage->loadMultiple($node_ids);

  /** @var \Drupal\node\NodeInterface $node */
  foreach ($nodes as $node) {
    $node->setNewRevision();
    $node->save();
  }

  $sandbox['#finished'] = 1;

}

```

If I run the same code directly (not from drush updb) it runs fine. Running from the admin menu "Run updates"; it also fails (so it is not a drush issue).

Commenting out the $node-\>save() and the error does not occur.

# Answer
You can reproduce the error with Drush:

```
# drush php

>>> $build = ['#markup' => 'TEST'];
=> [
     "#markup" => "TEST",
   ]

>>> $rendered = \Drupal::service('renderer')->render($build);
LogicException with message 'Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy_builder/#pre_render instead.'

>>> $rendered = \Drupal::service('renderer')->renderPlain($build);
=> Drupal\Core\Render\Markup {#4668
     markup: "TEST",
   }

```

So as the error message says modules which hook into the node save process should use renderPlain() instead. They shouldn't assume nodes are always saved within a render context of a themed Drupal page.

Code example for rendering a view in isolation:

```
$build = $view->buildRenderable();
$rendered = \Drupal::service('renderer')->renderPlain($build);

```
> 2 votes

---
Tags: 9
---


# Question
Title: What is the best way to theme the first row in the view differently?
I have a view with the first row of it being designed differently from the rest. What is the best way to theme the first row. Should I attach one view (First Row view) with a second view ? If so, how? Or should I theme using the template files and if so How can I know the row I am currently in?

The attached image may better explain what I am talking about:

# Answer
> 6 votes
In this specific situation, the issue can be easily solved by simply using CSS to target .views-row-1 differently than the other rows, as Jimajamma mentioned.

However, if you had a situation where the content in that first row was much more different than in the other rows, there is a solution natively in Views to create this sort of layout.

Create two displays in your View using the same filter criteria. Display A would be a block that shows only one node (the top, larger item in your mockup) and has a larger image format and different order for the fields to be displayed. Display B would be the display that you use as the page that your users see. You would attach Display A to the header of Display B and set Display B to be offset by 1 result, so that it does not duplicate the first node.

Here is a screenshot of the Views 3 UI, showing where to find these settings. Earlier versions of Views support the same type of set-up, but the naming and placement of the settings in the UI is different: https://skitch.com/sheenad/gqdmm/archive-content-shop.

# Answer
> 4 votes
The Views nodes split module allows site administrators or builders to have a different view mode for the first nodes of a view result.

# Answer
> 4 votes
If the field content in the first row is the same as the rest of the view, and the only thing you want done is it displayed differently, eg, bigger picture, text in a different spot, etc, you can do it all with CSS.

Just look at the html generated by views and you will see something along the lines of:

```
<div class="views-row views-row-1 views-row-odd views-row-first">

```

wrapping the first row. So just theme ".views-row-first" differently than the rest of your ".views-row"s and you should be all set. You can theme even and odd rows differently, too, and even individual rows.

# Answer
> 3 votes
As has been said, it really depends what you're trying to do. If you simply want to style them differently then css is the way to go. However, if you want to actually have different content in row 1 then you might consider using Display Suite.

Using this you can configure a view to use the Display Suite display (in place of fields, content, etc) and then set up which content display mode you want to use for each row.

Check out a tutorial I found about this here: http://clikfocus.com/blog/changing-views-output-based-row for information on how to do this.

# Answer
> 2 votes
I've suffered through this problem numerous times since our graphic designer likes to make image style of the first row different from the rest. Because of some display reasons I couldn't put the first row in a separate view block. Here's how I solved my problem.

**1)** In my view I added field Global: View rows counter. Set it to start at `0`. It cannot be hidden, otherwise it won't work. This is to pass row number to `views-view-fields.tpl.php`

**2)** I've created custom `views-view-fields.tpl.php` template. Inside at the beginning of the first foreach loop I added

```
if($id == 'counter'){

  if(strip_tags ($field->content) == '0'){

   //alter your display for that row here

  }

  continue; // this is to hide the counter from view

}

```

**3)** In my case to alter image style of the first row I added

```
if(isset($fields['field_name']) && !empty($fields['field_name'])){

  $row->field_field_name[0]['rendered']['#image_style']= 'image_style_name';

  $fields['field_name']->content = '<div class="field-content">' . render($row->field_field_name[0]['rendered']) . '</div>';

}

```

This can be also done in `views-view-field.tpl`. I wish there was a less heavy-handed way to alter and render the field, like `field_view_field` for entities. I couldn't find any, though.

# Answer
> 1 votes
You can add display of type "*Block*" that for the first item only and add another display of type "*Attachment*" and set it to be attached to the first display.

# Answer
> 1 votes
Another way to do this is

1. setup 2 content type view modes (lets say `teaser` and `teaser alternate`)
2. add https://www.drupal.org/project/views\_parity\_row and in the setup use `frequency 0, start 0, end 1` which will mean `teaser alternate` will be the first row and all other row will have `teaser` view mode

# Answer
> 1 votes
I think the Views Parity Row solution is great but you can also do this with a simple preprocess function in your theme.

1. Setup two view modes: `teaser` and `featured_teaser`.
2. Use a different image style with larger image dimensions for the `featured_teaser` view mode.
3. Setup view showing content with the `teaser` view mode.
4. Add below preprocess function to your custom theme's .theme file.
5. Replace theme\_name with your custom's theme name.
6. Replace view\_name with your view's machine name.
7. Replace display\_name with your display name.
8. Use CSS Grid for the layout: https://codepen.io/danield770/pen/WpyrdO

*

```
function theme_name_preprocess_views_view(&$variables) {
  /** @var \Drupal\views\ViewExecutable $view */
  $view = $variables['view'];
  if ($view->id() == 'view_name' && $view->current_display == "display_name") {
    $variables['rows'][0]['#rows'][0]['#view_mode'] = 'featured_teaser';
  }
}

```

---
Tags: views, theming
---


# Question
Title: MenuLink vs MenuLinkContent - what's the point?
I'm struggling to figure out relationship between MenuLink and MenuLinkContent.

I'm creating new menu item like:

```
$menuItem = MenuLinkContent::create($params);

```

I can also query those elements like:

```
$menuItems = \Drupal::entityTypeManager()->getStorage('menu_link_content')->loadByProperties(['link.uri' => "internal:$path"]);

```

And that works well. Now if I need one of those object I want to get it's "siblings" - other object that share same parent. I have some weird structure:

```
$this->menuLinkManager = \Drupal::service('plugin.manager.menu.link');
$parentId = $menuItem->getParentId();
$parent = $this->menuLinkManager->createInstance($this->menuLinkManager->getDefinition($parentId)['id']);

```

And here I'm getting it's parent, but it's not MenuLinkContent object any more but instance of MenuLinkInterface. It has some fields as MenuLinkContent, but not all. I.e. I don't know how to get link path and similar.

There I can go further:

```
$siblings = $this->menuLinkManager->getChildIds($parent->getPluginId());

```

But main question is h**ow to get MenuLinkContent when I have that MenuLinkInterface object?**

Sub-question - why oh why is needed this parallel menu system and parallel menu classes?

# Answer
> 0 votes
> ```
> $siblings = $this->menuLinkManager->getChildIds($parent->getPluginId());
>
> ```
>
> *But main question is how to get MenuLinkContent when I have that MenuLinkInterface object?*

There are two types of plugin IDs. Without or with a colon `:`.

**Non-derived plugins**

Without they point directly to a single plugin definition.

For example the admin menu

```
\Drupal::service('plugin.manager.menu.link')->getChildIds('system.admin');

```

consists mainly of non-derived menu links which IDs you find in \*.links.menu.yml files.

**Derived plugins**

With colon the first part is the base plugin ID and the second part is the derivative ID.

For example, if you have created a multi-level main menu from UI and apply this command on a menu parent

```
\Drupal::service('plugin.manager.menu.link')->getChildIds('standard.front_page');

```

You get links like this

```
menu_link_content:421a421a-cb1d-33e7-a810-1e7341f7906b

```

for the base plugin MenuLinkContent (BTW also defined in a YAML file) with a deriver for MenuLinkContent entities (identified by UUID).

```
$entity = \Drupal::service('entity.repository')
  ->loadEntityByUuid('menu_link_content', '421a421a-cb1d-33e7-a810-1e7341f7906b');

```

If you have already a plugin instance you can get the UUID from the plugin object. See https://drupal.stackexchange.com/a/235769/47547

---
Tags: 8, navigation
---


# Question
Title: How to disable text format options in CKEditor
I wish users don't have the option which text format they want to use as shown here:

I have been playing around with the better formats module, Currently only works on Field API fields on fieldable entities implementing core style text processing. So this module only makes sure with which text format they will start off editing with, so this dCurrently only works on Field API fields on fieldable entities implementing core style text processing.oesn't do anything at all, as the users still have the option to choose which text format they would like to choose.
Besides hiding this option with CSS, is there another way to disable this option for specific users?

# Answer
The simplify module will allow you to hide text format selection, and a lot of other bling too: https://drupal.org/project/simplify

The simplify module allows you to hide the text format selection globally on all content types, as in the attached screen. Alternately, you can disable text format selection for each content type individually.

I've really only used it one one site so far, but haven't had any trouble.
> 1 votes

# Answer
There's an option called "Text processing" in the content type's body field settings (`Content types > YourContentType > Manage fields > Body > Edit`). If you check "Plain text", it should disappear.
> 0 votes

# Answer
In Drupal 9. Use can set the allowed\_formats. If there is only one format, it will hide the select box

```
'body' => [
        '#type' => 'text_format',
        '#format'=> 'full_html',
        '#allowed_formats' => ['full_html'],
      ]

```
> 0 votes

---
Tags: 7, wysiwyg
---