title: Migration with custom files path

text:
# Question
Title: Migration with custom files path
I have to migrate a website from Drupal 7 to Drupal 9. My Drupal 7 files were located in this directory : sites/mywebsite/files In Drupal 9, files will be located in this directory : sites/default/files

While paths are automatically managed by media module in ckeditor in D9, the path for every file is still sites/mywebsite/files/myfile.pdf. I don't know where to change it.

How to fix this?

Thanks

# Answer
You can achieve that by adopting the below snippet to your use case.

```
source:
  constants:
    PROFILE_PICTURES_FILE_DIRECTORY: 'public://profile_pictures/'

process:

  profile_picture_destination_filename_base:
    -
      plugin: concat
      source:
        - title
        - field_account_id
      delimiter: '-'

  profile_picture_destination_filename:
    -
      plugin: callback
      callable: basename
      source: field_profile_picture # This is the photo URL column.
    -
      plugin: callback
      callable: ucfirst

  profile_picture_destination_full_path:
    -
      plugin: concat
      source:
        - constants/PROFILE_PICTURES_FILE_DIRECTORY
        - '@profile_picture_destination_filename_base'
        - '@profile_picture_destination_filename'
    -
      plugin: urlencode

  profile_picture_source_image_path:
    -
      plugin: urlencode
      source: field_profile_picture # This is the photo URL column.
  uri:
    plugin: file_copy
    source:
      - '@profile_picture_source_image_path'
      - '@profile_picture_destination_full_path'
    file_exists: 'rename'
    move: FALSE

```
> 0 votes

---
Tags: files, migrations, 9
---


# Question
Title: How to iterate multi dimensional array and pipe each sub array to another plugin as input in Migration yml
I am migrating CSV data into Nodes and Paragraphs in Drupal 8.

I have field in CSV file which has JSON data, I have written a process plugin to convert JSON data to multi-dimensional array.

I would like to know a way to pass the each sub array to my another custom process plugin. Is there any such process plugin available to pipe sub array from parental array in core `migrate` or through `migrate_plus` module.

I am looking for something similar so that it passes only sub array into the final custom process plugin.

```
  pseudo_field_country_time_zones:
    - # plugin which converts JSON data to multi dimensional array.
      plugin: country_timezones_data_formatter
      source: timezones
    - # not sure if this is correct plugin to process array.
      plugin: sub_process
    -
      plugin: country_timezones_paragraphs

```

You might ask why cant you process the data in the `country_timezones_paragraphs` process plugin itself. That plugin is being used by other process, so dont want to change it. Other solution for me is to write another process plugin but it will be just code duplication with foreach loop added to `country_timezones_paragraphs`.

I believe there is already a plugin available either from migrate or migrate\_plus module for this scenario , but not able to identify what it is.

---

```
$input_data = '[{"zoneName":"Africa Ceuta","gmtOffset":3600,"gmtOffsetName":"UTC+01:00","abbreviation":"CET","tzName":"Central European Time"},{"zoneName":"Atlantic Canary","gmtOffset":0,"gmtOffsetName":"UTC\u00b100","abbreviation":"WET","tzName":"Western European Time"},{"zoneName":"Europe Madrid","gmtOffset":3600,"gmtOffsetName":"UTC+01:00","abbreviation":"CET","tzName":"Central European Time"}]';

```

---

Decoded JSON array.

> $decoded\_array = var\_dump(json\_decode($input\_data, TRUE));

```
Array
(
    [0] => Array
        (
            [zoneName] => Africa Ceuta
            [gmtOffset] => 3600
            [gmtOffsetName] => UTC+01:00
            [abbreviation] => CET
            [tzName] => Central European Time
        )

    [1] => Array
        (
            [zoneName] => Atlantic Canary
            [gmtOffset] => 0
            [gmtOffsetName] => UTC±00
            [abbreviation] => WET
            [tzName] => Western European Time
        )

    [2] => Array
        (
            [zoneName] => Europe Madrid
            [gmtOffset] => 3600
            [gmtOffsetName] => UTC+01:00
            [abbreviation] => CET
            [tzName] => Central European Time
        )

)

```

---

# Answer
There's no such process plugin in core or migrate\_plus. If you can't find what you need in those lists, you'll probably have to write a custom solution. You may want to check out SubProcess process plugin which may be able to work with your decoded array with minimal changes.
> 0 votes

---
Tags: 8, migrations
---


# Question
Title: How to write custom access for a route which redirects the user to another route if a condition is true
If I visit **example.route.one** and certain conditions are fulfilled I want to redirect it to **example.route.two** OR else access should be allowed. How Can I achieve this? I tried writing the redirection in the custom controller **routeOne** but this method does not work properly for non-admin users, the issue being if I click/visit **example.route** it automatically redirects me to **example.route.two**

Menu Yml file - example.links.menu.yml

```
example.route:
  title: 'Route Example'
  route_name: example.route
  parent: system.admin
  description: 'Contains Route Example'
  weight: -99

example.route.one:
  title: 'Route One'
  route_name: example.route.one
  description: 'Route one example'
  parent: example.route
  weight: 1

example.route.two:
  title: 'Route Two'
  route_name: example.route.two
  description: 'Route two example'
  parent: example.route
  weight: 2

```

Routing File - exmaple.routing.yml

```
example.route:
  path: '/admin/route'
  defaults:
    _controller: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
    _title: 'Route Example'
  requirements:
    _access: 'TRUE'

example.route.one:
  path: '/admin/route/one'
  defaults:
    _title: 'Route one'
    _controller: '\Drupal\example\Controller\ExampleController::contentOne'
  requirements:
    _custom_access: '\Drupal\example\Controller\ExampleController::routeOne'
  options:
    _admin_route: TRUE

example.route.two:
  path: '/admin/route/two'
  defaults:
    _title: 'Route two'
    _controller: '\Drupal\example\Controller\ExampleController::contentTwo'
  requirements:
    _custom_access: '\Drupal\example\Controller\ExampleController::routeTwo'
  options:
    _admin_route: TRUE

```

Controller for custom access - ExampleController.php

```
<?php

namespace Drupal\example\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Access\AccessResult;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Url;

/**
 * Defines a route controller .
 */
class ExampleController extends ControllerBase {

  /**
   * {@inheritdoc}
   */
  public function routeOne() {
    if (TRUE) {
      $response = new RedirectResponse(Url::fromRoute('example.route.two')->setAbsolute()->toString());
      $response->send();
      return AccessResult::forbidden();
    }
    else {
      return AccessResult::allowed();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function routeTwo() {
    return AccessResult::allowed();
  }

  /**
   * {@inheritdoc}
   */
  public function contentOne() {
    return [
      '#type' => 'markup',
      '#markup' => $this->t("hello route one"),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function contentTwo() {
    return [
      '#type' => 'markup',
      '#markup' => $this->t("hello route two"),
    ];
  }

}

```

# Answer
> 0 votes
The issue if you click/visit `example.route` it automatically redirects to `example.route.two` is caused by the access method not only called when you visit `example.route.one`, but also on other pages with links pointing to `example.route.one`, for example in a menu.

So use access methods only for calculating access results. If this then results in a 403 you can catch it in an event subscriber and set a redirect response instead of the default 403 message.

See Dynamically change the "access denied page" title and body.

---
Tags: 8, routes
---


title: Can I add a custom block?

text:
# Question
Title: Can I add a custom block?
I want to have a block with 3 text body fields. I've done this before in Drupal 8 where I created a custom block and was able to add different fields to it.

In my Drupal 7 setup, I can add a block but cannot see where to add a custom block. Is this possible? If not, is there a way to set up a block with 3 different body fields?

# Answer
> 0 votes
Use the Bean module, this will allow you to create custom Block types with fields, even image fields. It integrates nicely with the blocks module.

---
Tags: 7, blocks
---


# Question
Title: How to display a message according to the country of the store?
On Drupal 8, I installed Drupal Commerce 2

I want to modify the TWIG file of the products to show "Made in France", if the store country is France and made in Belgium, if the store country is Belgium.

How to display a message according to the country of the store ?

I would like to do this in the products TWIG file and in the stores TWIG file.

There is certainly a condition to be met but I do not know which one.

`commerce-store--online--full.html.twig` :

```
  {% if  (how to make the condition to check the store country) FR %}
    <div class="row mr-0 mb-3 ml-0 shadow d-flex flex-wrap flag-france">
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-primary"></div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 bg-white d-flex align-self-center justify-content-center">
        <small class="font-weight-bold text-center">ENTREPRISE FRANÇAISE</small>
      </div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-danger"></div>
    </div>
  {% elseif (how to make the condition to check the store country) BE %}
    <div class="row mr-0 mb-3 ml-0 shadow d-flex flex-wrap flag-belgique">
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-primary"></div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 bg-white d-flex align-self-center justify-content-center">
        <small class="font-weight-bold text-center">ENTREPRISE BELGE</small>
      </div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-danger"></div>
    </div>
  {% endif %}

```

# Answer
> 0 votes
For `commerce-store--online--full.html.twig` it should looks like:

```
  {% if store_entity.address.country_code == FR %}
    <div class="row mr-0 mb-3 ml-0 shadow d-flex flex-wrap flag-france">
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-primary"></div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 bg-white d-flex align-self-center justify-content-center">
        <small class="font-weight-bold text-center">ENTREPRISE FRANÇAISE</small>
      </div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-danger"></div>
    </div>
  {% elseif store_entity.address.country_code == BE %}
    <div class="row mr-0 mb-3 ml-0 shadow d-flex flex-wrap flag-belgique">
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-primary"></div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 bg-white d-flex align-self-center justify-content-center">
        <small class="font-weight-bold text-center">ENTREPRISE BELGE</small>
      </div>
      <div class="col-4 col-sm-4 col-md-4 col-lg-4 col-xl-4 p-3 bg-danger"></div>
    </div>
  {% endif %}

```

---
Tags: 8, theming, commerce
---


# Question
Title: Display images as a form element in a webform
The goal is quite simple – I'm looking for a way to display an image in a webform. By that I mean the image would part of the webform as a complement to a question (example: "what color is the car in this picture").

If possible it'd be great if the user could to upload the images when administrating the webform elements, and also if they were their own element that would be awesome (but even adding them to the descriptions of the question-elements themselves *could* work as well).

