# Question
Title: Why doesn't cweagans/composer-patches install my custom patch for drupal/slick?
Basically, I have installed slick module and customised code and created a patch file using "git diff" command. Slick module file path is `modules/contrib/slick/` directory. Below is the code that i have written in the composser.json file.

```
"require": {
        "drupal/slick": "^2.7",
}

----------------------------------

"patches": {
  "drupal/slick": {
  "Slick custom changes": "patches/slick/slick.patch"
},

```

But when running composer install, it just removes this slick package from "modules/contrib/slick, but does not reinstall or add the patch.

If i remove "Slick custom changes": "patches/slick/slick.patch" from composer.json and execute composer install cmd then it install slick module.

How to avoid removing this package and applying the patch?

git apply \> "patches/slick/slick.patch" executes successfully and apply patches. But composer install fails to apply patch.

"cweagans/composer-patches" is already installed.

Below is the patch code

```
diff --git a/docroot/modules/contrib/slick/css/layout/slick.module.css b/docroot/modules/contrib/slick/css/layout/slick.module.css
index 88b0d639f..3f4b10398 100644
--- a/docroot/modules/contrib/slick/css/layout/slick.module.css
+++ b/docroot/modules/contrib/slick/css/layout/slick.module.css
@@ -17,14 +17,15 @@
   .slide__caption {
     left: 0;
     padding: 20px;
-    top: 10%;
+    top: 0%;
   }

   .slide--caption--center .slide__caption,
   .slide--caption--center-top .slide__caption,
   .slide--caption--left .slide__caption,
   .slide--caption--right .slide__caption {
-    width: 42%;
+    width: 50%;
+    height: 100%;
   }

   .slide--caption--center .slide__caption {
diff --git a/docroot/modules/contrib/slick/css/theme/slick.theme.css b/docroot/modules/contrib/slick/css/theme/slick.theme.css
index 79db65f87..0313802ba 100644
--- a/docroot/modules/contrib/slick/css/theme/slick.theme.css
+++ b/docroot/modules/contrib/slick/css/theme/slick.theme.css
@@ -116,12 +116,24 @@
 .slide__title {
   margin: 10px 0 5px;
   line-height: 1.2;
+  font-size: 3em;
+  font-weight: 600;
+  color: #fff;
 }

 .slide__link {
   margin: 30px auto;
 }

+.slide__description{
+  font-size: 1.652rem;
+    line-height: 1.2em;
+    font-weight: 400;
+    font-family: "Open Sans",sans-serif;
+    color: #fff;
+    opacity: 1;
+}
+
 /* Overrides .slick-slider to make caption text selectable. */
 .slide__caption {
   cursor: text;
@@ -130,7 +142,11 @@
   -o-user-select: text;
   -webkit-user-select: text;
   user-select: text;
-  width: 100%;
+  width: 50%;
+  background: #0b172e8a;;
+  margin-top: auto;
+  margin-bottom: auto;
+  margin-left: 0px;
 }

 /* Only display when JS is ready. */
@@ -206,13 +222,14 @@
 }

 .slick-arrow::before {
-  color: #ff6d2c;
+  color: #eb0000;
   font-size: 36px;
   font-size: 2.25rem;
+  opacity: 1;
 }

 .slick-arrow:hover::before {
-  color: #37465b;
+  color: #8c0c0c;
 }

 /**
@@ -249,6 +266,7 @@ img[data-lazy] {
 .slide__media {
   overflow: hidden;
   position: relative;
+  opacity:0.75
 }

 /* Center the image to reduce gap at RHS with smaller image, larger container */
@@ -274,3 +292,8 @@ img[data-lazy] {
 .slick--less .draggable {
   cursor: default;
 }
+
+.slick-dots
+{
+    bottom: -25px;
+}
diff --git a/docroot/modules/contrib/slick/templates/slick-slide.html.twig b/docroot/modules/contrib/slick/templates/slick-slide.html.twig
index 987a6c471..6e368485a 100644
--- a/docroot/modules/contrib/slick/templates/slick-slide.html.twig
+++ b/docroot/modules/contrib/slick/templates/slick-slide.html.twig
@@ -73,6 +73,22 @@
             <p class="slide__description">{{ item.caption.alt }}</p>
           {% endif %}

+          {% if item.caption.caption_img %}
+            <p class="slide__description" >{{ item.caption.caption_img }}</p>
+          {% endif %}
+
+          {% if item.caption.caption_p_cta_url %}
+            <a class="primaryCta__button primaryCta__button--" href={{ item.caption.caption_p_cta_url }} aria-label="button" type="button">
+              {{ item.caption.caption_p_cta }}
+            </a>
+          {% endif %}
+
+          {% if item.caption.caption_s_cta_url %}
+            <a class="secondaryCta__button secondaryCta__button--" href={{ item.caption.caption_s_cta_url }} aria-label="button" type="button">
+              {{ item.caption.caption_s_cta }}
+            </a>
+          {% endif %}
+
           {% if item.caption.data %}
             <div class="slide__description">{{ item.caption.data }}</div>
           {% endif %}
diff --git a/docroot/modules/contrib/slick/templates/slick.theme.inc b/docroot/modules/contrib/slick/templates/slick.theme.inc
index b0bf8f512..6afe4f92c 100644
--- a/docroot/modules/contrib/slick/templates/slick.theme.inc
+++ b/docroot/modules/contrib/slick/templates/slick.theme.inc
@@ -10,6 +10,9 @@
 use Drupal\blazy\Blazy;
 use Drupal\slick\SlickDefault;
 use Drupal\slick\Entity\Slick;
+use Drupal\image_field_caption\ImageCaptionStorage;
+use Drupal\image_field_caption\ImageCaptionItem;
+use Drupal\image_field_caption\ImageFieldCaption;

 /**
  * Prepares variables for slick.html.twig templates.
@@ -100,6 +103,7 @@ function template_preprocess_slick(&$variables) {

   // Process individual item.
   $variables['items'] = [];
+  $i=0;
   foreach ($element['#items'] as $delta => $item) {
     $item_settings = array_merge($settings, (array) ($item['settings'] ?? []));
     $item_attrs = (array) ($item['attributes'] ?? []);
@@ -116,9 +120,15 @@ function template_preprocess_slick(&$variables) {
       '#settings' => $item_settings,
       '#attributes' => $item_attrs,
       '#content_attributes' => $content_attrs,
+      '#caption_img' => $variables['element']['#items'][$i]['item']->caption,
+      '#caption_p_cta' => $variables['element']['#items'][$i]['item']->primary_cta,
+      '#caption_p_cta_url' => $variables['element']['#items'][$i]['item']->primary_cta_url,
+      '#caption_s_cta' => $variables['element']['#items'][$i]['item']->secondary_cta,
+      '#caption_s_cta_url' => $variables['element']['#items'][$i]['item']->secondary_cta_url,
     ];
     $variables['items'][$delta] = $slide;
     unset($slide);
+    $i++;
   }
 }

@@ -136,7 +146,7 @@ function template_preprocess_slick_wrapper(&$variables) {
  */
 function _slick_preprocess_slick_item(&$variables) {
   $element = $variables['element'];
-  foreach (['attributes', 'content_attributes', 'delta', 'item', 'settings'] as $key) {
+  foreach (['attributes', 'content_attributes', 'delta', 'item', 'settings', 'caption_img', 'caption_p_cta', 'caption_p_cta_url', 'caption_s_cta', 'caption_s_cta_url'] as $key) {
     $default = $key == 'delta' ? NULL : [];
     $variables[$key] = $element["#$key"] ?? $default;
   }
@@ -168,8 +178,20 @@ function template_preprocess_slick_slide(&$variables) {
   _slick_preprocess_slick_item($variables);

   // All slide types -- main, thumbnail, grid, overlay -- may have captions.
-  foreach (['alt', 'data', 'link', 'overlay', 'title'] as $key) {
-    $variables['item']['caption'][$key] = $variables['item']['caption'][$key] ?? [];
+  foreach (['alt', 'data', 'link', 'overlay', 'title', 'caption_img', 'caption_p_cta', 'caption_p_cta_url', 'caption_s_cta', 'caption_s_cta_url'] as $key) {
+    if($key =='caption_img'){
+      $variables['item']['caption'][$key] = $variables['caption_img'] ?? [];
+    } else if ($key == 'caption_p_cta') {
+      $variables['item']['caption'][$key] = $variables['caption_p_cta'] ?? [];
+    } else if ($key == 'caption_p_cta_url') {
+      $variables['item']['caption'][$key] = $variables['caption_p_cta_url'] ?? [];
+    } else if ($key == 'caption_s_cta') {
+      $variables['item']['caption'][$key] = $variables['caption_s_cta'] ?? [];
+    } else if ($key == 'caption_s_cta_url') {
+      $variables['item']['caption'][$key] = $variables['caption_s_cta_url'] ?? [];
+    } else  {
+      $variables['item']['caption'][$key] = $variables['item']['caption'][$key] ?? [];
+    }
   }

   $item = &$variables['item'];
@@ -183,7 +205,7 @@ function template_preprocess_slick_slide(&$variables) {
   $item['slide']     = $item['slide'] ?? [];
   $item['caption']   = array_filter($item['caption']);
   $sets['split']     = !empty($item) && (!empty($sets['caption']) || !empty($sets['title']));
-  $sets['data']      = !empty($item['caption']['alt']) || !empty($item['caption']['title']) || !empty($item['caption']['data']);
+  $sets['data']      = !empty($item['caption']['alt']) || !empty($item['caption']['title']) || !empty($item['caption']['data']) || !empty($item['caption']['image_field_caption']);
   $sets['fullwidth'] = !empty($sets['skin']) && strpos($sets['skin'], 'full') !== FALSE;
   $sets['grid']      = empty($sets['grid']) ? FALSE : $sets['grid'];
   $sets['detroy']    = $sets['current_item'] == 'main' && !empty($sets['grid']) && !empty($sets['unslick']);

```

composer.json code

