Drupal Problems and Solutions

DrupalABC aims to provide solution to programming problems faced by Drupal developers.Start learning by reading some of the latest problems below-

How to resolve CSRF token issue in headless/decoupled application ?

Whenever we send a request to Drupal website from our embedded JS application, we have to send a CSRF token with request otherwise it is seen as request forgery issue. You can provide CSRF token to your JS application in the following way:

/**
 * Implements hook_page_attachments().
 */
function example_module_page_attachments(array &$attachments) {
  $attachments['#attached'] = [
    'drupalSettings' => [
      'csrf' => \Drupal::csrfToken()->get(CsrfRequestHeaderAccessCheck::TOKEN_KEY),
    ],
  ];
}

And in your JS application CSRF token can be accessed from drupalSettings object. Make sure this token is added to every request to avoid X-CSRF token not found issues.

What is the correct Nginx configuration for Drupal 7 website?

Here is a sample Nginx Server block for Drupal 7 website.

server  {

        server_name www.example.com;

        root /var/www/html/example.com/;

        access_log /var/log/nginx/example.access.log;

        error_log  /var/log/nginx/example.error.log info;

        index index.php;

        location = /favicon.ico {

                log_not_found off;

                access_log off;

        }

        location = /robots.txt {

                allow all;

                log_not_found off;

                access_log off;

        }

        # This matters if you use drush

        location = /backup {

                deny all;

        }

        # Very rarely should these ever be accessed outside of your LAN

        location ~* \.(txt|log)$ {

                allow 127.0.0.1;

                deny all;

        }

        location ~ \..*/.*\.php {

                return 403;

        }

        location / {

                # This is cool because no php is touched for static content

                try_files $uri $uri/ @rewrite;

                expires max;

        }

        # Block access to "hidden" files and directories whose names begin with a

        # period. This includes directories used by version control systems such

        # as Subversion or Git to store control files.

        location ~ (^|/)\. {

                 return 403;

        }

        # Block access to scripts in site files directory

        location ~ ^/sites/[^/]+/files/.*\.php$ {

                 deny all;

        }

        # Don't allow direct access to PHP files in the vendor directory.

        location ~ /vendor/.*\.php$ {

                deny all;

                return 404;

        }

        location @rewrite {

                # Some modules enforce no slash (/) at the end of the URL

                # Else this rewrite block wouldn't be needed (GlobalRedirect)

                rewrite ^/(.*)$ /index.php?q=$1;

        }

        location ~ \.php$ {

            try_files $uri =404;

            fastcgi_split_path_info ^(.+\.php)(/.+)$;

            fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

            fastcgi_index index.php;

            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

            include fastcgi_params;

            #auth_basic "Restricted Content";

            #auth_basic_user_file /etc/nginx/.htpasswd;

        }

}

 

How to set Drupal cron using crontab in linux environment?

It is always a nice practice to disable automated cron module and setup Drupal cron tasks from the crontab in linux and use of Drush instead of hitting a request on Drupal generated URL. Here is the way to achieve that:

1. Enter command crontab -e to open the cron tab in editor.

2. Enter the following line and save the file.

    0 */2 * * * cd /var/www/html/example-drupal && /usr/local/bin/drush cron

So this will ensure cron runs every 2 hours. Make sure to set correct Drupal directory and drush path.

What are the correct nginx configuration settings for Magento website using PHP 7.3 FPM?

Based on the nginx sample configuration provided the by Magento repository, i have create an nginx configuration which can be used to setup Magento on any VPS.

upstream fastcgi_backend {
    server unix:/var/run/php/php7.3-fpm.sock;
}

