# Question
Title: How to show associated options with the "Entity select element" when using Webform + Webform Node
I have a webform with an Entity select element. The referenced item is a content type (for example: product). This Product content type has 5 nodes (product 1, product 2 etc.). When viewing the webform it shows a select list with the 5 options (expected).

Now I would like to make use of a node with the webform associated. This content type has the fields Product (entity reference) and webform (to associate the form to the node). When I add 2 products to this node, I would like the webform to only show those 2 products (instead of all) in the Entity select element.

I know there is an option to use a view and tried to use a relationship with contextual filters, but I can't seem to find the right options. Any suggestions?

# Answer
> 0 votes
Found out how to create this relation. In views I had to add the following settings:

1. Add relation for desired field.
2. Add another relation that is referenced by that content.
3. Add contextual filter NID with a relation to the field selected in step 1.

---
Tags: webforms
---


# Question
Title: How do I get a list the comment types' machine name?
Drupal ships with just one comment type enabled, with the machine name `comment`. But if the **Forum** module is installed, there is also `comment_forum`. And site builders can define new comment types in the GUI.

How do I get a list the comment types' machine name? Or: How can I get all comments, regardless of name.

# Answer
Comment types are an entity type, so you can load them as with any entity type, and get the machine name from CommentType::id():

```
$comment_types = array_map(
  function ($comment_type) {
    return $comment_type->id();
  },
  \Drupal::entityTypeManager()->getStorage('comment_type')->loadMultiple()
);

```

Or to load all comments, regardless of type, you can use:

```
\Drupal::entityTypeManager()->getStorage('comment')->loadMultiple()

```
> 7 votes

---
Tags: 9, comments
---


# Question
Title: How do I automatically include the entity reference of an entity reference with JSON:API?
My nodes of content type **Article** contain an entity reference to **Audio media**. This **Audio media** has a file entity reference.

When listing articles via JSON:API, I want to automatically include this file entity reference for any articles that have it.

To auto-include the **Audio media** entity reference, I can use the JSON:API Defaults submodule of the JSON:API Extras module to add `audioMedia` (JSON:API Extras customized name for the entity reference field pointing to **Audio media**).

However, I don't know how to auto-include the file entity reference, which is on the `audioMedia` entity reference.

I tried customizing the **Audio media** resource to include the file reference, but that includes it when accessing **Audio media** via JSON:API, not when accessing **Articles**.

I also tried adding `file` to the **Default include list** for **Articles**, but this gives an error that `file` is not an available option.

So how can I auto-include the entity reference of an entity reference with JSON:API Defaults?

# Answer
> 0 votes
Multi-level references need to be linked by a period:

`audioMedia.file`

---
Tags: 9
---


title: How to programmatically import a feed?

text:
# Question
Title: How to programmatically import a feed?
I'm using Drupal 8 and creating a feed entity like this:

```
//...
$feed = \Drupal::entityTypeManager()->getStorage('feeds_feed')->create(array(
            'type' => 'my_feed',
            'uuid' => \Drupal::service('uuid')->generate(),
            'title' => 'RSS feed',
            'uid' => $uid,
            'status' => 1,
            'created' => time(),
            'source' => $form_state->getValue('rss_feed_url'),
          ));
$feed->save();
//...

```

That works fine! But how can I execute the import after saving the new feed entity? I've tried the following:

```
// Batch starts and returns "This webpage has a redirect loop"
$feed->startBatchImport();

// Returns an error: "Call to undefined method Drupal\feeds\FeedImportHandler::startCronImport()"
$feed->startCronImport();

```

How can I import the feed items after creating the feed entity?

# Answer
This is working for me. Note: You will need to know the numerical $id of your Feed from the D8 DB table feeds\_feed. In my case it is 1 so $id = 1.

```
use Drupal\feeds\Entity\Feed;

function mymodule_cron() {

  /**
   * Runs single feeds on cron
   */

  $feed = Feed::load($id);
  if (!$feed->isLocked()) {
    $queue = \Drupal::queue('feeds_feed_import:' . $feed->bundle());
    if ($queue->createItem($feed)) {
      // Add timestamp to avoid queueing item more than once.
      $feed->setQueuedTime(REQUEST_TIME);
      $feed->save();
    }
  }
}

```
> 2 votes

# Answer
This should work:

```
$feed = \Drupal::entityTypeManager()->getStorage('feeds_feed')->create(array(
            'type' => 'my_feed',
            'uuid' => \Drupal::service('uuid')->generate(),
            'title' => 'RSS feed',
            'uid' => $uid,
            'status' => 1,
            'created' => time(),
            'source' => $form_state->getValue('rss_feed_url'),
          ));
$feed->save();
$feed->import();

```
> 1 votes

# Answer
Feeds also has drush support, and drush can be scripted quite easily:

> ```
>   feeds:list-feeds Display all feeds using a drush command.
>   feeds:enable     Enable a feed specified by its id.
>   feeds:disable    Disable a feed specified by its id.
>   feeds:import     Import a feed specified by its id.
>   feeds:import-all Import all feeds.
>   feeds:lock       Lock a feed specified by its id.
>   feeds:unlock     Unlock a feed specified by its id.
>
> ```

It's as simple as `drush feeds 123`, where 123 is the entity ID of the feed.

In my case, I find it easier to import feeds by machine name, because machine names will always be the same even across different sites that import the same config, whereas entity IDs can vary among sites that import the same config.

I wrote a patch to add machine name support to feeds drush import.
> 0 votes

---
Tags: 8, feeds
---


title: HtmlRouteProvider not found error

text:
# Question
Title: HtmlRouteProvider not found error
I've just started using the Modal module version 4.1.15 and haven't made any changes to the file structure, now after clearing the cache I get this error:
`Error: Class 'Drupal\modal_page\Entity\RouteProvider\ModalHtmlRouteProvider' not found in Drupal\Core\Entity\EntityTypeManager->createHandlerInstance() (line 272 of /var/www/html/core/lib/Drupal/Core/Entity/EntityTypeManager.php)`

Is there a new class I need to create to serve a route to the function, or is this an easy fix?

# Answer
It seems the RouteProvider folder containing the class I needed was deleted somehow, dropping it back in and clearing the cache fixed the issue.
> 0 votes

---
Tags: modal-dialogs
---


# Question
Title: How do I programmatically set contextual filters?
I need to set a contextual filter programmatically and *almost* every view I have will have this filter. However, some wont and will have other contextual filters instead.

I have tried following the examples in here but this will just set the first argument to be my filter value regardless of what field is it for.

In `views_pre_build` I get the keyed arguments list under `$view->argument` and can do `->setArgument()` but this doesn't change the set of results.

Is there an easier way of setting a specific contextual filter?