```
{
    "name": "******",
    "description": "*******",
    "license": "proprietary",
    "authors": [
        {
            "name": "**********",
            "email": "********"
        }
    ],
    "type": "project",
    "minimum-stability": "dev",
    "prefer-stable": true,
    "require-dev": {
        "behat/behat": "3.6.1",
        "behat/mink-extension": "^2.3",
        "behat/mink-goutte-driver": "^1.2",
        "composer/composer": "^2",
        "consolidation/config": "1.2.1",
        "deployer/dist": "^6.8",
        "deployer/recipes": "^6.2",
        "dmore/behat-chrome-extension": "^1.3",
        "dmore/chrome-mink-driver": "2.7.0",
        "drupal/coder": "8.3.8",
        "drupal/drupal-extension": "^4.1",
        "drush/drush": "^10.6",
        "kint-php/kint": "^3.3",
        "mglaman/drupal-check": "^1.2",
        "mikey179/vfsstream": "1.6.8",
        "mouf/nodejs-installer": "1.0.14",
        "phpunit/phpunit": "^9.5",
        "symfony/css-selector": "^3.0",
        "symfony/phpunit-bridge": "^5.2",
        "widgetsburritos/drupal-patch-checker": "^2.0"
    },
    "require": {
        "algolia/places": "1.19.0",
        "choices/choices": "9.0.1",
        "ckeditor/autogrow": "4.16.2",
        "ckeditor/codemirror": "v1.17.12",
        "ckeditor/fakeobjects": "4.16.2",
        "ckeditor/image": "4.16.2",
        "ckeditor/link": "4.16.2",
        "codemirror/codemirror": "5.57.0",
        "composer/installers": "^1.9",
        "cweagans/composer-patches": "1.x-dev#4f3414441522dfeecff697f061ce27412a2b677b",
        "drupal/advban": "^1.3",
        "drupal/akamai": "^4.0",
        "drupal/auditfiles": "^3.0",
        "drupal/autoban": "^1.6",
        "drupal/better_exposed_filters": "^5.0",
        "drupal/blazy": "^2.13",
        "drupal/captcha": "^1.0",
        "drupal/google_tag": "^1.3",
        "drupal/image_field_caption": "^1.2",
        "drupal/lazy": "^3.2",
        "drupal/lb_settings_report": "1.0.x-dev",
        "drupal/libraries": "3.x-dev#3b7ae61a8e68ce37638b313eaccf4febaa48e3fa",
        "drupal/path_redirect_import": "^1.0",
        "drupal/pathauto": "^1.8",
        "drupal/slick": "^2.7",
        "drupal/slick_extras": "^1.0@RC",
        "drupal/slick_views": "^2.6",
        "drupal/smtp": "^1.0",
        "drupal/stage_file_proxy": "^1.0",
        "drupal/textfield_counter": "^2.0",
        "drupal/tmgmt": "^1.10",
        "drupal/tmgmt_smartling": "^4.8",
        "drupal/token": "1.x-dev#195fca31519225d63f5b543a4e6b039931bfc6ef",
        "drupal/token_custom": "^1.0"

    },
    "repositories": {
        "0": {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        },
        "1": {
            "type": "composer",
            "url": "https://asset-packagist.org"
        },
        "ckeditor.image": {
            "_webform": true,
            "type": "package",
            "package": {
                "name": "ckeditor/image",
                "version": "4.16.2",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "ckeditor.image"
                },
                "dist": {
                    "url": "https://download.ckeditor.com/image/releases/image_4.16.2.zip",
                    "type": "zip"
                }
            }
        },
        "jquery.inputmask": {
            "_webform": true,
            "type": "package",
            "package": {
                "name": "jquery/inputmask",
                "version": "5.0.5",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "jquery.inputmask"
                },
                "dist": {
                    "url": "https://github.com/RobinHerbots/jquery.inputmask/archive/5.0.5.zip",
                    "type": "zip"
                }
            }
        },
        "signature_pad": {
            "_webform": true,
            "type": "package",
            "package": {
                "name": "signature_pad/signature_pad",
                "version": "2.3.0",
                "type": "drupal-library",
                "extra": {
                    "installer-name": "signature_pad"
                },
                "dist": {
                    "url": "https://github.com/szimek/signature_pad/archive/v2.3.0.zip",
                    "type": "zip"
                }
            }
        }
    },
    "scripts": {
        "post-install-cmd": [
            "Composer\\Config::disableProcessTimeout",
            "scripts/post-install.sh",
            "npm ci"
        ],
        "post-update-cmd": [
            "Composer\\Config::disableProcessTimeout",
            "scripts/post-install.sh",
            "npm install"
        ],
        "npm": [
            "npm"
        ],
        "check:patch": [
            "WidgetsBurritos\\DrupalPatchChecker\\DrupalPatchChecker::checkComposerFile"
        ]
    },
    "config": {
        "bin-dir": "bin/",
        "sort-packages": true,
        "platform": {
            "php": "7.3"
        },
        "allow-plugins": {
            "composer/installers": true,
            "cweagans/composer-patches": true,
            "drupal/core-composer-scaffold": true,
            "oomphinc/composer-installers-extender": true,
            "mouf/nodejs-installer": true,
            "widgetsburritos/drupal-patch-checker": true
        }

    },
    "extra": {
        "composer-patches-skip-reporting": true,
        "drupal-scaffold": {
            "locations": {
                "web-root": "docroot"
            },
            "file-mapping": {
                "[web-root]/robots.txt": false,
                "[web-root]/sites/development.services.yml": false,
                "[web-root]/sites/example.settings.local.php": false,
                "[web-root]/sites/example.sites.php": false,
                "[web-root]/web.config": false
            }
        },
        "drush": {
            "services": {
                "drush.services.yml": "^9"
            }
        },
        "installer-types": [
            "rs-library",
            "npm-asset"
        ],
        "installer-paths": {
            "docroot/core": [
                "type:drupal-core"
            ],
            "docroot/libraries/{$name}": [
                "type:drupal-library",
                "type:npm-asset"
            ],
            "docroot/modules/contrib/{$name}": [
                "type:drupal-module"
            ],
            "docroot/profiles/contrib/{$name}": [
                "type:drupal-profile"
            ]
        },
        "mouf": {
            "nodejs": {
                "version": "14.10.1",
                "forceLocal": true,
                "includeBinInPath": true
            }
        },
        "enable-patching": true,
        "composer-exit-on-patch-failure": true,
        "patches": {
            "dmore/chrome-mink-driver": {
                "https://github.com/acquia/blt/issues/3224": "patches/drupal-extension/chrome-mink-driver.patch"
            },
            "drupal/core": {
                "3114365 - Vocabulary name not shown in View for Anonymous Users": "patches/core/taxonomy_vocabulary_view_permission-3114365.patch",
                "3190265 - guessMimeType declaration not compatible with Symfony interface": "patches/core/3190265-2.patch",
                "3114467 - 'Negate' form value for condition plugins should be cast to boolean in validation.": "patches/core/3114467-16.patch"
            },
            "drupal/advanced_text_formatter": {
                "3072029 - Untrimmed text before normalizing can return empty spaces in the event that no html tags are allowed": "patches/advanced_text_formatter/advanced-text-formatter-3072029.patch",
                "3068628 - Drupal 9 Deprecated Code Report": "patches/advanced_text_formatter/3068628-11.patch"
            },
            "drupal/entity_embed": {
                "3069448 - Array to string conversion for Media Image": "patches/entity_embed/entity-embed-array-to-string--3069448-19.patch"
            },
            "drupal/yoast_seo": {
                "3119603 - Drupal 9 readiness": "patches/yoast_seo/3119603-14.patch"
            },
            "drush/drush": {
                "3572 - `drush cex` doesn't remove `language` directory when it should": "patches/drush/drush-ops_drush-3572.patch"
            },
            "drupal/slick": {
                "MTE-8015 - Slick slider changes 1": "patches/slick/slick.patch"
            }
        }
    },
    "version": "9.2.43"
}

```

How to apply patch for .install file? Here is the patch code for .install file

```
diff --git a/image_field_caption/image_field_caption.install b/image_field_caption/image_field_caption.install
index b339c7a87..25a098b4f 100644
--- a/image_field_caption/image_field_caption.install
+++ b/image_field_caption/image_field_caption.install
@@ -70,6 +70,34 @@ function image_field_caption_schema() {
         'length' => 255,
         'not null' => FALSE,
       ),
+      'primary_cta' => array(
+        'description' => 'The primary cta.',
+        'type' => 'text',
+        'length' => 25,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
+      'primary_cta_url' => array(
+        'description' => 'The primary cta url.',
+        'type' => 'text',
+        'length' => 250,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
+      'secondary_cta' => array(
+        'description' => 'The secondary cta.',
+        'type' => 'text',
+        'length' => 25,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
+      'secondary_cta_url' => array(
+        'description' => 'The secondary cta url.',
+        'type' => 'text',
+        'length' => 25,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
     ),
     'indexes' => array(
       'entity_type' => array('entity_type'),
@@ -148,6 +176,34 @@ function image_field_caption_schema() {
         'length' => 255,
         'not null' => FALSE,
       ),
+      'primary_cta' => array(
+        'description' => 'The primary cta.',
+        'type' => 'text',
+        'length' => 25,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
+      'primary_cta_url' => array(
+        'description' => 'The primary cta url.',
+        'type' => 'text',
+        'length' => 250,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
+      'secondary_cta' => array(
+        'description' => 'The secondary cta.',
+        'type' => 'text',
+        'length' => 25,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
+      'secondary_cta_url' => array(
+        'description' => 'The secondary cta url.',
+        'type' => 'text',
+        'length' => 25,
+        'not null' => TRUE,
+        'default' => 'PCTA',
+      ),
     ),
     'indexes' => array(
       'entity_type' => array('entity_type'),

```

When i release code to staging it shows error "Drupal\Core\Database\DatabaseExceptionWrapper. SQLSTATE(42502):Base table or view not found: 1146 Table 'www.image\_field\_caption'. dosent exist: SELECT Distinct 'ifc'.'entity\_type' AS 'entity\_type' FROM 'image\_field\_caption' 'ifc'.Array() in Drupal\image\_field\_caption\ImageCaptionStorage-\>list()(line 425 of module/contrib/image\_field\_caption/src/ImageCaptionStorage.php)"

below is the ImageCaptionStorage.php code its shows error for function "public function list(){ ... -\>execute() ...}"

