# Question
Title: message: "No PDF generation tool found! Please dowload a supported PHP PDF generation tool ... "
I installed print module but I got this message when I wanted to install PDF section, I was reviewing pdf modules such as dompdf mPDF TCPDF wkhtmltopdf

but any works when I want to install them, please help

# Answer
Do you mean that none work? I know that wkhtmltopdf requires (or used to) an X server. Most people, and what I did at a point, was to install Xvfb, https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml
> 0 votes

---
Tags: 7, files
---


# Question
Title: Is there a performance hit to using persistant variables?
While working on some old custom code I noticed that variable\_set() was being used in a manner that always made new key pair values and never made a call to variable\_del. These values would be read once under a certain condition and never read again.

Are persistant variables something that get cleared on clear cache or are they always building up?

if they are building up does this affect the size or speed of page load?

example:

```
variable_set('key_name_' . $increment, $value);

```

# Answer
In Drupal 6 and 7, variables created with `variable_set()` are stored in the `{variable}` database table. They are not automatically cleared when the cache is cleared. They are only removed when `variable_del()` is called.

Whenever a page is loaded, all variables in the `{variable}` table are loaded into the global `$conf` array. So yes - if a site is automatically creating new variables at a constant rate without cleaning them up, it could in theory cause performance degradation.

You can see in the `variable_get()` function that it is simply loading the global `$conf` array and looking for the requested variable within that.

It sounds like the custom code *should* have been using a dedicated database table for the data it was storing, because then it would only load that information when it needed to. Variables are loaded on every pageload.
> 2 votes

# Answer
Yes.

> If you find a module doing this in Drupal 7, consider checking that the value of the variable has changed before saving it, converting to use the cache system if that’s feasible, saving the value in a dedicated table if it’s not requested frequently, or like drupal\_http\_request() just logging the change via watchdog().

From *High Performance Drupal*.
> 0 votes

---
Tags: 7, performance, configuration
---


title: Add a term to a vocabulary

text:
# Question
Title: Add a term to a vocabulary
I am using Drupal API as api\_driver to run BEHAT scenarios. Please see below scarios for creating a term for the taxonomy "test\_new". While running, this got success but when I take the application and look for the new term created it showing on the listing page. But when clicking on Edit of that term, name and description is not get updated, its showing empty but parent field is correctly mapped.

Why is this happening?

```
  Given "test_new" terms:
    | name              | parent         | description_field    |
    | Test term one     | Test parent    | term one description |
    And I wait for 20 seconds

```

# Answer
> 0 votes
It got worked by adding language and format for terms. Please see below code.

```
  Given "test_new" terms:
    | name           | parent      | description          | format     | language |
    | Test term one  | Test parent | term one description | plain_text | en       |

```

---
Tags: testing
---


# Question
Title: How to add more field columns using Inline Entity Form table display
I was wondering if it is possible to have more columns in an Inline Entity Form table to show things like serial numbers and make/model after I input the Node ID. I was reading the answers from this question but I am confused on how to make these work. But in the end I would like the table to look similar to this:

For example, I would like to be able to input the existing Inventory number (node) and when I click "add" it will display the make/model and the serial number (if this is even possible). Which will then be saved as a Sales Order.

# Answer
> 3 votes
Consider using ief\_table\_view\_mode module or hook\_inline\_entity\_form\_table\_fields\_alter()

For more information see answers to a similar question: How to show fields in the Inline Entity Form display widget?

---
Tags: entities
---


# Question
Title: hook_inline_entity_form_table_fields_alter add custom field
Need some help with Inline Entity Form hook function hook\_inline\_entity\_form\_table\_fields\_alter.

I'm trying to add columns to the table that is visible when editing a specific node. I have been able to add fields and got the content to print too, but I need to add a checkbox. I've unfortunate not been able to **find how to add other custom fields**, so I wonder if someone has used this function before?

I guess it would be possible to add a "checkbox" fields to the content type itself, but in this case its more like a function rather than a value that I want to save.

Best, Fever

# Answer
> 0 votes
Add the checkbox field to the referenced entity. Also, as an alternative you could use ief\_table\_view\_mode module instead of hook\_inline\_entity\_form\_table\_fields\_alter and then set the fields that should be displayed in the table on the referenced entity in the Entity form table view mode.

---
Tags: 7, entities, hooks
---


# Question
Title: What is the purpose of key_value_expire table?
In Drupal8, what purpose does the key\_value\_expire table data serve? Can that be excluded from a database backup?

I ask because, during development, I backup the database using "drush sql-dump --ordered-dump" and exclude tables like "cache\*", but after making a few minor content changes in a node/page (did not create a revision) and re-dumping the database, git diff is saying that all of the data in the key\_value\_expire table changed.

key\_value\_expire is one of the larger tables in Drupal, in terms of # of rows of data, so it will balloon the storage requirements for Git if the data in this table changes completely for every minor change on the site.

Also, is there a detailed explanation of the functionality/purpose of each Drupal table?

Thank you very much in advance.

# Answer
Beside the form cache and the update status the key\_value\_expire table is mainly used by the private and shared temp store. There you find a good explanation what the purpose of this data is:

> class PrivateTempStore
>
> Stores and retrieves temporary data for a given owner.
>
> A PrivateTempStore can be used to make temporary, non-cache data available across requests. The data for the PrivateTempStore is stored in one key/value collection. PrivateTempStore data expires automatically after a given timeframe.
>
> The PrivateTempStore is different from a cache, because the data in it is not yet saved permanently and so it cannot be rebuilt. Typically, the PrivateTempStore might be used to store work in progress that is later saved permanently elsewhere, e.g. autosave data, multistep forms, or in-progress changes to complex configuration that are not ready to be saved.
>
> The PrivateTempStore differs from the SharedTempStore in that all keys are ensured to be unique for a particular user and users can never share data. If you want to be able to share data between users or use it for locking, use \Drupal\user\SharedTempStore.

Reference: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21TempStore%21PrivateTempStore.php/class/PrivateTempStore/10 https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21TempStore%21SharedTempStore.php/class/SharedTempStore/10
> 8 votes

---
Tags: 8, database, drush, version-control
---


# Question
Title: How to hide an image field from teaser view if video field has data?
>

```
foreach($view->result as $value){
     if($value->_entity->field_videos->getValue()[0]['target_id']){
      kint($value->_entity->field_blogimage)
    }

```

I am getting following image by kint, I need to set exclude to 0 for image field of this view in views\_pre\_render hook in drupal 8.

>

# Answer
> 1 votes
```
function mymodule_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\
  EntityInterface $entity, $context) {
  // For nodes, change the view mode when it is teaser.
  $current_path = \Drupal::service('path.current')->getPath();
  if($current_path=='/dblog'){
    if ($entity->getEntityTypeId() == 'node') {
        // kint($entity->getFields()['field_videos']
        //  ->getValue()[0]['target_id']);
        if(!(empty($entity->getFields()['field_videos']
        ->getValue()[0]['target_id']))){
        $view_mode='single';
        }
    }

  }

}

```

well in my case, i solved my problem like this, i created new view mode with needed fields and switched view modes using above hooks.I think this one is a good alternative.Thanks Guys @OPTASY Canada @Chriss Happy

# Answer
> 0 votes
I don't fully understand the question, but I think if you displayed fields and styled them that way, you could:

* Include the image field, above the video field, and exclude it from display.
* In the video fields no results behaviours, you could just add the image field.

---
Tags: views, 8, hooks
---


# Question
Title: How do I set the block visibility with PHP?
In a site running Drupal 8, I want to show my block in two cases: when my view page is shown and when a node of my content type is shown.

How do I set the block visibility with PHP?

# Answer
The core visibility configuration is not so good in combining multiple visibility condition.

The module Block Visibility Groups provides more tools to do this. You can decide whether all condition must pass (logical AND) or only one condition must pass (logical OR) and put the logic in a group and reuse it on different blocks.
> 2 votes

---
Tags: 8, blocks
---


# Question
Title: How to create sub-directory based multi-site?
I want to create subdirectory based multisite, for this I roamed full day in internet but nowhere I found how can do the symlink in a proper manner. I will divide my requirement below:

Site name I have is: capacad(accesible by url: `localhost:81/capacad/`)

I want multisite url should be: `localhost:81/capacad/subsite`

So to achieve this I created a folder named subsite in `C:\xampp\htdocs\capacad\sites\subsite`.

Later this step I have to do symlink. So how can I achieve that.

I tried this command: `C:\>mklink /d C:\xampp\htdocs\capacad\sites\subsite C:\xampp\htdocs\capacad`

This is creating multiple loops inside the subsite folder.

I am not getting the what path names where to link. Can anybody please explain me elaborately how can I achieve this in windows.

Thanks for any suggestions.

I followed some below links:

link1

link2

link3

# Answer
You can modify the site names in the file sites/site.php

```
$sites = array(
  'site1.your-multisite.local' => 'website1',
  'your-multisite.local.site2' => 'website2',
);

```

Also update the settings.php file of each subdomain with the credentials of respective sites.

Also need to update the site url from the host settings.

```
 ServerAlias    *.your-multisite.local your-multisite.local.*

```
> 0 votes

---
Tags: 7, multi-sites, subsites
---


title: add class to form element

text:
# Question
Title: add class to form element
```
function ajax_register_form_user_login_alter(&$form, &$form_state, $form_id) {
   $form['fbuser'] = array(
      '#type' => 'item',
      '#markup' => 'You have a facebook account?',
      '#weight' => -10,
    );
   $form['login_link'] = array(
      '#type' => 'item',
      '#markup' => '<a class="facebook-action-connect" rel="nofollow" href="foo"><img src="foo" alt=""></a></div>',
      '#weight' => -6,
    );
   }

```

How can I add a class to this div's?

# Answer
You might be looking for the `#attributes` property that you can add to forms and form elements. See example below

```
function ajax_register_form_user_login_alter(&$form, &$form_state, $form_id) {
   $form['fbuser'] = array(
      '#type' => 'item',
      '#markup' => 'You have a facebook account?',
      '#weight' => -10,
      '#attributes' => array('class' => array('my-class-1')),
    );
   $form['login_link'] = array(
      '#type' => 'item',
      '#markup' => '<a class="facebook-action-connect" rel="nofollow" href="foo"><img src="foo" alt=""></a></div>',
      '#weight' => -6,
      '#attributes' => array('class' => array('my-class-2')),
    );
   }

```
> 15 votes

# Answer
According to the drupal official form api guide, the item type cannot use the `#attributes` property:

https://api.drupal.org/api/drupal/developer!topics!forms\_api\_reference.html/7#item

A workaround could be using the `#prefix` and `#suffix` properties:

```
$form['fbuser'] = array(
  '#type' => 'item',
  '#markup' => 'You have a facebook account?',
  '#weight' => -10,
  '#prefix' => '<span class="my_class">',
  '#suffix' => '</span>', // close the span openend by the #prefix property
);

```

The drawback is that the css class will be added to a parent of the item element, not to the item itself.
> 6 votes

# Answer
Use `'#attributes' => array('class' => array('my-class'))` or else you can do this:

```
$form['html_markup_address'] = array(
  '#markup' => l(t('Add New Address'), 'mymodule/nojs',
   array('attributes' => array('class' => array('ctools-use-modal'))))
);

```
> 1 votes

# Answer
You could use `_form_set_class()`

Docs: https://api.drupal.org/api/function/\_form\_set\_class/7.x

Example:

```
_form_set_class($element, array('my-class'));

```
> 0 votes

---
Tags: 7, forms
---


# Question
Title: How do I view content using an administrative theme like Seven, when logged in as administrator?
I can't view nodes using the Seven theme as administrative theme. When I am logged in as administrator, I can only view management pages with Seven, but no content pages.

I thought that the settings on this page should be sufficient.

>

How do I set an administrative theme like Seven to view nodes when I am logged in as administrator?

# Answer
Drupal doesn't treat Content/Node view page as admin pages even after enabling "**Use the administration theme when editing or creating content**" setting on "**Admin =\> Appearance**" Page. This is just a setting allowed by Drupal Core. Node module uses this setting and alter Content/Note edit, delete, revision, etc. page URLs so Drupal can treat these path as Admin path.

You'll have to alter route defined by Core's **Node** module. You can do this by implementing `alterRoutes()` and tell Drupal to treat Content View page as admin URLs. Check example below:

```
namespace Drupal\example\Routing;

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

/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('entity.node.canonical')) {
      // Node module has option to define all path as admin path,
      // where path has "_node_operation_route" option set to TRUE.
      $route->setOption('_node_operation_route', TRUE);
      // Below line define path as admin path.
      // $route->setOption('_admin_route', TRUE);
    }
  }

}

```

If **Use the administration theme when editing or creating content** setting is enabled then, the Node module checks if any path has `_node_operation_route` option set to `TRUE`. If yes, it alters the path and set `_admin_route` option to `TRUE` so the path will be treated as an **admin path** (and then you will see it as in an admin theme, which is in this case, Seven).

If this doesn't work you can specifically set `_admin_route` option to `TRUE` for Content/Node View (`entity.node.canonical`) page programatically (check commented code).
> 7 votes

---
Tags: 8
---


# Question
Title: Set image as permanent in custom block plugin, temporary URI
I'm building a custom block plugin with an image upload which is working fine except for the fact that although the $file-\>status is set to permanent the URI still comes up as temporary.

This is the code I'm using:

```
namespace Drupal\eight\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\file\Entity\File;
use Drupal\image\Entity\ImageStyle;

class MyBlock extends BlockBase {
  public function defaultConfiguration() {
    return [
      'upload_image' => '',
    ] + parent::defaultConfiguration();
  }

  public function blockForm($form, FormStateInterface $form_state) {
    $form['upload_image'] = [
      '#type' => 'managed_file',
      '#title' => $this->t('Upload Image'),
      '#default_value' => $this->configuration['upload_image'],
    ];

    return $form;
  }

  public function saveImage($fid) {
    $file = File::load( $fid );
    if ($file) {
      $file->setPermanent();
      $file->save();
    }
  }

  public function blockSubmit($form, FormStateInterface $form_state) {
    $fid = $form_state->getValue('upload_image')[0];
    $this->saveImage($fid);

    $this->configuration['upload_image'] = [$fid];
  }

  public function build() {
    $config = $this->getConfiguration();
    $image = '';

    $file = File::load($config['upload_image'][0]);
    if ($file) {
      return [
        'logo' => $file->getFileUri(),
      ];
    } else {
      return [];
    }
  }
}

```

Inspecting the $file object before and after the saveImage method the status is actually changing from 0 to 1 but the URI I get is still pointing to the temporary file scheme.

URI: temporary://xxxxx.jpg

URL: xxxxx.xxx/system/temporary?file=xxxxx.JPG

What would be the way to correctly store the image as permanent?

# Answer
To set the correct file scheme is necessary to define the upload location in the form array.

I've amended the form as follows:

```
public function blockForm($form, FormStateInterface $form_state) {
  $form['upload_image'] = [
    '#type' => 'managed_file',
    '#title' => $this->t('Upload Image'),
    '#default_value' => $this->configuration['upload_image'],
    '#upload_location => 'public://blocks',
    ];

  return $form;
}

```

The URI and URL are now as expected and the file is permanently saved.
> 4 votes

---
Tags: 8, blocks, media, files
---


title: Entity table not created

text:
# Question
Title: Entity table not created
I use drupal:generate:entity to generate my entity but it doesn't create the database table. Then it result an error when i tried to access to my entity list page.

I tried to launch www.mysite.com/update.php but no databases update was found. Can you help me please ?

```
Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'drupal8db.myc_static_content_entity' doesn't exist: SELECT COUNT(*) AS expression FROM (SELECT 1 AS expression FROM {static_content_entity} base_table) subquery; Array ( ) in Drupal\Core\Entity\EntityListBuilder->getEntityIds() (line 98 of core/lib/Drupal/Core/Entity/EntityListBuilder.php).
Drupal\Core\Database\Statement->execute(Array, Array) (Line: 610)
Drupal\Core\Database\Connection->query('SELECT COUNT(*) AS expression
FROM
(SELECT 1 AS expression
FROM
{static_content_entity} base_table) subquery', Array, Array) (Line: 81)
Drupal\Core\Database\Driver\mysql\Connection->query('SELECT COUNT(*) AS expression
FROM
(SELECT 1 AS expression
FROM
{static_content_entity} base_table) subquery', Array, Array) (Line: 508)
Drupal\Core\Database\Query\Select->execute() (Line: 245)
Drupal\Core\Entity\Query\Sql\Query->result() (Line: 77)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 296)
Drupal\Core\Entity\Query\QueryBase->initializePager() (Line: 224)
Drupal\Core\Entity\Query\Sql\Query->finish() (Line: 76)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 98)
Drupal\Core\Entity\EntityListBuilder->getEntityIds() (Line: 80)
Drupal\Core\Entity\EntityListBuilder->load() (Line: 228)
Drupal\Core\Entity\EntityListBuilder->render() (Line: 22)
Drupal\Core\Entity\Controller\EntityListController->listing('static_content_entity')
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 574)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array) (Line: 139)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 62)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 652)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

```

Here is my entity class definition :

```
/**
 * Defines the Static content entity entity.
 *
 * @ingroup static_content_master
 *
 * @ContentEntityType(
 *   id = "static_content_entity",
 *   label = @Translation("Static content entity"),
 *   handlers = {
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "list_builder" = "Drupal\static_content_master\StaticContentEntityListBuilder",
 *     "views_data" = "Drupal\static_content_master\Entity\StaticContentEntityViewsData",
 *
 *     "form" = {
 *       "default" = "Drupal\static_content_master\Form\StaticContentEntityForm",
 *       "add" = "Drupal\static_content_master\Form\StaticContentEntityForm",
 *       "edit" = "Drupal\static_content_master\Form\StaticContentEntityForm",
 *       "delete" = "Drupal\static_content_master\Form\StaticContentEntityDeleteForm",
 *     },
 *     "access" = "Drupal\static_content_master\StaticContentEntityAccessControlHandler",
 *     "route_provider" = {
 *       "html" = "Drupal\static_content_master\StaticContentEntityHtmlRouteProvider",
 *     },
 *   },
 *   base_table = "static_content_entity",
 *   admin_permission = "administer static content entity entities",
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "name",
 *     "uuid" = "uuid",
 *     "uid" = "user_id",
 *     "langcode" = "langcode",
 *     "status" = "status",
 *   },
 *   links = {
 *     "canonical" = "/admin/structure/static_content_entity/{static_content_entity}",
 *     "add-form" = "/admin/structure/static_content_entity/add",
 *     "edit-form" = "/admin/structure/static_content_entity/{static_content_entity}/edit",
 *     "delete-form" = "/admin/structure/static_content_entity/{static_content_entity}/delete",
 *     "collection" = "/admin/structure/static_content_entity",
 *   },
 *   field_ui_base_route = "static_content_entity.settings"
 * )
 */

```

# Answer
I uninstalled my module and reinstalled it. I found out that tables were created at the initialization of the module.
> 5 votes

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


# Question
Title: rest POST via Postman always ends in 403 access denied
I try to create a node via a rest POST over Chrome's Postman using Drupal 8.2.3., but i always get a 403 access denied.

Can anyone point out a step-by-step how-to on the settings? Mainly regarding the permissions that need to be set accordingly.

I did obtains the token at `/rest/session/token` and added into the request header.

The Request was: `MYURL.de/rest/node?_format=json`. For your information: I created the service-endpoint `/rest`, and I also tried with: `MYURL.de/node?_format=json`, but the same result.

Can anyone drop me a hint?

# Answer
* Your request need `?_format=json` on the end of request.
* Clear cache.
* Delete all sessions, `delete from sessions`.
* Call login service, `/user/login?_format=json`, method `POST` choose raw in Body and there put username and password in `JSON` format:

```
{
   "username": "value",
   "password": "value",
}

```

and choose JSON (`application/json`).

This service will return `X-CSFR-TOKEN`, use it for your request.
> 2 votes

---
Tags: users, 8
---


title: Recommended file permissions

text:
# Question
Title: Recommended file permissions
Similarly to what described in https://www.drupal.org/node/244924, which is for Drupal 7, is there any script to set the right permissions for Drupal 8?

How can we take care of the file permissions for contributed modules? For example, I know a few modules which would have different permissions for files like .htaccess and other private folders in the modules. Is there a way we can reset the file permissions to initial versions?

# Answer
I've been running the same script included on that page for sites running either Drupal 7 or Drupal 8, with no adverse effects. I would recommend just using that.
> 1 votes

---
Tags: 8, files
---


title: Access denied on admin/structure

text:
# Question
Title: Access denied on admin/structure
I have defined a new user role "Webmaster", and assigned it the permissions to administer forms, menu & menu items and taxonomy terms (all). Going to the admin/structure url still yields an "Access denied".

What permissions do I need set to allow my webmasters access to the admin/structure url?

# Answer
The user needs the permission "Use the administration pages and help".

Then the user can access `/admin` and `/admin/structure`.

If the user has no other admin rights, the admin menus will be rather empty. They will fill up if you assign more permissions.
> 6 votes