server {
    listen 80;
    server_name magento.example.com;
    set $MAGE_ROOT /var/www/html/magento.example.com;
    root $MAGE_ROOT/pub;
    index index.php;
    autoindex off;
    charset UTF-8;
    error_page 404 403 = /errors/404.php;

    
   location /.user.ini {
        deny all;
    }

    location ~* ^/setup($|/) {
        root $MAGE_ROOT;
        location ~ ^/setup/index.php {
            fastcgi_pass   fastcgi_backend;
            fastcgi_param  PHP_FLAG  "session.auto_start=off \n suhosin.session.cryptua=off";
            fastcgi_param  PHP_VALUE "memory_limit=756M \n max_execution_time=600";
            fastcgi_read_timeout 600s;
            fastcgi_connect_timeout 600s;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

        location ~ ^/setup/(?!pub/). {
            deny all;
        }

        location ~ ^/setup/pub/ {
            add_header X-Frame-Options "SAMEORIGIN";
        }
    }

    location ~* ^/update($|/) {
        root $MAGE_ROOT;

        location ~ ^/update/index.php {
            fastcgi_split_path_info ^(/update/index.php)(/.+)$;
            fastcgi_pass   fastcgi_backend;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            fastcgi_param  PATH_INFO        $fastcgi_path_info;
            include        fastcgi_params;
        }

        location ~ ^/update/(?!pub/). {
            deny all;
        }

        location ~ ^/update/pub/ {
            add_header X-Frame-Options "SAMEORIGIN";
        }
    }
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /pub/ {
        location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) {
            deny all;
        }
        alias $MAGE_ROOT/pub/;
        add_header X-Frame-Options "SAMEORIGIN";
    }

    location /static/ {
        expires max;

        location ~ ^/static/version {
            rewrite ^/static/(version\d*/)?(.*)$ /static/$2 last;
        }

        location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2|json)$ {
            add_header Cache-Control "public";
            add_header X-Frame-Options "SAMEORIGIN";
            expires +1y;

            if (!-f $request_filename) {
                rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last;
            }
        }
        location ~* \.(zip|gz|gzip|bz2|csv|xml)$ {
            add_header Cache-Control "no-store";
            add_header X-Frame-Options "SAMEORIGIN";
            expires    off;

            if (!-f $request_filename) {
                rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last;
            }
        }
        if (!-f $request_filename) {
            rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last;
        }
        add_header X-Frame-Options "SAMEORIGIN";
    }

    location /media/ {
        try_files $uri $uri/ /get.php$is_args$args;

        location ~ ^/media/theme_customization/.*\.xml {
            deny all;
        }

        location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ {
            add_header Cache-Control "public";
            add_header X-Frame-Options "SAMEORIGIN";
            expires +1y;
            try_files $uri $uri/ /get.php$is_args$args;
        }
        location ~* \.(zip|gz|gzip|bz2|csv|xml)$ {
            add_header Cache-Control "no-store";
            add_header X-Frame-Options "SAMEORIGIN";
            expires    off;
            try_files $uri $uri/ /get.php$is_args$args;
        }
        add_header X-Frame-Options "SAMEORIGIN";
    }

    location /media/customer/ {
        deny all;
    }

    location /media/downloadable/ {
        deny all;
    }

    location /media/import/ {
        deny all;
    }
    location /errors/ {
        location ~* \.xml$ {
            deny all;
        }
    }

    location ~ ^/(index|get|static|errors/report|errors/404|errors/503|health_check)\.php$ {
        try_files $uri =404;
        fastcgi_pass   fastcgi_backend;
        fastcgi_buffers 1024 4k;

        fastcgi_param  PHP_FLAG  "session.auto_start=off \n suhosin.session.cryptua=off";
        fastcgi_param  PHP_VALUE "memory_limit=756M \n max_execution_time=18000";
        fastcgi_read_timeout 600s;
        fastcgi_connect_timeout 600s;

        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    gzip on;
    gzip_disable "msie6";
    gzip_comp_level 6;
    gzip_min_length 1100;
    gzip_buffers 16 8k;
    gzip_proxied any;
    gzip_types
        text/plain
        text/css
        text/js
        text/xml
        text/javascript
        application/javascript
        application/x-javascript
        application/json
        application/xml
        application/xml+rss
        image/svg+xml;
    gzip_vary on;

    location ~* (\.php$|\.phtml$|\.htaccess$|\.git) {
        deny all;
    }

}
 

How to set HTTPS on website using Nginx and CloudFlare as CDN

First of all, you have to add correct settings in Cloudflare under the SSL/TLS tab. Make sure it is set to Full if using self-generated/certbot generated certificate or else Full Strict if using Cloudflare provided certificate. Once the settings have been done from Cloudflare, move to Nginx configuration of the website and set them like this:

server {

       listen 80;

       listen [::]:80;

       server_name example.com www.example.com;

       return 301 https://example.com$request_uri;

 

}

server {

        listen 443 ssl;

        listen [::]:443 ssl;

        server_name www.example.com;

        ssl on;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        return 301 https://example.com$request_uri;

}

server {

        listen 443 ssl;

        listen [::]:443 ssl;

        server_name example.com;

        ssl on;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        root /var/www/html/example.com;

        index index.html;

 

        location / {

                try_files $uri $uri/ =404;

        }

}

 

First server block ensures redirection to HTTPS and 2nd makes sure non-www is redirected to www. You can modify them as per you convenience.  Avoid automatic NGINX redirections settings done by Certbot if using Cloudflare.

How to modify entity form display settings programtically?

Here is an example snippet for the same:

    $settings = \Drupal::entityTypeManager()
      ->getStorage('entity_form_display')
      ->load('commerce_product.default.default')
      ->setComponent('variations', [
        'type' => 'inline_entity_form_complex',
        'weight' => 10,
        'settings' => ['allow_new' => 'true', 'allow_duplicate' => 'true'],
      ])->save();

How to embed Webform in Drupal 8 form?

There might be a situation where a single/multiple webforms have to be added in a custom form or you may want to display webform based on some conditions. Here is an example snippet to achieve the same.

//Load webform programatically.

$webform = \Drupal::entityTypeManager()->getStorage('webform')->load($webform_id);
$webform_markup = $webform->getSubmissionForm();

//Add the markup into a Drupal 8 form.

$form['markup'] = [

      '#prefix' => '<div id = "webform">',
      '#suffix' => '</div>',
      '#type' => 'markup',
      '#markup' => $webform_markup,
      '#weight' => 1,

];

 

How to attach library using hook_preprocess_page?

Hook preprocess can be used to attach libraries on any page in Drupal 8 based on any condition. Developers can also add drupalSettings variable. Here is the code snippet:

/**
 * Hook_preprocess_page().
 */
function example_preprocess_page(&$variables) {

  $variables['#attached']['library'][] = 'example_module/example_library';

  $variables['#attached']['drupalSettings']['siteBaseUrl'] = 'example.com';

}