title: How to include remote web page

text:
# Question
Title: How to include remote web page
I have a simple problem but can't find a simple solution. I want to include remote (dynamically created) web page into Drupal generated page. Previously i used PHP filter module in Drupal, so i would write something like readfile("remoteURL") in CKeditor and that worked fine. Now, i'm searching for something more elegant and more secure but i just can't find it. Anybody knows? Thx.

Regards.

# Answer
> 0 votes
Add a preprocess hook to your theme and parse the DOM of the external page for the HTML you want to include:

*mytheme.theme*

```
use Drupal\Component\Utility\Html;

/**
 * Implements hook_preprocess_HOOK() for node templates.
 */
function mytheme_preprocess_node(&$variables) {
  $url = 'www.example.com';
  $response = \Drupal::httpClient()->get($url);
  $dom = Html::load((string) $response->getBody());
  $xpath = new \DOMXPath($dom);
  $nodes = $xpath->query('/html/body/div');
  foreach ($nodes as $node) {
    $external_content = $dom->saveHTML($node);
    $variables['content']['external'][] = ['#markup' => $external_content];
  }
}

```

---
Tags: 9
---


# Question
Title: is it possible to make use of data stored using the user.data service ifor filtering views?
Allowing a user to bookmark a node i have created

```
 public function bookmark($nid,$uid) {
    $user_data = \Drupal::service('user.data');
    $bookmarked_nodes = $user_data->get('my_module', $uid, 'bookmark');
    $bookmarked_nodes[$nid] = $nid;
    $user_data->set('my_module', $uid, 'bookmark', $bookmarked_nodes);
    \Drupal::messenger()->addStatus(t('node bookmarked.'));
  }

```

i would like then to create a view listing only nodes that has been bookmarked by the current user.

Is it possible ?

# Answer
> 1 votes
Better use the Flag module for a more robust bookmarking solution. Allows you to record a "flag" made by user (in this case, a bookmark) and has a ready-to-use Views integration to filter flags and relate the both user and the flagged entity.

---
Tags: views
---


title: Get taxonomy and check if published?

text:
# Question
Title: Get taxonomy and check if published?
I am trying to display taxonomy programitcally. The problem is, all taxonomy is displayed whther published all not. How can I filter only published taxonomy.

I use this code to get taxonomy.

```
$tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree(
  'vocabulary_name',
  0,
  1,
  TRUE
);

$results = [];

foreach ($tree as $term) {
  $results[] = $term->getName();
}

```

Can I add a filter like status-\>1, or status = pubished?

# Answer
> 1 votes
`TermStorage::loadTree()` is just a fancy way to load term entities. The first mode is a "quick mode" that skims data from `taxonomy_term_data`. The second mode is just a regular `loadMultiple()` that loads full entities using the IDs from the quick mode. Since you're interested in status data, you will be loading full entities instead of the quick mode.

Since you already have hold of the term storage service, you can just use `loadByProperties()`. Filter against the `vid`, `status`, and `parent` properties.

```
$terms = \Drupal::entityTypeManager()
    ->getStorage('taxonomy_term')
    ->loadByProperties([
      'vid' => 'vocabulary_name',
      'parent' => 0,
      'status' => 1,
    ])

```

---
Tags: taxonomy-terms
---


# Question
Title: How do I include a taxonomy term in exposed combine fields filter?
I am building a view with an exposed combine fields filter that needs to include a taxonomy vocabulary.

I have completed the below steps but the filter does not return any results when a taxonomy term is entered.

1. Added a relationship to the specific taxonomy term field (field\_research: Taxonomy Term)
2. Added a new field based on the relationship created for the taxonomy term (field\_research: Taxonomy Term) Taxonomy term:Vocabulary with formatter 'Label'. When displaying the new field in the view, terms do not appear - just the vocabulary name.
3. In 'Global: Combine fields filter', selected new field for 'fields to combine for filtering'

# Answer
> 0 votes
When you want to really add the label of the vocabulary you need to add the vocabulary as an additional relationship. Then you add the label field of the vocabulary to your combined filter.

What you have actually done is adding the reference field from the term to the vocabulary to the combined filter. You may choose a formatter showing you the label but the filter only has the value from the reference field which is in database - and this simply is the id of the vocabulary. The combined filter cannot use the formatter result but only the value of the field in database.

# Answer
> 0 votes
I found the answer here:

https://www.drupal.org/forum/support/post-installation/2012-10-10/combine-fields-filter-and-taxonomy#comment-6943886

> Try adding a relationship to the term reference field.
>
> Then add a "Taxonomy term: Name " field using the relationship you just created. Set it to hidden if you like. Then include this new field in your "Combine fields filter".

---
Tags: views
---


# Question
Title: Module template for a comment field is not triggering comment_preprocess_field
I have a custom module in which I am trying to override a comment field's template in Drupal 9.3.

In my module file I have defined the hook\_theme to override the core template in use. (*comment.html.twig*), which works, but it is not triggering the *comment\_preprocess\_field* hook in *comment.module* which then assigns the comment variables to the template.

My module file hook\_theme is:

```
function MODULE_theme() {
  return [
    'field__field_FIELD_NAME' => [
      'base_hook' => 'field',
    ]
  ];
}

```

This works and my custom template is displayed, but it is missing the comments variables passed from *comment\_preprocess\_field*.

If I place the template in my theme, the *comment\_preprocess\_field* hook runs and the variables are added to the template, but not when done from a custom module.

Does anyone know how to get the hook *comment\_preprocess\_field* to run when overriding a comment field template in a module?

# Answer
> 1 votes
Use `base hook`, instead of `base_hook` (no underscore):

```
function MODULE_theme() {
  return [
    'field__field_FIELD_NAME' => [
      'base hook' => 'field',
    ]
  ];
}

```

That should invoke the preprocess as normal. You'll need to rebuild caches after making the change.

---
Tags: hooks, comments
---


# Question
Title: How to display translated fields labels of a node view
I would like to display a node in NL. This node is not translatable but I would like to have the fields labels translated in NL.

This rendering occurs in a cron job and is used to render an email in the recipient language (ex: NL).

Unfortunately, the following code output the labels in the current language of the page (if I run it outside the cron) or in the default language of the site from within the cron job

```
$entity = Drupal\node\Entity\Node::load($nid);
$view_builder = Drupal::entityTypeManager()->getViewBuilder($entity->getEntityTypeId());
$summary = $view_builder->view($entity, 'summary', 'nl');
$render=Drupal::service('renderer')
->renderPlain($summary);
dpm($render);

```

**Solutions I have already tested:**

1-I have tried the solution which set the config override language to the desired language here without luck

2-I have also tried the solution which set a custom language negotiator here without success

3-Finally I have tried the solution which use the 'language' session parameter here without any result

I have traced the code and I think that the language is selected/choose in the render part... But it was really difficult to understand this due to the complexity.

I was also thinking to add a `'#langcode'` to the build but I couldn't find an example.

# Answer
To display translated field labels you need to add solution 1 to the code you have already and also clear the cached field definitions, which unfortunately don't cache per config language.

The complete code should look like this:

```
$language_manager = \Drupal::languageManager();

$nid = 1;
$langcode = 'nl';
$language = $language_manager->getLanguage($langcode);

$original_language = $language_manager->getConfigOverrideLanguage();
$language_manager->setConfigOverrideLanguage($language);
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
drupal_static_reset('options_allowed_values');

$entity = Node::load($nid);
$view_builder = \Drupal::entityTypeManager()->getViewBuilder($entity->getEntityTypeId());
$summary = $view_builder->view($entity, 'summary', $langcode);
$render = \Drupal::service('renderer')
  ->renderPlain($summary);

$language_manager->setConfigOverrideLanguage($original_language);
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();

```
> 3 votes

---
Tags: i18n-l10n
---


# Question
Title: Sub request doesn't take care of the language
I have defined a route as follow:

```
mymodule.node_summary:
  path: '/node/{node}/summary'
  options:
    parameters:
      node:
        type: 'entity:node'
  defaults:
    _controller: '\Drupal\mymodule\Controller\NodeSummaryController::content'
    _title: 'Summary'
  requirements:
    node: \d+
    _entity_access: 'node.view'

```

Then I have created the following controller:

```
class NodeSummaryController {

  public function content(Node $node = NULL) {
    $view_builder = Drupal::entityTypeManager()
      ->getViewBuilder('node');
    $summary = $view_builder->view($node, 'summary');
    $render = Drupal::service('renderer')
      ->renderPlain($summary);
    $response = new Response($render);
    return $response;
  }
}

```

If I visit the page `/nl/node/xxx/summary` everything is fine, my node's summary is displayed in dutch

But if I try to get this content with a sub-request, I get the result in the default language of my site, not in dutch

```
  $kernel = \Drupal::service('http_kernel.basic');
  $sub_request = \Symfony\Component\HttpFoundation\Request::create("/nl/node/xxx/summary");
  $response = $kernel->handle($sub_request, \Symfony\Component\HttpKernel\HttpKernelInterface::SUB_REQUEST);
  $html = $response->getContent();
  dpm($html); // ERROR THIS IS NOT IN DUTCH

```

# Answer
I was a bit overly optimistic in the previous question suggesting a sub-request. The language manager service doesn't store data in such a way that it can run within a sub-request scope. So it seems you need to do the same as in the previous question, only that now the interface translation works without a custom negotiator by resetting the language manager (and also the string translation service, see the comment) before running the sub-request:

```
$language_manager = \Drupal::languageManager();

$langcode = 'nl';
$language = $language_manager->getLanguage($langcode);
$original_language = $language_manager->getConfigOverrideLanguage();
$language_manager->reset();
\Drupal::service('string_translation')->setDefaultLangcode($langcode);
$language_manager->setConfigOverrideLanguage($language);
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();

$kernel = \Drupal::service('http_kernel.basic');
$sub_request = \Symfony\Component\HttpFoundation\Request::create('/' . $langcode . '/node/1/summary');
$response = $kernel->handle($sub_request, \Symfony\Component\HttpKernel\HttpKernelInterface::SUB_REQUEST);

$language_manager->reset();
$current_language = $language_manager->getCurrentLanguage();
\Drupal::service('string_translation')->setDefaultLangcode($current_language->getId());
$language_manager->setConfigOverrideLanguage($original_language);
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();

$html = $response->getContent();

```
> 2 votes

---
Tags: http-request
---


# Question
Title: page not found after restoring from the backup except home page (Tried all solutions, which I got through googling)?
I restored my site from the backup taken from another computer. Another drupal site is working fine in my machine, but this site which I restored from a backup is not working fine.

I am able to see the home page, front page but not any other pages of this restored site. when I click on links displaying 404 error (page not found).

When it is working for some other site, it has to work for other also. But I am missing some site specific configurations.