# Answer
> 0 votes
Contextual filters use query string params. You could hard code these into the URL. If using a Url object, you can pass a third argument \['query' =\> \['param1 =\> 'param1\_value',...\]\]. Try setting a filter and seeing what the URL param name & value is after doing so.

In hook\_views\_pre\_build(), you can also set the filter value directly:

```
$view->filter['filter_name']->value = 'filter_value';

```

It's helpful to have Xdebug so you can see the names of existing filters. If you don't have xdebug, try finding the correct filter name in the -\>filter property, then find the desired filter value, and put 2 and 2 together.

# Answer
> 3 votes
If you have the `$view` object, you can pass contextual filter params using the setArguments() method. Here is an example I'm using to pass four nids to the view to filter the results contextually:

```
$view->setArguments(['125+109+110+111']);

```

# Answer
> 0 votes
```
function your_module_views_pre_build(ViewExecutable $view) {
  if ($view->id() == 'viewname' && $view->getDisplay()->display['id'] == 'machinenameOfDisplay') {
      dump( $view->args ); //you will get all the argument
      $view->args[1] = 'your value' //set specific argument
  }
}

```

---
Tags: views, 8
---


# Question
Title: How to add a secondary Ajax submit to a regular node form?
I'm trying to add an Ajax submit to a regular node edit form (Drupal 9). I'm using Field Groups so that there's a series of tabs, and I've added a pair of "buttons" (Right now they're just markup `<div>s`, but I could change them to real buttons if that's recommended) that users can use to move forward and back through the tabs with some Javascript.

The ask now is that each time the tab focus changes, the form is submitted via Ajax. All the examples I'm finding seem to be doing something other than what I'm after. I've seen examples using completely custom forms, loading forms, and altering fields, but nothing that just adds the ability to submit a a regular node form with Ajax.

Things I've tried:

* Adding an `#ajax` subarray of various sorts to the buttons and/or the regular submit element. *Nothing Ajaxy at all has happened in any of these experiments*
* Using Javascript to trigger a click event on the submit, without and without an `#ajax` subarray. *All I get is a regular submit with page refresh*
* Bypassing all of that just calling `$.post($('#form-id').attr('action'), $('#form-id').serialize())`. *There's some semblance of Ajax submit going on as my custom `hook_form_alter` gets hit, but the node isn't saved/updated. I think that's failing because there's no proper submit/op value associated with it, and I haven't been able to figure out how to add/set it.*

Can someone point me in the right direction?

# Answer
after reading a tone of documentations and examples of other Drupal developers, I figured out a way which worked for me very good. But this may not a best practice way, after all ;-)

Here is what I've done, to add a new button to a node content type edit form:

# how to build an async node save button

## add new button to a content type

In your module add hook *form\_alter* to you my\_module.module file to add the new button to your content type edit form:

```
  /**
   * Implements hook_form_alter().
   */
  function emp_save_edit_form_alter(&$form, FormStateInterface $form_state): void {
    $formObject = $form_state->getFormObject();
    $entity = $formObject->getEntity();
    $contentType = $entity->getType();

    if ($contentType === "YOUR_CONTENT_TYPE") {

      $form['actions'][] = [
        '#type' => 'submit',
        '#value' => 'Async save',
        // this is required to have the entity stored properly
        '#submit' => [
          '::submitForm',
          '::save',
        ],
        // this enables the button to used the async way
        '#ajax' => [
          'callback' => 'formSubmitAjax',
          /*if you want to to use a progress bar instead of the spinning clock, the use this:
          'progress' => [
            'type'=> 'bar',
            'message' => 'saving...'
          ]*/
        ],
        '#weight' => 1,
      ];

    }
  }

```

This will a submit button named "Async save" to your edit form which should do the following:

* call the function *submitForm* and *save* of the node entity form (or any other entity form, if you like)
* call the function *formSubmitAjax* Both are executed with ajax. The edit form should not be reloaded.

## add function formSubmitAjax

Then also add the still missing function *formSubmitAjax* to your my\_module.module file:

```
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\OpenModalDialogCommand;
use Drupal\Core\Ajax\ReplaceCommand;
  /**
   * Submit form with ajax - add messages to be shown after ajax request is processed
   */
  function formSubmitAjax(&$form, FormStateInterface $form_state): AjaxResponse
  {
    $response = new AjaxResponse();
    // ToDo add redirect when form is an "add-form"

    // if functions "submitForm" or "save" will have errors, these should be collected in $form_state->errors
    if ($errors = $form_state->getErrors()) {
      foreach ($errors as $error) {
        $errorHtml = strtr('<div class="messages messages--error">$errorText</div>', ['$errorText' => $error->render()]);
        // show message as a drupal Dialog Modal
        $response->addCommand(new OpenModalDialogCommand('Error', $errorHtml));
      }
    } else {
      $date = new DateTime();
      // add a message to show things worked out - with current timestamp
      $successMsg = 'Your changes have been saved at ' . $date->format('Y-m-d H:i:s');
      $successHtml = strtr('<div class="messages messages--status">$statusText</div>', ['$statusText' => $successMsg]);
      $response->addCommand(new OpenModalDialogCommand('Saved', $successHtml));
    }
    $response->addCommand(new ReplaceCommand(NULL, $form));
    // the changed time of the form has to be changed after a form is submitted to prevent the error "this page as already saved by another user" or so
    $response->addCommand(new InvokeCommand('input[name="changed"]','val',[time()]));
    // prevent messages to be shown after reloading the edit form, all recent messages have to be deleted
    Drupal::messenger()->deleteAll();
    return $response;
  }

```

Te be sure this code find it's way into Drupal, rebuild your cache:

```
drush cr

```
> 3 votes

# Answer
The first point is the only straightforward way. A regular node edit form has already Ajax form elements. You can check the "ajax" subarray of `drupal-settings-json` delivered to the browser.

You should see your own Ajax callback here as well:

```
  "ajax": {
    "edit-field-article-add-more": {
      "callback": [
        "Drupal\\Core\\Field\\Plugin\\Field\\FieldWidget\\EntityReferenceAutocompleteWidget",
        "addMoreAjax"
      ],
      "wrapper": "field-article-add-more-wrapper",
      "effect": "fade",
      "event": "mousedown",
      "keypress": true,
      "prevent": "click",
      "url": "\/node\/123\/edit?destination=\/admin\/content\u0026ajax_form=1",
      "dialogType": "ajax",
      "submit": {
        "_triggering_element_name": "field_article_add_more",
        "_triggering_element_value": "Add another item"
      }
    },
    "edit-field-paragraph-add-more-add-more-button-text": {
      "callback": [
        "Drupal\\paragraphs\\Plugin\\Field\\FieldWidget\\InlineParagraphsWidget",
        "addMoreAjax"
      ],
      ...

```

If not, then you have to debug server-side PHP. If yes, then client-side Javascript.
> 1 votes

---
Tags: nodes, forms, ajax, 9
---


# Question
Title: Call to a member function bundle() on null in Drupal\Core\Entity\Plugin\Condition\EntityBundle->evaluate()
I have a dev site built on Drupal 9.1.9 and now I'm trying to use the site in 9.3.9. Everything is fully functional on 9.1.9 but when I try to run the same site on 9.3.9 I get. I believe the error is being generated from the context module somehow and I tried disabling each context rule and am still facing the error.

```
The website encountered an unexpected error. Please try again later.
Error: Call to a member function bundle() on null in Drupal\Core\Entity\Plugin\Condition\EntityBundle->evaluate() (line 93 of core/lib/Drupal/Core/Entity/Plugin/Condition/EntityBundle.php).

Drupal\Core\Entity\Plugin\Condition\EntityBundle->evaluate() (Line: 77)
Drupal\Core\Condition\ConditionManager->execute(Object) (Line: 84)
Drupal\Core\Condition\ConditionPluginBase->execute() (Line: 26)
Drupal\context\ContextManager->resolveConditions(Object, 'or') (Line: 352)
Drupal\context\ContextManager->evaluateContextConditions(Object) (Line: 254)
Drupal\context\ContextManager->evaluateContexts() (Line: 242)
Drupal\context\ContextManager->getActiveContexts() (Line: 274)
Drupal\context\ContextManager->getActiveReactions() (Line: 44)
Drupal\context\EventSubscriber\BlockPageDisplayVariantSubscriber->onSelectPageDisplayVariant(Object, 'render.page_display_variant.select', Object)
call_user_func(Array, Object, 'render.page_display_variant.select', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'render.page_display_variant.select') (Line: 224)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 163)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 80)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 50)
Drupal\ban\BanMiddleware->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 708)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

```

> core/lib/Drupal/Core/Entity/Plugin/Condition/EntityBundle.php Once, I made changes to evaluate function by providing if condition on the $entity, then it works as expected. I'm not confident that this approach is the correct way to fix the issue here.

```
public function evaluate() {
    // Returns true if no bundles are selected and negate option is disabled.
    if (empty($this->configuration['bundles']) && !$this->isNegated()) {
      return TRUE;
    }
    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = $this->getContextValue($this->getDerivativeId());
    //var_dump($entity); die();
    if($entity){
      return !empty($this->configuration['bundles'][$entity->bundle()]);
    }
  }

```

Should I be looking for the patches here or is there any way I can debug what's causing this error? Any advice would be highly appreciated.

# Answer
The generic entity bundle condition was introduced in Drupal 9.3. See the change record https://www.drupal.org/node/2983299

This error is usually caused by a context mapping in config. This can also happen in the standard block layout without the context module.

What is the entity type if you var\_dump `$this->getDerivativeId()`? This could lead to a context rule like in this issue https://www.drupal.org/project/context/issues/3260611
> 0 votes

---
Tags: entities
---


# Question
Title: Drupal.Ajax.prototype.beforeSubmit results in AJAX Error
I have a module that creates an AJAX Form.

I need to copy some values from the DOM to a form field when (or before) the form is submitted.

In my module JS, I tried this:

```
(function($, Drupal) {

  Drupal.behaviors.beforeAjaxFormSubmit = {
    attach: function(context, settings) {

      Drupal.Ajax.prototype.beforeSubmit = function(form_values, element, options) {

        console.log('Will alter form here ...')
      };
    }
  };
})(jQuery, Drupal);

```

The console log is shown but right after comes an AJAX Error:

> An AJAX HTTP error occurred.
> HTTP Result Code: 200
> Debugging information follows.
> Path: /intervention/create?ajax\_form=1
> StatusText: OK
> ResponseText: TypeError: Argument 1 passed to Drupal\Core\Render\MainContent\AjaxRenderer::renderResponse() must be of the type array, null given, called in /var/www/html/web/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php on line 89 in Drupal\Core\Render\MainContent\AjaxRenderer-\>renderResponse() (line 49 of /var/www/html/web/core/lib/Drupal/Core/Render/MainContent/AjaxRenderer.php).
> \[\[Prototype\]\]: Error at http://d9.localhost:8000/core/misc/ajax.js?v=9.4.2:110:32

Does anyone know what I am doing wrong or if this is not the right approach?

### Edit:

```
(function($, Drupal) {

  Drupal.behaviors.beforeAjaxFormSubmit = {
    attach: function(context, settings) {

      // Add submit handler to form.beforeSend.
      // Update Drupal.Ajax.prototype.beforeSend only once.
      if (typeof Drupal.Ajax !== 'undefined' && typeof Drupal.Ajax.prototype.beforeSubmitInterventionForm === 'undefined') {
        Drupal.Ajax.prototype.beforeSubmitInterventionForm = Drupal.Ajax.prototype.beforeSubmit;
        Drupal.Ajax.prototype.beforeSubmit = function(form_values, element_settings, options) {

          // Things will happen here

          return this.beforeSubmitInterventionForm.apply(this, arguments);
        };
      }
    }
  };
})(jQuery, Drupal);

```

This is what I have now but I am still getting the same AJAX Error.

# Answer
> 1 votes
You need to call the code of the original beforeSubmit().

I've found this great example in the webform module:

*/webform/js/webform.element.managed\_file.js*

```
  // Add submit handler to form.beforeSend.
  // Update Drupal.Ajax.prototype.beforeSend only once.
  if (typeof Drupal.Ajax !== 'undefined' && typeof Drupal.Ajax.prototype.beforeSubmitWebformManagedFileAutoUploadOriginal === 'undefined') {
    Drupal.Ajax.prototype.beforeSubmitWebformManagedFileAutoUploadOriginal = Drupal.Ajax.prototype.beforeSubmit;
    Drupal.Ajax.prototype.beforeSubmit = function (form_values, element_settings, options) {
      var $form = this.$form;
      var $element = $(this.element);

      // Determine if the triggering element is within .form-actions.
      var isFormActions = $element
        .closest('.form-actions').length;

      // Determine if the triggering element is within a multiple element.
      var isMultipleUpload = $element
        .parents('.js-form-type-webform-multiple, .js-form-type-webform-custom-composite')
        .find('.js-form-managed-file').length;

      // Determine if the triggering element is not within a
      // managed file element.
      var isManagedUploadButton = $element.parents('.js-form-managed-file').length;

      // Only trigger block submit for .form-actions and multiple element
      // with file upload.
      if ($form.data('webform-auto-file-uploads') > 0 &&
        (isFormActions || (isMultipleUpload && !isManagedUploadButton)) &&
        blockSubmit($form)) {
        this.ajaxing = false;
        return false;
      }
      return this.beforeSubmitWebformManagedFileAutoUploadOriginal.apply(this, arguments);
    };
  }

```

---
Tags: forms, ajax, 9
---


# Question
Title: Order balance not directly updated after payment created
I'm trying to figure out why my order balance isn't directly updated after I've created a payment. I'm debugging it with xDebug. This is my OnNotify function

```
$this->order = Order::load($orderId);
//isPaid = false
  if ($this->order !== NULL) {
    //create the payment, assign it to the order
    $payment = $this->createPayment($this->order, $mt);
    if ($this->order->isPaid()) { //isPaid still false instead of true

```

This is how the payment is created

```
  protected function createPayment(OrderInterface $order, $mt){
    $payment_storage = $this->entityTypeManager->getStorage('commerce_payment');
    /** @var \Drupal\commerce_payment\Entity\Payment $payment */
    $payments = $payment_storage->loadByProperties(['order_id' => $this->order->id()]);
    $price = new Price(((int)$mt)/100, 'EUR');
    if (count($payments) == 0) {
      $payment = $payment_storage->create([
        'state' => 'completed',
        'amount' => $price,
        'payment_gateway' => $this->entityId,
        'order_id' => $this->order->id(),
        'remote_id' => null,
        'remote_state' => null,
        'completed' => time()
      ]);
      $payment->save();
      $this->order->save();
      return $payment;
    }

```

So if i put breakpoint, the isPaid is always false. However, if I don't use the debugger, the order balance works correctly (without the process beeing executed twice or anything...). Any ideas ?

# Answer
The Payment entity's post save function explains it:

```
  /**
   * {@inheritdoc}
   */
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    parent::postSave($storage, $update);

    $order = $this->getOrder();
    if ($order && $this->isCompleted()) {
      $payment_order_updater = \Drupal::service('commerce_payment.order_updater');
      $payment_order_updater->requestUpdate($order);
    }
  }

```

When a payment is saved, a request to the related order is merely requested, not initiated. At the end of the page request, when PHP is destroying the `PaymentOrderUpdater` service, that is when the updates to the relevant orders are finally processed. This is to avoid any kind of "save within a save" scenario.
> 1 votes

---
Tags: commerce, 9, payment-gateways
---


# Question
Title: Can't access download page for webform submissions
Basically, we're running into an issue where we're being returned a HTTP error 500 when trying to view the webform submissions download page, i.e. the following page: https://www.hartmanns.dk/en/admin/structure/webform/manage/hartmanns\_academy\_08\_september/results/download

When trying to access our download page, we see a HTTP error 500 with the following logs:

```
AH01071: Got error 'PHP message: PHP Fatal error: Declaration of Drupal\\webform\\Plugin\\WebformElement\\WebformSignature::accessFileDownload($uri) must be compatible with Drupal\\webform\\Plugin\\WebformElementFileDownloadAccessInterface::accessFileDownload(string $uri) in /var/www/vhosts/hartmanns.dk/httpdocs/web/modules/contrib/webform/src/Plugin/WebformElement/WebformSignature.php on line 30\n', referer: https://www.hartmanns.dk/en/admin/structure/webform/manage/hartmanns_academy_08_september/results/submissions

```

Have any of you run into this issue? We've tried clearing cache, setting the correct permissions etc., however, from the logs it seems to be an incompatibility issue.

We're running Drupal core 8.9.20 & Webform 6.1.3.

Any help is greatly appreciated. :)