---
Tags: 8, users
---


# Question
Title: Override or extend function of a contributed module
i need to modify the submit function of the module **custom\_search** *(8.x-1.0-beta3)*.

I need to set a **Cookie** every time the **guest user** search something, how can i override or extend the submit function?

It looks like not represent a **hook**. The function is: **custom\_search\_search\_page\_submit** located in the file *custom\_search.module* and called by the **custom\_search\_form\_alter** function that implements **hook\_form\_alter()**

```
/**
 * Search pages settings form callback.
 */
function custom_search_search_page_submit($form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $pageId = $form_state->getValue('id');
  // Save settings, and path as well so we can use it to retrieve the correct settings later.
  \Drupal::configFactory()->getEditable('custom_search.settings.results')->set($pageId . '.path', $form_state->getValue('path'))
    ->set($pageId . '.search', $form_state->getValue('custom_search_search'))
    ->set($pageId . '.advanced.visibility', $form_state->getValue('custom_search_advanced_search'))
    ->set($pageId . '.advanced.collapsible', $form_state->getValue('custom_search_collapsible'))
    ->set($pageId . '.advanced.collapsed', $form_state->getValue('custom_search_collapsed'))
    ->set($pageId . '.advanced.criteria', $form_state->getValue('custom_search_criteria'))
    ->set($pageId . '.advanced.types', $form_state->getValue('custom_search_types'))
    ->set($pageId . '.advanced.languages', $form_state->getValue('custom_search_languages'))
    ->set($pageId . '.info', $form_state->getValue('custom_search_info'))
    ->set($pageId . '.filter.position', $form_state->getValue('custom_search_filter_position'))
    ->set($pageId . '.filter.label', $form_state->getValue('custom_search_filter_label'))
    ->set($pageId . '.filter.any', $form_state->getValue('custom_search_filter_any'))
    ->save();
}

```

# Answer
> 2 votes
I ended up with the next code on my own module, thanks to @4k4 and @marcvangend It works like a charm!!

```
<?php

/**
 * @file
 * Bring customizations to the default core functions
 *
 */
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Datetime\DrupalDateTime;

 /**
 * Implements hook_form_alter().
 */
function my_module_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'search_form') {
    $form['#submit'][] = 'my_module_search_page_submit';
  }
}

function my_module_search_page_submit($form, FormStateInterface $form_state) {
  $form_values = $form_state->getValues();
  $date = new DrupalDateTime();
  user_cookie_save(['search_form-'.$date->format('Y-m-d_H-i-s') => $form_values['keys'] ]);
}

```

# Answer
> 3 votes
You don't need to override the submit function. Each module or theme can do exactly the same as the custom search module does. Use a form alter hook and add their own submit function to the form array. On submit they are each executed one after another.

**mymodule.module**

```
/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if ($form_id == 'form_id') {
    $form['actions']['submit']['#submit'][] = 'mymodule_search_page_submit';
  }
}

function mymodule_search_page_submit($form, \Drupal\Core\Form\FormStateInterface $form_state) {
  // set cookie
}

```

---
Tags: 8, hooks
---


# Question
Title: Validate File Extension In Drupal 8 Entity Form
I have an Entity in Drupal 8 named `visual_tracker_entity` Here is my entity,

```
/**
 * @file
 * Contains \Drupal\visual_tracker\Entity\VisaulTrackerEntity.
 */

namespace Drupal\visual_tracker\Entity;

use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\visual_tracker\VisaulTrackerEntityInterface;
use Drupal\user\UserInterface;

/**
 * Defines the Visaul tracker entity entity.
 *
 * @ingroup visual_tracker
 *
 * @ContentEntityType(
 *   id = "visaul_tracker_entity",
 *   label = @Translation("Visaul tracker entity"),
 *   handlers = {
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "list_builder" = "Drupal\visual_tracker\VisaulTrackerEntityListBuilder",
 *     "views_data" = "Drupal\visual_tracker\Entity\VisaulTrackerEntityViewsData",
 *
 *     "form" = {
 *       "default" = "Drupal\visual_tracker\Form\VisaulTrackerEntityForm",
 *       "add" = "Drupal\visual_tracker\Form\VisaulTrackerEntityForm",
 *       "edit" = "Drupal\visual_tracker\Form\VisaulTrackerEntityForm",
 *       "delete" = "Drupal\visual_tracker\Form\VisaulTrackerEntityDeleteForm",
 *     },
 *     "access" = "Drupal\visual_tracker\VisaulTrackerEntityAccessControlHandler",
 *     "route_provider" = {
 *       "html" = "Drupal\visual_tracker\VisaulTrackerEntityHtmlRouteProvider",
 *     },
 *   },
 *   base_table = "visaul_tracker_entity",
 *   admin_permission = "administer visaul tracker entity entities",
 *   entity_keys = {
 *     "id" = "id",
 *     "address" = "address",
 *     "lat"="lat",
 *     "lng" = "lng"
 *   },
 *   links = {
 *     "canonical" = "/admin/structure/visaul_tracker_entity/{visaul_tracker_entity}",
 *     "add-form" = "/admin/structure/visaul_tracker_entity/add",
 *     "edit-form" = "/admin/structure/visaul_tracker_entity/{visaul_tracker_entity}/edit",
 *     "delete-form" = "/admin/structure/visaul_tracker_entity/{visaul_tracker_entity}/delete",
 *     "collection" = "/admin/structure/visaul_tracker_entity",
 *   },
 *   field_ui_base_route = "visaul_tracker_entity.settings"
 * )
 */
class VisaulTrackerEntity extends ContentEntityBase implements VisaulTrackerEntityInterface {
  use EntityChangedTrait;
  /**
   * {@inheritdoc}
   */
  public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
    parent::preCreate($storage_controller, $values);
    $values += array(
      'user_id' => \Drupal::currentUser()->id(),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getName() {
    return $this->get('name')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setName($name) {
    $this->set('name', $name);
    return $this;
  }
  /**
   * {@inheritdoc}
   */
  public function getAddress() {
    return $this->get('address')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setAddress($address) {
    $this->set('address', $address);
    return $this;
  }
  /**
   * {@inheritdoc}
   */
  public function getLatittude() {
    return $this->get('lat')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setLatitude($lat) {
    $this->set('lat', $lat);
    return $this;
  }
  /**
   * {@inheritdoc}
   */
  public function getLongitude() {
    return $this->get('lng')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setLongitude($lng) {
    $this->set('lng', $lng);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getCreatedTime() {
    return $this->get('created')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setCreatedTime($timestamp) {
    $this->set('created', $timestamp);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getOwner() {
    return $this->get('user_id')->entity;
  }

  /**
   * {@inheritdoc}
   */
  public function getOwnerId() {
    return $this->get('user_id')->target_id;
  }

  /**
   * {@inheritdoc}
   */
  public function setOwnerId($uid) {
    $this->set('user_id', $uid);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setOwner(UserInterface $account) {
    $this->set('user_id', $account->id());
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function isPublished() {
    return (bool) $this->getEntityKey('status');
  }

  /**
   * {@inheritdoc}
   */
  public function setPublished($published) {
    $this->set('status', $published ? NODE_PUBLISHED : NODE_NOT_PUBLISHED);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    $fields['id'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('ID'))
      ->setDescription(t('The ID of the Visaul tracker entity entity.'))
      ->setReadOnly(TRUE);
    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('The UUID of the Visaul tracker entity entity.'))
      ->setReadOnly(TRUE);

    $fields['user_id'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Authored by'))
      ->setDescription(t('The user ID of author of the Visaul tracker entity entity.'))
      ->setRevisionable(TRUE)
      ->setSetting('target_type', 'user')
      ->setSetting('handler', 'default')
      ->setDefaultValueCallback('Drupal\node\Entity\Node::getCurrentUserId')
      ->setTranslatable(TRUE)
      ->setDisplayOptions('view', array(
        'label' => 'hidden',
        'type' => 'author',
        'weight' => 0,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'entity_reference_autocomplete',
        'weight' => 5,
        'settings' => array(
          'match_operator' => 'CONTAINS',
          'size' => '60',
          'autocomplete_type' => 'tags',
          'placeholder' => '',
        ),
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    $fields['my_new_file'] = BaseFieldDefinition::create('file')
      ->setLabel(t('My New File'))
      ->setDescription(t('The name of the Visaul tracker entity entity.'))
      ->setDefaultValue('')
      ->setDisplayOptions('view', array(
        'label' => 'above',
        'type' => 'file',
        'weight' => -4,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'file',
        'weight' => -4,
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['address'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Address'))
      ->setDescription(t('The addres of the Visaul tracker entity entity.'))
      ->setSettings(array(
        'max_length' => 250,
        'text_processing' => 0,
      ))
      ->setDefaultValue('')
      ->setDisplayOptions('view', array(
        'label' => 'above',
        'type' => 'string',
        'weight' => -4,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'string_textfield',
        'weight' => -4,
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['lat'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Latitiude'))
      ->setDescription(t('The latiitude of the Visaul tracker entity entity.'))
      ->setSettings(array(
        'max_length' => 50,
        'text_processing' => 0,
      ))
      ->setDefaultValue('')
      ->setDisplayOptions('view', array(
        'label' => 'above',
        'type' => 'string',
        'weight' => -4,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'string_textfield',
        'weight' => -4,
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
    $fields['lng'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Longitude'))
      ->setDescription(t('The name of the Visaul tracker entity entity.'))
      ->setSettings(array(
        'max_length' => 50,
        'text_processing' => 0,
      ))
      ->setDefaultValue('')
      ->setDisplayOptions('view', array(
        'label' => 'above',
        'type' => 'string',
        'weight' => -4,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'string_textfield',
        'weight' => -4,
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    $fields['status'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Publishing status'))
      ->setDescription(t('A boolean indicating whether the Visaul tracker entity is published.'))
      ->setDefaultValue(TRUE);

    $fields['langcode'] = BaseFieldDefinition::create('language')
      ->setLabel(t('Language code'))
      ->setDescription(t('The language code for the Visaul tracker entity entity.'))
      ->setDisplayOptions('form', array(
        'type' => 'language_select',
        'weight' => 10,
      ))
      ->setDisplayConfigurable('form', TRUE);

    $fields['created'] = BaseFieldDefinition::create('created')
      ->setLabel(t('Created'))
      ->setDescription(t('The time that the entity was created.'));

    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
      ->setDescription(t('The time that the entity was last edited.'));

    return $fields;
  }

}

```

I need add validation rule for file type field. The default file type is come with `.txt` extension. I want to only allow `.xls` and `.xlsx` . This is the `file` filed,