could any body please help me in this regard

# Answer
Looks like you have lost your .htaccess in the process. Download newest Drupal core from Drupal.org, extract it and put .htaccess in the root directoy of your Drupal. If this still does not work, and your .htaccess is ignored, go to official Clean URLs documentation, and find a section **Server configuration for Clean URLs on a dedicated server, with httpd.conf** \- this should show you how to configure it properly.
> 1 votes

# Answer
I tried in this way, I gone to mysite.com/index.php?q=admin/config/search/clean-urls

I turned off clean urls.. My site working now...!
> 0 votes

# Answer
Hello its all about Clean URL enable to your site, so just got to

**?q=admin/config/search/clean-urls**

and turned off clean url

your issue will be sort out
> 0 votes

# Answer
Check Apache config. Maybe this config is missing

\<Directory /var/www/\> Options Indexes FollowSymLinks AllowOverride None Require all granted
> 0 votes

---
Tags: migrations, backups
---


title: Perform an LDAP search from a module

text:
# Question
Title: Perform an LDAP search from a module
I am trying to perform an LDAP search from `hook_form_validation()` in a webform using Drupal 9 and drupal/ldap 4.3.

I have configured the LDAP module on my site, but I am not using it for authentication. I can however use ldap query and perform a test of the ldap server on /admin/config/people/ldap/server successfully.

At the bottom of API usage they say you can use the following code.

```
$factory = \Drupal::service('ldap.servers');
$server = $factory->getServerByIdEnabled('my_server');

```

I have been enlightend cliefen that the service is ldap.bridge. Here is my current code.

```
use Drupal\user\Entity\User;
use Drupal\taxonomy\Entity\Term;
use Drupal\ldap_servers\Entity\Server;

function drp_form_alter( &$form, &$form_state, $form_id ) {
  if ( $form_id === 'webform_submission__myform_node_5930_add_form' ) {
    $userid = \Drupal::currentUser()->id();
    $username = \Drupal::currentUser()->getAccountName();
    $server = \Drupal::service('entity_type.manager')->getStorage( 'ldap_server')->load('myserver');
    $bridge = \Drupal::service('ldap.bridge');
    $bridge->setServer( $server );
    if ($bridge->bind()) {

        // $dn ='ou=accounts,ou=departments,dc=servername,dc=someplace';
        // $filter="(uid=xxxx1)";
        // $returnattr = array( "sn", "givenname", "mail");

    }
  }

}

```

I was able to successfully bind the ldap server.

Question: how do I actually make an ldap search, using the drupal/ldap code, inside the bridge-\>bind if statement?

I did not use the $factory-\> code that the API mentioned. Do I need to?

Thanks for all your help, I am struggling, but learning :)

# Answer
I think there's just a couple of calls missing, or at least the following works for me:

```
if ($bridge->bind()) {
    $ldap = $bridge->get() ;
    $options = [] ;
    $entries = $ldap
        ->query('', "(&(objectclass=groupOfNames)(member=$user_dn))", $options)
        ->execute()
        ->toArray() ;
}

```

(The query is irrelevant, of course – it comes straight from my code).
> 1 votes

---
Tags: webforms, 9
---


# Question
Title: How to remove a css file from an already-overridden definition?
I want to create a custom theme and remove a css file from diretory **themes/stable/css/filter.caption.css** from Stable theme. I found this file in **stable.info.yml**

```
libraries-override:
  filter/caption:
    css:
      component:
          css/filter.caption.css: css/filter/filter.caption.css

```

From **my\_custom.info.yml**

```
libraries-override:
  filter/caption:
    css:
      component:
        css/filter.caption.css: false

```

or

```
libraries-override:
  filter/caption:
    css:
      component:
        css/filter/filter.caption.css: false

```

I tried that way but it is not work to remove a css file **themes/statble/css/filter.caption.css**.

# Answer
In **stable.info.yml** we have

```
libraries-override:
  filter/caption:
     css:
       component:
         css/filter.caption.css: css/filter/filter.caption.css

```

So **my\_theme.info.yml** to disable it could be:

```
libraries-override:
  filter/caption:
    css:
      component:
        /themes/contrib/stable/css/filter/filter.caption.css: false

```

A bug in libraries-override makes it difficult to override a library or library asset that has already been overridden. See https://www.drupal.org/project/drupal/issues/2642122#comment-11830072 for more information.
> 4 votes

---
Tags: theming, 10
---


# Question
Title: PHPUnit throws error: \Drupal\Tests\DocumentElement class not found
I have added some phpunit tests to my custom module. When trying to run them in I get this error: `Class '\Drupal\Tests\DocumentElement' not found` I have copied core/phpunit.xml.dist to core/phpunit.xml and edited the URL and DB values but nothing else.

The command I'm running is `vendor/bin/phpunit -c web/core/phpunit.xml web/modules/contrib/my_module/`.

It seems that the classloader is not working. What have I missed?

I'm using drupal 9 and phpunit 9. I've also tried with phpunit 7 and 8 but I get the same error.

# Answer
> 7 votes
Finally got to the bottom of this! The package drupal/core-dev is required.

```
composer require --dev drupal/core-dev

```

This installs the package as a development dependency.

# Answer
> -1 votes
Drupal forgot to add few dependency libraries.

See you have these 2 libraries.

```
composer show symfony/phpunit-bridge
composer show phpspec/prophecy-phpunit

```

If you don't please install.

I also noticed that following library also essential.

```
behat/mink

```

---
Tags: 9, testing
---


# Question
Title: How do I get the product item author id from the order object?
I have a website, where users can add their products. After a user purchases a product and pays for it, I want to create some custom logic. I need to know the authors of the individual items purchased. After following this guide I have the below EventSubscriber code

```
public function orderCompleteHandler(WorkflowTransitionEvent $event) {
  $order = $event->getEntity();
  $items = $order->getItems();

  foreach($items as $item){
    error_log($item->getTotalPrice()->getNumber());
    // Here I want to get the item's author
  }
}

```

*(Please disregard the error\_log function as it is only for developing purposes)*

It works as expected and lists the prices (one-by-one) of the items purchased. Now I want to list the authors of the items as well. Unfortunately there is no built in method to get the authors. I was thinking to go in the direction of getting the order item as an entity and then getting the entity author that way. Any suggestions how to do this? or any other suggested approaches?

# Answer
> 1 votes
The point is, the order items (purchased entities) are not products, but product variations. You need first to get product object as the parent of a variation and then you can call the `getOwner()` method as suggested by *@Jaypan* to get user object.

You can do all this stuff by one simple line inside your loop as below

```
foreach($items as $item) {
    $userObj = $item->getPurchasedEntity()->getProduct()->getOwner();
}

```

# Answer
> 0 votes
As per the discussion above with @Jaypan Commerce order doesn't implement the EntityOwnerInterface so I made a pretty ugly workaround, that I'm posting, so it might help others, but please only use this if you know what you are doing.

```
public function orderCompleteHandler(WorkflowTransitionEvent $event) {
$order = $event->getEntity();
$items = $order->getItems();

foreach ($items as $item) {
  $item_id = $item->getPurchasedEntityId();
  $database = \Drupal::database();
  $query = $database->query("SELECT * FROM commerce_product_field_data WHERE product_id = :product_id", [
    ':product_id' => $item_id,
  ]);
  $result = $query->fetchAssoc();
  $author_id = $result['uid'];
}

```

---
Tags: commerce, event-subscribers
---


# Question
Title: How to alter pagination url of embedded view programmatically?
I m trying to send mail which contain some data along with embedded view result programmatically. This mail is trigger on submit of webform. Webform ajax property is enable. Due to which it send incorrect url.

Used below code

```
$view = Views::getView($viewID);
$view->initDisplay();
.....
$vars['result_table'] = $view->buildRenderable('email', $contetxtualFilter);

```

In twig file

```
{{ result_table }}

```

Here output of first page is send in mail correctly but the pagination link has incorrect url.

Ex of incorrect pagination link of Page 1 is - "?\_wrapper\_format=drupal\_ajax&ajax\_form=1&page=0"
Ex of correct pagination link of Page 1 is - "www.test.com/productone?page=0"

Do you have any idea, how can I send correct pagination link in email without turning off webform ajax property. So that when user click on pagination in mail he is redirect to specific page.

# Answer
> 0 votes
It seems that the incorrect pagination link is being generated due to the \_wrapper\_format and ajax\_form query parameters being added to the URL. These query parameters are used by Drupal to render views using AJAX, but they should not be included in a regular URL.

To fix this issue, you can try setting the use\_ajax option to false when building the renderable array:

```
$vars['result_table'] = $view->buildRenderable('email', $contetxtualFilter, null, ['use_ajax' => false]);

```

This should generate the correct pagination links in the email.

---
Tags: views, 9
---


# Question
Title: Index.php prompts to download instead of executing
I am running into a issue where I am trying to load up my Drupal site, but instead of going to the main page, it instead prompts to download / save the file.

I know that my PHP is active and I can't seem to figure out what the issue is. I have looked around googling but none of the suggestions there have helped. Has anyone else run into this issue? I am using Drupal 7.

apache config file:

```
<IfModule mime_module>
    #
    # TypesConfig points to the file containing the list of mappings from
    # filename extension to MIME-type.
    #
    TypesConfig conf/mime.types

    #
    # AddType allows you to add to or override the MIME configuration
    # file specified in TypesConfig for specific file types.
    #
    #AddType application/x-gzip .tgz
    #
    # AddEncoding allows you to have certain browsers uncompress
    # information on the fly. Note: Not all browsers support this.
    #
    AddEncoding x-compress .Z
    AddEncoding x-gzip .gz .tgz
    #
    # If the AddEncoding directives above are commented-out, then you
    # probably should define those extensions to indicate media types:
    #
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz
    AddType application/x-httpd-php .php
    AddType application/x-httpd-php .php3

    #
    # AddHandler allows you to map certain file extensions to "handlers":
    # actions unrelated to filetype. These can be either built into the server
    # or added with the Action directive (see below)
    #
    # To use CGI scripts outside of ScriptAliased directories:
    # (You will also need to add "ExecCGI" to the "Options" directive.)
    #
    #AddHandler cgi-script .cgi

    # For type maps (negotiated resources):
    #AddHandler type-map var

    #
    # Filters allow you to process content before it is sent to the client.
    #
    # To parse .shtml files for server-side includes (SSI):
    # (You will also need to add "Includes" to the "Options" directive.)
    #
    #AddType text/html .shtml
    #AddOutputFilter INCLUDES .shtml
</IfModule>

```

.htaccess file:

```
#
# Apache/PHP/Drupal settings:
#

# Protect files and directories from prying eyes.
<FilesMatch "\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\..*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock))$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig\.save)$">
  Order allow,deny
</FilesMatch>

# Don't show directory listings for URLs which map to a directory.
Options -Indexes

# Follow symbolic links in this directory.
Options +FollowSymLinks

# Make Drupal handle any 404 errors.
ErrorDocument 404 /index.php

# Set the default handler.
DirectoryIndex index.php index.html index.htm

# Override PHP settings that cannot be changed at runtime. See
# sites/default/default.settings.php and drupal_environment_initialize() in
# includes/bootstrap.inc for settings that can be changed at runtime.

# PHP 5, Apache 1 and 2.
<IfModule mod_php5.c>
  php_flag magic_quotes_gpc                 off
  php_flag magic_quotes_sybase              off
  php_flag register_globals                 off
  php_flag session.auto_start               off
  php_value mbstring.http_input             pass
  php_value mbstring.http_output            pass
  php_flag mbstring.encoding_translation    off
</IfModule>

# Requires mod_expires to be enabled.
<IfModule mod_expires.c>
  # Enable expirations.
  ExpiresActive On

  # Cache all files for 2 weeks after access (A).
  ExpiresDefault A1209600

  <FilesMatch \.php$>
    # Do not allow PHP scripts to be cached unless they explicitly send cache
    # headers themselves. Otherwise all scripts would have to overwrite the
    # headers set by mod_expires if they want another caching behavior. This may
    # fail if an error occurs early in the bootstrap process, and it may cause
    # problems if a non-Drupal PHP file is installed in a subdirectory.
    ExpiresActive Off
  </FilesMatch>
</IfModule>

# Various rewrite rules.
<IfModule mod_rewrite.c>
  RewriteEngine on

  # Set "protossl" to "s" if we were accessed via https://.  This is used later
  # if you enable "www." stripping or enforcement, in order to ensure that
  # you don't bounce between http and https.
  RewriteRule ^ - [E=protossl]
  RewriteCond %{HTTPS} on
  RewriteRule ^ - [E=protossl:s]

  # Make sure Authorization HTTP header is available to PHP
  # even when running as CGI or FastCGI.
  RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

  # Block access to "hidden" directories whose names begin with a period. This
  # includes directories used by version control systems such as Subversion or
  # Git to store control files. Files whose names begin with a period, as well
  # as the control files used by CVS, are protected by the FilesMatch directive
  # above.
  #
  # NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
  # not possible to block access to entire directories from .htaccess, because
  # <DirectoryMatch> is not allowed here.
  #
  # If you do not have mod_rewrite installed, you should remove these
  # directories from your webroot or otherwise protect them from being
  # downloaded.
  RewriteRule "(^|/)\." - [F]

  # If your site can be accessed both with and without the 'www.' prefix, you
  # can use one of the following settings to redirect users to your preferred
  # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
  #
  # To redirect all users to access the site WITH the 'www.' prefix,
  # (http://example.com/... will be redirected to http://www.example.com/...)
  # uncomment the following:
  # RewriteCond %{HTTP_HOST} .
  # RewriteCond %{HTTP_HOST} !^www\. [NC]
  # RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
  #
  # To redirect all users to access the site WITHOUT the 'www.' prefix,
  # (http://www.example.com/... will be redirected to http://example.com/...)
  # uncomment the following:
  # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
  # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]

  # Modify the RewriteBase if you are using Drupal in a subdirectory or in a
  # VirtualDocumentRoot and the rewrite rules are not working properly.
  # For example if your site is at http://example.com/drupal uncomment and
  # modify the following line:
   RewriteBase /drupal
  #
  # If your site is running in a VirtualDocumentRoot at http://example.com/,
  # uncomment the following line:
   RewriteBase /

  # Pass all requests not referring directly to files in the filesystem to
  # index.php. Clean URLs are handled in drupal_environment_initialize().
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !=/favicon.ico
  RewriteRule ^ index.php [L]

  # Rules to correctly serve gzip compressed CSS and JS files.
  # Requires both mod_rewrite and mod_headers to be enabled.
  <IfModule mod_headers.c>
    # Serve gzip compressed CSS files if they exist and the client accepts gzip.
    RewriteCond %{HTTP:Accept-encoding} gzip
    RewriteCond %{REQUEST_FILENAME}\.gz -s
    RewriteRule ^(.*)\.css $1\.css\.gz [QSA]

    # Serve gzip compressed JS files if they exist and the client accepts gzip.
    RewriteCond %{HTTP:Accept-encoding} gzip
    RewriteCond %{REQUEST_FILENAME}\.gz -s
    RewriteRule ^(.*)\.js $1\.js\.gz [QSA]

    # Serve correct content types, and prevent mod_deflate double gzip.
    RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1]
    RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1]

    <FilesMatch "(\.js\.gz|\.css\.gz)$">
      # Serve correct encoding type.
      Header set Content-Encoding gzip
      # Force proxies to cache gzipped & non-gzipped css/js files separately.
      Header append Vary Accept-Encoding
    </FilesMatch>
  </IfModule>
</IfModule>

# Add headers to all responses.
<IfModule mod_headers.c>
  # Disable content sniffing, since it's an attack vector.
  Header always set X-Content-Type-Options nosniff
</IfModule>

```

# Answer
> 1 votes
I have fixed the issue.

In my httpd config file, there is a section called

```
<Directory />
AllowOverride none
</Directory>

```

When I turned this on, this is what prompted to download the php files instead of executing them.

```
<Directory />
AllowOverride All
</Directory>

```

With no success, I turned it back off to `none`. However, I went to my vhosts config file instead, and there too, they also have a directory tag. It did not have AllowOveride in it, so I decided to add it.

```
<Directory "c:/wamp64/vhosts/mysite">
    AllowOverride All
    Order Allow,Deny
    Allow from All
    Require local
</Directory>

```

This fixed the issue for me and now clean URL's is working perfectly. Hope it helps to someone in the future!!!

# Answer
> 0 votes
I have a Drupal installation over an Apache server configured with MAMP.

Deleting the **.htaccess** file in the root folder of my Drupal installation worked for me.

---
Tags: .htaccess
---


# Question
Title: How to have Views Attachment show all results of View, including the ones on the next pager pages
We have a Drupal 9 View using a GeoField Map to display the results using an attachment. The problem is that we want the map to show all the results, not just the ones on the first page.

Currently, we have the pager set to 25 items per page so the map only shows those 25 instead of all of the results.

In addition to this, the map attachment is then replaced on the next page with the results from the next page.

# Answer
Attachment Views Display has several options that let you control its pagination in relation to the Display it is attached to.

Under **Attachment settings** make sure that the **Inherit contextual filters:** and **Inherit exposed filters:** are set to values that make sense in your case.

If you're using Contextual or regular Filters on your original (Page) Display, and you want the Attachment (Map) to always show all results no matter what, then those two options should be set to **No**.

This will make the map results independent from any narrowing down of the results that you or your users may apply on the Page (for example if you have Exposed Filters).

Then you can adjust **Pager** settings to be different from the original Display.

Under **Pager** settings on the Attachment Display opt to **Inherit pager: No**, and **override** the setting **Items to display:** to **Display all items** so it's different from the one you're using on the original Display (Page).
> 0 votes

---
Tags: views
---


# Question
Title: Paragraphs field preprocess hook not called
To simplify this issue, I just have 2 hooks:

```
1. customtheme_preprocess_paragraph__registration_button()
2. customtheme_preprocess_paragraph__registration_button__default()

```

When I access a node with a registration button with a default view mode, only the first hook is called. Also, when I access the `$variables['view_mode']` in that hook, it gives the value 'default'.

Furthermore, it only takes the paragraph--registration-button.html.twig as template, but not paragraph--registration-button--default.html.twig

I am using Drupal Core 9.5.4 and Paragraphs 1.15.0. Could this be something in my setup?

# Answer
This can be closed, it was a custom setup.
> 0 votes

---
Tags: 9, paragraphs
---


# Question
Title: What is the purpose of drush entity-updates?
After updating Drupal 8 modules, I have been warned on the Drupal 8 status page that:

> Entity/field definitions: The following changes were detected in the entity type and field definitions.

After a bit of Google rummaging, it seems the solution to this is to run `drush entity-updates`. However I find this a bit strange as it seems to be another command that one needs to remember or incorporate into one's workflow after updating the database, not to mention it didn't seem immediately obvious about how to address the original warning.

What's more, it's often the case that in development you'll have an alert for other actions in the Status page which will mean you won't immediately know if you need to action this.

Can anybody explain what is this warning is for - or rather, why has this feature been introduced into D8, and why isn't it factored into the database update operation but must be run seperately?

# Answer
> 19 votes
`drush entity-updates` is a developer tool. If you change entity/field definitions in your custom module you can quickly apply this.

In production this should not happen. If you update a module between official releases, then the update code in the module should handle this.

But in your case you are mentioning that your site is in developing. So there are a lot of things, which could have caused this. Either in your own code or in dev or alpha versions of contrib modules.

I found this example from the CR *Write update functions for entity schema updates, automation removed* (where there are further examples):

```
/**
 * Add 'revision_translation_affected' field to 'node' entities.
 */
function node_update_8001() {
  // Install the definition that this field had in
  // \Drupal\node\Entity\Node::baseFieldDefinitions()
  // at the time that this update function was written. If/when code is
  // deployed that changes that definition, the corresponding module must
  // implement an update function that invokes
  // \Drupal::entityDefinitionUpdateManager()->updateFieldStorageDefinition()
  // with the new definition.
  $storage_definition = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Revision translation affected'))
      ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
      ->setReadOnly(TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('revision_translation_affected', 'node', 'node', $storage_definition);
}

```

# Answer
> 1 votes
Command "drush entity-updates" has been removed from v 8.7.0

See https://www.drupal.org/node/3034742

> Starting with 8.7.0, Drupal core no longer provides support for automatic entity updates. Whenever an entity type or field storage definition needs to be created, changed or deleted, it has to be done with an explicit update function as provided by the Update API, and using the API provided by the entity definition update manager.

# Answer
> 0 votes
There is a contrib module that takes the place of the original command.

You can install it with

```
composer require drupal/devel_entity_updates

```

Enable it with

```
drush en devel_entity_updates

```

and run it with

```
drush entup

```

https://www.drupal.org/project/devel\_entity\_updates

---
Tags: 8, entities, drush, updating
---


# Question
Title: Migrate into paragraphs without parent import
If I have a data source with some values, can I process those into a paragraph attached to a node in Drupal 8 without having to run a prior migration to create the paragraphs first (and then relying on a migration\_lookup)?

Would I need some kind of process plugin (like Import Json data into node uses) or can this be done out of the box with simple generic sub-process/mapping config in the YML?

