# Question
Title: Using the built in summary feature when using ONLY paragraphs module for text
I want to have more flexibility in creating content as usual. Therefore, I use the Paragraphs module, and I also **disabled the standard body text**. So now, a user can now freely decide how he wants to mix images, text and other content (like embedded videos). For example, an article could now start with a text followed by a full size image, or with 2 half size images followed by a full size video and then the text and so on.

So far so good. Now the problem is that I loose the standard summary function since the default body text is just disabled. This is especially a problem for any list of articles, i.e. the front page.

I have managed to kinda solve this problem by a custom preprocess hook:

```
function MY_THEME_preprocess_node(array &$variables) {

  $node  = \Drupal\node\Entity\Node::load($variables['node']->id());

  if ($node->field_paragraph && !empty($node->field_paragraph->getValue())) {

    foreach ($node->field_paragraph->getValue() as $key => $value) {
      $paragraph = FALSE;
      if (!empty($value['entity'])) {
        // Use that, we're probably previewing.
        $paragraph = $value['entity'];
      } elseif (!empty($value['target_id'])) {
        $paragraph = Paragraph::load($value['target_id']);
      }

      if (!empty($paragraph) && $paragraph instanceof Paragraph) {

        $summary = $paragraph->getSummary();

        if ($summary && $paragraph->type->getValue()[0]["target_id"] === "text") {
          $variables['summary'] = $summary;
          break;
        }
      }
    }
  }
}

```

What this does is to loop over all paragraph entries (if any) in a given node and **stop iterating at the first occurence** of a paragraph type named "text", if there is **also** a result for the `getSummary()` function, i.e. this paragraph item also contains some text. Keep in mind that I am far from being a Drupal expert, so this code might not be the optimal way?

However, I cannot seem to control the length of the summary, also any headlines defined in the same paragraph are included as well. Last but not least, the result also contains unneeded markup, so in my `node--article--teaser.html.twig` twig template I have to strip out those tags again:

```
<p>{{ summary|striptags }}</p>

```

The next problem arises when I want to use that summary for the description meta tags on any given article page (so in this case, NOT the pages that contain only lists of articles). Usually I would just use the Metatags module and use this for the description: `[node:summary]`

Of course that does not work here, and I can imagine that further down the road I will encounter more problems like this.

Therefore, it seems to me that the cleanest way would be to kinda **emulate** `[node:summary]`, i.e. that this value is automatically calculated by something similar to the function I used above. So for the consumer of this value this would look **identical** as if the page / node had an actual "default" summary.

Now, is this possible at all, and if "yes" how can I achieve this? Any insights are greatly appreciated!

# Answer
> 0 votes
Well, looks like it is time again to answer my own question!

So, since the Metatag Module I want to also use is based on tokens anyway, I have managed to implement this using my own module which in turn just defines an additional custom token which in turn returns my desired summary. Here is what my current `custom_summary_token.module` code looks like right now (still work in progress):

```
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\paragraphs\Entity\Paragraph;

function custom_summary_token_token_info(){
    $type = [
        'name' => t('Nodes'),
        'description' => t('Tokens related to individual nodes.'),
        'needs-data' => 'node'
    ];

    $node['custom_summary'] = array(
        'name' => t("Custom Summary"),
        'description' => t("Token for dynamically generating a node summary, depending on the content. Used for extracting text when not using standard body field, but only paragraphs."),
    );

    return [
        'types' => ['node' => $type],
        'tokens' => ['node' => $node],
    ];
}

function custom_summary_token_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata){

    if (!isset($data['node'])) { return; }

    $replacements = array();
    $node = $data['node'];

    if($type == 'node' && !empty($node)) {

        foreach ($tokens as $name => $original) {

            switch ($name) {

                case 'custom_summary':

                    if (!empty($node->body->value)) {

                        $text = strip_tags($node->body->value);

                    } else if ($node->field_summary && !empty($node->field_summary->getValue())) {

                        $text = $node->field_summary->getValue()[0]["value"];

                    } else if ($node->field_paragraph_test && !empty($node->field_paragraph_test->getValue())) {

                        foreach ($node->field_paragraph_test->getValue() as $key => $value) {
                            $paragraph = FALSE;
                            if (!empty($value['entity'])) {
                                $paragraph = $value['entity']; // Use that, we're probably previewing.
                            } elseif (!empty($value['target_id'])) {
                                $paragraph = Paragraph::load($value['target_id']);
                            }
                            if ($paragraph !== FALSE && $paragraph instanceof Paragraph && $paragraph->getType() === "text") {
                                $text = strip_tags($paragraph->get('field_text_body')->value);
                                break;
                            }
                        }

                    }

                    if (strlen($text) > 150) {
                        $text = substr($text, 0, 150)." ...";
                    }

                    $text = str_replace(" ", " ", $text); // filter out artefact when editing with chrome
                    $replacements[$original] = $text;
                    break;
            }
        }
    }

    return $replacements;

}

```

So what this does in that tokens hook is (after checking that we have the right token of course) first to look for an ordinary default body text which is not empty. Simply because then this also works for my other (in this case also simpler) content types. Then, the code looks for a custom field named `field_summary`. Turned out that some users actually want to create a custom summary, so yeah now they can do that as well. For those who don't (the majority ...), the code then looks for the **first** paragraph instance which is also a text block (and not empty). Last but not least, tags are stripped, and the whole thing is truncated to 150 chars, with some "..." appended for good measure.

Now, I can use this just like any token in my Metatag setup: `[node:custom_summary]`, and - with a little help from the twig tweak module - also in any template:

```
{{ drupal_token('node:custom_summary', { node: node }) }}

```

Of course this implementation still might be too naive or there would be an even better way, also I am not sure how big the performance impact of such a solution is. But hey - at least this works!

What would you think?

---
Tags: paragraphs
---


title: hook_node_update not working

text:
# Question
Title: hook_node_update not working
I placed the following function in my custom module.

```
function MYMODULE_node_update($node) {
  if ($node->type === 'page') {
    $node->title = 'test';
  }
}

```

When editing and saving a node of content type page nothing happens. What can be the issue?

---

Problem solved. It seemed to be caused by the following:

my custom module wasn't ending with ?\> and above all my module name was custom\_site.module and my hooks started with custom. This didn't give problems before with my other hooks so I never noticed. (This helped: https://drupal.stackexchange.com/a/111272/85560)

My module name now is custom.module and now custom\_node\_presave() works.

# Answer
> 2 votes
You should use hook\_node\_presave if you want to change a field's value as the hook is invoked from node\_save() before the node is saved to the database. And as leymannx stated, make sure you clear the cache before implementing a new hook.

---
Tags: 7, nodes, hooks
---


# Question
Title: Views: Is it possible to Group "exposed" filters in a <div> and add css to it?
In Drupal 7, I have a Views which contained "content: ID", "Content: Type", "Content: Title", "Content: Organization", Conent: City", "Content: State" and "Date: Date(node)". They are all exposed. How can I group them into 3 groups(the group in rearrange only give the feature to add "and" or "or" group), so I can add CSS and make them as an expandable list. Is it possible?

# Answer
Exposed filters appear in a form so you have to use hook\_form\_alter as well as hook\_theme to theme any form.

Using hook\_form\_alter assign a new theme to that particulat form. hook\_theme is usead for register a new theme.

For more information about form theming visit here
> 1 votes

# Answer
Use Views exposed groups. From the project page:

> Adds a new exposed filter style where exposed filters can be grouped into fieldsets (either traditional fieldsets, collapsed fieldsets, or vertical tabs). This is especially useful when a view has an unwieldily number of exposed filter options.
> 0 votes

# Answer
Currently, the Views Exposed Form Fieldset module is probably the way to go as that is actively supported and has both Drupal 7 and 8 versions.
> 0 votes

---
Tags: views, theming
---


# Question
Title: Changing field instance display settings for view_mode
### Background

In the user.module file in `user_build_content()`, there is a line that adds fields for a given view\_mode:

```
$account->content += field_attach_view('user', $account, $view_mode, $langcode);

```

The documentation for the `field_attach_view()` function says

> Each field is displayed according to the display options specified in the $instance definition for the given $view\_mode.

Digging further, I find that the instance definitions are loaded/cached using `FieldInfo->getBundleInstances()`, which loads them from the `field_config_instance` table in the database in `field_read_instances()`.

### Question

I have some custom user fields already being displayed for the 'teaser' view\_mode, to the exclusion of others, and I cannot find where this is coming from since no hook appears to do it in the code.

How do I change the display settings of a field for a specific view\_mode? Is there a place to do this in the field UI somewhere?

**Edit:** I found the defaults coming from `hook_field_default_field_instances()`, which were exported into a module using the Features module. Can anyone tell me where I can change them in the UI in order to re-export the feature?

# Answer
This took me so long to find. Account Settings -\> Manage Display

```
admin/config/people/accounts/display/teaser

```
> 0 votes

---
Tags: 7, users
---


# Question
Title: Use hook_views_pre_render() to change field to url link
I want to use hook\_views\_pre\_render() to read in a view and change a field output to a clickable link.

Here is code:

```
function sbn_views_pre_render(ViewExecutable $view) {
    // https://drupal.stackexchange.com/questions/272495/how-to-get-views-field-names-values-for-hook-views-pre-render
    if ($view->id() == 'find_paragraphs') {
      foreach ($view->result as $key => $value) {
        $parent_id_value =  $value->_entity->parent_id->getValue()[0]['value'];
        $parent_type_value =  $value->_entity->parent_type->getValue()[0]['value'];
        $private_files = $value->_entity->field_private_files->getValue()[0]['value'];
        if ($parent_type_value == 'node') {
          $link = '<a href="/node/'.$parent_id_value.'">'.$parent_id_value.'</a>';
          // $value->_entity->set('parent_id', $link);
        }
        if ($parent_type_value == 'paragraph') {
        }
      }
    }
}

```

Formatting the $link value using standard html coding does not work. Any ideas on how to format the link from within this hook so that the rendered field is a clickable link?

# Answer
I have not been able to figure out how to conditionally change field to link using hook\_views\_pre\_render(), but I did figure out how to do it within the Views UI:

Fields-\>Parent ID-\>Rewrite results-\>**Override the output of this field with custom text:**

```
{% if parent_type == 'paragraph' %}
<a href="/find-paragraphs?id={{ parent_id }}">{{ parent_id }}</a>
{% else %}
<a href="/node/{{ parent_id }}">{{ parent_id }}</a>
{% endif %}

```
> 0 votes

---
Tags: views, hooks
---


# Question
Title: Why would a multilingual site sometimes say "Save (this translation)" and other times say "Save (all translations)"?
We have a multilingual Drupal 8 site supporting 17 different languages and many more localized versions of those languages.

I have been noticing that sometimes when I am editing a node it says "Save (this translation)" but then other times it says "Save (all translations)".

What is triggering it to act differently at times? Have we configured something wrong with our translations/multilingual setup?

With what we are doing I believe we want them to save independently of each other.

# Answer
> 4 votes
The text of the submit button depends only on the translation settings of the status field. If the field "Publishing status" is not translatable for the content type, the button says "Save (all translations)".

You can change the language settings for *content types, taxonomy vocabularies, user profiles* here: /admin/config/regional/content-language

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


# Question
Title: How do you enable translation for a field which was defined by a contrib module?
I am trying to enable translation for a field which was defined by a different module.

The problem is this field does not list in the UI. When I checked the definition for this field in `hook_entity_field_storage_info` I can see the `setTranslatable(TRUE)` is missing. So I added the same in `hook_entity_field_storage_info_alter` . After this I can see the field listing in the UI for translation, but when I enable the checkbox and submit the value is not saved.

How can I enable translation for this field?

# Answer
> 2 votes
After a bit of struggle and research, here is the approach taken -

**custom\_module.install file -**

```
/**
 * Enable translation for workbench_reviewer field.
 * Implements hook_update_n.
*/
function hook_update_xxxx() {
  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
  $field_storage_definition_node = $entity_definition_update_manager->getFieldStorageDefinition('workbench_reviewer', 'node');
  $field_storage_definition_node->setTranslatable(TRUE);
  $entity_definition_update_manager->updateFieldStorageDefinition($field_storage_definition_node);

}

```

**custom\_module.module file -**

```
/**
 * Implements hook_entity_field_storage_info_alter().
 */
function hook_entity_field_storage_info_alter(&$fields, EntityTypeInterface $entity_type) {
  // Alter translation settings.
  if (($entity_type->id() == 'node' || $entity_type->id() == 'taxonomy_term') && !empty($fields['workbench_reviewer'])) {
    $fields['workbench_reviewer']->setTranslatable(TRUE);
  }
}

/**
 * Implements hook_entity_bundle_field_info_alter().
 */
function hook_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  // Alter translation settings.
  if (($entity_type->id() == 'node' || $entity_type->id() == 'taxonomy_term') && !empty($fields['workbench_reviewer'])) {
    $fields['workbench_reviewer']->setTranslatable(TRUE);
  }
}

```

Once running `drush updb` I can see the field appearing in translation UI with the **checkbox enabled**.

# Answer
> -1 votes
You can set it to “Translatable” at the “Entity” level and as such you need the following hook.

```
hook_entity_base_field_info_alter

```

It alters existing field definitions -like ones defined by other modules. There is also

```
[hook_entity_base_field_info]

```

to provide new field definitions

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21entity.api.php/function/hook\_entity\_base\_field\_info/8.8.x

The hook you used **\[hook\_entity\_field\_storage\_info\_alter\]** works at the field level.

For example, if some module wanted to create Entity for new field ( called my-title) and make it Translatable at the “Entity” level it would be like:

```
$fields[‘my-title’] = BaseFieldDefinition::create(‘string’)
   →setTranslatable(TRUE);

```

So, the the hook(described above) is changing such a “base definition of the given Entity”.

The Steps you will need in your code is:

1) Load the given Entity.

2) Set it by using \[setTranslatable(TRUE)\].

3) save it (similar to $node→save();).

For example, for the “Article” NodeType, step 1 can be

```
$type = \Drupal::entityTypeManager()→getStorage(‘node_type’)→
load(article’);

```

Check out the following for deeper understanding:

```
\Drupal\core\Entity\Query\QueryInterface.

 BaseFieldDefinition’s setTranslatable method
  & isTranslatable method

```

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Field%21BaseFieldDefinition.php/class/BaseFieldDefinition/8.8.x

The docs have it buried it

> In Drupal 8 field language is no longer exposed in the public API, instead fields are attached to language-aware entity objects from which they "inherit" their language

https://www.drupal.org/docs/8/api/entity-api/entity-translation-api

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


# Question
Title: How to programmatically clear/refresh module file cache?
I'm maintaining a module, and have reworked the file structure of the module to make it more... modular.

In the update functions, some of the new files are referenced, but Drupal isn't aware of the new files until the cache has been cleared. The files are included in the .info file.

Please can someone tell me how to get Drupal to refresh its list of the files in this module?

Thanks,

\[Side note - quite surprised that hooks and cache aren't available as tags!\]

# Answer
Add a MYMODULE.install file to your module. In there implement `hook_update_N` to flush all caches. When others update your module, and then do database updates, Drupal will pick up this hook and flushes the cache and your new files will be recognized.

```
/**
 * Pick up new files.
 */
function MYMODULE_update_7100(&$sandbox) {
  drupal_flush_all_caches();
}

```
> 0 votes

---
Tags: 7
---


# Question
Title: How can I have a view to load more rows on clicking a "Load more" button?
We have created a view, `myview`, where we want to display 3 nodes (content type = basic) and add a View All button on page load. The purpose of the 'View All' button will be to show 6 more (the view is supposed to show max 9).

**How can we display 3 nodes with a View All button?**

What we tried, but the view did not display the view all button nor did it allow me to limit to total of 9. I also could not find an appropriate view hook to do what i am looking for.

View settings:

* Change pager plugin to full
* change pager plugin to mini

# Answer
Looks like Views Infinite Scroll is a good option for you:

> Views infinite scroll allows you to load and display pages of any view inline, using AJAX (this has been called infinite scrolling, load more, autopaging, endless pages and more). The pager can be triggered with the press of a button or automatically as the user scrolls to the bottom of the view's content.

Here's the pager settings:
> 7 votes

# Answer
There are more ways of solving it depending on your circumstances.

The obvious way is through 2 views displays with different paths, or as parent-child `path3` for the first one and `path3/path9` for the second one (you can set them as Drupal tabs that way, so Drupal tab can play the role of your button "Show 6 more"). Set one to only show 3 items, the other one to show 9. Add a text area in the Views Footer of your first display and add the anchor HTML that leads to the page link of your second views display.

If you know a bit of Ajax you could display one of the displays as an attachment that has pager offset set to 3, and use Ajax button to make it display.

---

You can allow users to choose how many items are displayed by Exposing the Full or Mini pager with the option `Allow user to control the number of items displayed in this view` and enter `3, 9` while setting `Items per page` to 3.

This way you will see 3 items to start with, but there will be a dropdown above your results where users can choose either 3 or 9. If they choose 9 the page will reload to show 9 items in the results.

Using the Pager this way also gives you parameters on your links so you can even build links/button elsewhere on your site to link to a page with a particular number of results `path3?items_per_page=9`.

The downside for you may be that there are also pager links at the bottom of the results (Previous, Next) that you might not want displayed. Maybe you can hide them with CSS.

You should also research into the Pager related modules, maybe Views flexible pager and Pagerer can help.
> 2 votes

---
Tags: views, 8
---


# Question
Title: Error while set a paragraph field to NULL during cron run
I am using Drupal 8 and I have implemented a `hook_cron` to set a node field to NULL. Here is my code:

```
if ($lesson->field_lesson_ended_at->value < $current_time && $session_id && count($paragraphs) > 0) {
  $pids = [];
  foreach ($paragraphs as $paragraph) {
    $pids[] = $paragraph['target_id'];
  }
  $storage_handler = \Drupal::entityTypeManager()->getStorage('paragraph');
  $entities = $storage_handler->loadByProperties(['id' => $pids]);

  foreach ($entities as $entity) {
    try {
      $apiObj->forceDisconnect($session_id, $entity->get('field_session_connection_id')->value);
    } catch (Exception $e) {

    }
  }
  $storage_handler->delete($entities);
  $lesson->set("field_session_id", NULL);
  $lesson->save();
}

```

When cron task reaches these lines:

```
$lesson->set("field_session_id", NULL);
$lesson->save();

```

Throws the following error (capture from cron logs):

```
Error: Call to a member function getTranslation() on null in Drupal\Core\Entity\ContentEntityBase->hasTranslationChanges() (line 1430 of core\lib\DRupal\Core\Entity\ContentEntityBase.php)

```

Any ideas on how to solve this issue?

# Answer
> 0 votes
Even if the cron job is working now after you changed the order, you might get the same error later when using the saved parent entity.

Don't delete referenced paragraph entities programmatically (now the last command after you've changed the order). The Entity Reference Revisions module is handling this automatically after all revisions referencing the paragraph are removed.

---
Tags: 8, entities, cron, paragraphs
---


title: Remove commerce item from cart

text:
# Question
Title: Remove commerce item from cart
I can add an order item from the cart by doing this :

```
\Drupal::service('commerce_cart.cart_manager')->getStorage('commerce_order_item')->create(array())

```