**So basically, how can I setup a "display custom image in the webform"-element?**

I've tried searching for a solution but all my results are about how to add an image upload field, which is quite the opposite of what I'm looking for.

Grateful for any help I could get on this.

# Answer
> 2 votes
If you install the IMCE module and set up the right permissions, users can upload and insert images into a webform.

Another option is to change the Webform module's default HTML Editor to use a Text format which supports inline images. You would do this by going to Webform \> Configuration \> Elements ( (/admin/structure/webform/config/elements)

---
Tags: 8, webforms
---


title: How do I get the current URL in a rule?

text:
# Question
Title: How do I get the current URL in a rule?
I am trying to make a Rule where after the user logs in they are redirected to the front page *except when they are setting their first time password or resetting their password* To do it I want to use a Rule that acts on User Logged In, with a condition that checks if the url they are on has edit in the name, and if it doesn't then redirect them to the front page.

My issue is that when I try to use the Path Contains Text condition it never triggers, and if I try to print the url in a message as the action it is always empty.

What am I doing wrong? What do I need to do to get the results I want?

# Answer
> 0 votes
Here is a working example taken from the Rules Examples module, which is a submodule of D8 Rules Essentials.

```
langcode: en
status: false
dependencies:
  module:
    - tr_rulez
  enforced:
    module:
      - tr_rulez
id: redirect_to_home
label: 'Redirect to home on Login'
events:
  -
    event_name: rules_user_login
description: 'Issue #2975452-6: Redirect all users to "/" on login, except for when a one-time login password is used.'
tags:
  - login
  - redirect
  - rules_examples
config_version: '3'
expression:
  id: rules_rule
  uuid: 7263942c-3847-460d-af3f-6c78f80fbcc1
  conditions:
    id: rules_and
    uuid: a8c1bb95-b783-4238-a7e1-9b4b9fb96ca4
    conditions:
      -
        id: rules_condition
        uuid: f35e2d95-850d-455d-99e2-629e37b17cb7
        context_values:
          text: reset
        context_mapping: {  }
        context_processors:
          text:
            rules_tokens: {  }
        provides_mapping: {  }
        condition_id: rules_path_contains_text
        negate: true
  actions:
    id: rules_action_set
    uuid: d17285ef-4de4-498a-8b78-654cf79566ee
    actions:
      -
        id: rules_action
        uuid: a529b090-e6f3-4421-aede-75489267d888
        context_values:
          url: /
        context_mapping: {  }
        context_processors:
          url:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_page_redirect

```

---
Tags: 8, rules, uri
---


title: Change parent of multiple child pages

text:
# Question
Title: Change parent of multiple child pages
I have a page with many child pages. And I have a task: there's needed to change parent for all of this child pages. I can move single page using "node hierarchy \> Parent \> Enter the title of the parent node." and write wanted node title there, but I can't use it for many pages. Is there solution for this problem? I tried to google it, but find nothing.

# Answer
> 0 votes
I'm assuming your parent-child relationships are done through an Entity reference field on the child node pointing to a parent.

As always there is more than one way of solving it in Drupal but one popular way is to use the Views Bulk Operations (VBO) module.

The module Views Bulk Edit helps to speed it up by showing the field options to update.

The procedure is to create Views where you can see all the child nodes among the results. It can be all nodes of that type, or you can even create it specifically for one parent node where its children nodes are automatically filtered.

VBO allows you to add a Field to your Views that shows up as a checkbox next to each result row. It also adds an Action you can trigger on the chosen rows.

With that configured you will be able to choose nodes from your results and edit them in bulk.

---
Tags: nodes
---


# Question
Title: How do I fix a "The requested URL /user/login was not found on this server." error?
I am currently migrating a Drupal 8 site from one cloud server to another. The servers are Ubuntu and CentOS (AWS EC2) respectively. After copying the files and exporting-importing the database, I am able to see the home page successfully on the new server.

However, whenever I click on any link or enter any path in the browser, I get the following error:

> Not Found
>
> The requested URL /user/login was not found on this server.

What can I check to eliminate this error? I thought this may have something to do with clean URLs, but it seems that Drupal 8 deprecated that setting. What else can I try?

**Edit:** Here is the .htaccess file in case it helps:

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

# Protect files and directories from prying eyes.
<FilesMatch "\.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock))$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$">
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
  <IfModule !mod_authz_core.c>
    Order allow,deny
  </IfModule>
</FilesMatch>

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

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

# Add correct encoding for SVGZ.
AddType image/svg+xml svg svgz
AddEncoding gzip svgz

# Most of the following PHP settings cannot be changed at runtime. See
# sites/default/default.settings.php and
# Drupal\Core\DrupalKernel::bootEnvironment() for settings that can be
# changed at runtime.

# PHP 5, Apache 1 and 2.
<IfModule mod_php5.c>
  php_value assert.active                   0
  php_flag session.auto_start               off
  php_value mbstring.http_input             pass
  php_value mbstring.http_output            pass
  php_flag mbstring.encoding_translation    off
  # PHP 5.6 has deprecated $HTTP_RAW_POST_DATA and produces warnings if this is
  # not set.
  php_value always_populate_raw_post_data   -1
</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>

# Set a fallback resource if mod_rewrite is not enabled. This allows Drupal to
# work without clean URLs. This requires Apache version >= 2.2.16. If Drupal is
# not accessed by the top level URL (i.e.: http://example.com/drupal/ instead of
# http://example.com/), the path to index.php will need to be adjusted.
<IfModule !mod_rewrite.c>
  FallbackResource /index.php
