# Question
Title: Using Filter by an entity reference view with Rewrite Results gives "there are no entities matching" error
I'm using Drupal 9.2. I have created entity reference views and use them as filter for entity reference fields (autocomplete widget). When I'm using only "Content: Title" field everything works as expected. When using more fields either hidden (rewriting Title) or visible, I get "There are no entities matching \[my selection\]" error on save.

\*** Edit n.1 for more details:

I have a content type that has an entity reference field (autocomplete widget). When the user selects the referenced node I want the options to display something different than the node's title.

So I use "Views: Filter by an entity reference view" as Reference method of the field and I have created a view with an "Entity Reference Display" to use with the field.

If the only Field used in view is "Content: title" everything works as expected and the entity reference field is saved. If I use let's say "Content: Short name" then autocomplete field is indeed searching and showing Short name, but when I save the form I get "There are no entities matching \[Short name\]".

I have tried using only "Content: Title" and rewriting output and I still get the same problem.

The same happens if I use a view with users and I show firstname and lastname instead of username. Autocomplete widget searches and shows options with the selected fields correctly but saving the form result in error with no entities matching.

I really don't know how this feature works to start debugging. Is the actual referenced node id saved in a hidden field or element data attributes?

Does anybody have any idea why this is happening or how to debug? Thanks

\*** Edit n.2

After some debugging I can see that method matchEntityByTitle of EntityAutocomplete is called which in turn calls getReferenceableEntities of ViewsSelection. To validate selechion this plugin searched for a match of the "value" (fields combination) in any of the fields marked for search. This normally returns no results and the field is not validated. So is this normal behaviour and this feature can only work with title (or single field) values or do I miss something else?

# Answer
> 0 votes
Solved:

the problem was that I used method proposed here

https://drupal.stackexchange.com/a/295790/101436

to remove id in parenthesis. This would result in validation being done by matchEntityByTitle and failing.

So the real problem would be how to hide id in parenthesis and still be able to use different fields from entity reference view.

---
Tags: views
---


# Question
Title: How do I use the 'Display Wrapper Attributes' feature?
EDIT: Let's forget I ever mentioned the word 'email'. Can someone please explain to me how this part of the Webform (for Drupal 8) v5.x is supposed to work?

---

The image below is from the 'Advanced' tab of a custom composite element in a Drupal Webform. The element is creating an unordered list `<ul>` in HTML-speak. The list items `<li>` are, in turn, a list of information. I would like to create some space between the bottom of one `<li>` item and the top of the next one.

In the 'Submission Display' section of the 'Advanced' tab of the element I'm building for the webform, is a way to add 'Display CSS classes' and/or 'Display CSS style'. As you can see, I know how to create the 'custom' CSS class here; but, then what do I do to tell Drupal or Webform to do stuff WITH the custom class?

# Answer
As far as I know, Webform doesn't have any special feature for adding CSS.

The normal way to add CSS in Drupal is to create a subtheme of your site's theme and then add a custom stylesheet there. This is a bit complicated to set up but is the recommended approach for long-term maintainability.

However, if you just want to define one or two css classes to clean up your webform, setting up a subtheme may seem like overkill. In that case, you can use the Asset Injector module to add custom CSS (or JS) as you like.
> 0 votes

---
Tags: webforms
---


title: Webform export to CSV programmatically

text:
# Question
Title: Webform export to CSV programmatically
I'm looking to write a module that automatically uploads the submissions of a webform to an ftp server every week or so.

I'm looking for the recommended way to use the CSV export plugin that comes with the WebForm module to render a csv file to a string. I would want to set the following options:

* separator (default is , but should be ; because Europe)
* start date and end date of submissions (weekly export)

I see there are a lot of classes and configuration options available, but I'm not sure about the best way to string them together to achieve what I need.

# Answer
> 2 votes
After looking at the `drush webform-export` code I came up with the following code sample. It appears to work, however jrockowitz advises me that using drush straight up should be the best solution. I'm sure there's something wrong with the following code. For one, it probably breaks when the export is too large.

```
$webform_id = 'easykit_vip_formulier';
$webform = \Drupal\webform\Entity\Webform::load($webform_id);
$submission_exporter = \Drupal::service('webform_submission.exporter');
$export_options = $submission_exporter->getDefaultExportOptions();

$export_options['delimiter'] = ';';
$export_options['multiple_delimiter'] = ',';
$export_options['range_type'] = 'date';
$export_options['range_start'] = '2018-02-18';
$export_options['range_end'] = '2018-02-26';

$submission_exporter->setWebform($webform);
$submission_exporter->setExporter($export_options);
$submission_exporter->generate();
$file_path = $submission_exporter->getExportFilePath();

print file_get_contents($file_path);

unlink($file_path);

```

# Answer
> 1 votes
In-case if anyone interested in a custom script, check this out:

mymodule/src/Controller/DownloadCSVController.php

```
namespace Drupal\mymodule\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Response;

class DownloadCSVController extends ControllerBase{

    public function downloadCustomers(){

        $submissions = array();
        $row = array();
        $select = \Drupal::service('database')
        ->select('webform_submission_data', 'wsd')
        ->fields('wsd', array('sid'))
        ->orderBy('wsd.sid', 'DESC')
        ->condition('wsd.webform_id', 'webform_name', '=')
        ->execute();

        // Get all the results.
        $results = $select->fetchAll(\PDO::FETCH_COLUMN);
        if ($results != null && count($results) >= 1) {
            $storage = \Drupal::entityTypeManager()->getStorage('webform_submission');
            $submissions = $storage->loadMultiple($results);

        }

        if(count($submissions) > 0) foreach ($submissions as $submission) {
            $data = array(
                $submission->getElementData('first_name'),
                $submission->getElementData('last_name'),
            );

            $rows[] = implode(',', $data);
        }

        $content = implode("\n", $rows);
        $response = new Response($content);
        $response->headers->set('Content-Type', 'text/csv');
        $response->headers->set('Content-Disposition','attachment; filename="sample.csv"');

        return $response;
    }

}

```

mymodule/mymodule.routing.yml

```
mymodule.downloadCustomers:
  path: '/mymodule/downloadCustomers'
  defaults:
    _title: 'Download Customers'
    _controller: \Drupal\mymodule\Controller\DownloadCSVController::downloadCustomers
  requirements:
    _permission: 'access content'

```

# Answer
> 0 votes
Better to create a service so you can use it anywhere:

```
<?php

namespace Drupal\my_module\Services;

use Drupal\Core\Archiver\ArchiverManager;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\webform\Entity\WebformSubmission;
use Drupal\webform\Plugin\WebformElementManagerInterface;
use Drupal\webform\Plugin\WebformExporterManagerInterface;
use Drupal\webform\WebformSubmissionExporter;
use Drupal\webform\WebformSubmissionForm;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Database\Connection;
use PDO;

/**
 * Class DailySubmissionCSVExport.
 */
class DailySubmissionCSVExport extends WebformSubmissionExporter
{

  protected $connection;

  /**
   * {@inheritDoc}
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    FileSystemInterface $file_system,
    EntityTypeManagerInterface $entity_type_manager,
    StreamWrapperManagerInterface $stream_wrapper_manager,
    ArchiverManager $archiver_manager,
    WebformElementManagerInterface $element_manager,
    WebformExporterManagerInterface $exporter_manager,
    Connection $connection
  )
  {
    parent::__construct($config_factory, $file_system, $entity_type_manager, $stream_wrapper_manager, $archiver_manager, $element_manager, $exporter_manager);
    $this->connection = $connection;
  }

  /**
   * {@inheritdoc}
   */
  public function generate()
  {
    $entity_ids = $this->getQuery()->execute()->fetchAll(PDO::FETCH_COLUMN, 'sid');
    $webform_submissions = WebformSubmission::loadMultiple($entity_ids);

    $this->writeHeader();
    $this->writeRecords($webform_submissions);
    $this->writeFooter();
  }

  /**
   * {@inheritdoc}
   */
  public function getQuery()
  {
    $webform = $this->getWebform();

    /** @var SelectInterface $query * */
    $query = $this->connection->select('webform_submission_data', 'wsd');
    $query->join('webform_submission', 'ws', 'wsd.sid = ws.sid');
    $query->fields('wsd', array('sid'));
    $query->orderBy('wsd.sid', 'DESC');
    return $query;
  }
}

```

Define service in `my_module.service.yml` file

```
  my_module.exporter:
    class: Drupal\my_module\Services\DailySubmissionCSVExport
    arguments: ['@config.factory', '@file_system', '@entity_type.manager', '@stream_wrapper_manager', '@plugin.manager.archiver', '@plugin.manager.webform.element', '@plugin.manager.webform.exporter', '@logger.factory', '@database']

```

---
Tags: 8, webforms
---


title: How do I enable product revisions?

text:
# Question
Title: How do I enable product revisions?
I am using Drupal commerce 2 with Drupal 9. I added few products and I need to access their revisions, but there is no revision option for products in Drupal commerce.

How can I enable revisions for a product?

# Answer
> 2 votes
As of today, the answer is "You can't." The rationale is that the kinds of things people tended to do with revisions weren't really best solved by revisions within Drupal. Consider, for example, the challenges of representing referenced entities in other contexts (i.e. rendering a product title to an order page). There is no reference relationship that would ensure the appropriate revision of the product is loaded in the future, meaning what an order page shows may change over time accidentally / inappropriately.

While a patch is in progress for this (linked above in the comments), you should consider whether you *really* need revisions. If you merely want to log changes made to a product, you might consider some other mechanism instead.

---
Tags: commerce, 9
---


title: The view doesn't display products

text:
# Question
Title: The view doesn't display products
I've edited the default product type and added a taxonomy term reference field and added some products that reference my product categories.

The default taxonomy view isn't display my products, I believe because it just shows related nodes?!

How do I get the taxonomy view to display related products?

# Answer
Views are designed by default to query a single base table. You'll need to create your own product catalog View instead of trying to use the default one provided for listing content.
> 1 votes

---
Tags: views, commerce, taxonomy-terms, 9
---


# Question
Title: How do I stop Form Builder/API from filtering certain HTML tags from #prefix and #suffix on fields?
## **Summary:**

Drupal seems to be stripping certain html tags from the #suffix of Form API created fields and I can't figure out how to stop it.

## **Environment:**

Working in Drupal 8.9.13 with a minimum of modules.

## **Details:**

I don't know Drupal well, and I've been tasked with fixing a custom Form that was imported from Drupal 7. It's being built through the Form API stuff, i.e. https://www.drupal.org/node/268072 The form is using #prefix and #suffix to wrap a div around each field, but it's also adding several labels to the #suffix that are being used for validation notices (shown and hidden via jQuery). Unor