```
  $fields['my_new_file'] = BaseFieldDefinition::create('file')
          ->setLabel(t('My New File'))
          ->setDescription(t('The name of the Visaul tracker entity entity.'))
          ->setDefaultValue('')
          ->setDisplayOptions('view', array(
            'label' => 'above',
            'type' => 'file',
            'weight' => -4,
          ))
          ->setDisplayOptions('form', array(
            'type' => 'file',
            'weight' => -4,
          ))
          ->setDisplayConfigurable('form', TRUE)
          ->setDisplayConfigurable('view', TRUE);

```

Please help me.

# Answer
> 4 votes
If you're using a file field, then you can set the "file\_extensions" setting. You can find out more information about a "file" type by going to the FileItem API page (or look it up in your IDE). The class annotation is helpful to learn about things such as the Constraint system if you need to add any additional constraints.

```
 $fields['my_new_file'] = BaseFieldDefinition::create('file')
   ->setSetting('file_extensions', 'xls xlsx');

```

# Answer
> 6 votes
Separately, if you are building a Drupal 8 form that has a file upload, you can pass upload validators in the following manner:

```
$validators = array(
  'file_validate_extensions' => array('csv'),
  'file_validate_size' => array(file_upload_max_size()),
);
$form['csv']['csv_file'] = array(
  '#type' => 'file',
  '#title' => $this->t('CSV File'),
  '#description' => array(
    '#theme' => 'file_upload_help',
    '#description' => $this->t('The CSV file must include columns in the following order:'),
    '#upload_validators' => $validators,
  ),
  '#upload_validators' => $validators,
);

```

... and then validate those extensions during validateForm:

```
public function validateForm(array &$form, FormStateInterface $form_state) {
  $this->file = file_save_upload('csv_file', $form['csv']['csv_file']['#upload_validators'], FALSE, 0);

  // Ensure we have the file uploaded.
  if (!$this->file) {
    $form_state->setErrorByName('csv_file', $this->t('File to import not found.'));
  }
}

```

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


# Question
Title: How to use Views and Rules to activate a new node flag for existing OG members?
We have a flag for nodes called subscribe\_og.

From this point in time users will click that flag to join, or leave, a group.

If you are not a member of the group, the flag says 'Join'. If you are a member the flag says 'leave'.

Old members of a group currently see 'leave' as they have not clicked the flag.

Is it possible to use Views and Rules to generate a list of group members, check if they have have activated the node flag, and if not, activate the node flag for them?

I had a little look at Rules Components and came up with this, which seems to do nothing.

```
    { "rules_gerw" : {
    "LABEL" : "gerw",
    "PLUGIN" : "rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "flag", "og" ],
    "IF" : [
      { "NOT flag_flagged_node" : {
          "flag" : "subscribe_og",
          "node" : [ "site:og-context--node" ],
          "flagging_user" : [ "site:current-user" ]
        }
      },
      { "AND" : [
          { "og_user_in_group" : {
              "account" : [ "site:current-user" ],
              "group" : [ "site:og-context--node" ],
              "states" : { "value" : { "1" : "1" } }
            }
          }
        ]
      }
    ],
    "DO" : [
      { "flag_flagnode" : {
          "flag" : "subscribe_og",
          "node" : [ "site:og-context--node" ],
          "flagging_user" : [ "site:current-user" ],
          "permission_check" : "1"
        }
      }
    ]
  }
}

```

# Answer
# Step 1: Fix your rules Component

The "***... seems to do nothing ...***"-part of your question, is like a variation of "it doesn't work" ... which is extremely hard to debug without access to your site.

However, what I find bizarre about your Rules Component is:

1. You're using token `site:og-context--node`, but there is nothing in your rule that assigns a value to it. So wild guess: it's value is blank or something like that. If my guess is correct, then your rule "works as implemented, ie "it is doing nothing", because not both Rules Conditions are satisfied.
2. It is related to user = `site:current-user`. So you've to be a bit lucky to have this Rules Condition satisfied (it depends if the current user is yes or no member of some group which might be blank).

What I think is needed, at a minimum, is that you use appropriate parameters for this Rules Component, actually for all of your tokens you're using that start with `site:`.

To do so, have a look at this improved version of your Rules Component. The main difference with yours is that I introduced 2 parameters, and replaced all `site:`

```
{ "rules_using_parameters" : {
    "LABEL" : "A Rules component using parameters",
    "PLUGIN" : "rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "flag", "og" ],
    "USES VARIABLES" : {
      "flagging_user" : { "label" : "Flagging user", "type" : "user" },
      "node_to_flag" : { "label" : "Node to be flagged", "type" : "node" }
    },
    "IF" : [
      { "NOT flag_flagged_node" : {
          "flag" : "subscribe_og",
          "node" : [ "node-to-flag" ],
          "flagging_user" : [ "flagging-user" ]
        }
      },
      { "AND" : [
          { "og_user_in_group" : {
              "account" : [ "flagging-user" ],
              "group" : [ "node-to-flag" ],
              "states" : { "value" : { "1" : "1" } }
            }
          }
        ]
      }
    ],
    "DO" : [
      { "flag_flagnode" : {
          "flag" : "subscribe_og",
          "node" : [ "node-to-flag" ],
          "flagging_user" : [ "flagging-user" ],
          "permission_check" : "1"
        }
      }
    ]
  }
}

```

You should be able to just copy the exported rule above, and simply import this Rules Component in your own environment.

After you did this, navigate to `admin/config/workflow/rules/components` in your own site, and then use the hyperlink "execute" to qa-test it in your own site. After you use that link, use the button that says ***`Switch to direct input mode`***. Then you'll be able to enter some ***Node to be flagged***. Use a similar technique to specify the **Flagging** and hit the ***`Execute`*** mode.

If both Rules Conditions are satisfied, then the node you selected will be marked as flagged by the user you specified.

So please do some QA-testing of this variation of your rule. And make sure to select accurate testcase (different from your own userid, aka `site:current-user`).

And if this QA-testing results in "***... it still does nothing ...***", then perform appropriate Rules debugging, as explained in my answer to "How can I display the value of a variable inside a condition?".

Move on to **Step 2** after your QA-testing is completed (and you're sure the rule works as designed).

# Step 2: Let VBO do the bulk of the work

This step is pretty easy ... Just create an appropriate view of all your **nodes** to be processed, and transform it into a Views Bulk Operations view. The clue to what you want VBO to do as an operation is ... you guessed it: **Execute the Rules Component from Step 1**.

If you're not familiar with how to do so, have a look at the video about Using Rules components with VBO". If you want even more, then also watch the subsequent "Using Rules components with more than one parameter" video.

**Attention**: to process many nodes at once is quite a challenge (memory requirements, etc). Therefor you might want to also watch the video about "More details about VBO settings" ... Before you are tempted to use VBO for processing them all at once ...

Happy VBO-ing while Rules-ing!
> 1 votes

---
Tags: views, rules, organic-groups, flags
---


title: Possible Ways to Style a View (Block)

text:
# Question
Title: Possible Ways to Style a View (Block)
What are the possible ways one can style a View (Block) in Drupal 7? I have a View outputting to a Block on a Drupal 7 site that has custom styles which I need to copy; however, I cant seem to find where they are located.

# Answer
> 1 votes
The possible ways are:

1) using a CSS file, ex: **style.css** (located in your `/sites/all/themes/YOURTHEME/css` folder)

```
.block { border: solid red; }

```

2) using jQuery, ex: **style.js** (located in your `/sites/all/themes/YOURTHEME/js` folder)

```
$('.block').css({"border":"solid red"});

```

3) using a template file, ex: **block.tpl.php** or **view.tpl.php** (located in your theme's `/sites/all/themes/YOURTHEME/template` folder)

```
<style>
.block { border: solid red; }
</style>

```

4) **Inside the view**, if they add a **header or footer** of `text area` or `unfiltered text` and then put inside the header/footer:

```
<style>
.block { border: solid red; }
</style>

```

or

```
<script src="myScript.js"></script>

```

5) Using the CSS Injector module

6) Using the JS Injector module

---
Tags: 7, views, blocks
---


title: Pagination for inline entity form

text:
# Question
Title: Pagination for inline entity form
I'm using Drupal 8 and have question about Inline Entity Form module.

Is it possible to introduce pagination in inline entity form module somehow?

Ideally, I'm looking for already available solution, but I'm fine if I will have to extend the module for this. But I'm not sure how it can be done.

Any pointers and help would be much appreciated.

# Answer
I'm not ruling out mystery module that I am unaware of, but I can give some insight.

The first obvious choice is the API, just reference the hooks in : `/modules/contrib/inline_entity_form/inline_entity_form.api.php`

You can also add a FieldWidget in your module like: `YOUR_MODULE/src/Plugin/Field/FieldWidget/IEFPagination.php`, then you would select it under `Manage Form Display`.

```
namespace Drupal\YOUR_MODULE\Plugin\Field\FieldWidget;

use Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormComplex;

/**
 *
 * @FieldWidget(
 *   id = "ief_paginated",
 *   label = @Translation("IEF - Paginated"),
 *   field_types = {
 *     "entity_reference"
 *   },
 *   multiple_values = true
 * )
 */

class IEFPagination extends InlineEntityFormComplex {

 public function formElement(\Drupal\Core\Field\FieldItemListInterface $items, $delta, array $element, array &$form, \Drupal\Core\Form\FormStateInterface $form_state) {

    $element = parent::formElement($items, $delta, $element, $form, $form_state);

    /* Adjust element here */

    return $element;
}

 public static function buildEntityFormActions($element) {

    $element = parent::buildEntityFormActions($element);

    /* Or here */

    return $element;
 }

```
> 0 votes

---
Tags: 8, entities
---


# Question
Title: Crumbs is not showing parent of taxonomy term
I’m using Drupal 7.5.2 and am attempting to use the Crumbs module (version 7x-2.5) to show parent and child paths in the breadcrumbs trail and it’s not working.

My URL alias structure—which I am attempting to recreate in the breadcrumbs—is as follows:

* **My Great Node Pile:** A view page that is neither taxonomy term or a node.
* **Category:** A view page that is connected to the parent taxonomy term.
* **Category Child:** A view page that is connected to the child taxonomy term.
* **Node:** The node associated within that parent category and child category.

Only one category—child or parent category—can be associated to a node at any given time.

My “Entity Parent” settings for all node content types is as follows; note all content is based in the path of `my-great-node-pile/` which is a stand-alone view that is simply the “home base” for this stuff; it is neither a taxonomy term parent item or a child item:

```
my-great-node-pile/[node:field_category:parent]/[node:field_category]

```