</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 "(^|/)\.(?!well-known)" - [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/foo will be redirected to http://www.example.com/foo)
  # 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/foo will be redirected to http://example.com/foo)
  # 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 /

  # Redirect common PHP files to their new locations.
  RewriteCond %{REQUEST_URI} ^(.*)?/(install.php) [OR]
  RewriteCond %{REQUEST_URI} ^(.*)?/(rebuild.php)
  RewriteCond %{REQUEST_URI} !core
  RewriteRule ^ %1/core/%2 [L,QSA,R=301]

  # Rewrite install.php during installation to see if mod_rewrite is working
  RewriteRule ^core/install.php core/install.php?rewrite=ok [QSA,L]

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

  # For security reasons, deny access to other PHP files on public sites.
  # Note: The following URI conditions are not anchored at the start (^),
  # because Drupal may be located in a subdirectory. To further improve
  # security, you can replace '!/' with '!^/'.
  # Allow access to PHP files in /core (like authorize.php or install.php):
  RewriteCond %{REQUEST_URI} !/core/[^/]*\.php$
  # Allow access to test-specific PHP files:
  RewriteCond %{REQUEST_URI} !/core/modules/system/tests/https?.php
  # Allow access to Statistics module's custom front controller.
  # Copy and adapt this rule to directly execute PHP files in contributed or
  # custom modules or to run another PHP application in the same directory.
  RewriteCond %{REQUEST_URI} !/core/modules/statistics/statistics.php$
  # Deny access to any other PHP files that do not match the rules above.
  # Specifically, disallow autoload.php from being served directly.
  RewriteRule "^(.+/.*|autoload)\.php($|/)" - [F]

  # 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
> 2 votes
It sounds like .htaccess does not exist in the root. Check that the provided Drupal 8 .htaccess file exists in the application root.

# Answer
> 0 votes
You can try to access like this? http://\[domain-name\]/~\[user-name\]/user/login some check userDir directive in your apache configuration ... https://www.drupal.org/project/drupal/issues/359540

---
Tags: 8, database, migrations, uri
---


title: How do I create a link?

text:
# Question
Title: How do I create a link?
Say I am extending The `blockBase` class to create a custom block, and I am implementing the `blockBuild` method to create some markup for my block. Something like this:

```
 class YourModuleBlock extends BlockBase {

   /**
     * Implements \Drupal\block\BlockBase::blockBuild().
     */
     public function build() {
      return array(
        '#markup' => 'This is a block!',
      );
     }
   }

```

If I wanted to provide a link in this markup, in D7 I would have used the `l` function, but this is no longer available (see here). So, I need to make available the new D8 method for generating links. I could just use an `<a>` tag, but this was never best practice in D7.

So, what is the right method to use for creating links and how do I make it available to my function?

# Answer
> 69 votes
\Drupal::l is deprecated. Maybe this case will be useful for somebody

```
  use Drupal\Core\Url;
  use Drupal\Core\Link;
  $url = Url::fromRoute('entity.node.edit_form', array('node' => NID));
  $project_link = Link::fromTextAndUrl(t('Open Project'), $url);
  $project_link = $project_link->toRenderable();
  // If you need some attributes.
  $project_link['#attributes'] = array('class' => array('button', 'button-action', 'button--primary', 'button--small'));
  print render($project_link);

```

# Answer
> 38 votes
Here are some examples of creating links in Drupal 8. Note that $this-\>t('some text') is available within blocks that extend BlockBase. If you copy these to another class that doesn't have it or use these in a .module file, you may need to change this to t() .

Basic Link to a node:

```
$node = Node::load($nid);
$build['node_link'] = $node->toLink()->toRenderable();

```

This creates a render array like this:

```
$link = [
  '#type' => 'link',
  '#url' => $url_object,
  '#title' => 'Title of Node',
];

```

You can create the render array without loading the node this way:

```
$url_object = Url::fromRoute('entity.node.canonical', ['node' => $nid]);
$link = [
  '#type' => 'link',
  '#url' => $url_object,
  '#title' => $this->t('Read More'),
];

```

Or using the core Link class:

```
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid]);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

```

If you want to use markup in the text of your link, you can't just put a string in. You need to use a render array element:

```
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid]);
$link_text =  [
  '#type' => 'html_tag',
  '#tag' => 'span',
  '#value' => $this->t('Load More'),
];
$link = Link::fromTextAndUrl($link_text, $url);

```

To create an absolute link, you add this option to the URL, not the link:

```
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid], ['absolute' => TRUE]);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

```

To add a class to your link, you also need to add this to the URL, not the link:

```
$options = [
  'attributes' => [
    'class' => [
      'read-more-link',
    ],
  ],
];
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid], $options);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

```

To add a query string to your link, you also need to this to the URL, not the link:

```
$options = [
  'query' => [
    'car' => 'BMW',
    'model' => 'mini-cooper',
  ],
  'attributes' => [
    'class' => [
      'read-more-link',
    ],
  ],
];
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid], $options);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

```

To set the link to open in a new window with target = \_blank:

```
$options = [
  'attributes' => [
    'target' => '_blank'
  ],
];
$url = Url::fromRoute('entity.media.edit_form', ['media' => $entity->id()], $options);
$link = Link::fromTextAndUrl(t('Edit'), $url);
$form['entity']['edit_link'] = $link->toRenderable();

```

Here's a link to a taxonomy term page:

```
$url = Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $tid]);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

```

Here's a link to node edit page:

```
$url = Url::fromRoute('entity.node.edit_form', ['node' => $nid]);
$link = Link::fromTextAndUrl($this->t('Edit'), $url);
$build['read_more'] = $link->toRenderable();

```

To create an external link:

```
$url = Url::fromUri('http://www.example.com/');
$link = Link::fromTextAndUrl($this->t('Vist this example site'), $url);
$build['external_link'] = $link->toRenderable();

```

Link to homepage:

```
$url = Url::fromRoute('<front>');
$link = Link::fromTextAndUrl($this->t('Home'), $url);
$build['homepage_link'] = $link->toRenderable();

```

Note that on any of these url objects, you can get the url as a string by calling:

```
$url->toString();

```

For example:

```
$url_string = Url::fromRoute('<front>')->toString();

```

# Answer
> 27 votes
The change notice, `l()` and `url()` are removed in favor of a routing based URL generation API give the following code examples for Drupal 8.

```

use Drupal\Core\Link;
use Drupal\Core\Url;

// Internal path, defined by a route
$url = Url::fromRoute('book.admin');
$internal_link = Link::fromTextAndUrl(t('Book admin'), $url)->toString();

// External URI.
$url = Url::fromUri('http://www.example.com/');
$external_link = Link::fromTextAndUrl(t('External link'), $url)->toString();

```

Route names are in the *.routing.yml* files and (by default) in the *router* database table.

# Answer
> 23 votes
Another option is to create a link in a render array

```
$url = Url::fromRoute('entity.node.edit_form', array('node' => NID));
$link = [
  '#type' => 'link',
  '#url' => $url,
  '#title' => t('This link was rendered')
];

```

Drupal supplies us with some helper methods to create urls and links to entities.

```
$url = Node::load(NID)->toUrl('edit-form');

```

And

```
$link = Node::load(NID)->toLink(t('link text'), 'edit-form');
$link_render_array = $link->toRenderable();

```

# Answer
> 16 votes
The ability to set attributes seems lost or convoluted in the previous examples because the functionality is just not obvious. There are two ways to create links depending on if it has a route or not and each behaves a little bit different so here are the examples.

1. With a route. This makes the most sense, you can just supply it in the options.

```
Link::createFromRoute('My link',
  'entity.node.canonical',
  ['node' => 123],
  ['attributes' => ['class' => 'special']]));

```
2. With an external url. This one is a little weird. There isn't an option argument so it might seem impossible but its actually OK. The reason is that inexplicably links never have options only the URL they describe. This means you pass in the class to the URL when you create it and it will just work.

```
Link::fromTextAndUrl('My link',
  Url::FromUrl('https://example.com/about',
    ['attributes' => ['class' => 'special']]));

```

A corollary to all this is that you can also do this.

```
$link = Link::fromTextAndUrl('Example',  Url::fromUri('https://example.com/about'));
$link->getUrl()->setOption('attributes', ['class' => 'superspecial']);

```

# Answer
> 2 votes
A complete example with attributes and HTML markup in the link text:

```
  $url = Url::fromRoute(
   'your.route.name',
   [],
   ['attributes' => ['id' => 'add-link', 'class' => ['btn', 'btn-sm', 'btn-primary']]]
  );
  $link = Link::fromTextAndUrl(
    Markup::create('<span class=\'glyphicon glyphicon-plus\'></span> ' . t('Add new item')),
    $url
  );

```

# Answer
> 1 votes
The answers here gave me some good pointers. All I wanted was to provide a link to the node in my logs...So here's what I ended up with

```
  use Drupal\Core\Url;
  use Drupal\Core\Link;
  /* ...
  .. */
  $url = Url::fromRoute('entity.node.canonical', array('node' => $object->id()));
$strings = array(
  '!node' => Link::fromTextAndUrl($object->getTitle(), $url)->toString(),
  '%nid' => $nid,
);
\Drupal::logger('mymodule_actions')->notice('Updating !node (%nid)', $strings);

```

# Answer
> 1 votes
For Drupal 8 or 9, if you want to add some markup around the text, you can do like this:

```
// If you know the route name.
$url = Url::fromRoute('route_name');
// If you just know the path.
$url = Url::fromUserInput('/yourpath');
// Create a link with HTML tag around the text.
$button = Link::fromTextAndUrl(Markup::create('<span>My page</span>'), $url);
$button = $button->toRenderable();
$button['#attributes'] = ['class' => ['class1','class2',]];

```

# Answer
> 0 votes
I was need to add link to the table as a #suffix, but was need to put it as a html, to Achieve this I did

`\Drupal\Core\Link::fromTextAndUrl("Add New page", Url::fromRoute('mymodule.add_new_page'))->toString();`

Where mymodule.add\_new\_page is route from my module yml file.

# Answer
> -3 votes
```
\Drupal\Core\Link::createFromRoute(t('TEXT'), 'ROUTE')->toString()

```

---
Tags: navigation, 8
---


title: Add author to a newly created node

text:
# Question
Title: Add author to a newly created node
When users sign up, I create a new node and add that user into one of the entity reference fields through rules.

What I built so far is the following.

1. *After saving a new user* event
2. *Create a new content item* action (Parameters: type: advisor\_student\_matching\_program, title: title comes here)
3. *Set a data value* (Parameters: data: node\_created.field\_university\_student, value: @user.current\_user\_context:current\_user)
4. *Save entity* (Parameters: entity: node\_created, immediate: 1)

Everything works fine except for the third step.

```
uuid: 692696f4-4c6d-45cc-8a5b-3b69f1925bd0
langcode: en
status: true
dependencies: {  }
id: register_university_student
label: 'Register University Student'
events:
  -
    event_name: 'rules_entity_insert:user'
description: ''
tags: {  }
config_version: '3'
expression:
  id: rules_rule
  uuid: 6f4c1ccb-973c-48ec-aed1-637bdb50e301
  weight: 0
  conditions:
    id: rules_and
    uuid: 3f479a19-06b2-4e05-80c2-4cff28650409
    weight: 0
    conditions: {  }
  actions:
    id: rules_action_set
    uuid: abbb62e5-a610-4ab7-8e3a-f96a4570f049
    weight: 0
    actions:
      -
        id: rules_action
        uuid: 3bce44f5-accb-4239-9c1d-377f29debebf
        weight: 0
        context_values:
          type: advisor_student_matching_program
          title: 'title comes here'
        context_mapping: {  }
        context_processors:
          type:
            rules_tokens: {  }
          title:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: 'rules_entity_create:node'
      -
        id: rules_action
        uuid: eba88823-1ab3-493a-9b62-e22e49a2db4a
        weight: 0
        context_values: {  }
        context_mapping:
          data: node_created.field_university_student
          value: '@user.current_user_context:current_user'
        context_processors: {  }
        provides_mapping: {  }
        action_id: rules_data_set
      -
        id: rules_action
        uuid: 779eadc9-f208-4cfa-b37e-351126c56243
        weight: 0
        context_values:
          immediate: '1'
        context_mapping:
          entity: node_created
        context_processors:
          immediate:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_entity_save
      -
        id: rules_action
        uuid: 18d0c0d6-d9c6-4fc9-8127-4291fe80081c
        weight: 0
        context_values:
          url: /register-uni-basic-information
        context_mapping: {  }
        context_processors:
          url:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_page_redirect

```

# Answer
> 1 votes
Should have used `user`, instead of `@user.current_user_context:current_user`.

---
Tags: 8, rules
---


# Question
Title: API error: "The 'administer nodes' permission is required."
When sending a POST to Drupal 8's JSON:API (to create an entity) that references another content piece (linked by a UUID), I get the error:

"The current user is not allowed to POST the selected field (uid). The 'administer nodes' permission is required."

or in more detail:

```
"errors": [
        {
            "title": "Forbidden",
            "status": "403",
            "detail": "The current user is not allowed to POST the selected field (uid). The 'administer nodes' permission is required.",
...

```

the original JSON in the POST request is:

```
{
  "data": {
    "type": "node--itinerary",
    "attributes": {
      "title": "Article by admin",
      "body": {
        "value": "Custom value",
        "format": "plain_text"
      }
    },
    "relationships": {
      "uid": {
        "value": "a05c9063-d594-4e5e-8b1f-f0b6b9f0d77e"
        }
    }
  }
}

```

I've tried researching this issue but it's not clear what the permission is that needs to be set (there is no: "administer nodes" in permissions) and it's not clear if this level of access is too much. Does anyone have any further information/ideas?

# Answer
> 1 votes
First, `administer nodes` is the machine name of the permission. On the Permissions page, the name of that permission is `Administer content`. There's probably some historical reason why Drupal has some permissions where the machine name is different than the name shown in the UI, but it's horrible usability.

In any case, this is definitely too much access if you just want the user to be able to set the entity reference. Normally, you probably want to give the user some combination of `Content type (Itinerary): Create` `Content type (Itinerary): Edit`, and `Content type (Itinerary): Delete` permissions, which will be under **Node** at `/admin/people/permissions`.

Actually, though, your code has another problem. The error is about posting `uid`, which is not your entity reference, but the author of the node.

The format for setting the user id, as noted in the docs:

```
{
  "data": {
    "type": "node--article",
    "attributes": {
      "title": "Article by admin",
      "body": {
        "value": "Custom value",
        "format": "plain_text"
      }
    },
    "relationships": {
      "uid": {
        "data": {
          "type": "user--user",
          "id": "{{UUID of user 1}}"
        }
      }
    }
  }
}

```

You are missing the part about `data` and `type`.

And, even if you use this code above, it won't set an entity reference field. To set the entity reference field, in addition to the author, you need to set the entity reference field like this (example of setting a node entity reference field on a taxonomy term flag; this is maybe not the best example for your case but its code I wrote recently that shows how to set an entity reference field; in this case, the entity reference field is `flagged_entity`):

```
  data: {
    type: 'flagging--my_flag_type',
    attributes: {
      entity_type: 'taxonomy_term',
      entity_id: drupalId,
      field_text: textFieldValue,
    },
    relationships: {
      uid: {
        data: {
          type: 'user--user',
          id: MyUser.id,
        },
      },
      flagged_entity: {
        data: {
          type: 'taxonomy_term--group',
          id: MyGroup.id,
        },
      },
    },
  },

```

---
Tags: 8
---


# Question
Title: How to query only specific id's in a custom source plugin
I have 40/1040 source product\_id's I need to ignore in one migration, so that I can put them in their own separate migration. I can exclude and include them in the yaml files, but it's a bit ugly and I would rather do so in the custom source plugin because doing this in the yaml is not performant as they are all queried in both.

I can exclude the 40 from their own yaml this way:

```
process:
  variation_id:
    -
      plugin: skip_on_value
      source: product_id
      method: row
      value:
        - 1
        - 2
        - all the way to 40

```

I can include only the 40 in another yaml this way:

```
process:
  variation_id:
    -
      plugin: skip_on_value
      not_equals: true
      source: product_id
      method: row
      value:
        - 1
        - 2
        - all the way to 40

```

But I would rather set a string of `product_id`'s to include/exclude (I'm guessing in the `public function query()`??) because when I run the smaller migration (the 40) there is no need to query and ignore the other 1000 variations.