I can embed as many divs as I want in the #suffix, but it's stripping labels. I also tried spans, and those seem to be stripped too. `'#suffix' => '<div class="bupkis"><label>vegetable</label>cabbage</div></div>'),` is resulting in `<div class="bupkis">vegetablecabbage</div></div>`

I appreciate that this isn't probably the ideal way to manage validation, but it's what I have and it was working in Drupal 7. I don't have budget to rebuild it all, I just want to get it to work as-is in Drupal 8.

## **Attempted fixes:**

I've tried adding label and span to the 'Filtered HTML' format, in case it was using that as a default, but it didn't help.

I've tried Markup::create, i.e. `'#suffix' => Markup::create('<div class="bupkis"><label>vegetable</label>cabbage</div></div>'),` which I found in another stack overflow post... but that just causes a crash.

I've tried to find like a content type or something for this form, to see if I can adjust filters there... but there doesn't seem to be one. I think it's just dynamically generated, and there's no underlying pre-set structure?

# Answer
The filtering doesn't use a text filter format. It is filtered against Xss::$adminTags, which doesn't contain `<label>`.

If you are sure the string is safe you can put it in a Markup object to avoid XSS filtering:

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

...

  '#suffix' => Markup::create('<div class="bupkis"><label>vegetable</label>cabbage</div></div>'),

```

For this to work you have to add a use statement before the class or procedural function.
> 7 votes

---
Tags: 8, forms
---


# Question
Title: Redirect to Different URl on validation errors in form builder
I am using drupal 8 fapi and i have user case as below

I have a form on https://example.com/landing-page and I submit the form and there are validation errors .the page should reload as https://example.com/landing-page#lead-form.

Is there any hack we can implement?

I came with logic

if validation has error set form redirect page to example.com/landing-page#lead-form

```
if($form_state->getErrors() ) {
  $response = new TrustedRedirectResponse('example.com/landing-page#lead-form');
  $form_state->setResponse($response);
}

```

some how its not working.

Is there any way we can change the url to example.com/landing-page#lead-form and show the validation error at same time .

# Answer
> 0 votes
You can use like

For Internal:

```
global $base_url;
$response = new TrustedRedirectResponse($base_url.'/landing-page#lead-form');
// You can use any one of these below to show error message.
$form_state->setError($element, $message);
$form_state->setErrorByName($element, $message);
$form_state->setResponse($response);

```

For External: Use full link

```
$response = new TrustedRedirectResponse('https://facebook.com');
// You can use any one of these below to show error message.
$form_state->setError($element, $message);
$form_state->setErrorByName($element, $message);
$form_state->setResponse($response);

```

# Answer
> 0 votes
You can use EnforcedResponseException to terminate form processing and redirect:

```
$response = new RedirectResponse(Url::fromRoute('user.login', [], ['absolute' => TRUE])->toString());
throw new \Drupal\Core\Form\EnforcedResponseException($response);

```

For external urls use TrustedRedirectResponse not RedirectResponse:

```
$response = TrustedRedirectResponse('http://www.google.com');
throw new \Drupal\Core\Form\EnforcedResponseException($response);

```

---
Tags: 8, forms
---


# Question
Title: Is there a way to reduce or block webform submissions with foreign (non-English) content?
On Drupal 8/9 we have webforms that have been getting 5-20 spam/bot emails per day with foreign languages (looks like it may be Rusian). We have Honeypot, reCaptcha 2/3, Antibot, and Cloudflare setup but these messages still come through. I was wondering if there is a way to detect non-English characters and block the submissions?

An example of the body content of one of the submissions:

> Your Message Здесь собраны лучшие рассказы русских писателей. Дети обожают читать про приключения и веселые истории из жизни своих сверстников, а так же про забавных животных. Смешные диалоги, необычные сюжеты и яркие иллюстрации влюбляют в себя юных читателей с первых страниц.

# Answer
> 1 votes
Drupal allows you to alter a form using the `hook_form_alter()` hook. I work primarily in D7, but it looks like the same approach I'd take in 7 would work in 8/9.

You want to create a custom module and use hook\_form\_alter() to alter the validation part of the form. You want to check that whatever field you want to test against doesn't contain the characters you're getting.

The following is pseudo code, but hopefully can get you started in the right direction.

```
 function mymodule_myform_form_alter(&$form, &$form_state, $form_id){
      $form['#validate'][] = 'mymodule_myform_check_foreign_chars_validate';
 }

// callback function
function mymodule_myform_check_foreign_chars_validate(&$form, &$form_state){
      $char = "Д";
      $mystring = $form_state['values']['textfieldnametocheck'];

      // Test if text contains the word, character, etc, that you do not want
      if(strpos($mystring, $char) !== false){
      form_set_error('textfieldnametocheck', t('Certain characters not allowed.'));
  }

```

The gist is you want to find out the $form\_id of the form you want to alter. And, you want to add additional validation logic so that when the submit button is hit, your module applies that additional logic against the form validation process.

Above I'm testing for just one character, but you could create an array of characters to test against. It really doesn't matter what language it is, you just know the characters are not English or any language you're doing business in. You could add Chinese characters, Greek, etc should you get spam in other languages.

References:

How can I find the form ID of a form?

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21form.api.php/function/hook\_form\_alter/8.8.x

# Answer
> 0 votes
I got the answer from Reddit, for Drupal 8 webform you can create a conditional for the email handler and use a regex expression to check that the submission field (body) contains only English characters. The expression I used to enable the submission is:

^\[\s\x20-\xff\x{2000}-\x{206f}\]\*$

---
Tags: webforms
---


# Question
Title: How can I control block visibility with code?
In Drupal 6, I could control block visibility using PHP code in the block UI configuration like:

```
<?php return MYMODULE_abc() || MYMODULE_def() ; ?>

```

These functions looked up the current node, taxonomy, etc. to decide on whether to display the block. This PHP option is gone in Drupal 8, but there is a `$visibility` field in `BlockBase`. Can I use this to programmatically set the visibility at runtime?

# Answer
A working code snippet how to use `hook_block_access()`. Here I retrieve the condition from a field of the current node:

```
use Drupal\block\Entity\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;

/**
 * Implements hook_block_access().
 */
function MYMODULE_block_access(Block $block, $operation, AccountInterface $account) {

  if ($operation === 'view' && $block->getPluginId() === 'MYBLOCK') {

    $node = \Drupal::routeMatch()->getParameter('node');

    $hero_image_exists = FALSE;

    if ($node instanceof NodeInterface) {
      if ($node->hasField('field_hero_image')) {
        if (!$node->get('field_hero_image')->isEmpty()) {
          $hero_image_exists = TRUE;
        }
      }
    }

    return AccessResult::forbiddenIf($hero_image_exists === FALSE)->addCacheableDependency($block);
  }

  return AccessResult::neutral();
}

```

---

Thanks @Insasse for sharing the following gem in the comments. For programmatically created custom blocks you can control visibility directly from inside the block class via `blockAccess()`:

> ```
> class MyBlock extends BlockBase {
>   /**
>    * {@inheritdoc}
>    */
>   public function build() {
>     return [
>       '#markup' => $this->t('This is a simple block!'),
>     ];
>   }
>
>   /**
>    * {@inheritdoc}
>    */
>   protected function blockAccess(AccountInterface $account) {
>     return AccessResult::allowedIfHasPermission($account, 'access content');
>   }
>
> }
>
> ```

Source: How to Programmatically Create a Block in Drupal 8
> 26 votes

# Answer
Lacking the php filter in Drupal 8, this will no longer be possible from the UI.

The only option is to use the block api.

hook\_block\_access is your best canidate. From there you can check the `$operation` and return an AccessResult based on your conditions.

Just like in the UI only this time putting the php into a module.
> 8 votes

# Answer
For 8.2.x you need to create a **Condition Plugin** and implement the **ContextProviderInterface**.

See an example from D.O. but it is somehow outdated (because BlockEvent and BlockSubscriberBase removed in favor of a context repository service).

It would nice also to use Drupal console to generate the plugin:

```
drupal generate:plugin:condition

```
> 5 votes

# Answer
Here is the Drupal 8 solution: Block Exclude Pages.

> **This module adds an exclude pages filter for blocks.**
>
> To exclude specific pages after the wild card or in between wildcards, simply prefix the path pattern with a prefixed '!' in the block page visibility configuration.
>
> This works for visibility set to "show for the listed pages", in this case, the exclude paths will hide the block on pages that match the despite the wildcard set to show.
>
> Or the other way around, if the page list is set to "hide for the listed pages" the excluded paths will show the block on pages where the pattern matches despite the wild card set to hide.
> 5 votes

# Answer
to extend block visibility possibilities you can try this patch:

https://www.drupal.org/project/drupal/issues/923934#comment-12401360

it introduces the *AND* / *OR* conjunction operator for the visibility conditions so you can say oh I want this block visible if it is of my\_content\_type *OR* user has admin role *OR* the url starts with my/path/to/\* etc.. also the conditions could be negated so you can set a lot of conditions at which you don't want your block to be visible

also if you use the Drupal Commerce module you can try the above by installing the https://www.drupal.org/project/commerce\_quick\_purchase module note that being installed the module exposes this functionality for all blocks on the system even if you don't use the block provided by the module see more

https://github.com/drugan/commerce\_quick\_purchase#block-visibility

additionally you can create your own condition plugin see example from the module

https://cgit.drupalcode.org/commerce\_quick\_purchase/tree/src/Plugin/Condition
> 1 votes

# Answer
Drupal 8, 9 and 10 have an improved 'path' condition for all content that implement Drupal Conditions: Condition Path

It allows included and excluded paths simultaneously to control block or other content visibility. It acts like the mentioned Block Exclude Pages module, but is more generic and leverages the Drupal Condition plugin API.
> 1 votes

---
Tags: 8, blocks
---


# Question
Title: How can I change the label on the "Add media" button in media field widget?
I would like to change the label on the button named "Add media" on the media field widget. For instance to write "Add image" or "Add document". How can I change it?

# Answer
> 1 votes
During the form construction process, there are a bunch of times that Drupal allows your own modules to hook in and alter things like this.

Here's one, which you would implement in a custom module, that hooks in when the media library widget is being prepared and alters it everywhere it's used:

```
function MYMODULE_field_widget_media_library_widget_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
  $element["open_button"]["#value"] = t('Add image');
}

```

Here's another one that hooks in during the construction of any node form, which might be more appropriate if I only want to make this change for a particular field or entity type:

```
function MYMODULE_form_node_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (isset($form["field_my_media"])) {
    $form["field_my_media"]["widget"]["open_button"]["#value"] = t('Add image');
  }
}