So if I have a node that resides in the aliased area of “My Great Node Pile” titled “Cool Stuff” that has this parent/child taxonomy term URL structure; using Pathauto for that so do not take this pseudeo-example 100% literally:

```
my-great-node-pile/field-category/field-category-child/cool-stuff

```

Then I would expect my breadcrumb trail to be this:

```
My Great Node » Category » Category Child » Cool Stuff

```

But with the default Crumbs settings, this is the bizarre breadcrumb trail I am getting:

```
My Great Node » Category Child » My Great Node » Cool Stuff

```

What? If the entity parent is `[node:field_category:parent]/[node:field_category]` then why is it apprarently rendering as `[node:field_category]/My Great Node`?

***Example Note:*** *The names of items here—including tokens—are neutralized to protect anonymity of the project, but I assure you all tokens and examples here are proven to have the values they should have via the output of the Devel (version 7.x-1.5) module.*

# Answer
> 0 votes
After spending more time than I wanted to to dealing with this—exploring solutions and Googling seemingly forever—I came across this post on the official Drupal site titled “Crumbs not working” and specifically this answer from ‘donquixote’ which states:

> * are these system paths or node aliases? If they are node aliases, do you have the "path" plugin enabled? (\*)

Okay, so that seems like an idea. So I went into the Crumbs settings area under “Structure \> Crumbs” and dragged the `path` setting—which describes itself as “Chop off the last fragment of the path alias, consider the result as the parent path.”—from “Disabled by default” to the second position of “Enabled” (see attached screenshot), hit “Save configuration” and… et voilà… It works! Parent and child taxonomy terms are being rendered in the breadcrumb path as expected.

# Answer
> 0 votes
One important thing to notice is that Crumbs trail-finding works recursively.

Every rule in "Entity parent" or in the main plugin configuration page is only there to specify the direct parent page.

The rest of the trail, like the grandparent, grand-grandparent etc are determined via recursion.

## About your example

> My “Entity Parent” settings for all node content types is as follows; note all content is based in the path of my-great-node-pile/:
>
> `my-great-node-pile/[node:category:parent]/[node:category]`

I suspect that the token string does not work.

First, `[node:category]` should probably be something like `[node:field_category]` if you are using a taxonomy term reference field.

Secondly, I recommend to specify the system path of the node's category, not the alias: `taxonomy/term/[node:field-category:1:tid]`. Notice the `-` instead of `_`. This is just how tokens work, apparently.

Thirdly, what you really should do instead, is use the already-existing plugin for `taxonomy.termReference.field_categories.node.*`.

## Proposed solution

On admin/structure/crumbs:

First, enable the `taxonomy.termReference.field_categories.node.*` (replace field\_categories with the field name of your choice). This tells Crumbs that the parent page of a node should be the category.

Then, enable `taxonomy.termParent.*` or leave it in the "Inherit" section. This tells Crumbs that the parent page for a category should be the parent category.

Finally, go to `admin/structure/crumbs/entity-parent/taxonomy-term` and set `my-great-node-pile` as the parent path for categories.

## Alternative I: The "path" plugin.

If you sure that your aliases are all perfect, you could simply work with the "path" plugin alone, as you already proposed.

If you do this, you can remove the "Entity parent" token strings.

But beware that this requires your aliases are all working correctly. E.g. if for some reason you have one node with the wrong alias, then your breadcrumbs will break down for this node.

## Alternative II: "Easy breadcrumb" module

Basically, Easy breadcrumb is equivalent to Crumbs with ONLY the "path" plugin.

If you are sure your aliases are perfect, and you are not interested in any of the other functionality in Crumbs, then Easy breadcrumb can be for you.

It does not give you the deep recursion like Crumbs. E.g. if you visit a node/123 which has an alias, and then go to node/123/edit, which does not have an alias, then Crumbs will preserve the beginning of the breadcrumb, while with Easy breadcrumb you will lose most of the breadcrumb on the node edit page.

## Troubleshooting: Crumbs "Debug" tab

Notice that the "Debug" tab is there for a reason..

---
Tags: 7, taxonomy-terms, breadcrumbs
---


# Question
Title: Varnish selective clearing not happening
I am using:

* NginX 1.10.2
* Varnish 4.1
* Drupal 7 with the following modules
    + Expire (Set to external.)
    + Varnish (Set to selective.)
    + Purge (Set to 127.0.0.1:80.)

The settings.php file contains the following lines.

```
// Configuration when using varnish and expire module (selective mode)
$conf['cache_backends'][] = 'sites/all/modules/varnish/varnish.cache.inc';
$conf['cache_class_external_varnish_page'] = 'VarnishCache'; // This allows manual flushing of the cache
$conf['cache_class_cache_page'] = 'DrupalFakeCache';  // Turn off drupal page caching (varnish handles this!)
$conf['cache_lifetime'] = 0;
//$conf['page_cache_maximum_age'] = 21600;  // 6  hours
//$conf['page_cache_invoke_hooks'] = FALSE;

```

The output of `varnishadm -T 127.0.0.1:6082 -S /etc/varnish/secret ban.list` is the following.

```
Present bans:
1480690623.867808    21 -  req.http.host ~ metalfans.dev && req.url ~ ^/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit$
1480690623.867018     0 -  req.http.host ~ metalfans.dev && req.url ~ ^/node/1723$|^/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit$
1480690623.825829     0 -  req.http.host ~ metalfans.dev && req.url ~ ^/$|^/frontpage$|^/metalnieuws$|^/node/1723$|^/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit$
1480690118.323817    29 -  req.http.host ~ metalfans.dev && req.url ~ ^/$|^/frontpage$|^/metalnieuws$|^/node/1722$|^/nieuws/1722/zoveel-kost-graspop-metal-meeting-2017$

```

The VCL file contains the following lines.

```
    # This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition.  Set this to point to your content
# server.
#
vcl 4.0;

backend default {
  .host = "127.0.0.1";
  .port = "8282";
}

acl purge {
  "localhost";
  "127.0.0.1";
}
# handles redirecting from http to https
sub vcl_synth {
  if (resp.status == 750) {
    set resp.status = 301;
    set resp.http.Location = req.http.x-redir;
    return(deliver);
  }
}

sub vcl_recv {
 # Do not cache these paths.
  if (req.url ~ "^/status\.php$" ||
      req.url ~ "^/update\.php" ||
      req.url ~ "^/install\.php" ||
      req.url ~ "^/apc\.php$" ||
      req.url ~ "^/admin" ||
      req.url ~ "^/admin/.*$" ||
      req.url ~ "^/user" ||
      req.url ~ "^/user/.*$" ||
      req.url ~ "^/users/.*$" ||
      req.url ~ "^/info/.*$" ||
      req.url ~ "^/flag/.*$" ||
      req.url ~ "^.*/ajax/.*$" ||
      req.url ~ "^.*/ahah/.*$" ||
      req.url ~ "^/system/files/.*$") {

    return (pass);
  }

if ( (req.http.host ~ "^(?i)metalfans.dev|test.be") && req.http.X-Forwarded-Proto !~ "(?i)https") {
  set req.http.x-redir = "https://" + req.http.host + req.url;
  return (synth(750, ""));
}

  # Always cache the following file types for all users. This list of extensions
  # appears twice, once here and again in vcl_fetch so make sure you edit both
  # and keep them equal.
  if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
    unset req.http.Cookie;
  }

  # Remove all cookies that Drupal doesn't need to know about. We explicitly
  # list the ones that Drupal does need, the SESS and NO_CACHE. If, after
  # running this code we find that either of these two cookies remains, we
  # will pass as the page cannot be cached.
  if (req.http.Cookie) {
    # 1. Append a semi-colon to the front of the cookie string.
    # 2. Remove all spaces that appear after semi-colons.
    # 3. Match the cookies we want to keep, adding the space we removed
    #    previously back. (\1) is first matching group in the regsuball.
    # 4. Remove all other cookies, identifying them by the fact that they have
    #    no space after the preceding semi-colon.
    # 5. Remove all spaces and semi-colons from the beginning and end of the
    #    cookie string.
    set req.http.Cookie = ";" + req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]+|SSESS[a-z0-9]+|wcf_cookieHash=[a-z0-9]+|wcf_userID=[a-z0-9]+|NO_CACHE)=", "; \1=");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      # If there are no remaining cookies, remove the cookie header. If there
      # aren't any cookie headers, Varnish's default behavior will be to cache
      # the page.
      unset req.http.Cookie;
    }
    else {
      # If there is any cookies left (a session or NO_CACHE cookie), do not
      # cache the page. Pass it on to Apache directly.
      return (pass);
    }
  }
}

sub vcl_deliver {
        if (obj.hits > 0) {
                set resp.http.X-Cache = "HIT";
        } else {
                set resp.http.X-Cache = "MISS";
        }
}
sub vcl_recv {
# Check the incoming request type is "PURGE", not "GET" or "POST".
  if (req.method == "PURGE") {
    # Check if the IP is allowed.
    if (!client.ip ~ purge) {
      # Return error code 405 (Forbidden) when not.
      return (synth(405, "Not allowed."));
    }
    return (purge);
  }
}

```

The other related issue I found is Configuring Varnish for Drupal with Proper Module Usage (Expiration Cache, Varnish, Purge, Memcache).

Yet, the page age doesn't change at all until the TTL has expired, which is set to about 5 minutes, while the minimum cache is set to "0"/none.

The watchdogs logs shows that the clearing is happening, so it must be on the Varnish side NginX doesn't do full page caching.

This is the Varnish/Drupal log.