Is there a similar way to delete a product line from my cart ?

# Answer
> 6 votes
Orders have a `removeItem` method defined on their interface. You just need to pass the loaded order item to that method, and then delete the orderitem.

```
/**
 * Removes an order item.
 *
 * @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
 *   The order item.
 *
 * @return $this
 */
public function removeItem(OrderItemInterface $order_item);

```

# Answer
> 2 votes
Example function on how to remove all the products of specific product type from cart:

```
function _remove_all_products_of_types($typesToRemove)
{
  $orders = \Drupal::service('commerce_cart.cart_provider')->getCarts();
  $items = reset($orders)->getItems();

  foreach ($items as $item){
    $productType = $item->getPurchasedEntity()->get('type')[0]->get('target_id')->getValue();
    if (in_array($productType, $typesToRemove)){
      foreach ($orders as $order){
      //  $order->removeItem($item); <- wrong way!!!

      // proper way!
      $cart_manager = \Drupal::service('commerce_cart.cart_manager');
      $cart_manager->removeOrderItem($order, $item);

      }
    }
  }
}

```

Function parameter is array of product type machine names (strings).

# Answer
> 0 votes
See how the commerce\_xquantity module does this: https://github.com/drugan/commerce\_xquantity/blob/8.x-1.x/src/Entity/XquantityOrderItem.php#L318

---
Tags: 8, commerce
---


# Question
Title: How can I remove everything from a Commerce cart if a certain product is added, except that product?
I'm sure this is pretty simple to do but I'm spacing out on it.

If a product of a certain type is added to the cart, I want to remove everything in the cart , regardless of its type, except for that product. At the same time I need to make sure that the quantity for that product will never exceed 1.

I've started a `hook_commerce_cart_product_add()` implementation but I haven't got very far with it:

```
function MYMODULE_commerce_cart_product_add($order, $product, $quantity, $line_item) {
  if ($product->type == 'the_product_type') {
    // Now what?!
  }
}

```

I'm more than happy to use Rules instead of custom code for this, but again I haven't got very far trying it that way.

Any pointers would be greatly appreciated.

# Answer
This is the code I ended up using:

```
function MYMODULE_commerce_cart_product_add($order, $product, $quantity, $line_item) {
  if ($product->type == 'directory_subscription') {
    $order_wrapper = entity_metadata_wrapper('commerce_order', $order);

    // Loop through the line items
    foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
      // If this is the product we're keeping, make sure the quantity is always 1.
      if ($line_item_wrapper->commerce_product->product_id->value() == $product->product_id) {
        $line_item_wrapper->quantity->set(1);
        $line_item_wrapper->save();
      }
      else {
        // Remove any other product from the order
        commerce_cart_order_product_line_item_delete($order, $line_item_wrapper->line_item_id->value());
      }
    }
  }
}

```

If anyone has any suggestions on how to improve the above I'd be grateful.
> 1 votes

# Answer
For Drupal 8 it should look like:

```
function remove_all_products_except_some()
{
  $orders = \Drupal::service('commerce_cart.cart_provider')->getCarts();
  $items = reset($orders)->getItems();

  foreach ($items as $item){
      foreach ($orders as $order){
        if (SOME CONDITION) {
           $order->removeItem($item);
         }
      }
    }
  }
}

```
> 0 votes

---
Tags: commerce
---


title: How to use non-english language in code

text:
# Question
Title: How to use non-english language in code
I'm italian and I've to develop a multilingual drupal site but english translations of strings (that should be added in code or templates) will be done in the future.

Is there a way to use in code a non-english language and use t() and other functions to translate them in english?

# Answer
AFAIK core's does not support (and could take a while to do so) keyed based translation (like Symfony or other do). Theres an idea queued but seems to fall on deaf ears.
> 1 votes

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


title: Add a class to an element after AJAX

text:
# Question
Title: Add a class to an element after AJAX
I have a view of nodes with an AJAX on scroll set up. Everytime a person scrolls down the page new elements inside a view show up (e.g. nodes).

I'm trying to add a new class only to **new** nodes that show up after each AJAX call. So far I've only managed to add a class to all nodes inside a view using drupal.behaviors, even the ones that were originally visible in the DOM(before AJAX call).

What am I missing?

My current code:

```
 $(document).ready(function($) {
    $('.views-infinite-scroll-content-wrapper').find('.views-row').addClass('i-was-here-first');
});

  Drupal.behaviors.testing = {
    attach:function (context, settings) {
      $('.views-infinite-scroll-content-wrapper', context).find('.views-row').addClass('i-was-here-second');
    }
};

```

# Answer
Taking a blind guess: Your `context` matches the entire parent container, so you can't filter by "new ones only" with `context`. But as a workaround you could specify a more explicit `find` to filter only new ones:

This will add `.i-was-here-first` to every views row present on document ready:

```
 $(document).ready(function($) {
    $('.views-infinite-scroll-content-wrapper').find('.views-row').addClass('i-was-here-first');
});

```

Now use that class to filter sub-sequent behavior calls by using a more explicit `find()`:

```
Drupal.behaviors.testing = {
    attach:function (context, settings) {
      $('.views-infinite-scroll-content-wrapper', context).find('.views-row:not(.i-was-here-first)').addClass('i-was-here-second');
    }
};

```

Side note:
I'd recommended not to use `$(document).ready()` at all in Drupal because this might cause problems when using BigPipe module, which is active by default. Drupal will initially trigger all behaviors with document as context, so you should use something like this instead:

```
Drupal.behaviors.instead_of_document_ready_do_this = {
  attach: function (context, settings) {
    $(document, context).once('my_unique_name').each( function... );
  }
}

```
> 1 votes

---
Tags: ajax
---


title: Using drupal-scaffold correctly

text:
# Question
Title: Using drupal-scaffold correctly
I am in the process of starting new projects using drupal/recommended-project over the Drupal composer project template. One of the differences I have noted is that the Drupal scaffold tool fires every time even when just installing a new module or theme.

In this case, I get write permission warnings about settings.php, and I have other concerns such as .htaccess or robots.txt being replaced.

I read some of the docs and added this in my composer.json file:

```
"drupal-scaffold": {
    "locations": {
        "web-root": "docroot/"
    },
    "file-mapping": {
        "[web-root]/sites/default/settings.php": false,
        "[web-root]/.htaccess": {
            "mode": "replace",
            "path": "assets/drupal/.htaccess"
        }
    }
},

```

This prevents settings.php from being touched, and replaces the .htaccess file from Drupal with one containing our modifications. The drawback that I see here is if .htaccess had some security changes, I would have to do a manual diff and put the custom rewrite rules back in.

Is this the proper way to use drupal-scaffold?

# Answer
> 3 votes
I use the patch method mentioned on https://www.drupal.org/docs/develop/using-composer/using-drupals-composer-scaffold#toc\_4

e.g:

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

```

Then if the core file changes it will either merge correctly or the patch will fail and you'll see that in your composer command and can make the relevant changes to your patch

---
Tags: 8, composer
---


# Question
Title: How to install a distribution on Docker using ddev composer command?
I am new to docker. I have to install Openy distribution on docker using ddev CLI. ddev use this command to setup a normal Drupal 8 installation.

```
ddev composer create drupal-composer/drupal-project:8.x-dev --stability dev --no-interaction --prefer-dist

```

it's working fine. Now I have to install openy on docker, composer command for openy is:

```
composer create-project ymcatwincities/openy-project MY_PROJECT --no-interaction --no-dev

```

I tried writing `ddev` before openy command and many other changes are made but not successful. Now my main question is that, that how to install any other Drupal distribution using composer command on docker.

# Answer
> 0 votes
Note difference. First the official command.

```
ddev composer create ...

```

And now the command you executed.

```
ddev composer create-project ...

```

See? DDEV provides its own command to create a project. So just adding `ddev` in front of any composer command doesn't always work. Instead it's `ddev composer create ...`.

---
Tags: 8, distributions
---


# Question
Title: How to get a machine name of a custom block
I have a custom "Slider Items" field type, as well as the custom "Channel Slider Block Type" type block (created using "Custom block library").

Also, I have several "Channel Slider Block Type" blocks. I need to somehow determine the machine name of a block that this field displays in @FieldFormatter of my field. How can this be implemented? Perhaps there is a special service for this?

```

/**
 * @FieldFormatter(
 *   id = "channel_slider_formatter",
 *   label = @Translation("Channel Slider Formatter"),
 *   field_types = {
 *     "channel_slider"
 *   }
 * )
 */
class ChannelSliderFormatter extends FormatterBase {

  public function viewElements(FieldItemListInterface $items, $langcode) {
    // Here I need to get a block that reflects this field.
    $blockMachineName = '...';
    ...
    return [
      '#theme' => 'channel_slider',
      '#items' => $itemsData,
    ];
  }

}

```

# Answer
> 1 votes
Custom blocks do not have machine name since they are content entities. What you can do is to check the bundle of the block in your field formatter.

```
public function viewElements(FieldItemListInterface $items, $langcode) {
  if ($items->isEmpty()) {
    return NULL;
  }

  $entity = $items->first()->getEntity();
  if ($entity->getTargetEntityTypeId() === 'block_custom') {
     // Heres my great block type.
     $block_type = $entity->bundle();
     // Do something with it.
  }

  // The usual sutff.
}