# Answer
> 1 votes
It doesn't look possible Out of the Box without another import. You could try with a contributed module like: https://www.drupal.org/project/migrate\_child\_entity\_generate

---
Tags: 8, migrations, paragraphs
---


# Question
Title: Contextual links in block disabled when using Twig Tweak and UUID
In my taxonomy-term--NAME.html.twig I use a reference field to load a 'block\_content'.

```
{% for item in term.field_blocks %}
  {% set uuid =  item.entity.uuid.value %}
  {{ drupal_block('block_content:' ~ uuid) }}
{% endfor %}

```

The block is rendered correctly but without the 'contextual links' (quick edit on front-end).

When I look into the twig\_tweak module, I see you can add an array with configuration options.

```
public function drupalBlock($id, array $configuration = [], $wrapper = TRUE) {

    $configuration += ['label_display' => BlockPluginInterface::BLOCK_LABEL_VISIBLE];

    /** @var \Drupal\Core\Block\BlockPluginInterface $block_plugin */
    $block_plugin = \Drupal::service('plugin.manager.block')
      ->createInstance($id, $configuration);
    ...
}

```

Does anyone know how I can change the twig-rule to something like this:

```
{{ drupal_block('block_content:' ~ uuid, {show_contextual_links:true}) }}

```

I found this question, but that is not correct: Programatically render block with contextual links (in php)

# Answer
> 1 votes
I was able to do it like this:

```
<div data-quickedit-entity-id="block_content/1008" class="contextual-region" data-once="quickedit" data-quickedit-entity-instance-id="0">
  {{ drupal_contextual_links('block_content:block_content=1008:langcode:') }}
  {{ drupal_entity('block_content', 1008) }}
</div>

```

# Answer
> 1 votes
When you use `{{ drupal_entity('block_content', 'content_block_id') }}`, Drupal skips the block template, which contains the code for contextual links. If you use `{{ drupal_block('plugin_id') }}`, it will apply the block template, including title, links and other attributes.

If you look at the default block template in Classy (block.html.twig):

```
{%
  set classes = [
    'block',
    'block-' ~ configuration.provider|clean_class,
    'block-' ~ plugin_id|clean_class,
  ]
%}
<div{{ attributes.addClass(classes) }}>
  {{ title_prefix }}
  {% if label %}
    <h2{{ title_attributes }}>{{ label }}</h2>
  {% endif %}
  {{ title_suffix }}
  {% block content %}
    {{ content }}
  {% endblock %}
</div>

```

The `{{ title_suffix }}` part contains the code that renders the contextual links.

---
Tags: 8, theming, blocks
---


title: How to upload .webp to Image field?

text:
# Question
Title: How to upload .webp to Image field?
https://www.drupal.org/project/imagewebp lets you upload a regular jpg/png which converts it into webp, but how to upload already a file that is in webp?

Adding it as one of allowed extensions in the field setting does not work.

**update** As an alternative this can be solved with https://www.drupal.org/project/file\_entity, but this is for the file field and not image field.

The question is about image field. Because in production site that already has image field in use with many images and pages active, it needs .webp extension support added to already existing image field.

# Answer
> 2 votes
Drupal Core 7 does not yet support WebP but there are reportedly working patches on this in-progress issue: https://www.drupal.org/project/drupal/issues/3179554.

---
Tags: 7, files
---


# Question
Title: Use AJAX On Node Add Form To Change Field Required Status
On a node/add form I have a pair of fields that need to be able to control one another. The first field allows a user to enter a birthdate, the second field allows the user to say the birthdate is unknown.

I have attempted to work with Conditional Fields to make this work but I think for my case AJAX would be better.

If the birthdate\_unkown field is **not** checked then the birthdate field should be required. When the birthdate\_unkown field is checked then I would like to be able to make it so that the field is no longer required.

I have a working AJAX callback function I just cannot figure out how to use AJAX to change if the field is required or not.

I have tried options like:

```
$response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','attr',['required', false]));

```

or

```
$response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','removeAttr',['required']));

```

I have this code in a function that looks like this:

```
function _custom_field_unknown_birthday_logic(&$form, FormStateInterface $form_state) {
    \Drupal::logger('custom')->error('Unknown Birthday Callback');
    $values = $form_state->getValues();
    $unknown_birthdate = $values['field_unknown_birthdate']['value'];
    \Drupal::logger('custom')->error('Unknown Birthday Callback Value '. $unknown_birthdate);

    $response = new AjaxResponse();
    if ($unknown_birthdate == false) {
        $response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','attr',['required']));
        \Drupal::logger('custom')->error('Birthdate IS required');
    } else if ($unknown_birthdate == true) {
        $response->addCommand(new InvokeCommand('edit-field-birthdate-0-value-date','removeAttr',['required'] ));
        \Drupal::logger('custom')->error('Birthdate IS NOT required');
    } else {
        \Drupal::logger('custom')->error('No Change to Birthdate');
    }
    return $response;
}

```

With the extensive logging I am doing I can see that I am getting to the right places in the code to issue the AJAX commands. That said the AJAX commands do not appear to change anything. I do not see anything in the console for Dev Tools either.

Any help on figuring out how to do this with AJAX is greatly appreciated. Once I get this working with AJAX there is more that needs to be accomplished that will not work with just States API.

Thanks!

# Answer
> 1 votes
Changes to the form must be made in the form definition, and cannot be made in the ajax callback, as Drupal has already cached the form by the point of the ajax callback, so even if you figured out a way to remove the required attribute on the field in the ajax callback, Drupal would reject a missing value as the form cache from before the ajax callback will still have the form field marked as required.

Instead, in your *form definition* (not the #ajax callback), you likely want some version of this:

```
if ($form_state->getValue('field_unknown_birthdate')) {
  unset($form['field_birthday_value']['widget']['#required']);
}

```

Note that I am guessing the location of the `#required` key, as well as the field names, so you'll have to inspect the actual `$form` object to determine the array in which the `#required` key is set, and unset it.

---
Tags: nodes, javascript, ajax
---


# Question
Title: How can I redirect node page for a content type to custom URL?
I need to redirect all the pages for a content type to a custom URL in Drupal 8.

I used to do this in Drupal 7 by implementing `hook_init()` with the function `drupal_goto()` or by using the Rules module. Unfortunately both `hook_init()` and `drupal_goto()` are removed in Drupal 8, and the Rules module is not stable yet, and I can't figure out how to do it in Drupal 8.

How can I achieve what I am trying to do?

# Answer
> 13 votes
Here is how I managed to solve this issue, based on the example in drupal.org/node/2013014:

I registered Event Subscriber in my\_redirect\_module.services.yml file:

```
   services:
     my_redirect_module_event_subscriber:
     class: Drupal\hbmsu_redirect\EventSubscriber\MyRedirectModuleSubscriber
     tags:
       - {name: event_subscriber}

```

and then in the file `my_redirect_module/src/EventSubscriber/MyRedirectModuleSubscriber.php`

I added this code:

```
  namespace Drupal\my_redirect_module\EventSubscriber;

  use Symfony\Component\HttpFoundation\RedirectResponse;
  use Symfony\Component\HttpKernel\KernelEvents;
  use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  use Symfony\Component\EventDispatcher\EventSubscriberInterface;

  class MyRedirectModuleSubscriber implements EventSubscriberInterface {

      public function checkForRedirection(GetResponseEvent $event) {

          $baseUrl = $event->getRequest()->getBaseUrl();
          $attr = $event->getRequest()->attributes;
          if(null !== $attr &&
             null !== $attr->get('node') &&
             $attr->get('node')->get('type')->getString() == 'my_content_type') {
              $event->setResponse(new RedirectResponse($baseUrl.'/some_internal_url_path'));
          }
      }

      /**
       * {@inheritdoc}
       */
      static function getSubscribedEvents() {
          $events[KernelEvents::REQUEST][] = array('checkForRedirection');
          return $events;
      }

  }

```

in `checkForRedirection` function, I'm checking if the page is for a node with the content type `my_content_type`, then redirect to the page `mywebsite.com/some_internal_url_path`

# Answer
> 1 votes
If you need to redirect from a custom form or an existing form (login, logout,...)=\> (I assume this is what you want as you ask redirecting from a content type, I think you mean "after editing a content type");

then you can use

```
$form_state->setRedirect('user.page');

```

you can add this code in your form\_alter, form\_submit functions of your content type that you need to redirect

You can find some doc: https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Form!FormSubmitterInterface.php/function/FormSubmitterInterface%3A%3AredirectForm/8.2.x

Like this example:

```
$form_state->setRedirect('entity.node.canonical',
 array('node' => 123),
  array(
    'query' => array(
      'foo' => 'bar',
    ),
    'fragment' => 'baz',
  ),

```

));

# Answer
> 1 votes
You can use Rabbit hole and Token modules. With Rabbit hole you will be able to set a Page Redirect for the content type, and with Token you can choose a field where users will be redirected when they try to access to a node.

# Answer
> 0 votes
You can install Entity Redirect module

That module provides a UI configurable redirect after saving a node or other entity and works for both Drupal 8, 9, 10.

Provides four different types of redirection:

```
Default: This will not impact the entity but will just go to the default.
Add Form: Redirect to a new add form for the content type/entity.
Local Url: provide a local url in the form of /about to go to any page on the site.
External Url: Same as local url but to an external location. Note: this is only available to users with the permission set external entity redirects.

```

. For example for the Node type Article that would be at /admin/structure/types/manage/article, click on Publishing options, you will see a **REDIRECT AFTER ENITY OPERATIONS**

---
Tags: 8, redirection
---


title: Can BigPipe exclude certain blocks?

text:
# Question
Title: Can BigPipe exclude certain blocks?
I've got BigPipe enabled in Drupal 8, and it helps to make pages initially load faster.

However, the header block is always one of the blocks that loads in on a delay, which visually looks bad since the content shifts down afterwards.

Is there any type of preprocess on a block to exclude it from BigPipe not be loaded on a delay, and force it to be in the initial page load?

Many thanks.

# Answer
You can exclude a block from BigPipe by disabling placeholdering in the block build (preprocess is too late).

```
/**
 * Implements hook_block_build_BASE_BLOCK_ID_alter().
 */
function mymodule_block_build_example_block_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
  // Disable placeholdering of this block.
  $build['#create_placeholder'] = FALSE;
}

```

But if this is one of the blocks always having a delay it could make the entire module BigPipe useless.

You can solve the content shift in CSS. Delay or stop the block rendering (in this case you can use preprocess) and fill the gap in the partially loaded page with CSS.

Or make the header block more granular. When all dynamic parts are placeholdered the rest of the block is cacheable and loads with the initial page load.

Example block:

```
  public function build() {

    $build = [];

    $build[] = [
      '#markup' => '<p>Static part of the block, loads with the initial page.</p>',
    ];

    $build[] = [
      '#lazy_builder' => ['\Drupal\mymodule\LazyBuilders::getUser', []],
      '#cache' => ['contexts' => ['user']],
      // contexts user, session or max-age 0 are automatically placeholdered
    ];

    return $build;
  }

```

*/src/LazyBuilders.php:*

```
<?php

namespace Drupal\mymodule;

use Drupal\Core\Render\Element\RenderCallbackInterface;

class LazyBuilders implements RenderCallbackInterface {

  public static function getUser() {
    return [
      '#markup' => \Drupal::currentUser()->getDisplayName(),
    ];
  }

}

```
> 7 votes

# Answer
I could not get 4uk4 solution to work but based on it I was able to

```
use \Drupal\Core\Block\BlockPluginInterface;

function MYMODULE_block_build_alter(array &$build, BlockPluginInterface $block) {
  if ($block->getPluginId() === 'system_menu_block:main') {
    $build['#create_placeholder'] = FALSE;
  }
}

```
> 2 votes

---
Tags: 8, blocks, caching
---


# Question
Title: Display only search box with live search and no content with results
I have configured search API with autocomplete, the search box is exposed in a views block. But the block displays the default 5 results below the search box even if the box is not used yet. I want the search box only to be visible, not the content of the block. But i cant seem to set the number of displayed result to 0. Any idea?

# Answer
> 1 votes
Under **Exposed form** Settings set the **Exposed form style** to **Input required** instead of `Basic`.

This will hold off showing any results until the user interacts with the form.

If the results are showing in the wrong region (for example below the Exposed form, instead of in the main content area) you probably didn't use the correct Block. Make sure your "Exposed form in block:" Setting is set to "Yes" to get a stand-alone Exposed form that can be placed in a different page region from the results.

---
Tags: search, 9
---


title: Field values in node HTML body

text:
# Question
Title: Field values in node HTML body
I am using Drupal 10 and trying to edit the body of a node. I want to use the node field values in the HTML body, for example *\[field\_name\]*, but this does not appear to work as it only shows that specific text and not the actual value of the node. I also have tried *\[field:field\_name\]* with no such luck. Is there any way to do this without having to edit any template file? I have the text format set to 'Full HTML'.

# Answer
It sounds like you need to use tokens. Drupal core has token functionality built in but doesn't include fields.

Have a look at this module it adds token support for fields https://drupal.org/project/token and this module https://drupal.org/project/token\_filter allows you to use tokens in the text editor
> 1 votes

---
Tags: nodes, 10
---


# Question
Title: Import CSV to nodes/entities in Drupal 8 including a UI
What’s the best solution for importing CSV files into nodes or entities in Drupal 8 that offers a UI so content editors can import regularly?

I’ve heard D8 Migrate works well but I understand there’s currently no UI for the import process.

CSV import via Feeds doesn’t appear to be ready yet.

# Answer
I do this all the time, making use of migration configuration entities (provided by the migrate\_plus module). Define a migration plugin in your migration module's config/install directory, using the CSV source plugin from the migrate\_source\_csv module \- omitting the 'path' source configuration, which will be filled in from the form. Let's say the ID of this migration is example\_csv. Create a form with a file upload element (named 'csv\_file' in this case), and in the submitForm() method:

```
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $all_files = $this->getRequest()->files->get('files', []);
    if (!empty($all_files['csv_file'])) {
      $validators = ['file_validate_extensions' => ['csv']];
      if ($file = file_save_upload('csv_file', $validators, 'public://', 0)) {
        $csv_migration = Migration::load('example_csv');
        $source = $csv_migration->get('source');
        $source['path'] = $file->getFileUri();
        $csv_migration->set('source', $source);
        $csv_migration->save();
        drupal_set_message($this->t('File uploaded as @uri.', ['@uri' => $file->getFileUri()]));
      }
      else {
        drupal_set_message($this->t('File upload failed.'));
      }
    }
  }

```

This updates the migration settings with the new file. You still have to run the migration using `drush mi example_csv` to actually import the content.

Or add some code to the function to actually execute the import:

```
      $migration_instance = \Drupal::service('plugin.manager.migration')->createInstance('example_csv');

      $executable = new MigrateExecutable($migration_instance, new MigrateMessage());

      try {
        $migration_status = $executable->import();
      }
      catch (\Exception $e) {
        \Drupal::logger('migrate_drupal_ui')->error($e->getMessage());
        $migration_status = MigrationInterface::RESULT_FAILED;
      }
      if ($migration_status) {
        drupal_set_message($this->t('Import Successful'));
      }
      else {
        drupal_set_message($migration_status, 'error');
      }

```
> 10 votes

# Answer
It is probably better and faster to use Feeds, but since the D8 version is still under development; alternatively, you could use Excel + VBA (*Visual Basic for Applications*, comes with Excel) + Internet Explorer 11.

Here an example how you can import your CSV content using VBA.

For example, lets assume you want to import this and create new nodes with the info from your CSV:

Here is a sample VBA code:

```
Sub Drupal_Import()

Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")

Dim x As Integer

For x = 2 To 4 'this controls which rows get added, so only 2 to 4

myURL = "https://rgr79.ply.st/node/add/article"

With IE
.Visible = True 'makes your Internet Explorer window visible.
.navigate myURL
End With

Do
el = vbNullString
On Error Resume Next
Set HTML = IE.document
el = HTML.getElementsByClassName("visually-hidden")(1).innerText
DoEvents
Loop While el = vbNullString

'the above loops until the visualy-hidden class is detected, which means the edit form has been loaded

Application.Wait (Now + TimeValue("00:00:03")) 'tells the program to wait 3 secs.

Set HTML = IE.document

HTML.getElementById("edit-title-0-value").Value = Cells(x, 1).Value 'here the 1 is the Y (so 1 is Column A)

HTML.getElementById("edit-body-0-value").Value = Cells(x, 2).Value 'here the 2 is the Y (so 2 is Column B)

Cells(x, 3).Value = "Done" 'here we use the 3rd column (Column C) and mark it as Done to keep track.

HTML.getElementsByClassName("button js-form-submit form-submit")(1).Click 'clicks the submit button

Application.Wait (Now + TimeValue("00:00:00")) 'here I have a wait for 0, increase it to 2 or 3 if you see your VBA get stuck after submitting a node.

Do
el = vbNullString
On Error Resume Next
Set HTML = IE.document
el = HTML.getElementsByClassName("messages messages--status")(0).innerText
DoEvents
Loop While el = vbNullString

'all the above does is loops the code until the drupal message is detected, which means the node was loaded, after the submit.

Next x

End Sub

```

Make sure you change the domain name in `myURL = "https://rgr79.ply.st/node/add/article"` line to your domain. I am using a simplytest.me domain, if you can't already tell.

How to add the VBA code?

Click on the Developer tab and then on Visual Basic icon (or ALT + F11)

and Paste the code inside of Sheet1(Sheet1)

Now in the toolbar, click on `tool` and then `References`

You will need to scroll, find and checkmark

* Microsoft HTML Object Library
* Microsoft Internet Controls

**Note:** I know it works with Internet Explorer 11, not sure if it works with the new Microsoft Edge browser.

Now you are ready to run the script. You can do so by clicking the Play button

You could also run it by clicking the Macros Icon (see image2), but I prefer to do it from the VBA window.

So you hit the play button and an IE window automatically opens and you see this:

Oh yes, you forgot to log in, lol.

So you proceed to login to Drupal and then you close explorer (since cookies history saves your login) and plan on hitting the play button again. But you are not able to... you see the play button greyed out and not able to make any changes to the VBA code... What is going on?

Well your code is still running, so you need to hit the Stop (reset) button.

Now you can click the play button again and joy the world of automatization.

### Important

If you plan to insert stuff to the Body field (like we are doing in this example), since Drupal 8 uses CKEditor for this field and CKEditor is JS, we cannot target a div class or ID; thus, we cannot add content inside CKEditor.

Fortunately, there is a work around. Make sure your IE 11 Security settings are set to High, this automatically will block all JS. Therefore, CKeditor will not load, and the body field will be just like the other fields.

---

### If you need to edit nodes example:

```
Sub Drupal_Edit()

Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")

Dim x As Integer

For x = 2 To 4 'this controls which rows get added, so only 2 to 4

myURL = "https://rgr79.ply.st/node/" & Cells(x, 3) & "/edit"

With IE
.Visible = True 'makes your Internet Explorer window visible.
.navigate myURL
End With

Do
el = vbNullString
On Error Resume Next
Set HTML = IE.document
el = HTML.getElementsByClassName("visually-hidden")(1).innerText
DoEvents
Loop While el = vbNullString

'the above loops until the visualy-hidden class is detected, which means the edit form has been loaded

Application.Wait (Now + TimeValue("00:00:04")) 'tells the program to wait 3 secs.

Set HTML = IE.document

HTML.getElementById("edit-title-0-value").Value = Cells(x, 1).Value 'here the 1 is the Y (so 1 is Column A)

HTML.getElementById("edit-body-0-value").Value = Cells(x, 2).Value 'here the 2 is the Y (so 2 is Column B)

Cells(x, 4).Value = "Done" 'here we use the 4th column (Column D) and mark it as Done to keep track.

HTML.getElementsByClassName("button js-form-submit form-submit")(1).Click 'clicks the submit button

Application.Wait (Now + TimeValue("00:00:00")) 'here I have a wait for 0, increase it to 2 or 3 if you see your VBA get stuck after submitting a node.

Do
el = vbNullString
On Error Resume Next
Set HTML = IE.document
el = HTML.getElementsByClassName("messages messages--status")(0).innerText
DoEvents
Loop While el = vbNullString

'all the above does is loops the code until the drupal message is detected, which means the node was loaded, after the submit.

Next x

End Sub

```
> 1 votes

# Answer
The above is working fine for me but `Migratin::Load()` and `save()` method is not available in Drupal 8 3.x. I have done some changes in above @Mike Ryan suggested code. Here is the working code on form sumbit handler.

```
public function submitForm(array &$form, FormStateInterface $form_state) {
$all_files = $form_state->getValue('csv_file');
if (!empty($all_files)) {
  $file = file_load($all_files[0]);
  if (!empty($file)) {
    $csv_migration = \Drupal::service('plugin.manager.migration')->createInstance('panalist_migration');
    $source = $csv_migration->get('source');
    $source['path'] = $file->getFileUri();
    $csv_migration->set('source', $source);
    drupal_set_message($this->t('File uploaded as @uri.', ['@uri' => $file->getFileUri()]));
    $executable = new MigrateExecutable($csv_migration, new MigrateMessage());

    try {
      $migration_status = $executable->import();
    }
    catch (\Exception $e) {
      \Drupal::logger('migrate_drupal_ui')->error($e->getMessage());
      $migration_status = MigrationInterface::RESULT_FAILED;
    }
    if ($migration_status) {
      drupal_set_message($this->t('Import Successful'));
    }
    else {
      drupal_set_message($migration_status, 'error');
    }
  }
  else {
    drupal_set_message($this->t('File upload failed.'));
  }
}

```
> 0 votes