I created a copy of the source plugin so that I could use a distinct plugin for each of the 2 migrations. Here is the plugin that I am currently using for both:

```
use CommerceGuys\Intl\Currency\CurrencyRepository;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;

/**
 * Gets Commerce 1 commerce_product data from database.
 *
 * @MigrateSource(
 *   id = "commerce1_product_bundle",
 *   source_module = "commerce_product"
 * )
 */
class CommerceProduct extends FieldableEntity {

  /**
   * {@inheritdoc}
   */
  public function fields() {
    return [
      'product_id' => t('Product variation ID'),
      'sku' => t('SKU'),
      'title' => t('Title'),
      'type' => t('Type'),
      'language' => t('Language'),
      'status' => t('Status'),
      'created' => t('Created'),
      'changed' => t('Changes'),
      'data' => t('Data'),
      'commerce_price' => t('Price with amount, currency_code and fraction_digits'),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    $ids['product_id']['type'] = 'integer';
    $ids['product_id']['alias'] = 'p';
    return $ids;
  }

  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = $this->select('commerce_product', 'p')->fields('p');
    if (isset($this->configuration['product_variation_type'])) {
      $query->condition('p.type', $this->configuration['product_variation_type']);
    }
    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    $product_id = $row->getSourceProperty('product_id');
    $revision_id = $row->getSourceProperty('revision_id');
    foreach (array_keys($this->getFields('commerce_product', $row->getSourceProperty('type'))) as $field) {
      $row->setSourceProperty($field, $this->getFieldValues('commerce_product', $field, $product_id, $revision_id));
    }

```

So I'm asking how to exclude an array of 40 product\_id's in one plugin, and then only include an array of 40 product\_id's in the other plugin.

Should I do this in the `public function getIds()`, the `public function query()`, or the `public function prepareRow(Row $row)`?

My guess would be in the `public function query()` But I would like to know the best way, and why.

# Answer
This was quite easy by adding a `$query->condition()` to `public function query()` using `IN` and `NOT IN` in dynamic queries

This worked to exclude certain id's:

```
$products = [1, 2, 3,];
$query->condition('product_id', $products, 'NOT IN');

```

This worked to include only certain id's:

```
$products = [1, 2, 3,];
$query->condition('product_id', $products, 'IN');

```

I was then able to clean up the yamls, and only query the stuff I wanted.
> 1 votes

---
Tags: 8, migrations
---


title: db_delete does not actually delete

text:
# Question
Title: db_delete does not actually delete
I'm trying to delete from the dr\_cache\_form table,in D7, but somehow the record does not get deleted

```
                 function mymodule_multistep_form_submit($form, &$form_state) {
//.....

                 $form_id = array();
                 $form_id[0]='form_' . $form_state['values']['form_build_id'];
                 $form_id[1]='form_state_' . $form_state['values']['form_build_id'];
                 dd($form_id,'$form_id=');

             $query = db_select('cache_form', 'cf');
             $query->fields('cf',array('cid'))
            ->condition('cid', $form_id[0], '=');

$result = $query->execute()->fetchAll();
dd($result,'$result=');

                $deleted=db_delete('cache_form')
                //->condition('cid', $form_id, 'IN')
                ->condition('cid', $form_id[0], '=')
                ->execute();
                //dpq($deleted);
//              dd($deleted);
}

```

So in my drupal\_debug.log file I find the entries corresponding to the above lines, but when I go to the database in mysql and select * from dr\_cache\_form where cid='the form id that was printed in the drupal\_deug"; then the row is there, it isn't actually deleted.

Do I need to flush somehow the db\_delete... all other database operations are working fine, insert, update, select... just this delete does not want to actual delete the row in the db.

the $delete variable is set to 1 after db\_delete

I'm calling it from an multistep form in the last step of the form, thus the cid exists in the dr\_cache\_form table before db\_delete is called, as I can see it via phpmyadmin, and also it gets printed in the drupal\_debug whit the $result variable

# Answer
> 0 votes
db\_delete works fine, but the problem is that I was trying to delete the cache of the current form from within the code of that form e.g. submit form. Logically this is ok for me because I was trying to delete the cache at the end of my multistep form where the user cannot do anything else but navigate away.

There must be a check somewhere either in db\_delete not to allow to delete the cache of the current form. I tried and I managed to delete from cache\_form other entries from the exact same place in the code, just not targeting the current\_form cache.

I was aware that I'm deleting the cache of the current form, but I just wanted to test that the db\_delete works, and then move on with a more complicated logic where I would not delete the current cache but the previous form from the cache.

---
Tags: 7
---


# Question
Title: How to update drupal/core-recommended from 9.0.11 to 9.1.4?
I did composer update drupal/core-recommended --with-dependencies and this got the site updated to 9.0.11.

In Available Updates Drupal is recommending 9.1.4. What composer command will get me there with drupal/core-recommended?

Composer.json is

```
{
    "name": "drupal/recommended-project",
    "description": "Project template for Drupal 9 projects with a relocated document root",
    "type": "project",
    "license": "GPL-2.0-or-later",
    "homepage": "https://www.drupal.org/project/drupal",
    "support": {
        "docs": "https://www.drupal.org/docs/user_guide/en/index.html",
        "chat": "https://www.drupal.org/node/314178"
    },
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],
    "require": {
        "composer/installers": "^1.9",
        "drupal/admin_toolbar": "^3.0",
        "drupal/bootstrap4": "^2.1",
        "drupal/bootstrap_layouts": "^5.2",
        "drupal/coffee": "^1.0",
        "drupal/core-composer-scaffold": "^9",
        "drupal/core-project-message": "^9",
        "drupal/core-recommended": "^9",
        "drupal/ds": "^3.9",
        "drupal/field_group": "^3.1",
        "drupal/hierarchical_term_formatter": "^1.2",
        "drupal/module_filter": "^3.1",
        "drupal/shs": "^1.0",
        "drupal/stage_file_proxy": "^1.0",
        "drupal/views_bootstrap": "^4.3",
        "drush/drush": "^10.3"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "sort-packages": true
    },
    "extra": {
        "drupal-scaffold": {
            "locations": {
                "web-root": "web/"
            }
        },
        "installer-paths": {
            "web/core": [
                "type:drupal-core"
            ],
            "web/libraries/{$name}": [
                "type:drupal-library"
            ],
            "web/modules/contrib/{$name}": [
                "type:drupal-module"
            ],
            "web/profiles/contrib/{$name}": [
                "type:drupal-profile"
            ],
            "web/themes/contrib/{$name}": [
                "type:drupal-theme"
            ],
            "drush/Commands/contrib/{$name}": [
                "type:drupal-drush"
            ],
            "web/modules/custom/{$name}": [
                "type:drupal-custom-module"
            ],
            "web/themes/custom/{$name}": [
                "type:drupal-custom-theme"
            ]
        },
        "drupal-core-project-message": {
            "include-keys": [
                "homepage",
                "support"
            ],
            "post-create-project-cmd-message": [
                "<bg=blue;fg=white>                                                         </>",
                "<bg=blue;fg=white>  Congratulations, you’ve installed the Drupal codebase  </>",
                "<bg=blue;fg=white>  from the drupal/recommended-project template!          </>",
                "<bg=blue;fg=white>                                                         </>",
                "",
                "<bg=yellow;fg=black>Next steps</>:",
                "  * Install the site: https://www.drupal.org/docs/8/install",
                "  * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html",
                "  * Get support: https://www.drupal.org/support",
                "  * Get involved with the Drupal community:",
                "      https://www.drupal.org/getting-involved",
                "  * Remove the plugin that prints this message:",
                "      composer remove drupal/core-project-message"
            ]
        }
    }
}

```

# Answer
> -2 votes
try This is working with me :

```
 composer update drupal/core-recommended --with-dependencies

```

if not working try this at composer.json :

```
    "drupal/core-composer-scaffold": "^9.1",
    "drupal/core-project-message": "^9.1",
    "drupal/core-recommended": "^9.1",

```

After change Run:

```
    composer install or update

```

---
Tags: 9
---


# Question
Title: How does a developer adopt an orphan module?
Is there any way for a developer to apply for adoption of an orphan module?

Some modules like the Views PHP module are still actively used by many sites, but there isn't any active maintainer on it.

I searched for Drupal orphan module adoption but saw no relevant result. Hence I'm asking for advice here.

# Answer
> 5 votes
There is a well-established process for this. As this process may change, it is best to refer to the official documentation to guide you. Please read Taking over unsupported (abandoned) projects

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


# Question
Title: How do I remove part of the HTML markup?
In my Drupal 8 template, I use `{{ product.variations }}` which produces the following HTML markup.