```

---
Tags: forms, media, 9
---


# Question
Title: Proper way to get input field value with AJAX
I want to do some calculations in node edit form vith ajax. Form fields is created via UI, so i need to drill into field array to get value(s). Maximum result what i have is replacing target field with result of #defaul\_value of source fields. Nothing happens when i change source.

```
<?
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;

function module_form_alter(&$form, &$form_state, $form_id) {

    $form['field_source']['widget'][0]['value']['#ajax']  = array(
        'callback' => 'myAjaxCallback',
        'method' => 'replace',
        'effect' => 'fade',
        'event' => 'change',
        'wrapper' => 'calc',
    );

    $form['field_source2']['widget'][0]['value']['#ajax']  = array(
        'callback' => 'myAjaxCallback',
        'method' => 'replace',
        'effect' => 'fade',
        'event' => 'change',
        'wrapper' => 'calc',
    );

    $form['field_target']['#prefix'] = '<div id="calc">';
    $form['field_target']['#suffix'] = '</div>';
    $form['field_target']['#disabled'] = TRUE;

 /* some calculations */
    $s1 = $form['field_souce']['widget'][0]['value']['#default_value']; /*  HOW TO GET PROPER SOURCE VALUES "ON FLY" WHEN EDITOR CHANGES IT? */
    $s2 = $form['field_souce2']['widget'][0]['value']['#default_value'];
    $result = $s1 * $s2;

    $form['field_target']['widget'][0]['value']['#default_value'] = $result;
}

function myAjaxCallback($form, FormStateInterface $form_state)  {
   return $form['field_target'];
}

```

Calculations gives result, but only with values which already submitted, so when i change source values AJAX firing & fading, but nothing happens whith target. What i try is get values with:

```
$s1 = $form_state->getValue('source'); <-- gives "0" $result
$s1 = $form['field_souce']['widget'][0]['value'] <-- get error Unsupported operand types

```

# Answer
found a way to get input value

```
$values = $form_state->getUserInput();
$s1 = $values['field_source']['0']['value'];
$s2 = $values['field_source2']['0']['value'];

```
> 0 votes

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


# Question
Title: hook_preprocess_field() $variables crashing while printing
I am trying to modify a file field value and add a download svg icon and then add it to a twig file by using a preprocess field.

```
function my_preprocess_field(&$variables) {
  if ($variables['element']['#field_name'] == 'field_download') {
    print_r($variables);
  }
}

```

I am not sure what I am doing wrong here but the variable is not loading and it is timing out (memory exhaustion)

# Answer
Use Devel with vardumper and dump only the `$element` instead of the whole `$variables` something like:

```
function myfi_preprocess_field(&$variables) {
  $element = $variables['element'];
  if ($element['#field_name'] == 'field_download') {
    // Dump only the element.
    dpm($element);
  }
}

```
> 0 votes

# Answer
If you have installed devel module, you can enable kint module. In your code you can use the `kint()` function to print the variable...

Example:

```
function myfi_preprocess_field(&$variables) {
    if ($variables['element']['#field_name'] == 'field_download') {
        kint($variables);
    }
}

```
> 0 votes

# Answer
The other two answers are perfectly fine, but short of enabling development-specific modules, you can sometimes get by in the short term by only printing the keys of the array, rather than the entire array;

```
print_r(array_keys($variables));

```

After seeing what keys are available, you could then print\_r() just the particular key that you're looking for within $variables to see what's in it.
> 0 votes

---
Tags: 8
---


title: permissions for fillpdf URL

text:
# Question
Title: permissions for fillpdf URL
I'm using the FillPDF module and the FillPDF online service to render the PDFs. Everything works fine provided I'm logged in as the site admin; however, when I'm logged in as a std. user, I get an access denied when I click on the fillpdf link.

The link looks like: /fillpdf?fid=4&entity\_id=entity\_name:659441

I have not created a route for this URL but I'm thinking that's what I need to do? Am I on the right track?

Thanks, P

# Answer
> 0 votes
If it's working for you when you're an admin, then it's unlikely that you'll need to create a route - there's already a route working for some class of user.

Check that you've gone to the Permissions admin page and configured the module's permissions correctly; this is often overlooked after installing new modules. Then maybe check to make sure that the standard user can access entity 659441 normally; if any of the entities used in the FillPDF request are not accessible to a particular user, then it's highly likely the request will be denied.

---
Tags: routes
---


title: Incorporating logs into Splunk

text:
# Question
Title: Incorporating logs into Splunk
As of now we are running Drupal 8 and we would like to send the Drupal logs to Splunk. I have researched several plugins for Drupal that did such a thing, unfortunately they were all for Drupal 7 and not compatible with Drupal 8.

I have looked into building my own module to do this, but its the triggering of this module where I am at a lost. It seems these modules are triggered via an URL endpoint such as /site/login. This isnt exactly what is wanted, essentially anytime Drupal logs information we want to send that out to Splunk.

Any ideas on how to implement this?

Thanks guys.

# Answer
In Drupal 8 you may define your own logger implementation to do whatever you want with log messages. The default logger provided by core Drupal saves these messages in the Drupal database and makes them available in the UI at `/admin/reports/dblog`. This default logger is implemented in the core dblog module by the logger class `\Drupal\dblog\Logger\DbLog`, and that's a great example to use when you write your own.

A logger is a class that implements `LoggerInterface` and is used as a service with the 'logger' service tag. **All** registered loggers are used for every channel. You don't need to 'trigger' a logger or do anything special to have that logger automatically used by core Drupal, other than tagging the service.

The service definition for the core DbLog logger looks like this (from dblog.services.yml):

```
services:
  logger.dblog:
    class: Drupal\dblog\Logger\DbLog
    arguments: ['@database', '@logger.log_message_parser']
    tags:
      - { name: logger }
      - { name: backend_overridable }

```

You can see that the `logger.dblog` service is implemented by the `DbLog` class, and this service is tagged as a logger. That tag is how Drupal knows to send log message to this service. Without the tag, Drupal wouldn't know this service was a destination for log messages.

Another good example in core is the core syslog module, which provides a logger that uses the PHP `syslog()` function to send messages to an operating-system-dependent location (probably a flat text file shared by all other programs that log messages on that operating system).

To make your own 'Splunk' logger, you would create a module that defines a logger service, for example `logger.splunk`. (Services are defined in the module's `<modulename>.services.yml` file.) You must have a class, for example 'Splunk' that implements `LoggerInterface`. In that 'Splunk' class you may use the Splunk API to send log messages to Splunk. The details of how to do that is up to you as it has nothing to do with Drupal at this point. If you have code that sends log messages to Splunk from a standalone program then I think it is pretty clear from examples provided by core how to use that code in your logger class.

Your module will consist of a `<modulename>.info.yml` file, a `<modulename>.services.yml` file, and a `<modulename>/src/Logger/Splunk.php` file. Nothing more is needed. If you've done it right, then when you enable your module all messages should be logged to Splunk.
> 2 votes

# Answer
I'm not sure about Splunk in partcular, but Drupal core has the syslog module that outputs log information to a flat file on the server, which Splunk could maybe then consume.
> 1 votes

---
Tags: 8, log-messages
---


# Question
Title: how to get translation of taxonomy term in a preprocess function
I am using `MYTHEME_preprocess_views_view` to assign the taxonomy term as the page title for all the entries of a content type. it's working fine but the issue is when I switch the language from English to Arabic the page content is translating correctly but the title still remains in English. While I have translated all the taxonomy terms. Here is my code.

```
/* Preprocess Function to print the taxonomy term as title for media_center bundle */
function kmtheme_preprocess_page_title(&$variables) {
  $node = \Drupal::request()->attributes->get('node');
  if ($node && $node->hasField('field_media_center') && !$node->field_media_center->isEmpty()) {
  }

  if ($node && $node->bundle() == 'media_center') {
    $term = \Drupal\taxonomy\Entity\Term::load($node->get('field_media_center')->target_id);
    $term_name = $term->getName();

    $variables['title'] = t($term_name);
  }
}

```

I want to get the translated value of the taxonomy term when the language switch from English to Arabic.

# Answer
> 1 votes
```
function MYTHEME_preprocess_page_title(&$variables) {

  // Get node.
  $node = getNode($variables);

  // Check for node and field.
  if ($node && $node->hasField("field_name") && !$node->get('field_name')->isEmpty()) {

    // Get term ID.
    $term = \Drupal\taxonomy\Entity\Term::load($node->get('field_name')->target_id);

    // Get current langcode.
    $langCode = \Drupal::languageManager()->getCurrentLanguage()->getId();

    // Check for translation.
    if ($term->hasTranslation($langCode)) {

      // Get term from context.
      $term = \Drupal::service('entity.repository')->getTranslationFromContext($term, $langCode);
    }

    // Get term name.
    $termName = $term->getName();

    // Set term name as title.
    $variables['title'] = t($termName);
  }
}

```

---

```
// I like checking for node contexts but not necessary for this question.
function getNode($variables = NULL) {

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

  // $variables['node'].
  if (isset($variables['node'])) {
    if (is_numeric($variables['node'])) {
      return \Drupal::entityTypeManager()->getStorage('node')->load($variables['node']);
    }
    return $variables['node'];
  }

  // $variables['row'].
  if (isset($variables['row']) && !empty($variables['row']->nid)) {
    return \Drupal::entityTypeManager()->getStorage('node')->load($variables['row']->nid);
  }

  // Node canonical.
  if ($routeName === 'entity.node.canonical') {
    return \Drupal::routeMatch()->getParameter('node');
  }

  // Node revision.
  if ($routeName === 'entity.node.revision') {
    $revisionId = \Drupal::routeMatch()->getParameter('node_revision');
    return node_revision_load($revisionId);
  }

  // Node preview.
  if ($routeName === 'entity.node.preview') {
    return \Drupal::routeMatch()->getParameter('node_preview');
  }

  return NULL;
}

```

---
Tags: transliteration
---


# Question
Title: ArgumentCountError: Too few arguments to function LetterQueryClient::__construct(), 0 passed and exactly 1 expected
I am trying to make a plugin that connects to a json endpoint on another drupal site. But im getting an error in my service class. Please help me understand what im doing wrong.

This is my service declaration in services.yml inside the module folder:

```
services:
  letter_query_client:
    class: Drupal\******\Plugin\views\LetterQueryClient
    argument: ['@http_client_factory']

```

This is my service class:

```
namespace Drupal\*******\Plugin\Views;

use Drupal\Component\Serialization\Json;

class LetterQueryClient {

  /**
   * @var \GuzzleHttp\Client
   */
  protected $client;