```
<?php

/**
 * @file
 * Contains \Drupal\image_field_caption\ImageCaptionStorage.
 */

namespace Drupal\image_field_caption;

use Drupal\Core\Database\Connection;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheTagsInvalidator;

class ImageCaptionStorage {

  protected $cacheBackend;
  protected $cacheTagsInvalidator;
  protected $database;
  protected $tableData = 'image_field_caption';
  protected $tableRevision = 'image_field_caption_revision';
  public function __construct(
        CacheBackendInterface $cacheBackend,
        CacheTagsInvalidator $cacheTagsInvalidator,
        Connection $database
    ) {
    $this->cacheBackend = $cacheBackend;
    $this->cacheTagsInvalidator = $cacheTagsInvalidator;
    $this->database = $database;
  }

  public function isCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta, $primary_cta, $primary_cta_url, $secondary_cta, $secondary_cta_url) {
    return (!empty(self::getCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta, $primary_cta, $primary_cta_url, $secondary_cta, $secondary_cta_url))) ? TRUE : FALSE;
  }

  public function getCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta, $primary_cta, $primary_cta_url, $secondary_cta, $secondary_cta_url) {
    $captions = &drupal_static(__FUNCTION__);

    $cacheKey = $this->getCacheKey($entity_type, $entity_id, $revision_id, $language, $field_name, $delta, $primary_cta, $primary_cta_url, $secondary_cta, $secondary_cta_url);

    if (isset($captions[$cacheKey])) {
      $caption = $captions[$cacheKey];
    }
    elseif ($cached = $this->cacheBackend->get($cacheKey)) {
      $caption = $cached->data;
    }
    else {
      // Query.
      $query = $this->database->select($this->tableData, 'ifc');
      $result = $query
              ->fields('ifc', array('caption', 'caption_format', 'primary_cta', 'primary_cta_url', 'secondary_cta', 'secondary_cta_url'))
              ->condition('entity_type', $entity_type, '=')
              ->condition('bundle', $bundle, '=')
              ->condition('field_name', $field_name, '=')
              ->condition('entity_id', $entity_id, '=')
              ->condition('revision_id', $revision_id, '=')
              ->condition('language', $language, '=')
              ->condition('delta', $delta, '=')
              ->execute()
              ->fetchAssoc();

      // Caption array.
      $caption = array();
      if (!empty($result)) {
        $caption = $result;
      }

      // Let the cache depends on the entity.
      // TODO: Use getCacheTags() to get the default list.
      $this->cacheBackend->set(
            $cacheKey,
            $caption,
            Cache::PERMANENT,
            [
              $field_name,
              'image_field_caption',
            ]
        );
    }

    return $caption;
  }

  public function insertCaption($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta, $caption, $caption_format, $primary_cta, $primary_cta_url, $secondary_cta, $secondary_cta_url) {

    $query = $this->database->insert($this->tableData);
    $query
          ->fields(array(
            'entity_type' => $entity_type,
            'bundle' => $bundle,
            'field_name' => $field_name,
            'entity_id' => $entity_id,
            'revision_id' => $revision_id,
            'language' => $language,
            'delta' => $delta,
            'caption' => $caption,
            'caption_format' => $caption_format,
            'primary_cta' => $primary_cta,
            'primary_cta_url' => $primary_cta_url,
            'secondary_cta' => $secondary_cta,
            'secondary_cta_url' => $secondary_cta_url,
          ))
      ->execute();
    $this->clearCache($field_name);
  }

  public function insertCaptionRevision($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language, $delta, $caption, $caption_format, $primary_cta, $primary_cta_url, $secondary_cta, $secondary_cta_url) {
    $query = $this->database->insert($this->tableRevision);
    $query
          ->fields(array(
            'entity_type' => $entity_type,
            'bundle' => $bundle,
            'field_name' => $field_name,
            'entity_id' => $entity_id,
            'revision_id' => $revision_id,
            'language' => $language,
            'delta' => $delta,
            'caption' => $caption,
            'caption_format' => $caption_format,
            'primary_cta' => $primary_cta,
            'primary_cta_url' => $primary_cta_url,
            'secondary_cta' => $secondary_cta,
            'secondary_cta_url' => $secondary_cta_url,
          ))
      ->execute();
    $this->clearCache($field_name);
  }

  public function deleteCaption($entity_type, $bundle, $field_name, $entity_id, $language) {
    $query = $this->database->delete($this->tableData);
    $query
          ->condition('entity_type', $entity_type, '=')
          ->condition('bundle', $bundle, '=')
          ->condition('field_name', $field_name, '=')
          ->condition('entity_id', $entity_id, '=')
          ->condition('language', $language, '=')
          ->execute();
    $this->clearCache($field_name);
    // @todo Try to return the count of the affected rows.
  }

  public function deleteCaptionRevision($entity_type, $bundle, $field_name, $entity_id, $revision_id, $language) {
    $query = $this->database->delete($this->tableRevision);
    $query
      ->condition('entity_type', $entity_type, '=')
      ->condition('bundle', $bundle, '=')
      ->condition('field_name', $field_name, '=')
      ->condition('entity_id', $entity_id, '=')
      ->condition('revision_id', $revision_id, '=')
      ->condition('language', $language, '=')
      ->execute();
    $this->clearCache($field_name);
    // @todo Try to return the count of the affected rows.
  }

  public function deleteCaptionRevisions($entity_type, $bundle, $field_name, $entity_id, $language) {
    $query = $this->database->delete($this->tableRevision);
    $query
      ->condition('entity_type', $entity_type, '=')
      ->condition('bundle', $bundle, '=')
      ->condition('field_name', $field_name, '=')
      ->condition('entity_id', $entity_id, '=')
      ->condition('language', $language, '=')
      ->execute();
    $this->clearCache($field_name);
    // @todo Try to return the count of the affected rows.
  }

  public function deleteCaptionRevisionsByRevisionId($revision_id) {
    $query = $this->database->delete($this->tableRevision);
    $query
      ->condition('revision_id', $revision_id, '=')
      ->execute();
  }

  public function clearCache($field_name) {
    $this->cacheTagsInvalidator->invalidateTags([
      $field_name,
      'image_field_caption',
    ]);
  }

  public function getCacheKey($entity_type, $entity_id, $revision_id, $language, $field_name, $delta, $primary_cta, $primary_cta_url, $secondary_cta, $secondary_cta_url) {
    return implode(
        ":",
        [
          'caption',
          $entity_type,
          $entity_id,
          $revision_id,
          $language,
          $field_name,
          $delta,
          $primary_cta,
          $primary_cta_url,
          $secondary_cta,
          $secondary_cta_url,
        ]
    );
  }

  public function list($key = 'entity_type') {
      $list = &drupal_static(__FUNCTION__);

      if (!isset($list[$key])) {
          // Query.
          $query = $this->database->select($this->tableData, 'ifc');
          $result = $query
              ->fields('ifc', array($key))
              ->distinct()
              ->execute()
              ->fetchAll();

          $list[$key] = [];
          foreach ($result as $row) {
              $list[$key][] = $row->{$key};
          }
      }

      return $list[$key];
  }

}

```

# Answer
> 5 votes
A few things to know up-front:

1. Composer patches has the concept of `patch-levels`. These correspond to the `[-p strip-count]` option of the `patch` command (and same for `git apply`).

If you're not familiar with that option, it basically tells `patch` how many portions of the file path to strip off to find the files being patched. Or in other words, how many forward slashes and their preceding strings should be removed from the start of the path string.
2. The package (module)'s path is used as the working directory for applying a patch (not the project root).
3. By default, the plugin will make different attempts to apply the patch, in this order, failing silently until they're all exhausted:

* -p1
    * -p0
    * -p2
    * -p4

These are presumably the most common.

If you look at the paths in your patch:

```
diff --git a/docroot/modules/contrib/slick/css/layout/slick.module.css b/docroot/modules/contrib/slick/css/layout/slick.module.css

```

And apply the rules above, you need to remove 5 slashes to get the correct path (not 1, 0, 2, or 4), so the default fails.

There are two ways to fix:

1. Change the paths in the patch file to, e.g.

```
diff --git a/css/layout/slick.module.css b/css/layout/slick.module.css

```

Above will satisfy `-p1`, you could also change it to match a different level
2. Set the `patchLevel` manually for the project in composer.json:

```
"extra": {
  ...
  "patchLevel": {
    ...
    "drupal/slick: "-p5"
  }
}

```

If you use the second option, keep in mind it will apply to any patch you use for that module, so mixing local patches with ones from drupal.org won't work. The first option is probably best for predictability.

For future reference, you can create your patches with `-p1` compatibility by using git options:

```
git -C path/to/modified/module diff --relative

```

This would get you the same as the first fix above:

```
diff --git a/css/layout/slick.module.css b/css/layout/slick.module.css

```

# Answer
> 1 votes
As already pointed out, it should be `./patches/` if you have the patches folder in the Drupal root directory.

Furthermore, I see you're using a dev version that is fixed so it cannot be updated

```
"cweagans/composer-patches": "1.x-dev#4f3414441522dfeecff697f061ce27412a2b677b",

```

Instead, it should be

```
"cweagans/composer-patches": "^1.7",

```

So do the following:

1. Remove the patch code part

```
        ,
        "drupal/slick": {
            "MTE-8015 - Slick slider changes 1": "./patches/slick/slick.patch"
        }

```
2. Remove `composer remove cweagans/composer-patches`
3. Re-add `composer require cweagans/composer-patches`

* This should install 1.7 version. If not, do `composer require cweagans/composer-patches:^1.7`
4. Re-add the patch code from #1
5. Delete the module folder `sudo rm -rf web/modules/contrib/slick/`

Not sure if it's just me, but I could've sworn step #5 wasn't necessary! I just did this routine 2 days ago.. Updating the patches section alone should be good enough. But for some reason it's not working for me today. I think something funky must be going on somewhere... or I'm just not remembering correctly.

6. Run `composer update --lock` and it should apply your patch

---
Tags: composer
---


# Question
Title: Where can i find the path/URL of a module after installing it?
I just installed two modules on a Drupal 9 site: https://www.drupal.org/project/simple\_forum and https://www.drupal.org/project/answers.

I want to get the URL where all posts/questions are listed and use it in a menu, but I cannot find where those are. The only thing I found is the URL for creating new posts and questions.

# Answer
You can look at the routing file for modules to determine the paths the module declares. In your case you will look at `simple_forum.routing.yml` and `project_answers.routing.yml`. Look at the `path` key for the various entries.
> 3 votes

# Answer
Instead of looking for the routes individually module by module, you can install the Devel module temporarily in your local environment (never use on a production server) and go to `/devel/routes` to get a list of all routes currently active for the site.
> 1 votes

# Answer
> I want to get the URL where all posts/questions are listed and use it in a menu

To answer your question, for those 2 specific modules, there simply isn't one. Those 2 modules do not provide any.

You can always use Views to create a page view and add title and comment count as fields and format its display as a table.
> 1 votes

---
Tags: routes, 9
---


# Question
Title: How to do dependency injection for ConstraintValidator?
After upgrading to Drupal 10, running the coding standards check suggested that I could use DI in my validation constraints.

For example, this simple one:

```
<?php

declare(strict_types=1);

namespace Drupal\my_module\Plugin\Validation\Constraint;

use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * Validates the DateTimeMidnightOnly constraint.
 */
class DateTimeMidnightOnlyValidator extends ConstraintValidator {

  /**
   * {@inheritdoc}
   */
  public function validate(mixed $value, Constraint $constraint): void {
    foreach ($value as $item) {
      if (!$this->isMidnight($item->value)) {
        $item_value = $item->value;
        \Drupal::logger('my_custom_error_channel')->error("Invalid midnight timestamp! $item_value");
        $this->context->addViolation($constraint->notMidnight, ['%value' => $item_value]);
      }
    }
  }

  /**
   * Is the DateTime string midnight?
   *
   * @param string $value
   *   The DateTime string.
   *
   * @returns bool
   *   TRUE if it is a midnight string.
   */
  private function isMidnight(string $value): bool {
    return str_ends_with($value, 'T00:00:00');
  }

}

```

So I tried injecting the logger:

```
  /**
   * Logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected LoggerChannelFactoryInterface $loggerFactory;

  /**
   * Constructs DateTimeMidnightOnlyValidator.
   *
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger factory.
   */
  public function __construct(LoggerChannelFactoryInterface $logger_factory) {
    $this->loggerFactory = $logger_factory;
  }

```

This results in an error:

> ArgumentCountError: Too few arguments to function Drupal\custom\_module\Plugin\Validation\Constraint\DateTimeMidnightOnlyValidator::\__construct(), 0 passed in /var/www/html/web/core/lib/Drupal/Core/DependencyInjection/ClassResolver.php on line 31 and exactly 1 expected