# Answer
> 1 votes
I googled your error message and this webform issue was the second result.

This has already been committed so you can try upgrading to the 6.2 beta which will hopefully fix the issue-- except you are on Drupal 8, which has been unsupported since November 30, 2021, and 6.2 requires Drupal 9.2+.

Really you should update to Drupal 9 ASAP and then update Webform, but if you can't wait you could try the patches in the linked issue.

---
Tags: webforms
---


# Question
Title: Redirection from user login to another page for logged in users
Due to requirements with our reverse proxies, I had to show the user login form on a different URL. Well, no problem, I thought, I'll just copy the relevant section from `user.routing.yml` and display it on a different path:

```
mymodule.user.login:
  path: '/ls/login'
  defaults:
    _form: '\Drupal\user\Form\UserLoginForm'
    _title: 'Log in'
  requirements:
    _user_is_logged_in: 'FALSE'
  options:
    _maintenance_access: TRUE

```

This works, **but** if an user accesses the login URL after having logged in (typically because they bookmarked the login page), they get an "Access denied" page. I can understand it – after all, there is the requirement that the user is NOT logged is. I was thinking of ways to circumvent this, but then I noticed that the *original* URL (still accessible if I access the server directly rather than through the proxies) does not have this problem: if I go to `/usr/login` it after logging in, I get redirected to the user page, `/user/{{id}}`.

I don't understand how the latter works, I looked at `UserLoginForm.php` in addition to `user.login.form`, but I found no clue. What is involved here?

# Answer
> 2 votes
*I don't understand how the latter works, I looked at UserLoginForm.php in addition to user.login.form, but I found no clue. What is involved here?*

In core there is an exception event subscriber catching the 403 and redirecting to the current user page:

*web/core/modules/user/src/EventSubscriber/AccessDeniedSubscriber.php*

```
...

  public function onException(ExceptionEvent $event) {
    $exception = $event->getThrowable();
    if ($exception instanceof AccessDeniedHttpException) {
      $route_name = RouteMatch::createFromRequest($event->getRequest())->getRouteName();
      $redirect_url = NULL;
      if ($this->account->isAuthenticated()) {
        switch ($route_name) {
          case 'user.login';
            // Redirect an authenticated user to the profile page.
            $redirect_url = Url::fromRoute('entity.user.canonical', ['user' => $this->account->id()], ['absolute' => TRUE]);
            break;

      ...

      if ($redirect_url) {
        $event->setResponse(new RedirectResponse($redirect_url->toString()));
      }

```

You can copy the class to your custom module to do the same thing for a custom route, together with the service definition (to mymodule.services.yml):

```
services:
  user_access_denied_subscriber:
    class: Drupal\user\EventSubscriber\AccessDeniedSubscriber
    arguments: ['@current_user']
    tags:
      - { name: event_subscriber }

```

and adjust both with custom names and namespace.

---

**Different approach**

A different approach might be to alter the existing route instead of creating a new one, so that dependencies on the route name, like this redirect code, still work. See Change '/user(/\*)' URLs to 'profile(/\*)'

---
Tags: routes, 9
---


# Question
Title: Change '/user(/*)' URLs to 'profile(/*)'
I want change all /user, /user/\* urls by /profile, /profile/\* urls. From a custom module, I copied all user routes (found in /core/module/user/user.routing.yml) to my custom .routing.yml file. I replaced all "user\*" paths by "profile\*".

Now, I have the following.

```
mycustommodule.register:
  path: '/profile/register'
  defaults:
    _entity_form: 'user.register'
    _title: 'Create new account'
  requirements:
    _access_user_register: 'TRUE'

mycustommodule.pass:
  path: '/profile/password'
  defaults:
    _form: '\Drupal\user\Form\UserPasswordForm'
    _title: 'Reset your password'
  requirements:
    _access: 'TRUE'
  options:
    _maintenance_access: TRUE

mycustommodule.page:
  path: '/profile'
  defaults:
    _controller: '\Drupal\user\Controller\UserController::userPage'
    _title: 'My account'
  requirements:
    _user_is_logged_in: 'TRUE'

mycustommodule.login:
  path: '/profile/login'
  defaults:
    _form: '\Drupal\user\Form\UserLoginForm'
    _title: 'Log in'
  requirements:
    _user_is_logged_in: 'FALSE'
  options:
    _maintenance_access: TRUE

mycustommodule.login.http:
  path: '/profile/login'
  defaults:
    _controller: \Drupal\user\Controller\UserAuthenticationController::login
  methods: [POST]
  requirements:
    _user_is_logged_in: 'FALSE'
    _format: 'json'

mycustommodule.login_status.http:
  path: '/profile/login_status'
  defaults:
    _controller: \Drupal\user\Controller\UserAuthenticationController::loginStatus
  methods: [GET]
  requirements:
    _access: 'TRUE'
    _format: 'json'

mycustommodule.logout.http:
  path: '/profile/logout'
  defaults:
    _controller: \Drupal\user\Controller\UserAuthenticationController::logout
  methods: [POST]
  requirements:
    _user_is_logged_in: 'TRUE'
    _format: 'json'
    _csrf_token: 'TRUE'

mycustommodule.cancel_confirm:
  path: '/profile/{user}/cancel/confirm/{timestamp}/{hashed_pass}'
  defaults:
    _title: 'Confirm account cancellation'
    _controller: '\Drupal\user\Controller\UserController::confirmCancel'
    timestamp: 0
    hashed_pass: ''
  requirements:
    _entity_access: 'user.delete'
    user: \d+

mycustommodule.reset.login:
  path: '/profile/reset/{uid}/{timestamp}/{hash}/login'
  defaults:
    _controller: '\Drupal\user\Controller\UserController::resetPassLogin'
    _title: 'Reset password'
  requirements:
    _user_is_logged_in: 'FALSE'
  options:
    _maintenance_access: TRUE
    no_cache: TRUE

mycustommodule.reset:
  path: '/profile/reset/{uid}/{timestamp}/{hash}'
  defaults:
    _controller: '\Drupal\user\Controller\UserController::resetPass'
    _title: 'Reset password'
  requirements:
    _access: 'TRUE'
  options:
    _maintenance_access: TRUE
    no_cache: TRUE

mycustommodule.reset.form:
  path: '/profile/reset/{uid}'
  defaults:
    _controller: '\Drupal\user\Controller\UserController::getResetPassForm'
    _title: 'Reset password'
  requirements:
    _user_is_logged_in: 'FALSE'
  options:
    _maintenance_access: TRUE
    no_cache: TRUE

```

From my website, when I go to the http://mysite/profile, I'm redirected to the correct page (the user view), but the URL change automatically to http://mysite/user. I want keep the URL as http://mysite/profile. How can I do that? Is it possible?

# Answer
The routes you've defined are new routes with different names and this is the reason the standard routes are still in place. If you want to override the standard routes you would have to use the same route names like `user.page:`.

But this is not the best approach to alter multiple routes. Better use a route subscriber:

**src/EventSubscriber/RouteSubscriber.php**

```
<?php

namespace Drupal\mymodule\EventSubscriber;

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

class RouteSubscriber extends RouteSubscriberBase {

  protected function alterRoutes(RouteCollection $collection) {
    foreach ($collection->all() as $route) {
      if (strpos($route->getPath(), '/user') === 0) {
        $route->setPath(preg_replace('/^\/user/', '/profile', $route->getPath()));
      }
    }
  }

  public static function getSubscribedEvents() {
    $events = parent::getSubscribedEvents();

    $events[RoutingEvents::ALTER] = array('onAlterRoutes', -250);

    return $events;
  }

}

```

**mymodule.services.yml**

```
services:
  mymodule.route_subscriber:
    class: Drupal\mymodule\EventSubscriber\RouteSubscriber
    tags:
      - { name: event_subscriber }

```
> 8 votes

# Answer
Answer from 4k4 is good BUT it goes through all routes which is IMHO not right. Instead try this approach:

```
<?php

/**
 * @file
 * Contains \Drupal\mymodule\RouteOverride\PageManagerRoutesOverride.
 */

namespace Drupal\mymodule\RouteOverride;

use Drupal\Core\Routing\RouteBuildEvent;
use Drupal\Core\Routing\RoutingEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Component\Discovery\YamlDiscovery;

/**
 * Class PageManagerRoutesOverride
 * Overrides paths for the Page Manager module to suit the structure of mymodule.
 */
class PageManagerRoutesOverride implements EventSubscriberInterface {

  /**
   * Path to the root of the project.
   *
   * @var string
   */
  protected $root;

  /**
   * The module handler service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * Constructs a new PageManagerRoutesOverride object.
   *
   * @param string $app_root
   *   The current application root path.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_hander
   *   The module handler service.
   */
  public function __construct($app_root, ModuleHandlerInterface $module_hander) {
    $this->root = $app_root;
    $this->moduleHandler = $module_hander;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[RoutingEvents::ALTER] = 'alterRoutes';
    return $events;
  }

  /**
   * Alters existing routes.
   *
   * @param \Drupal\Core\Routing\RouteBuildEvent $event
   *   The route building event.
   */
  public function alterRoutes(RouteBuildEvent $event) {
    // See if the Page Manager UI module is enabled.
    if (!$this->moduleHandler->moduleExists('page_manager_ui')) {
      return;
    }

    // Page manager has just too many routes and is still quite prone to changes
    // so instead of overriding them manually, we'll use the actual route definitions.
    $module_directory = $this->moduleHandler->getModule('page_manager_ui')->getPath();
    $discovery = new YamlDiscovery('routing', [$this->root . '/' . $module_directory]);
    $route_files = $discovery->findAll();

    // Get the route names.
    if (isset($route_files['page_manager_ui'])) {
      $route_names = array_keys($route_files['page_manager_ui']);
    } else {
      $route_names = [];
    }

    // Fetch the collection which can be altered.
    $collection = $event->getRouteCollection();

    // Process the routes.
    foreach ($route_names AS $route_name) {
      // Fetch the route.
      $route = $collection->get($route_name);

      // Set the new path.
      $route_path = strtr($route->getPath(), [
        '/admin/structure/page_manager' => '/mymodule/content/page-builder',
        '/admin/structure/page_variant' => '/mymodule/content/page-builder'
      ]);
      $route->setPath($route_path);

      // Some custom alterations.
      switch ($route_name) {
        case 'entity.page.collection':
          $route->setDefault('_title', 'Page builder');
          break;
      }
    }
  }

}

```

And the service:

```
mymodule.page_manager_routes_override:
  class: Drupal\mymodule\RouteOverride\PageManagerRoutesOverride
  arguments: ['@app.root', '@module_handler']
  tags:
    - { name: event_subscriber }

```
> 1 votes

# Answer
If you aren't a coder, the Rename Admin Paths module can do this.

It allows you to rename `/user` routes and `/admin` routes in Drupal 7, 8, and 9.

Install the module, go to the config, and choose the new routes.

**YOU NEED TO TEST THIS!** Some contrib modules are badly coded and will break if the user route is not at `/user` or the `/admin` route is not at admin. If such an error occurs, it should be reported to that module's issue queue.
> 0 votes

---
Tags: users, 8, routes
---


# Question
Title: How do I find out which system.info my site is using?
I have 3 sites using the same host. I have updated them from 7.89 to 7.91 however only one site shows as using 7.91. I have hunted my host files for a system.info with 7.89 without any luck.

Where do I find which system.info files are being used by my sites?

# Answer
The Drupal 7 Core version is in `includes/bootstrap.inc` on line 10, not in a `.info` file. Example:

```
define('VERSION', '7.91');

```
> 1 votes

# Answer
The *system.info* file is simply the file containing information for the *System* module. As such, there should not be more than a *system.info* file in a Drupal site, except in the case you copied the Drupal core files more than once.

The *system.info* file doesn't contain any release value. It just contains a reference to a constant defined in another file.

```
name = System
description = Handles general site configuration for administrators.
package = Core
version = VERSION
core = 7.x
files[] = system.archiver.inc
files[] = system.mail.inc
files[] = system.queue.inc
files[] = system.tar.inc
files[] = system.updater.inc
files[] = system.test
required = TRUE
configure = admin/config/system

```

`VERSION` is defined in the *includes/bootstrap.inc* file. If that file has been updated, it's probable the Drupal core release isn't reported correctly.
> 1 votes

---
Tags: 7, updating
---


# Question
Title: Composer not updating modules in windows
I'm update drupal core using composer with success.

```
composer update

Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 9 updates, 0 removals
  - Upgrading drupal/core (9.4.0 => 9.4.5)
  - Upgrading drupal/core-composer-scaffold (9.4.0 => 9.4.5)
  - Upgrading drupal/core-project-message (9.4.0 => 9.4.5)
  - Upgrading drupal/core-recommended (9.4.0 => 9.4.5)
  - Upgrading drupal/core-vendor-hardening (9.4.0 => 9.4.5)
  - Upgrading guzzlehttp/guzzle (6.5.7 => 6.5.8)
  - Upgrading guzzlehttp/psr7 (1.8.5 => 1.9.0)
  - Upgrading symfony/css-selector (v6.1.0 => v6.1.3)
  - Upgrading symfony/mailer (v5.4.8 => v5.4.11)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 9 updates, 0 removals
  - Upgrading drupal/core-composer-scaffold (9.4.0 => 9.4.5): Extracting archive
  - Upgrading drupal/core-project-message (9.4.0 => 9.4.5): Extracting archive
  - Upgrading drupal/core-vendor-hardening (9.4.0 => 9.4.5): Extracting archive
  - Upgrading guzzlehttp/psr7 (1.8.5 => 1.9.0): Extracting archive
  - Upgrading guzzlehttp/guzzle (6.5.7 => 6.5.8): Extracting archive
  - Upgrading drupal/core (9.4.0 => 9.4.5): Extracting archive
  - Upgrading drupal/core-recommended (9.4.0 => 9.4.5)
  - Upgrading symfony/css-selector (v6.1.0 => v6.1.3): Extracting archive
  - Upgrading symfony/mailer (v5.4.8 => v5.4.11): Extracting archive
    Cleaning: guzzlehttp/psr7
    Cleaning: symfony/css-selector
Package doctrine/reflection is abandoned, you should avoid using it. Use roave/better-reflection instead.
Package symfony/debug is abandoned, you should avoid using it. Use symfony/error-handler instead.
Generating autoload files
Hardening vendor directory with .htaccess and web.config files.
44 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Scaffolding files for drupal/core:
  - Copy [project-root]/.editorconfig from assets/scaffold/files/editorconfig
  - Copy [project-root]/.gitattributes from assets/scaffold/files/gitattributes
  - Copy [web-root]/.csslintrc from assets/scaffold/files/csslintrc
  - Copy [web-root]/.eslintignore from assets/scaffold/files/eslintignore
  - Copy [web-root]/.htaccess from assets/scaffold/files/htaccess
  - Copy [web-root]/example.gitignore from assets/scaffold/files/example.gitignore
  - Copy [web-root]/sites/default/default.settings.php from assets/scaffold/files/default.settings.php
Cleaning installed packages.

```

But i'm trying update modules with composer and it not working. The log show that download and installation is success, but in website reports the module is out of date.

```
composer require drupal/metatag:^1.21

./composer.json has been updated
Running composer update drupal/metatag
Loading composer repositories with package information
Updating dependencies
Lock file operations: 2 installs, 0 updates, 0 removals
  - Locking drupal/metatag (1.21.0)
  - Locking drupal/token (1.11.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Installing drupal/token (1.11.0): Extracting archive
  - Installing drupal/metatag (1.21.0): Extracting archive
Package doctrine/reflection is abandoned, you should avoid using it. Use roave/better-reflection instead.
Package symfony/debug is abandoned, you should avoid using it. Use symfony/error-handler instead.
Generating autoload files
Hardening vendor directory with .htaccess and web.config files.
44 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
Cleaning installed packages.

```

After I run /update.php but in /admin/modules/update the module metatag continues in 8.x-1.19, instead 8.x-1.21. I'm using windows.

composer.json

```
{
"name": "drupal/legacy-project",
"description": "Project template for Drupal 9 projects with composer following drupal/drupal layout",
"type": "project",
"license": "GPL-2.0-or-later",
"homepage": "https://www.drupal.org/project/drupal",
"support": {
    "docs": "https://www.drupal.org/docs/user_guide/en/index.html",
    "chat": "https://www.drupal.org/node/314178"
},
"repositories": [
    {
        "type": "composer",
        "url": "https://packages.drupal.org/8"
    }
],
"require": {
    "composer/installers": "^1.9",
    "drupal/core-composer-scaffold": "^9.3",
    "drupal/core-project-message": "^9.3",
    "drupal/core-recommended": "^9.3",
    "drupal/core-vendor-hardening": "^9.3",
    "drupal/symfony_mailer": "^1.0@alpha"
},
"conflict": {
    "drupal/drupal": "*"
},
"minimum-stability": "stable",
"prefer-stable": true,
"config": {
    "sort-packages": true,
    "allow-plugins": {
        "composer/installers": true,
        "drupal/core-composer-scaffold": true,
        "drupal/core-project-message": true,
        "drupal/core-vendor-hardening": true
    }
},
"extra": {
    "drupal-scaffold": {
        "locations": {
            "web-root": "./"
        }
    },
    "installer-paths": {
        "core": [
            "type:drupal-core"
        ],
        "libraries/{$name}": [
            "type:drupal-library"
        ],
        "modules/contrib/{$name}": [
            "type:drupal-module"
        ],
        "profiles/contrib/{$name}": [
            "type:drupal-profile"
        ],
        "themes/contrib/{$name}": [
            "type:drupal-theme"
        ],
        "drush/Commands/contrib/{$name}": [
            "type:drupal-drush"
        ],
        "modules/custom/{$name}": [
            "type:drupal-custom-module"
        ],
        "profiles/custom/{$name}": [
            "type:drupal-custom-profile"
        ],
        "themes/custom/{$name}": [
            "type:drupal-custom-theme"
        ]
    },
    "drupal-core-project-message": {
        "include-keys": [
            "homepage",
            "support"
        ],
        "post-create-project-cmd-message": [
            "<bg=blue;fg=white>                                                         </>",
            "<bg=blue;fg=white>  Congratulations, you’ve installed the Drupal codebase  </>",
            "<bg=blue;fg=white>  from the drupal/legacy-project template!               </>",
            "<bg=blue;fg=white>                                                         </>",
            "",
            "<bg=yellow;fg=black>Next steps</>:",
            "  * Install the site: https://www.drupal.org/docs/8/install",
            "  * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html",
            "  * Get support: https://www.drupal.org/support",
            "  * Get involved with the Drupal community:",
            "      https://www.drupal.org/getting-involved",
            "  * Remove the plugin that prints this message:",
            "      composer remove drupal/core-project-message"
        ]
    }
}

```

}