```
<div data-drupal-selector="edit-actions" class="form-actions js-form-wrapper form-group" id="edit-actions--2">
  <button class="button--add-to-cart button button--primary js-form-submit form-submit btn btn-primary" data-drupal-selector="edit-submit" type="submit" id="edit-submit" name="op" value="Ajouter au panier">Ajouter au panier</button>
  <span>Ajouter au panier</span>
</div>

```

How do I remove the `<button>` part from it?

I tried using `{{ product.variations|without('button', 'submit') }}`, but it doesn't work.

# Answer
If I understand correctly, and if my french (google translate :P) is precise.. you wish to remove the add to cart button from your variations.

In that case I see two options. If you wish to just hide the button in some view modes, like a teaser or whatever, just use the `THEME/HOOK_form_commerce_order_item_add_to_cart_form_alter` and try to remove the submit action. Having said that, I can not guarantee the HTML validity of a form without a submit button or how it will work with the form action, since I have not tested it, but I guess it won't be a problem.

On the other hand, if you just want non purchasable variations, you could try this patch out and let the issue maintainers know how it worked :D

Let me know what worked for you,

Best Regards
> 2 votes

---
Tags: 8, theming
---


# Question
Title: Redirect After Creating New Taxonomy Term
I am new to Drupal. I am trying to figure out if it is possible to redirect back to the Taxonomy page right after adding the new vocabulary term instead of being directed to the manage page of the newly created term. Would this have to be changed in the controller for the taxonomy module? Or in another file?

Any help is appreciated, Thank You.

# Answer
> 0 votes
To add a redirection after creating **new** Taxonomy Term I suggest using the `hook_preprocess_HOOK()` in the `MYTHEME.theme` file.

E.g. here is code that add redirection back to the Vocabulary - list of all terms - for the **Add term** button:

```
/**
 * Implements hook_preprocess_HOOK() for menu-local-action templates.
 */
function MYTHEME_preprocess_menu_local_action(array &$vars) {
  if ($vars['link']['#title'] == 'Add term') {
    // Add redirection to the Terms list after creating a new term.
    $destination = Url::fromRoute('<current>')->toString();
    $vars['link']['#options']['query']['destination'] = $destination;
  }
}

```

---
Tags: 8, users, taxonomy-terms, redirection, page-controller
---


# Question
Title: If multiple routes match a path pattern, how can I tell which one would be used?
If multiple routes are returned by something like the following:

```
$route_provider = \Drupal::service('router.route_provider');
$found_routes = $route_provider->getRoutesByPattern('collection/%collection/items');

```

How can I find out which of those routes would be used if a path matched that pattern?

According to the docs:

> `getRoutesByPattern()` returns a route collection of matching routes. The collection may be empty and will be sorted from highest to lowest fit (match of path parts) and then in ascending order by route name for routes with the same fit.

In my case, two routes with the same fitness are returned in alphabetical order:

Would the first or second one be considered more fit?

# Answer
> 1 votes
Your question is not clear enough.

Again, Your quote had full answer, the result is sorted by the fitness from highest to lowest fit. In case, they were equal, it would be sorted by alphabet of `route name`.

Return to your question, people usually use this function when they have a full or nearly full `route name` to check. or they have to add another condition that out of scope of this function.

**You can not ask how Drupal determine which one wins when they are equal**.

---
Tags: 8, routes
---


# Question
Title: Views block that shows all references to current node (cross references)
I'm confused with views filters and relations...

In my articles I have a field (field\_article\_reference\_nodes) that references other nodes and shows these as a link. Now I want to attach a view to other nodes that lists all articles referencing them.

So this is kind of a cross reference. How do I have to set the filters/relations for this view to list all articles that are referencing the current node?

Thanks for your support! Mathias

# Answer
> 2 votes
After knowing that this approach is called "reverse entity reference". I found this tutorial: https://mushtaq.ch/blog/4/drupal-8-reverse-entity-reference-in-view

But in step 3 I needed to use "Content USING field\_myfield" instead of "Content referenced from field\_myfield".

Thanks for your help!

---
Tags: views, 9
---


# Question
Title: Updating user leads to sql integrity issue
Please help me find what I am doing wrong to update a user field. I am trying to update all existing users in my Drupal 8 instance. I could do the same thing easily in D7, but can't get it working in D8. When I execute the following code, I get an integrity violation on the SQL server:

If I take it out of the foreach loop and just execute it on one user it works fine, but with multiple users it works on the first one and then dies on the second user.

```
    $users = User::loadMultiple(\Drupal::entityQuery('user')->execute());
    foreach($users as $user){
      foreach(__get_user_units($user->getUsername()) as $unit){
        $drupalUnits[]=['value'=>$unit];
      }
      //Resulting Array Example (print_r output):
      //    Array
      //    (
      //        [0] => Array
      //            (
      //                [value] => Web Services
      //            )
      //        [1] => Array
      //            (
      //                [value] => Developers
      //            )
      //    )

      $user->get('field_unit')->setValue($drupalUnits);
      $user->save();
    }

```

The results from \__get\_user\_units is an array of values to enter into the 'field\_unit' multivalued field. the foreach then formats that information to match what by default comes from getting the value of that field.

The error that I receive says (Sanitized and formatted for readability):

> ```
> Drupal\Core\Database\IntegrityConstraintViolationException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '-en' for key 'user__name':
> INSERT INTO users_field_data
>             (uid,
>              langcode,
>              preferred_langcode,
>              preferred_admin_langcode,
>              NAME,
>              pass,
>              mail,
>              timezone,
>              status,
>              created,
>              changed,
>              access,
>              login,
>              init,
>              default_langcode,
>              ldap_user_puid_sid,
>              ldap_user_puid,
>              ldap_user_puid_property,
>              ldap_user_current_dn,
>              ldap_user_last_checked,
>              ldap_user_ldap_exclude)
> VALUES      (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2,
>              :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5,
>              :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8,
>              :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11,
>              :db_insert_placeholder_12, :db_insert_placeholder_13, :db_insert_placeholder_14,
>              :db_insert_placeholder_15, :db_insert_placeholder_16, :db_insert_placeholder_17,
>              :db_insert_placeholder_18, :db_insert_placeholder_19, :db_insert_placeholder_20);
> Array (
> [:db_insert_placeholder_0] => 70
>  [:db_insert_placeholder_1] => en
>  [:db_insert_placeholder_2] => en
>  [:db_insert_placeholder_3] =>
>  [:db_insert_placeholder_4] => >
>  [:db_insert_placeholder_5] => >
>  [:db_insert_placeholder_6] => >
>  [:db_insert_placeholder_7] => America/Detroit
>  [:db_insert_placeholder_8] => 1
>  [:db_insert_placeholder_9] => 1590514193
>  [:db_insert_placeholder_10] => 1610341561
>  [:db_insert_placeholder_11] => 1607618808
>  [:db_insert_placeholder_12] => 1590514193
>  [:db_insert_placeholder_13] =>
>  [:db_insert_placeholder_14] => 1
>  [:db_insert_placeholder_15] =>
>  [:db_insert_placeholder_16] =>
>  [:db_insert_placeholder_17] =>
>  [:db_insert_placeholder_18] => >
>  [:db_insert_placeholder_19] => 1612193014
>  [:db_insert_placeholder_20] =>
>  ) in Drupal\Core\Database\Connection->handleQueryException() (line 698 of /var/www/intranet8/web/core/lib/Drupal/Core/Database/Connection.php).
>
>
> Drupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '<>-en' for key 'user__name':
> INSERT INTO users_field_data
> (uid,
> langcode,
> preferred_langcode,
> preferred_admin_langcode,
> NAME,
> pass,
> mail,
> timezone,
> status,
> created,
> changed,
> access,
> login,
> init,
> default_langcode,
> ldap_user_puid_sid,
> ldap_user_puid,
> ldap_user_puid_property,
> ldap_user_current_dn,
> ldap_user_last_checked,
> ldap_user_ldap_exclude)
> VALUES      (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2,
> :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5,
> :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8,
> :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11,
> :db_insert_placeholder_12, :db_insert_placeholder_13, :db_insert_placeholder_14,
> :db_insert_placeholder_15, :db_insert_placeholder_16, :db_insert_placeholder_17,
> :db_insert_placeholder_18, :db_insert_placeholder_19, :db_insert_placeholder_20);
> Array (
> [:db_insert_placeholder_0] => 70
> [:db_insert_placeholder_1] => en
> [:db_insert_placeholder_2] => en
> [:db_insert_placeholder_3] =>
> [:db_insert_placeholder_4] => <>
> [:db_insert_placeholder_5] => <<PASSWORD_HASH>>
> [:db_insert_placeholder_6] => <<email_address>>
> [:db_insert_placeholder_7] => America/Detroit
> [:db_insert_placeholder_8] => 1
> [:db_insert_placeholder_9] => 1590514193
> [:db_insert_placeholder_10] => 1610341561
> [:db_insert_placeholder_11] => 1607618808
> [:db_insert_placeholder_12] => 1590514193
> [:db_insert_placeholder_13] => <<init_address>
> [:db_insert_placeholder_14] => 1
> [:db_insert_placeholder_15] =>
> [:db_insert_placeholder_16] =>
> [:db_insert_placeholder_17] =>
> [:db_insert_placeholder_18] => <<LDAP_USER_DN>>
> [:db_insert_placeholder_19] => 1612193014
> [:db_insert_placeholder_20] =>
> )
> in
>
>
>
> ```

# Edit 1:

In looking closer, the user information seems to be combining user1 and user2 before saving. the init and password fields both have the value for user 2. I don't see how this could be unless 1) the save was somehow asynchronous or 2) the iterator for $users is not working properly.

# Edit 2:

I have traced this down to the ldap\_user module function ldap\_user\_user\_presave() (which implements hook\_user\_presave). If I skip that function call everything works. Looking like it might not be connected to my code.