# Answer
Now you can use Content Import module (https://www.drupal.org/project/contentimport). Heres a post on how to use it: https://www.ostraining.com/blog/drupal/content-import-module/
> 0 votes

# Answer
If you don't need to store CSV values in entity fields take a look at https://www.drupal.org/project/viewer
> 0 votes

---
Tags: 8, migrations, feeds, importing-exporting
---


# Question
Title: Is it possible to recreate cache tables from a more fixed source?
I am working with a dockerized Drupal environment in which we want to track content alongside our theme, modules, etc in source control. We achieve content tracking by using `mysqldump` to dump the database to disk, with one table per file. Then when the environment is created using Docker Compose, the SQL files on disk recreate the database state. We also track certain files from `sites/default/files` like uploaded images and copy those to the Drupal container on environment start.

Whenever we make a change in our environment, we want to persist the change in our source control by overwriting the SQL files on disk, but even for innocuous changes like logging in a user and logging them back out (theoretically ending up where you began), there are a lot of modified tables:

Several of these are related to user data, but they are mostly caching-related, and the same tables change for other innocuous changes.

Ideally I'd like to prevent "noise" in our commits by minimizing the number of modified files whenever we make a content change. For these cache tables, is it possible to only track their table `CREATE` statement and not the content of the cache, and just recreate the cache content somehow when we spin up a new instance of the Docker environment?

# Answer
To spin up the Drupal container you don't need the content of `cache_*` and `watchdog` tables. You could use Drush with the option `--structure-tables-list`, but it should be no problem to replicate this in custom code:

```
drush sql-dump --structure-tables-list=\
cache_bootstrap,cache_config,cache_container,\
cache_default,cache_discovery,cache_entity,\
cache_menu,cache_toolbar,cache_data,\
cache_dynamic_page_cache,cache_page,\
cache_render,watchdog \
> mysite.sql

```
> 1 votes

---
Tags: caching
---


# Question
Title: How to show layout's label or description in a custom Layout Builder settings form
I have successfully made custom layouts and a custom settings form, something like this: https://www.codimth.com/blog/web/drupal/how-add-custom-settings-layouts-drupal-8-9

I want the custom settings form to include the layout's label and description as I have defined them in the layouts.yml file.

Like, at the top of the form before my settings, the name of the layout and then the description. I don't want to have to make a new Class for each layout just to show different label and description.

# Answer
My colleague figured it out :D

```
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
  $configuration = $this->getConfiguration();
  $definition = $this->getPluginDefinition();
  $form['feature_set_info'] = [
    '#type' => 'item',
    '#markup' => '<div class="form-item"><div class="isu-layout-form-title">' . $definition->getLabel() . '</div><p class="description isu-form-element-description">' . $definition->getDescription() . '</p></div></div>',
  ];
  // The rest of my form
  return $form;
}

```

In particular `$definition = $this->getPluginDefinition();` and then use it as `$definition->getLabel()` and `$definition->getDescription()`.
> 1 votes

---
Tags: 9, layout-builder
---


# Question
Title: With English, French and Spanish enabled. Recently our Comms folks can't add translations
We're using Drupal 9.4.10 - turned on content translation for the Comms role for all content types, URLs, etc. but that role cannot create translations for any content type. They can edit the translations after they're created by an Administrator. Other than giving them Admin permissions does anyone have any ideas about how this could be?

They can actually click on Add translation then fill in the translated content, but when trying to save the translation, the error is Either the path '/node/x'is invalid or you do not have access to it.

# Answer
> 0 votes
This was solved at least for now, by giving Link to any page permission to our Comms role (as noted in the issue).

The only side effect with this is that the Comms folks now see all menu items that they don't have access to, so not ideal.

---
Tags: users, i18n-l10n
---


# Question
Title: How to add condition via views_query_alter() to filter a multi-value select field that does not contain a value?
I have \_views\_query\_alter() hook that I need to filter out nodes whose multi-value select does **not** contain a value ("National"). The code below works to show the nodes that **do** contain "National" but I need to do the opposite and cannot get it to work due the field being a multi-value field.

```
function HOOK_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {

  if ($view->id() == 'state_landing_page') {
    $field = 'field_resource_location_type';
    $value = 'National';
    $operator = '=';
    $query->addWhere('conditions', $field, $value, $operator);
  }
}

```

# Answer
To filter out nodes that do not contain the value "National" in a multi-value select field, you can use the following code instead

```
function HOOK_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
      if ($view->id() == 'state_landing_page') {
        foreach ($query->where as &$condition_group) {
          foreach ($condition_group['conditions'] as &$condition) {
             if ($condition['field'] == 'node.field_resource_location_type') {
              $condition = [
                'field' => 'node.field_resource_location_type',
                'value' => 'National',
                'operator' => '<>',
              ];
            }
          }
        }
      }
    }

```

The operator **\<\>** or **!=** is used to exclude nodes that contain the value "National" in the field. This should work for multi-value fields as well. The **\<\>** operator and **!=** operator are equivalent in MySQL, so either one will work in this case.
> 2 votes

---
Tags: views
---


# Question
Title: Attaching a library to only one custom module
I wrote a sample custom module (*juniper*) and created the corresponding juniper.libraries.yml file to link the CSS and JS. I am trying to load this library only on this module pages (/juniper). However, I have issues:

1. I tried to add the library via *juniper.info.yml*:

```
libraries:
  - juniper/june

```

but this doesn't work for some reason

2. I added the juniper\_page\_attachments hook to the *juniper.module*

```
function juniper_page_attachments(array &$page) {
  //$page['#attached']['library'][] = 'juniper/june';
}

```

but it added the library to the whole site, not just the module.

Could you please help me figure out how to limit the library loading only to the custom module page I created? Thanks!

# Answer
> 1 votes
There's a few different ways of doing this, depending on how you're building `/juniper`.

* If you have a controller that is returning a render array, you can include something like `$build['#attached']['library'][] = 'juniper/june';` to just include it for that page.
* If you're going to use this library on any `/juniper/*` page, then something like a hook\_page\_attachments could be used with logic similar to this:

```
/**
 * Implements hook_page_attachments().
 */
function juniper_page_attachments_alter(array &$attachments)
{
  $route_uri = \Drupal::request()->getRequestUri();

  if(str_starts_with($route_uri, '/juniper/')) {
    $attachments['#attached']['library'][] = 'juniper/june';
  }
}

```

Another solution could be to check out `\Drupal::routeMatch()` if you want to attach to particular routes, or `\Drupal::currentUser()` if you only want to attach for particular users.

# Answer
> 1 votes
You can't attach libraries from module info files. That only works for themes. And yes, if you attach in the page attachments hook without any other condition on the URL or whatever it will be added on every site.

Preferably you only attach to the element where you need either from inside a template via `{{ attach_library('your_module/library_name') }}` or from a render array maybe from a preprocess hook like `hook_preprocess_paragraph` etc.

But this is already documented really well in the official docs: Adding assets (CSS, JS) to a Drupal module via \*.libraries.yml.

---
Tags: hooks
---


# Question
Title: Splitting exposed form filters amongst several blocks
I have a views search page in D8 where I'm I have exposed filters that are shown in blocks. I'm also using search facet blocks. What I want in the sidebar is the exposed filter text search field, followed by the facets, and then an exposed filter for selecting a date range.

I've seen a few places mention you can create a duplicate of the views page keeping the same path and have one set of filters in one views block and others in an additional views block. I think this was for D7 because I can't make it work in D8. Basically they replace the url arguments when one or the other is submitted instead of combining them like they normally would do.

What I've currently done is shown the exposed filter block twice and using CSS (display: none) to aria-hidden="true" hide the redundant exposed filters from screens and assistive technology.

It gets flagged though when I used WAVE to test its accessibility since there are duplicative form labels. It's also, imho, a nasty hack and I'd rather do it the right way if possible.

Is there a right or better way?

# Answer
> 1 votes
There is a solution to this, you can use the module Configurable Views Filter Block to split your search field from the rest of your exposed form, it also natively works with better exposed filters. Right now you may or may not also need the following patches to stitch everything together with facets (2.x), have not tested with 3.x, but will most likely be similar.

```
"drupal/configurable_views_filter_block": {
  "Issue #3347722: Stop using the build id for the block id": "https://git.drupalcode.org/project/configurable_views_filter_block/-/merge_requests/1.patch"
},
"drupal/facets": {
  "Issue #2986981-32: Ajax facet block seems to lose Views context": "https://www.drupal.org/files/issues/2023-01-04/2986981-32.patch",
  "Issue #3168241-8: Facets and exposed filters don't work together with Ajax": "https://www.drupal.org/files/issues/2021-12-05/3168241-8.patch"
}

```

You can also theme your view exposed forms, I had to add some theme suggestions to do so, you can see an explanation on #3347722 on how to do so. I just wrapped up a page using this method, and I was able to acomplish exactly what you were looking to do. Another great helper was using Formdazzle to expose more templates on my exposed form for theming.

# Answer
> 0 votes
In Drupal 8, Views pages allow you to render your exposed filters as a separate block. In your view, select your Page display, then, under Advanced, toggle on the option **Exposed form in block**.

You can now separately place the exposed filter like any other block. It doesn't even need to be on the same page as the view results.

# Answer
> 0 votes
Although not perfect, a possible solution is to modify the exposed form. For me, the file was `views-exposed-form--search.html.twig`.

You can then display your separate form elements using things like:

```
{{ form.items_per_page }}
{{ form.sort_bef_combine }}
{{ form.search_api_fulltext }}
{{ form.actions }}

```

If you need to load a view or other node inside you can do so with the twig tweak module and output things like

```
{{ drupal_entity('block', 'facetsummary') }}
{{ drupal_entity('node', node_id_created_in_preprocessor, 'search_highlight') }}

```

Essentially I used the exposed form markup to emulate what I wanted to do and my exposed form tag ended up wrapping around a large portion of my pages output.

Make sure to somewhere do something like this so that the forms hidden fields are also rendered

```
{{ form|without('search_api_fulltext','actions','results','items_per_page','sort_bef_combine') }}

```

As a note, this will only work if your exposed filters are close enough to do this with.

In my case I needed to load the full-text search at the top, a view in the middle and then my exposed filters next. This means that my view is now technically wrapped inside of the form tag.

If your filters are far enough apart then this may not work for you.

I hope this helps someone!

---
Tags: views, 8, blocks
---


# Question
Title: Errors when providing or generating keys for Simple OAuth module
I'm trying to configure simple\_oauth to use with local Lando install of a Drupal 9 site with decoupled React frontend.

I've tried to manually generate the keys in the terminal:

```
$ openssl genrsa -out private.key 2048
$ openssl rsa -in private.key -pubout -out public.key

```

...placing the keys into a sibling directory of /web/ and /vendor/ called /keys/.

It throws these error messages:

"The Public Key file does not exist." "The Private Key file does not exist."

So then I tried pressing the "Generate Keys" button. When prompted for a "Directory for the keys", I input the same path to that /keys/ folder

Despite copying the output of a pwd from terminal directly into the field, it throws this error:

'Directory "/home/myusername/Desktop/react1/keys" is not a valid directory.'

What am I missing here?

# Answer
> 0 votes
I was able to get it working just by using "/app/keys" as the paths on ~/admin/config/people/simple\_oauth, instead of the actual path on my machine as in the OP.

I suppose this comes down to me having an opportunity to learn more about Lando+Drupal.

---
Tags: 9, authentication-authorization
---


# Question
Title: How to remove duplicates in view... the return
I know that this question turn around in Drupal answers but I couldn't get a working answer for my use case.

Here it is: I have a view which is producing duplicate results (and I understand why) but I couldn't find a way to remove them in the hook `views_query_alter`

This view is requesting nodes with some filters and a left join (Require this relationship) on a field wich contains references to paragraphs (`node__field_aw_agenda`). This is this relationship which produce the duplicates.

```
SELECT "node_field_data"."nid" AS "nid", "node_field_data"."langcode" AS "node_field_data_langcode", DATE_FORMAT(paragraphs_item_field_data_node__field_aw_agenda__paragraph__field_agenda_date.field_agenda_date_value, '%Y%m%d') AS "paragraphs_item_field_data_node__field_aw_agenda__paragraph_", MIN(node_field_data.nid) AS "nid_2", MIN(paragraphs_item_field_data_node__field_aw_agenda.id) AS "paragraphs_item_field_data_node__field_aw_agenda_id"
FROM
{node_field_data} "node_field_data"
LEFT JOIN {node__field_aw_agenda} "node__field_aw_agenda" ON node_field_data.nid = node__field_aw_agenda.entity_id AND node__field_aw_agenda.deleted = '0'
INNER JOIN {paragraphs_item_field_data} "paragraphs_item_field_data_node__field_aw_agenda" ON node__field_aw_agenda.field_aw_agenda_target_id = paragraphs_item_field_data_node__field_aw_agenda.id
LEFT JOIN {node__field_aw_prod_state} "node__field_aw_prod_state" ON node_field_data.nid = node__field_aw_prod_state.entity_id AND node__field_aw_prod_state.deleted = '0'
LEFT JOIN {node__field_aw_images} "node__field_aw_images" ON node_field_data.nid = node__field_aw_images.entity_id AND node__field_aw_images.deleted = '0'
LEFT JOIN {paragraph__field_agenda_date} "paragraphs_item_field_data_node__field_aw_agenda__paragraph__field_agenda_date" ON paragraphs_item_field_data_node__field_aw_agenda.id = paragraphs_item_field_data_node__field_aw_agenda__paragraph__field_agenda_date.entity_id AND paragraphs_item_field_data_node__field_aw_agenda__paragraph__field_agenda_date.deleted = '0'
WHERE ("node_field_data"."status" = '1') AND ("node_field_data"."type" IN ('aw_audiovisu', 'aw_scenicarts')) AND ("node__field_aw_prod_state"."field_aw_prod_state_value" IN ('prem', 'play')) AND ("node_field_data"."langcode" IN ('fr')) AND ("node__field_aw_images"."field_aw_images_target_id" IS NOT NULL)
GROUP BY "node_field_data"."nid", "paragraphs_item_field_data_node__field_aw_agenda__paragraph_", "node_field_data_langcode"
ORDER BY "paragraphs_item_field_data_node__field_aw_agenda__paragraph_" DESC

```

As you can see, there is a `GROUP BY` term with several fields in it. This `GROUP BY` term is added in the following hook

```
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  $view_id = $view->id();
  $display_id = $view->current_display;
  if (($view_id == 'my_view') && ($display_id == 'my_display_id')) {
    $query->addField('node_field_data', 'nid', 'nid', [
      'function' => 'groupby',
    ]);
    $query->groupby = ['node_field_data.nid'];
  }
}

```

Note that this hook is adding only one `GROUP BY` field (`"node_field_data"."nid"`), I don't know how this lead to add the other fields (`"paragraphs_item_field_data_node__field_aw_agenda__paragraph_", "node_field_data_langcode"`)

Please do not provide me a solution with `hook_views_pre_render()` as I am looking for a generic SQL solution

As requested, here is a screenshot of the view UI

# Answer
To remove unnecessary **GROUP BY** statements added to a query, you can use the `unset()` function in your hook implementation to remove the unwanted groupings. Here's an updated version of your code that *removes the unwanted GROUP BY fields*:

```
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  $view_id = $view->id();
  $display_id = $view->current_display;
  if (($view_id == 'my_view') && ($display_id == 'my_display_id')) {
    $query->addField('node_field_data', 'nid', 'nid', [
      'function' => 'groupby',
    ]);
    $query->groupby = ['node_field_data.nid'];

    // Remove unwanted GROUP BY fields
    unset($query->groupby['paragraphs_item_field_data_node__field_aw_agenda__paragraph_']);
    unset($query->groupby['node_field_data_langcode']);
  }
}

```
> 0 votes

---
Tags: views
---


# Question
Title: How to convert date/time from timezone to another timezone in migration process
I'm using format\_date process plugin to import data from external API to drupal 8 node. The date/time in API is "Asia/Jerusalem" time - `2017-06-24 20:52:55` The date/time from the API is saved in drupal node as it was a UTC `2017-06-24T20:52:55` When the node is displayed (I have "Asia/Jerusalem" timezone defined for me) it shows `2017-06-24 23:52:55`

This is the configuration file I used

```
source:
  fields:
    -
      name: status_updated
      label: 'Status updated'
      selector: status_updated
destination:
  plugin: 'entity:node'
process:
  field_ext_status_updated:
    plugin: format_date
    from_format: 'Y-m-d H:i:s'
    to_format: 'Y-m-d\TH:i:s'
    #timezone: 'Asia/Jerusalem'
    settings:
     validate_format: false
    source: status_updated

```

I need either to convert the source date first from "Asia/Jerusalem" to "UTC" and then pass it to format\_date or change the configuration file in way that it will save the date as `2017-06-24T17:52:55`so for users with timezone "Asia/Jerusalem" it will show the correct date/time `2017-06-24 20:52:55`

How can I achieve it? removing the comment for `timezone: 'Asia/Jerusalem'` not helped

# Answer
Timezone conversion is not yet supported - the issue where it's being developed is https://www.drupal.org/node/2883892.
> 1 votes

# Answer
Timezone conversion is now supported, with `from_timezone` and `to_timezone` `format_date` plugin parameters. See updated status of the issue posted by @Mike\_Ryan: https://www.drupal.org/node/2883892

So, above configuration should become:

```
field_ext_status_updated:
  plugin: format_date
  from_format: 'Y-m-d H:i:s'
  to_format: 'Y-m-d\TH:i:s'
  from_timezone: 'Asia/Jerusalem'
  to_timezone: 'UTC'
  settings:
    validate_format: false
  source: status_updated

```
> 0 votes

---
Tags: 8, migrations
---


title: Hook post update not found

text:
# Question
Title: Hook post update not found
I have a problem with the `drush updb` command which does not find the hook post updates of my custom module. I noticed that the module install saves the module's name string here in database, table "key\_value", in BLOB file.

Table key\_value :  BLOB file :

My post update in mymodule.post\_update.php :

As it is present in the database, the command seems to consider that the hooks are executed when not. Is there a trick or something missing to solve this problem? My site is in 9.5.4.

# Answer
> 1 votes
Sounds like you want to run update hooks on a newly installed module. Then you should use deploy hooks. Other then update and post-update hooks they run also for newly installed modules. The only requirement is you run `drush deploy:hook` during your deployment routine or simply switch from `drush updb` to `drush deploy` which also contains `drush updb` and `drush deploy:hook` already and runs everything in the right order.

(`drush cim` will enable the module and in the end `drush deploy:hook` will pick the deploy hooks up.)

Create a file *MYMODULE.deploy.php* and inside there put `MYMODULE_deploy_NAME(&$sandbox)` and go.

# Answer
> 0 votes
Any update function listed in `existing_updates` has already been executed, and Drupal won't execute it again (post-update hooks typically operate on content, and you don't want to run those sorts of updates twice unintentionally).