```

# Answer
> 2 votes
A custom content block has no unique machine name, only a bundle type, an UUID and an ID. Only custom content blocks placed in a region have a machine name, but this is NOT the machine name of the block, it is the machine name of the block placement (configuration)

---
Tags: 8, blocks
---


# Question
Title: Cron timeouts at 60 seconds, but all the related timeouts are set higher
We're getting 504 Gateway Timeouts on AWS from a Drupal 7 site at 60 seconds, but everything AFAIK is greater than that. The timeout is specifically during running the feeds\_source\_import in Ultimate Cron.

We have a NLB with two TCP listeners that forward to the IPs of an ALB. According to the docs, the NLB has a timeout of 350 seconds for TCP connections. https://docs.aws.amazon.com/elasticloadbalancing/latest/network/network-load-balancers.html#connection-idle-timeout

The ALB is using an HTTP and HTTPS listener, and we have the Idle Timeout set to 300 seconds.

Finally on the servers themselves are running CentOS 7.7, Apache 2.4 and PHP-FPM 7.2. reqtimeout\_module is turned off completely. Here are some values from php.ini:

```
max_execution_time = 300
max_input_time = 120
max_input_vars = 4000
memory_limit = 300M
default_socket_timeout = 120

```

And apparently cron lock time is set to 240 in Drupal Core. https://stackoverflow.com/a/9220479/5004648

Is there anything else we're missing that would terminate the connection at 60 seconds?

Given that we have several feeds, I decided to try to also run the importer manually by visiting: /import/video\_importer and also get a timeout. For reference, the feed is pulling only a 128KB CSV file that has 912 lines.

# Answer
> 0 votes
Solved. It was the timeout of the proxy connection to PHP-FPM. It involves going down a rabbit-hole of Apache values and defaults so strap in.

As per ProxyPass the proxy default of `connectiontimeout` is `timeout`.

The default value of `timeout` is `ProxyTimeout`

The default of `ProxyTimeout` is the core Apache `TimeOut`

The default of `TimeOut` is 60. So there you go.

I set a value of `TimeOut 180` in my Virtualhost for the site in question and the import went through.

Now just to wrangle all these values back down to a sensible level now that I know the culprits.

---
Tags: 7, feeds, cron
---


title: How do I create product variants?

text:
# Question
Title: How do I create product variants?
I have a product (for example, "Desk") which has two attributes (size and life). Size has the values *small*, *medium*, and *large*. Life has the values *7 years* and *10 years*.

The price is different for each variation. How can I change the price for each variation?

# Answer
> 0 votes
You would need to use the Ubercart Attributes module, which is included in the Ubercart core module. From the Ubercart user guide:

> Products are not created equally, and in some cases the customer gets to decide the type of product they want. For example, your store may sell t-shirts, and the customer may find a design they like but need to get it in a certain size. In a situation like this, you will need to take advantage of the product attribute system in Ubercart. It lets you define attributes (like size), give them options (like small, medium, and large), and enable attributes and options on a per-product basis. For an example, check out the Ubercart Beanie on the Livetest.

The module allows you to set different prices per attribute and it is not very difficult to setup really.

Having said that, I prefer the Drupal Commerce way of handling product variations.

# Answer
> 0 votes
While attributes are certainly one way of handling variations, (and generally the recommended way) If you want to step into the current way that the big-boys are handling variations which takes you to a different product page when selected, you can easily create variations with Paragraphs, Entity Reference and Views. The one downside is that you have to reference each product with the variant. I haven't had a chance to figure out how to get **cer** or **ref\_field** to automatically sync the references, however in theory those would probably work.

As a loose guide: 1) Create a paragraph bundle called **Product Variant**

2) Add a field to the paragraph. **Name:** Variant Name **Type:** Text

3) Add a field to the paragraph. **Name:** Variant Reference **Type:** Entity Reference

4) Go to your Product Content Type and add a field. **Name:** Product Variation **Type:** Paragraphs

4 a) Point the paragraph field to the Product Variant paragraph bundle

5) Create a view **Product Variations**

6) Set the Format to **Jump Menu**

7) Add relationships to the entity references:

* Paragraphs item: Entity with the Product Variation (field\_product\_variation)
* Entity Reference: Variant Reference
* (Content entity referenced from field\_variant\_reference) Content: Product Variation

8) Add the Title field and make sure it is using the relationship that points to the paragraphs field title (field\_product\_variation)

9) Set the contextual filter to the Nid of the product using the relationship of the paragraph field\_product\_variation

10) Add the view to your product page above the "add to cart" form with your favorite insert method (I use Panels)

11) Edit each and every product that will need the variations. Set the Name of that products variation, then choose the nodes through entity reference of the node variations. This must be done for each product within the variation unless you figure out how to get CER or ref\_field to work. More on this below.

Again, this is a loose guide to give an idea of how to do it.

As shown in the images, the dropdown is not part of the UC attribute system but instead a way to navigate to the respective variant page. From there, you would add attributes to the respective product that might change the characteristics of that particular product.

For example, lets say you have five T-Shirt logo designs that are based on the band FooGoo. Each shirt design has different colors and sizes available. You would use my proposed "Variation" to switch between the product pages of each design, that way each logo design is housed within its own product page, then use the stock UC attributes to handle the color and size of each design.

Given this example, you would have to edit all 5 design product pages. The first we'll give a variation name of "Design 1", the second a variation name of "Design 2" and so-on. For Design 1, add Design 1, Design 2, Design 3 etc as the referenced nodes. Do the same for Design 2 and so-on. Once all 5 products point to each other, the jump-menu will work to switch between all of the pages.

Good luck!

"And they said you *need* Commerce..."

---
Tags: 7, ubercart
---


title: How can I force HTTPS for all images?

text:
# Question
Title: How can I force HTTPS for all images?
I'm moving my Drupal 7 website to `https` but I keep having issues with some images that gets loaded with full path, but with http://. For example the site logo and view images have `http://` path. (Inside DB table file\_amanged files are all saved with `public://` path.) They are all files loaded through the Drupal UI.

How can I force all images to use https?

# Answer
You need to use a module like Pathologic which will force protocol relative URLs for all assets.

https://www.drupal.org/project/pathologic

The `public://` path is a stream wrapper, and has no effect on whether the browser sees http/https or not. Pathologic will fix all of this for you.
> 1 votes

# Answer
I know this is an old post but I ran into this issue on several sites with a ton of content. I ended up adding a meta tag to my html.tpl for a quick fix

```
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

```

See https://developers.google.com/web/fundamentals/security/prevent-mixed-content/fixing-mixed-content
> 1 votes

# Answer
The only solution I've found so far is adding a mytheme\_preprocess\_html to replace all absolute:

Insecure content warning with D7 and SSL
> 0 votes

---
Tags: media
---


# Question
Title: How to add class to field--item element generated by paragraphs
I have a paragraph type called "Grid Item".

I've created a file called "paragraph--grid-item--default.html.twig" where I print all my required fields.

It all works as expected, but I need to add classes (from some list fields) to the element "field--item". I can add classes in any other children of this element but on directly on it.

This is the current output I have:

This is the code I'm using in the template:

```
{% block paragraph %}
    <div class="{{ content.field_block_size.0 }} {{ content.field_block_style.0 }} ">
        <div class="heading"> {{content.field_image.0}}
            {{content.field_block_title.0}}
        </div>
     <div class="card-body"> {{content.field_body.0}}</div>
     <p>
     {{content. field_read_more_link.0}}
     </p>

</div>
{% endblock paragraph %}

```

The classes content.field\_block\_size.0 and content.field\_block\_style.0 are applied as expected but I need them on the parent element...field--item

# Answer
> 1 votes
It depends a little on how your Paragraph is structured. Is it a single paragraph type with multiple generic fields in it or a paragraph with multiple other paragraph types inside of it?

If it's the latter, you have to create two twig files (For the parent and the child) but you can control output for each row and the contents of each row.

Alternatively, if you are just trying to style each item what's wrong with just selecting the field--item elements, eg:

```
 .field--whatever-parent-is-called .field--item { style here. }

```

---
Tags: 8, theming, paragraphs
---


# Question
Title: More template suggestion for views exposed form
Using the debug function I have found only one template suggestion for view's exposed form:

form--views-exposed-form.html.twig

I need to make changes to particular view, but I dont have other default suggestions like:

form--views-exposed-form--view-name--display-name.tpl.php

Should I write a function like hook\_views\_exposed\_form\_alter()

# Answer
1. create exposed form filters template following this naming standard:
views-exposed-form--**{view-name}--{display-name}**.html.twig

to get the view-name you can get from Backoffice (Structure \> Views \> search for your view \> then get machine name and repalce the underscore with dash - see image bellow)

so we get this template:
views-exposed-form--**media-gallery**.html.twig
2. put your static HTML(we will replace in next step) there and clear cache you'll find the new tempalte.
3. if you want to print the exposed fitlers just put `{{form}` in your tempalte

> views-exposed-form--**media-gallery**.html.twig