# Answer
> 1 votes
I think that you have two copies of metatag, one, which you installed in `modules/metatag`, which is version 1.19 and another which Composer installs in `modules/contrib/metatag`, which is version 1.21. This is the best answer I can provide given the information you provided in comments.

---
Tags: composer
---


# Question
Title: address dependent locality field not shown
drupal 8.8.2 address 8.x-1.7

address module is working in that i can add an address to my content, however I am not able to display the "dependent locality " field even when it is set to "no override" or "required"

from the doc i did find : https://docs.drupalcommerce.org/commerce2/developer-guide/customers/addresses/countries-and-subdivisions

it shows a "suburb" field, which i am assuming is this field. I was planning to use this to contain the "county"

is there a dependency i need to check to enable this field ?

thanks for your time.

ps. i was not sure how to tag this question, i did not see a tag for modules or address

# Answer
> 1 votes
i must be blind... right under the doc i was reading i see

The Commerce Guys addressing data set only includes subdivisions that are required for addressing.

so this field is not included because it is not needed for an address.

# Answer
> 0 votes
Using Drupal 9 and address-8.x-1.10, this field can be enabled by adding it to the format. Enable the field as either optional/required under field settings. Then create an AddressFormatSubscriber with something like the following:

```
class AddressFormatSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
{

  public static function getSubscribedEvents() {
    $events[AddressEvents::ADDRESS_FORMAT][] = ['onAddressFormat'];
    return $events;
  }

  public function onAddressFormat(AddressFormatEvent $event) {
    $definition = $event->getDefinition();

    // Adds additional-name to format
    $format = $definition['format'];
    $format = str_replace('%additionalName', '', $format);
    $format = str_replace('%postalCode', "%postalCode %dependentLocality", $format);
    $definition['format'] = $format;

    $event->setDefinition($definition);
  }

}

```

(Don't forget to register in your-module.services.yml.)

As far as I can tell, this is required to display the field and to satisfy validation.

Here is the formal documentation on Address Formats: https://docs.drupalcommerce.org/commerce2/developer-guide/customers/addresses/address-formats

---
Tags: nodes, 8
---


title: Debugging node/route access

text:
# Question
Title: Debugging node/route access
I want to set a breakpoint in xdebug to debug an interesting issue the site is having regarding user access to certain nodes. My question is where do I do that in D8? Where, specifically, is the D8 replacement for user\_access to be found?

Not using any form of node access, but am using Group and Content Moderation. The problem could lie with either of them, but I thought the best approach would be to break where Drupal decides whether a user has access to node/###/edit, then step from there.

The problem is that the user's role's permissions give all node and content moderation permissions for the applicable content type. Yet, when going to the admin/content page or admin/content/moderation, given two nodes of the same content type authored by a user of the given role, with the same node and moderation status, only one has an edit button. In viewing the nodes, only one has an edit link.

I have rebuilt permissions, to no effect.

# Answer
> 2 votes
The `/node/{node}/edit` path is defined by the `entity.node.edit_form` route. This route uses the `_entity_access` requirement to lookup access. When that route's requested the entity API will execute `EntityAccessCheck::access()` and `NodeAccessControlHandler::access()` to lookup the account permssions for the relevant node.

# Answer
> 1 votes
I found the best place to put debug code is in `\Drupal\Core\Access\AccessManager::check`. In my case...

```
    $result = AccessResult::neutral();
if (!empty($checks)) {
  $arguments_resolver = $this->argumentsResolverFactory->getArgumentsResolver($route_match, $account, $request);
  $result = AccessResult::allowed();
  foreach ($checks as $service_id) {
    $result = $result->andIf($this->performCheck($service_id, $arguments_resolver));
    // Begin debug
    if($route_match->getRouteName() == 'entity.node.edit_form') {
      $this_check = $this->performCheck($service_id, $arguments_resolver);
      dpm(compact('service_id', 'this_check'), __FILE__ . ":" . __LINE__);
    }
    // End debug
  }
}
// Begin debug
if($route_match->getRouteName() == 'entity.node.edit_form') {
  dpm($result, __FILE__ . ":" . __LINE__);
}
// End debug
return $return_as_object ? $result : $result->isAllowed();

```

---
Tags: 8, debugging
---


# Question
Title: Can phpstorm infer the entity type from \Drupal::entityTypeManager()->getStorage()?
Curious whether it's possible to get phpstorm to infer entity types when loading them via entity storage, e.g. `\Drupal::entityTypeManager()->getStorage('node)->load(1)`, without needing to use comments.

# Answer
If you don't want to declare the variable in a phpDoc style comment

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

```

your IDE understands also PHP code, like the PHP type operator `instanceof`:

```
$node = \Drupal::entityTypeManager()->getStorage('node')->load(1);
if ($node instanceof \Drupal\node\NodeInterface) {
  // your code using $node
}

```
> 4 votes

---
Tags: debugging
---


# Question
Title: How to redirect to content if view have 1 result?
Views page show content. How to redirect to content page if views has only one result?

# Answer
> 1 votes
In your theme's **themename.theme** file add:

At the very top add:

```
use Drupal\views\ViewExecutable;
use Symfony\Component\HttpFoundation\RedirectResponse;

```

Then add:

```
/*
 * Implements hook_views_pre_render()
 */
function THEMENAME_views_pre_render(ViewExecutable $view) {
    if($view->id() == "view_name" && $view->current_display == 'view_machine_name') {
      if (!empty($view->result) && count($view->result) == 1) {
        $url = $view->result[0]->_entity->toUrl()->toString();
        $response = new RedirectResponse($url);
        $response->send();
      }
    }
}

```

Clear the cache so changes kick in.

---

my\_module/src/Controller/**ViewPageController.php**

```
namespace Drupal\my_module\Controller;

use Drupal\Core\Cache\CacheableRedirectResponse;
use Drupal\Core\Controller\ControllerBase;
use Drupal\views\Views;

/**
 * Defines HelloController class.
 */
class ViewPageController extends ControllerBase {

  public function content() {

    $view = Views::getView('view_name');
    $view->setDisplay('view_machine_name');
    $view->execute();

    if (!empty($view->result) && count($view->result) == 1) {

      $url = $view->result[0]->_entity->toUrl()->toString(TRUE);
      $response = new CacheableRedirectResponse($url->getGeneratedUrl());
      $response->getCacheableMetadata()->addCacheTags($view->getCacheTags());
      $response->addCacheableDependency($url);
      return $response;

    }
    else {

      return [
        '#type' => 'view',
        '#name' => 'view_name',
        '#view' => $view,
        '#display_id' => 'view_machine_name',
        '#embed' => TRUE,
        '#cache' => $view->getCacheTags(),
      ];

    }

  }

}

```

This is the view\_machine\_name.

# Answer
> 0 votes
There's a LOT better way. Use hook\_views\_post\_render() instead. See my comment here.

and the documentation at views.api.php

```
/**
 * Post-process any render data.
 *
 * The module or theme may add, modify or remove elements in $output after
 * rendering.
 *
 * If a module wishes to act on the rendered HTML of the view rather than the
 * structured content array, it may use this hook to add a #post_render
 * callback:
 * @code
 * // The object must implement \Drupal\Core\Security\TrustedCallbackInterface.
 * $output['#post_render'][] = '\Drupal\my_module\View::postRender';
 * @endcode
 *
 * See \Drupal\Core\Render\RendererInterface::render() for #post_render
 * documentation.
 *
 * Alternatively, it could also implement hook_preprocess_HOOK() for
 * the particular view template, if there is one.
 *
 * @param \Drupal\views\ViewExecutable $view
 *   The view object being processed.
 * @param array $output
 *   A structured content array representing the view output. The given array
 *   depends on the style plugin and can be either a render array or an array of
 *   render arrays.
 * @param \Drupal\views\Plugin\views\cache\CachePluginBase $cache
 *   The cache settings.
 *
 * @see \Drupal\views\ViewExecutable
 */
function hook_views_post_render(ViewExecutable $view, array &$output, CachePluginBase $cache) {

  // When using full pager, disable any time-based caching if there are fewer
  // than 10 results.
  if ($view->pager instanceof Drupal\views\Plugin\views\pager\Full && $cache instanceof Drupal\views\Plugin\views\cache\Time && count($view->result) options['results_lifespan'] = 0;
    $cache->options['output_lifespan'] = 0;
  }
}

```

---
Tags: views, 8
---


title: Image inside paragraph being cached

text:
# Question
Title: Image inside paragraph being cached
I have a Paragraph type called image - that holds a media reference and also a field which describes how the sibling image should be rendered. I look at the value of the "field\_image\_style" - and then apply a responsive image style to the Image in a preprocess\_paragraph call:

```

function my_module_preprocess_paragraph(&$variables)
{

  if ($variables['paragraph']->hasField('field_image_style') && isset($variables['paragraph']->field_image_style->entity)) {
    /** @var \Drupal\Core\Entity\Entity\EntityViewMode $viewMode */
    $viewMode = $variables['paragraph']->field_image_style->entity->field_view_mode_for_media->entity;
    //kint($viewMode);
    if ($viewMode != null) {
      $viewModeMachineName = $viewMode->id();
      //kint($viewModeMachineName);
      $viewModeMachineNameMediaPrefixRemove = str_replace("media.", "", $viewModeMachineName);
      //kint($viewModeMachineNameMediaPrefixRemove);

      //kint($variables['content']['field_image'][0]['#view_mode']);
      $variables['content']['field_image'][0]['#view_mode'] = $viewModeMachineNameMediaPrefixRemove;
    }
  }
}