```
    Varnish log:
*   << BeReq    >> 360553
    -   Begin          bereq 360552 pass
    -   Timestamp      Start: 1480696516.686305 0.000000 0.000000
    -   BereqMethod    POST
    -   BereqURL       /node/1723/edit?content_lock_token=i7EJ9zBOgYFwoo3oJo0Q2-8vJcxXIQHAS6rF_wpwu6w
    -   BereqProtocol  HTTP/1.0
    -   BereqHeader    X-Forwarded-Host: metalfans.dev
    -   BereqHeader    X-Real-IP: 192.168.0.142
    -   BereqHeader    X-Forwarded-Proto: https
    -   BereqHeader    X-Forwarded-Port: 443
    -   BereqHeader    X-Secure: on
    -   BereqHeader    Host: 127.0.0.1
    -   BereqHeader    Content-Length: 21671
    -   BereqHeader    user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
    -   BereqHeader    accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    -   BereqHeader    accept-language: en-US,en;q=0.5
    -   BereqHeader    accept-encoding: gzip, deflate, br
    -   BereqHeader    referer: https://metalfans.dev/node/1723/edit?content_lock_token=i7EJ9zBOgYFwoo3oJo0Q2-8vJcxXIQHAS6rF_wpwu6w
    -   BereqHeader    upgrade-insecure-requests: 1
    -   BereqHeader    content-type: application/x-www-form-urlencoded
    -   BereqHeader    X-Forwarded-For: 192.168.0.142, 127.0.0.1
    -   BereqHeader    Cookie: SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   BereqHeader    X-Varnish: 360553
    -   VCL_call       BACKEND_FETCH
    -   VCL_return     fetch
    -   BackendOpen    24 861794af-024b-4385-9de4-2bffb4c51725.default 127.0.0.1 8282 127.0.0.1 45761
    -   BackendStart   127.0.0.1 8282
    -   Timestamp      Bereq: 1480696516.686349 0.000044 0.000044
    -   Timestamp      Beresp: 1480696518.436420 1.750116 1.750072
    -   BerespProtocol HTTP/1.1
    -   BerespStatus   302
    -   BerespReason   Moved Temporarily
    -   BerespHeader   Server: nginx
    -   BerespHeader   Date: Fri, 02 Dec 2016 16:35:18 GMT
    -   BerespHeader   Content-Type: text/html; charset=UTF-8
    -   BerespHeader   Connection: close
    -   BerespHeader   Expires: Sun, 19 Nov 1978 05:00:00 GMT
    -   BerespHeader   Cache-Control: no-cache, must-revalidate
    -   BerespHeader   X-Content-Type-Options: nosniff
    -   BerespHeader   Location: https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit
    -   TTL            RFC 0 10 -1 1480696518 1480696518 1480696518 280299600 0
    -   VCL_call       BACKEND_RESPONSE
    -   TTL            VCL 120 10 0 1480696518
    -   VCL_return     deliver
    -   Storage        malloc Transient
    -   ObjProtocol    HTTP/1.1
    -   ObjStatus      302
    -   ObjReason      Moved Temporarily
    -   ObjHeader      Server: nginx
    -   ObjHeader      Date: Fri, 02 Dec 2016 16:35:18 GMT
    -   ObjHeader      Content-Type: text/html; charset=UTF-8
    -   ObjHeader      Expires: Sun, 19 Nov 1978 05:00:00 GMT
    -   ObjHeader      Cache-Control: no-cache, must-revalidate
    -   ObjHeader      X-Content-Type-Options: nosniff
    -   ObjHeader      Location: https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit
    -   Fetch_Body     4 eof stream
    -   BackendClose   24 861794af-024b-4385-9de4-2bffb4c51725.default
    -   Timestamp      BerespBody: 1480696518.436477 1.750172 0.000056
    -   Length         0
    -   BereqAcct      911 21671 22582 354 0 354
    -   End

    *   << Request  >> 360552
    -   Begin          req 360551 rxreq
    -   Timestamp      Start: 1480696516.686255 0.000000 0.000000
    -   Timestamp      Req: 1480696516.686255 0.000000 0.000000
    -   ReqStart       127.0.0.1 44983
    -   ReqMethod      POST
    -   ReqURL         /node/1723/edit?content_lock_token=i7EJ9zBOgYFwoo3oJo0Q2-8vJcxXIQHAS6rF_wpwu6w
    -   ReqProtocol    HTTP/1.0
    -   ReqHeader      X-Forwarded-For: 192.168.0.142
    -   ReqHeader      X-Forwarded-Host: metalfans.dev
    -   ReqHeader      X-Real-IP: 192.168.0.142
    -   ReqHeader      X-Forwarded-Proto: https
    -   ReqHeader      X-Forwarded-Port: 443
    -   ReqHeader      X-Secure: on
    -   ReqHeader      Host: 127.0.0.1
    -   ReqHeader      Connection: close
    -   ReqHeader      Content-Length: 21671
    -   ReqHeader      user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
    -   ReqHeader      accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    -   ReqHeader      accept-language: en-US,en;q=0.5
    -   ReqHeader      accept-encoding: gzip, deflate, br
    -   ReqHeader      referer: https://metalfans.dev/node/1723/edit?content_lock_token=i7EJ9zBOgYFwoo3oJo0Q2-8vJcxXIQHAS6rF_wpwu6w
    -   ReqHeader      upgrade-insecure-requests: 1
    -   ReqHeader      content-type: application/x-www-form-urlencoded
    -   ReqHeader      cookie: _ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIta
    -   ReqUnset       X-Forwarded-For: 192.168.0.142
    -   ReqHeader      X-Forwarded-For: 192.168.0.142, 127.0.0.1
    -   VCL_call       RECV
    -   ReqUnset       cookie: _ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIta
    -   ReqHeader      Cookie: ;_ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIt
    -   ReqUnset       Cookie: ;_ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIt
    -   ReqHeader      Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew;SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA;SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS
    -   ReqUnset       Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew;SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA;SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS
    -   ReqHeader      Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDi
    -   ReqUnset       Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDi
    -   ReqHeader      Cookie: ; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   ReqUnset       Cookie: ; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   ReqHeader      Cookie: SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   VCL_return     pass
    -   VCL_call       HASH
    -   VCL_return     lookup
    -   VCL_call       PASS
    -   VCL_return     fetch
    -   Link           bereq 360553 pass
    -   Timestamp      ReqBody: 1480696516.686347 0.000091 0.000091
    -   Timestamp      Fetch: 1480696518.436485 1.750230 1.750139
    -   RespProtocol   HTTP/1.1
    -   RespStatus     302
    -   RespReason     Moved Temporarily
    -   RespHeader     Server: nginx
    -   RespHeader     Date: Fri, 02 Dec 2016 16:35:18 GMT
    -   RespHeader     Content-Type: text/html; charset=UTF-8
    -   RespHeader     Expires: Sun, 19 Nov 1978 05:00:00 GMT
    -   RespHeader     Cache-Control: no-cache, must-revalidate
    -   RespHeader     X-Content-Type-Options: nosniff
    -   RespHeader     Location: https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit
    -   RespHeader     X-Varnish: 360552
    -   RespHeader     Age: 0
    -   RespHeader     Via: 1.1 varnish-v4
    -   VCL_call       DELIVER
    -   RespHeader     X-Cache: MISS
    -   VCL_return     deliver
    -   Timestamp      Process: 1480696518.436498 1.750243 0.000013
    -   RespHeader     Content-Length: 0
    -   Debug          "RES_MODE 2"
    -   RespHeader     Connection: close
    -   Timestamp      Resp: 1480696518.436509 1.750254 0.000011
    -   ReqAcct        1032 21671 22703 436 0 436
    -   End

    *   << Session  >> 360551
    -   Begin          sess 0 HTTP/1
    -   SessOpen       127.0.0.1 44983 :80 127.0.0.1 80 1480696516.686237 20
    -   Link           req 360552 rxreq
    -   SessClose      RESP_CLOSE 1.750
    -   End

    *   << BeReq    >> 163863
    -   Begin          bereq 163862 pass
    -   Timestamp      Start: 1480696518.438621 0.000000 0.000000
    -   BereqMethod    GET
    -   BereqURL       /nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit
    -   BereqProtocol  HTTP/1.0
    -   BereqHeader    X-Forwarded-Host: metalfans.dev
    -   BereqHeader    X-Real-IP: 192.168.0.142
    -   BereqHeader    X-Forwarded-Proto: https
    -   BereqHeader    X-Forwarded-Port: 443
    -   BereqHeader    X-Secure: on
    -   BereqHeader    Host: 127.0.0.1
    -   BereqHeader    user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
    -   BereqHeader    accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    -   BereqHeader    accept-language: en-US,en;q=0.5
    -   BereqHeader    accept-encoding: gzip, deflate, br
    -   BereqHeader    referer: https://metalfans.dev/node/1723/edit?content_lock_token=i7EJ9zBOgYFwoo3oJo0Q2-8vJcxXIQHAS6rF_wpwu6w
    -   BereqHeader    upgrade-insecure-requests: 1
    -   BereqHeader    X-Forwarded-For: 192.168.0.142, 127.0.0.1
    -   BereqHeader    Cookie: SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   BereqHeader    X-Varnish: 163863
    -   VCL_call       BACKEND_FETCH
    -   VCL_return     fetch
    -   BackendOpen    24 861794af-024b-4385-9de4-2bffb4c51725.default 127.0.0.1 8282 127.0.0.1 45766
    -   BackendStart   127.0.0.1 8282
    -   Timestamp      Bereq: 1480696518.438658 0.000038 0.000038
    -   Timestamp      Beresp: 1480696519.142807 0.704186 0.704149
    -   BerespProtocol HTTP/1.1
    -   BerespStatus   200
    -   BerespReason   OK
    -   BerespHeader   Server: nginx
    -   BerespHeader   Date: Fri, 02 Dec 2016 16:35:19 GMT
    -   BerespHeader   Content-Type: text/html; charset=utf-8
    -   BerespHeader   Connection: close
    -   BerespHeader   Vary: Accept-Encoding
    -   BerespHeader   Expires: Sun, 19 Nov 1978 05:00:00 GMT
    -   BerespHeader   Cache-Control: no-cache, must-revalidate
    -   BerespHeader   X-Content-Type-Options: nosniff
    -   BerespHeader   Content-Language: nl
    -   BerespHeader   X-Frame-Options: SAMEORIGIN
    -   BerespHeader   X-Generator: Drupal 7 (http://drupal.org)
    -   BerespHeader   Link: ,,,,,,<https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit?amp>; rel="amphtml",<https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit>; rel="canonical",<https://metalfans.dev/node/1723>; r
    -   BerespHeader   Content-Encoding: gzip
    -   TTL            RFC 0 10 -1 1480696519 1480696519 1480696519 280299600 0
    -   VCL_call       BACKEND_RESPONSE
    -   TTL            VCL 120 10 0 1480696519
    -   VCL_return     deliver
    -   Storage        malloc Transient
    -   ObjProtocol    HTTP/1.1
    -   ObjStatus      200
    -   ObjReason      OK
    -   ObjHeader      Server: nginx
    -   ObjHeader      Date: Fri, 02 Dec 2016 16:35:19 GMT
    -   ObjHeader      Content-Type: text/html; charset=utf-8
    -   ObjHeader      Vary: Accept-Encoding
    -   ObjHeader      Expires: Sun, 19 Nov 1978 05:00:00 GMT
    -   ObjHeader      Cache-Control: no-cache, must-revalidate
    -   ObjHeader      X-Content-Type-Options: nosniff
    -   ObjHeader      Content-Language: nl
    -   ObjHeader      X-Frame-Options: SAMEORIGIN
    -   ObjHeader      X-Generator: Drupal 7 (http://drupal.org)
    -   ObjHeader      Link: ,,,,,,<https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit?amp>; rel="amphtml",<https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit>; rel="canonical",<https://metalfans.dev/node/1723>; r
    -   ObjHeader      Content-Encoding: gzip
    -   Fetch_Body     4 eof stream
    -   Gzip           u F - 50512 302363 80 212767 404025
    -   BackendClose   24 861794af-024b-4385-9de4-2bffb4c51725.default
    -   Timestamp      BerespBody: 1480696519.180351 0.741730 0.037544
    -   Length         50512
    -   BereqAcct      821 0 821 790 50512 51302
    -   End

    *   << Request  >> 163862
    -   Begin          req 163861 rxreq
    -   Timestamp      Start: 1480696518.438582 0.000000 0.000000
    -   Timestamp      Req: 1480696518.438582 0.000000 0.000000
    -   ReqStart       127.0.0.1 44988
    -   ReqMethod      GET
    -   ReqURL         /nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit
    -   ReqProtocol    HTTP/1.0
    -   ReqHeader      X-Forwarded-For: 192.168.0.142
    -   ReqHeader      X-Forwarded-Host: metalfans.dev
    -   ReqHeader      X-Real-IP: 192.168.0.142
    -   ReqHeader      X-Forwarded-Proto: https
    -   ReqHeader      X-Forwarded-Port: 443
    -   ReqHeader      X-Secure: on
    -   ReqHeader      Host: 127.0.0.1
    -   ReqHeader      Connection: close
    -   ReqHeader      user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
    -   ReqHeader      accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    -   ReqHeader      accept-language: en-US,en;q=0.5
    -   ReqHeader      accept-encoding: gzip, deflate, br
    -   ReqHeader      referer: https://metalfans.dev/node/1723/edit?content_lock_token=i7EJ9zBOgYFwoo3oJo0Q2-8vJcxXIQHAS6rF_wpwu6w
    -   ReqHeader      upgrade-insecure-requests: 1
    -   ReqHeader      cookie: _ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIta
    -   ReqUnset       X-Forwarded-For: 192.168.0.142
    -   ReqHeader      X-Forwarded-For: 192.168.0.142, 127.0.0.1
    -   VCL_call       RECV
    -   ReqUnset       cookie: _ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIta
    -   ReqHeader      Cookie: ;_ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIt
    -   ReqUnset       Cookie: ;_ga=GA1.2.2139442399.1477560769; Drupal.tableDrag.showWeight=0; DRUPAL_UID=1; DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoIt
    -   ReqHeader      Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew;SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA;SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS
    -   ReqUnset       Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew;SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA;SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS
    -   ReqHeader      Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDi
    -   ReqUnset       Cookie: ;_ga=GA1.2.2139442399.1477560769;Drupal.tableDrag.showWeight=0;DRUPAL_UID=1;DrupalModuleFilter=activeTab%3Dnew; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDi
    -   ReqHeader      Cookie: ; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   ReqUnset       Cookie: ; SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   ReqHeader      Cookie: SSESS66c4e60279a94b947645ab1ea38c2c77=IFnE4CiYlSSuvwUqH9PVCeMxat9fc-gllYz3uWNyuTA; SESS66c4e60279a94b947645ab1ea38c2c77=YwcVtmCMoItaDicS4uGJKlilsFiybrpJ-lxhsIC48vs
    -   VCL_return     pass
    -   VCL_call       HASH
    -   VCL_return     lookup
    -   VCL_call       PASS
    -   VCL_return     fetch
    -   Link           bereq 163863 pass
    -   Timestamp      Fetch: 1480696519.142865 0.704283 0.704283
    -   RespProtocol   HTTP/1.1
    -   RespStatus     200
    -   RespReason     OK
    -   RespHeader     Server: nginx
    -   RespHeader     Date: Fri, 02 Dec 2016 16:35:19 GMT
    -   RespHeader     Content-Type: text/html; charset=utf-8
    -   RespHeader     Vary: Accept-Encoding
    -   RespHeader     Expires: Sun, 19 Nov 1978 05:00:00 GMT
    -   RespHeader     Cache-Control: no-cache, must-revalidate
    -   RespHeader     X-Content-Type-Options: nosniff
    -   RespHeader     Content-Language: nl
    -   RespHeader     X-Frame-Options: SAMEORIGIN
    -   RespHeader     X-Generator: Drupal 7 (http://drupal.org)
    -   RespHeader     Link: ,,,,,,<https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit?amp>; rel="amphtml",<https://metalfans.dev/nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit>; rel="canonical",<https://metalfans.dev/node/1723>; r
    -   RespHeader     Content-Encoding: gzip
    -   RespHeader     X-Varnish: 163862
    -   RespHeader     Age: 0
    -   RespHeader     Via: 1.1 varnish-v4
    -   VCL_call       DELIVER
    -   RespHeader     X-Cache: MISS
    -   VCL_return     deliver
    -   Timestamp      Process: 1480696519.142896 0.704314 0.000031
    -   RespHeader     Accept-Ranges: bytes
    -   Debug          "RES_MODE 4"
    -   RespHeader     Connection: close
    -   Timestamp      Resp: 1480696519.180378 0.741796 0.037482
    -   ReqAcct        942 0 942 875 50512 51387
    -   End

    *   << Session  >> 163861
    -   Begin          sess 0 HTTP/1
    -   SessOpen       127.0.0.1 44988 :80 127.0.0.1 80 1480696518.438567 21
    -   Link           req 163862 rxreq
    -   SessClose      RESP_CLOSE 0.742
    -   End
----------------------------------------------------------------------------------------
Drupal expire log:
    Expiration was executed for the next URLs:

        URL:
        Wildcard: false
        Expired object: node
        --------
        URL: frontpage
        Wildcard: false
        Expired object: node
        --------
        URL: node/1533
        Wildcard: false
        Expired object: node
        --------
        URL: metalfestivals/hellfest-open-air-2017
        Wildcard: false
        Expired object: node
        --------
        URL: metalnieuws
        Wildcard: false
        Expired object: node
        --------
        URL: node/1723
        Wildcard: false
        Expired object: node
        --------
        URL: nieuws/1723/de-eerste-namen-voor-hellfest-2017-zijn-een-feit
        Wildcard: false
        Expired object: node
        --------

```