# Answer
The problem came down to an error in the way the ldap\_user submodule of the ldap module was working. I had to refactor my code to only update one user per cron run (acceptible in my application) so that the LDAP code did not mess it up. The offending code has been reported to the maintainers of the LDAP module (https://www.drupal.org/project/ldap/issues/3196170) for their review. Without that error, either my original code or the code suggested by @abdulazizsaeed would have worked.
> 1 votes

# Answer
try this it is working with me:

```
$users = \Drupal::entityQuery('user')
      ->condition('status', '1')
      ->execute();
    foreach ($users as $uid) {

      $user = \Drupal::entityTypeManager()->getStorage('user')->load($uid);
      $user->set('field_unit', $drupalUnits);
      $user->save();

    }

```
> 0 votes

---
Tags: 8, entities, users
---


# Question
Title: How can I have custom content as last page?
I have a view which shows nodes of 3 specific content types. The content shown is coming from the parent node with entity reference fields where the nodes can be selected to be shown in the view.

I was wondering how I could add custom content, or maybe a node to the end of a that view without having to select it on the parent, because this is always the same content.

What I want is like have the view display a node or some programmatically custom content. It should be there as last page. For example I have a view with 4 nodes, the pager should show 5 and have the 5th page be the node/content I want. I don't want to have to add it every time on the parent node with the entity reference field. It should be there by default.

# Answer
Probably the easiest way to do this would be to add a footer to your view. If you are on the admin screen for your view, you should see options for Page Settings, Header, and Footer in the middle column.

If you "Add" content to the Footer area it will always output below your view content. There are several options including to display a rendered node.
> 2 votes

# Answer
You can achieve this by creating your own views template file in themes/custom/MYTHEME\_NAME/templates. See this documentation for naming conventions https://api.drupal.org/api/drupal/core%21modules%21views%21views.theme.inc/group/views\_templates/8.6.x

In my case, I am using the Views Bootstrap Module and wanted to change the template of a view which uses the Bootstrap Grid mode. So I copied `views-bootstrap-grid.html.twig` from the module's directory (/modules/contrib/views\_bootstrap/templates) into my theme's template directory and renamed it to `views-bootstrap-grid--companies--block.html.twig`

Inside the template file, I added the needed html code:

```
{#
/**
 * @file views-bootstrap-grid.html.twig
 * Default simple view template to display Bootstrap Grids.
 *
 *
 * - columns: Contains rows grouped by columns.
 * - rows: Contains a nested array of rows. Each row contains an array of
 *   columns.
 * - column_type: Contains a number (default Bootstrap grid system column type).
 *
 * @ingroup views_templates
 */
#}
{%
  set classes = [
    'views-view-grid',
  ]
%}
{% if title %}
  <h3>{{ title }}</h3>
{% endif %}
<div id="{{ id }}" {{ attributes.addClass(classes) }}>
  <div class="row">
    {% for row in rows %}
      <div {{ row_attributes.addClass(options.row_class) }}>
        {{ row }}
      </div>
    {% endfor %}
    <div class="my_custom_text">
        MY CUSTOM TEXT
    </div>
  </div>
</div>

```
> 0 votes

---
Tags: 8, views
---


# Question
Title: Field weight in display mode is not respected on custom entity
I have a custom entity type with a set of base fields and I can create/view/update/delete entities. However When I create & enabled a custom view mode to the entity type and set to display subset of fields (using Manage display) in a page using below code:

```
$view_builder = $this->entityTypeManager->getViewBuilder('my_entity');
$build['top_summary'] = $view_builder->view($entity, 'summary');

```

The fields get rendered, but not in the order they are in the view mode. They are in the order of the IDs of the fields alphabetically. So if the entity has these fields in this order:

1. First name
2. Last name
3. Email

They get displayed as

1. Email
2. First name
3. Last name

I can hide fields using the hidden section, but can't change the visible fields' order.

Updating the fields' order in `core.entity_view_display.[ENTITY_TYPE].[BUNDLE].[VIEW MODE]` does not help as the fields are sorted alphabetically on config import/export

# Answer
> 2 votes
After debugging the `Drupal\Core\Field\FormaterBase` on how the fields getting rendered, it seems the weights are getting applied to each field in `Drupal\Core\Entity\EntityViewBuidler,` but they are not getting rendered in the order at the entity level.

So providing a theme for the entity using `hook_theme` and a preprocess solves this issue. Here is the code:

```
// mymodule.module

use Drupal\Core\Render\Element;

/**
 * Implements hook_theme().
 */
function mymodule_theme() {
  return [
    'myentity' => [
      'render element' => 'elements',
    ],
  ];
}

/**
 * Prepares variables for myentity templates.
 *
 * Default template: myentity.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - elements: An associative array containing the entity
 *     information and any fields attached to the entity.
 *   - attributes: HTML attributes for the containing element.
 */
function template_preprocess_myentity(array &$variables) {
  foreach (Element::children($variables['elements']) as $key) {
    $variables['content'][$key] = $variables['elements'][$key];
  }
}

```

```
<!-- myentitty.html.twig -->
<article{{ attributes }}>
  {% if content %}
    {{- content -}}
  {% endif %}
</article>

```

---
Tags: 8, entities
---


# Question
Title: How do I change the node title when saving it?
For a content type (*Article*), when I create a new node and save it, I want to append a field value (for example, *Location*) to the node title.

There seems to be great answers using custom plugins (Modify the node title with the node ID before saving it) and even modules (How do I build the node title from field values when saving the node?), but they're not applicable to Drupal 9.

If the suggested solution requires creating custom module and overriding a function, then please direct me to some implementation guide and specify files locations as I'm a newbie in writing Drupal code.

# Answer
> 1 votes
To do this without writing code, the module you want for Drupal 9 is Automatic Entity Label. Nodes are entities, so you can use this to set the label (title).

---
Tags: nodes, 9
---


# Question
Title: Modify the node title with the node ID before saving it
I need to modify the node title while saving the node ID. I implemented `hook_form_FORM_ID_alter()` as follows.

```
/**
 * Implements hook_form_FORM_ID_alter()
 */
function module_name_form_form_id_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['title']['#access'] = FALSE;
  $form['#entity_builders'][] = 'change_node_title';
}

function change_node_title($entity_type, NodeInterface $node, $form, FormStateInterface $form_state) {
  $node_id = $node->nid->value; // Not getting the node details
  $node->setTitle('Custom Title -' . $node_id);
}

```

The node details aren't found from the #entity\_builders callback.

How can modify the node title before saving it? I don't want to use any custom modules for this. I don't want to use `hook_node_presave()` either, as it would affect the cloned nodes.

# Answer
Never tried **entity\_buildres** but you could probably use the old and tried way of adding a submit handler

```
function MODULENAME_form_alter(&$form, &$form_state, $form_id) {
  // this is the create form id, edit form would be node_article_edit_form
  if($form_id == 'node_article_form') {
    $form['actions']['submit']['#submit'][] = 'MODULENAME_change_title';
  }
}

function MODULENAME_change_title($form, $form_state) {
  $node = $form_state->getFormObject()->getEntity();
  $node->setTitle('Custom Title - ' . $node->id());
  $node->save();
}

```
> 4 votes

# Answer
I would advice to use hook\_entity\_presave() for this:

```
/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function MYMODULE_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  // save a different value as title
  if ($entity->bundle() == 'NODE_TYPE') {
    $entity->title = 'Custom Title - ' . $entity->id();
  }
}

```
> 0 votes

---
Tags: 8, hooks
---


# Question
Title: Is it possible to install Drush 9 without using Composer?
Is it somehow possible to install Drush 9 without using Composer?

# Answer
No.

As it says in the docs:

> Drush 9 only supports one install method. It requires that your Drupal 8 site be built with Composer and Drush be listed as a dependency.

If you don't know how to use composer, you need to learn now, because you'll have serious problems using Drupal without it.
> 3 votes

---
Tags: drush, composer
---


# Question
Title: How to add code logic to Display Suite fields without PHP in Drupal 8? Twig?
Using Display Suite in Drupal 7 I can easily add PHP logic to any custom Display Suite Field. In Drupal 8 PHP is not allowed. How can I program logic in Display Suite fields in Drupal 8?

As an example, I'd like to use a simple if/then statement to show/hide a node field. I have tried embedding Twig into the field but it does not execute. It just renders as plain text.

This is my sample code `{# This is a test comment. #}`

# Answer
Showing hiding fields in twig is pretty simple. You can check if a field has a value like so:

```
{% if node.field_foo is not empty %}
  {{ content.field_foo }}
{% endif %}

```

You cannot execute raw PHP from a twig file, nor can you inject Twig and parse it out through field formatters (probably not without a lot of work, anyway).

***Note the difference between checking the node object and rendering the content array.***

You want to do checks against the entity object, and *never* (in my opinion) the render array. In the above code, if the field has a value, then the condition is true. If you want to *check* the value for a specific string, it is likely better suited for a preprocess hook.

What if the twig template being rendered is a Paragraph, and not a Node template? Not much difference:

```
{% if paragraph.field_foo is not empty %}
  {{ content.field_foo }}
{% endif %}

```

If you need more muscle, I would advise moving your logic to a preprocess hook in `mytheme.theme` where you can use whatever PHP you want, and inject new variables into your Twig file.

```
function mytheme_preprocess_node(&$variables) {
  $variables['show_foo_field'] = FALSE;

  // if field ...
  // and maybe some more conditions?
  $variables['show_foo_field'] = TRUE;
  // end if...
}

```

Then in the twig template...

```
{% if show_foo_field %}
  {{ content.field_foo }}
{% endif %}

```

Now, you say you are using Display Suite - I personally don't inject condition or code through the UI like what you are asking. But one thing I do know about Display Suite is it (when I last looked) tends to hijack a majority of the preprocess calls \- so check its docs or API for the right preprocess hook to call for nodes.

The current hooks for Display suite can be viewed in its .api.php file.

Definitely enable twig debug to be able to check what the Twig template naming pattern should be (suggestions) in the HTML source, and be aware of `mytheme_preprocess_node` potentially not firing. You will need to locate the correct DS hook.
> 1 votes

# Answer
Just an update: starting from its version 8.3.4, Display Suite supports "twig fields" as a new custom field type. https://www.drupal.org/project/ds/issues/3072095
> 0 votes

---
Tags: theming, display-suite
---


# Question
Title: Create a list of webform submissions sorted and searchable by data in user submitted form fields
I am using Webform 6.x on Drupal 8. I would like to create a list of submissions that are sorted and searchable by the user entered data within the submissions. I am able to generate a list of of the submissions but I'm unable to compare, sort, or view the field data within the form submissions.

# Answer
> 0 votes
You can accomplish this with views.

1. Create a view set to show 'Webform Submissions'
2. Under advanced click 'Add' next to relationships.
3. Select the form you want the submissions for in 'Webform Node'
4. Select the field you want to sort/search by in 'Component Data'
5. Select 'Relate using node and Component ID'
6. Add as many relationships as you want if you want to sort/search by more fields.
7. Add Webform Submission Data:Value in the fields section and select the webform node and the component data.
8. Add Webform submission data: Data field in Filter Criteria. Select the relationship of the field you want to sort/search by and expose the filter if you want to allow it to be searchable.

I was looking at a Drupal 7 instance when preparing this answer so the naming might be slightly different but it should work the same in 8.

---
Tags: views, webforms
---


# Question
Title: Best practice: Twig logic versus Preprocess functions
I use Twig and Twig Tweak to do most of the processing. However, from time to time I need to rely on Preprocess functions to get the desired result.

This led me to a situation where now most of my variables are created in a Preprocess function before handing them over to Twig (this keeps my templates clean, simple and most of all easy to read). I also don't like my code being scattered between Templates and Theme functions.

But regarding Drupal Documentation, this method seems discouraged.

> ```
> function mytheme_preprocess_node(&$variable) {
>  if ($variable['node']->getType() === 'my_content_type_machine_name') {
>  $variable['my_title'] = $variable['node']->field_my_title->value;
>  }
> }
>
> ```
>
> You may now use the more concise `{{ my_title }}` in your twig file to refer to `{{ node->field_my_title->value }}`.
>
> However, while this might be possible, **it is discouraged** to create new variables in this manner. Using `{{ node.field_my_title.value }}` is fairly reasonable to type and avoids any potential issues and should be preferred.

So basically my question is: Are there any simple rules to follow regarding Twig versus Preprocess functions for additional logic?

# Answer
> 0 votes
Best practice is documented in the node template. These are the two most important variables:

```
* Available variables:
 * - node: The node entity with limited access to object properties and methods.
 *   Only method names starting with "get", "has", or "is" and a few common
 *   methods such as "id", "label", and "bundle" are available. For example:
 *   - node.getCreatedTime() will return the node creation timestamp.
 *   - node.hasField('field_example') returns TRUE if the node bundle includes
 *     field_example. (This does not indicate the presence of a value in this
 *     field.)
 *   - node.isPublished() will return whether the node is published or not.
 *   Calling other methods, such as node.delete(), will result in an exception.
 *   See \Drupal\node\Entity\Node for a full list of public properties and
 *   methods for the node object.
 * - label: (optional) The title of the node.
 * - content: All node items. Use {{ content }} to print them all,
 *   or print a subset such as {{ content.field_example }}. Use
 *   {{ content|without('field_example') }} to temporarily suppress the printing
 *   of a given child element.

```

It clearly states that you should print the render array `{{ content }}` and use the object `{{ node }}` with its properties and methods to get the node data you need.

---
Tags: 8, theming
---


# Question
Title: How to add "rel" attributes to all external links throughout the website?
I'm trying to add attributes for external links such as the `rel="noopener noreferrer"` for all the external links where `target="_blank"`. I've tried using modules such as the noreferrer and sel, but neither affect the links in my views.

How can I add `rel="noopener noreferrer"` to all links globally where `target="_blank"`?

# Answer
By implementing hook\_link\_alter in either a custom module or your theme.

The code (untested) would be similar to:

```
/**
 * Implements hook_link_alter().
 */
function MODULE/THEME_link_alter(&$variables) {
  if (isset($variables['options']['attributes']['target']) && $variables['options']['attributes']['target'] == '_blank') {
    $variables['options']['attributes']['rel'] = 'noopener noreferrer';
  }
}

```
> 2 votes

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


# Question
Title: "Fatal error: Call to a member function setFormClass()"
I am trying to load the node in an external script, and shows me the following error.

> Fatal error: Call to a member function setFormClass() in field\_ui\_entity\_type\_build()

The code causing the error is the following one.

```
define('DRUPAL_DIR', dirname(realpath(dirname(__FILE__))));
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
use Drupal\node\Entity\Node;

$autoloader = require_once DRUPAL_DIR . '/autoload.php';
$request = Request::createFromGlobals();
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod', FALSE);
$kernel->boot();
$kernel->preHandle($request);

$nid = 123;
$node = Node::load($nid);
$node->set('field_number', 222);
$node->save();

```

Any help?

# Answer
The code shown in the question doesn't correctly bootstrap Drupal. An external script needs to do that, differently from a module. While loading the autoloader allows PHP to find the `Node` class, that isn't sufficient to bootstrap Drupal correctly.

I usually use the authenticate.php file as guideline for writing code for an external script file that needs to bootstrap Drupal.

```
use Drupal\Core\DrupalKernel;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\NodeInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Route;

// Change the directory to the Drupal root.
// Edit the following line to make it point to the directory containing the autoload.php file.
chdir('.');
$autoloader = (require_once 'autoload.php');

try {
  $request = Request::createFromGlobals();
  $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
  $kernel->boot();

  // A route is required for route matching.
  $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('<none>'));
  $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<none>');
  $kernel->preHandle($request);

  // Ensure our request includes the session if appropriate.
  if (PHP_SAPI !== 'cli') {
    $request->setSession($kernel->getContainer()->get('session'));
  }
} catch (HttpExceptionInterface $e) {
  $response = new Response('', $e->getStatusCode());
  $response->prepare($request)->send();
  exit;
}

\Drupal::moduleHandler()->addModule('system', 'core/modules/system');
\Drupal::moduleHandler()->addModule('node', 'core/modules/node');
\Drupal::moduleHandler()->load('system');
\Drupal::moduleHandler()->load('node');

$node = Node::load(123);
$node->set('field_number', 222);
$node->save();

```

Actually, `$kernel->preHandle($request)` should be sufficient to load all the modules, since it contains the following code.

```
// Load all enabled modules.
$this->container->get('module_handler')->loadAll();

```

The code that explicitly loads the modules isn't necessary. At the same time, not explicitly loading the modules makes the code dependent from the installation profile, as the previous code line only loads the modules the installation profile enabled.
> 2 votes

---
Tags: 9, external-scripts
---


title: Create ECK Entity via Ajax

text:
# Question
Title: Create ECK Entity via Ajax
I'm trying to create a ECK Entity Content programmatically. I know, because I've used it elsewhere, I have the right code for creating the Entity Content but in my current setup it is not working anymore.

What I have is the following:

.routing.yml

```
timetracking.ajax_check:
path: '/js/timetracking/ajax/{nid}'
defaults:
    _controller: '\Drupal\timetracking\Controller\TimeTrackingController::timetrackingAjaxCheck'
requirements:
    _csrf_token: 'TRUE'

```

TimeTrackingControlle.php

```
<?php

namespace Drupal\timetracking\Controller;

use Drupal\Core\Controller\ControllerBase;

/**
 * Controller routines for user routes.
 */
class TimeTrackingController extends ControllerBase {

  public function timetrackingAjaxCheck($nid) {
    $user = $this->currentUser();
    $timer = (int) $this->timeSpentConfig->get('time_spent_timer');
    /* @    -- Save One Test Entity */
    $test_entity = \Drupal::entityTypeManager()->getStorage('time_tracking')->create([
      'type' => 'time',
      'title' => 'test-2',
      'field_id' => 1,
    ]);
    $test_entity->save();
  }
}

```

.js

```
(function ($, Drupal) {
  Drupal.behaviors.timetracking = {
    attach: function(context, settings) {
      // Fetch ajax callback url
      var callbackUrl = '/js/timetracking/ajax/10';

      function timetrackingSendTimer() {
        $.ajax({
          type: 'get',
          url: callbackUrl,
          dataType: 'json',
          data: 'js=1&timer=10'
        });
      }
      timetrackingSendTimer();
    }
  }
})(jQuery, Drupal);

```

When I put the *Save One Test Entity* in a .module file it creates an Enitity but when I put it inside the controller it is not. The controller is running as expected when I am debugging it using `DPM` I get a nice output.

I'm wondering if it is possible to do this inside the Controller? And if not how can I use Ajax to create an ECK Entity?

# Answer
In your route you require CSRF token and your ajax call is missing the CSRF token.

Get a CSRF token from ur drupal site using url "/session/token" and send it with your Ajax request.

But is it wise to do it this way? i don't know.

For making ECK Entity with ajax Post i would use REST resource or make a custom REST resource with basic\_auth or cookie authentication, that way you wont need a CSRF Token.
> 0 votes

---
Tags: 8
---


# Question
Title: Pass book node id as second parameter to drupal_block("book_navigation")?
I'm trying to use `drupal_block("book_navigation")` in a twig template (with the twig\_tweak module installed) to display a list of chapters for a book page. But I'm getting a list of all books and their chapters.

Is there a way to use `drupal_block("book_navigation")` to produce a list of chapters for just the one book, maybe by passing the id of the book node as a second parameter? Or some other way?

Compare to the user interface /admin/structure/block. There, when you place a Book Navigation block in a region, you can choose the configuration option "Show block only on book pages". This causes the block to produce a list of chapters for only the book whose page the list appears on. So it's clearly possible to do it using the book navigation block. Just need to know how.

# Answer
After digging into the Book module code, I discovered that in a twig template (with the twig\_tweak module installed) I can use

```
    {{ drupal_block("book_navigation", {block_mode: "book pages"}) }}

```

to create a list of chapters for only the current book (which is what I need). This is equivalent to the configuration option "Show block only on book pages". Probably in documentation somewhere, but much googling didn't find it for me.
> 1 votes

# Answer
In your twig file:

```
{{ drupal_block('my_block', {tab_data: "Results"}) }}

```

In your Myblock.php file

```
public function defaultConfiguration() {
  return [
    'tab_data' => NULL,
  ];
}

public function build() {

  return [
    '#theme' => 'my_theme',
    '#tab_data' => $this->configuration['tab_data'],
  ];
}

```

we can access the tab data in the build function of the block through the configuration variable.
> 0 votes

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


title: Form submit handler never called

text:
# Question
Title: Form submit handler never called
I'm trying to process my custom form. However, code inside the submitForm function is never called. I have not seen any solutions, yet for getting Drupal 8's submitForm to be called.

```
namespace Drupal\archive\Form;

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

class DateForm extends FormBase
{
    public function getFormId() { return 'archive_dateform'; }

    public function buildForm(array $form, FormStateInterface $form_state)
    {
        $form['#action'] = Url::fromRoute('archive.dateform')->toString();

        $form['type'] = [
            '#type' => 'hidden',
            '#value' => $form_state->get('type')
        ];

        $form['year'] = [
            '#title'         => 'Year',
            '#type'          => 'number',
            '#size'          => 4,
            '#step'          => 1,
            '#default_value' => $form_state->get('year'),
        ];

        $options = [];
        for ($i=1; $i<=12; $i++) { $options[$i] = date('F', mktime(0, 0, 0, $i, 10)); }
        $form['month'] = [
            '#title'         => 'Month',
            '#type'          => 'select',
            '#options'       => $options,
            '#default_value' => $form_state->get('month'),
            '#empty_option'  => 'All',
            '#empty_value'   => 0
        ];

        $form['actions']['#type'] = 'actions';
        $form['actions']['submit'] = [
            '#type'        => 'submit',
            '#value'       => 'Search',
            '#button_type' => 'primary'
        ];
        return $form;
    }

    public function validateForm(array &$form, FormStateInterface $form_state)
    {
        $type = $form_state->get('type');
        if (!$type) {
            $form_state->setErrorByName('type', 'Missing Type');
        }
    }

    public function submitForm(array &$form, FormStateInterface $form_state)
    {
        echo "submitForm\n";
        exit();
        $type = $form_state->get('type');

        $year = (int)$form_state->get('year');
        if (!$year) { $year = (int)date('Y'); }
        $params = ['year'=>$year];

        $month = (int)$form_state->get('month');
        if ($month) { $params['month'] = $month; }

        $form_state->setRedirect("archive.$type", $params);
        return;
    }
}

```

And using from a controller

```
namespace Drupal\archive\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Form\FormState;

class ArchiveController extends ControllerBase
{
    public function archive($type, $year, $month, $day)
    {
        $year  = (int)$year;
        $month = (int)$month;
        $day   = (int)$day;

        if (!$year) { $year = (int)date('Y'); }

        if (!$month) {
            $date = "$year-01-01";
            $period = new \DateInterval('P1Y1D');
        }
        else {
            if (!$day) {
                $date   = "$year-$month-01";
                $period = new \DateInterval('P1M1D');
            }
            else {
                $date   = "$year-$month-$day";
                $period = new \DateInterval('P1D');
            }
        }
        $start = new \DateTime($date);
        $end   = new \DateTime($date);
        $end->add($period);

        $manager = \Drupal::entityTypeManager();
        $query   = \Drupal::entityQuery('node')
                ->condition('type',    $type)
                ->condition('created', $start->format('U'), '>=')
                ->condition('created', $end  ->format('U'), '<')
                ->condition('status',  1);

        $form_state = new FormState();
        $form_state->set('type',  $type);
        $form_state->set('year',  $year);
        $form_state->set('month', $month);
        $form = \Drupal::formBuilder()->buildForm('Drupal\archive\Form\DateForm', $form_state);

        return [
            '#theme'   => 'archive_results',
            '#year'    => $year,
            '#start'   => $start,
            '#form'    => $form,
            '#results' => $manager->getViewBuilder('node')->viewMultiple(
                            $manager->getStorage('node')->loadMultiple($query->execute()),
                            'teaser'
                        )
        ];
    }
}

```

# Answer
I think your validation fails because you need to

```
$form_state->setValue('type',  $type);

```

in your controller instead of

```
$form_state->set('type',  $type);

```
> 0 votes

# Answer
You're returning the form in #form. Drupal doesn't process things inside #attributes. That means your form isn't really a form and a lot of the required processing isn't happening.

You need to define your template as accepting a render element, and then e.g. print it as elements.form and set as just 'form' =\> $form.
> 2 votes

# Answer
It's an old post but it help me someway, so I will leave my answear, hope it will help someone.

I had same problem, my submit never called.

I pass my form as @Berdir said, like this:

MYMODULE.module file.

```
function MYMODULE_theme($existing, $type, $theme, $path) {
  return [
    'admin_form' => [
      'template' => 'admin-form',
      'render element' => 'form',
    ],
  ];
}

```

The on my form.php (MYMODULE/scr/Form/form.php) inside buildForm function

```
$form['simulator_values']['connection_services'] = [
  '#type' => 'textfield',
  '#maxlength' => 140,
  '#default_value' => $config->get('connection_services'),
  '#required' => TRUE,
];

$form['actions'] = [
  '#type' => 'actions'
];

$form['actions']['submit'] = [
  '#type' => 'submit',
  '#value' => $this->t('Submit ss')
];

return [
  '#theme' => 'admin_form',
  'render element' => $form,
];

```

Finally on twig side have to build form like this

```
<form {{ attributes }}>
  {{ form.form_build_id }}
  {{ form.form_token }}
  {{ form.form_id }}
  {{ form['render element'].advanced_info }}
  {{ form['render element'].actions.submit }}
</form>

```

Without form\_build\_id, form\_token and form\_id the submit button won't work.

As far I understood drupal need those information about the form to process everything on the right way, because you can have multiple forms on the same page.
> 1 votes

---
Tags: 8, forms
---


# Question
Title: How to theme back end forms created by a custom module?
I want to be able to theme a custom form I create using a custom module that builds a form. The form is created programmatically using the code below:

```
public function buildForm(array $form, FormStateInterface $form_state) {

    $form['name'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Name'),
      '#required' => TRUE
    );

    $form['address'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Address'),
      '#required' => TRUE
    );

    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    );

    return $form;
}

```

This form is rendered on the Drupal 8 back-end and uses the admin theme classy `BEGIN OUTPUT from 'core/themes/classy/templates/form/form.html.twig'`. However there isn't a override file name suggestion.

How would I theme this form?

# Answer
> 4 votes
> I was looking for a way to use a twig template to theme the form. How would I go about doing that?

First your form needs to have an ID

```
public function buildForm(array $form, FormStateInterface $form_state) {

    $form['name'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Name'),
      '#required' => TRUE
    );

    $form['address'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Address'),
      '#required' => TRUE
    );
    $form['actions'] = array('#type' => 'actions');
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    );

    return $form;
}

public function getFormId() {
  return 'the_custom_form_id';
}

```

Now we create a new suggestion:

mymodule/**mymodule.module**

```
<?php

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_theme_suggestions_alter
 */
function mymodule_theme_suggestions_alter(array &$suggestions, array $variables) {

    if (isset($variables['element']) && isset($variables['element']['#type']) && $variables['element']['#type'] == 'form') {
        $original_theme_hook = $variables['theme_hook_original'];

        $suggestions[] = $original_theme_hook . '__' . str_replace('-', '_', $variables['element']['#id']);
    }

    return $suggestions;

}

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

    if ($form_id == 'the_custom_form_id') {

      $form['#theme'] = ['my_custom_form'];

    }

}