```
{{form}}
```
4. but if you want to print each exposed fitler serpately follow this steps : (Structure \> Views\> search for your view \> Edit \> click on filter name under the **FILTER CRITERIA** \> scroll down and copy **Filter identifier** input value \> go back to the template and print your exposed filter one by one {{ form.$fitler name }}

> views-exposed-form--**media-gallery**.html.twig

```
{#1.print 1st exposed fitler form element + label #}
{{ form.field_thematiques_target_id }}

{#2.print 2nd form element + label #}
{{ form.field_type_media_value }}

{#3.include all other form elment ex submit button but to prevent
duplication remove other one #}
{{ form|without('field_thematiques_target_id','field_type_media_value') }}

```
> 5 votes

---
Tags: 8, theming
---


# Question
Title: What are the differences between Drush 9 and 10
We are using Drupal 8.8 with **Drush 9**.

What are the main risks and benefits of upgrading to **Drush 10**?

The official release description is rather vague.

# Answer
You can check the difference here https://github.com/drush-ops/drush/compare/9.7.1...10.0.0

As you can see, they are mostly fixes and improvements.

There are also some compatibility changes:

> Source: https://docs.drush.org/en/master/install/

As long as you're using PHP 7.1+ there is no risk. The benefit is that it will still work once Drupal 9 comes out later this year.
> 3 votes

---
Tags: drush
---


# Question
Title: What is the right way of loading a service?
when trying to use a service in drupal actually there is 3 ways , what is the preferred way to use a service and why :

1. passing dependencies directly through the constructor:

```
public function __construct(AccountProxyInterface $current_user) {

}

```
2. passing the dependencies through the `create()` method wich look to me the same as injecting it through the `__construct()`, with the only difference , an instance will be created eah time (no singleton design pattern - not same instance will be reused)

```
      public static function create(ContainerInterface $container)
  {
    //1.getting service from the service container.
    $Door = $container->get('custom_service.door');
    //2.create a new object of current class, and Inject the dependency  object into the constructor
    return new static($Door);
  }

  //constructor receive the dependency set by the create() method
  public function __construct(Door $Door)
  {
    kint($Door);
  }

```
3. just get get the service from the service container and no need to inject it using :
```
$Door = \Drupal::service('custom_service.door')
```

# Answer
1. The standard way to inject services in other services is passing dependencies directly through the constructor:

*mymodule.services.yml:*

```
services:
  mymodule.foo_service:
    class: Drupal\mymodule\FooService
    arguments: ['@current_user']

```
2. While you can define a factory method in \*.services.yml, see https://symfony.com/doc/current/service\_container/factories.html, in Drupal the most common places for this are Controllers and Plugins which implement ContainerInjectionInterface::create or ContainerFactoryPluginInterface::create. See How do I use dependency injection on \Drupal::moduleHandler() to a Controller?
3. `\Drupal::service...` is largely used from procedural code when not in an OOP context, like hooks or static callbacks. See the comment from @Kevin.
> 8 votes

---
Tags: 8, dependency-injection, symfony-services
---


# Question
Title: How to use a set of global and per subsite permissions in a multisite installation?
**Use case:**
I have a multisite installation in which I want to define a global configuration to be available to all subsites. I define this configuration in the **default** site. For this example let's say that is:

* a role **editor**
* a content type **Article**
* a content type **Page**

Now..

1. In all subsites that role **editor** need to have the permission *"Use the toolbar"*. A global permission.
2. In **subsite-a**, I want to allow the editor to **only** add nodes of type **Article**
3. In **subsite-b**, I want to allow the editor to **only** add nodes of type **Page**

To add to that, let's say in the future I need to add a permission to the global set, I want to be able to import that set of permissions to all subsites without overriding any individual subsite permissions.

Currently I am using config\_split and added *user.role.editor.yml* to the conditional section but I can't seem to make it work with the scenario described above.

**Question:**
How to maintain a global set of permissions and per site set of permissions without the global config overriding the config of the subsite? They need to rather extend each other so to say.

Any suggestions/help?

# Answer
For now I solved this by creating a seperate **global** role which stays in the default shared config. I added the **editor** role to the conditional (graylist) section (configured per subsite) using config\_split. So that way I am able to have seperate permissions for that role.

That global role can be automatically assigned to a subsite user during a new subsite install via a bash script/drush command for example.
> 1 votes

---
Tags: 8, configuration, multi-sites
---


# Question
Title: How do you access other submitted values from ConstraintValidator?
May well be missing the obvious here. So in Drupal 8 I have a content type. That has a date range field and then using paragraphs, a paragraph with several fields including a date field.

So I need to validate it so that the date range field (field\_A) checks that the start and end are correct. That is the start is on or before the end. No problem, that is done and dusted - **FirstConstraintValidator.php**.

Next (**SecondConstraintValidator.php**) for the paragraphs on that content type I need to check the date field, call it field\_B, is on or between the start and end date of Field\_B. This is where I am having issues. I may be trying to do it a way that it cannot be done.

So I have (I know it is messy and incomplete):

**my\_module.module**

```
function my_module_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
  if ($entity_type->id() === 'paragraph' && $bundle === 'bundle_B') {
    $fields['field_B']->addConstraint('SecondConstraint', []);
  } else if ($entity_type->id() === 'node' && $bundle === 'bundle_A') {
    $fields['field_A']->addConstraint('FirstConstraint', []);
  }
}

```

**FirstConstraintValidator.php**

```
class FirstConstraintValidator extends ConstraintValidator {
  public function validate($items, Constraint $constraint) {

    $entity = $items->getEntity();

    $start_date = date("Y-m-d",strtotime($entity->get('field_A')->getValue()[0]['value']));
    $end_date = date("Y-m-d",strtotime($entity->get('field_A')->getValue()[0]['end_value']));

    if ($start_date > $end_date) {
      // Start date must be on or before end date...
      $this->context->addViolation( xxxxxx );
    }
  }
}

```

**SecondConstraintValidator.php**

```
class SecondConstraintValidator extends ConstraintValidator {
  public function validate($items, Constraint $constraint) {

    $entity = $items->getEntity();
    $parentEntity = $entity->getParentEntity();

    // THIS IS WHERE I NEED TO GET SUBMITTED VALUES.
    // LINES BELOW RETURNED ORIGINAL STORED VALUE, NOT UPDATED VALUE
    $start_date = date("Y-m-d",strtotime($parentEntity->get('field_A')->getValue()[0]['value']));
    $end_date = date("Y-m-d",strtotime($parentEntity->get('field_A')->getValue()[0]['end_value']);

    // field_a is valid (i.e. start date is before or on end date)
    if ($start_date <= $end_date) {

      if ($items->value > $end_date || $items->value < $start_date) {
        // The date is after the end date of field_a
        // OR
        // the date is before the start date of field_a
        $this->context->addViolation( xxxxx );
      }
    }
  }
}

```

I notice when I save the node the paragraphs are validated before the rest of the node. Anyway, the alternative is to use form\_alter and $form\['#validate'\]\[\] but my understanding was in D8 we should be using ConstraintValidator and similar. So question is, am I doing this the right way? Am I missing something?

Thanks

***------- UPDATE - PARTLY SOLVED -------***

Thanks to @4k4 have a partly working solution. This may help someone else.

**my\_module.module** changed from original to (i.e.adding constraint to the paragraph field.

```
function my_module_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
 if ($entity_type->id() === 'node' && $bundle === 'bundle_A') {
    $fields['field_A']->addConstraint('FirstConstraint', []);
    $fields['field_B']->addConstraint('SecondConstraint', []);
  }
}

```

field\_A is a date range field\_B refers to a paragraph which has a date field and others in it.

**SecondConstraintValidator.php** changed to:

```
class SecondConstraintValidator extends ConstraintValidator {
  public function validate($items, Constraint $constraint) {

    $entity = $items->getEntity();

    $start_date = date("Y-m-d",strtotime($parentEntity->get('field_A')->getValue()[0]['value']));
    $end_date = date("Y-m-d",strtotime($parentEntity->get('field_A')->getValue()[0]['end_value']);

    // field_a is valid (i.e. start date is before or on end date)
    if ($start_date <= $end_date) {

      if ($items->value > $end_date || $items->value < $start_date) {

        // field_A is valid, but field_B is not. show an error for field_B
        $this->context->addViolation( xxxxx );
      }
    }
  }
}

```

The above is fine and works if you only have one paragraphs. If you allow multiple, note this is not working correctly, you need something like this:

**SecondConstraintValidator.php**

```
class SecondConstraintValidator extends ConstraintValidator {
  public function validate($items, Constraint $constraint) {

    $entity = $items->getEntity();

    $start_date = date("Y-m-d",strtotime($entity->get('field_a')->getValue()[0]['value']));
    $end_date = date("Y-m-d",strtotime($entity->get('field_a')->getValue()[0]['end_value']));

    // field_a is valid (i.e. start date is before or on end date)
    if ($start_date <= $end_date) {
        foreach ($items as $activity) {

          $date = $activity->getValue()['subform']['field_b'][0]['value']->format('Y-m-d');
          if ($date > $end_date || $date < $start_date) {
            $this->context->addViolation( xxxxx );
          }
        }
    }
  }
}

```

The above, again may not be the best solution. It adds a violation to every field\_B, so if you have added 2 copies of the paragraph and only one doesn't validate this will show an error on all. **$this-\>context-\>addViolation( xxxxx );** needs changing to add violation only to the field in that paragraph.

# Answer
Thanks to all the comments, have a working solution which may help others.

**my\_module.module** changed from original to (i.e.adding constraint to the paragraph field.

```
function my_module_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
 if ($entity_type->id() === 'node' && $bundle === 'bundle_A') {
    $fields['field_A']->addConstraint('FirstConstraint', []);
    $fields['field_B']->addConstraint('SecondConstraint', []);
  }
}

```

field\_A is a date range field\_B refers to a paragraph which has a date field and others in it. field\_C is the date field inside the paragraph

**SecondConstraintValidator.php** changed to:

```
class SecondConstraintValidator extends ConstraintValidator {
  public function validate($items, Constraint $constraint) {

    $entity = $items->getEntity();

    $start_date = date("Y-m-d",strtotime($parentEntity->get('field_A')->getValue()[0]['value']));
    $end_date = date("Y-m-d",strtotime($parentEntity->get('field_A')->getValue()[0]['end_value']);

    // field_a is valid (i.e. start date is before or on end date)
    if ($start_date <= $end_date) {

      if ($items->value > $end_date || $items->value < $start_date) {

        // field_A is valid, but field_B is not. show an error for field_B
        $this->context->addViolation( xxxxx );
      }
    }
  }
}

```

The above is fine and works if you only have one paragraphs. If you allow multiple you need something like this:

**SecondConstraintValidator.php**

```
class SecondConstraintValidator extends ConstraintValidator {
  public function validate($items, Constraint $constraint) {

    $entity = $items->getEntity();

    $start_date = date("Y-m-d",strtotime($entity->get('field_a')->getValue()[0]['value']));
    $end_date = date("Y-m-d",strtotime($entity->get('field_a')->getValue()[0]['end_value']));

    // field_a is valid (i.e. start date is before or on end date)
    if ($start_date <= $end_date) {
        foreach ($items as $key as $activity) {

          $date = $activity->getValue()['subform']['field_c'][0]['value']->format('Y-m-d');
          if ($date > $end_date || $date < $start_date) {
            $this->context->buildViolation("message")->atPath($key.'.field_c')->addViolation();
          }
        }
    }
  }
}

```

The above, again may not be the best solution. Open to comments, but it works!
> 2 votes

---
Tags: paragraphs
---


title: How do you wrap an image with a link?

text:
# Question
Title: How do you wrap an image with a link?
In Drupal 7 this was done with the l() command and setting the html option to true. I have found the Link::fromTextAndUrl() method in Drupal 8 but no mention of something similar to the html option.

\[EDIT\] I think i was not clear with my original question. This is not for an image field; i was simply asking how to wrap a link around:

```
<img src="path_to_my_img">

```

# Answer
> 2 votes
This way should be bulletproof:

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

$url = $node->get('field_url')->getValue();
$imageUri = $node->get('field_image')->entity->getFileUri();
$image = [
  '#theme' => 'image_style',
  '#style_name' => 'medium',
  '#uri' => $imageUri,
  '#width' => 200,
  '#height' => 100
];
$rendered = render($image)
$linkMarkup = Markup::create($rendered);
$link = Link::fromTextAndUrl($linkMarkup, $url);
$link = $link->toRenderable();
render($link)

```

# Answer
> 1 votes
Yes, Link::fromTextAndUrl() is the replacement for l(), but in D8 you use toRenderable() instead of a html option. This produces a render array which is rendered later.

```
use Drupal\Core\Link;

  $renderable = Link::fromTextAndUrl($title, $url)
    ->toRenderable();

```

BTW you can build this render array directly, with the same result, or the image as title, see Render image that is linked

# Answer
> 1 votes
This worked for me:

```
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\Core\Render\Markup;
$img = '<img src="path_to_my_image" />';
$rendered_image = render($img);
$image_markup = Markup::create($rendered_image);
$link = Link::fromTextAndUrl($image_markup, Url::fromUri('internal:/my_path'))->toString();

```

# Answer
> 0 votes
I am not sure if this functionality is preserved in D8

You could either do it in a **twig template** `node--[type-name].html.twig`

```
<a href="{{ content.field_url }}"> {{ content.field_image }} </a>

```

Or you could do it in a **custom module** manually

```
$url = $node->get('field_url')->getValue();
$image_uri = $node->field_image->entity->getFileUri();
$image_url = \Drupal\image\Entity\ImageStyle::load("large")->buildUrl($image_uri);
$image_with_link = "<a href='" . $url . "'>" . $image_url . "</a>";

```

---
Tags: media
---


# Question
Title: How to set the default value of an exposed filter rather than -Any-?
I have a view with exposed filters in Drupal 7 and I need to set the default value of a filter to `current year`. I also need to unset/remove the `- Any -` option from the select list.

# Answer
> 9 votes
This solution is working on **Drupal \>= 8**

```
function YOURMODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form['#id'] == 'views-exposed-form-my-view-display') {
    $request = \Drupal::request();
    if (is_null($request->get('EXPOSED_FILTER_FIELD_MACHINE_NAME'))) {
      // get all input fields first then modify the one you want to change
      $input = $form_state->getUserInput();
      $input['EXPOSED_FILTER_FIELD_MACHINE_NAME'] = 'DEFAULT_VALUE;
      $form_state->setUserInput($input);
    }
  }
}

```

for instance, here I set the current node as the default category referenced

```
<?php
use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_alter().
 */
function unsw_dev_form_alter(&$form, FormStateInterface &$form_state, $form_id) {

  // set default category
  if ($form_id == 'views_exposed_form') {
    $request = \Drupal::request();
    if (is_null($request->get('field_cause_category_target_id'))) {
      $node = \Drupal::routeMatch()->getParameter('node');
      if ($node instanceof \Drupal\node\NodeInterface && $node->getType() == 'cause') {
        $form_state->setUserInput(['field_cause_category_target_id' => $node->id()]);
      }
    }
  }
}

```

# Answer
> 3 votes
You can use `hook_form_alter()` to alter any form.

```
function yourmodule_name_form_alter(&$form,&$form_state,$form_id) {
  if ($form_id == 'views_exposed_form') {
    $form['field_width_value']['#default_value'] = 'whatever you want';
    unset($form['field_width_value']['#options']['All']);
  }
}

```

# Answer
> 2 votes
My case scenario for a taxonomy field and filtered results, not just default value:

```
if ($form_id == 'views_exposed_form') {
  $account = user_load($user->uid);
  $country = taxonomy_term_load($account->field_country[LANGUAGE_NONE][0]['tid']);
  $form['country']['#options'] = array($country->tid => $country->name);
  $form['country']['#default_value'] = $country->tid;
  $form_state['input']['country'] = $country->tid;
}

```

# Answer
> 1 votes
where are you going to set default value of current year? If you want to remove -any- from options, make it required. or use Better Expose Filter to override the -any-.

I'm not sure if this post is your duplicate but I'm going to put my answer here also.

An expose filter but by default is the current year.

This is what you're going to do.

* Add your date field to your filter criterion
* Date selection form element: SELECT
* Filter granularity: YEAR
* Expose it
* Operator: Is equal to
* Choose "Enter Relative Date"
* Type this: now

First Part:

Second Setting:

Expose Filter with Default Value

Is this what you want?

# Answer
> 0 votes
Having also this need I just found this module: Views Advanced Labels and successfully used it, replacing the - Any - by a custom simple text for 2 exposed filters in the same view.

It says that it works with tokens. So I guess using `[date:custom:Y]` or maybe creating a date format could be an option.

Some more resources here: Auto update to the current year in the copyright footer (© 2010-2013)

# Answer
> -2 votes
This is my solution; it works for Drupal 7 too.

```
function my_theme_form_alter(&$form,&$form_state,$form_id) {
  if ($form_id == 'views_exposed_form') {
    $form['**FIELD_ID**']['#options']['All'] = '**YOUR TEXT**';
  }
}

```

---
Tags: 7, views
---


# Question
Title: Getting the workflow associated to a node type
How do i get the workflow entity associated to a certain node bundle? So far my approach has been to use EntityTypeManager to load the workflow config entity storage and trying to load the right workflow using loadByProperties() function,

```
$workflow = $this->entityTypeManager->getStorage('workflow')->loadByProperties();

```

except I don't know what properties I should be specifying or If I'm approaching this the right way.

# Answer
Workflows are configuration entities so you can load them using their id:

```
$workflow = $this->entityTypeManager->getStorage('workflow')->load('workflow_machine_name');

```

Or "query" them using the Entity Query (check the Drupal 8 example shown here):

```
$query = $this->entityTypeManager->getStorage('workflow')->getQuery();
$query->condition('type_settings.entity_types.node', 'article', 'IN');
$workflows = $query->execute();

```

The condition is a proof-of-concept drawn from another config entity query but is the right path you need to test it agains the workflow entity schema.
> 3 votes

---
Tags: workflows
---


# Question
Title: Page Content Type: Displaying error in Preview mode
Whenever I am creating or editing a node, in the preview mode I see these errors.

>

This is the code I am using.

```
/**
 * Implements hook_preprocess_html().
 */
function campaigns2019_preprocess_html(&$variables) {
  if (isset($variables['node_type']) && $variables['node_type'] === 'landing_page') {
    $node = \Drupal::routeMatch()->getParameter('node');
    if ($node->field_dark_theme->value) {
      echo("<script>console.log('here');</script>");
      $variables['attributes']['data-theme'] = 'dark';
    }
  }
}

```

The dark theme does not show up in preview mode though. However, if I ignore the errors and create my page, the dark theme works and everything seems to be displayed correctly. When is `template_preprocess_html()` called? Where in Drupal is it called?

# Answer
> 0 votes
The error is about accessing `field_dark_theme` from an un-existing node instance. The proper way of loading the node during preview is explained here.

On the other hand, welcome to the wonderful world of PHP for debugging properly (on Drupal), please check this post and this documentation entry check your proper IDE/stack on how to setup debugging tools.

---
Tags: 8, theming, nodes
---


title: EntityQuery does not return values

text:
# Question
Title: EntityQuery does not return values
I am trying to get some entities using the "entity.query" service.

What am I doing:

in my module (file "mymodule.module") I execute:

```
function mymodule_preprocess_page(&$variables) {
  $query = \Drupal::entityQuery('node');
  $query->condition('type', 'article');
  $nids = $query->execute();
}

```

What I get:

* when I browse a page under the name of an authorized user - the request returns the results
* when I browse the site as a guest, the query does not return any results.

Why am I not getting any results when I browse the site as a guest? Any ideas?

# Answer
Entity query respects access by default. Add the -\>accessCheck(FALSE) method to prevent access checking. Be careful, removing access checks may expose restricted data. It may be better to configure view permissions or whatever access system you're using to allow anonymous users to access content instead of removing the check.
> 3 votes

---
Tags: 8, entities
---


# Question
Title: Errors from custom FieldItemList::getConstraints() displayed next to every single property
**Summary**

Errors set by constraints on custom field types appear next to every single property by default.

We can use the `::errorElement()` method on the widget to place errors that come from the `::getConstraints()` method of the field **item**.

However, errors that come from `::getConstraints()` in a custom field item **list** will not go through `::errorElement()`. How can we reasonably place them?

**Details**

My original problem ist very complicated. I've drastically simplified it to show only what's essential. We start with a very simple custom field type with 2 number properties.

```
class YearRangeType extends FieldItemBase {
  public static function propertyDefinitions($field_definition) {
    $properties['start'] = DataDefinition::create('integer');
    $properties['end'] = DataDefinition::create('integer');
    return $properties;
  }

  public static function schema($field_definition) {
    $schema = ['columns' => [
      'start' => ['type' => 'int',],
      'end' => ['type' => 'int',],
    ],];
    return $schema;
  }

  public function isEmpty() {
    $start = $this->get('start')->getValue();
    $end = $this->get('end')->getValue();
    return !($start || $end);
  }
}

```

We define a custom `FieldItemList` for it that adds a simple validation: checking if at least 2 items are present.

```
class YearRangeItemList extends FieldItemList {
  public function getConstraints() {
    $constraints = parent::getConstraints();
    $constraints[] = $this->getTypedDataManager()
      ->getValidationConstraintManager()
      ->create('Count', [
        'min' => 2
      ]);
    return $constraints;
  }
}

```

When I try to save only one item, the field will look like this:

If the errors would result from `YearRangeType::getConstraints(), we could use the`errorElement()\` method of the widget to place them.

However, the Drupal core class `WidgetBase` does deliberately not pass errors set by the item list to `errorElement()`, see these lines in the Drupal core code (version 8.8.1).

How else should we place them?

# Answer
> 0 votes
We can place the errors with three modifications in the widget class.

First, we add the empty form element `non_field_errors` we can attach the errors to.

```
class YearRangeWidget extends WidgetBase {
    ...
    public function form($items, &$form, $form_state, $get_delta = NULL) {
        $formElement = parent::form($items, $form, $form_state, $get_delta);
        $formElement['non_field_errors'] = ['#type' => 'item'];
        return $formElement;
    }
    ...
}

```

Second, in the `flagErrors` method, we collect all errors that do **not** belong to any property and call a separate method to treat them.

```
class YearRangeWidget extends WidgetBase {
    ...
    public function flagErrors($items, $violations, $form, $form_state) {
        $listViolations = [];
        foreach ($violations as $key => $violation) {
            if ($violation->getPropertyPath() === '') {
                $listViolations[] = $violation;
                $violations->remove($key);
            }
        }
        parent::flagErrors($items, $violations, $form, $form_state);
        $this->flagNonFieldErrors($items, $listViolations, $form, $form_state);
    }
    ...
}

```

Third, we define the method treating the separated errors.

```
class YearRangeWidget extends WidgetBase {
    ...
    public function flagNonFieldErrors($items, $violations, $form, $form_state) {
        $field = $items->getName();
        foreach ($violations as $violation) {
            $form_state->setError(
                $form[$field]['non_field_errors'],
                $violation->getMessage()
            );
        }
    }
    ...
}

```

---
Tags: entities
---


# Question
Title: Views duplicate result if multiple entity reference
case: I have 2 content types A & B and there is field in B which is entity reference of A and this field can hold multiple values from A "Multiple Values", so i created view to show records from B and i added some fields from A based on relation i made in the view "Entity Referenced", the problem is i get duplicated result if this field has multiple values even if i checked distinct in the view.

so is there direct way to solve it, or i have to fix it with custom code in custom module ?

# Answer
> 1 votes
I figured out good solution which is as follow: -A is the content type & B is the second content type
-A is field entity reference in the content type of A with multiple values.
-in the views in creating view of content type B just render the field of entity reverence A normally, by default it will render the title whether its 1 value or more.
-now the views for this field in formatter option choose Rendered Entity.
-and in view mode we can choose Tokens.
-now we got to the content type A and then go to manage display tab.
-at the bottom left in the menu click on Custom display settings and then check the option Tokens and click save.
-now in the top right tab "Tokens" display will appear, click on it. -now we choose which field we want to appear in the view & we can control the label, value, the format. for my case i just showed 1 field without the label and with plain text format and thats was great enough with out making relation and duplicate the content.

# Answer
> 0 votes
as my understanding this duplicated results are actually not duplicated :)

**let's say we have two type:**

* content type is the cities (type B in your question)
* content type is the employees (type A in your question

**so, that means the view will look like**

* Jorge lives in Washington
* Ali lives in Cairo
* Hana lives in Washington

we can see here the Washington is not really duplicated because each one related the different employee

**the general solution is the grouping like the following**

**Washington** : Jorge + Hana
**Cairo** : Ali

if this is really your case,, i advice you to read this post

# Answer
> 0 votes
The problem is that the records actually *are* distinct from a database perspective as there are multiple records generated by different entity references.

The Drupal 8 core issue for this is Views relationships with multi-valued entity reference fields invalidate Distinct query option. There should be usable patches there.

For Drupal 7, use the Views Distinct module as it probably won't be fixed in Views.

---
Tags: views, entities
---


# Question
Title: How I can add an optional parameter in REST API URL
How I can add an optional parameter in drupal 8 REST API URL

```
"canonical" = "/content/get/{id}"

```

But I have to add value for `id` here, How I can make this `id` optional

# Answer
> 3 votes
I experienced the same issue and solved it by adding the current request from the request stack to my resource:

**RestBase.php**

```
<?php

namespace Drupal\api\Plugin\rest;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Psr\Log\LoggerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;

class RestBase extends ResourceBase {

  /**
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;
  /**
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $currentRequest;

  /**
   *
   * @param array $configuration
   * @param type $pluginId
   * @param type $pluginDefinition
   * @param array $serializerFormats
   * @param \Drupal\api\Plugin\rest\resource\LoggerInterface $logger
   * @param \Drupal\api\Plugin\rest\resource\AccountProxyInterface $currentUser
   */
  public function __construct(array $configuration, $pluginId, $pluginDefinition, array $serializerFormats, LoggerInterface $logger, AccountProxyInterface $currentUser, Request $currentRequest) {
    parent::__construct($configuration, $pluginId, $pluginDefinition, $serializerFormats, $logger);

    $this->currentUser = $currentUser;
    $this->currentRequest = $currentRequest;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
    return new static(
        $configuration,
        $pluginId,
        $pluginDefinition,
        $container->getParameter('serializer.formats'),
        $container->get('logger.factory')->get('rest'),
        $container->get('current_user'),
        $container->get('request_stack')->getCurrentRequest()
    );
  }

  /**
   *
   * @param array $message
   * @param integer $cache
   * @return ResourceResponse
   */
  protected function getResponse($message, $cache = 0) {
    $build = [
      '#cache' => [
        'max-age' => $cache,
      ]
    ];

    $response = new ResourceResponse($message);
    $response->addCacheableDependency($build);

    return $response;
  }

}

```

**TestResource.php (the actual REST resouce)**

```
<?php

namespace Drupal\api\Plugin\rest\resource;

use Drupal\rest\ResourceResponse;
use Drupal\api\Plugin\rest\RestBase;

/**
 * Test resource.
 *
 * @RestResource(
 *   id = "test_resource",
 *   label = @Translation("Test API Resource"),
 *   uri_paths = {
 *     "canonical" = "/api/test-resource"
 *   }
 * )
 */
class TestResource extends RestBase {

  /**
   *
   * @return ResourceResponse
   */
  public function get() {
    if (!$this->currentUser->hasPermission('use ' . $this->pluginId . ' service')) {
      throw new AccessDeniedHttpException('Access denied.');
    }

    $id = $this->currentRequest->get('id');

    $message = [
      'message' => 'Hello, you called service: ' . $this->pluginId,
      'id' => $id,
    ];

    return parent::getResponse($message);
  }

}

```

In my own base class `RestBase` I added the current request from the request stack (besides the `AccountProxy` for permission purposes) by overriding the `create` method of the `ResourceBase` class. You can then access query parameters in your REST resource by calling the `get($key)` method on the request object.

You will need to pass your parameters in the API URI like so: `http://localhost/api/test-resource?_format=<your-format>&<parameter1>=<value1>`. Considering this example API URI you would access `parameter1` via `$value1 = $this->currentRequest->get('parameter1')`.

I guess that it is not possible to have slugs in your resources at the moment. If someone knows how please do tell :).

