# Question
Title: How to create a node out of a webform submission?
I'd like to be able to create a node out of a webform submission in Drupal 8. It can happen either on successful submission or as an additional task after the webform has been submitted. I've seen some info on creating content entities via REST/GET (https://www.drupal.org/docs/8/core/modules/rest/3-post-for-creating-content-entities) and I know that you can post a webform submission to a URL with Webform (yamlform) using either x-www-form-urlencoded or JSON, but I'm not sure if this is even the right thing to be looking at.

The webform, submissions, and content type I'd like to use are all on the same site.

I know this question came up for Drupal 7 and the direction was to have them use a content type, but we're not able to allow the submitters to use content types at this time because of the way the site is setup.

# Answer
> 4 votes
```
<?php

/**
 * Convert webform submission to "Bulletin" content type.
 */

namespace Drupal\subtonode\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\webform\Entity\WebformSubmission;
use Drupal\node\Entity\Node;
use Symfony\Component\HttpFoundation\RedirectResponse;

class SubToNodeController extends ControllerBase {
  public function subtonode($webform_submission) {
    //$sid = 2;
    $node_details = WebformSubmission::load($webform_submission);
    $submission_array = $node_details->getOriginalData();
    $title = $submission_array['title'];
    $body = $submission_array['body'];
    $contact_name = $submission_array['contact_name'];
    $contact_email = $submission_array['contact_email'];
    $contact_website_uri = $submission_array['website'];
    $contact_website_title = $submission_array['website'];
    $des_pub_date = $submission_array['bulletin_publish_date'];
    $image_fid = $submission_array['image'];

// Create file object from remote URL.
    if (!empty($image_fid)) {
      $file = \Drupal\file\Entity\File::load($image_fid);
      $path = $file->getFileUri();
      $data = file_get_contents($path);
      $node_img_file = file_save_data($data, 'public://' . $file->getFilename(), FILE_EXISTS_REPLACE);
    }

    $timestamp = date("Y-m-d\TH:i:s", strtotime($des_pub_date));

// Create node object with attached file.
    $node = Node::create([
      'type' => 'bulletin',
      'title' => $title,
      'body' => [
        'value' => $body,
        'summary' => '',
        'format' => 'markdown',
      ],
      'field_bulletin_contact_name' => $contact_name,
      'field_bulletin_contact_email' => $contact_email,
      'field_bulletin_desired_publicati' => $timestamp,
      'field_bulletin_reference_submiss' => [
        'target_id' => $webform_submission,
      ],
      'field_bulletin_contact_website' => [
        'uri' => $contact_website_uri,
        'title' => $contact_website_title,
      ],
      'field_photo' => [
        'target_id' => (!empty($node_img_file) ? $node_img_file->id() : NULL),
        'alt' => 'Hello world',
        'title' => 'Goodbye world'
      ],
    ]);

    if (!empty($submission_array['audience'])) {
      $target_ids_aud = $submission_array['audience'];
      foreach ($target_ids_aud as $target_id) {
        $node->field_bulletin_audience->AppendItem($target_id);
      }
    }

    if (!empty($submission_array['category'])) {
      $target_ids_cat = $submission_array['category'];
      foreach ($target_ids_cat as $target_id) {
        $node->field_bulletin_category->AppendItem($target_id);
      }
    }

    $node->save();

    $url = '/admin/content/webform';
    $response = new RedirectResponse($url);
    //$response->send(); // don't send the response yourself inside controller and form.

    drupal_set_message(t('You have successfully created a node from webform submission @sid', array('@sid' => $webform_submission)), 'success');
    return $response->send();
  }
}

```

# Answer
> 8 votes
Also, check out the Webform Content Creator module.

> This module provides the ability to create nodes after submitting webforms, and do mappings between the fields of the created node and webform submission values.

# Answer
> 7 votes
The answer from @owenpm3 is great for adding this as an administrative duty.

In order to automate this and make it occur on a successful submission, I would create a custom WebformHandler that you add to your form in the configuration settings, the same way you configure your form to send an email upon a successful submission. So under your web forms Settings tab, under the sub-tab: Emails / Handlers.

To build this you would need to create a custom module, mymodule and place the custom webform handler in: mymodule/src/Plugin/WebformHandler/

I will call the WebformHandler MyWebformHandler.php. Aside from this you will need an info file and that should do it.

Code for MyWebformHandler.php as follows:

```
<?php

namespace Drupal\mymodule\Plugin\WebformHandler;

use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\Entity\Node;
use Drupal\webform\WebformInterface;
use Drupal\webform\Plugin\WebformHandlerBase;
use Drupal\webform\webformSubmissionInterface;
use Drupal\webform\Entity\WebformSubmission;

/**
 * Create a new Article node from a webform submission.
 *
 * @WebformHandler(
 *   id = "article_from_webform",
 *   label = @Translation("Create a node on submit"),
 *   category = @Translation("Content"),
 *   description = @Translation("Creates a new Article node from Webform Submissions."),
 *   cardinality = \Drupal\webform\Plugin\WebformHandlerInterface::CARDINALITY_UNLIMITED,
 *   results = \Drupal\webform\Plugin\WebformHandlerInterface::RESULTS_PROCESSED,
 *   submission = \Drupal\webform\Plugin\WebformHandlerInterface::SUBMISSION_REQUIRED,
 * )
 */

class MyWebformHandler extends WebformHandlerBase {

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

    // Get an array of form field values.
    $submission_array = $webform_submission->getData();

    // Dump the $submission_array to acquire the fields if you don't know what fields you're working with.

    // Prepare variables for use in the node.
    $title = $submission_array['subject'];
    $body = "<p>" . $submission_array['name'] . "<br/>";
    $body .= $submission_array['email'] . "</p>";
    $body .= $submission_array['message'];

    // Create the node.
    $node = Node::create([
      'type' => 'article',
      'status' => FALSE,
      'title' => $title,

      'body' => [
        'value' => $body,
        'format' => 'basic_html',
      ],

    ]);

    // Save the node.
    $node->save();
  }
}

```

---
Tags: 8, nodes, webforms
---


# Question
Title: How to add a database index to a base field
**Goal:**

Add a database index to a 'created' field.

**Given:**

There is a custom entity with a base field `created`. The field is stored the entity table. Field source code of the `created` field:

```
$fields['created'] = BaseFieldDefinition::create('created')
  ->setLabel(t('Created'))
  ->setDescription(t('The time that the entity was created.'))
  ->setDisplayOptions('view', [
    'label' => 'hidden',
    'type' => 'timestamp',
    'weight' => 3,
    'settings' => [
      'date_format' => 'medium',
      'custom_date_format' => '',
      'timezone' => '',
    ],
  ])
  ->setDisplayConfigurable('view', TRUE);

```

**What I researched:**

I have not found a way to add index using the `\Drupal\Core\Field\BaseFieldDefinition()`.

As I understand indexes are defined in a `@FieldType` plugin. The `created` field is implemented via the `\Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem()` plugin and obviously does not have have indexes there.

P.S. I know, that I can write an updatescript to add an index to the table manually.

# Answer
Currently the only way to do that is to create your own storage\_schema entity handler.

See Node as an example, the annotation:

```
*     "storage_schema" = "Drupal\node\NodeStorageSchema",

```

There you can alter both the schema for a while table, or you can do it for a specific field. NodeStorageSchema does both:

```
  /**
   * {@inheritdoc}
   */
  protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
    $schema = parent::getEntitySchema($entity_type, $reset);

    $schema['node_field_data']['indexes'] += array(
      'node__frontpage' => array('promote', 'status', 'sticky', 'created'),
      'node__status_type' => array('status', 'type', 'nid'),
      'node__title_type' => array('title', array('type', 4)),
    );

    return $schema;
  }

```

And below in getSharedTableFieldSchema():

```
if ($table_name == 'node_revision') {
  switch ($field_name) {
    case 'langcode':
      $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
      break;

    case 'revision_uid':
      $this->addSharedTableFieldForeignKey($storage_definition, $schema, 'users', 'uid');
      break;
  }
}

```
> 19 votes

# Answer
For those wondering which part from berdir's reply is necessary for creating an index on a base column - here is a full example on creating index on a string column `sku`:

`ekr_product/Entity/Product.php:`

```
<?php

 * @ContentEntityType(
...
 *     "storage_schema" = "Drupal\ekr_product\ProductStorageSchema",

```

`ekr_product/ProductStorageSchema.php:`

```
<?php

namespace Drupal\ekr_product;

use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
use Drupal\Core\Field\FieldStorageDefinitionInterface;

/**
 * Defines the node schema handler.
 */
class ProductStorageSchema extends SqlContentEntityStorageSchema {

  /**
   * {@inheritdoc}
   */
  protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) {
    $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
    $field_name = $storage_definition->getName();

    switch ($field_name) {
      case 'sku':
        $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
        break;
    }

    return $schema;
  }

}

```

Few comments on this.

You might be thinking why using method `getSharedTableFieldSchema` when creating index on the **base** table? Truly, *shared* word is sorta associated with fields stored in a separate tables. But from the function's documentation it follows that if your schema modification isn't cross-field you should use exactly this function.

Note also that the third parameter to `addSharedTableFieldIndex` is set to `TRUE`. Suddenly this makes the column you're creating index on `NOT NULL`. This is the same as if you'd be doing:

```
$schema['fields']['your_field']['not null'] = TRUE;

```

somewhere in schema overrides. This is a way to make the column **required** at the database level.

HTH.
> 8 votes

# Answer
Besides the options berdir posted, configurable fields can have manually added indexes via \Drupal\field\Entity\FieldStorageConfig::$indexes

For example, in `field.storage.media.field_media_video_embed_field.yml` file you'd have:

```
indexes:
  field_media_video_embed_field__value:
    - value

```

to add an index on the `value` property. Note the second line in this example is just the index name and has no special meaning and could be anything else, it's just a naming convention. But the third line here needs to be the property name and *not* the SQL database column name (which would be `field_media_video_embed_field__value`).
> 7 votes

# Answer
While the above API approaches are recommended, here's one more raw approach that can be useful for some cases.

In this case, it adds an SQL index to a base field for the MySQL/MariaDB database engine:

```
/**
 * Add SQL index on published_date base field
 */
function MY_MODULE_update_8010(&$sandbox) {
  // Add index
  // ALTER TABLE $table ADD INDEX $name ($column1, $column2..)
  db_query("ALTER TABLE node_field_data ADD INDEX node_field__published_date (published_date)");
}

```
> 2 votes

---
Tags: 8, entities, database
---


title: How to make PHPUnit test in a Module?

text:
# Question
Title: How to make PHPUnit test in a Module?
I'm not very much knowledgeable about making PHPUnit and Drupal testing setup.

I am having problems regarding database calls.

I tried to setup phpunit test.

Inside my `module/some_module`. I installed phpunit by running

```
composer require --dev phpunit/phpunit ^8

```

This is my `module/some_module/composer.json`

```
{
    "autoload": {
        "classmap": [
            "src/"
        ]
    },
    "require-dev": {
        "phpunit/phpunit": "^8"
    }
}

```

This is my `module/some_module/tests/SampleTest.php`

```
<?php

use PHPUnit\Framework\TestCase;
use Drupal\nat\Controller\SampleController;
use Drupal\Core\Controller\ControllerBase;

final class SampleTest extends TestCase
{
    public function testCanFilterData(): void
    {
        $this->getMockBuilder(ControllerBase::class)
            ->getMock();

        $class = new ReflectionClass(SampleController::class);
        $method = $class->getMethod('filterData');
        $method->setAccessible(true);

        $obj = new SampleController();
        $args = [1, 2, 3];
        $method->invokeArgs($obj, [$args]);

        print_r($foo);
    }
}

```

This is my `module/some_module/src/Controller/SampleController.php`

```
<?php

namespace Drupal\some_module\Controller;

use Drupal\Core\Controller\ControllerBase;

class SampleController extends ControllerBase {
    public function index()
    {
        $ids = [1, 2, 3]
        $data = [];

        $data['some_data'] = $this->filterData($ids);

        return [*
            '#theme' => 'test_template',
            '#data' => $data,
          ];
    }

    private function filterData($ids)
    {
        $connection = \Drupal::database();
        $query = $connection->query("SELECT
                id, name
            FROM products
            WHERE id IN (:ids[])",
            [
                ':ids[]' => $ids,
            ]
        );

        return $query->fetchAll(\PDO::FETCH_ASSOC);
    }
}

```

When I ran `phpunit tests/NatTest.php`, I am getting this error:

```
1) NatTest::testCanBeCreatedFromValidEmailAddress
Error: Class 'Drupal' not found

```

So my question is how can I test this? I can't mock `Drupal` because I actually want to execute a database query from Drupal. How can I do this?

# Answer
Automated tests describes the different tests and makes clear which test should be used, in a Drupal environment. In particular, it says:

* Unit tests: Test functionality of a class **if the Drupal environment** (database, settings, etc.) and web browser are **not needed for the test**, **or** if the Drupal environment **can be replaced by a "mock" object**.
* Kernel tests: Test functionality of a class **if the full Drupal environment** and web browser are **not needed for the test, but the functionality has significant Drupal dependencies that cannot easily be mocked.** **Kernel tests can access** services, **the database**, and a minimal mocked file system, and they use an in-memory pseudo-installation. However, modules are only installed to the point of having services and hooks, unless you install them explicitly.

If you are testing a class that should insert data in the database, the test should be a Kernel test, which means:

* The base class of the test should be \Drupal\KernelTests\KernelTestBase
* The namespace of the test should start with (in your case) \Drupal\Tests\some\_module\Kernel, and it should be placed in the some\_module/tests/src/Kernel directory or a sub-directory

For example, the `DatabaseBackendTagTest` class implements a Kernel test that accesses the database.

```
  public function testTagInvalidations() {
    // Create cache entry in multiple bins.
    $tags = [
      'test_tag:1',
      'test_tag:2',
      'test_tag:3',
    ];
    $bins = [
      'data',
      'bootstrap',
      'render',
    ];
    foreach ($bins as $bin) {
      $bin = \Drupal::cache($bin);
      $bin->set('test', 'value', Cache::PERMANENT, $tags);
      $this->assertTrue($bin->get('test'), 'Cache item was set in bin.');
    }
    $connection = Database::getConnection();
    $invalidations_before = intval($connection->select('cachetags')->fields('cachetags', ['invalidations'])->condition('tag', 'test_tag:2')->execute()->fetchField());
    Cache::invalidateTags(['test_tag:2']);

    // Test that cache entry has been invalidated in multiple bins.
    foreach ($bins as $bin) {
      $bin = \Drupal::cache($bin);
      $this->assertFalse($bin->get('test'), 'Tag invalidation affected item in bin.');
    }

```

The code shown in the question just reads data from the database. (I don't see code writing the database.) Keep in mind that the database used from tests isn't automatically populated; if the purpose of the test is verifying the controller outputs the correct data, the database table needs to be filled with the data. That is normally done from the `setUp()` method, which could also initialize a property with the connection (for example with `$this->connection = Database::getConnection();`) if the data is the same for each test, or at the beginning of the test method, if each test needs different data. (For example, `testCanFilterData()` could test the controller filter the data in the database and `testCanFilterWrongData()` could test the controller doesn't output completely wrong data or out-of-the-set data.)
> 4 votes

# Answer
Here is a documentation about PHPUnit in Drupal 8. https://www.drupal.org/docs/8/phpunit

However what you are trying to create is not a unit test at all, because you are querying an existing database. You need to write an integration test which is a whole different story. For this purpose consider using Behat or Drupal Test Traits.
> 0 votes

---
Tags: testing
---


title: From Controller to html.twig

text:
# Question
Title: From Controller to html.twig
I have a module that define a Routing and a controller

```
my.partner:
  path: '/partner/{alias}'
  defaults:
    _controller: '\Drupal\myname\Controller\PagesController::partner'
    _title: 'Partner'

```

In controller I define the template to use:

```
$variables = [
         '#theme' => 'page_partner',
]....

```

But I need to pass some "variables" from this "controller" to html \<head\>. How can I do it ?

# Answer
> 1 votes
Define the variables in your theme and the pass them as "#variable" = value. E.g. in YOUR\_MODULE.module have something like:

```
function tb_megamenu_theme($existing, $type, $theme, $path) {
  $items['tb_megamenu'] = [
  'template' => 'tb-megamenu',
    'variables' => [
      'menu_name' => NULL,
      'content' => NULL,
      'section' => 'frontend',
      'block_theme' => \Drupal::config('system.theme')->get('default'),
    ],
  ];
}

```

In your controller use:

```
$render = [
  '#theme' => 'tb_megamenu',
  '#menu_name' => $this->getMenuName(),
  '#block_theme' => $this->getThemeName(),
  '#content' => $this->getContent(),
];

```

# Answer
> 0 votes
This has been bumped up to the homepage. To make the comment of @Clive more clear, you can attach page attachments via `#attached` to any theme or render element (`#theme`, `#type`, `#markup`) and it will bubble up to page level when rendered:

```
$variables = [
  '#theme' => 'page_partner',
  '#attached' => [
    'html_head' => [
      [
        [
          '#tag' => 'meta',
          '#attributes' => [
            'name' => 'foo',
            'content' => 'bar',
          ],
        ],
        'my_module_foo',
      ],
    ],
  ],
];

```

---
Tags: 8
---


title: How can I turn off caching redirect?

text:
# Question
Title: How can I turn off caching redirect?
I have a url that would normally redirect to a specific page, however, some code is run prior to this. I am returning a `RedirectResponse` instance, and it appears to be being cached. How can I force this not to be cached?

# Answer
A response built from the RedirectReponse class is not cached. So you should not need to set any cache metadata. The problem here is probably the page cache for anonymous requests, which caches all responses, even redirects and no matter if they are cachable or not.

You can disable this cache by using the kill switch before returning the response:

```
\Drupal::service('page_cache_kill_switch')->trigger();

```

This will only disable the *Internal Page Cache*. To control caches outside of drupal, like proxies or browser caches, go to `/admin/config/development/performance` and set a "Page cache maximum age" or set response headers. See this comment How can I turn off caching redirect?
> 19 votes

# Answer
As noted in the comments above, `RedirectResponseSubscriber` does alter redirects. Here's the relevant snippet:

```
if (!($response instanceof SecuredRedirectResponse)) {
    try {
      // SecuredRedirectResponse is an abstract class that requires a
      // concrete implementation. Default to LocalRedirectResponse, which
      // considers only redirects to within the same site as safe.
      $safe_response = LocalRedirectResponse::createFromRedirectResponse($response);
      $safe_response->setRequestContext($this->requestContext);
    }

```

So if you have a custom redirect that should not be cached, then create a custom class that extends `SecuredRedirectResponse` and implement the required `isSafe()` method. You may wish to leverage `LocalAwareRedirectResponseTrait` to use there to verify the url is local, along with any other check to verify that this is your redirect and not a mis-use. Your redirect will then skip the block above and not be converted to a cacheable redirect. Thanks to @smartsheet-eng for pointing me in the right direction.
> 1 votes

# Answer
You may want to cache your response with CacheableRedirectResponse
> 0 votes

---
Tags: 8, caching, redirection
---


title: Custom formatter for paragraphs field

text:
# Question
Title: Custom formatter for paragraphs field
I want to build a custom formatter for a paragraphs field that renders some of the fields of the paragraph. However, I don't know how to access the single files of the paragraph field.

So far I've only written the skeleton of the formatter, but it doesn't do much, except that I can return a serialised string of all of the entire field, which does include the necessary information, but I only need three particular fields rendered themselves in a nice way (a term reference field with a label, a boolean field as "yes" or "no" and a text field. A Twig template is not an option for this.

The function looks like this:

```
public function viewElements(FieldItemListInterface $items, $langcode) {
  $element = [];

  foreach ($items as $delta => $item) {
    // Desired fields: field_network_name, field_network_specific_site_code, field_network_verified

    $element[$delta] = [
      '#markup' => "Output: " . serialize($item)
    ];
  }

  return $element;
}

```

I'd need to know how to elegantly access the fields inside $item.

# Answer
Thanks to the comment above I was able to find a solution. This function allows to access three fields within a paragraph (term reference field, text field, boolean field).

```
public function viewElements(FieldItemListInterface $items, $langcode) {
$element = [];

  // Render each element as markup in case of multi-values.
  foreach ($items as $delta => $item) {

    // Desired fields: field_network_name (term reference), field_network_specific_site_code (text), field_network_verified (boolean);
    // this return the termID
    $network_name_tid = render($item->entity->field_network_name->target_id);
    // this termID is used to load the term object
    $full_taxonomy_term_object = taxonomy_term_load($network_name_tid);
    // then you can get the name of the term, or any other information about the term
    $network_label = $full_taxonomy_term_object->getName();

    // getting the values for the text and boolean fields is more straightforward
    $network_site_code = render($item->entity >field_network_specific_site_code->value);
    $network_site_verified = render($item->entity->field_network_verified->value);

    // in the end you put them together, have conditions and format them as you need
    $element[$delta] = [
      '#markup' => $network_label . $network_site_verified . $network_site_code
    ];
  }

  return $element;
}

```

However, the problems of hard-coding something like this persist. Even though this can be tackled by having the right failsaves in place.

Edit: You don't need the "render" either. Addtionally, the "render" causes a notice in the system logs. I also stumbled upon this useful cheat sheet: https://www.metaltoad.com/blog/drupal-8-entity-api-cheat-sheet
> 0 votes

---
Tags: 8, forms, paragraphs
---


# Question
Title: Get title of referenced item two levels deep with Search API
I have three content types: A, B and C.

```
A refers to B
and B refers to C

```

Now with use of the search api module I search my content types and I want to only output `C`. But in the result I want to show under which items the `C` is put. So some kind of breadcrumb. A view row should look like:

---

Type: C

**Title of node**

Found in: A \> B

---

I am able to output the title of `B` but for some reason I'am not able to get the title of `A`. I tried to work with relationships in view but the `A` reference is not shown even not when I add `B` as a relation. I tried adding the content types to my search index and tried adding them direct as field to my search index ( `field_content_B:entity:field_content_A:entity:title` ). But nothing works. Can someone help me with figuring out what goes wrong?

# Answer
> 0 votes
None of the relations information is stored in C, so when you have C views it can't show relations info out-of-box.

Usually the way to show the "Child" for a "Parent" node is by using the Contextual filter for the Entity Reference field with the "provide default value" and "Content ID from URL" options. In your case A is a child of B, and B is a child of C.

Then you can use the **Custom text** field to construct your text, you can use the Contextual arguments in that field, this will give you information about the "Child" of the node in view row.

Maybe you can work through that to get to the "Grandchild" info, I haven't tried it.

I'd suggest chaining the reverse Relationships, they are called something like "Content referenced from field\_my\_reference", first you add the one for the child, then add another Relationship for the grandchild, and make the second Relationship use the First one. That's how you get to correct nodes.

Add the fields for the B and A titles with using the correct Relationship for each. Thena again you can use the Custom text field to override how their output is worded. You can "Exclude from display" the fields you use in Custom text after you have it showing the way you want inside Custom text.

---
Tags: views, 8, search
---


title: Transfer Aegir site to LAMP

text:
# Question
Title: Transfer Aegir site to LAMP
**Can anyone please advice me on how to move a Drupal 7 site from Aegir to a LAMP stack?**

I've been handed the emergency project of moving a site to a new hosting. Ordinarily, that would be easy enough until I realise the site is loosing it's hosting in a matter of days, **settings.php** is not in the **sites/default** directory nor is the **files** directory. The structure is not standard D7 at all.

I later realised the site is currently hosted on Aegir which admittedly I know nothing about but I wonder if Aegir created the non standard structure. I used the **tree** command to show the structure below:

```
tree project/sites/ -L 2
core-1.23/sites/
|-- all
|   |-- drush
|   |-- libraries
|   |-- modules
|   |-- README.txt
|   `-- themes
|-- default
|   `-- default.settings.php
|-- example.sites.php
|-- sites.php
`-- www.clientsite.com
    |-- drushrc.php
    |-- email
    |-- files
    |-- googlef1245ba6b3c38a3c.hmtl
    |-- libraries
    |-- local.settings.php
    |-- modules
    |-- pdf
    |-- private
    |-- README.md
    |-- settings_.php
    |-- settings.php
    |-- themes
    `-- vendor

```

As you can see, the settings.php is in a sub-directory named after the actual live site, very unlike a vanilla Drupal 7 code structure.

I admit I am stymied by this.

Can anyone tell me if this is how Aegir layout the Drupal structure and **how I can move this to a more traditional D7 structure** ???

# Answer
> 0 votes
You wrote:

> `settings.php` is not in the `sites/default` directory nor is the `files` directory. The structure is not standard D7 at all.

That's incorrect. From the Aegir documentation:

> Aegir installs sites on a platform, which means it places the site directory in `/var/aegir/platforms/<your_platform>/sites/<yoursite.com>`. Many sites can all be installed alongside each other inside a platform's 'sites' directory. This is a standard, built-in Drupal feature known as 'multisite', and it is not unique to Aegir.

...and the official Drupal documentation on multisite:

> It should be noted, however, that using the Aegir hosting system is preferred. It does all of the heavy lifting for you using secure best practices including automatically configuring virtual hosts for both Apache and Nginx, adding HTTPS support, running Composer commands, etc. See the documentation for setting up a "platform", Aegir-speak for a multisite codebase.

So when you ask, *how I can move this to a more traditional D7 structure?*, the correct answer is that you can't. Besides following Drupal standards, Aegir additionally follows best practices for security (e.g. setting secure file permissions) and sustainability (point-and-click upgrades of multiple sites at once). So you're far better off hosting Drupal sites with Aegir than the "traditional" way.

My recommendation would therefore be to set up a new Aegir instance elsewhere, and then remotely import the sites before the older instance is decommissioned. If you're running a LAMP stack yourself, there are very few reasons why you shouldn't be running Aegir for multi-site Drupal.

---
Tags: 7, aegir
---


# Question
Title: Variables injected or set in a Twig file are undefined after the first position of an entity reference field
I have a Paragraph setup that has an entity reference field allowing an editor to select multiple nodes to use in a display.

Based on the count of nodes, I want to trigger a class. I figured a way to do this was with `hook_preprocess_node()` in the theme:

```
$referringItem = $node->_referringItem;
    if (!empty($referringItem)) {
      $referringEntity = $referringItem->getEntity();

      if (
        !empty($referringEntity)
        && ($referringEntity instanceof NodeInterface || $referringEntity instanceof Paragraph)
       ) {
        $referringEntityType = $referringEntity->getType();
        $referringEntityTypeId = $referringEntity->getEntityTypeId();
      }
    }

if ($referringEntityType == 'homepage_feature') {
        $count = $referringEntity->get('field_items')->count();

        // Default.
        $variables['top_image'] = FALSE;
        $variables['right_image'] = FALSE;

        // Should this be count is only 1 AND it is the first delta item in field_feature?
        // If not, any single item Homepage Feature will get top-image which may not be
        // desired.
        if ($count == 1) {
          $variables['top_image'] = TRUE;
        }
      }

```

The logic above might be too involved. Basically I am looking back to see what paragraph type was used, so I can pass new variables to the template.

What I noticed is that even though the code is hit for every node listed, the variables only exist in the first node. I dumped them in the template and it is correct there, but they are undefined in the other nodes.

In Twig, I tried dumping the variable at the top of the template:

`{{ top_image }}`

I can see it in the first record `1` above the markup, and then it never shows again.

How can I ensure the variables are passed to the template, correctly, every time?

**Edit**:

Looks like using the same node with the same view mode in different paragraphs or entity references on the same page can cause this to happen.

Is the solution then to add cache tags/context to the node being rendered to account for what parent is outputting it?

# Answer
> 2 votes
Based on the comments to the question, I extended the `EntityReferenceEntityFormatter` class and modified one part in the `viewElements` method (the rest is the same):

```
  $view_builder = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId());
  $elements[$delta] = $view_builder->view($entity, $view_mode, $entity->language()->getId());

  try {
    $parent = $items->getParent();
    $parent_entity = $parent->getValue();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->id();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->bundle();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->getEntityTypeId();
    $elements[$delta]['#cache']['keys'][] = 'context_aware';

    // Add special information for different paragraph types.
    if ($parent_entity->getEntityTypeId() == 'paragraph') {
      if ($parent_entity->bundle() == 'homepage_feature') {
        $elements[$delta]['#style_flags']['top_image'] = FALSE;
        $elements[$delta]['#style_flags']['right_image'] = FALSE;

        if ($parent_entity->get('field_items')->count() === 1) {
          $elements[$delta]['#style_flags']['top_image'] = TRUE;
        }
      }
    }
  } catch (\Exception $e) {
    // Add logging
  }

```

Later on, down in preprocess\_node:

```
// ONLY for the homepage handling of featured content.
      if ($referringEntityType == 'homepage_feature') {
        $variables['top_image'] = $variables['elements']['#style_flags']['top_image'];
        $variables['right_image'] = $variables['elements']['#style_flags']['right_image'];
      }

```

I was able to then add the same node in the same paragraph type multiple times with the correct information. The correct classes are now applied.

Edit:

Just to add to this too, be sure to set your cacheable dependencies so any change to what holds references will not require a cache clear:

```
$parent = $items->getParent();
$entity->addCacheableDependency($parent);

```

Edit 2:

Thanks to extra guidance from 4k4, I injected the renderer service and reduced down to:

```
    $parent = $items->getParent();
    $parent_entity = $parent->getValue();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->id();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->bundle();
    $elements[$delta]['#cache']['keys'][] = $parent_entity->getEntityTypeId();
    $elements[$delta]['#cache']['keys'][] = 'context_aware';

    if ($this->paragraphDisplaySettings->isApplicable($parent_entity)) {
      $elements[$delta]['#style_flags'] = $this->paragraphDisplaySettings->getSettings($parent_entity);
    }

    $this->renderer->addCacheableDependency($elements[$delta], $parent);

```

`paragraphDisplaySettings` is a custom service object that aids in evaluating different flags to pass through from the original code just to keep it cleaner and leaner. It's working great.

---
Tags: 8, theming
---


title: How do I use an image CAPTCHA?

text:
# Question
Title: How do I use an image CAPTCHA?
I am trying to show a CAPTCHA image in the form of my custom form, but it doesn't appear.

Why doesn't this code show the CAPTCHA as expected?

```
/**
 * Created by PhpStorm.
 * User: sony
 * Date: 28/02/2016
 * Time: 23:23
 */

/**
 * @file
 * Contains \Drupal\contact_form\Form\ContributeForm.
 */

namespace Drupal\contact_form\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\UrlHelper;

/**
 * Contribute form.
 */
class ContributeForm extends FormBase {
    /**
     * {@inheritdoc}
     */
    public function getFormId() {
        return 'contact_form_contribute_form';
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(array $form, FormStateInterface $form_state) {
        $form['Full Name'] = array(
            '#type' => 'textfield',
            '#title' => t('Full Name'),
            '#required' => TRUE,
        );
        $form['E-mail'] = array(
            '#type' => 'email',
            '#title' => t('E-mail'),
        );

        $form['Type of feedback'] = array(
            '#type' => 'radios',
            '#title' => t('Feedback'),
            '#description' => t('Type of feedback'),
            '#options' => array(
                t('Comments or suggestions'),
                t('Questions'),
                t('Report a problem(s)'),
                t('Other'),
            )
        );
        $form['Subject'] = array(
            '#type' => 'textfield',
            '#title' => t('Subject'),
        );
        $form['Your Message'] = array(
            '#type' => 'textarea',
            '#title' => t('Your Message'),
        );
        $form['my_captcha_element'] = array(
            '#type' => 'captcha',
            '#captcha_type' => 'Image',
        );

        $form['sendt'] = array(
            '#type' => 'submit',
            '#value' => t('Send'),
        );
        return $form;

    }

    /**
     * {@inheritdoc}
     */
    public function validateForm(array &$form, FormStateInterface $form_state) {
        if (!UrlHelper::isValid($form_state->getValue('video'), TRUE)) {
            $form_state->setErrorByName('video', $this->t("The video url '%url' is invalid.", array('%url' => $form_state->getValue('video'))));
        }
    }

    /**
     * {@inheritdoc}
     */
    public function submitForm(array &$form, FormStateInterface $form_state) {
        foreach ($form_state->getValues() as $key => $value) {
            drupal_set_message($key . ': ' . $value);
        }
    }

```

# Answer
Captcha is not a valid form element in Drupal 8. Since you haven't listed if you are using any other contributed modules, I am not sure what or where `#type => captcha` comes from.

I advise using Mollom to do captcha handling for forms.

https://www.drupal.org/project/mollom
> 1 votes

# Answer
Captcha is a valid form element if you have captcha module installed.

```
$form['tabs']['upload']['captcha'] = [
  '#type' => 'captcha',
  '#captcha_type' => 'captcha/Math',
]

```

if you want to use recaptcha, the type is `'#captcha_type' => 'recaptcha/reCAPTCHA',`
> 0 votes

---
Tags: forms, 8, captcha
---


# Question
Title: wrong translation in admin/structure/views
I have a multi language site with Drupal 8.7.4 and default language is English.

when i go to en/admin/structure/views i see list of views in English language. if i go to french interface via fr/admin/structure/views i expect to see list of views in french words for example i expect to see 'Surveillance' instead of 'watchdog' but i see all views name in English.

Config Translation is enabled and french translation for view's name is available.

# Answer
The Views list is a config entity list and these are listed override free:

*ConfigEntityListBuilder::load*

```
  public function load() {
    $entity_ids = $this->getEntityIds();
    $entities = $this->storage->loadMultipleOverrideFree($entity_ids);

    // Sort the entities using the entity class's sort() method.
    // See \Drupal\Core\Config\Entity\ConfigEntityBase::sort().
    uasort($entities, [$this->entityType->getClass(), 'sort']);
    return $entities;
  }

```

This is intentional. The pros and cons are discussed in these issues:

Config entity admin lists show configuration with overrides (eg. localized)

Menu overview always shows the untranslated config entities
> 2 votes

# Answer
I was able to reproduce your issue in a fresh Drupal 8.7.5 installation.
I reported the issue in Drupal core issue tracker.

Also, here are a screenshot in which French Views names are displayed in an English interface:
> 1 votes

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


# Question
Title: hook_custom_theme() works except if a user submits a user form with mismatched passwords. Then they get served the admin theme
Title basically. My `hook_custom_theme()` has been working for ages and I only just realised the admin theme is being served for an error when saving a user form ie. mismatched passwords.

A snippet from the top of my function:

```
function custom_theme_change_custom_theme() {
    global $top_bar_color;
    $top_bar_color = '#2b3643';
    if (strpos($_SERVER['HTTP_HOST'], 'example.com') !== false) {
        switch (returnRoleForTheme()) {
            case 'old': $th = 'theme_1'; $top_bar_color = '#2b3643'; break;
            case 'young': $th = 'theme_2'; $top_bar_color = '#6dad19'; break;
            case 'kid': $th = 'theme_3'; $top_bar_color = '#6dad19'; break;
        }
    }
    return $th;
}

```

Any ideas on how to force the theme like for every other part of the website? Why would this page in particular revert to Adminimal?

# Answer
> 0 votes
hook\_custom\_theme()'s documentation says :

> The return value of this hook will be used on all pages except those which have a valid per-page or per-section theme set via a theme callback function in hook\_menu(); the themes on those pages can only be overridden using hook\_menu\_alter().

so i guess that what you need here is having your custom rules ina helper function that you call both in hook\_custom\_theme() and the theme callback of the error page from hook\_menu\_alter()

---
Tags: 7, theming, users
---


# Question
Title: Displaying associative array data in twig
Using drupal 8.7.x

I have an associative array that is returned to twig. However I can't seem to get the data displayed.

Associative array:

```
array_push($mealsArray, ["meal" =>
  [
    ['strMeal' => $mealTitle],
    ['strMealThumb' => $mealImage],
    ['mealUrl' => $mealTitleUrl]
  ]
]);

```

Return to twig:

```
return [
  '#theme' => 'recipe_search_block',
  '#meals' => $meals,
  '#ingredientList' => $ingredients,
  'form' => $form,
];

```

In twig I'm trying to display them like this:

```
   <div class="u-row u-margin-top">
    {% for meal in meals %}
      {% for fields in meal %}
        <div class="u-col-md-3 u-col-xs-6">
          <div class="m-recipe">
            <a class="m-recipe__link"href="/recipes/{{ fields["mealUrl"] }}"></a>
            <header class="m-recipe__header u-margin-bottom">
              <h3>{{ fields["strMeal"] }}</h3>
            </header>
            <div class="m-recipe__image">
              <img src="{{ fields["strMealThumb"] }}" alt="{{ fields["strMeal"] }}">
            </div>
          </div>
        </div>
      {% endfor %}
    {% endfor %}
  </div>

```

When I debug with kint this is the output I get

Any help would be appreciated, thanks in advance!

# Answer
> 1 votes
Sollution:

Associative array:

```
array_push($mealsArray, ["meal" =>
  [
    'strMeal' => $mealTitle,
    'strMealThumb' => $mealImage,
    'mealUrl' => $mealTitleUrl
  ]
]);

```

Twig:

```
{% for meal in meals %}
      {% for fields in meal %}
        <div class="u-col-md-3 u-col-xs-6">
          <div class="m-recipe">
            <a class="m-recipe__link" href="/recipes/{{ fields.mealUrl }}"></a>
            <header class="m-recipe__header u-margin-bottom">
              <h3>{{ fields.strMeal }}</h3>
            </header>
            <div class="m-recipe__image">
              <img src="{{ fields.strMealThumb }}" alt="{{ fields.strMeal }}">
            </div>
          </div>
        </div>
        {% endfor %}
    {% endfor %}

```

The return statement remains unchanged.

---
Tags: theming
---


# Question
Title: Is it possible to show a menu in a view as buttons?
I'm trying to build a page with a quick menu. Now I've created a menu by the regular way and I've shown this on the place i wanted. Now due to the way my site currently looks, this is very out of the shape I wanted it to be.

Now my question is: Is it possible to show my menu items as a view and decorate them with a button (and if possible an icon from the FontAwesome library)?

My idea would look something like this, with the blue things as buttons creating for every menu item:

A module or a work around would both be fine!

# Answer
> 0 votes
with https://www.drupal.org/project/menu\_link\_attributes you can add a css classes to each menu item so that you can theme it as needed.

---
Tags: views, 8
---


# Question
Title: How is the user logout process supposed to work?
I’ve built a complete private site. Everything seems to work. When users wants to log out, they are redirect from /user/logout /user/login?destination=/, which seems the normal behavior, for what I understand.

A client told me he is not redirected to /user/login?destination=/ but stays on /user/logout, getting an Access Denied error.

I can’t reproduce this issue.

How is the logout supposed to work? Is the redirect from /user/logout to /user/login?destination=/ the normal behavior?

# Answer
> 1 votes
> Is the redirect from /user/logout to /user/login?destination=/

No, the normal behavior is to redirect to the frontpage. You probably have a module installed which issues a second redirect when the logged out user doesn't have access to the frontpage.

> How is the user logout process supposed to work?

This is the core controller as example:

*UserController::logout*

```
  /**
   * Logs the current user out.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   A redirection to home page.
   */
  public function logout() {
    user_logout();
    return $this->redirect('<front>');
  }

```

So you only need to call user\_logout() in custom code to implement your own logout.

---
Tags: 8, users
---


title: Disable caching on a route

text:
# Question
Title: Disable caching on a route
I have a route with a parameter, e.g. `/r/{app_id}`. The controller extends `ContainerInjectionInterface`. The method either returns a render array or a `new TrustedRedirectResponse`.

I believe I have a caching problem because subsequent visits to the page will not update even with changing `{app_id}`. If I visit from another browser I get the correct response one time.

My controller is, basically, this:

```
if (!$a) {
  return ['#markup' => 'no'];
}

return new TrustedRedirectResponse($url);

```

I have tried to disable cache in several ways, to no avail:

* `addCacheableDependency`
* putting `#cache => ['max-age' => 0]` on the render array
* `\Drupal::service('page_cache_kill_switch')->trigger();`
* using `$response = new Response()` and `$response->setCache(['max_age' => 0])` and then, from within the conditional, using `$response->setContent('blah')`

Not having luck with any of the above.

# Answer
> 10 votes
You have to do all together, set cache max-age = 0 for all responses the controller returns and apply the kill switch

```
public function mycontroller() {

  \Drupal::service('page_cache_kill_switch')->trigger();

  if (!$a) {
    return [
      '#markup' => 'no',
      '#cache' => ['max-age' => 0],
    ];
  }

  return (new TrustedRedirectResponse($url))
    ->addCacheableDependency((new CacheableMetadata())->setCacheMaxAge(0));
}

```

and then clear the cache one more time.

# Answer
> 12 votes
You can also disable caching via the route under the `options` key like this, `no_cache: 'TRUE'`. Here is a full example of a route:

```
my_awesome_module.do
  path: '/do-awesome'
  defaults:
    _controller: '\Drupal\my_awesome_module\Controller\MyAwesomeModuleController::doAwesome'
  options:
    no_cache: 'TRUE'

```

---
Tags: routes, caching
---


# Question
Title: REST Export Serializer adds quotation marks to my field
I'm using the REST export to expose a list of my nodes including some fields. One of the fields is paragraphs field with subfields.

I have written a formatter for this paragraphs field that puts together some of the fields within the paragraph and renders them as a json object.

The only problem I have is that the serialiser automatically adds quotation marks, which turns my json object into a string and thus renders the formatter futile.

Can I somehow tell the serializer to not do that to my field and just print the json string without doing anything to it? I couldn't find any setting in the view that would help me. Using a "raw output" only prints the paragraph ID.

EDIT: A couple of hours later I stumbled upon this article (https://blog.karmacomputing.co.uk/drupal-8-rest-endpoint-with-entity-reference-field-set-to-unlimited-using-views/) and the REST Views module (https://www.drupal.org/project/rest\_views) which basically does what I want to achieve, but unfortunately only renders the entire paragraph content as an array and doesn't allow to change the labels. A boolean field is also printed as a string. It's close to what I need, but not quite it.

# Answer
> 0 votes
I had to change my overall approach to the problem, but managed to solve the serialising problem by using two additional modules:

https://www.drupal.org/project/views\_field\_view

https://www.drupal.org/project/rest\_export\_nested

The description of the REST Export Nested explains everything. The only thing that might provide problematic is the performance as this involves potentially calling a lot of sub-views. So maybe writing a custom normaliser as indicated in one of the comments is a better approach.

---
Tags: views, 8
---


# Question
Title: How to get entity Translation's title in Twig
i am trying to get row title -node title- in my custom module with `template_preprocess_modulename_view($variables)` and `views-modulename-view.html.twig` with using

```
row.content['#row']._entity.title.value

```

but it always return node title of translation source.

how can i get correct node translation title in twig?

--

**update:**

i am going to clarify my problem:

i have a view which returns nodes without any condition- example of returned output is like:

```
- 'title of node 1 in english'
- 'title of node 1 in french'

```

i want to manipulate title in twig but `row.content['#row']._entity.title.value` returns always node 1 in translation source language. -in this case english-

is it possible to get exact title of row -considering translation and language of returned row- in twig?

**update 2**

in `template_preprocess_modulename_view($variables)` i tried:

```
  $rows = $variables['rows'];

  foreach($rows as $index=>$value){
    if (isset($value['#row'])){
      $row=$value['#row'];
      var_dump($row->_entity->get('langcode')->value);
    }
  }

```

but `$row->_entity->get('langcode')->value` returns language of translation source of row, not language of row itself.

# Answer
> 2 votes
Normally you filter rows having all the same language, but you don't have to. So rows can have different languages.

The code in the question seems to get the entity from the wrong place. See this topic for examples of different kind of rows: How to access raw data in twig template using views table format

A normal views row is a ResultRow object having the property `_entity`, which then should return the translated entity:

```
$entity = $row->_entity;

```

See ResultRow::$\_entity

But it doesn't. Tested it with the pre-installed view Content and I had to get the entity translation of the row language stored in `node_field_data_langcode` before I could get the translated title:

```
foreach (views_get_view_result('content') as $row) {
  $entity = $row->_entity;
  $langcode = $row->node_field_data_langcode;
  $entity = $entity->getTranslation($langcode);
  $translated_title = $entity->label();
}

```

---
Tags: views, 8, theming
---


# Question
Title: 403 Error on AJAX Request in add new item (collection field)
I have normal content type which has 12 collection fields each field has unlimited value when i try to click `add new item` on any field it gives me ajax error

```
An AJAX HTTP error occurred.
HTTP Result Code: 403
Debugging information follows.
Path: /?q=system/ajax
StatusText: Forbidden
ResponseText:

```

I have another content type and also has collection field with unlimited value .. but it works without any problem so please help me why some content type has error and the other doesn't have

by the way: i use D7 and i upgraded it to 7.35 but this problem was before the upgrading

i have checked all the answers in the `Drupal Answers` but unfortunately did it help

**edit:**

```
ResponseText:
@import url("http://example.org/modules/system/system.base.css?nlmla7");
@import url("http://example.org/modules/system/system.base-rtl.css?nlmla7");
@import url("http://example.org/modules/system/system.menus.css?nlmla7");
@import url("http://example.org/modules/system/system.menus-rtl.css?nlmla7");
@import url("http://example.org/modules/system/system.messages.css?nlmla7");
@import url("http://example.org/modules/system/system.messages-rtl.css?nlmla7");
@import url("http://example.org/modules/system/system.theme.css?nlmla7");
@import url("http://example.org/modules/system/system.theme-rtl.css?nlmla7");
@import url("http://example.org/sites/all/modules/date/date_api/date.css?nlmla7");
@import url("http://example.org/sites/all/modules/date/date_api/date-rtl.css?nlmla7");
@import url("http://example.org/sites/all/modules/date/date_popup/themes/datepicker.1.7.css?nlmla7");
@import url("http://example.org/sites/all/modules/date/date_repeat_field/date_repeat_field.css?nlmla7");
@import url("http://example.org/modules/field/theme/field.css?nlmla7");
@import url("http://example.org/modules/field/theme/field-rtl.css?nlmla7");
@import url("http://example.org/sites/all/modules/field_hidden/field_hidden.css?nlmla7");
@import url("http://example.org/modules/node/node.css?nlmla7");
@import url("http://example.org/sites/all/modules/recieve_orders/css/orders_styles.css?nlmla7");
@import url("http://example.org/modules/search/search.css?nlmla7");
@import url("http://example.org/modules/search/search-rtl.css?nlmla7");
@import url("http://example.org/modules/user/user.css?nlmla7");
@import url("http://example.org/modules/user/user-rtl.css?nlmla7");
@import url("http://example.org/sites/all/modules/views/css/views.css?nlmla7");
@import url("http://example.org/sites/all/modules/views/css/views-rtl.css?nlmla7");
@import url("http://example.org/sites/all/modules/admin_menu/admin_menu.css?nlmla7");
@import url("http://example.org/sites/all/modules/admin_menu/admin_menu-rtl.css?nlmla7");
@import url("http://example.org/sites/all/modules/admin_menu/admin_menu.uid1.css?nlmla7");
@import url("http://example.org/sites/all/modules/ctools/css/ctools.css?nlmla7");
@import url("http://example.org/sites/all/modules/adminimal_admin_menu/adminimal_admin_menu.css?nlmla7");
@import url("http://example.org/modules/shortcut/shortcut.css?nlmla7");
@import url("http://example.org/modules/shortcut/shortcut-rtl.css?nlmla7");
@import url("http://example.org/sites/all/themes/adminimal_theme/css/reset.css?nlmla7");
@import url("http://example.org/sites/all/themes/adminimal_theme/css/style.css?nlmla7");
@import url("http://example.org/sites/all/themes/adminimal_theme/css/style-rtl.css?nlmla7");
@import url("http://example.org/sites/all/themes/adminimal_theme/css/mobile.css?nlmla7");
@import url("http://example.org/sites/all/themes/adminimal_theme/css/tablet.css?nlmla7");ySite.org/sites/all/themes/adminimal_theme/css/tablet.css?nlmla7");

```

and there are too many custom modules in my site

**but** the thing which make me more conflicted is why it doesn't give error in the other content type

# Answer
> 0 votes
for what it's worth we just wrestled with this for a while on our own sites. The solution actually ended up being disabling cloudflare on 'system/ajax' URLs. If you're running CF and have this problem - try it!

---
Tags: ajax, entities
---


title: Remove comment link from node teaser

text:
# Question
Title: Remove comment link from node teaser
I want to remove comment link (actually it is `li` element) from node teaser view on homepage and term listing. I want ways to do in controller/service or in template or if possible in admin.

I have created `links--node.html.twig` in my template and place the following code:

```
{% if links -%}
  {%- if heading -%}
    {%- if heading.level -%}
      <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}</{{ heading.level }}>
    {%- else -%}
      <h2{{ heading.attributes }}>{{ heading.text }}</h2>
    {%- endif -%}
  {%- endif -%}
  <ul{{ attributes }}>
    {%- for key, item in links -%}
      <li{{ item.attributes.addClass(key|clean_class) }}>
        {%- if item.link -%}
          {{ item.link }}
        {%- elseif item.text_attributes -%}
          <span{{ item.text_attributes }}>{{ item.text }}</span>
        {%- else -%}
          {{ item.text }}
        {%- endif -%}
      </li>
    {%- endfor -%}
  </ul>
{%- endif %}

```

as here was told. But it did not help my as links go in loop. I could insert `if` condition. But I do not know variables. I tried dump `item` from loop but a page was loading without the end. I do not want to use twig `in` to search for needed item. Actually I need the right way(s) to remove comment link. If I can check `for key, item in links if item.name != "comment"` it could be great. But I prefer do it in code like in proper way without hacks.

# Answer
**Firstly**, dirty way. In the template `links--node.html.twig` change this line `{%- for key, item in links -%}` to `{%- for key, item in links if key != 'comment-add' and key != 'comment-forbidden' -%}`. This is for removing 'comment-add' and 'comment-forbidden' link. If you also want to remove links count apend the line with `and key != 'comment-comments'`. A simplier way to achieve this is to replace all `if`s with `if 'comment' not in key`. Twig's in.

**The second** is more right way. The point is in using the hook `hook_node_links_alter`(doc). This hook alter node links behaviour. There is a core comment module. It realy worth looking if you want to know how node comment works. It requires drupal 8 module knowledge. The service responsible for node comments links is `comment.link_builder` and defined in `core/modules/comment/comment.services.yml`. And while observing `core/modules/comment/src/CommentLinkBuilder.php` you can find that it add different links to render array and all logic. So comment is just a module. So back to hook. It alters node links and add comment links. So you need to remove it again. To do it you can define your own module to create a hook. In module directory you need to create `MODULE.module` file and place the following code there:

```
use Drupal\node\NodeInterface;

function kapusta_node_links_alter(array &$links, NodeInterface $node, array &$context) {
  unset($links['comment__comment']);
}

```

Here nothing special, just implementing `hook_node_links_alter`. It removes comment link.

**The third** way is more elegant but need more work. It is based on similar things as the second way. The point is to rewrite the service `core/modules/comment/src/CommentLinkBuilder.php`. For this you need to define your own module. Then you will create a service with the similar name to `CommentLinkBuilder.php`. The symfony (framework drupal is using) will rewrite the service from comment module. And you will get your profit. So firsly you duplicate the service. To do this you create `MODULE.services.yml` in your module folder. The file content is the following:

```
services:
  comment.link_builder:
    class: Drupal\kapusta\CommentLinkBuilder
    arguments: ['@current_user', '@comment.manager', '@module_handler', '@string_translation', '@entity.manager']

```

Where do I get this? From `core/modules/comment/comment.services.yml`. Just replaced class with my own. Then you create that class. You will get the file `modules/custom/kapusta/src/CommentLinkBuilder.php` with the following content:

```
<?php

namespace Drupal\kapusta;

use Drupal\comment\CommentLinkBuilder as Base;
use Drupal\Core\Entity\FieldableEntityInterface;

class CommentLinkBuilder extends Base{
  public function buildCommentedEntityLinks(FieldableEntityInterface $entity, array &$context) {
    return [];
  }
}

```

'kapusta\` is my module name. So that's it.

**P.S** How I found it. I debugged variables in the twig `{%- for key, item in links -%}`. I discovered tha value of `key` in each iteration. It were `comment-*` keys I wrote about in the beginning. Then I search the project files by `comment-add` and found `CommentLinkBuilder`. With xdebug I came to the hook. Then I realize that it is just simple module. Hope this helps.
> 3 votes

# Answer
Great explanation, what I did was simpler and dirtier by putting in the css display: none. But I should try your suggestion. What I think drupal will be necessary to separate the types of links to be able to use them in different ways in different places. I think the design is for a web design older than how the card links is implemented which is a more modern design, and how it is implemented inside the article are different.
> 0 votes

---
Tags: 8, nodes, comments
---


# Question
Title: Why does d7_user_role need a db connection configured when migration group already defines it
I've just done a super basic user\_role import and I'm trying to do a user import. Both are in the same migration group and the migration group has a souce key to specify which database listed in settings.php to use.

I can migrate and roll back the user\_role import fine, but as soon as I try to import the users, I get "Migration mysite\_user did not meet the requirements. No database connection configured for source plugin d7\_user\_role"

migrate\_plus.migration\_group.basic\_migration.yml

```
uuid: 512c4248-7f60-4b08-9cc2-8d804657262c
langcode: en
status: true
dependencies: {  }
id: basic_migration
label: basic_migration
description: 'basic migrations'
source_type: 'Drupal 7'
module: null
shared_configuration:
  source:
    key: legacy

```

migrate\_plus.migration.mysite\_role.yml

```
uuid: 6e288181-f2fd-4e22-885e-02282cc4d222
langcode: en
status: true
dependencies: {  }
id: mysite_role
class: null
field_plugin_method: null
cck_plugin_method: null
migration_tags:
  - 'Drupal 7'
  - Configuration
migration_group: basic_migration
label: 'Mysite Role'
source:
  plugin: d7_user_role
process:
  id:
    -
      plugin: machine_name
      source: name
    -
      plugin: user_update_8002
  label: name
  permissions:
    -
      plugin: static_map
      source: permissions
      bypass: true
      map:
        'use PHP for block visibility': 'use PHP for settings'
        'administer site-wide contact form': 'administer contact forms'
        'post comments without approval': 'skip comment approval'
        'edit own blog entries': 'edit own blog content'
        'edit any blog entry': 'edit any blog content'
        'delete own blog entries': 'delete own blog content'
        'delete any blog entry': 'delete any blog content'
        'create forum topics': 'create forum content'
        'delete any forum topic': 'delete any forum content'
        'delete own forum topics': 'delete own forum content'
        'edit any forum topic': 'edit any forum content'
        'edit own forum topics': 'edit own forum content'
    -
      plugin: flatten
  weight: weight
destination:
  plugin: 'entity:user_role'
migration_dependencies: null

```

migrate\_plus.migration.mysite\_user.yml

```
uuid: bd0ef271-9c8f-40d7-9b65-8147e4cdda47
langcode: en
status: true
dependencies: {  }
id: mysite_user
class: Drupal\user\Plugin\migrate\User
field_plugin_method: null
cck_plugin_method: null
migration_tags:
  - 'Drupal 7'
  - Content
migration_group: basic_migration
label: 'Mysite User'
source:
  plugin: d7_user
process:
  uid: uid
  name: name
  pass: pass
  mail: mail
  created: created
  access: access
  login: login
  status: status
  timezone: timezone
  langcode:
    plugin: user_langcode
    source: language
    fallback_to_site_default: false
  preferred_langcode:
    plugin: user_langcode
    source: language
    fallback_to_site_default: true
  preferred_admin_langcode:
    plugin: user_langcode
    source: language
    fallback_to_site_default: true
  init: init
  roles:
    plugin: migration_lookup
    migration: d7_user_role
    source: roles
  user_picture:
    -
      plugin: default_value
      source: picture
      default_value: null
    -
      plugin: migration_lookup
      migration: d7_file
destination:
  plugin: 'entity:user'
migration_dependencies:
  required:
    - d7_user_role
    - mysite_role
  optional:
    - d7_field_instance
    - d7_file
    - language
    - default_language
    - user_picture_field_instance
    - user_picture_entity_display
    - user_picture_entity_form_display

```

Any pointers where to start looking would be much appreciated.

# Answer
The section of migrate\_plus.migration.mysite\_user.yml that reads this:

**roles:
plugin: migration\_lookup
migration: d7\_user\_role
source: roles**

has to be edited by switching "d7\_user\_role" for the id of your user role migration, which in your case is "mysite\_role"

**roles:
plugin: migration\_lookup
migration: mysite\_role
source: roles**
> 1 votes

---
Tags: 8, migrations
---


title: ConfirmFormBase to FormBase

text:
# Question
Title: ConfirmFormBase to FormBase
Drupal 8.7.x

I have a Form button with a confirmation page to delete an ingredient. I'm trying to convert it to a standard Form that just deletes it without confirmation, however I keep getting an error.

Confirmation Form (works just fine) src/Form/DeleteIngredient.php:

```
 <?php

namespace Drupal\recipe_search\Form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Url;

/**
 * Class DeleteIngredient
 *
 * @package Drupal\recipe_search\Form
 */
class DeleteIngredient extends ConfirmFormBase{

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'delete_ingredient';
  }

  public $cid;

  public function getQuestion() {
    return t('Do you want to delete %cid?', array('%cid' => $this->cid));
  }

  public function getCancelUrl() {
    return new Url('recipe_search.recipes');
  }

  public function getDescription() {
    return t('Only do this if you are sure!');
  }
  /**
   * {@inheritdoc}
   */
  public function getConfirmText() {
    return t('Delete it!');
  }
  /**
   * {@inheritdoc}
   */
  public function getCancelText() {
    return t('Cancel');
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $cid = NULL) {
    $this->pid = $cid;
    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

    $database = \Drupal::database();
    $database->delete('ingredient_list')
      ->condition('pid', $this->pid)
      ->execute();

    $form_state->setRedirect('recipe_search.recipes');

  }

```

Tried this for normal form without confirmation src/Form/DeleteIngredient.php:

```
<?php

namespace Drupal\recipe_search\Form;

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

/**
 * Class DeleteIngredient
 *
 * @package Drupal\recipe_search\Form
 */
class DeleteIngredient extends FormBase{

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'delete_ingredient';
  }

  public $cid;

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $cid = NULL) {
    $this->pid = $cid;
    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

    $database = \Drupal::database();
    $database->delete('ingredient_list')
      ->condition('pid', $this->pid)
      ->execute();

    $form_state->setRedirect('recipe_search.recipes');

  }
}

```

This is where I return the form to the twig template src/Block/RecipeSearch.php:

```
//FETCH THE INGREDIENTS TO MAKE AN API CALL
$result = $connection->select('ingredient_list', 'il');
$result->fields('il', array('ingredient', 'pid'));
$result->condition('uid', $uid);
$data = $result->execute();
$results = $data->fetchAll(\PDO::FETCH_OBJ);

foreach ($results as $field) {
  $delete = Url::fromUserInput('/delete/'.$field->pid);

  array_push($ingredients, ["ingredient" => $field->ingredient, "delete" => $delete]);
  array_push($ingredientsArray, $field->ingredient);
};

```

This is the Error I'm getting:

> Error: Cannot call abstract method Drupal\Core\Form\FormInterface::buildForm() in Drupal\recipe\_search\Form\DeleteIngredient-\>buildForm() (line 32 of /var/www/html/web/modules/custom/recipe\_search/src/Form/DeleteIngredient.php)

I guess you cannot use buildForm while extending FormBase but I don't know how I should solve this.

Thanks in advance!

# Answer
> 1 votes
There is no `FormBase::buildForm()` method. `FormBase` implements `FormStateInterface`, and the method `FormStateInterface::buildForm()` exists. So when you extend `FormBase`, you must implement `buildForm()`, however you do not/cannot call `parent::buildForm()`. Instead, you must build the form array yourself, and return that.

This differs from `ConfirmForm` which has a `buildForm()` method, which is why when you extend `ConfirmForm` you can call `parent::buildForm()`.

---
Tags: forms
---


# Question
Title: Include external JS/CSS libraries in a module?
What is the Drupal 8 equivalent of including external libraries (like sites/all/libraries) for custom modules?

# Answer
> 3 votes
Quoting this blog post

> **Core API changes in Drupal 8**
>
> The drupal\_add\_js() and drupal\_add\_css() functions for manual inclusions of JS/CSS files have been removed in favour of library definitions that properly declare their dependencies. As a result of this, all modules and also themes have to declare their libraries in order to include JS and/or CSS files. During the development of D8 the way of declaring a library evolved from a renamed info hook (hook\_library\_info()) to finally using YAML (like in many other places in D8) by describing the libraries in \*.libraries.yml files. The info hook finally was removed fully. See the change record for more information. The new hook\_library\_info\_alter() hook is of course still there.
>
> Another big change is the usage of Composer for dependency management, like many other modern frameworks do. Although Composer is primarily for PHP libraries, it can be used for JS libraries too. Using Composer not only spares you manually downloading the library from Github, etc and afterwards manually extracting and uploading the files to your server, but also eliminates the error source of placing the files into the right directory structure. (Note: Composer integration is not fully finished yet, see: https://www.drupal.org/node/2372815)

# Answer
> 1 votes
The module.libraries.yml file is a great improvement in Drupal 8. You can define css and js files you need for one task in your module, so that other modules can use them.

But it is not supposed to make the libraries module completly redundant. For external libraries, that are not specific to one module, it may still be advisable to use the shared library folder:

Libraries API 8.x

To answer the question, the equivalant in drupal 8 is the same as in drupal 7. But we have to see, how the module developers will use the new possibilities, and how much will be left for the shared libraries.

**Edit:**

A lot of people get confused by the name of this 2 hooks:

1. hook\_library\_info()
2. hook\_libraries\_info()

The first one is in core of drupal 7 and got replaced by the new libraries system in drupal 8. The second one is from the contrib module Libraries API and is still alive.

# Answer
> 0 votes
You didn't specify if you wanted the library served via a CDN, but for a lot of people that might be the case. Here's an example with Fontawesome (webfont icon library).

This is from a theme, but the principle is exactly the same with a module.

*mytheme.libraries.yml*:

```
[...]

fontawesome:
  js:
    "//kit.fontawesome.com/1abc23d4ef.js": { type: external }

```

*mytheme.info.yml*:

```
[...]

libraries:
  - mytheme/fontawesome

```

(Then clear the cache.)

If you're including CSS you need to specify it's SMACSS category (base, component, theme etc.) which controls the order it's loaded in.

Note I'm not *actually* sure what `type: external` does (it still works without). If someone can clarify I'll edit the answer.

Further reading:

---
Tags: 8
---


title: Hook to run afer config import

text:
# Question
Title: Hook to run afer config import
I need to run some code after the config for my module is imported(it will create/update a css file that depends on configuration). So what is the correct hook to use? The module install will run only on first time when the module is instaled.

# Answer
> 5 votes
The config system has switched already to events and the documentation for events describes in "My First Drupal 8 Event Subscriber" how to subscribe to a config event:

https://www.drupal.org/docs/8/creating-custom-modules/subscribe-to-and-dispatch-events

See also this example from the Color module:

*/core/modules/color/src/EventSubscriber/ColorConfigCacheInvalidator.php*

```
<?php

namespace Drupal\color\EventSubscriber;

use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Config\ConfigCrudEvent;
use Drupal\Core\Config\ConfigEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * A subscriber invalidating cache tags when color config objects are saved.
 */
class ColorConfigCacheInvalidator implements EventSubscriberInterface {

  /**
   * The cache tags invalidator.
   *
   * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
   */
  protected $cacheTagsInvalidator;

  /**
   * Constructs a ColorConfigCacheInvalidator object.
   *
   * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
   *   The cache tags invalidator.
   */
  public function __construct(CacheTagsInvalidatorInterface $cache_tags_invalidator) {
    $this->cacheTagsInvalidator = $cache_tags_invalidator;
  }

  /**
   * Invalidate cache tags when a color theme config object changes.
   *
   * @param \Drupal\Core\Config\ConfigCrudEvent $event
   *   The Event to process.
   */
  public function onChange(ConfigCrudEvent $event) {
    // Changing a theme's color settings causes the theme's asset library
    // containing the color CSS file to be altered to use a different file.
    if (strpos($event->getConfig()->getName(), 'color.theme.') === 0) {
      $this->cacheTagsInvalidator->invalidateTags(['library_info']);
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[ConfigEvents::SAVE][] = ['onChange'];
    $events[ConfigEvents::DELETE][] = ['onChange'];

    return $events;
  }

}

```

---
Tags: 8, configuration
---


title: How to include a patch to a JS library?

text:
# Question
Title: How to include a patch to a JS library?
I'm using the Superfish library in my Drupal 8.7.x project. I included it in composer.json like this:

```
 "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        },
        {
            "name": "mehrpadin/superfish",
            "version": "2.1",
            "type": "drupal-library",
            "source": {
                 "url": "https://github.com/amclin/Superfish-for-Drupal.git",
                 "comment": "use amclin because of pull request 29",
                 "type": "git",
                 "reference": "c11a5ac10f8c99f809858c0384a4c415411778ce"
            },
            "require": {
                 "composer/installers": "~1.0"
             }
         }
    ]
.....

```

Now I found a patch to a problem I have, so I'd like to apply the patch to the JS file automatically. Much like the way I can apply patches to Drupal modules. Specifically this one:

https://www.drupal.org/files/issues/smallscreen\_patch.diff

Any idea how to do that?

# Answer
As Kevin already mentioned: it can be done using 'composer-patches' in a similar way to patching a Drupal module.

The mentioned patch contained more than I wanted to patch, so I downloaded the patch and added it to a local 'patches' directory. Also, the patch uses a path that starts at 'libraries', while the patch configuration starts one level deeper.

So the patch configuration becomes:

```
....
patches {
    "mehrpadin/superfish": {
        "Fixed nested UL accordion functionality": "./patches/smallscreen_patch.diff"
    }
}
...

```

And the patch itself is changed from:

```
diff --git a/libraries/superfish/sfsmallscreen.js b/libraries/superfish/sfsmallscreen.js
index 9765fed..f5722a9 100644
--- a/libraries/superfish/sfsmallscreen.js
+++ b/libraries/superfish/sfsmallscreen.js

```

to

```
diff --git a/superfish/sfsmallscreen.js b/superfish/sfsmallscreen.js
index 9765fed..f5722a9 100644
--- a/superfish/sfsmallscreen.js
+++ b/superfish/sfsmallscreen.js

```
> 1 votes

---
Tags: 8, composer
---


title: Date input format problem

text:
# Question
Title: Date input format problem
I need to import a large dataset (over 300,000 records) into a Drupal 8 site. I have figured out how to do this with feeds on a small test dataset.

The dates in the records are in the format *June 8, 2018*. I do not see a way to use a Drupal 8 Date field to input dates in this format.

I need to be able to create a view that displays records based on a date range.

What is the best way to get the data into Drupal in a format that a view can use? Would it be to maybe use computed field to transform the data while it is being imported? Or would it be better to maybe execute a SQL query after the data is imported?

# Answer
> 3 votes
Rather than using Feeds, I suggest using the core Migrate module. There is also a core plugin for converting dates during migration, `FormatDate`. This will allow you do specific the input format and the output format. I believe, this process configuration would work in your case:

```
process:
  field_date:
    plugin: format_date
    from_format: 'F j, Y'
    to_format: 'Y-m-d'
    source: event_date

```

If Feeds is your preferred method, then you can try the Feeds Tamper module. Based on the plugin list for Drupal 8, I think you would need to do a "String to Unix timestamp" tamper on the field, followed by a "Unix timestamp to Date" tamper, using 'Y-m-d' as the format string. However, I haven't used Feeds and Feeds Tamper in a long time, and would typically write custom tampers for something like this.

---
Tags: datetime
---


title: Block email from submitting webforms

text:
# Question
Title: Block email from submitting webforms
I have a list of email addresses that I would like not be able to submit in webforms. I can't seem to find a setting for this? Is this currently possible or do I need to make a custom module to implement this?

# Answer
You can probably add a validation pattern to the email address and block a list of email addresses for submitting the form. Or you need to create a custom module.
> 1 votes

---
Tags: 8, webforms
---


# Question
Title: Rule on Saving New Comment not triggered
I want to do some action after saving a news comment which needs comment's CID but I can not do anything after saving news comment!!

I have tested any other actions but none of them triggered by this action.

I have the same problem with the "after updating existing comment".

Only the "before saving comment" action works but I need comment's cid in my code and this value isn't set before saving a comment. So, how can I do my job?

# Answer
> 1 votes
I cannot reproduce this problem. Attached is an export of a rule which fires when a comment is added to an Article or when a comment on an Article is updated. The Rule simply prints a system message containing the CID so that you can see the Rule was able to access the CID. I have tested this and I always get the message, with the CID, when adding or updating a comment.

```
{ "rules_comment_added_or_updated" : {
    "LABEL" : "Comment added or updated",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules_i18n", "rules", "comment" ],
    "ON" : {
      "comment_insert--comment_node_article" : { "bundle" : "comment_node_article" },
      "comment_update--comment_node_article" : { "bundle" : "comment_node_article" }
    },
    "DO" : [
      { "drupal_message" : { "message" : "Comment id = \u0022[comment:cid]\u0022" } }
    ]
  }
}

```

Note that in general you should not be using PHP code except as a last resort. It would be much better to use a custom action or condition instead. Both ways require writing PHP, but a custom action or condition is secure. In any case, neither is needed here.

# Answer
> 0 votes
I used `$comment->cid` in php code instead of `[comment:id]` and it worked correctly.

---
Tags: 7, rules, comments
---


# Question
Title: How to add extra eventlistener to menu object in attached library
This is my first Drupal 8 project and I'm running into a problem figuring out how to attach an extra event handler to an object. I am working on a custom theme using Radix as base theme. I am using Superfish as menu module. One of the issues is that Superfish creates an extra 'root' menu called 'Menu' that is shown when the Bootstrap hamburger menu is clicked. You subsequently need to click on 'Menu' to show the actual (accordion) menu. I found a snippet of code in an issue: https://www.drupal.org/project/superfish/issues/2891228 that hides the 'Menu' toggle, but I cannot get it to work.

I have setup a library definition and created a 'script.js':

```
import "popper.js";
import "bootstrap";

(function($, Drupal) {
  Drupal.behaviors.helloWorld = {
    attach(context) {
      console.log("Hello World");
    }
  };

  Drupal.behaviors.myMainMenu = {
    attach(context) {
      console.log("myMainMenu: " + context.toString());
      $(".navbar-collapse", context).once('myMainMenu').on(
        "show shown shown.bs.collapse show.bs.collapse",
        () => {
        console.log("navbar-collapse");
        if (!$("#superfish-main-accordion").hasClass("sf-expanded")) {
          console.log('no expand');
          $(".superfish-main-toggle")
            .click()
            .hide();
        }
      });
    }
  };
})(jQuery, Drupal);

```

I know the script runs, because I see 'Hello World' and 'myMainMenu' + some glob several times in the console. But I never manage to get the other console messages.

I also know the code in the if statement is correct, because, if I run it manually in the console, it works as intended.

What should be the correct code?

# Answer
> 0 votes
Couple of problems. But the main two are:

1. In Drupal 8, you need to call `$.each()` on `$.once()`
2. In Drupal you don't need to call `$.on()` on elements. The combination of `Drupal.behaviors` and `$.once()` achieves the same goal.

So your code should be something like:

```
$(".navbar-collapse", context).once('myMainMenu').each(function () {
  // Do stuff here
});

```

---
Tags: 8, theming, javascript
---


# Question
Title: How to disable Toolbar on certain pages / theme?
Before deprecation of `hook_page_build/hook_page_build_alter()` we used good old method:

```
$page['page_top']['toolbar']['#access'] = FALSE;

```

(*Source*)

It disabled Toolbar for specific route in specific theme.

Now I checked `hook_page_top()`, `hook_toolbar()` and `hook_preprocess_page()`. Nothing helped, so I temporarily removed `{{ page_top }}` region from my *html.html.twig* but it doesn't look as the right approach.

# Answer
*page\_top* and *page\_bottom* are still available, but on html.html.twig. `template_preprocess_html()` initializes those variables with the following code.

```
  $variables['page_top'] = NULL;
  if (isset($variables['html']['page_top'])) {
    $variables['page_top'] = $variables['html']['page_top'];
    unset($variables['html']['page_top']);
  }
  $variables['page_bottom'] = NULL;
  if (isset($variables['html']['page_bottom'])) {
    $variables['page_bottom'] = $variables['html']['page_bottom'];
    unset($variables['html']['page_bottom']);
  }

```

Since `toolbar_page_top()` uses the following code, I take you can use `hook_preprocess_html()` to avoid the toolbar appears.

```
  $page_top['toolbar'] = array(
    '#type' => 'toolbar',
    '#access' => \Drupal::currentUser()->hasPermission('access toolbar'),
    '#cache' => [
      'keys' => ['toolbar'],
      'contexts' => ['user.permissions'],
    ],
  );

```

Bear in mind that a note on Added hook\_page\_attachments(\_alter)() and removed hook\_page\_build/alter() says:

> You no longer can change $page\['content'\] (or, generally speaking, $page\[$region\_name\]) into something completely different.
> 1 votes

# Answer
The alternative is implementing `hook_module_implements_alter()` to remove the implementation of `hook_page_top()` done from the Toolbar module, implement `hook_page_top()` in your module, and call `toolbar_page_top()` when necessary.

```
function mymodule_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'page_top') {
    $group = $implementations['mymodule'];
    unset($implementations['mymodule']);
    unset($implementations['toolbar']);
    $implementations['mymodule'] = $group;
  }
}

function mymodule_page_top(array &$page_top) {
  $theme = \Drupal::theme()->getActiveTheme()->getName();
  if ($theme != "theme where you don't want the toolbar" && \Drupal::moduleHandler()->moduleExists('toolbar')) {
    toolbar_page_top($page_top);
  }
}

```

In the example code I am showing, the toolbar is added only when the current theme is not a specific one.
> 1 votes

# Answer
The complexity with Toolbar removal is that not only markup in `page_top` must be removed, but also classes added to the `<body>`.

The code below allows to add `$settings['hide_admin_toolbar'] = TRUE;` to your `settings.local.php` and remove both Toolbar markup and classes.

```
/**
 * Implements template_preprocess_html().
 */
function MYTHEME_preprocess_html(&$variables) {
  // Hide admin toolbar.
  if (Settings::get('hide_admin_toolbar')) {
    if (!empty($variables['attributes']['class'])) {
      unset($variables['page_top']['toolbar']);
      $variables['attributes']['class'] = array_filter($variables['attributes']['class'], function ($value) {
        return strpos($value, 'toolbar-') !== 0;
      });
    }
  }
}

```
> 1 votes

---
Tags: 8
---


# Question
Title: One field (entity reference - paragraph) with two display modes
I am having issue with displaying one field twice in my template having different display modes.

I have a content type **basic page** with field **field\_gallery** (which is entity reference on paragraph). In template node--page--full.html.twig I want to render **field\_gallery** twice. Once using **default** display mode and second using **teaser**.

```
<div class="container">
    {# this as teaser #}
    {{ content.field_gallery }}

    {# this as default or whatever #}
    {{ content.field_gallery }}
</div>

```

I tried do it using **hook\_preprocess\_node**, but could not achieve the result I want.

```
$variables['custom_display_mode'] = $variables['node']->get('field_gallery')
    ->view(array(
       'label' => 'hidden',
       'type' => 'teaser'
));

```

I do not want to use any custom module, I'm kinda new to drupal hooks and i'm sure that it must be possible somehow, to set custom variable and print it in my template.

Thanks.

# Answer
An array with `'type' => 'teaser'` is specifying a field formatter, but you probably don't have a field formatter with this name.

You need to add the view mode (display mode) as string argument to view():.

```
$variables['custom_display_mode'] = $variables['node']->get('field_gallery')
  ->view('teaser');

```

For more info see How to apply a Field Formatter to a node field programmatically?
> 0 votes

---
Tags: 8, hooks, paragraphs
---


title: Permissions Rebuild fails

text:
# Question
Title: Permissions Rebuild fails
After I installed a quiz module on my Drupal 7 site, it asked me to rebuild permissions. when I try to rebuild it throws this error:

I've tried everything that I found online, including:

* increasing web server RAM
* max\_execution\_time = 1600
* max\_input\_time = 180
* max\_input\_nesting\_level = 300
* memory\_limit = 512M
* disabling batch mode from node.module core file

nothing seems to work.

There are about 600k records in the node table. I know this is a lot, and probably it causes my issue, but what is the workaround? How can I rebuild permissions with this many nodes easily?

# Answer
Wherever that "Illegal access" Ajax error comes from, I recommend to rebuild node access from the command line instead. With Drush the following command should do it.

```
$ drush php-eval 'node_access_rebuild();'

```

---

With that many (600k) records in your database it may also be better to have that done by some more advanced process like the one provided by the Node Access Rebuild Progressive module. It also provides its own Drush command.

```
$ drush node-access-rebuild-progressive

```

> ### Approach
>
> The module works by processing nodes in chunks, from highest node.nid to lowest, until all nodes have been recomputed, storing the last processed nid in a variable (d7) / as state (d8). This ensure no nodes can be skipped, while avoiding having to populate a Queue or other equivalent mechanism, which can be heavy in itself.
> 0 votes

---
Tags: 7
---


# Question
Title: Node Reference Argument In loadByProperties() while Creating API
I have a custom module which generates an API, I want the API to filter content based on a node reference field. How do I pass the field **field\_author**(Entity Reference from another content type) field as an argument to loadByProperties?

```
public function get() {

$entities = \Drupal::entityTypeManager()->getStorage('node')-
>loadByProperties(['field_author' => 'Holmes']);

}

```

# Answer
> 2 votes
Thanks to 4k4

I modified my code to

```
    $entities = \Drupal::entityTypeManager()->getStorage('node')-
    >loadByProperties(['field_author' => '469']);

```

Where 469 is the nid of my Referenced Node

---
Tags: entities
---


# Question
Title: How to create a Search API search box that redirects you to the search page
I am using Drupal 8 and the Search API. I have created a search page using the API and views (basically modified the view that came prebuilt when you install the search API). Everything works as expected when you are on the search page doing a search.

The problem I am having is that I would like to create a search block identical to the one the default Drupal Search creates with the same behaviour. Meaning that when you enter a search term, it redirects you to the search page displaying the search results. I can't figure how to do this (assuming it is possible to do so).

I have created a search block but it wants to display the results of the search in the block itself. I don't know how to make the search block redirect to the search page.

I know when using the default search block you can implement the following hook:

```
function mytheme_search_box_form_submit($form, &$form_state) {
   $form_state['#redirect'] = 'path of redirect';
}

```

Is there something similar for the Search API?

# Answer
There was a similar question for Drupal 7 Expose a view's filters both in a block, and in the actual view. In Drupal 8 this should be much easier, you can do this in UI:

Place the block `Exposed form: search_content-page_1` a second time, now in the region *Content* above the block *Main page content* and configure the visibility to show only on pages with the path `/search/content`.
> 3 votes

# Answer
You can create a view page of search and link it like '/search' and use this HTML code to get terms into the search page:

```
<form action="/search" method="get" id="search-block-form" accept-charset="UTF-8">
<input data-drupal-selector="edit-keys" type="search" id="edit-keys" name="keys" value="" size="15" maxlength="128" class="search"/>
    </form>

```
> 0 votes

# Answer
Just add a complement to the answers for D8

> Place the block Exposed form: search\_content-page\_1 a second time, now in the region Content above the block Main page content and configure the visibility to show only on pages with the path /search/content.

You need to set to YES in you page views in "advanced" tab "Exposed form in block" If you try that with simple block views is not working.
> 0 votes

---
Tags: 8, search
---


# Question
Title: Prevent clubbing of server side error messages on top
I have inline form errors module enabled on my drupal 8 site. The server-side errors that appear on form submission are appearing as clubbed together like below:

How to change this error language and prevent clubbing for example if there would have been multiple errors the message would have been "2 errors have been found: FieldName1, FieldName2".

Is it a part of core and how to show errors in different lines?

# Answer
You can disable that module to return to the more traditional line-by-line error output globally, or hook into it programatically form-by-form:

```
function MODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'foo_form') {
    $form['#disable_inline_form_errors'] = TRUE;
  }
}

```
> 2 votes

---
Tags: 8, theming, forms
---


# Question
Title: How can I add a pager to the top of a forum?
I am using the standard forum module that comes with Drupal 8. The problem is, when I view a forum node, it shows the pager the bottom. I want the pager to also appear at the top.

The closest I've been able to come is editing the "comment--comment\_forum.html.twig" template. If I put random text at the top of this template, then I can see the text appearing at the right spot I want. But if I put this:

```
{{ pager }}

```

Then nothing shows. So the comment--comment\_forum.html.twig template doesn't know what "pager" is.

Does anyone know where the correct place is to add a pager to the top of forum posts?

# Answer
Pager is known within the "views-view.html.twig" file: /core/modules/views/templates/views-view.html.twig

If you are using a contributed or custom theme you can override that file and move the pager output where you'd like. So your new file would live here: `/themes/custom/MY_THEME/templates/views-view.html.twig"` for example.

As near as I can tell there's no setting for this in core currently, although it's been requested.

See also: https://api.drupal.org/api/drupal/core%21modules%21views%21templates%21views-view.html.twig/8.7.x

https://api.drupal.org/api/drupal/core%21modules%21views%21views.theme.inc/function/template\_preprocess\_views\_view/8.7.x
> 2 votes

---
Tags: 8, theming
---


# Question
Title: Custom Entity: define a view in entity reference field
I defined a custom entity and for a entity reference field I want to set the view reference widget and a view/ display to be used instead of an autocomplete.

I tried many different settings - nothing worked. The latest version not working is:

```
$fields['user'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('User account'))
  ->setDescription(t('The user account this profile is connected to'))
  ->setSetting('target_type','user')
  ->setDisplayOptions('view', array(
    'label' => 'inline',
    'type' => 'string',
    'weight' => -6,
  ))
  ->setDisplayOptions('form', array(
    'type' => 'views',
    'settings' => array(
      'handler_settings' => array(
        'view_name' => 'users_without_profile',
        'display_name' => 'entity_reference_1',
        'arguments' => []
      ),
      'weight' => 20
    )

  ))
  ->setDisplayConfigurable('form', TRUE)
  ->setDisplayConfigurable('view', TRUE);

```

For the form view setting I also tried

```
  ->setDisplayOptions('form', array(
    'type' => 'views',
    'settings' => array(
      'view_name' => 'users_without_profile',
      'display_name' => 'entity_reference_1',
      'arguments' => [],
      'weight' => 20
    )
  ))

```

and

```
  ->setDisplayOptions('form', array(
    'type' => 'entity_reference_autocomplete',
    'settings' => array(
        'handler' => 'views',
        'handler_settings' => array(
            'view_name' => 'users_without_profile',
            'display_name' => 'entity_reference_1',
            'arguments' => [],
        ),
        'weight' => 20
    )
  ))

```

No success. Can somebody give me a hint?

# Answer
> 2 votes
It seems that the previous answer was missing a small detail: the information about the view needs to be wrapped into an array with key 'view' llike following:

```
$fields['user'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('User account'))
  ->setDescription(t('The user account this profile is connected to'))
  ->setSetting('target_type','user')
  ->setSetting('handler', 'views')
  ->setSetting('handler_settings', [
    'view' => [
      'view_name' => 'users_without_profile',
      'display_name' => 'entity_reference_1',
      'arguments' => [],
    ]
  ])

```

In this way it is finally working

# Answer
> 1 votes
The handler settings are part of the base field itself, rather than being a setting for the form display.

This should work:

```
$fields['user'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('User account'))
  ->setDescription(t('The user account this profile is connected to'))
  ->setSetting('target_type','user')
  ->setSetting('handler', 'views')
  ->setSetting('handler_settings', [
    'view_name' => 'users_without_profile',
    'display_name' => 'entity_reference_1',
    'arguments' => [],
  ])
  ...

```

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


# Question
Title: Only allow 1 discount using commerce_discount
I am having trouble finding out how to only allow 1 discount per order.

eg. a specific user role allows 15% discount on their order. We also have another discount set up that applies a further 15% on a certain product.

We don't want to allow both discounts to be applied when that specific user role orders that product.

We are using:

* Drupal 7
* Commerce 7.x-1.13
* Commerce\_discount v 7.x-1.0-alpha5

# Answer
Your version of Commerce Discount is too outdated to support discount compatibility. However, it's so old, that the upgrade process may be complicated. Drupal Commerce itself is also currently at version 1.15, so that will need to be updated, too.

I'd recommend creating a copy of your website and bringing those modules up to date, maybe even one version at a time, running update.php in between each upgrade. (Theoretically, it should work fine to run update.php all at once, but Commerce Discount has to do a lot of field manipulation in its update functions, and I just worry about the potential for things to break...)

Once you do that, you'll have discount compatibility settings that will allow you to enforce a discount being incompatible with any other discount, and by adjusting the sort order on the discounts you can identify which discounts should apply first to ensure the restricted one applies first when possible.
> 0 votes

---
Tags: 7, commerce
---