/**
 * Implements hook_theme()
 */
function mymodule_theme() {

    $themes['my_custom_form'] = ['render element' => 'form'];

    return $themes;

}

```

**Note:** If you're the creator of the form, you can skip the hook\_form\_alter part and just put `$form['#theme'] = ['my_custom_form'];` inside your form

mymodule/templates/**my\_custom\_form.html.twig**

```
<div class="something">{{ form.name }}</div>
<div class="something-else">{{ form.address }}</div>
<div class="something-else2">{{ form.actions }}</div>

```

# Answer
> 4 votes
One option is to add a prefix and suffix to your form arrays

```
$form['name'] = array(
  '#type' => 'textfield',
  '#title' => $this->t('Name'),
  '#required' => TRUE
  '#prefix' => '<div class="something">',
  '#suffix' => '</div>',
);

$form['#attached']['css'] = array(
 'path/to/my.css' => array(
   'group' => CSS_AGGREGATE_THEME,
   'weight' => 999
 ),
);

```

**my.css**

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

```

# Answer
> 2 votes
It's an old post but it help me someway, so I will leave my answear, hope it will help someone.

The first answear of this post help me a lot, at the end I simplify some code.

I had same problem when I try to theme my form.

What I have done

MYMODULE.module file.

```
function MYMODULE_theme($existing, $type, $theme, $path) {
  return [
    'admin_form' => [
      'template' => 'admin-form',
      'render element' => 'form',
    ],
  ];
}

```