So I need to pass the argument-- how do I do that? For custom services I know I can use `mymodule.services.yml`, and for totally overriding core services I can use `MyModuleServiceProvider.php`, but what about validation constraints?

# Answer
> 5 votes
To pass the argument implement ContainerInjectionInterface::create().

For example:

```
class TaxonomyTermHierarchyConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  private $entityTypeManager;

  /**
   * Creates a new TaxonomyTermHierarchyConstraintValidator instance.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager')
    );
  }

...

```

Example from /core/modules/taxonomy/src/Plugin/Validation/Constraint/TaxonomyTermHierarchyConstraintValidator.php

---
Tags: dependency-injection, 10
---


# Question
Title: Why fails the comparsion between two identical version numbers in this script?
I try to compare in a Script two different version numbers of Drupal via `drush status`. The result should be printed out in a if-else. I made a minimal example:

```
# put paths in vars
WEBSITE_ROOT_LIVE=/PATH/TO/LIVE
WEBSITE_ROOT_TEST=/PATH/TO/DEV

# get the drupal version line from drupal status output
cd $WEBSITE_ROOT_TEST
test=$(drush status | grep "Drupal version")
cd $WEBSITE_ROOT_LIVE
live=$(drush status | grep "Drupal version")

# count chars in output
wc -c <<< $live
wc -c <<< $test

# print variables
echo $live
echo $test

# compare
if [ "$test" != "$live" ]
then
    echo "not equal"
else

    echo "equal"
fi

```

Strangely this is the output:

```
84
88
Drupal version : 9.5.0
Drupal version : 9.5.0
not equal

```

The difference in characters is the explanation, but why are they different? On one side the string has not so much chars, on the other side they are different length. Why is that so, and how can i fix this? I suspect the substitution within the shells `$()` syntax.

# Answer
The standard output of Drush is for humans.

For scripts use the Drush output options to select the field and output a string value:

```
drush status --fields=drupal-version --format=string

```

or shorter with `--field=FIELD` to select just one field, and force format to *string*.

```
drush status --field=drupal-version

```

See `drush help status`.
> 2 votes

---
Tags: drush, updating
---


# Question
Title: Shared sites/all/libraries/ directory is not recognized by contrib modules
I'm trying to put the `colorbox` javascript library to the shared `sites/all/libraries` directory but it is not recognized by the `colorbox` module. The same seems to go for the `jquery.cycle` library. I just copied the `libraries` directory from sites/nias.cz/libraries\` to the shared one. The final example path is

```
sites/all/libraries/colorbox/jquery.colorbox.js

```

# Answer
> 1 votes
Libraries have changed since Drupal 7. Libraries are no longer stored in *sites/all/libraries*. Drupal 8+ uses Composer and stores third-party libraries in *libraries*.

---
Tags: 9, multi-sites
---


# Question
Title: How to retrieve GET parameter in Twig template
I'm attempting to retrieve a GET request variable for use in a twig template. For instance if you go to the page myurl.com/node/64?name=Dave I want the page to render

```
<h1>Dave</h1>

```

However I'm having trouble retrieving this variable. I've attempted

```
<h1>{{app.request.get('name')}}</h1>

```

In my twig template but it turns up empty. How would I retrieve a GET variable from within a twig template?

# Answer
You didn't say what template this is for, but `app` is not defined in any of the templates I have seen.

What you could do, is add a theme\_preprocess\_TEMPLATE function to include the GET params. Here is a page template example:

In your mytheme.theme file, add a hook\_preprocess\_page function.

```
/**
 * Implements hook_preprocess_page()
 */
function MYTHEME_preprocess_page(&$vars) {
  $vars['get']['name'] = $_GET['name'];
}

```

Then in your page.html.twig you can render it like this:

```
<h1>{{ get.name }}</h1>

```
> 16 votes

# Answer
You can create a Twig function to achieve this. E.g:

```
namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class AppExtension extends AbstractExtension
{
    public function getFunctions()
    {
        return [
            new TwigFunction('getQueryArg', [$this, 'getQueryArg']),
        ];
    }

    public function getQueryArg(string $argName): string|int {
      return \Drupal::request()->query->get($argName);
    }
}

```

In TWIG you would call it as: `{{ getQueryArg('name') }}`

See https://symfony.com/doc/current/templating/twig\_extension.html
> 0 votes

---
Tags: theming, 8
---


title: Print field of taxonomy term in twig

text:
# Question
Title: Print field of taxonomy term in twig
I have a taxonomy term called Event type. Inside that term I have a Color field. I want to pass the HEX value of the Color field as a variable in Twig.

The taxonomy term variable in Twig (on node level) looks something like this

```
{{ content.field_event_type }}

```

So in order to access the field that exists inside that term, I would need something like this

```
{{ content.field_event_type.field_color_field.value }}

```

But I can't seem to make it work.

How do I do this? Thank you.

# Answer
> 0 votes
Just for anyone else having a brain malfunction like me and wanted to print a taxonomy term that had been selected and not 1 specific term like all the other posts, do this:

```
{{ node.field_name.entity.label }}

```

---
Tags: taxonomy-terms
---


# Question
Title: Drush commands not defined - drush 11.4.0 drupal 9.5.1
This configuration is working properly on xampp local install (drush version)

`Drupal version : 9.5.1
DB driver : mysql
DB hostname : localhost
DB port : 3306
Database : Connected
Drupal bootstrap : Successful
PHP binary : C:/xampp/php/php.exe
PHP config : C:/xampp/php/php.ini
PHP OS : WINNT
PHP version : 7.4.27
Drush script : C:/xampp/htdocs/mysite/vendor/drush/drush/drush
Drush version : 11.4.0`

But on webserver, any drush command I type (for example cr) returns a "Command "cr" is not defined." Drush was installed via composer global require drush/drush (also exists as vendor/bin/drush in website root with same behavior)

drush list returns :

`Available commands:
help Display help for a command
list List commands` I think I have pretty much the same config on another webserver with no such problem. Any ideas on that ?

# Answer
Drush used to be installed globally, but that will no longer work. Instead, Drush LAUNCHER is installed globally. This creates a global `drush` command, however it does not contain the Drush code itself. The Drush code is instead added to each project on a per-project basis, managed using composer. When calling `drush`, Drush Launcher will take your current working directory, determine if it is a Drupal installation, and if it is, look for Drush in the vendor folder, and execute that on the current Drupal installation.
> 2 votes

---
Tags: drush
---


# Question
Title: How can I find out if all my contrib modules are compatible with the latest core version?
I have quite a number of Drupal modules on my Drupal 9 website and I want to update my Drupal core to the latest, but I'm not sure if this would break the entire site if one of the modules isn't compatible with the latest core version.

I can go to each module page individually to check, but is there a quick command in the CLI to find out? `drush pm-list` doesn't really seem to help.

# Answer
> 8 votes
If by "latest core version" you mean moving from one major version to another (for example, 9 to 10), you can use the Upgrade Status module.

In addition to telling you whether each contrib module is compatible with the new version, you can scan your custom modules and contrib modules to look for compatibility issues.

You can use Upgrade Status from drush, too:

`drush upgrade_status:analyze`

# Answer
> -1 votes
You can install Drupal Rector which can save you a lot of manual work by automating code upgrades to Drupal 10. Run the following command from the project root directory:

```
composer require --dev palantirnet/drupal-rector

```

Here is the official documentation about Drupal Rector: https://www.drupal.org/project/rector

While Drupal Rector has very good transformation coverage for deprecated APIs, the results should not be considered complete. For the Drupal Rector UI version, you can also download Upgrade Rector module.

---
Tags: 10
---


# Question
Title: How can I return a templated response from an Exception Event subscriber?
I'm currently using an Event Subscriber to catch exceptions and return a plain-text message response to the user (instead of the default white screen of death).

Is there a way to return a templated response (using the site's theme, similar to a Controller's response) from the event subscriber in Drupal 9/10?

# Answer
This depends on the exceptions you want to catch.

Example for 5xx HTTP exceptions:

```
namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

/**
 * Exception subscriber for handling 5xx exceptions
 */
class MymoduleExceptionSubscriber extends DefaultExceptionHtmlSubscriber {

  protected static function getPriority() {
    return -129;
  }

  protected function getHandledFormats() {
    return ['html'];
  }

  /**
   * Handles a 5xx error for HTML.
   *
   * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
   *   The event to process.
   */
  public function on5xx(ExceptionEvent $event) {
    if (($exception = $event->getThrowable()) && $exception instanceof HttpExceptionInterface) {
      $this->makeSubrequest($event, '/my5xxcontroller', $exception->getStatusCode());
    }
  }

}

```

Example for all exceptions (only for demonstration purpose, better check for the exceptions you want to catch):

```
namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

/**
 * Exception subscriber for handling all exceptions
 */
class MymoduleExceptionSubscriber extends DefaultExceptionHtmlSubscriber {

  protected static function getPriority() {
    return -129;
  }

  protected function getHandledFormats() {
    return ['html'];
  }

  /**
   * Handles all exceptions for HTML
   *
   * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
   *   The event to process.
   */
  public function onException(ExceptionEvent $event) {
    $request = $event->getRequest();
    $handled_formats = $this->getHandledFormats();
    $format = $request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT, $request->getRequestFormat());
    if (empty($handled_formats) || in_array($format, $handled_formats)) {
      $this->makeSubrequest($event, '/my5xxcontroller', 500);
    }
  }

}

```

*mymodule.services.yml*

```
services:
  mymodule.5xx_subscriber:
    class: Drupal\mymodule\EventSubscriber\MymoduleExceptionSubscriber
    tags:
      - { name: event_subscriber }
    arguments: ['@http_kernel', '@logger.channel.php', '@redirect.destination', '@router.no_access_checks']

```
> 2 votes

---
Tags: event-subscribers
---


# Question
Title: How to determine reason for unprocessed files in Drupal to Drupal migration
Finally ran my first file migration from Drupal 6 to Drupal 7 using UI.

* 3100 Items
* 3036 Processed
* 62 Unprocessed
* 2498 messages

I am simply trying to figure out what those 62 files are, and why they did not process.

I looked at the "messages" link for the file migration task. They all say something like:

`2701 Informational Deleted documents from index with query id:"pyli4t/file/3782" OR sm_parent_document_id:"pyl4t/file/3782"` Don't know what to do with this, or how to query for unprocessed files.

I looked at the **migrate\_map\_43b7eadb1file** table for the migration task, but don't see anything that indicates what files were not processed.

I looked at the **migrate\_message\_43b7eadb1file** table and was able to locate the two files that failed using this SQL statement: `SELECT * FROM migrate_message_43b7eadb1file WHERE level != 4` But, nothing about unprocessed files.

That's all I can think to do. Any suggestions?

# Answer
It looks like this poster received an answer from the Drupal-to-Drupal data migration module maintainer over at drupal.org, so for convenience I will post it here:

Source:Issue#2476077: How to determine reason for unprocessed files