```

The html for rendering the image is being cached - and when I rebuild the cache - the site flips between one flavour and the next. How do I make the cache key on the value I am setting such that I get a cached copy for each different $viewModeMachineNameMediaPrefixRemove ?

Full data structure added below for completeness:

Paragraph type: Image Image contains two fields - both Entity references. field\_image \> Entity Reference \> Media field\_image\_style \> Entity Reference \> Taxonomy Term (Image style)

The Taxonomy term Image style then has two fields; Tax term \> Text plain (css format) - used to decorate the paragraph Tax term \> Entity Reference \> View mode (points to view mode of Media Image)

This view mode is then used to select primarily one of two Responsive Image Styles.

The preprocess hook is on the paragraph - as the paragraph knows about both the image and the way in which it needs to be rendered.

# Answer
Thanks to all for their contributions. Ended up using the solution proposed by @Hudri:

`unset($variables['content']['field_image'][0]['#cache']['keys']);`

Which allowed for both image styles to be used on the same image across different paragraphs.
> 0 votes

---
Tags: hooks, caching, paragraphs
---


# Question
Title: How can I render or change programmatically the responsive image style for an image field for a paragraph?
I want to allow the editor user to be able to select different responsive image styles to render an image field from a paragraph field. So I have defined another field where the user can select the responsive style they want.

The problem is that I can't apply that responsive style on the fly on the twig template, so I tried to altered the field or create the picture element and assign it to a variable I can access from the template in the hook\_preprocess\_field, but I can't access the url of the image in the variables. So I don't know how to carry on.

Is there a way to achieve this?

# Answer
> 5 votes
You don't need to swap the image, only the information how to render the image. And you can't do this in a field template. This is only possible in the paragraph template, where both fields are available:

```
function mytheme_preprocess_paragraph(&$variables) {
  if ($variables['paragraph']->hasField('field_image_style')) && isset($variables['content']['field_image']['0']) {
    $image_style = $variables['paragraph']->field_image_style->value;
    $variables['content']['field_image']['0']['#responsive_image_style_id'] = $image_style;
  }
}

```

# Answer
> 1 votes
I have encountered this issue a handful of times and the best solution I found was using something like Zurb Interchange. This takes an image and swaps out the image src based on the screen size, dynamically.

I don't have a version for Drupal 8, but there is one for Drupal 7. It lets you select what image styles it should generate derivatives of, and their order (order important for media query). If you're interested in Zurb's plugin, perhaps you can port it to Drupal 8. I haven't had time or the opportunity to do so yet.

Though, as I understand it, it might not be necessary to do for Drupal 8, with the new stuff they added into 8.x: https://www.bluecoda.com/blog/using-responsive-images-drupal-8 \- but I don't know if it swaps out the right image when the browser is resized by the user (something Interchange and plugins like it would do).

# Answer
> 0 votes
Beware of caching here folks. I started from the example above - thanks @4uk4 - then added a cache key removal line. Code below:

```
if ($variables['paragraph']->hasField('field_image_style') && isset($variables['paragraph']->field_image_style->entity)) {
    /** @var \Drupal\Core\Entity\Entity\EntityViewMode $viewMode */
    $viewMode = $variables['paragraph']->field_image_style->entity->field_view_mode_for_media->entity;
    // kint($viewMode);
    if ($viewMode != null) {
      $viewModeMachineName = $viewMode->id();
      //kint($viewModeMachineName);
      $viewModeMachineNameMediaPrefixRemove = str_replace("media.", "", $viewModeMachineName);
      //kint($viewModeMachineNameMediaPrefixRemove);
      //kint($variables['content']['field_image'][0]['#view_mode']);
      $variables['content']['field_image'][0]['#view_mode'] = $viewModeMachineNameMediaPrefixRemove;
      //  Need to tweak the cache keys - as we are getting a cached copy of the HTML for the responsive image style
      // Remove the cache keys for the image - rely on cache for the paragraph
      // See here: https://drupal.stackexchange.com/questions/311888/image-inside-paragraph-being-cached?noredirect=1#comment397045_311888
      unset($variables['content']['field_image'][0]['#cache']['keys']);
      //kint($variables['content']);
    }
  }

```

---
Tags: 8, media, theming
---


# Question
Title: How to get newly created user id in user_presave hook?
Following is my .module file code

```
/**
 * Implements hook_user_presave().
 */

function cost_sheet_user_presave($account) {
    $source_userid = $account->id();
    \Drupal::messenger()->addMessage(t($source_userid));

}

```

This is giving me uid for already existing users when edited but not printing any value when a new user is created. How to get uid of newly created user in drupal 8 user presave hook?

# Answer
> 1 votes
You can't get the user ID in `hook_user_presave()` for a new user because the ID isn't assigned until the user is saved.

## So how do I run code that uses the user ID when saving a user, regardless of whether the user is new or has been edited?

Refactor your code that does something with the user ID into a function, `doStuffWithUserID()`.

```
function mymodule_user_presave($account) {
  if (!$account->isNew()) {
    doStuffWithUserID();
  }
}

function mymodule_user_insert($account) {
  // The new account has been saved, so we have an ID.
  doStuffWithUserID();
}

```

# Answer
> 0 votes
The only hooks called after an entity is saved in the database are `hook_ENTITY_TYPE_update()` for updated entities, and `hook_ENTITY_TYPE_insert()` for new entities. Once the entity is stored in the database, its ID will have a value.

Unfortunately, Drupal core doesn't use any `hook_ENTITY_TYPE_postsave()` which would make sense as it uses `hook_ENTITY_TYPE_presave()`.

This means that your module should implement `cost_sheet_user_update()` and `cost_sheet_user_insert()`.

Keep in mind that `EntityStorageBase::doPostSave()` invokes either one or the other of those hooks. Their code doesn't need to check whether the entity is new.

```
// Allow code to run after saving.
$entity->postSave($this, $update);
$this->invokeHook($update ? 'update' : 'insert', $entity);

```

---
Tags: 8, users, hooks
---


title: Reset button for an AJAX form

text:
# Question
Title: Reset button for an AJAX form
How do i programatically reset the values of an AJAX submitted form for Drupal 8? I Want to reset them with an AJAX callback. Here is my current callback. It works because i'm forcing the values to NULL.

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

          $form_state->clearErrors();
          $form_state->setRebuild(TRUE);

          $form['address']['#value']    = NULL;
          $form['customer']['#value']   = NULL;
          $form['name']['#value']       = NULL;
          $form['email']['#value']      = NULL;
          $form['location']['#value']   = NULL;
          $form['zip_code_1']['#value'] = NULL;
          $form['zip_code_2']['#value'] = NULL;
          $form['phone']['#value']      = NULL;
          $form['subject']['#value']    = NULL;
          $form['message']['#value']    = NULL;

          return $form;
        }

```

# Answer
I found a couple solutions that works in Drupal 9 that should also work in 8. Untested.

In my buildForm() I am setting some '#default\_values`with`$form\_state-\>getValue('name')\`. Maybe you are too?

In my case I have a non ajax version of the form that does not have a clear button. In my ajax form's `buildForm()` function; I simply add "unset()" to the beginning of the form because there is never an instance in which the form needs to be pre-populated on page load in my case. The form will not reload in-between state changes either, so we never have to worry about \`#default\_value' being set.

Example:

```
public function buildForm(array $form, FormStateInterface $form_state) {
    //get parent's form
    $form = parent::buildForm($form, $form_state);
    //unset default values so the form clears properly
    unset($form['address']['#default_value']);
    unset($form['customer']['#default_value']);
    unset($form['name']['#default_value']);
    // the rest of your form modifications

    return $form
}

```

Alternatively or in addition to, if you need your form to be pre-populated on page load via arguments (might be overkill); In your ajax `buildForm()` you can detect the last callback made and preform your unsets within:

```
//within the buildForm() ajax function, example clear button with your callback name
$form['clear'] = [
      '#type' => 'button',
      '#value' => $this->t('Clear'),
      '#ajax' => [
        'callback' => '::resetFormCallback',
        'event' => 'click',
      ],

//Check the operating button that submitted a callback action that rebuilt the form
//assign boolean
$form_cleared = 'Clear' === (string) $form_state->getValue('op');
if($form_cleared) {
  //preform unsets here
}

```
> 0 votes

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


# Question
Title: How can I create an entity reference exposed filter?
How can I create an entity reference exposed filter?

The only option I have is input of type text.

# Answer
> 0 votes
You need an additional module for that:

Entity Reference Exposed Filters

This might also help: Views field select filter

I'm not sure if this one supports exposed or only normal filters: Views Entity Reference Filter

# Answer
> 0 votes
You can reated a hook\_form\_FORM\_ID\_form\_alter() in my module.module file.Below is my code example:

```
function module_form_views_exposed_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form['#id'] == 'views-exposed-form-view-name-page-1') {

    if (array_key_exists('field_name_target_id', $form)) {

      // Rewrite the default 'All' option
      if (!empty($form['field_name_target_id']['#options']['All'])) {
        $option_default = ['All' => t('- Any -')];
      }

      $options = $form['field_name_target_id']['#options'];

      // Ensure that only terms that are used in the view
      // are displayed in the filter
      $connection = Database::getConnection();
      $query = $connection->select('node__field_name', 'vocabulary');
      $query->join('node_field_data', 'n', 'n.nid = vocabulary.entity_id');
      $query->fields('vocabulary', ['field_name_target_id']);
      $query->fields('n', ['status']);
      $query->condition('vocabulary.bundle', 'nodebundle');
      $query->condition('n.status', 1);
      $data = $query->distinct()->execute();

      $results = array_flip($data->fetchAll(\PDO::FETCH_COLUMN, 'field_name_target_id'));
      $options = array_intersect_key($options, $results);

      // Rebuild the option select with the term values and the all option
      $form['field_name_target_id']['#options'] = $option_default + $options;
    }
  }
}

```

---
Tags: views, 8
---


# Question
Title: Extending Core classes with the @internal tag
I need to make weights of Taxonomies translatable and only show translations of terms when you change language.

To do this I need to override the OverviewTerms class from the Taxonomy module to change some of its methods. However, when I try to extend the OverviewTerms class PhpStorm puts a strikethrough on OverviewTerms because it is marked as `@internal`, although I can still extend and use the new extension.

What does the `@internal` tag mean and what is the right way to extend classes with this tag?

# Answer
Drupal 8 and 9 backwards compatibility and internal API policy (backend), linked by @4uk4, states:

> Contributed and custom code should avoid calling internal APIs because they might change in minor releases and such changes may not be documented in change records.

To me, the most important point here is **such changes may not be documented in change records**, meaning that if you extend an `@internal` class, your code may break, and even if you read the change records for that release, you may not be able to quickly identify the change because the relevant change may not have a change record.

So, the best thing to do is not to extend `@internal` classes and instead use hooks or extend other classes to achieve the behavior you want. For example, for taxonomy terms, you could try adding the behavior in an entity bundle class.

If you absolutely must extend an `@internal` class, then you also need to have extensive unit/functional tests of whatever you add, and you need to run those tests every time you update core to ensure nothing breaks.
> 4 votes

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


title: Custom views filter on computed field

text:
# Question
Title: Custom views filter on computed field
I've built a custom field into the view which displays the menu name a node is assigned to, but I want to filter on the menu name. How can you filter on this computed field? The only examples I have found are for updating the SQL query to filter on existing values in the table.