# Answer
> 3 votes
For a custom REST resource supporting only GET where an optional path param could be for filtering, you can add a default for a parameter in the routes() method and thus make it optional.

For example this has the essential bits:

```
/**
 * Provides a resource for groups that may have inventory.
 *
 * @RestResource(
 *   id = "owning_groups",
 *   label = @Translation("All Groups That May Own Inventory (optionally limited to one space)"),
 *   uri_paths = {
 *     "canonical" = "/rest/owning_groups/{nid}",
 *   }
 * )
 */
class OwningGroupsRestResource extends ResourceBase {

  /**
   * Responds to a GET request.
   *
   * @param int $nid
   *   Space node ID.
   *
   * @return \Drupal\rest\ResourceResponse
   *   Rest Response with all group nid/titles.
   *
   * @throws \Exception
   */
  public function get($nid): ResourceResponse {
    $space_node = NULL;
    if ($nid) {
      /** @var \Drupal\node\NodeInterface $space_node */
      $space_node = $this->entityTypeManager->getStorage('node')->load($nid);
      if (!$space_node || $space_node->bundle() !== 'space') {
        throw new NotFoundHttpException('No such space');
      }
    }
...

   return $response;
 }

  /**
   * {@inheritdoc}
   */
  public function routes() {
    $collection = parent::routes();
    // Add defaults for optional parameters.
    $defaults = [
      'nid' => 0,
    ];
    foreach ($collection->all() as $route) {
      $route->addDefaults($defaults);
    }
    return $collection;
  }

}

```