# Answer
I found the problem. It seems that my self singed certificate causses issues for curl and since purge uses curl, it just can't make the connection because its not secure.

If you come across this issue use the following command:

> curl --insecure -X PURGE https://domain.tld/myurltopurge/

Ad the following code in default.vcl:

```
sub vcl_hit {
        if (req.method == "PURGE") {
                return (synth(200, "Purged."));
        }
}

sub vcl_miss {
        if (req.method == "PURGE") {
                return (synth(200, "OK but nothing to purge - URL was not in cache"));
        }
}

```

The output should be like this:

```
    <!DOCTYPE html>
<html>
  <head>
    <title>200 Purged</title>
  </head>
  <body>
    <h1>Error 200 Purged</h1>
    <p>Purged</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 98477</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>

```

Doing this does clear the cache..
> 0 votes

---
Tags: 7, caching, proxies
---


# Question
Title: Views_view_result and Devel possible incompatibility
I have experienced a very strange behaviour of Drupal 7. I had Devel module activated, and a View which made the sql logs to disappear from screen. The view was used by `views_get_view_result()`. When I have changed the exact code to use `views_embed_view()`, with the same and exact rendering, the SQL logs started to appear again.

Is there some Drupal 7 expert (ninja level suspected) out there that can understand what could happen? The bug was consistent, it always happened in the same View config (I replicated different Views with different names and the behaviour always appeared at the same point).

The configuration that caused the problem was:

* Field collection
* View with field collection
* Contextual filter (here it started to ignore sql log output)
* Call to the function views\_view\_result. Even the call itself, without using the value, caused the problem.

Solution: Call `views_view_embed()` instead. No problem anymore. Same contextual filters, and blocks used. Exact configuration and exact output than `views_view_result()`.

*Note:* I need an explanation of why this is happening, and a possible solution. The output of the SQL logging is not sent to the HTML source output of the page.

Code used. The commented lines do not work, and are substituted by the non-commented lines above them. The function is supossed to return an integer.

```
 function sacar_numero_productos($id_categorias, $marca){
     $marca = str_replace("/", "", $marca);
     $a = views_embed_view("numero_productos", "block_1", $id_categorias, $marca);
    // LINE BELOW DOES WORK BUT DESTROYS THE OUPUT OF SQL QUERIES
    //$a = views_get_view_result("numero_productos", "block_1", $id_categorias, $marca);

return (int)(trim(strip_tags($a)));

   // IF I USE views_get_view_result, this is the return value instead.
   /*if(isset($a[0]->field_data_field_id_unico_oem_field_id_unico_oem_value) && (int)$a[0]->field_data_field_id_unico_oem_field_id_unico_oem_value > 0){
       return (int)$a[0]->field_data_field_id_unico_oem_field_id_unico_oem_value;
    } // if*/
    return 0;
} // function

```

# Answer
The short answer: Devel is not incompatible with Views.

The longer answer:

The difference between `views_embed_view` and `views_get_view_result` is essentially that `views_embed_view` renders the view while `views_get_view_result` only executes it. The code for the two processes are almost identical, but the difference is that `views_embed_view` does more as part of the render process. You can see the details in `view::render`.

The gist of it is that when embedding the view, you get views to do a lot more things, like initializing the theme, invoking more hooks.

Best guess for where your problem lies would be some other module integrating with views and/or devel or some other details you haven't written in your question.

The devel query log works by using the core database log, starting it with hook\_boot and getting the info with a shutdown function. There are some scenarios where devel will be silent, fx when doing redirects. There is a good chance, that the issue is related to how devel figures out when to be silent or not. It's near impossible to figure out the exact cause without being able to debug your exact site and configuration as any module / configuration can be the cause to what you are seeing. If you want to investigate you should look into

* `devel_silent()`
* `devel_shutdown()`
* `devel_shutdown_real()`
> 4 votes

# Answer
Sometimes query log arguments and explain functionality do not work on pages generated by a view because some elements returned by `Database::getLog` (used internally by devel) contain very complex objects in caller arguments; This causes silent failure in `json_encode` (used to serialize the query logs data) due 'Recursion detected' error, so no data is written to devel query log files nor shown on the screen.

The issue should be solved in SQL query log doesn't work on pages generated by a view. Try to use the latest devel -dev version and see if the issue still occurs
> 2 votes

---
Tags: 7, views, debugging
---


title: The right form to work with pages