# Answer
> 0 votes
It is to my knowledge not possible to add a filter to a view for a computed field. A possible workaround would be to use hook\_views\_pre\_render() to remove rows before Drupal renders the view.

Example code:

```
/**
 * Implements hook_views_pre_render().
 */
function mymodule_views_pre_render(ViewExecutable $view) {
  if ($view->id() === 'my_view' && $view->current_display === 'page_1') {
    foreach ($view->result as $key => $value) {
      $menu_name = $value->_entity->get('menu_name')->value;
      if ($menu_name !== 'My Menu') {
        // Remove row from the view
        unset($view->result[$key]);
      }
    }
  }
}

```

---
Tags: 8, views
---


title: TypeError on "drush config-export"

text:
# Question
Title: TypeError on "drush config-export"
I've been receiving the following error message when trying to do a `drush config-export` command.
However, I am able to successfully do the configuration export from the Drupal admin page (`admin/config/development/configuration/full/export`).

```
TypeError: Argument 2 passed to [error] Drupal\Core\Config\FileStorage::write() must be of the type array, boolean given, called in /vendor/drush/drush/commands/core/config.drush.inc on line 519 in Drupal\Core\Config\FileStorage->write() (line 140 of /web/core/lib/Drupal/Core/Config/FileStorage.php)
#0
/vendor/drush/drush/commands/core/config.drush.inc(519): Drupal\Core\Config\FileStorage->write('field.field.nod...', false)
#1
/vendor/drush/drush/commands/core/config.drush.inc(448): _drush_config_export('sync', '../data/sync', false)
#2
/vendor/drush/drush/includes/command.inc(422): drush_config_export()
#3
/vendor/drush/drush/includes/command.inc(231): _drush_invoke_hooks(Array, Array)
#4
/vendor/drush/drush/includes/command.inc(199): drush_command()
#5
/vendor/drush/drush/lib/Drush/Boot/BaseBoot.php(67): drush_dispatch(Array)
#6
/vendor/drush/drush/includes/preflight.inc(66): Drush\Boot\BaseBoot-bootstrap_and_dispatch()
#7 /Users/Bcorrigan/sites/flowrite8/vendor/drush/drush/drush.php(12):
drush_main()
#8
{main}.

```

The only reference I can find to something similar is here: https://www.drupal.org/node/2830047

But I did not have that module installed when I started getting the error. It's installed now, but still getting the error and will probably remove it soon.

I started receiving the error yesterday, reverting to previous version of Git have made no difference in receiving the error.

Anyone else run into this? Know how to fix? Thanks for any help you can provide.

# Answer
> 0 votes
Just try

```
drush config-export --destination="<folder-path>"

```

Path should be some writable folder

# Answer
> 0 votes
This issue can happen if the export directory does not have the write permissions. I just created a folder with write permissions and I was able to successfully export the configurations using `drush config-export`. Or, if you want to choose different directory just specify --destination params as

```
drush config-export --destination="YOUR_FOLDER_PATH"

```

---
Tags: 8, drush, configuration
---


title: Use translations with nl2br in template

text:
# Question
Title: Use translations with nl2br in template
Is it possible to use translations with `nl2br`?

I tried `{{ "This offer may \n interest you"|nl2br|t }}`, but it doesn't translate the string because it contains a `'\n'` character.

I already tried with `{% trans %}{% endtrans %}` instead of `|t`, but the result is same.

# Answer
> 0 votes
Did you try `{{ "This offer may \n interest you"|nl2br|striptags|t }}`?

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


# Question
Title: Twig filter on Webform Computed Twig element
I have a webform where I am gathering information on multiple questions (q1, q2) using the Image Select input type where each option has a value of 0,1,2,3 or 4.

I then use a Computed Twig Element element to perform a calculation on those modules:

```
{{data.q1 + data.q2}}

```

The value calculates correctly, but also gives an error:

```
Warning: A non-numeric value encountered in __TwigTemplate_cd3a9ebc1b3926be2ad8645d59045ec00f6b94edddb5e60df6140411f5dece1d->doDisplay() (line 39 of /tmp/rolling/e1555e9/twig/62f1d500a7ac1___string_template__101327_Sz_1wKa-YlFg9227-b5dQAz4B/hK-aBjEvfXL8MqrWdNU0pXNOjmLq_uceb--VyGVgJEg.php)

```

I wondered if this is because the value from the Image Select element is a string instead of an integer and hoped I could fix it by using a Twig conversion filter to convert it to an integer:

```
{{data.q1|integer + data.q2|integer}}

```

However, when I try to add that filter, it gives me the error:

```
Computed value/markup is not valid.
- Unknown "integer" filter in
"__string_template__791a...."
at line 1.

```

Any ideas on how to remove that error or additional troubleshooting steps?

# Answer
> 2 votes
I don't know if all of Drupal's Twig extensions are available in the Webform context. Try this:

```
{{data.q1|number_format + data.q2|number_format}}

```

---
Tags: webforms
---


# Question
Title: Refresh ( or reopen) a Dialog (meida browser) with javascript
I have a media field, which when the user clicks on it, the media selector will open with the list of media.

I have a custom button there which do some ajax calls at the end I want to refresh the content of the Dialog ( Media browser Modal).

**Question: How in the javascript file we can detect the open dialog and refresh it?** ( because I want to see the latest updates)

I see there are some ways to trigger open a link on a dialog here and here but it's different from what I wanted. I want to reopen opened Dialog ( media browser).

I took a look at the modal ajax command,

```
[{command: "settings",…},…]
0: {command: "settings",…}
1: {command: "update_build_id", old: "form-Un8r-lGuizetNMAm2fi418NHrJF0v28SSLOXsfh-04o",…}
2: {command: "openDialog", selector: "#drupal-modal", settings: null,…}
command: "openDialog"
data: "<div id=\"media-library-wrapper\" class=\"media-l
dialogOptions: {dialogClass: "media-library-widget-modal", title: "Add or select media", height: "75%", width: "75%",…}
dialogClass: "media-library-widget-modal"
height: "75%"
modal: true
title: "Add or select media"
width: "75%"
selector: "#drupal-modal"
settings: null

```

how can I Refresh(or reopen) an opened Dialog ( Media library) in custom Js file?

**Update:**

an idea, in js, get "field\_name" of modal from action, then try to trigger "mousedown" action on the button. but looks like no very good solution for me.

# Answer
for resolving this, I noticed the `action` of the modal `form` contains several parameters, one of that is `fieldName` which shows which field caused modal open.

```
/media-library?
media_library_opener_id=media_library.opener.field_widget&
media_library_allowed_types%5Bpicture_park%5D=picture_park&media_library_selected_type=picture_park&
media_library_remaining=1
&media_library_opener_parameters%5Bfield_widget_id%5D=field_meida_2
&media_library_opener_parameters%5Bentity_type_id%5D=node&
media_library_opener_parameters%5Bbundle%5D=article&
media_library_opener_parameters%5Bfield_name%5D=field_meida_2&
hash=bGb3mXT_TI82FjHJbQYkJUm_UpaRXAQYNQYa0iZ7skM

```

So, in the Js file, I detect file name, then find button and just trigger `mousedown` action on that.

```
jQuery("input[data-media-library-widget-value=" + fieldName + "]").parent().find(".media-library-open-button").trigger("mousedown");

```

```
  function getUrlVars(url) {
    var vars = {};
    var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
      vars[key] = value;
    });
    return vars;
  }

```

with this solution it's possible to refresh the Dialog in a custom javascript.
> 0 votes

---
Tags: ajax, 9, modal-dialogs
---


# Question
Title: Is there a way to add external links to images uploaded in media browser?
A customer of mine, when they upload an image through the media browser, want to add an external URL to it. I tried adding the URL to the image field in the image type of media browser but I am not sure how to achieve this functionality.

>

>

# Answer
> 0 votes
**1. How can I add a new field to a media item's form in the media browser?**

Media have a 'Media library' *Form Display* mode - add the new field to this form display and it'll appear when adding the media item through the media library.

**2. How can I render the media item with this new field?**

Media have *View* modes, (configurable via the 'Manage display' tab of the media type). The first step is to configure a view mode to display your new field. Then configure your system to use that view mode when it renders the referenced media item.

If the media is added via an entity reference field on a node (or some other entity), configure the node to render the media with that view mode via the node's Manage Display screen.

If the media is uploaded through a WYSIWYG, configure the appropriate text format(s) to render media with the view mode you configured. This configuration is provided by the 'Embed media' filter and is unique per text format. (Text format configuration is found in the Administration menu at *Configuration \> Content authoring \> Text formats and editors*.)

p.s. To render the image linked, without custom code or templates, use the Linked Field module.

---
Tags: media
---


title: Contextual filter Term OR Empty

text:
# Question
Title: Contextual filter Term OR Empty
I have a view using taxonomy CONTEXTUAL FILTERS.

1. taxonomy vocab 1 terms AND
2. taxonomy vocab 2 terms

Both are set to get the taxonomy id from the url, limited to a specific taxonomy vocabulary and share any of the terms.

But on taxonomy vocab 2, I would like to have an additional filter to pull content without any vocab 2 terms at all.

something along the lines of

1. has taxonomy vocab 1 terms AND
2. has taxonomy vocab 2 terms OR
3. has NO taxonomy vocab 2 terms

I can do this with two separate views:

VIEW 1

1. has taxonomy vocab 1 terms AND
2. has taxonomy vocab 2 terms

VIEW 2

1. has taxonomy vocab 1 terms AND
2. has NO taxonomy vocab 2 terms

but I would like to combine the results.

**Edit:** if I have this set of content with terms, and the Contextual argument is **`term 1`** I want the first and third to be shown in Views results:

**`content 1 | term 1`**
`content 2 | term 2`
**`content 3 | no term selected`**

# Answer
You can draw some clues from this question: Views contextual filters for NULL value You should use Computed field or some other way of introducing custom PHP into your Views (custom module is the best option).

If you use more than one Contextual and need to have the `OR` operator between them you can use the Views Contextual Filters OR module.

There is also a patch for the D7 version you can expand on: Add an "OR IS NULL" option to contextual filters.

But since you're using two vocabularies and need to maintain the `AND` between the two contextuals you won't be able to use the "OR" module and you'll have to come up with a custom code solution for the second contextual that takes care of the both "there is specific term" and "there are no terms" in one contextual filter, so you can combine it with the contextual for the Vocabulary 1.
> 0 votes

# Answer
I needed to convert a contextual filter to be an IS NULL condition. I was able to do this with a query alter. I set my contextual filter to a fixed value of string "null" and then created a custom module with a `MYMODULE.views_execution.inc` file.