If you're confident that executing the contents of that function is the right solution to your problem, then just change the function name to something that hasn't been executed before.

---
Tags: hooks, drush, 9
---


# Question
Title: Displaying all pages in a BOOK teaser block within a block
I'm trying to display all the BOOKS in my site as a teaser block with the pages below it.

Like this:

```
Title: This is the book of my Cat
Page: 1 2 3 4 5 6 7 8

Title: This is the book of my Dog
Page: 1 2 3 4 5 6 7 8

Title: This is the book of my Bird
Page: 1 2 3 4 5 6 7 8

```

I have the following View setup to display the teaser of the books on the site filtered by the value of having children or not.

In the teaser of the book I have the "Views Book Pages" block to display the children pages. But I can't seem to get it to show up properly as I think I am using the relationships incorrectly. Or do I use contextual filters? Currently I have the relationship set to "Book Parent", but this still shows all pages of ALL books under each book teaser.

# Answer
> 0 votes
You don't need Contextual filters if you want to show all items, Contextual filters are used when there is a context that informs Views to narrow down results, for example, a context of a single book, to show pages only from that single book.

In your case you want to show all pages that exist, but group them according to Books they belong to.

It seems like you're using a field reference to connect your Pages to Books, so that is what you use to group the results by.

You already have the Book Parent Relationship, this introduces the Book parent info into this Views, along with the "children" pages.

You also have the Page title Field, that takes care of the Page links. Now you need to make them display with the logic of which book they belong to.

Add the "Content: Title" Field (another one), make it use the Relationship, and it will show the Book title, not the Page title.

Then under `Format` settings set the first grouping field to the (second) Content Title field, the one for the Book title. You can also set that field to `Exclude from display` so it's not repeated for every Page, since it will be used as the "grouping" field.

---
Tags: views
---


# Question
Title: How to ignore opening quote in views sort
I use views to display a sorted list of book titles. Titles that begin with a quote are listed first. I want to ignore the quote for sorting purposes. So, instead of:

* "Once Upon a Time": Fairy Tales in Reality
* Grimm's Fairy Tales
* The Best Book of Fairy Tales

I want:

* Grimm's Fairy Tales
* "Once Upon a Time": Fairy Tales in Reality
* The Best Book of Fairy Tales

It appears the Views Natural Sort module will handle this, but it's still in Alpha for Drupal 8. Is there another, relatively straightforward (non-custom-code if possible) means of accomplishing this?

I've read a number of posts addressing more complex situations with fairly complex solutions, but it seems something this simple should have a simple solution.

# Answer
Thanks to all for the suggestions. After I got Natural Sort mostly working, I ran into problems using the sorted titles with Views grouping due to accented letters (no fault of Natural Sort). For example, I'd get a group with "A" as the group heading and another group with "Á" (accented A).

To solve this problem, I did the following:

* Add a field named `sort_title` to the content type and hide it from users.
* Add a `node_presave()` hook for the content type to a custom module.
* Create a `sortable_title` function in the hook to
    + Replace accented letters and other international characters in the title with close English equivalents.
    + Force the entire title to uppercase.
    + Strip all non-alphanumeric characters from the front of the title.
    + Add a ~ character to titles that begin with a number (because I want them to sort after titles beginning with letters).
* Save this sortable title in the `sortable_title` field for the node.
* Use the `sortable_title` field for sorting and grouping in the view, instead of the regular title field, which I was using (and which is still the one that gets displayed).
* I also subthemed the views-view-list.html.twig template to replace the ~ with # in the grouped heading (I had already subthemed the file for another reason anyway).

This approach isn't the most general, but it's giving me exactly the outcome I want, so I'm no longer using Natural Sort. It's only about 30 lines of code in the hook function (most of that being a table of international characters and their replacements) and of course, there's the hidden duplicate of the title field.
> 0 votes

# Answer
views\_natural\_sort is able to do this kind of sorting.

It might be currently in alpha state but it already has more than 250 installation for the alpha 3 release which means that most major bugs should have already been ironed out.

Upon enabling you are able to choose title to sort with and you are given 2 extra options for natural sorting (`sort natually ascending` and `sort natually descending`)

It also has some handy settings at `admin/structure/views/settings/views_natural_sort` which you will allow you to chose what other characters you want to ignore (and other settings)

Following are the default settings
> 1 votes

# Answer
Well, I wouldn't recommend views\_natural\_sort module for solving described issue. Especially when you have lots of content (I have 200K nodes). views\_natural\_sort creates a dedicated table and store there cleaned up fields. For my case it sounds overkill.

I used next approach:

* installed and enable views\_sort\_expression
* added "Expression" sort criteria into the view
* configured "Expression".

Expression:

```
REGEXP_REPLACE(node_field_data.title, '^Panelblock: +|^Panel: +|[«»"()„] ?|(  )', '')

```

Which replaces specific chars, interested words and double spaces.

And then views generates such query:

```
SELECT
  ...,
  REGEXP_REPLACE(node_field_data.title, '^Panelblock: +|^Panel: +|[«»"()„] ?|(  )', '') AS "views_sort_expression_0"
FROM
  {node_field_data} "node_field_data"
WHERE
  ...
ORDER BY
  ...
  "views_sort_expression_0" ASC
LIMIT ...

```

Tip: to build and test regex use awesome https://regex101.com/ service.
> 0 votes

---
Tags: views, 8
---


# Question
Title: Display the last page in a BOOK content type as a link?
I'm currently using the core BOOK content type as a form of discussions. I created a views page with all the books and titles exposed. But I also want to append the last page of the book in the Views page. Setting the Depth = 1 I get the first page of the book and title, which is correct. But how do I set it to show the last Depth of the book so it can create a link to the last page?

# Answer
Showing only the latest anything is too complicated a query.

You first have to include all items into Views, then sort them according to your desired criteria, and when your item is at the top of the list restrict Views to only show one item. That is how you can get the Book Page with largest Book Weight number, or Changed field, if you're wanting content that is latest to have been changed.

Having only one item needs to be incorporated into another query, which means another Views, so you can use your "latest" info in a list of other items.

In your case you need to create separate Views of Book Discussions with Depth 2, add Sorting according to Depth, Weight, or Changed (what ever criteria you mean by "last"), and set the Pager to show only 1 item in results. This Views is a helper Views, to be embedded into your original Views. To make the connection you also need to add the Contextual Filter for the Book parent (Page Depth 1?) that will then be used in your original Views to show the correct Page for the correct Book title in the list of all Books.

Then you need to install a contributed module that enables you to embed Views Displays into other Views Displays: Views Field View

Be mindful that combining queries like this can cause performance issues, these types of queries are generally speaking slower than regular Views and depending on the number of your data items can be heavy on performance.

With that module installed edit your original Views of Book titles and add a new Field (Global:View field). You will need to save these Field settings in two steps, (select, save, select, save), and you might need to have the Book Parent ID present in the original Views (you can set it to "Exclude from display"), that field needs to match the Contextual filter Field from your helper Views.

You can look up the actual argument name under "Replacement patterns". Read more on the GitLab page for the module: views\_field\_view
> 0 votes

---
Tags: views, 9
---


# Question
Title: Auto assign term to node from term field from user
I have a term field called "Organization" on both Content and User entities.

On the Content entity, the field for Organization is hidden.

For the user, they select a value for Organization.

I'd like to automatically assign a value on a Node to be equal to the value of Organization in the User entity (if available, other leave empty).

There seems to be a number of ways to do this:

* Rules, ECA, and other workflow tools
* Context ecosystem of modules
* Prepopulate modules

Constraints include: speed: cannot have node saving slow down due to workflow.

I'm hoping someone has experience implementing such a feature and would kindly shed some light to their approach.

# Answer
> 2 votes
Can easily create a custom module with the following

use hook\_entity\_presave ...

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21entity.api.php/function/hook\_entity\_presave/9.4.x

your code would look something like this...

```
 use Drupal\node\NodeInterface;

 function YOURMODULE_node_presave(NodeInterface $node) {
   switch ($node->getType()) {
     case "your_content_type":

       // Get the current user or //$node->getOwnerId();
       $user = \Drupal::entityTypeManager()->getStorage('user')->load(\Drupal::currentUser()->id());
       // Probably check if is set ect..
       $user_org = $user->field_organization->target_id;
       $node->set('field_organization', $user_org);
     break;
   }
  }

```

This should not slow saving down too much at all - as making con jobs or adding stuff to the a queue worker to do later would be silly in this case as needing it on a node.

---
Tags: taxonomy-terms, 9, workflows
---


# Question
Title: How do I access a field value for an entity (e.g. node) object?
`node_load((int) $nid)` loads a fully-populated node entity. `$node->title->value` gets the title, but how do I access field values in Drupal 8?

# Answer
I guess you do not need to convert `$entity` into an array, this would simply work.

```
$entity->get('field_name')->getValue();

```

Alternatively, we can make it easier to read as follows:

```
$entity->field_name->value;

```

FYI : Using `kint()` from the `devel_kint` module will let you know all the available methods that could be used to access the object elements, so comparatively `var_dump()` is less helpful.
> 128 votes

# Answer
in drupal 8 , $node being of class node

```
 $node->field_machine_name->getValue();

```

or

```
$node->get('field_machine_name')->getValue();

```

will return an array of values.

If you expect only one, you might as well stringify the array with

```
$node->field_machine_name->getString();

```

or

```
 $node->get('field_machine_name')->getString();

```
> 73 votes

# Answer
For fields you should be able to use `$node->body->value` for example. If you don't know what the field names are I recommend installing the Devel module for Drupal 8 and inspecting the node via like `dsm($node)`.
> 36 votes

# Answer
You can always do `$entity->toArray()` to see what's in an entity. Even when using xdebug (for example with phpstorm) making sense of an entity object on its own is very hard. I doubt `dsm($node)` in Drupal 8 makes any sense. If you insist on in-browser debugging (but you shouldn't, Drupal 8 is too complex to debug without xdebug) `dsm($node->toArray())` is what you want.
> 18 votes

# Answer
Use following code snippet to get node field values

This is used to get node id from url

```
$nid = \Drupal::routeMatch()->getRawParameter($node_id);

```

To load node data using nid

```
$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);

```

This is used to get field value.

```
$terms = $node->get('field_Name')->getValue();

```

This is used to get node title.

```
$product_name = $node->getTitle();

```
> 17 votes

# Answer
It's simply:

```
$node->get('field_name')->getValue();

```

If the field is an entity reference field, there are some special ways to get the referenced entities.

To get the target id (first element):

```
$entity->get('field_entity_reference')->target_id;

```

To get the loaded entity (first element):

```
$entity->get('field_entity_reference')->entity;

```

When using `->entity` on the field it automatically returns the loaded entity.

If the field can contain multiple references, you can fetch them all like this:

```
$entities = $entity->get('field_entity_reference')->referencedEntities();

```

That will return an array of entities.
> 14 votes

# Answer
For me, having an `$entity` (a node) this worked:

```
$entity->field_name->getValue();

```

using 8.1.
> 7 votes

# Answer
While using (the actual correct way):

```
$node = \Drupal\node\Entity\Node::load($nid);
$node->get('nid')->value; // returns a raw value - Node ID

// Following both returns array structure containing value/target id nested value.
$node->get('nid')->value();
$node->nid->getValue();

```
> 7 votes

# Answer
```
use Drupal\node\Entity\Node

$node = Node::load($nid);
$title = $node->get('title')->value;

```

Or

```
use Drupal\node\Entity\Node

$title = Node::load($nid)->get('title')->value;

```

Here is nice write up about accessing values from the node object https://www.frobiovox.com/posts/2016/03/28/simplify-drupal-8-field-value-calls.html
> 5 votes

# Answer
When not using nodes but entities (like the OP asked) things get a little more murky. For example when using an address entity it only took me 8 tries to get the organization value.

```
$v1 = $address->get('field_address_organization')->getString();
$v2 = $address->get('organization')->getString();
$v3 = $address->get('field_organization')->getString();
$v4 = $address->field_organization->getValue();
$v5 = $address->organization->getString();
$v6 = $address->field_organization->getString();
$v7 = $address->organization->getValue();
$v8 = $address->organization;

```

The only one that didn't throw an exception was the last one. And I'm lying when I say it only took me 8 tries to get the right answer - but 8 is all I'll admit to publicly. :)
> 4 votes

# Answer
I had to get the address entity and render it programmatically. After a lot of searching and debugging, this is what worked best for me

```
if ($field_name == 'field_address') {
      $render_array = $entity->get($field_name)->view('address_plain');
      $body .= \Drupal::service('renderer')->renderRoot($render_array);
    }

```
> 0 votes

---
Tags: 8, entities
---