The on my form.php (MYMODULE/scr/Form/form.php) inside buildForm function

```
$form['simulator_values']['connection_services'] = [
  '#type' => 'textfield',
  '#maxlength' => 140,
  '#default_value' => $config->get('connection_services'),
  '#required' => TRUE,
];

$form['actions'] = [
  '#type' => 'actions'
];

$form['actions']['submit'] = [
  '#type' => 'submit',
  '#value' => $this->t('Submit ss')
];

return [
  '#theme' => 'admin_form',
  'render element' => $form,
];

```

Finally on twig side have to build form like this

```
<form {{ attributes }}>
  {{ form.form_build_id }}
  {{ form.form_token }}
  {{ form.form_id }}
  {{ form['render element'].advanced_info }}
  {{ form['render element'].actions.submit }}
</form>

```

Without form\_build\_id, form\_token and form\_id the submit button won't work.

As far I understood drupal need those information about the form to process everything on the right way, because you can have multiple forms on the same page.

# Answer
> 0 votes
Please have a look at the Formdazzle! module.

> Drupal form theming with less pain Theming drupal forms can be difficult and time-consuming. This module provides a set of utilities that make form theming easier.
>
> Currently, this module provides theme suggestions for forms that are much more useful than those provided by Drupal core.
>
> * Theme suggestions for all form elements (including buttons)
> * Theme suggestions for all form element labels
> * All theme suggestions include the form ID and the form element name; e.g. `[element-type]--[form-id]--[form-element-name].html.twig`
> * New in 2.1.0! Twig debugging comments have been added to all forms for the hidden \[`form-id].html.twig` template.
>
> While Drupal core only provided these two theme suggestions:
>
> ```
> input.html.twig
> input--textfield.html.twig
>
> ```
>
> Formdazzle adds the following two theme suggestions to the list:
>
> ```
> input--textfield--webform-contact.html.twig
> input--textfield--webform-contact--first-name.html.twig
>
> ```

---
Tags: 8, theming
---