```
// loop over where groups
  if (is_array($query->where)) {
    foreach ($query->where as $whereIndex => $where) {

      // loop over where group conditions
      if (is_array($where['conditions'])) {
        foreach ($where['conditions'] as $conditionIndex => $condition) {

          // loop over group condition values
          if (is_array($condition['value'])) {
            foreach ($condition['value'] as $valueIndex => $value) {

              // if the value is the string of 'null'
              if ($value === 'null') {

                // convert the condition to a 'IS NULL' query
                $query->where[$whereIndex]['conditions'][$conditionIndex]['field'] = strstr($condition['field'], ' =', true);
                $query->where[$whereIndex]['conditions'][$conditionIndex]['value'] = NULL;
                $query->where[$whereIndex]['conditions'][$conditionIndex]['operator'] = 'IS NULL';
              }
            }
          }
        }
      }
    }
  }

```

Source: https://gist.github.com/devkinetic/02439eff676d0ad89a558e0b2693b9e8
> 0 votes

# Answer
This appears to be an issue in Drupal Core. You can apply a patch from there that is appropriate to your version of Drupal.
> 0 votes

---
Tags: views, 8
---


# Question
Title: How to display results database query in a custom block
This is my first post - so hello everyone :) I am trying to write a custom module that displays a certain number of posts from a certain category. I need a few of these blocks to display posts from different categories. The purpose of this is to create a custom theme. I figured it would be easier to do this with the module than with the views - the theme is quite complex. Besides, I want to exclude posts that will be displayed in the block with the latest 4 posts from different categories from showing in each block later. I created a controller:

```
<?php

namespace Drupal\fashion\Controller;

use Drupal\Core\Controller\ControllerBase;

class FashionController extends ControllerBase {

  public function FashionQuery() {

    $database = \Drupal::database();
    $query = $database->select('node_field_data', 'n');
    $query->join('node__field_news_category', 'nc', 'n.nid = nc.entity_id');
    $query
      ->fields('n', ['nid', 'type', 'created', 'title'])
      ->fields('nc', ['entity_id'])
      ->condition('nc.field_news_category_target_id', '2')
      ->condition('n.type', 'news')
      ->range(0,4);

    $result = $query->execute();

    return $result;
   }

}

```

Then I created a block:

```
<?php

/**
 * @file
 * Creates a block displays Fashion created in FashionController.php
 */

namespace Drupal\fashion\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\fashion\Controller\FashionController;

/**
 * Provides the Fashion main block.
 *
 * @Block(
 *   id = "fashion_block",
 *   admin_label = @Translation("Fashion Block Main"),
 *   category = @Translation("Custom Block"),
 * )
 */
class FashionBlock extends BlockBase implements BlockPluginInterface {

  /**
   * {@inheritdoc}
   */
  public function build() {

    $fashion_variable = new FashionController;
    $render_fashion_ids = $fashion_variable->FashionQuery();

    return [
      '#theme' => 'fashion_block',
      '#variables' => [
        '#ids' => $render_fashion_ids->entity_id,
        '#titles' => $render_fashion_ids->title,
      ],
    ];
  }
}

```

And a .module file:

```
<?php

/**
 * Implements hook_theme().
 */
function fashion_theme($existing, $type, $theme, $path) {
  return [
    'fashion_block' => [
      'variables' => [
        'ids' => NULL,
        'titles' => NULL,
      ],
    ],
  ];
}

```

and twig file (for now only for check if it works):

```
<ul>
    {% for id in ids %}
        <li>{{ id }}</li>
    {% endfor %}
    {% for title in titles %}
        <li>{{ title }}</li>
    {% endfor %}
</ul>

```

...and nothing is displayed.

I know that I am doing something wrong - I am a beginner in writing modules. If anyone could say what I am doing wrong, I would be very grateful.

Best wishes Arek

# Answer
Assuming your `FashionQuery` method yields actual results, the way to print that result set would probably be something like this (untested):

```
$render_fashion_ids = $fashion_variable->FashionQuery();
$ids = array_map(function ($item) {
  return $item->entity_id;
}, $render_fashion_ids);
$titles = array_map(function ($item) {
  return $item->title;
}, $render_fashion_ids);

return [
  '#theme' => 'fashion_block',
  '#ids' => $ids,
  '#titles' => $titles,
];

```

Besides the preprocessing of the result set to create 2 distinct new variables for the `$ids` and the `$titles`, also note the absence of the `#variables` key in the final render array.

You also want to check if the twig file is actually found (e.g. by adding some markup that is always visible). Please refer to the hook\_theme() documentation to see how to specify the name of the twig file if necessary.
> 1 votes

# Answer
Personally, I would use the Views module for this.

It's very easy to build the queries in Views, plus there are useful features like Contextual Filters if you need to handle large numbers of entities.

Views also has really robust support for theming. As noted by @leymannx, you can use theme templates to easily theme the view. You can create theme templates for each field, entity, view mode, the view itself, the particular block display-- whatever you need. You can find examples in Views twig naming conventions.

In addition, if you are displaying your view as fields, you can easily remove the default markup or customize the classes from the Views UI. See Customize the output style of a view field.

The hardest part of theming in Views is deciding which template to override. Understanding how Drupal models data is a bit tricky at first, so if you need help with that, feel free to ask a new question.
> 1 votes

---
Tags: database
---


# Question
Title: How to completely change node/entity rendering to my own render element using hook_entity_build_defaults_alter()
I want to interrupt the normal entity view build process for certain content type and view mode combination, and use a custom render array instead of the default node builder render array.

I can almost get there using the following:

```
/**
 * Implements hook_ENTITY_TYPE_build_defaults_alter().
 */
function custom_node_build_defaults_alter(array &$build, NodeInterface $node, $view_mode) {
  if ($view_mode === 'my_special_view_mode') {
    $build = [
      '#type' => 'my_special_element',
      '#thing1' => $node->get('my_field')->getValue(),
      '#cache' => $build['#cache'],
    ];
  }
}

```

This hook is invoked by `\Drupal\Core\Entity\EntityViewBuilder::viewMultiple()`. but then `\Drupal\Core\Entity\EntityViewBuilder::view()` immediately prevents it from working because it manually adds in its own `#pre_render` hook...

```
  public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
    $build_list = $this->viewMultiple([$entity], $view_mode, $langcode);

    // The default ::buildMultiple() #pre_render callback won't run, because we
    // extract a child element of the default renderable array. Thus we must
    // assign an alternative #pre_render callback that applies the necessary
    // transformations and then still calls ::buildMultiple().
    $build = $build_list[0];
    $build['#pre_render'][] = [$this, 'build'];

    return $build;
  }

```

...which means that when we get to rendering in `\Drupal\Core\Render\Renderer::doRender()`, because there has been a pre\_render hook added manually, my render element's pre\_render hook gets ignored due to the simple array merge:

```
    // If the default values for this element have not been loaded yet, populate
    // them.
    if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) {
      $elements += $this->elementInfo->getInfo($elements['#type']);
    }

```

# Answer
> 1 votes
Let's write a view builder handler decorator.

```
function foobar_entity_type_alter(array &$entity_types) {
  $entity_type = $entity_types['node'];
  $entity_type->set('foobar_original_viewer_class', $entity_type->getViewBuilderClass());
  $entity_type->setViewBuilderClass(FoobarNodeViewBuilder::class);
}

```

```
class FoobarNodeViewBuilder implements EntityHandlerInterface, EntityViewBuilderInterface, TrustedCallbackInterface {

  public function __construct(EntityHandlerInterface|EntityViewBuilderInterface|TrustedCallbackInterface $originalHandler);

  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
    return new static($container->get('entity_type.manager')
      ->createHandlerInstance($entity_type->get('foobar_original_viewer_class'), $entity_type)
  }

  public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
    return $this->originalHandler->view($entity, $view_mode, $langcode);
  }

}

```

(If PHP 8 is not available then just rewrite the constructor without union types and property promotion.)

You will, of course, want to do this for every method of the interfaces being implemented, I am too lazy to type it in. Now in `view` you have complete power as to what happens.

For tidier code, move the string `foobar_original_viewer_class` into a class constant.

# Answer
> 0 votes
So I think I have a solution now that didn't involve overriding the view builder class for every entity type on the site, because the logic is solely based on view mode names:

```

/**
 * Implements hook_entity_build_defaults_alter().
 */
function custom_entity_build_defaults_alter(array &$build, EntityInterface $entity) {
  // When using a view mode that starts with component override the entity build
  // process to generate a component render element instead.
  if ($entity instanceof FieldableEntityInterface && strpos($build['#view_mode'], 'component_') === 0) {
    $build['#component_render_element'] = determineTheRenderElementFromViewMode($build['#view_mode']);
    // Remove the default theme set by \Drupal\Core\Entity\EntityViewBuilder::getBuildDefaults()
    unset($build['#theme']);
  }
}

/**
 * Implements hook_entity_view_alter().
 */
function custom_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if (isset($build['#component_render_element'])) {
    // Generate the component render element.
    $build['component_render_element'] = [
      // In this example, view mode matches 1:1 with a render element.
      '#type' => $build['#component_render_element'],
      '#label' => $entity->label(),
      '#url' => $entity->toUrl(),
      ...
    ];
  }
}

/**
 * Implements hook_entity_view_alter().
 */
function custom_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  if (isset($build['component_render_element'])) {
    // Hide any fields on the build array other than our render element.
    foreach (Element::getVisibleChildren($build) as $key) {
      if ($key !== 'component_render_element') {
        $build[$key]['#access'] = FALSE;
      }
    }
  }
}

```

Now this would have been a lot easier if I wasn't using render elements, and instead just used `#theme` for these elements because I could probably do all the logic inside custom\_entity\_build\_defaults\_alter(). The tricky part was undoing #theme, and adding a #type, but dealing with the fact that entity rendering happens in two parts, one early that adds a pre-render callback, and then the actual entity rendering in the pre-render callback itself.

I also found this strange in `\Drupal\Core\Entity\EntityViewBuilder::buildComponents`, likely going to file a bug report:

```
    // Let the displays build their render arrays.
    foreach ($entities_by_bundle as $bundle => $bundle_entities) {
      $display_build = $displays[$bundle]->buildMultiple($bundle_entities);
      foreach ($bundle_entities as $id => $entity) {
        $build[$id] += $display_build[$id];
      }
    }

```

Because of the simple array merge, the build defaults *always* take precedence over the actual display build render arrays, which is the opposite of what I would expect.

---
Tags: nodes, hooks, 9
---