text:
# Question
Title: The right form to work with pages
Reciently, I'm starting to work with Drupal 8, but I have some problems working with main pages. I can create a content type for all pages, but, the fields I use in to create this, must be content all posible options to input in all pages, and, for the final user, this solution can be a little confusing.

For instance, in one page I need to create a field to related another content type, with unlimited inputs, to display in this page. But, in another page, I need another related content type, with only one input.

The same case happenend for static blocks or similar.

Of course, I can create a content type for each diferent pages, but sounds like a horrible solution (I think).

I Acquainted with the suggestion template system, and I use it, but not satisfy this casuistic.

Perhaps, I'm totally wrong with the workflow of drupal and the solution is work totally diferent.

Thank you in advance.

# Answer
> 2 votes
You don't need to create a content type for each different page. You need some tools for site building. I think in your case Paragraphs will be the best solution.

You can for example create different paragraph types with a reference field, one to a content type with one input and one to another content type with unlimited inputs. You can define as many paragraphs types as you want.

Then you put a paragraph field in the page content type and the user can fill this field with the paragraphs he needs to build the content, so that each page can have a different layout.

---
Tags: theming, 8, workflows
---


# Question
Title: How do I keep l() from escaping my link's text?
I'm using Drupal 7's `l()` function in my template as follows:

```
<h3>
  <?php print l(
    $fields['title']->content,
    'node/'.$fields['nid']->content,
    array('attributes' => array())
  ); ?>
</h3>

```

The problem is, this is causing apostrophes in my titles to display at `&#039` instead of an apostrophe. How can I use `l()` properly to keep this from happening?

# Answer
> 2 votes
You could add that option in `l()` function : `array('html'=>true)`.

```
<h3>
  <?php print l(
    $fields['title']->content,
    'node/'.$fields['nid']->content,
    array('html'=>true))
  ); ?>
</h3>

```

Be aware that the escaping serves a purpose: it prevents security problems such as XSS. When you use the `'html'=>true` option, make sure you are passing in safe HTML code.

Better use `decode_entities` plus `strip_tags`, because the former "*could revert previous sanitization efforts*":

```
print l( decode_entities( strip_tags( $fields['title']->content )), 'node/'.$fields['nid']->content );

```

## Edit

As per marcvangend, below examples **shouldn't be necessary**, since Drupal `l()` function takes care of of path aliases and language prefixes.

Try also

```
<h3>
  <?php
    global $language;
    $langcode = $language-> language,
    print l(t($fields['title']->content), '/'. $langcode .'/'. drupal_get_path_alias('node/'.$fields['nid']->content, $langcode ));
  ?>
</h3>

```

Or

```
<h3>
  <?php
    global $language;
    $langcode = $language-> language;
    print '<a href="/' . drupal_get_path_alias('node/'.$fields['nid']->content, $langcode ) . '">'. t($fields['title']->content) .'</a>';
  ?>
</h3>

```

# Answer
> 3 votes
@Kojo's answer is getting a bit crowded and confusing IMHO so let me post my recommended approach here.

---

## 'html' =\> true

The key to the problem is passing the `html` option to the `l()` function like this:

```
<h3>
  <?php print l(
    $fields['title']->content,
    'node/' . $fields['nid']->content,
    array('html' => TRUE)
  ); ?>
</h3>

```

This tells `l()` to bypass the `check_plain()` function which normally escapes the link text.

## Security

Using `'html' => TRUE` is a security risk if you are not sure if the author can be trusted (ie. it is user generated content).

Depending on where the variables in your template come from, `$fields['title']->content` may already have been sanitized. You can test this by setting the title to `<script>alert('hi');</script>`. Load the page. If you see a javascript popup, you have an XSS vulnerability to fix. Fortunately, Drupal has a couple of functions built in for that.

### Solutions for an XSS vulnerability

1. Use `filter_xss()`. A filter that only allows a small selection of HTML tags, fixes invalid markup, and filters out XSS risks. Example:

```
l(filter_xss($unsafe_text), $path, array('html' => TRUE));

```
2. Use `filter_xss_admin()`. This is a very permissive option, like `filter_xss()`, but only recommended to filter content entered by trusted site admins. Example:

```
l(filter_xss_admin($unsafe_text), $path, array('html' => TRUE));

```
3. Use `check_markup()`. This is the most configurable option. It uses one of your configured text formats, such as "filtered html", to filter out all but the whitelisted html tags (it will call `filter_xss()` for you). It will also apply other filters enabled on the text format. Make sure you choose a text format which has the "HTML filter" enabled in its configuration. Example:

```
l(check_markup($unsafe_text), $path, array('html' => TRUE));

```

---
Tags: 7
---


# Question
Title: Services won't authenticate email address used as username
I've installed the Email Registration module because I want my site's users to be able to register an account, and use their email address as their login username. This works great on the web login, however I've built an app to log users into my Drupal site as well using the Services module. When I try and log users in with their email address username, access is denied (whereas when they log in via the website, it authenticates just fine). Any idea why this might be?

# Answer
> 2 votes
The Email Registration module doesn't create any service resource. Also it doesn't change user login resource of the Services module that allows users to login just with their names. I have implemented user email and name login solution with this custom service:

```
  /**
 * Implements hook_services_resources().
 */

function custom_mail_login_services_resources() {
        return array(
   'custom_email_login' => array(

        'actions'=>array (
        'mail_login' => array(
        'callback' => 'get_mail_login',
        'access callback' => 'user_is_anonymous',
        'args' => array(
            array(
            'name' => 'data',
            'optional' => FALSE,
            'source' => 'data',
            'type' => 'array',
            'description' => 'Name or email',
            ),
     ),
    ),
   ),
   ),
  );
}

  function get_mail_login($data) {
  global $user;
  $username = null;
  if ($name = db_query('SELECT name FROM {users} WHERE LOWER(mail) = LOWER(:mail)', array(':mail' => $data['mail']))->fetchField()) {
      $username = $name;
  }elseif ($name = db_query('SELECT name FROM {users} WHERE LOWER(name) = LOWER(:name)', array(':name' => $data['mail']))->fetchField()) {
      $username = $name;
  }else{
        return services_error(t('No user with this email or name exists!'), 403);
 }
 if ($user->uid) {
    // user is already logged in
    return services_error(t('Already logged in as @user.', array('@user' => $user->mail)), 406);
  }

  // Check if account is active.
  if (user_is_blocked($username)) {
    return services_error(t('The user %name has not been activated or is blocked.', array('%name' => $mail)), 403);
  }

  // Emulate drupal native flood control: check for flood condition.
  $flood_state = array();
  if (variable_get('services_flood_control_enabled', TRUE)) {
    $flood_state = _user_resource_flood_control_precheck($username);
  }

  // Only authenticate if a flood condition was not detected.
  if (empty($flood_state['flood_control_triggered'])) {
    $uid = user_authenticate($username, $data['password']);
  }
  else {
    $uid = FALSE;
  }

  // Emulate drupal native flood control: register flood event, and throw error
  // if a flood condition was previously detected
  if (variable_get('services_flood_control_enabled', TRUE)) {
    $flood_state['uid'] = $uid;
    _user_resource_flood_control_postcheck($flood_state);
  }

  if ($uid) {
    $user = user_load($uid);
    if ($user->uid) {
      user_login_finalize();

      $return = new stdClass();
      $return->sessid = session_id();
      $return->session_name = session_name();
      $return->token = drupal_get_token('services');

      $account = clone $user;

      services_remove_user_data($account);

      $return->user = $account;

      return $return;
    }
  }
  watchdog('user', 'Invalid login attempt for %username.', array('%username' => $username));
  return services_error(t('Wrong username/email or password.'), 401);
}

```

You have to put this code into your custom\_mail\_login.module file and add custom\_mail\_login. info file. Module name is custom\_mail\_login. Then enable this module and custom\_email\_login mail\_login resource in admin/structure/services/list/your\_endpoint/resources.

You have to send json request `{"mail":"useremail@address.com", "password":"password"}`. The parameter "mail" is an email or user name.

---
Tags: 7, users
---


title: Theme path in javascript

text:
# Question
Title: Theme path in javascript
I need to use my theme path in a jQuery script for a D8 theme I'm building. I know this is available as drupalSettings.path.baseURL (followed by the path to my theme) but how do you make this variable available to javascript? Lots of D7 info out there, not much D8.

# Answer
> 6 votes
You can attach the drupalSettings in any form / build / preprocess etc.

Something like :

```
function HOOK_preprocess_html(&$variables) {
 $variables['#attached']['drupalSettings']['path']['themeUrl'] = \Drupal::theme()->getActiveTheme()->getPath();
}

```

# Answer
> 4 votes
To make the variables from drupalSettings available in custom javascript code, you have to add `core/drupalSettings` as dependency when you define the library:

**mytheme.libraries.yml**

```
custom-javascript:
  version: 1.x
  js:
    js/custom-javascript.js: {}
  dependencies:
    - core/jquery
    - core/drupalSettings

```

**mytheme.info.yml**:

```
libraries:
  - mytheme/custom-javascript

```

**js/custom-javascript.js**

```
(function ($, drupalSettings) {

  var baseURL = drupalSettings.path.baseURL;

})(jQuery, drupalSettings);

```

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


# Question
Title: How do you create a custom stream wrapper?
I am trying to create a new custom stream wrapper. How can I do that?

# Answer
This is something I have worked on more than a year ago https://gist.github.com/ivanjaros/fcf7ed50fbb98024464a29cfdcb01167 I have written Google Cloud Storage stream wrapper last week which is much better than this but it is a bit different use case(I think that gist is 95% accurate to what I have now). Anyway, you'll need to provide the S3 service to it on your own. I'd suggest to go over the code and maybe get inspired but I wouldn't use it as is.

Also see this issue: https://www.drupal.org/node/2830828
> 2 votes

---
Tags: 8
---


# Question
Title: Include Lead Forensics code in all pages
I'm trying to include the tracking code Lead Forensics gave me. The code is:

```
<script type="text/javascript" src="http://www.path-trail.com/js/11111.js"></script>
<noscript><img src="http://www.path-trail.com/11111.png" style="display:none;" /></noscript>

```

I've tried creating a block with only this in the body, but it doesn't render in the page (when I check the generated code with 'view source code' on the browser, it isn't there). I don't know if it's the correct way to do it. Any idea? Thanks!

# Answer
The better way to do this is by placing the script in the code for the theme.

You may be able to pretend this is another script and use a Drupal module that adds a script to the theme.

An issue you may be having by using a block is that unless you have the right permissions and also are careful to preserve this code as source, Drupal may try to alter what you enter for security or because you don't have permission to add a script.

We are a user/partner of Drupal and LeadForensics.
> 0 votes

---
Tags: 7, javascript
---