> Side issue first - that informational message is coming from some contrib module (something search-related, perhaps) and not related to migration per-se. Grep your codebase for "Deleted documents from index" to see what it might be.
>
> So, the unprocessed count is precisely the count of source records, minus the number of records in the map table (so, you will never find an "unprocessed" record in the map table. All processed records are recorded in the map table with an appropriate status.
>
> The first question is, are there really unprocessed records, or is the source count off? The most common cause of "unprocessed" records being reported is a malformed source query that has more than one row with the same primary key (fid in this case) - this can happen when joining to another table that has multiple rows per "base" row. Elsewhere you've been speaking about extending migrate\_d2d classes and modifying their queries - could you have done that for the file query, and joined to another table?
>
> The next step is to try to identify specific unprocessed files. If your D6 and D7 databases are on the same MySQL server and accessible with the same MySQL user, you can do something like:
>
> ```
> select d6.fid
> from d6.files f
> left join d7.migrate_map_myfilemigration map on f.fid=map.sourceid1
> where map.sourceid1 is null
>
> ```
>
> If the dbs are not on the same server, you could try dumping the D6 files table (or just the fids) and loading it into a temp table on the D7 server.
> 0 votes

# Answer
In our case the reason for the unprocessed items was that we were returning FALSE in our source plugin's `prepareRow` method, after calling `parent::prepareRow`.

The base method includes the following code to explicitly mark the row as ignored:

```
$this->idMap->saveIdMapping($row, [], MigrateIdMapInterface::STATUS_IGNORED);

```
> 0 votes

---
Tags: migrations
---


# Question
Title: How to easily alter an entity's base field definition per bundle
We are using the group module in Drupal 8, which introduces a custom entity "group". This entity features a "label" base field with the title "Title". As groups administrator, you can create several different group types, which are handled as fieldable bundles of the group entity and inherit its label base field.

Depending on the group type, we wish to override the generic label title within forms, views, templates, and so on to e.g. 'Label', 'Name', 'Branch', 'Department', 'Section', ...

However, the group entity does not expose the label title within its config form as the node module does. So we tried overriding the title using hook\_entity\_base\_field\_info\_alter() like this:

```
/**
 * Implements hook_entity_base_field_info_alter().
 */
function mymodule_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'group' && !empty($fields['label'])) {
    $fields['label']->setLabel(t('Name'));
  }
}

```

Which works, but changes the title for all bundles.

Our next try was hook\_entity\_bundle\_field\_info\_alter(). It exposes bundle information, but it does not allow for base fields to be altered. Trying to re-add the base field definition with a different title (in order to let the core merge the field definitions and override the base field definitions) caused different run-time exceptions.

So we ended up in manually altering form build arrays and widget titles, which may cause trouble later when the amount of group types is increasing.

How can we alter the base field's title on a per-bundle base without having to extend the group module or manually altering all occurrences of our group entities' field labels?

# Answer
Bundle specific labels for base fields are stored in `label` of a BaseFieldOverride config entity:

> Defines the base field override entity.
>
> Allows base fields to be overridden on the bundle level.
>
> Plugin annotation
>
> ```
> @ConfigEntityType(
>   id = "base_field_override",
>   label = @Translation("Base field override"),
>   handlers = {
>     "storage" = "Drupal\Core\Field\BaseFieldOverrideStorage",
>     "access" = "Drupal\Core\Field\BaseFieldOverrideAccessControlHandler",
>   },
>   config_prefix = "base_field_override",
>   entity_keys = {
>     "id" = "id",
>     "label" = "label"
>   },
>   config_export = {
>     "id",
>     "field_name",
>     "entity_type",
>     "bundle",
>     "label",
>     "description",
>     "required",
>     "translatable",
>     "default_value",
>     "default_value_callback",
>     "settings",
>     "field_type",
>   }
> )
>
> ```

When you get a base field from EntityFieldManager::getFieldDefinitions($entity\_type\_id, $bundle), set a new label for the field and save the field definition, then this label is not stored in the entity type (which would not be possible, because this is in code and the same for all bundles), but in the mentioned base field override.
> 10 votes

# Answer
The answer of @4k4 got us on the right track. For our solution, we primarily tried altering the labels for some programmatically provided base group types.

In order to help others with a similar use case, here is how we did it:

We implemented hook\_entity\_bundle\_field\_info() within the module that provided our group entity bundle and then used BaseFieldOverride to creating the field overrides:

```
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\Entity\BaseFieldOverride;

/**
 * Implements hook_entity_bundle_field_info().
 */
function ourgroupmodule_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  $fields = [];

  // Whether the hook implementation was called for our group type.
  if ($entity_type->id() == 'group' && $bundle == 'ourgroup' && !empty($base_field_definitions['label'])) {
    // Create a base field override with custom title.
    $field = BaseFieldOverride::createFromBaseFieldDefinition($base_field_definitions['label'], $bundle);
    $field->setLabel(t('Our group label title'));
    $fields['label'] = $field;
  }

  return $fields;
}

```

As further stated by @4k4, the override could be done within other places as well. E.g. in form submit handlers to override title labels of groups that are created within the admin UI.
> 9 votes

# Answer
Here's an implementation of `BaseFieldOverride` on a bundle form (using `ConfigEntityBundleBase` as the bundler entity, as suggested by Drupal Console `generate:entity:content`).

```
class CustomEntityTypeForm extends EntityForm {
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);
    /* ... */
    $form['target_bundles'] = [
      '#title' => $this->t('Node types this bundle supports.'),
      '#type' => 'checkboxes',
      '#options' => $node_type_options,
      '#default_value' => $this->entity->getTargetBundles() ?: [],
    ];
    return $form;
  }

  public function save(array $form, FormStateInterface $form_state) {
    /*...*/
    $field_manager = \Drupal::service('entity_field.manager');
    $definitions = $field_manager->getFieldDefinitions('attendance', $this->entity->id());

    /* the name of the base field is 'bundles' */
    if ($definitions['bundles'] instanceof BaseFieldOverride) {
      $override = $definitions['bundles'];
    }
    else {
      $override = BaseFieldOverride::createFromBaseFieldDefinition($definitions['bundles'], $this->entity->id());
    }

    /* my actual override just changes handler settings for an entity reference widget */
    $override->setSetting('handler_settings', ['bundles' => $this->entity->get('bundles')]);
    $override->save()

    /* Proceeds to saving the form normally */
  }

}

```
> 2 votes

# Answer
Building on @Capi Etheriel's answer, but making the naming clearer and fixing a bug when creating new bundles:

```
public function form(array $form, FormStateInterface $form_state) {
  $form = parent::form($form, $form_state);
  ...

  $form['my_bundle_property'] = [
    '#title' => $this->t('My Bundle property'),
    '#description' => $this->t('This will override the "my_overriden_setting" setting of the "my_overriden_field" field on "my_entity_type" that this is a bundle of.',
    '#type' => 'checkboxes',
    '#options' => ['option1', 'option2],
    '#default_value' => $this->entity->get('my_bundle_property),
  ];

  return $form;
}

public function save(array $form, FormStateInterface $form_state) {
  // You must save the entity first, or the override logic will break when adding new bundles.
  $this->entity->save();

  $field_manager = \Drupal::service('entity_field.manager');
  $definitions = $field_manager->getBaseFieldDefinitions('my_entity_type');
  $override = $definitions['my_overridden_field']->getConfig($this->entity->id());

  $override->setSetting('my_overriden_setting', $this->entity->get('my_overriden_field'));
  $override->save();

  ...
}

```
> 0 votes

---
Tags: 8, entities
---


# Question
Title: Override the default private file access
In the site I am developing, the private files directory is outside the document root.
I have a content type (*Chapter*) with a file field that stores its files in the private files directory. When a *Chapter* node is published, its file is accessible to users, but when the node is unpublished, its file is not accessible to users. They get an access denied page.

How can I control the access to the attached file and allow users to access the attached file when the node is unpublished, in a custom module?

# Answer
> 2 votes
With Drupal, the access to private files is determined by access to the entity to which they are attached. I would create a new media entity type, setting the file storage to be private. Then you can set up custom access rules for the entity type, using standard Drupal methodology. Users with access to that entity will be allowed to access the private file, and users without access to that entity will be denied access to the file. Then you can attach the media item to whichever node or other entity you need.

# Answer
> 0 votes
The expected normal behaviour described above does not seem to work. i Have had to :

```
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
use Drupal\user\Entity\User;
use Drupal\media\MediaInterface;

function my_module_media_access(MediaInterface $media, $op, AccountInterface $account) {

  if ($op !== 'view') {
    return AccessResult::neutral();
  }

  $user = User::load($account->id());
  if ($media->bundle() === 'media_private') {
    $acces = AccessResult::forbidden();
    if ($user->hasRole('private access people') || $user->hasRole('administrator')) {
      $acces = AccessResult::neutral();
    }
    return $acces;
  }
  return AccessResult::neutral();
}

```

---
Tags: files, 9
---


# Question
Title: Sub category wrongly classified to root level and cannot be rectified
I am using SHS (Simple hierarchical select) which allows the user to create the child term under the parent term by themselves. For example:

root --Canon (parent level) ----5D3 (child level)

When I checked on the taxonomy list, I found those child levels are wrongly classified to root level, instead of their parent levels (the brand).

Even if I changed them to be under the brand manually, it was still keeping the previous hierarchical relationship after the action.

I checked the database and confirmed everything looked normal in {taxonomy\_term\__parent}, where they did connect to the correct parent term ID.

How comes this issue and how can I fix them?

Drupal version: 8.9

# Answer
> 0 votes
Problem solved. It was because of the langcode in the database.

User created terms were all set as '1' instead of 'en'.

I fixed them by

```
UPDATE **** SET `langcode`= 'en'
```

---
Tags: taxonomy-terms
---


# Question
Title: How can I add a button to every row of custom column?
I have created a custom column in the content listing section using `hook_views_data()`. I want to add a button to the every row of that custom column. Can anyone help me with this issue?

```
function sortd_views_data() {
  $data['node_field_data']['SortdAction'] = [
    'title' => t('Sortd Action'),
    'help' => t('Manual Sync/Unsync articles.'),
    'field' => [
      'handler' => 'views_handler_field',
      'id' => 'numeric',
    ],
    'sort' => [
      'handler' => 'views_handler_sort',
      'click sortable' => TRUE,
    ],
    'filter' => [
      'handler' => 'views_handler_filter_string',
    ],
    'argument' => [
      'handler' => 'views_handler_argument_string',
    ],
  ];

  return $data;
}

```

The 0 show for every row needs to be replaced with the button.

>

I tried to solve the problem using the following code.

```
function sortd_preprocess_views_view_table(&$variables) {
  drupal_set_message($variables['rows']);
  if ($variables['view']->id() == 'content') {
    foreach ($variables['rows'] as &$row) {
      $row['SortdAction'] = [
        '#type' => 'submit',
        '#value' => t('Sortd'),
      ];
    }
  }
}

```

Whenever I try to print `$variables['row']`, it shows me the correct data in that table.

# Answer
> 1 votes
1. In /admin/structure/views/view/YOUR\_VIEW\_ID, add a new field (*Custom text*)
2. In your hook, use the following code

```
function sortd_preprocess_views_view_field(&$vars){
  if ($vars['view']->id() == 'YOUR_VIEW_ID') {
    if ($vars['field']->field == 'nothing') {
      $vars['output'] = [
        '#markup' => "<div class='dropbutton-wrapper dropbutton-multiple'><div><ul class='dropbutton'><li class='edit dropbutton-action'></li></ul></div></div>",
      ]
    }
  }
}

```
3. Clear the cache

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


# Question
Title: Sort nodes by weight of taxonomy term attached to field
In a query for nodes I'm trying to sort the nodes by the weight of a taxonomy term attached to one of the node fields.

Here is how my query is built

```
    $node_storage = \Drupal::entityTypeManager()
      ->getStorage('node');
    $my_query = $node_storage
      ->getQuery()
      ->accessCheck(FALSE)
      ->condition('type', 'my_content_type')
      ->condition('status', NodeInterface::PUBLISHED)
      ->condition('field_my_custom_field', $this->id());

```

It's the sorting part where I get stuck. Here's my attempt

```
    $my_query->leftJoin('taxonomy_term_field_data', 'td', 'td.tid = node_field_data.field_my_custom_field.target_id')
    ->orderBy('td.weight', 'ASC')
    ->execute();

```

By leftJoin is not available. I've looked at https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21Query%21Sql%21Query.php/class/Query/9.0.x and I do see that sqlQuery is a property on the Query object that you can perform leftJoin on it but sqlQuery is a protected property.

Is sorting by this possible?

# Answer
I was able to sort by the taxonomy weight with this

```
->sort('field_my_custom_field.entity.weight','DESC');

```
> 1 votes

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


# Question
Title: Why can't I use video_embed_html5 on Drupal 10?
I'm trying to get past the video\_embed\_html5 error message while going to Drupal 10.0.1....it says it isn't supported in 10.0.1....does anyone know a workaround for this...

https://www.drupal.org/project/video\_embed\_html5

# Answer
You cannot use that module with Drupal 10 at the time that I write this. The project has not had commits since 2020 and is not marked yet as compatible with Drupal 10. There are automated compatibility fixes that its maintainers have not merged.
> 1 votes

---
Tags: 10
---


# Question
Title: Best practice to upgrade drupal 9.4 to 9.5? Composer or Drush method?
I can run this command to upgrade drupal 9.4 to 9.5, but I can also do it in drush. Which method is better and why?

composer require drupal/core-recommended:9.5.0 drupal/core-composer-scaffold:9.5.0 drupal/core-project-message:9.5.0 --update-with-all-dependencies

# Answer
Let me preface with what each of these are:

**Drush** is a command line shell and Unix scripting interface for Drupal. Drush core ships with lots of useful commands and generators. Similarly, it runs update.php, executes SQL queries, runs content migrations, and misc utilities like cron or cache rebuild.

**Composer** is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.

---

You cannot use Drush to update/upgrade Drupal 9. That particular Drush functionally/feature got deprecated. As Drupal 9 requires Drush 10 or higher, it doesn't have it.

>

<sub> source: Updating Drupal core via Drush </sub>

Composer is a very popular PHP tool used outside the Drupal world to manage dependencies.

Drupal decided to adopt it. Once this happened, there was no need for Drush to re-invent the wheel when there is already a dedicated tool built for this job specifically and that does it very well.
> 4 votes

---
Tags: drush, composer
---


title: loadByProperties with multiple fields

text:
# Question
Title: loadByProperties with multiple fields
I want to find a node with some values in two fields. To do that, I use loadByProperties in this way:

```
$nodes = \Drupal::entityTypeManager()
  ->getStorage('node')
  ->loadByProperties([
    'field_surname' => 'Surname',
    'field_name' => 'Name',
  ]);

```

This does not work. I am sure that at least one node with such values in these fields exists. This code is used in the .module file. When I debug with dpm(), nothing that I passed inside dpm() is displayed. But when I use this function with only one field, everything works fine. Maybe my understanding of loadByProperties is wrong? How can I find nodes based on values in two fields?

# Answer
> 1 votes
loadByProperties() requires the entity to match all values. If you want to match 'OR' you need to queries with entityTypeManager and combine the results.

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

$nidsA = $storage
  ->getQuery()
  ->condition('field_surname', 'Surname')
  ->execute();

$nidsB = $storage
  ->getQuery()
  ->condition('field_surname', 'Surname')
  ->execute();

$nids = array_merge($nidsA, $nidsB);

$nodes = $storage->loadMultiple($nids);

```

---
Tags: 9
---


# Question
Title: Where is the look of the Search button in Bootsrap5 defined?
I have a Drupal 9.5.1 website with **Bootstrap5** 2.0.6 as its base theme. The theme by default places a search form by means of a block named "Search" in the "Additional navigation region".

This block "Search" is provided by core, but how its looks seems to be determined by the theme. If I change the theme to **Bartik**, the same block by default appears in the "Sidebar first" region, but the button to press to search is an icon (I believe it is `fa-search` from FontAwesome), not the text "Search".

I have enabled Twig debugging, and found that in **Bootstrap5** the search form is themed by:

```
themes/contrib/bootstrap5/templates/form/input.html.twig

```

In **Bartik**, the search form is themed by:

```
core/modules/system/templates/input.html.twig

```

In my subtheme, I want to do replace the text "Search" on the button with a an icon, just like you get by default if you set **Bartik** as the default.

But I am unable to locate *where* the look of of the Search button is defined and how to change it from text to the `fa-search` icon that is used by **Bartik**.

So far I've looked for it in the templates that comes with **Bootstrap5** and from core (used by **Bartik**), including the `input.html.twig` that comes with both. There are subtle differences, but I am not able to pinpoint where the icon used by default by **Bartik** comes from.

I have tried to swap the one from core into my **Bootstrap5** subtheme. This just removes the background colour on the button, but has no other effect.

# Answer
> 0 votes
The twig template is, **probably**:

```
core/modules/system/templates/input.html.twig

```

So, I think there are not many options other than something like copy core/modules/system/templates/input.html.twig to your subtheme and edit it to something like:

```
{% if (attributes.id == 'the-id-of-the-submit') %}
  {%
    set classes = [
      'some-class',
      'some-other-class',
    ]
  %}
  <button{{ attributes.addClass(classes) }}></button>
{% else %}
  <input{{ attributes }} />{{ children }}
{% endif %}

```

---
Tags: 9, bootstrap-theme
---


# Question
Title: using hook_form_alter() to change year range of datetime select widget, with deltas for multi-value fields
I have multiple date fields on a node form for which I am using the select widget. The year select list has a range of years that is far too wide for our purposes (1900-present), so we want to limit it. I am able to accomplish this with hook\_form\_alter, however the fields that are multi-value to not reflect this change when they are loaded with ajax. Here is my current code which gets the first deltas:

```
public function alterQuarterlyReportForm(&$form, FormState  $form_state, $form_id) {

// form_alter functionality for quarterly reports
if ($form_id == 'node_quarterly_report_form' || $form_id == 'node_quarterly_report_edit_form') {

  // Limiting range of years in date fields on report form
      $form['field_draft_evaluation_date']['widget'][0]['value']['#date_year_range'] = '-3:+3';
      $form['field_draft_protocol_date']['widget'][0]['value']['#date_year_range'] = '-3:+3';
      $form['field_updated_milestone_plandate']['widget'][0]['value']['#date_year_range'] = '-3:+3';
      $form['field_committee_date']['widget'][0]['value']['#date_year_range'] = '-3:+3';
      $form['field_liaison_meeting_dates']['widget'][0]['value']['#date_year_range'] = '-3:+3';
      $form['field_meeting_date']['widget'][0]['value']['#date_year_range'] = '-3:+3'; }}

```

Obviously these are each set for delta 0, and what I am having trouble figuring out is how to get this working for each additional value that a user wants to enter. I have attempted a few foreach() loops, but I am not getting it right.

# Answer
I think you probably want this:

```
$fields = [
  'field_draft_evaluation_date',
  'field_draft_protocol_date',
  'field_updated_milestone_plandate',
  'field_committee_date',
  'field_liaison_meeting_dates',
  'field_meeting_date',
];

foreach ($fields as $field) {
  foreach (\Drupal\Core\Render\Element::children($form[$field]) as $index) {
    $form[$field]['widget'][$index]['value']['#date_year_range'] = '-3:+3';
  }
}

```

Note that Element::children() returns "The children of an element array are those key/value pairs whose key does not start with a '#'". For the above code, it will return the deltas for multi-value fields.
> 1 votes

---
Tags: hooks, datetime
---


# Question
Title: Correctly configure the JavaScript tools
I am trying to configure eslint for Drupal in `PHPStorm`, and it's really confusing.

For example, I have installed the node dependencies that comes in the `web/core/package.json` file. In `PHPStorm`, in the Eslint settings, I have configured web/core/node\_modules/eslint, but with this module `(eslint-config-drupal)`, I don't know if to configure it `with node_modules/eslint` which is in the root where I installed `eslint-config-drupal`. The same goes for prettier.

When I check the Drupal JavaScript coding standards using, for example, `./node_modules/.bin/eslint --no-ignore "../modules/custom/my_module/js/file.js"` I had to pass the `--no-ignore` parameter in order to see the style errors.

The `package.json` used by Drupal core has some interesting commands that I am interested in using, such as `transpiling ES6 to ES5`. What the core does is transpile a file.es6.js file to file.js.

In the Drupal documentation I see that the command can apparently be used like `npm run build:js -- --file ../modules/custom/my_module/js/file.es6.js`, but when I do so, I notice That the Babel plugins don't process them and only show the same file. I only added a generic header text.

I understand that these commands are for the Drupal core, and if I temporarily copy a `file.es6.js` file to a location within the core, Babel transpiles it correctly.

The only way I have managed to transpile it is to copy the `package.json` file, the core JavaScript files, and use it in the root of the project. What I don't like is having everything duplicated.

I don't know if there is a way to use what comes with Drupal core in a transparent way.

# Answer
> 0 votes
Update:

Starting with Drupal 10, an ES6 build process will no longer be used, and several of the scripts related to these tasks are removed.

Now Js code will be written directly without an intermediate compilation process.

---
Tags: 8, javascript, nodejs
---


title: How do I get a module path?

text:
# Question
Title: How do I get a module path?
I'm creating a module in Drupal 8 and I need to define a relative path to mymodule to pass it on a JavaScript file like this.

```
$scope.getPlatformIcon = function (_platform) {
     var modulePath = "/modules/mymodule"
     switch (_platform) {
         case "youtube":
         case "twitter":
         case "instagram":
         case "facebook":
             return modulePath+"/img/"+_platform+".png";
     }
     return false;
};

```

In Drupal 7 I could use the following.

```
var modulePath = Drupal.settings.mymodule.basePath;

```

For the Drupal 8 root directory, I could use the following.

```
drupalSettings.path.baseUrl

```

I didn't find how to get the module path.

How can I do it with Drupal 8?

# Answer
In Drupal 8 this drupal setting is not available by default. You can check the existing variables by looking for this JSON array on the HTML page:

```
<script type="application/json" data-drupal-selector="drupal-settings-json">{

```

To add the module path variable use this code:

```
$build['#attached']['drupalSettings']['mymodule']['mylib']['path'] = \Drupal::service('extension.list.module')->getPath('mymodule');

```

For more info about drupalSettings see:

using {{ twig variables }} inside external jquery

---

**Update Drupal 9.3**

Use the new service:

```
\Drupal::service('extension.list.module')->getPath('mymodule')

```

See the change record https://www.drupal.org/node/2940438

This function drupal\_get\_path() and the even more used file\_create\_url() will be the major deprecations for Drupal 10. Since Drupal versions prior to 9.3 are no longer supported it's now time to update the code in preparation for Drupal 10. Always check the change records for the correct replacement code.
> 15 votes

# Answer
To answer the original question (*how do I get a module path*), and not taking into account the javascript attachment part here is OO friendly solution (without showing the dependency injection itself):

```
$module_handler = \Drupal::service('module_handler');
$module_path = $module_handler->getModule('my_module')->getPath();

```

This will give you back the following (of course also depends on how your directory structure looks like)

```
"modules/custom/my_module"

```

`drupal_get_path` is indeed faster to write. However, it calls the same service above statically which makes your code unable to unit test (also not to mention the dependencies of your class are not visible). Long story short: if you choose to make things Quick&Dirty go for `drupal_get_path` any other cases use the right service yourself with a proper dependency injection.
> 31 votes

# Answer
Starting with Drupal 9.3 you can also get it by:

```
$themePath =
  \Drupal::service('extension.path.resolver')
  ->getPath('module', 'my_module');

```
> 2 votes

---
Tags: 8, javascript
---


# Question
Title: Moved an old installation profile now site is broken
I have a d9 site with an old installation profile originally written for d8.

I was having some issues with the profile preventing the uninstallation of some modules so I tried moving the entire folder for a moment to see if that removed the profile.

Instead, it broke (WoD) the site. I moved the profile directory right back where it was but no matter what I do the site remains WoD with the message:

`the profile myprofile does not exist`

The directory and all the files are there. Drush just keeps throwing that error. How can I fix this?

Just to be clear: I understand I should not have moved the directory. My question is how to get the site working again. In effect, what I did was:

1. Move the profile outside of `web/profiles`
2. visit the site + try to clear the cache with drush
3. Moved the profile back to `web/profiles`

The site will not work now. With modules and themes if the files are moved and replaced the site looks for them when they return, why will it not do this for the profile? Is there some entry in the DB indicating the profile is gone - if there is why would there be such a thing?

# Answer
A profile is like a module or theme, you have to uninstall it first before you can remove it from the file system. Additionally a profile can't just be uninstalled like a module. You need to switch the profile. This module might be helpful:

> **Profile Switcher**
>
> This module provides a Drush command to switch between install profiles found in /profile directory:
>
> ```
> drush switch:profile [new-profile]
>
> ```
>
> This is useful for moving an existing site to distribution or moving from an abandoned distribution back to a standard Drupal core install.

https://www.drupal.org/project/profile\_switcher

See the warnings, though:

> **IMPORTANT WARNINGS:**
>
> * Switching profiles is NOT a trivial change like switching a theme.
> * ALWAYS test before using on a live site and ALWAYS have a backup

**Recover broken site**

After moving the profile back to `web/profiles` you can recover a broken site by resetting the extension profile list:

```
drush ev "\Drupal::service('extension.list.profile')->reset();"

```

This not only clears the relevant cache entries but also the key `system.profile.files` stored in the State API.

Instead of the drush command you can clear the `cache_` tables and the entry `system.profile.files` in the collection `state` from the `key_value` table:

```
delete from 'key_value' where collection = 'state' and name = 'system.profile.files';

```
> 5 votes

# Answer
There's an approach to fix your problem which doesn't involve switching the profile at all:

Edit the profile's .info.yml file, and change the key for the list of modules from `required` to `install`. This will let you uninstall the modules, while still keeping them associated with that profile.
> 2 votes

---
Tags: 9, installation-profiles
---


# Question
Title: Upgrade report shows Invalid permissions will trigger runtime exceptions
Preparing my Drupal 9.5.1 website to go on Drupal 10. I have installed module Upgrade status.

getting in report this kind of error :

Invalid permissions will trigger runtime exceptions in Drupal 10. Permissions should be defined in a permissions.yml file or a permission callback.

most of the permissions is for background image module, Paragraphs, Flag.

I've found closest answer for this. Like a patch to be applied https://www.drupal.org/project/layout\_builder\_styles/issues/3323459

https://www.drupal.org/project/upgrade\_status/issues/3223068

but it won't solve this for me...

Is there any solution for this?

# Answer
> 2 votes
After searching trough the Drupal.org Upgrade Status module issues i got some kind of answer to my question

where maintainers discussed this kind of the message on D9.3 environment as per their discussion :

> Otherwise, the user may think they should be doing something to fix the issue when in fact it will get fixed. Perhaps add: This problem may be automatically corrected by the upgrade to Drupal 9.3.

So i assume that perfectly suits and to the D9.5.2

---
Tags: 10
---


# Question
Title: Swap columns inside every other row with Views and Bootstrap
i want to create block with views.I want style output like image bellow. Sorry i add image because my english is not good and i cant explain what i want

# Answer
One solution is to customize the view output to include the necessary Bootstrap Grid classes. Once you have done that, all is needed is a small bit of CSS.

**Remove default formatting**

Turn off default formatting in your format settings. (If using *Unformatted list* format, uncheck "Provide default field wrapper elements".)

**Add column classes**

Rewrite the output of your fields to include column classes `col-xs-12 col-md-6`. Example:

`<div class="col-xs-12 col-md-6">[field_image]</div>`

*This assumes you have two fields: one for image and another for text.*

**Add row class**

Override the views template for rows (e.g. views-view-unformatted.tpl.php) to include `row` class in the wrapper element. Example:

```
<?php foreach ($rows as $id => $row): ?>
  <div class="row <?php if ($classes_array[$id]) { print $classes_array[$id];  } ?>">
    <?php print $row; ?>
  </div>
<?php endforeach; ?>

```

**Output**

If you are using *Unformatted list* as your view format, your mark-up will look something like this:

```
<div class="row views-row views-row-6 views-row-even">
  <div class="col-xs-12 col-md-6">
    ...
  </div>
  <div class="col-xs-12 col-md-6">
    ...
  </div>
</div>

```

**CSS**

Now all you need to do is add some CSS to your theme's stylesheet that emulates Bootstrap's push/pull column ordering **in only the odd rows**; e.g.

```
@media screen and (min-width: 970px) {
  .view-testing .views-row-odd div:first-child {
    left: 50%;
  }
  .view-testing .views-row-odd div:last-child {
    right: 50%;
  }
}

```

Edit: An alternative is to use Views Bootstrap, as suggested here by Alex, but you will still need to override the mark-up to alternate column ordering per row.
> 2 votes

# Answer
Use Views Bootstrap and implement it using the grid.

> Views Boostrap module enables you to create components following the theme structure of the Bootstrap framework all within the configuration settings of the powerful Views module.
> 3 votes

# Answer
Off the top of my head I would use the default views classes with striping (under format settings) and use flexbox or float the image with CSS on your `.views-row.odd` and `.views-row.even`.

Note: Untested and from memory but should be really close.
> 1 votes

# Answer
This issue is so old, it has certainly been solved by now. However, for anyone else who comes along, https://www.drupal.org/project/views\_parity\_row will solve this through the UI.
> 1 votes

# Answer
This question is old but if you use now Bootstrap 5, you can use the CSS `order` property. Let's say your column has `col-lg-6` class :

```
.container-view {
    &:nth-of-type(odd) {
       .col-lg-6 {
           &:first-child {
            order: 2;
       }
     }
   }
 }

```

**Documentation :**

https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child

https://developer.mozilla.org/en-US/docs/Web/CSS/order
> 0 votes

---
Tags: theming, views
---


title: Can't uninstall forum module

text:
# Question
Title: Can't uninstall forum module
my core forum module installation gone wrong on a drupal 8.5.1 system and now, when I want to uninstall it I get:

```
    $ drush pmu --verbose forum
    Executing: mysql --defaults-extra-file=/tmp/drush_R3Uhpd --database=drupal_2 --host=localhost --port=3306 --silent  < /tmp/drush_enDNb4
    Executing: mysql --defaults-extra-file=/tmp/drush_OWoaeC --database=drupal_2 --host=localhost --port=3306 --silent  < /tmp/drush_3gNq9b
    The following extensions will be uninstalled: forum
    Do you really want to continue? (y/n): y
    array_flip(): Can only flip STRING and INTEGER values! EntityStorageBase.php:227                                                                                [warning]
    TypeError: Argument 1 passed to Drupal\forum\ForumUninstallValidator::hasTermsForVocabulary() must implement interface Drupal\taxonomy\VocabularyInterface, null given, called in                   [error]
    /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php on line 61 in Drupal\forum\ForumUninstallValidator->hasTermsForVocabulary() (line 103 of
    /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php)
    #0 /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php(61): Drupal\forum\ForumUninstallValidator->hasTermsForVocabulary(NULL)
    #1 /usr/local/www/drupal2/core/lib/Drupal/Core/Extension/ModuleInstaller.php(560): Drupal\forum\ForumUninstallValidator->validate('forum')
    #2 /usr/local/www/drupal2/core/lib/Drupal/Core/Extension/ModuleInstaller.php(365): Drupal\Core\Extension\ModuleInstaller->validateUninstall(Array)
    #3 /usr/local/www/drupal2/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php(91): Drupal\Core\Extension\ModuleInstaller->uninstall(Array, true)
    #4 /vendor/drush/drush/commands/core/drupal/environment.inc(227): Drupal\Core\ProxyClass\Extension\ModuleInstaller->uninstall(Array)
    #5 /vendor/drush/drush/commands/core/drupal/pm_8.inc(79): drush_module_uninstall(Array)
    #6 /vendor/drush/drush/commands/pm/pm.drush.inc(1250): _drush_pm_uninstall(Array)
    #7 /vendor/drush/drush/includes/command.inc(422): drush_pm_uninstall('forum')
    #8 /vendor/drush/drush/includes/command.inc(231): _drush_invoke_hooks(Array, Array)
    #9 /vendor/drush/drush/includes/command.inc(199): drush_command('forum')
    #10 /vendor/drush/drush/lib/Drush/Boot/BaseBoot.php(67): drush_dispatch(Array)
    #11 /vendor/drush/drush/includes/preflight.inc(66): Drush\Boot\BaseBoot->bootstrap_and_dispatch()
    #12 /vendor/drush/drush/drush.php(12): drush_main()
    #13 {main}.
    TypeError: Argument 1 passed to Drupal\forum\ForumUninstallValidator::hasTermsForVocabulary() must implement interface Drupal\taxonomy\VocabularyInterface, null given, called in /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php on line 61 in /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php on line 103 #0 /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php(61): Drupal\forum\ForumUninstallValidator->hasTermsForVocabulary(NULL)
    #1 /usr/local/www/drupal2/core/lib/Drupal/Core/Extension/ModuleInstaller.php(560): Drupal\forum\ForumUninstallValidator->validate('forum')
    #2 /usr/local/www/drupal2/core/lib/Drupal/Core/Extension/ModuleInstaller.php(365): Drupal\Core\Extension\ModuleInstaller->validateUninstall(Array)
    #3 /usr/local/www/drupal2/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php(91): Drupal\Core\Extension\ModuleInstaller->uninstall(Array, true)
    #4 /vendor/drush/drush/commands/core/drupal/environment.inc(227): Drupal\Core\ProxyClass\Extension\ModuleInstaller->uninstall(Array)
    #5 /vendor/drush/drush/commands/core/drupal/pm_8.inc(79): drush_module_uninstall(Array)
    #6 /vendor/drush/drush/commands/pm/pm.drush.inc(1250): _drush_pm_uninstall(Array)
    #7 /vendor/drush/drush/includes/command.inc(422): drush_pm_uninstall('forum')
    #8 /vendor/drush/drush/includes/command.inc(231): _drush_invoke_hooks(Array, Array)
    #9 /vendor/drush/drush/includes/command.inc(199): drush_command('forum')
    #10 /vendor/drush/drush/lib/Drush/Boot/BaseBoot.php(67): drush_dispatch(Array)
    #11 /vendor/drush/drush/includes/preflight.inc(66): Drush\Boot\BaseBoot->bootstrap_and_dispatch()
    #12 /vendor/drush/drush/drush.php(12): drush_main()
    #13 {main}
    TypeError: Argument 1 passed to Drupal\forum\ForumUninstallValidator::hasTermsForVocabulary() must implement interface Drupal\taxonomy\VocabularyInterface, null given, called in /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php on line 61 in Drupal\forum\ForumUninstallValidator->hasTermsForVocabulary() (line 103 of /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php).
    Drush command terminated abnormally due to an unrecoverable error.                                                                                [error]
    A non well formed numeric value encountered drush.inc:1671

```

How can I uninstall this module, because this problem leads to crash on the admin/modules/uninstall page:

```
The website encountered an unexpected error. Please try again later.
TypeError: Argument 1 passed to Drupal\forum\ForumUninstallValidator::hasTermsForVocabulary() must implement interface Drupal\taxonomy\VocabularyInterface, null given, called in /usr/local/www/drupal2/core/modules/forum/src/ForumUninstallValidator.php on line 61 in Drupal\forum\ForumUninstallValidator->hasTermsForVocabulary() (line 103 of core/modules/forum/src/ForumUninstallValidator.php).

```

My server config: Apache/2.4.29 (FreeBSD) OpenSSL/1.0.1u-freebsd PHP/7.1.14

PHP Ver. 7.1.14

DB MySQL Ver. 5.6.37

EDIT:

I forgot to mention, that admin/structure/forum gives me this:

```
Warning: array_flip(): Can only flip STRING and INTEGER values! in Drupal\Core\Entity\EntityStorageBase->loadMultiple() (line 227 of /usr/local/www/drupal2/core/lib/Drupal/Core/Entity/EntityStorageBase.php)
#0 /usr/local/www/drupal2/core/includes/bootstrap.inc(582): _drupal_error_handler_real(2, 'array_flip(): C...', '/usr/local/www/...', 227, Array)
#1 [internal function]: _drupal_error_handler(2, 'array_flip(): C...', '/usr/local/www/...', 227, Array)
#2 /usr/local/www/drupal2/core/lib/Drupal/Core/Entity/EntityStorageBase.php(227): array_flip(Array)
#3 /usr/local/www/drupal2/core/lib/Drupal/Core/Entity/EntityStorageBase.php(212): Drupal\Core\Entity\EntityStorageBase->loadMultiple(Array)
#4 /usr/local/www/drupal2/core/modules/forum/src/Form/Overview.php(54): Drupal\Core\Entity\EntityStorageBase->load(NULL)
#5 [internal function]: Drupal\forum\Form\Overview->buildForm(Array, Object(Drupal\Core\Form\FormState), NULL)
#6 /usr/local/www/drupal2/core/lib/Drupal/Core/Form/FormBuilder.php(514): call_user_func_array(Array, Array)
#7 /usr/local/www/drupal2/core/lib/Drupal/Core/Form/FormBuilder.php(271): Drupal\Core\Form\FormBuilder->retrieveForm('forum_overview', Object(Drupal\Core\Form\FormState))
#8 /usr/local/www/drupal2/core/lib/Drupal/Core/Controller/FormController.php(74): Drupal\Core\Form\FormBuilder->buildForm('forum_overview', Object(Drupal\Core\Form\FormState))
#9 [internal function]: Drupal\Core\Controller\FormController->getContentResult(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\RouteMatch))
#10 /usr/local/www/drupal2/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#11 /usr/local/www/drupal2/core/lib/Drupal/Core/Render/Renderer.php(582): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#12 /usr/local/www/drupal2/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#13 /usr/local/www/drupal2/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#14 /usr/local/www/drupal2/vendor/symfony/http-kernel/HttpKernel.php(151): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#15 /usr/local/www/drupal2/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#16 /usr/local/www/drupal2/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#17 /usr/local/www/drupal2/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#18 /usr/local/www/drupal2/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#19 /usr/local/www/drupal2/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#20 /usr/local/www/drupal2/core/modules/ban/src/BanMiddleware.php(50): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#21 /usr/local/www/drupal2/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\ban\BanMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#22 /usr/local/www/drupal2/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#23 /usr/local/www/drupal2/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#24 /usr/local/www/drupal2/core/lib/Drupal/Core/DrupalKernel.php(664): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#25 /usr/local/www/drupal2/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#26 {main}.

Warning: array_flip(): Can only flip STRING and INTEGER values! in Drupal\Core\Entity\EntityStorageBase->loadMultiple() (line 227 of core/lib/Drupal/Core/Entity/EntityStorageBase.php).

Page not found.

```

THX

# Answer
Just re-create Forums vocabulary and then you should be able able to uninstall the module.
> 2 votes

# Answer
You can temporally edit **core/modules/forum/src/ForumUninstallValidator.php** like that:

```
  /**
   * Determines if there are any taxonomy terms for a specified vocabulary.
   *
   * @param \Drupal\taxonomy\VocabularyInterface $vocabulary
   *   The vocabulary to check for terms.
   *
   * @return bool
   *   TRUE if there are terms for this vocabulary, FALSE otherwise.
   */
  protected function hasTermsForVocabulary(VocabularyInterface $vocabulary = NULL) {
    return FALSE;
    $terms = $this->entityTypeManager->getStorage('taxonomy_term')->getQuery()
      ->condition('vid', $vocabulary->id())
      ->accessCheck(FALSE)
      ->range(0, 1)
      ->execute();
    return !empty($terms);
  }

```

This way you will be able to uninstall the module. Then don't forget to rollback your changes!
> 1 votes

# Answer
The following fixed it and I suspect it's because of some bug in the Devel module (in my case) when generating Forum contents without having a Forums vocabulary :

1. Created a "Forums" vocabulary at **/admin/structure/taxonomy/add**
2. Going back to **/admin/modules/uninstall** no more error but the Forum checkbox is disabled and has this message :

> ```
> The following reason prevents Forum from being uninstalled:
>
> To uninstall Forum, first delete all Forum content
>
> ```

3. At content admin **admin/content?title=&type=forum&status=All&langcode=All** delete all forum type content. (I had it generated by the Devel module).
4. Now going back to Modules \> Uninstall the forum checkbox is enabled and uninstallable.
> 1 votes

# Answer
try checking your db first:

`select * from public.node__taxonomy_forums`

`select * from public.taxonomy_term_revision__forum_container;`

I found 3 terms in taxonomy\_term\_revision\__forum\_container that I did not know about. Once these were deleted I was able to successfully uninstall Forum.

`drush pmu forum`
> 0 votes

---
Tags: 8
---


# Question
Title: Feeds Documentation for importing data programatically
Team,

I need a help.

I was surfing internet, but couldn't get a luck to get a working example/documentation to import data programmatically and store into our custom tables.

I'm using Drupal 9 version and feeds module, and for importing data related to users, content type, feeds modules help me a lot. But we have some custom tables as well, and stuck here to import. I have followed below link, but have stuck in coding part to get & store the values in custom table.

https://www.drupal.org/docs/contributed-modules/feeds/creating-a-custom-feeds-workflow

And, everywhere, I'm getting the links for import using front-end, but not via programatically.

https://ostraining.com/blog/drupal/feeds/

https://www.specbee.com/blogs/how-import-external-feeds-your-drupal-9-website-feeds-module

https://metadrop.net/en/articles/import-your-content-feeds-drupal

I have asked some of my known Drupalers, and in my circle, we are not having a handy documentation or code example for importing data and storing in custom table. My friends recommended some other contrib modules for this case, but I would like to know if I can achieve this using Feeds.

I just need to import some data using csv file and store it in custom tables. Please do share if any working code example is there with anybody or any links over internet you have seen which I missed, please do share, kindly help.

Thanks in advance.

# Answer
I will assume a scenario where you just need to import some simple data from a csv file into Drupal. No *multi value fields*, no *reference fields* (including image fields), etc. Such scenario would require a much complicated script.

The solution I’m suggesting (bellow) assumes that you have *drush* installed and you are willing to run a *php* script under *drush*.

Something like the following might work:

```
<?php

// php -d memory_limit=-1 vendor/bin/drush php:script import_nodes.php

// general options
$csv_file_name = '/the/path/to/file.csv';
$type = 'some_type';

// get csv
$items_to_import = get_array_from_csv ($csv_file_name);

// start import
foreach ($items_to_import as $item) {

        // set title
        $title = $item['title'];

        // create node
        $node = \Drupal::entityTypeManager()
                    ->getStorage('node')
                    ->create([
                        'type' => $type,
                        'title' => $title,
                    ]);

        // set field_foo
        $field_foo = $item['field_foo'];
        $node->set('field_foo', $field_foo);

        // set field_bar
        $field_bar = $item['field_bar'];
        $node->set('field_bar', $field_bar);

        $node->save();
        unset ($node);

}

function get_array_from_csv ($filePath) {

    $dataArray = [];

    $rows = array_map ('str_getcsv', file ($filePath));
    $header = array_shift ($rows);

    foreach($rows as $row) {

        $dataArray[] = array_combine ($header, $row);

    }

    return $dataArray;

}

```

Run it (from your site directory) with the command:

```
php vendor/bin/drush php:script import_nodes.php

```

Or (if on low allocated memory for *php*) with the command:

```
php -d memory_limit=-1 vendor/bin/drush php:script import_nodes.php

```
> 0 votes

---
Tags: 9, feeds, importing-exporting
---