see also: How I can add an optional parameter in REST API URL

# Answer
> 1 votes
In your your\_module.routing.yml file in your route configuration

```
defaults:
  id: 'default-id'

```

see here under Optional parameters for more information

If you are trying to alter existing route you should use RouteSubscriber

Or if you need to display something else on `/content/get/` you should create additional route without `{id}`

# Answer
> 1 votes
There are some solutions on this page that explain how to do it. A different question is whether you should do it :)

From Drupal.org issue RestResource plugins: use get() method with optional parameter (or no parameter) to signal list support?:

One concept about the differences of collections and items:

> A "collection resource" is likely to support POST and GET. An "individual item resource" will probably support GET, PUT, PATCH, and DELETE.

Another thought on general domain:

> At least I think optional parameters are a flaw. I think on the REST domain level there is no notion of optional parameters. There is a collection resource and there is an individual object resource.

And about using Views:

> The REST module basically has spent no time/thought on how to deal with collections. AFAICT it deferred that entirely to Views.

**In summary:** it seems the standard idea is that you can use Views for collections or you can write 2 Resources - one for the collection and one for the item.

---
Tags: 8
---


title: Webform file upload with condition

text:
# Question
Title: Webform file upload with condition
I have a webform with file upload element. This works fine as long as the file upload element does not have a condition tied to it. Without the condition, one can see that the selected file was uploaded. With the condition, the file does upload, but the page does not update showing the uploaded file. It took me a while to realize that