  /**
   * LetterQueryClient constructor.
   *
   * @param $http_client_factory
   */
  public function __construct($http_client_factory) {
    $this->http_client_factory = $http_client_factory;
    $this->client = $http_client_factory->fromOptions([
      'base_uri' => '**********',
    ]);
  }

  public function getLetters() {
    $response = $this->client->get('********');
    $data = Json::decode($response->getBody());
    return $data;
}

}

```

This is my views query:

```
<?php

namespace Drupal\*****\Plugin\views\Query;

use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\views\ResultRow;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\Annotation\ViewsQuery;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Views query plugin
 *
 * @ViewsQuery(
 *   id = "views_*****",
 *   title = @Translation("Letter Query"),
 *   help = @Translation("Query against the API.")
 * )
 */

class ViewsLetterQuery extends QueryPluginBase implements ContainerFactoryPluginInterface {

  public function ensureTable($table, $relationship = NULL) {
    return '';
  }

  public function addField($table, $field, $alias = '', $params = []) {
    return $field;
  }

  /**
   * @var \Drupal\******\Plugin\views\LetterQueryClient
   */
  protected $LetterQueryClient;

  /**
   * ViewsLetterQuery constructor.
   *
   * @param array $configuration
   * @param $plugin_id
   * @param $plugin_definition
   * @param $LetterQueryClient
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, $LetterQueryClient) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->letter_query_client = $LetterQueryClient;

  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('letter_query_client')

    );
  }

  public function execute(ViewExecutable $view) {
    $index = 0;
    if ($letter_items = $this->LetterQueryClient->getLetters()) {
      foreach ($letter_items as $letter_item) {
        $row['title'] = $letter_item['title'];
        $row['field_note'] = $letter_item['field_note'];
        $row['index'] = $index++;
        $view->result[] = new ResultRow($row);

      }

    }

  }

}

```

# Answer
You *must* type-hint the parameters of your service's constructor, otherwise Symfony's auto-wire will not work:

```
namespace Drupal\*******\Plugin\Views;

use Drupal\Component\Serialization\Json;

class LetterQueryClient {

  /**
   * @var \GuzzleHttp\Client
   */
  protected $client;

  /**
   * LetterQueryClient constructor.
   *
   * @param $http_client_factory
   */
  public function __construct(Drupal\Core\Http\ClientFactory $http_client_factory) { // type-hint here
    $this->http_client_factory = $http_client_factory; // side note: this member variable is not defined
    $this->client = $http_client_factory->fromOptions([
      'base_uri' => '**********',
    ]);
  }

```

see https://symfony.com/doc/current/service\_container.html#injecting-services-config-into-a-service
> 1 votes

---
Tags: 9
---


title: Rules Custom Field

text:
# Question
Title: Rules Custom Field
I am developing a Drupal site, where the administrator creates user accounts. Indeed for this site the administrator creates user accounts, he fills in the fields with the strict minimum (Last name, First name, Mail).

When the user logs in, I would like the site to force him to fill in the remaining fields of the profile.

For this I wanted to use the Rules module, with:

* **Event**: User has logged in
* **Condition:** Data value is empty: ***Custom Field***
* **Action:** Page redirect (user/\[account: uid\]/edit)

The problem I am having is that I cannot access my customs fields in the data selector.

*Anyone know how to access my customs fields in Rules ?*

# Answer
> 0 votes
The event 'User has logged in' puts into context the user entity for the user who has just logged in. The user entity by itself has no fields. The user entity with added fields is known as a bundle.

To expose the fields of the bundle to Rules you need to use the 'Entity is of bundle' condition. This condition takes three inputs:

1. The specific entity you are checking. In your use case this should be the 'account' variable selected using the data selector.
2. The entity type. This should be the machine name of the entity type selected in 1), which in your case is 'user', entered with direct input.
3. The machine name of the bundle. Again, this will be 'user', entered with direct input.

Any conditions or actions added after this 'Entity is of bundle' condition will now have access to custom user fields.

The above steps are needed to expose the fields of any bundle to Rules - this is not just for the 'user' entity.

---
Tags: 8, entities, rules
---


title: Webform Add More for grouped elements

text:
# Question
Title: Webform Add More for grouped elements
I'm building a Webform in Drupal 8. One section has repetitive grouped elements that could be added more than once. For instance, it's something like:

Where they could add more if they want. If this was a node, I'd use Paragraphs to create a bundle for the language name, writing proficiency and speaking proficiency, and they'd be able to add as many as they like. I'm not sure how to do it in the new D8 Webform module though. I know something like Webform Add More kinda works (though, it's really just hiding a preset number fieldsets until they're needed, not creating them dynamically), but I can't figure out anything else even close to that.

Should I just make a set, static number? Or is there another way? I know Webform is totally different now in D8, with YAML config files and how the data is stored; should I try to just make my own custom field in code?

# Answer
If I gather correctly what you are asking then you are hitting https://www.drupal.org/node/2824714 . You need to write your own composite element, webform for now doesn't support this.
> 1 votes

# Answer
Webform now has the way of creating Custom Composite elements from the UI that can be marked as unlimited. There are also various settings about layout, add more buttons, etc...

It's been worked on under this ticket: https://www.drupal.org/project/webform/issues/2916573
> 0 votes

---
Tags: 8, webforms
---


# Question
Title: Options for storing API keys in config files?
I'm working on a project that's using Drupal Commerce and wondering about the possible options to secure the API keys exported as configuration YAML files.

We have the config directory outside of the web root and are fairly careful overall with security, but we currently have those committed to our private Git repository - should those be removed from the repository entirely, regenerated, and added to `.gitignore`?

# Answer
I use the Key module, combined with the Config Split module. You can set up the key module to use a file to store the API values. You can then use the config split module to create a conditional split on the configuration created for your production server. Put the values in the file on the production server, but do not commit that file to GIT. That way it is only on your production server, and not part of the GIT repository. For other non-production environments you can store test data in configuration rather than in a file, so that your test (sandbox) data can be committed to GIT.
> 3 votes

---
Tags: commerce, configuration, 9
---


title: How can I add an accordion?

text:
# Question
Title: How can I add an accordion?
I would like to create an accordion using the Drupal 9 webform. Any suggestions on how it should be done? Thanks

# Answer
> 3 votes
When adding a webform component, look in the Containers section and add a "Details" container to your form. This should give you an accordion-like behavior using HTML5 details/summary elements.

---
Tags: webforms, 9
---


# Question
Title: How to display a block on only the listed pages using wildcard and excluding subpages?
I have a block I'm displaying using block setting's "Only the listed pages". I'm using a wild card asterisk to show the block on any pages following `about-us/`. For example: `about-us/*`

The problem is I ONLY want pages immediately after `about-us/` to show. For example `about-us/faq` would show the block but `about-us/faq/content` should NOT show the block.

I tried `about-us/*/` but that had no effect.

Any suggestions?

# Answer
> 6 votes
**Method 1. PHP filter**

I think your question is partially answered here:

How to add page restrictions for blocks in drupal?

Only you might use this code:

```
<?php
$arg = explode('/', drupal_get_path_alias());
if ($arg[0] == 'about-us' && $arg[1] && $arg[2] == NULL) {
  return TRUE;
}
else {
  return FALSE;
}
?>

```

**Method 2: Context module**

Alternatively, you can try the Context module, which offers more robust visibility options. For instance, in addition to including paths you can prefix a path with a tilde "~" to *exclude* it.

I think this should do it:

```
about-us/*
~about-us/*/*

```

*Edit: Added second method.*

*Edit: Using $\_GET\['q'\] in method 1 instead of arg() (Thx, @leymannx!)*

# Answer
> 3 votes
Drupal 8 - Simple module to achieve this: https://www.drupal.org/project/block\_exclude\_pages

Simply add the path you want to exclude with a '!' Prefixed.

Example:

!/path/this

# Answer
> 1 votes
Set your block display settings to show on about-us/\* then add the following hook to your module.

```
<?php
/**
 * Implements hook_block_list_alter().
 */
function my_module_block_list_alter(&$blocks) {
  $alias = explode('/', drupal_get_path_alias());
  if ($alias[0] == 'about-us' && isset($alias[1]) && isset($alias[2])) {
    // unset the bid (block id)
    unset($blocks[55]);
  }
}
?>

```

*Edit: fixed condition - arg() doesn't return alias.*

# Answer
> 1 votes
In Drupal 8, you can use the Block Visibility Groups module to very easily combine multiple conditions for one or many blocks. For this case, you can add a page `[path]/*` condition and a negative `[path]/*/*` condition.

# Answer
> 0 votes
Using PHP filter module In Block settings \> Pages: check

> Pages on which this PHP code returns TRUE (experts only)

Paste this:

```
<?php
return preg_match('/^about-us(\/[a-z]*)?(\/)?$/',
drupal_get_path_alias($_GET['q']));
?>

```

# Answer
> 0 votes
There is another alternative to answer this question ... ***which doesn't require the PHP filter to be enabled*** (which you should try to avoid whenever possible) ... Just use the Rules block visibility module. Here is a quote from its project page:

> The Rules block visibility module allows Rules components to be used to control block visibility. This provides Drupal administrators and developers extreme flexibility in controlling when blocks should be displayed on their websites, in addition to the default visibility options provided by Drupal.
>
> The general idea is that if you can do it with Rules, you can use it to control block visibility, so the possibilities are limitless.
>
> Need to show a block only for users registered more than a month ago?
>
> Perhaps you have a block that must be shown only between 8am-5pm on weekdays?
>
> What about displaying or hiding a block based on current weather conditions?
>
> All of this can be done by using Rules block visibility.

With that, and as per the "*if you can do it with Rules, you can use it to control block visibility*" above, you've reduced your question to making Rules "***check the path of the current page***" (so that the block is only shown on your pages with a path that **starts with** "`about-us/`", but not on those pages that have a path like "`about-us/*/*`").

For an illustration of how to use this module, refer to my answer to "How to stop a Views block from displaying to admins, such as user/1?". It includes a Rules Component (in Rules export format), which you should replace by this variation of it to make it match your specific question):

```
{ "rules_block_visibility_show_on_selected_profile_pages" : {
    "LABEL" : "Show block on selected profile pages",
    "PLUGIN" : "rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules" ],
    "USES VARIABLES" : {
      "module" : { "label" : "Module", "type" : "text" },
      "delta" : { "label" : "Delta", "type" : "text" },
      "result" : { "label" : "Result", "type" : "boolean", "parameter" : false }
    },
    "IF" : [
      { "AND" : [
          { "text_matches" : {
              "text" : [ "site:current-page:path" ],
              "match" : "about-us\/",
              "operation" : "starts"
            }
          },
          { "NOT text_matches" : {
              "text" : [ "site:current-page:path" ],
              "match" : "about-us(\/[a-z]*)?(\/)?$/",
              "operation" : "regex"
            }
          }
        ]
      }
    ],
    "DO" : [ { "data_set" : { "data" : [ "result" ], "value" : "1" } } ],
    "PROVIDES VARIABLES" : [ "result" ]
  }
}

```

**Note**: the 2nd Rules Condition in the above Rules Component (with the regular expression in it) may need further refinements to perfectly fit your case. I.e. the "`about-us(\/[a-z]*)?(\/)?$/`" part of it (though I think it's pretty close to what your question is about).

# Answer
> 0 votes
The go to Drupal 8/9/10 solution for both including and excluding pages at the same time is the Condition Path module.

It uses the condition plugin API which makes it useful for all content implementing conditions (such as blocks).

**Example:** To show a block on all product pages but not on the subpage 'reviews', add the following pages in the condition:

* /products/\*
* !/products/\*/reviews

---
Tags: blocks, uri
---


# Question
Title: getvalue() of multiple values field return only the first value
I added a new field in the field manage user page. This is a sample integer multivalue field. (we can enter several integer)

I edited the profile of the admin user. I added (and save) some values in this field :

```
42
66
23
77

```

In a custom module, I load the current user and I want display all values of my integer multivalue field :

```
// Load the current user.
$user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());

// Get field data from that user.
$mycustomfield = $user->get('field_mycustomfield');

```

but when I print $mycustomfield-\>getValue(), I get only the first value :

```
// Display values
kint($mycustomfield->getValue()); // return only 42, but I want get 42, 66, 23, 77

```

How can I get ALL values of a custom field ?

Thanks :)