1. The file was indeed uploading
2. the condition was causing this behavior

I saw that there was a ticket about this exact issue for drupal 7 and it was marked as won't fix. I wasn't sure if this meant that it wouldn't be fixed just for Drupal 7 or does this apply to Drupal 8 as well?

# Answer
I found a good solution. Since there were multiple elements that depended on the same condition for visibility, I realized I could put them into a fieldset and define the condition for the fieldset instead. This did the trick.
> 0 votes

---
Tags: 8, webforms
---


# Question
Title: Drupal 8 url after installation using drush site-install
I used Composer to download and install Drupal 8.8.1 on Linux and used drush site:install command for setup.

Only the following lines/messages were shown after I entered drush site:install command.

```
You are about to DROP all tables in your 'drupal8' database. Do you want to continue? (yes/no) [yes]:

>yes

[notice]Starting Drupal installation. This takes a while.
[success] Installation complete. User name and password displayed.

```

I don't know my site URL. How do I find my site URL? Is there a default site URL?

Thank you

# Answer
> 1 votes
Congratulations on getting this far. You got Drupal and Drush downloaded and were able to configure the database. Those can both be challenging things to do.

Based on your description it seems like do not have a webserver. Drupal.org has some documentation on setting up a webserver and there are a few solutions to that, like setting up apache or nginx.

Since you mentioned you have drush available one of the easiest solutions is to use drush's `runserver` command. It is documented here

From the project root run the command:

```
drush runserver

```

The output of that command will tell you the URL to load into your browser. By default the URL is `http://127.0.0.1:8888` which it will tell you `Listening on http://127.0.0.1:8888`.

Here's a more detailed article from Lullabot on runserver.

---
Tags: drush
---


# Question
Title: More options for page--node--edit.html.twig for content type
Using my Theme debug I'm getting the following themplate suggestions

```
page--node--blogpost.html.twig

page--node--edit.html.twig

```

When I tried to use different template to edit a blogpost template only like

```
page--node--edit--blogpost.html.twig

```

the template was ignored. How to add more template suggestion for Drupal?

# Answer
> 1 votes
What you are looking for is called **theme suggestions** you can implement your own or alter existing ones. In this case since the *theme* hook is provided by another module (core) you need to alter the provided suggestions and add your own.

Check this post with useful examples. Also core's always have excelent examples (Bartik theme example).

```
/**
 * Implements hook_theme_suggestions_HOOK_alter() for form templates.
 */
function bartik_theme_suggestions_form_alter(array &$suggestions, array $variables) {
  if ($variables['element']['#form_id'] == 'search_block_form') {
    $suggestions[] = 'form__search_block_form';
  }
}

```

---
Tags: 8, theming
---


# Question
Title: Render paragraph reference field in page.html.twig
In **page.html.twig** I want to **show a paragraph reference field** which contains a left and right text\_field.

The **name of the reference field** in the node is: **field\_intro**. That field is linked to a paragraph type named: text\_left\_right

Using below code I can render the paragraphs, but if I add an extra field to the paragraph type, it is not updated. I would like to render all fields, even if I add a new field in the future.

That is not going to happen with this piece of code:

```
{% for item in node.field_intro %}
  {{ item.entity.field_left.value }}
{% endfor %}

```

I found a lot of answers for rendering in node.html.twig but not in page.html.twig.

**UPDATE after below comments and answer:** It is not recommended to print fields in a page.html.twig page. Better use views or blocks to establish what you need. And if you want to use templates, use node.html.twig.

# Answer
> 0 votes
> but if I add an extra field to the paragraph type, it is not updated. I would like to render all fields, even if I add a new field in the future.

To answer the question, you just need to loop though the paragraph fields.

```
{% for item in node.field_intro %}
  {% for paragraph_field in item.entity %}
     {% if 'field_' in paragraph_field %}
       {{ paragraph_field.value }}
     {% endif %}
  {% endfor %}
{% endfor %}

```

---
Tags: 8, theming, paragraphs
---


title: How to add a custom module to a menu?

text:
# Question
Title: How to add a custom module to a menu?
I am using Drupal 7. I have just built a wonderful custom module. Now I need to add it to my main menu, under the parent item "Tools and Resources."

I know I can go to the homepage and click on the little gear and go to "List links", which will take me to admin/structure/menu/manage/main-menu/list?destination=node and I can click-and-hold on the little compass and drag-and-drop my module in the desired place. But, is there a way to do this through the PHP code in the module itself?

# Answer
Menu items are nested using the item path. Take look to the *paragraphs* module:

```
/**
 * Implements hook_menu().
 */
function paragraphs_menu() {
  $items = array();
  $items['admin/structure/paragraphs'] = array(
    'title' => 'Paragraph Bundles',
    'description' => 'Manage Paragraph bundles',
    'page callback' => 'paragraphs_admin_bundle_overview',
    'access arguments' => array('administer paragraphs bundles'),
    'file' => 'paragraphs.admin.inc',
  );

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

  $items['admin/structure/paragraphs/add'] = array(
    'title' => 'Add Paragraph Bundle',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('paragraphs_admin_bundle_form'),
    'access arguments' => array('administer paragraphs bundles'),
    'type' => MENU_LOCAL_ACTION,
    'file' => 'paragraphs.admin.inc',
  );

  $items['admin/structure/paragraphs/%paragraphs_bundle'] = array(
    'title' => 'Edit paragraph bundle',
    'title callback' => 'paragraphs_bundle_title_callback',
    'title arguments' => array(3),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('paragraphs_admin_bundle_form', 3),
    'access arguments' => array('administer paragraphs bundles'),
    'file' => 'paragraphs.admin.inc',
  );

  ...

  return $items;
}

```

Also if you want to add your menu item to an existing menu other than administration use the *menu* key.

```
$items['menu-item'] = array(
  'title' => 'Foo bar',
  'page callback' => 'drupal_get_form',
  'page arguments' => array('foo_bar'),
  'menu' => 'user_menu'
);

```

Check the hook documentation for more information.
> 0 votes

---
Tags: 7, navigation
---


# Question
Title: Can we access paragraph field in views-view-unformatted.twig?
Is there a way to access the fields in paragraph in views-view-unformatted.twig.
I want to perform checking on field of paragraph before print the row
something like this

```
{% for row in rows %}
  {%
    set row_classes = [
      default_row_class ? 'views-row',
    ]
  %}
  {% if paragraph_field is not null %}
     <div {{ row.attributes.addClass(row_classes) }}>
        {{ row.content }}
     </div>
  {% endif %}
{% endfor %}

```

# Answer
I don't think you can get the value of field from paragraph field inside `views-view-unformatted.twig` all you can get is the `target_id` of referenced paragraph using `view.result[key]._entity`:

I suggest to use `template_preprocess_views_view_unformatted` like the following:

```
function YOURTHEME_preprocess_views_view_unformatted(&$variables) {
  $view = $variables['view'];
  $rows = $variables['rows'];
  if ($view->id() === 'YOUR_VIEW_ID') {
    $paragraph_storage = \Drupal::entityTypeManager()->getStorage('paragraph');
    foreach ($rows as $id => $row) {
      /** @var \Drupal\node\Entity\Node $node */
      $node = $view->result[$id]->_entity;
      // Get paragraph field.
      // Change field_paragraph by your filed ref to paragraph.
      if ($node->hasField('field_paragraph')) {
        $paragraph_ref_id = $node->field_paragraph->getValue()[0]['target_id'] ?? NULL;
        if ($paragraph_ref_id) {
          /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph_entity */
          $paragraph_entity = $paragraph_storage->load($paragraph_ref_id);
          // Get the value of your field.
          // Change field_paragraph_text by your field.
          // And set another variable to use in twig.
          $variables['rows'][$id]['should_display_row'] = ($paragraph_entity->field_paragraph_text->value !== NULL) ? TRUE : FALSE;
        }
      }
    }
  }
}

```

Now in your `views-view-unformatted.twig` you can check on `row.should_display_row` like the following:

```
{% for row in rows %}
  {%
    set row_classes = [
      default_row_class ? 'views-row',
    ]
  %}
  {% if row.should_display_row %}
    <div{{ row.attributes.addClass(row_classes) }}>
      {{- row.content -}}
    </div>
  {% endif %}
{% endfor %}

```
> 2 votes

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