**EDIT**

I try this ...

```
// Load the current user.
$user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());

// Set and save field data from that user.
$user->get('field_mycustomfield')->setValue(array(1,2,3,4,5));
$user->save();

// And display
$user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
$user_mycustomfield = $user->get('field_mycustomfield')->getValue();

kint($user_mycustomfield); // print array(1.2.3.4.5) x)

```

With a new user, if I set several values from his user profile edit page, getValue() return only the first value

But if I set several values via the api, I can get all values with getValue

It's really strange..

# Answer
> 5 votes
Drupal fields are represented by the `ItemList` class (whether they're multi-valued or not). The convenience method `getValue()` iterates through each item's `getValue()` method to build an array representation of the data value.

To retrieve a string representation of all the items in the list, you can use `ItemList::getString()`, which iterates through all the list items and calls `getString`() on each, then implodes them using `", "` for glue.

So, for your example:

```
var_dump($user->field_mycustomfield->getString());

```

will output

```
string(14) "42, 66, 23, 77"

```

# Answer
> 4 votes
```
$user->get('field_mycustomfield')->getValue();

```

# Answer
> -2 votes
```
/** @var \Drupal\Core\Datetime\DrupalDateTime $date */

// Get the default timezone
$default_timezone = new \DateTimeZone(date_default_timezone_get());
// Set some date/time objects
$now = new \DateTime('now', $default_timezone);
$now = \Drupal\Core\Datetime\DrupalDateTime::createFromDateTime($now);
print_r($now);
exit;

```

---
Tags: 8, entities
---


# Question
Title: If folders don't exist in URI path, file_save_data() fails
I am programmatically importing images and saving them via file\_save\_data();

```
$fileContentsPath = 'http://mypathtofile.com';
$uri = 'public://myfolder/mysecondfolder/filename.jpg';
$image = file_get_contents($fileContentsPath);
$file = file_save_data($image, $uri, FILE_EXISTS_REPLACE);

```

When I run this I get the following error: The specified file temporary://fileJ4LL4o could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.

I am pretty sure my temporary directory is configured correctly and the files folder is assigned to the apache user.

If I go into the files directory and make the directories (myfolder/mysecondfolder) via command line and rerun it works correctly.

So the problem is that if the folders don't exist from the $uri path, it fails instead of creating the folders.

# Answer
> 2 votes
I ended up using a function that creates the folders if needed. I copied what Patrick had here.

```
/**
 * Download external file.
 *
 * @param string $url       Full url to file to download.
 * @param string $uri       Drupal uri of where to save file
 *                          public://archive/test.pdf.
 * @param int $save_mode    File save mode from drupal core
 *                          Ex: FILE_EXISTS_REPLACE.
 *
 * @return mixed $new_file  The file object.
 */
function xcms_import_download_external_file($url, $uri, $save_mode = FILE_EXISTS_RENAME, $manage_file = TRUE) {

  $url_info = parse_url($url);
  $url_path_info = pathinfo($url_info['path']);

  // This helps with filenames with spaces
  $url = $url_info['scheme'] . '://' . $url_info['host']  . $url_path_info['dirname'] .'/'. rawurlencode($url_path_info['basename']);

  // Need to remove the filename from the uri
  $uri_target = file_uri_target($uri);
  $uri_scheme = file_uri_scheme($uri);
  $uri_path_info = pathinfo($uri_target);
  $directory = file_stream_wrapper_uri_normalize($uri_scheme . "://" . $uri_path_info['dirname']);

  if (file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
    $drupal_result = drupal_http_request($url);
    if (!empty($drupal_result->data)) {
      $path = file_stream_wrapper_uri_normalize($uri);
      if ($manage_file) {
        $new_file = file_save_data($drupal_result->data, $path, $save_mode);
      }
      else {
        return file_unmanaged_save_data($drupal_result->data, $path, $save_mode);
      }
    }
    else {
      drupal_set_message("Error downloading file, no data recieved for " . $url);
      return FALSE;
    }

    $new_file->display = 1;
    return (array)$new_file;
  }
  else {
    return FALSE;
  }
}

```

# Answer
> 9 votes
In drupal 8.7.0 and above (Drupal 9), `file_prepare_directory()` is deprecated.

Instead, use `FileSystemInterface::prepareDirectory()` : https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21File%21FileSystemInterface.php/function/FileSystemInterface%3A%3AprepareDirectory/8.8.x

In my case, I did :

```
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$directory = 'temporary://exports/';
$file_system->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);

```

# Answer
> 8 votes
I Noticed Similar issue while saving files using

```
 file_save_data();

```

In Drupal 8.

First I gave only first level directory to save the file as

```
$file = file_save_data($object->vertex_data, 'public://vertex_data.txt', FILE_EXISTS_REPLACE);

```

This worked fine.

But when I tried saving the file inside a subfolder as

```
$file = file_save_data($object->vertex_data, 'public://objects/vertex_data.txt', FILE_EXISTS_REPLACE);

```

it gave me the following Error :

```
File temporary://fileh1Gpl2 could not be moved/copied because the destination directory public://objects/ is not configured correctly.

```

The Solution for this is simple. Just use file\_prepare\_directory();

```
$directory = 'public://objects/'
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
$file = file_save_data($object->vertex_data,  $directory . 'vertex_data.txt', FILE_EXISTS_REPLACE);

```

This, first creates the folder if it does not exists and then proceeds to save the respective file.

---
Tags: files
---


# Question
Title: Language switcher block is different on remote site
I'm working on a multilingual site and on my local version of the site I added the default language switcher. It show like this:

```
<div class="language-switcher-language-url block block-language block-language-blocklanguage-content" id="block-languageswitchercontent" role="navigation">
        <div class="content">
            <ul class="links">
                <li class="en is-active" data-drupal-link-system-path="<front>">
                    <a class="language-link is-active" data-drupal-link-system-path="<front>" href="/" hreflang="en">English</a>
                </li>
                <li class="fr" data-drupal-link-system-path="<front>">
                    <a class="language-link" data-drupal-link-system-path="<front>" href="/fr/a-propos" hreflang="fr">Français</a>
                </li>
            </ul>
        </div>
    </div>

```

And when I click the link to go to the french version of the site I am send to the `/fr/a-propos` page. Just like I'd expect.

Now I pushed my site update to my remote server. Looking at the code there. I see the switcher is different:

```
<div class="language-switcher-language-content-entity block block-language block-language-blocklanguage-content" id="block-languageswitchercontent" role="navigation">
    <div class="content">
        <ul class="links">
            <li class="en" data-drupal-link-query="{"language_content_entity":"en"}" data-drupal-link-system-path="node/4">
                <a class="language-link" data-drupal-link-query="{"language_content_entity":"en"}" data-drupal-link-system-path="node/4" href="/">English</a>
            </li>
            <li class="fr" data-drupal-link-query="{"language_content_entity":"fr"}" data-drupal-link-system-path="node/4">
                <a class="language-link" data-drupal-link-query="{"language_content_entity":"fr"}" data-drupal-link-system-path="node/4" href="/fr/a-propos">Français</a>
            </li>
        </ul>
    </div>
</div>

```

The language switcher has a different class not `language-switcher-language-url` but `language-switcher-language-content-entity` so my styling is off. I changed to using the ID instead so the styling problem is fixed. but still strange things are happening. Sometimes when I click a link in the switch the url has the `language_content_entity` as parameter. And currently the active state of the language switch is not working on the remote site?

Using git both sites are exactly the same. The config is the same on both sites and I cleaned cache on my remote site.

Why is this code different on my remote site?

# Answer
The answer 4k4 gave was the right one:

*Language switching is based on language detection methods and what you've described are simply two different methods you have enabled. Normally you only need the path based method. If you have multiple methods enabled you have to be prepared that they are used depending on the context the page is built in.*
> 1 votes

# Answer
Possible reason:

1. Maybe you are not in the same page.
2. You dont have the same configuration

Solution:

We suggest you add your own custom class or container div. And from these, add the correct CSS.
> 0 votes

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


title: Unit Testing Mock Guzzle Response

text:
# Question
Title: Unit Testing Mock Guzzle Response
I'm trying to test a method that makes an HTTP request via Guzzle, so I can see if my code that filters that response is working. I have a mock json response in a json file that I want to use to test it. This is simply a saved version of an actual response.

I know you can mock methods e.g. this would override the get method to return a mock Guzzle Response. How do you mock a Guzzle response in Drupal 8?

```
    $this->mockHttp->expects($this->any())
      ->method('get')
      ->willReturn($mockGuzzleResponseShouldGoHere);

```

The mock Guzzle response needs to have a mock method getBody so I can do something like this:

```
$this->mockHttp->expects($this->any())
      ->method('getBody')
      ->willReturn(__DIR__ . 'Mocks/membership-classes.json');

```

and make sure that getBody returns my mock json file.

**Method to test that makes a Http Guzzle request**

```
<?php

/**
   * Call the GetMembershipClasses service.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   */
  public function getMembershipClasses() {

    try {
      // Load configuration for this module.
      $response = $this->http_client->get(
        $this->getBaseUrl() . '/2014/06/membershipClasses', [
          'headers' => $this->getAnonymousHeaders(),
        ]);

        $response = json_decode($response->getBody());

        // Get to the meat of the response.
        $response = $response->GetMembershipClassesResponseMessage->MembershipClasses->MembershipClass;

        // Validate returned data.
        $filtered = array();
        foreach ($response as $membership_class) {
          $membership_class->MembershipClassCode = $this->removeSpaces($membership_class->MembershipClassCode);
          if ($membership_class->IsActive === TRUE) {
            $filtered[] = $membership_class;
          }
        }
        return new JsonResponse($filtered);
    }
    catch (RequestException $e) {
      return $this->handleError($e);
    }

  }

```

**And the test class**

```
<?php

/**
 * Class RouteControllerAnonymousTest.
 *
 */
class AnonymousWebServicesTest extends UnitTestCase {

  /**
   * Mock of http_client service.
   *
   * @var \GuzzleHttp\Client
   */
  protected $mockHttp;

  /**
   * Mock of state service.
   *
   * @var \Drupal\Core\State\State
   */
  protected $mockState;

  /**
   * Mock of config.factory service.
   *
   * @var \Drupal\Core\Config\ConfigFactory
   */
  protected $mockConfigFactory;

  /**
   * Set up method which is called before any tests are
   * run. Mocks of the services that the class being tested rely on are
   * created.
   *
   * @return void
   */
  protected function setUp() {

    parent::setUp();
    $mockHttp = $this
      ->getMockBuilder('GuzzleHttp\Client')
      ->disableOriginalConstructor()
      ->setMethods(['get', 'getBody'])
      ->getMock();
    $this->mockHttp = $mockHttp;

    $mockState = $this
      ->getMockBuilder('Drupal\Core\State\State')
      ->disableOriginalConstructor()
      ->getMock();
    $this->mockState = $mockState;

    $mockConfigFactory = $this
      ->getMockBuilder('\Drupal\Core\Config\ConfigFactory')
      ->disableOriginalConstructor()
      ->getMock();
    $this->mockConfigFactory = $mockConfigFactory;

  }

  /**
   * Test the getMembershipClasses method.
   */
  public function testGetMembershipClasses() {

    // This needs to mock a Guzzle response from a get request
    $this->mockHttp->expects($this->any())
      ->method('get')
      ->willReturn('The mock guzzle response should go here);

    $this->mockHttp->expects($this->any())
      ->method('getBody')
      ->willReturn(__DIR__ . 'Mocks/membership-classes.json');

    $anonymousWebServices = new AnonymousWebServices(
      $this->mockHttp,
      $this->mockState,
      $this->mockConfigFactory
    );

    $membership_classes = $anonymousWebServices->getMembershipClasses();
    var_dump($membership_classes);
    // Insert some assert statement here

  }

}

```

# Answer
> 10 votes
Guzzle includes a mock handler that lets you provide a mock HTTP response. Docs are at http://docs.guzzlephp.org/en/latest/testing.html. Here's how you might use it in your unit test:

```
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;

/**
 * Test the getMembershipClasses method.
 */
public function testGetMembershipClasses() {

  $body = file_get_contents(__DIR__ . '/Mocks/membership-class.json');
  // This sets up the mock client to respond to the first request it gets
  // with an HTTP 200 containing your mock json body.
  $mock = new MockHandler([
    new Response(200, [], $body),
  ]);
  $handler = HandlerStack::create($mock);
  $this->mockHttp = new HttpClient(['handler' => $handler]);

  $anonymousWebServices = new AnonymousWebServices(
    $this->mockHttp,
    $this->mockState,
    $this->mockConfigFactory
  );

  $membership_classes = $anonymousWebServices->getMembershipClasses();
  $membership_classes = json_decode($membership_classes->getContent());

  $this->assertNotEmpty($membership_classes);
  foreach ($membership_classes as $membership_class) {
    $this->assertTrue($membership_class->IsActive === TRUE);

  }

}

```

You can queue multiple mock responses by adding them to your handler at creation time:

```
  $mock = new MockHandler([
    new Response(200, [], $body),
    new Response(400, [], 'Request malformed.'),
  ]);

```

Or you can add them after your client has already been instantiated, as long as you keep a reference to your mock handler around. If you have multiple test methods, this is a lot easier to read and maintain:

```
public function setUp() {
  $this->mockHandler = new MockHandler();
  $handler = HandlerStack::create($this->mockHandler);
  $this->mockHttp = new HttpClient(['handler' => $handler]);
}

public function testSomething() {
  $this->mockHandler->append(new Response(200, [], 'apples and bananas'));
  $responseBody = $this->mockHttp->get('http://example.com')->getBody();
  $this->assertEquals($responseBody, 'apples and bananas');
}

```

# Answer
> 0 votes
So this might not be best practice but it does work. I will leave it open for a while if someone has a better answer but this is what I did:

Because the guzzle get() method should return a response object and the code that I'm testing uses the getBody() method of that object I created a mock class for this response with just one method - getBody() - which returns my mock data. I then pass an instance of the MockResponse class as the return value of my mock of the get() method from the mockHttp class.

So, there's probably a more elegant way but it does the job!

```
  /**
   * Test the getMembershipClasses method.
   */
  public function testGetMembershipClasses() {

    $mockResponse = new MockResponse(__DIR__ . '/Mocks/membership-class.json');

    $this->mockHttp->expects($this->any())
      ->method('get')
      ->willReturn($mockResponse);

    $anonymousWebServices = new AnonymousWebServices(
      $this->mockHttp,
      $this->mockState,
      $this->mockConfigFactory
    );

    $membership_classes = $anonymousWebServices->getMembershipClasses();
    $membership_classes = json_decode($membership_classes->getContent());

    $this->assertNotEmpty($membership_classes);
    foreach ($membership_classes as $membership_class) {
      $this->assertTrue($membership_class->IsActive === TRUE);

    }

  }

}

/**
 * Class MockResponse.
 *
 * @package Drupal\Tests\hambs_api_wrapper\Controller\Unit
 */
class MockResponse {

  private $filePath;

  /**
   * @param {string} $filePath
   *   - The file path where the mock test file lives.
   */
  public function __construct($filePath) {
    $this->filePath = $filePath;
  }

  /**
   * Mocking the Guzzle getBody() method.
   *
   * @return string
   */
  public function getBody() {

    $file_location = $this->filePath;
    $file_handler = fopen($file_location, "r");
    $file = fread($file_handler, filesize($file_location));
    fclose($file_handler);

    return $file;

  }

}

```

# Answer
> -1 votes
```
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\RequestException;

// Create a mock and queue two responses.
$mock = new MockHandler([
    new Response(200, ['X-Foo' => 'Bar'], 'Hello, World'),
    new Response(202, ['Content-Length' => 0]),
    new RequestException('Error Communicating with Server', new Request('GET', 'test'))
]);

$handlerStack = HandlerStack::create($mock);
$client = new Client(['handler' => $handlerStack]);

// The first request is intercepted with the first response.
$response = $client->request('GET', '/');
echo $response->getStatusCode();
//> 200
echo $response->getBody();
//> Hello, World
// The second request is intercepted with the second response.
echo $client->request('GET', '/')->getStatusCode();
//> 202

// Reset the queue and queue up a new response
$mock->reset();
$mock->append(new Response(201));

// As the mock was reset, the new response is the 201 CREATED,
// instead of the previously queued RequestException
echo $client->request('GET', '/')->getStatusCode();
//> 201

```

---
Tags: 8, testing
---


# Question
Title: Determine whether module is enabled / disabled
I am trying to write a Drush script to enable a bunch of modules based on a hook. If it's already enabled, I would rather skip enabling that module.

Is there a way for Drush to return whether or not a module is enabled?

# Answer
This code will list all non core enabled modules:

```
drush pm-list --pipe --type=module --status=enabled --no-core

```
> 39 votes

# Answer
```
drush pm-info

```

Gives status of module with additional information as given below:

```
drush pm-info <module_name>

 Extension        :  <ext>
 Project          :  Unknown
 Type             :  module
 Title            :  <title>
 Description      :  <desc>
 Version          :  6.x-1.0
 Date             :  1970-01-01
 Package          :  <pkg>
 Core             :  6.x
 PHP              :  5.3.5
 Status           :  enabled
 Path             :  <path_to_the_module>
 Schema version   :  <schema_version>
 Requires         :  none
 Required by      :  <list_of_modules_this_module_is_required_by>
 Configure        :  None

```
> 9 votes

# Answer
with drush 10 :

```
drush pm:list --type=module --status=enabled | grep mymodule

```
> 3 votes

# Answer
One liner to get module status:

```
drush pm-info mymodule | grep Status | cut -d':' -f 2 | xargs

```

Returns either `not installed` or `enabled`

**Explanation:**

* `drush pm-info mymodule` \- gets info about the module
* `grep Status` \- just get the status line
* `cut -d':' -f 2` \- get the value after the colon
* `xargs` \- remove the whitespace
> 0 votes

---
Tags: drush
---


# Question
Title: What is the equivalent of Joomla's {loadposition} and {loadmodule}?
I have recently converted from Joomla to Drupal. I am still learning how to use it but I can't seem to find answers (esp for Drupal 9 not some ancient version usually coming up with google search) how to have same functionality of "loadposition" and "loadmodule" in Joomla, but in Drupal 9?

In Joomla, {loadposition} and {loadmodule} allows to embed ~~modules~~ / blocks (modules in Joomla, in Drupal I think those are called Blocks) inside an article (node) content. So that way you can call a block logic and code anywhere within an article (node) by simply adding {loadposition} to the code. Example:

I have a module (block) that displays a list of recent posts I have made. Let's call it "Recent Posts". And I want to include it on the "home page" and I also want to include it in the "blog". And I don't mean it in general, like just assigning it, but to load it precisely in that part of the code where I target it.

Recent posts ~~module~~ / block (aka {loadmodule recentpost} contains code:

```
// bla bla bla Recent Posts code

```

Homepage is made like this:

```
// bla bla bla homepage html

```

Blog page html:

```
// bla bla bla blog html

```

Now, let's say I want to add the recent posts code at the bottom of the content within the homepage content region, but at the same time I want to add it on the top of code before the main content code on the blog page html.

In Joomla it would end up like this:

Homepage + ~~module~~ / block :

```
// bla bla bla homepage html
{loadmodule recentpost}

```

Blog page + ~~module~~ / block :

```
{loadmodule recentpost}
// bla bla bla blog html

```

How to do this in Drupal 9? What is the equivalent of Joomla's {loadposition} and {loadmodule} in Drupal 9?

More info about {loadposition} and {loadmodule} here: https://docs.joomla.org/How\_do\_you\_put\_a\_module\_inside\_an\_article?

# Answer
> 0 votes
You can use the Entity Embed module coupled with the Entity Browser module to create similar functionality. These modules will produce a UI solution rather than a shortcode type solution - the result will be very similar to how media is embedded.

Read the Entity Browser documentation and create a new browser to select your blocks (or whatever kind of entities you want). Then create a new Embed button and add it to your WYSIWYG as documented on the Entity Embed project page / module README.

---
Tags: nodes, blocks, 9
---


# Question
Title: How to display 'Welcome [first_name] [last_name]' in a custom views block? D8
I would like to create a custom block / view to display a welcome message to the currently logged in user in Drupal 8. I followed this answer but it isn't working for me. Maybe things changed in D8. Is there a way to do it in D8 and / or am I doing something wrong?

I've added a bunch of Fields and Contextual Filters trying to get it to work but nothing shows up.

# Answer
> 1 votes
Changes:

1. Remove all the contextual filters, that you added. They are not necessary. You have already a filter criteria for the current user.
2. Change format from table to an unformatted list.
3. Remove all the fields except first name, last name.
4. Click on first name and exclude it from display.
5. Click on last name. Find the fieldset to override results, expand it.
6. Write your message there. It should look like: `Welcome {{field_first_name}} {{field_last_name}}`. You can look up the exact tokens in a fieldset below the text field.
7. Save the views.
8. Place your block in some region at `/admin/structure/block`.

---
Tags: views, users, blocks
---


# Question
Title: How do I avoid overwriting the .htaccess file when I use the Compose command?
On my new Drupal 9 website, I customized the `.htaccess` file and the `robots.txt` file

I don't want its files to be overwritten when updating with Composer.

I added the lines below in my composer.json file but the `.htassess` file is overwritten every time. What's wrong with my code ? Thank you

```
"extra": {
    "drupal-scaffold": {
        "locations": {
            "web-root": "./"
        },
        "file-mapping": {
            "[web-root]/.htaccess": false,
            "[web-root]/robots.txt": false
        }
    },
...

```

# Answer
> 2 votes
Both `.htaccess` and `robots.txt` are a part of Drupal core, they are called "Scaffold Files". When you do `composer update` it will download the repository version of these files.

You have to re-add your custom changes every time you do `composer update`. Fortunately there is an automated way to do this:

Option 1. Append your changes:

```
  "name": "my/project",
  ...
  "extra": {
    "drupal-scaffold": {
      "file-mapping": {
        "[web-root]/robots.txt": {
          "append": "assets/my-robots-additions.txt",
        }
      }
    }
  }

```

Option 2. Create patches:

```
  "name": "my/project",
  ...
  "scripts": {
    "post-drupal-scaffold-cmd": [
      "cd docroot && patch -p1 <../patches/htaccess-ssl.patch"
    ]
  }

```

Option 3. Exclude (not recommended):

The official example:

```
  "name": "my/project",
  ...
  "extra": {
    "drupal-scaffold": {
      "file-mapping": {
        "[web-root]/robots.txt": false
      }
    }
  }

```

The code, that you provided looks correct.

Make sure that you are using the https://github.com/drupal/core-composer-scaffold package and not the outdated https://github.com/drupal-composer/drupal-scaffold.

But this approach is not recommended, because you might miss important core changes/security fixes.

More details on Altering Scaffold Files.

---
Tags: installation, composer, 9, .htaccess
---


# Question
Title: How can I fix the "Deleted and replaced configuration entity" error during configuration import?
I am currently running into a configuration importing error which seems caused from field collections.

> Finalizing configuration synchronization.
> The import failed due for the following reasons: Deleted and replaced configuration entity "field\_collection.field\_collection.field\_lives\_around"

I just started yesterday with this project. I created many fields and configurations; I am not using any custom code at all, for now.

What could go wrong?

The field collection contains a list (text) and a field from the Geolocation Field module.

# Answer
The error happens when entity you are trying to create already exists. Or the data changed while config import was in progress. See: `ConfigImporter.php/checkOp()`.

> If the target already exists, use the entity storage to delete it again, if is a simple config, delete it directly.

Running import twice may help, but obviously not at the same time, otherwise, you probably need to remove that field manually and try again.

This could be a bug of the module, as normally modules should have the following condition in place, e.g.

```
 /**
  * Implements hook_ENTITY_TYPE_insert().
  */
 function hook_ENTITY_TYPE_insert(RoleInterface $role) {
   if (\Drupal::isConfigSyncing()) {
     // Do not change data while config import in progress.
     return;
   }
   // ...
 }

```

Related bug: The group\_roles field gets created too early during configuration sync.

---

Few hints:

* In case you don't need the particular import, you can use Config Ignore to ignore it.
* Try exporting the config first, then import again.
* Try importing config individually first, file by file by using Drupal Console, e.g.

```
drupal config:import:single --file=$PWD/config/sync/config_ignore.settings.yml

```
> 4 votes

# Answer
We got the `The import failed due to the following reasons: Deleted and replaced configuration entity ...` error during the early development on a new project when a lot of entities and fields got created at once. The fix usually was to simply run `drush cim` again. So our updated build routine now has `cim` twice in it to circumvent failing builds.

```
drush cim -y || true
drush cim -y

```

Of course, finding and fixing the actual root cause that makes the import fail at the first place as suggested by @kenorb would be the preferred solution. But sometimes during early development you simply want things to move forward and the workaround above helped us to get that done.

---

Turned out that in my case a custom profile's implementation of `hook_entity_bundle_create()` where some defaults for newly created bundles were set has caused the error. Adding the following few lines in the beginning of these implementations fixed it for us. Credits: @hchonov

```
// If we are currently importing configuration we expect it to be complete and
// therefore we should not try to create configuration here as if we do and
// that configuration is also part of the import then the import will fail
// with "Deleted and replaced configuration entity "@name"".
// @see \Drupal\Core\Config\ConfigImporter::checkOp().
/** @var \Drupal\Core\Config\ConfigInstallerInterface $config_installer */
$config_installer =  \Drupal::service('config.installer');
if ($config_installer->isSyncing()) {
  return;
}

```
> 0 votes

# Answer
You can also fix this issue by deleting the UUID from the config, both old and new.

1. remove the UUID line from the element
2. sql-sync the database to your local
3. run config import
4. run config export
5. commit the changes to that config

Your config will have a new, valid UUID that you can commit to your repo and import on your remote.
> 0 votes

---
Tags: 8, configuration
---


# Question
Title: How do I make an archived-dump of my site?
I have multiple versions of drush and cannot make an archive-dump of my site.

**drush8 ard**/**drush8 archive-dump** returns

> \[error\] The drush command 'ard' (and/or 'archive-dump') could not be found. Run `drush
>  cache-clear drush` to clear the commandfile cache if you have installed new extensions.

**drush6 ard**/**drush6 archive-dump** returns

> Drush 6.6.0 does not support Drupal . See http://drupal.org/project/drush for more information.
> \[error\] Command archive-dump needs a higher bootstrap level to run - you will need to invoke drush from a more functional Drupal environment to run\[error\] this command. The drush command 'archive-dump' could not be executed.

**drush ard**/**drush archive-dump** returns

> PHP Fatal error: Class 'Drupal\Core\Session\AccountInterface' not found in /var/www/mywebsite/core/includes/bootstrap.inc on line 60

---

**drush8** = * remote origin Fetch URL: https://github.com/drush-ops/drush.git Push URL: https://github.com/drush-ops/drush.git

**drush6** = * remote origin Fetch URL: https://github.com/drush-ops/drush.git Push URL: https://github.com/drush-ops/drush.git

**drush** = Drush Version:6.2.0

---

If I run **drush8 status** on my local site it returns

> Drush:9.0-dev-g9bbddb2

If I run **drush6 status** on my local site it returns

> Drush 6.6.0 does not support Drupal . See http://drupal.org/project/drush for more information.

If I run **drush status** on my local site it returns

> PHP Fatal error: Class 'Drupal\Core\Session\AccountInterface' not found in /var/www/mywebsite/core/includes/bootstrap.inc on line 60 Drush command terminated abnormally due to an unrecoverable error. \[error\] Error: Class 'Drupal\Core\Session\AccountInterface' not found in /var/www/mywebsite/core/includes/bootstrap.inc, line 60

# Answer
* Drush 8 supports: Drupal 7-\>8.3
* Drush 10 supports: Drupal 8.4-\>9

The Drush\Drupal Compatibility chart: https://www.drush.org/latest/install/#drupal-compatibility

Drush 8 is expected to go end of life with Drupal 7 in November 2022.

More information about `ard` in drush 9: https://github.com/pantheon-systems/documentation/issues/3946#issuecomment-467963427
> 0 votes

---
Tags: 8, drush
---


title: Drupal.t() does not work

text:
# Question
Title: Drupal.t() does not work
I am tring to use Drupal.t() within some javascript, and I am not able to do it.

Actually, it throws no errors, Doing something like :

```
console.log(Drupal.t('supplier'));

```

returns 'supplier', even though I am in another language and the alternative value was supplied for such language (The PHP code with the t() function works).

**Extra question** : Is there a way, to know from Drupal Javascript utilities the current locale, I am in ?

At the moment, I found a workaround by testing the following (pure jQuery) :

```
if(jQuery('body').hasClass('i18n-fr')){//so that we can
 locale = '/fr';                       //make localized ajax calls.
}

```

Cheers,

Any ideas ?

# Answer
> 8 votes
After using `Drupal.t()`, clear the cache once, and search text to translate from admin/build/translate/search.

# Answer
> 6 votes
In some cases the Drupal.t function doesnt work because the Drupal.t function doent get properly attached to drupal and therefor not picked up by the Javascript Locale Builder

1. First make sure the javascript file where the Drupal.t() function gets called is properly attached the drupal way.

If you're not sure that the file where the Drupal.t funtion is called is properly embedded. you can add the Drupal.t() function in custom a javascript file in your theme or module and make sure this custom javascript file is embedded and contains the strings you want to translate like so:

*/themes/mytheme/js/myThemeTranslateStrings.js*

```
Drupal.behaviors.myThemeTranslateStrings = {
    attach: function (context, settings) {
      Drupal.t('Your shopping cart is empty.');
      Drupal.t('Go to checkout');
      Drupal.t('Update quantities');
      Drupal.t('Another string I want to translate');
    }
};

```
2. Clear caches
3. Visit the page where the javascript file with the Drupal.t() function is called In case you attached it to your theme and set it globaly any page is fine.
4. Clear caches
5. Go to the Translate page (/admin/config/regional/translate)
6. You should now find the string you want to translate for example 'Go to checkout' and translate the string
7. Hit the save translation button at the bottom of the page
8. Clear caches again

and it ***should*** work now

**Debugging**

If not you can debug by going to the console of your browser and type:

```
Drupal.t('Go to checkout');

```

It should then return the translated string.

Another method is to type:

```
window.drupalTranslations

```

This should return an object with all the available strings for Drupal.t() to translate. If your string is not there it won't get translated even if the string is known in the translation interface.

To force a rebuild of the javascript translation object above you can do so with drush:

```
drush php:cli
_locale_rebuild_js('YOUR_TWO_CHAR_LANG_CODE_HERE');
exit;
drush cr

```

# Answer
> 5 votes
Note that when using a javascript minifier you should disable obfuscation or Drupal won't be able to find "Drupal.t" (it will be obfuscated to something like "e.t()").

# Answer
> 3 votes
You can't call console.log from your firebug/chrome console as drupal generates a js translation file for all texts found in your javascript source.

# Answer
> 0 votes
As a last resort, you can load your javascript files through php, and use the drupal php t()-function instead. Your javascript could look something like this:

original file where translation dont work for whatever reason: **test.js**

```
console.log(Drupal.t("Am I translated?"));

```

Changed to php: **test.js.php**

```
<?php
// Bootstrapping the drupal installation:
$drupal_root = '/path/to/drupal'; // Can be relative to your file
define('DRUPAL_ROOT', $drupal_root);
require_once(DRUPAL_ROOT . "/includes/bootstrap.inc");
require_once(DRUPAL_ROOT . "/includes/common.inc");
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
header('Content-type: application/javascript');
// Get the language as a GET-parameter
$lang = (string) @$_GET['langcode'];
// Sanitize input:
if (!in_array($lang, array_keys(language_list()))) {
  $lang = 'en';
}
$opt = array('langcode' => $lang);
$n = array();

// Here code can start
echo "console.log('" . t('Am I translated?', $n, $opt) . "')"

```

add the script as: `path/to/test.js?langcode=nb` (example for norwegian language)

So, there is some overhead loading drupal, printing the js-code from a php-file, and translating whatever needs to be translated. But all in all, it works! Which was the point for me, at least :)

---
Tags: javascript
---


# Question
Title: How do I apply patches from a merge request?
I used the patch #48 of Views exposed sort identifiers are not configurable. I need to update the core, and apply the latest rebased version of that.

However, the issue hasn't be marked *Fixed*, and I don't see any "patch file" to link in my composer.json.

How can achieve this?

# Answer
> 16 votes
If you look into the Issue queue you can see MR #54 is the latest code change.

Go to the URL of the MR and add **`.patch`** at the end of the URL you will get the path to the latest patch.

URL for your latest patch is #54

**Note** : It is advised to download patch locally from merge request to avoid issues due to new commits on the same merge requests. As new merge commits are not always correct.

---
Tags: composer, 9, community-official-site
---


# Question
Title: Extract more data on field_collection_item from REST APIs of Drupal
I am trying to display information regarding Contributed modules available on Drupal programmatically.

For that, I am taking the help of this documentation : https://www.drupal.org/drupalorg/docs/apis/rest-and-other-apis

When I am calling API like: https://www.drupal.org/api-d7/node.json?field\_project\_machine\_name=ctools

In return I am receiving a JSON object with the following details:

```
"field_supporting_organizations": [
                {
                    "uri": "https://www.drupal.org/api-d7/field_collection_item/1381907",
                    "id": "1381907",
                    "resource": "field_collection_item"
                }
],

```

Now, I want to extract more data on this field collection item, but I am unable to find the right API filters to do so.

Any help would be much appreciated.

# Answer
> 2 votes
To extrach more information from that field collection item, you just use the URI reported from that JSON data, but appending *.json* to the URI.
In your case, the URI is https://www.drupal.org/api-d7/field\_collection\_item/1381907.json, which returns the following data.

```
{
  "field_how_they_helped": "Maintenance",
  "field_supporting_organization": {
    "uri": "https://www.drupal.org/api-d7/node/2808667",
    "id": "2808667",
    "resource": "node"
  },
  "item_id": "1381907",
  "revision_id": "1675252",
  "field_name": "field_supporting_organizations",
  "archived": "0",
  "url": "https://www.drupal.org/field-collection/field-supporting-organizations/1381907",
  "host_entity": {
    "uri": "https://www.drupal.org/api-d7/node/343333",
    "id": "343333",
    "resource": "node"
  },
  "feeds_item_guid": null,
  "feeds_item_url": null,
  "feed_nid": null
}

```

If then you need to get more information about the organization, you visit https://www.drupal.org/api-d7/node/2808667.json, which returns the following data.

```
{
  "body": {
    "value": "<p>The University of British Columbia is a global centre for research and teaching, consistently ranked among the top 20 public universities in the world. Since 1915, UBC’s entrepreneurial spirit has embraced innovation and challenged the status quo. UBC encourages its students, staff and faculty to challenge convention, lead discovery and explore new ways of learning. At UBC, bold thinking is given a place to develop into ideas that can change the world.</p>",
    "summary": "",
    "format": "1"
  },
  "taxonomy_vocabulary_48": [],
  "taxonomy_vocabulary_50": [
    {
      "uri": "https://www.drupal.org/api-d7/taxonomy_term/24656",
      "id": "24656",
      "resource": "taxonomy_term"
    }
  ],
  "taxonomy_vocabulary_52": [
    {
      "uri": "https://www.drupal.org/api-d7/taxonomy_term/24104",
      "id": "24104",
      "resource": "taxonomy_term"
    }
  ],
  "field_budget": "",
  "field_contributions": {
    "value": "<p>Web services offer Drupal integration to the faculty and staff and they have provided a theme and commerce payment gateway integration module. Also have staff members contribute to Drupal and meetups for users within the University staff.</p>",
  "format": "1"
  },
  "field_link": {
    "url": "https://www.ubc.ca",
    "attributes": [],
    "display_url": null
  },
  "field_logo": {
    "file": {
      "uri": "https://www.drupal.org/api-d7/file/5711845",
      "id": "5711845",
      "resource": "file"
    },
    "alt": "The University of British Columbia",
    "title": ""
  },
  "field_org_marketplace_request": false,
  "field_org_training_request": false,
  "field_organization_headquarters": "Vancouver",
  "field_organization_list_rule": "never",
  "field_organization_training_desc": {
    "value": "",
    "format": "1"
  },
  "field_organization_training_list": "off",
  "field_organization_training_url": {
    "url": "",
    "attributes": [],
    "display_url": null
  },
  "field_organization_technologies": "off",
  "field_organization_support": [],
  "field_short_description": null,
  "field_hosting_type": [],
  "field_org_issue_credit_count": "12",
  "field_organization_type": {
    "uri": "https://www.drupal.org/api-d7/taxonomy_term/182533",
    "id": "182533",
    "resource": "taxonomy_term"
  },
  "field_org_membership_status": null,
  "field_organization_loc_served": [],
  "nid": "2808667",
  "vid": "10103871",
  "is_new": false,
  "type": "organization",
  "title": "The University of British Columbia",
  "language": "en",
  "url": "https://www.drupal.org/the-university-of-british-columbia",
  "edit_url": "https://www.drupal.org/node/2808667/edit",
  "status": "1",
  "promote": "0",
  "sticky": "0",
  "created": "1475153665",
  "changed": "1623042361",
  "author": {
    "uri": "https://www.drupal.org/api-d7/user/160302",
    "id": "160302",
    "resource": "user"
  },
  "book_ancestors": [],
  "comment": "1",
  "comments": [],
  "comment_count": "0",
  "comment_count_new": false,
  "feeds_item_guid": null,
  "feeds_item_url": null,
  "feed_nid": null,
  "flag_flag_tracker_follow_user": [],
  "flag_tracker_follower_count": null,
  "has_new_content": null,
  "last_comment_timestamp": "1475153665",
  "projects_supported": [
    {
      "id": "3054475",
      "title": "Maintainer Support",
      "uri": "https://www.drupal.org/api-d7/node/3054475"
    },
    {
      "id": "2920939",
      "title": "Responsive Table Filter",
      "uri": "https://www.drupal.org/api-d7/node/2920939"
    },
    {
      "id": "2724893",
      "title": "Composer Deploy",
      "uri": "https://www.drupal.org/api-d7/node/2724893"
    },
    {
      "id": "2632164",
      "title": "Twig Extensions",
      "uri": "https://www.drupal.org/api-d7/node/2632164"
    },
    {
      "id": "2162097",
      "title": "Views Selective Filters",
      "uri": "https://www.drupal.org/api-d7/node/2162097"
    },
    {
      "id": "1612464",
      "title": "SAML Service Provider",
      "uri": "https://www.drupal.org/api-d7/node/1612464"
    },
    {
      "id": "1378306",
      "title": "Entityform",
      "uri": "https://www.drupal.org/api-d7/node/1378306"
    },
    {
      "id": "1173784",
      "title": "Node authorize link",
      "uri": "https://www.drupal.org/api-d7/node/1173784"
    },
    {
      "id": "948986",
      "title": "Menu Position",
      "uri": "https://www.drupal.org/api-d7/node/948986"
    },
    {
      "id": "756434",
      "title": "Form Tips",
      "uri": "https://www.drupal.org/api-d7/node/756434"
    },
    {
      "id": "460628",
      "title": "Views Natural Sort",
      "uri": "https://www.drupal.org/api-d7/node/460628"
    },
    {
      "id": "343333",
      "title": "Chaos Tool Suite (ctools)",
      "uri": "https://www.drupal.org/api-d7/node/343333"
    },
    {
      "id": "265945",
      "title": "Menu Block",
      "uri": "https://www.drupal.org/api-d7/node/265945"
    },
    {
      "id": "165016",
      "title": "Editable Fields",
      "uri": "https://www.drupal.org/api-d7/node/165016"
    },
    {
      "id": "161539",
      "title": "Views Bulk Operations (VBO)",
      "uri": "https://www.drupal.org/api-d7/node/161539"
    },
    {
      "id": "92594",
      "title": "Calendar",
      "uri": "https://www.drupal.org/api-d7/node/92594"
    },
    {
      "id": "74958",
      "title": "Panels",
      "uri": "https://www.drupal.org/api-d7/node/74958"
    },
    {
      "id": "9044",
      "title": "Code Filter",
      "uri": "https://www.drupal.org/api-d7/node/9044"
    }
  ]
}

```

In general, to access the URI returned from that data, you need to append *.json* to the URI. For example, for https://www.drupal.org/api-d7/taxonomy\_term/24656, you use https://www.drupal.org/api-d7/taxonomy\_term/24656.json.

---
Tags: community-official-site
---