# Question
Title: Build custom form with entity form field
I have a feature to migrate from Drupal 7 to Drupal 9. This allows me to build a custom form made up of static fields, which I define in the code of my module, and fields dynamically retrieved from an entity.

It worked with the "ctools\_field\_invoke\_field function", which relies on the Chaos Tools module. This function is itself based on a native Drupal function "field\_default\_form".

This function was not migrated to Drupal 9 according to my research. Can I find an equivalent? Should I develop this function from scratch?

My previous code :

```
// If no language is provided use the default site language.
$options = array(
  'language' => field_valid_language($langcode),
  'default' => TRUE,
);

// Append to the form
ctools_include('fields');
$field_instance = field_info_instance($entity_type, $field_name, $bundle);
return (array) ctools_field_invoke_field($field_instance, 'form', $entity_type, $entity, $form, $form_state, $options);

```

# Answer
I did not find similar function either. Looks like it does not exist. Though, here is how it can be achieved in Drupal 8/9 forms:

```
$entity = $this->entityTypeManager->getStorage('node')->create([
  'type' => 'article'
]);
$form_state->set('entity', $entity);

/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$form_display = $this->entityTypeManager->getStorage('entity_form_display')->load('node.article.custom_form_display');
$form_state->set('form_display', $form_display);

foreach ($form_display->getComponents() as $name => $component) {
  $widget = $form_display->getRenderer($name);
  if (!$widget) {
    continue;
  }

  $items = $entity->get($name);
  $items->filterEmptyItems();
  $form[$name] = $widget->form($items, $form, $form_state);
  $form[$name]['#access'] = $items->access('edit');
}

```

This code was taken from the following article: https://www.webomelette.com/how-render-entity-field-widgets-inside-custom-form-drupal-8

*I am not affiliated with it, but personally, recommend to read.*
> 0 votes

---
Tags: entities, forms, 9
---


# Question
Title: How to import a custom content type in phpunit
I'm trying to write some PHPUnit Kernel tests that use a custom content type which seem to work until I try to reference fields on the content type. I'm guessing the content type isn't being imported from config. Is there a correct way to do this?

Example code which works in drush php but does not work in phpunit:

```
  public function createAction() {
    $storage = $this->container->get('entity_type.manager')->getStorage('node');
    $entity = $storage->create(['type' => 'action']);
    $entity->set('title', 'test');
    $entity->set('field_lookup_type', 'address');
    $entity->save();
    return $entity;
  }

```

The error from phpunit is "InvalidArgumentException: Field field\_lookup\_type is unknown."

# Answer
That wont do it. You either need to create a test module that has YAML configs to do this, or script in the changes in the test setup method. The latter method is longer, but frees you from having to maintain copies of YAML configs in an additional module(s). Here is an example.

```
  public function setUp() {
    parent::setUp();
    $this->entityTypeManager = $this->container->get('entity_type.manager');

    $this->installEntitySchema('node');
    $this->installEntitySchema('user');
    $this->installEntitySchema('taxonomy_term');
    $this->installSchema('node', 'node_access');
    $this->installConfig('node');
    $this->installConfig('taxonomy');
    $this->installConfig('filter');

    $this->createContentType(['type' => 'my_content_type']);

    FieldStorageConfig::create([
      'field_name' => 'field_lookup_type',
      'entity_type' => 'node',
      'type' => 'entity_reference',
      'cardinality' => 1,
      'locked' => FALSE,
      'indexes' => [],
      'settings' => [
        'handler' => 'default:taxonomy_term',
        'handler_settings' => [
          'target_bundles' => [],
          'sort' => [
            'field' => 'name',
            'direction' => 'asc',
          ],
          'auto_create' => false,
          'auto_create_bundle' => '',
        ],
      ]
    ])->save();

    FieldConfig::create([
      'field_name' => 'field_lookup_type',
      'entity_type' => 'node',
      'label' => 'My Field',
      'bundle' => 'my_content_type',
      'description' => '',
      'required' => FALSE,
      'settings' => [],
    ])->save();

```

This creates a node type, creates a taxonomy field, and sets the taxonomy field to that node type. This is the equivalent of loading several YAML files.

Then, either in setup or a test itself, you can:

```
 $node = $this->createNode(['type' => 'my_content_type', 'field_lookup_type' => 1]);

```

The traits to do this need to be included in your test class:

```
  use NodeCreationTrait,
    ContentTypeCreationTrait,

```
> 4 votes

---
Tags: 8, nodes
---


title: Render view inside block with caching

text:
# Question
Title: Render view inside block with caching
My setup is a bit unconventional. I have a view displaying a block, relying on a contextual filter (let's call it product ID). I also have a custom block that renders this view programmatically because I need to include this block in multiple places on the page and I have some custom logic that pulls the actual product ID to call the view with. Basically:

```
$view = Views::getView('view_id');
$args = ['product_id' => $whatever_product];
return $view->buildRenderable('views_block_id', $args);

```

The process basically works but, as usual, I'll have problems when there are several such blocks on the page. `Views` only caches using the block id as a cache tag, so the first rendered view gets cached and displayed in all places. Naturally, switching off the cache would work:

```
return $view->buildRenderable('views_block_id', $args, FALSE);

```

but not exactly what I have in mind, I don't want to lose the benefits of caching.

My initial thought was quite simple, let's use custom cache tags in the view, thanks to `views_custom_cache_tag`. So I did, including the argument from the contextual filter:

```
views_block:view_id-views_block_id
custom:{{ arguments.product_id }}

```

But it still doesn't work.

Is there any other way I missed? I can't push new cache tags right before I try to render the view. The usual view hooks don't get called in this case (the second block already gets the cached variant, without even bothering to go near the hooks).

# Answer
In a block you can switch off caching of the rendered View in ViewExecutable::buildRenderable:

```
$view->buildRenderable('views_block_id', $args, FALSE)

```

because the rendered result of each block instance is already cached.

By the way, cache tags are not involved when caching variants of the same element. This is only controlled by cache keys and contexts. With cache=FALSE you disable cache keys, but not contexts, which should still bubble up to the block level. If a context is missing, you can set a cache context manually, for example for the route or a url path query arg if the product ID depends on it.

Edit: I've removed the return statement, because it might be necessary to build a real render array with the embedded View.
> 2 votes

---
Tags: views, blocks, caching
---


# Question
Title: How do I programmatically set a content reference by name for a node?
Hi team i have some isssues.

I'm creating a node and i would like to set a content reference by name not by id, i'm doing this but this is not working: 'field\_content\_type\_items' is referenced to another content type

```
$node = \Drupal\node\Entity\Node::create([
    'type' => 'items',
    'status' => $status,
    'title' => $title,
    'field_content_type_items' =>  "CUN",
]);

```

Also i tried with this example `'field_content_type_items' => [['target_id' => 12]],` but i dont know the id for `CUN` so i cant use `target_id` also i've tried:

```
$node->set('field_content_type_items', 'CUN');

```

could you please help me?

How can i set a content name when i create a node?

Regards Mario

# Answer
Entity reference fields expect an entity ID, so unless you want to extend the field type (which could get unnecessarily messy), you'll need to get the ID of the target content.

One method to do this is `EntityStorageBase::loadByProperties()`, e.g.

```
$target_nodes = \Drupal::entityTypeManager()->getStorage('node')
  ->loadByProperties(['title' => 'CUN', 'type' => 'foo']);

if (count($target_nodes)) {
  // For the sake of example assume the first node is the right one.
  $target_id = reset($target_nodes)->id();

  // ...
}

```

Bear in mind that node titles aren't unique, so you might need to add some extra filtering logic to get the exact node you need.
> 2 votes

---
Tags: 8, nodes, taxonomy-terms
---


title: How to programmatically create Fields?

text:
# Question
Title: How to programmatically create Fields?
How can I approach implementing the following in Drupal 7?

What I need to do is create a module which defines a new fieldable entity, called 'Company'. I have a list of, let's say, 20 fields that need to be filled out by each Company instance. These questions are predefined and some may contain custom validation.

At the moment, I'm at the point when I can add new fields to the Company entity. This works fine at the moment. My issue is that I need all these fields to be there as soon the module is installed, so adding them via the interface isn't an option.

I was wondering how can I approach this? I'd assume it comes down being able to do what can be done using the 'Manage Fields' UI programmatically.

# Answer
Use field\_create\_field() to create the field itself and field\_create\_instance() to have an instance for the given entity bundle.

When creating fields as part of a custom module, you may or may not want to delete the field when the module is uninstalled. To do so, you can use field\_delete\_field() if you want to delete the field and all field instance, or if you want to delete specific instances you can use field\_delete\_instance().
> 41 votes

# Answer
Example on how to programatically add fields to the user profile and how to avail them, or not, into the User Registration form.

```

function MYMODULE_enable() {
  // Check if our field is not already created.
  if (!field_info_field('field_myField')) {

    // Create the field base.
    $field = array(
      'field_name' => 'field_myField',
      'type' => 'text',
    );
    field_create_field($field);

    // Create the field instance on the bundle.
    $instance = array(
      'field_name' => 'field_myField',
      'entity_type' => 'user',
      'label' => 'My Field Name',
      'bundle' => 'user',
      // If you don't set the "required" property then the field wont be required by default.
      'required' => TRUE,
      'settings' => array(
        // Here you inform either or not you want this field showing up on the registration form.
        'user_register_form' => 1,
      ),
      'widget' => array(
        'type' => 'textfield',
      ),
    );
    field_create_instance($instance);
  }
}

```
> 9 votes

# Answer
If you need to quickly create / delete fields from an existing Content Type or or Entity, without neither using the UI nor programming, you can use these little-known Drush commands:

> `drush field-create <bundle(for nodes)>
>  <field_name>,<field_type>,[widget_name] --entity_type` : Type of entity (e.g. node, user, comment). Defaults to node.

E.g.: Create two new fields for Article:

```
drush field-create article city,text,text_textfield subtitle,text,text_textfield

```

Other commands:

```
drush field-delete <field_name> [--bundle] [--entity_type]
drush field-info [field | types]
drush field-update <field_name> Return URL for field editing web page.
drush field-clone <source_field_name> <dst_field_name>

```
> 8 votes

# Answer
As pointed by others, you can use the Field API functions from the hook\_install() implementation of your module to create fields and their instances for you content type. See the node\_example\_install() for example usage of the function.

Another solution is to use the Features module. Features can export various site components to code in a module. Content types and fields are amongst these exportable. You can either generate a Features module and override your existing code, Features will then do its best to avoid breaking your code. Or you can generate a dummy module and copy./paste the fields-related code to your module. This requires basics understanding of how Features works.
> 4 votes

# Answer
In your install file you'll need to define both the 'hook\_install' and the 'hook\_uninstall'. Example included but read all about the extra keys in the API references (code is untested so might be typo's in there).

In the `hook_install` you can add the fields using:

field\_create\_field, This function builds a template for a field.

field\_create\_instance Can be used after creating the field to add it to content\_types (also known as bundles).

NOTE The names of various field types can be found in the modules that generate them (it's the key of the array item in their hook\_field\_info). You can find all the core field implementing modules in the modules/field/modules folder.

Settings can also be derived from the field modules. The settings you set in the `field_create_field` are the site wide ones. The ones you set in `field_instance_create` are the node\_type specific ones

```
    MY_MODULE_install(){
      // Generate the base for the field
      $field = array(
        'field_name' => 'FIELD_MACHINE_NAME',
        'type' => 'FIELD_TYPE' // See note above for what to put here
      );
      // Instance
      $instance = array(
        'field_name' => 'FIELD_MACHINE_NAME',
        'entity_type' => 'node',
      );

      // Create instances of the field and add them to the content_types
      $node_types = node_type_get_types();
      foreach($node_types as $node_type){
         $instance['bundle'] = $node_type->type;
         field_create_instance($instance);
      }
    }

```

In the `hook_uninstall`

field\_delete\_instance and field\_delete\_field can be used to remove them again, `field_delete_field` is called automatically if you delete the last instance (normally).

```
    MY_MODULE_uninstall(){
      $node_types = node_type_get_types();
      foreach($node_types as $node_type){
        if($instance = field_info_instance('node', 'FIELD_MACHINE_NAME', $node_type->type)) {
          field_delete_instance($instance);
        }
      }
    }

```
> 3 votes

# Answer
I recently had a similar need for a project, here is how I approached it, hope it helps somebody.

Basically you will create the fields you need using the fields UI, export them to code and then include them in your custom module. You will need the Devel module enabled.

I also created a Gist with this info.

Here we go....

1. Create the fields you need, using the usual Drupal UI.
2. On the same site, go to example.com/devel/php
3. Paste the following code into the "PHP code to execute" textbox.
4. Set the first 3 variables and then click execute

```
$entity_type = 'node';
$field_name = 'body';
$bundle_name = 'article';

$info_config = field_info_field($field_name);
$info_instance = field_info_instance($entity_type, $field_name, $bundle_name);
unset($info_config['id']);
unset($info_instance['id'], $info_instance['field_id']);
include_once DRUPAL_ROOT . '/includes/utility.inc';
$output = "\$fields['" . $field_name . "'] = " . drupal_var_export($info_config) . ";\n";
$output .= "\$instances['" . $field_name . "'] = " . drupal_var_export($info_instance) . ";";
drupal_set_message("<textarea rows=30 style=\"width: 100%;\">" . $output . '</textarea>');

```
5. You will get 2 arrays, something like this, hopefully with all the properties filled in.

> ```
> $fields['field_some_field'] = array(
>   'properties of the field'
> );
>
> $instances['field_some_field'] = array(
>   'properties of the instance'
> );
>
> ```

Now add the following code to your .install file. Replace all instances of mymodule with the actual module name. Paste the code from the devel output into the \_mymodule\_field\_data and \_mymodule\_instance\_data, as noted int the respective functions below. You can do this for as many fields as you like, just put all the $fields arrays in the \_mymodule\_field\_data function and all the $instances in the \_mymodule\_instance\_data function.

> ```
> function mymodule_install() {
>
>   // Create all the fields we are adding to our entity type.
>   // http://api.drupal.org/api/function/field_create_field/7
>   foreach (_mymodule_field_data() as $field) {
>     field_create_field($field);
>   }
>
>   // Create all the instances for our fields.
>   // http://api.drupal.org/api/function/field_create_instance/7
>   foreach (_mymodule_instance_data() as $instance) {
>     field_create_instance($instance);
>   }
> }
>
> // Create the array of information about the fields we want to create.
> function _mymodule_field_data() {
>   $fields = array();
>   // Paste $fields data from devel ouput here.
>   return $fields;
>   }
>
> // Create the array of information about the instances we want to create.
> function _mymodule_instance_data() {
>   $instances = array();
>   // Paste $instances data from devel output here.
>   return $instances;
> }
>
> ```
> 2 votes

# Answer
You could also consider using the Features module to create the fields at install time.

As Features generates code for fields, an option is just to use the Feature module to generate the code into a dummy module and then copy & paste into your module's .install file.

The benefit being is the module doesn't depend on the Features module in your target environment.
> 0 votes

# Answer
You can use the customcompanymodule code given below to programatically create a content type with its various fields.

You can add this code in a .install file of your custom module. It will programmatically add a content type called "company" and its various types of fields (text, numeric, date (note: you will need to install Date module as Date field is not provided by default), image, list).

I have also added the uninstall code that will remove the content type "company" along with all of its fields and data when you will uninstall your 'customcompanymodule' module.

You can modify/remove these fields as per your needs:

```
function customcompanymodule_install() {
     $t = get_t();
     node_types_rebuild();
     $company = array(
    'type' => 'company',
    'name' => $t('Company'),
    'base' => 'node_content',
    'module' => 'node',
    'description' => $t('Content type to handle companys.'),
    'body_label' => $t('Company Description'),
    'title_label' => $t('Company Title'),
    'promote' => 0,
    'status' => 1,
    'comment' => 0,
);
$content_type = node_type_set_defaults($company);

node_type_save($content_type);

foreach (_company_installed_fields() as $field) {
    field_create_field($field);
}

foreach (_company_installed_instances() as $instance) {
    $instance['entity_type'] = 'node';
    $instance['bundle'] = 'company';
    field_create_instance($instance);
}

$weight = db_query("SELECT weight FROM {system} WHERE name = :name",    array(':name' => 'categories'))->fetchField();
db_update('system')->fields(array(
            'weight' => $weight + 1,
        ))
        ->condition('name', 'company')
        ->execute();
}

function _company_installed_fields() {
$t = get_t();
$fields = array(
    'company_startdate' => array(
        'field_name' => 'company_startdate',
        'label' => $t('Company Start Date'),
        'cardinality' => 1,
        'type' => 'datetime',
        'module' => 'date',
        'settings' => array(
            'granularity' => array(
                'month' => 'month',
                'day' => 'day',
                'hour' => 'hour',
                'minute' => 'minute',
                'year' => 'year',
                'second' => 0,
            ),
            'tz_handling' => 'site',
            'timezone_db' => 'UTC',
            'cache_enabled' => 0,
            'cache_count' => '4',
            'todate' => 'required',
        ),
    ),
    'company_totalwinners' => array(
        'field_name' => 'company_totalwinners',
        'label' => $t('Maximum Company Winners'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_minwinner' => array(
        'field_name' => 'company_minwinner',
        'label' => $t('Minimum Entries for Company to Activate'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_totalentries' => array(
        'field_name' => 'company_totalentries',
        'label' => $t('Company Total Entries'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_points' => array(
        'field_name' => 'company_points',
        'label' => $t('Company Points'),
        'cardinality' => 1,
        'type' => 'number_integer',
        'module' => 'number',
        'settings' => array(
            'max_length' => 10000,
        ),
    ),
    'company_image' => array(
        'field_name' => 'company_image',
        'label' => $t('Image'),
        'cardinality' => 1,
        'type' => 'image',
        'settings' => array(
            'default_image' => 0,
            'uri_scheme' => 'public',
        ),
    ),
    'company_description' => array(
        'field_name' => 'company_description',
        'label' => $t('Company Description'),
        'cardinality' => 1,
        'type' => 'text',
        'module' => 'text',
        'length' => '255'
    ),
    'company_winner' => array(
        'field_name' => 'company_winner',
        'label' => $t('Company Description'),
        'cardinality' => 1,
        'type' => 'text',
        'module' => 'text',
        'length' => '255'
    ),
    'field_autowinnerselection' => array(
        'field_name' => 'field_autowinnerselection',
        'label' => $t('Auto Company Winner Selection'),
        'type' => 'list_boolean',
        'module' => 'list',
        'active' => '1',
        'locked' => '0',
        'cardinality' => '1',
        'deleted' => '0'
    ),
);
return $fields;
}

function _company_installed_instances() {
$t = get_t();
$instances = array(
    'company_startdate' => array(
        'field_name' => 'company_startdate',
        'label' => $t('Company Lifespan'),
        'cardinality' => 1,
        'widget' => array(
            'type' => 'date_popup',
            'module' => 'date',
            'settings' => array(
                'input_format' => 'm/d/Y - H:i:s',
                'input_format_custom' => '',
                'year_range' => '-3:+3',
                'increment' => '15',
                'label_position' => 'above',
                'text_parts' => array(),
            ),
        ),
    ),
    'company_totalwinners' => array(
        'field_name' => 'company_totalwinners',
        'label' => $t('Maximum Company Winners'),
        'cardinality' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_minwinner' => array(
        'field_name' => 'company_minwinner',
        'label' => $t('Minimum Number of Entries for Company to Activate'),
        'cardinality' => 1,
        'required' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_totalentries' => array(
        'field_name' => 'company_totalentries',
        'label' => $t('Company Total Entries'),
        'cardinality' => 1,
        'required' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_points' => array(
        'field_name' => 'company_points',
        'label' => $t('Company Points'),
        'cardinality' => 1,
        'required' => 1,
        'widget' => array(
            'type' => 'number',
            'module' => 'number',
            'settings' => array('size' => 60),
        ),
    ),
    'company_image' => array(
        'field_name' => 'company_image',
        'label' => $t('Image'),
        'cardinality' => 1,
        'required' => 1,
        'type' => 'company_image',
        'settings' => array(
            'max_filesize' => '',
            'max_resolution' => '213x140',
            'min_resolution' => '213x140',
            'alt_field' => 1,
            'default_image' => 0
        ),
        'widget' => array(
            'settings' => array(
                'preview_image_style' => 'thumbnail',
                'progress_indicator' => 'throbber',
            ),
        ),
        'display' => array(
            'default' => array(
                'label' => 'hidden',
                'type' => 'image',
                'settings' => array('image_style' => 'medium', 'image_link' => ''),
                'weight' => -1,
            ),
            'teaser' => array(
                'label' => 'hidden',
                'type' => 'image',
                'settings' => array('image_style' => 'thumbnail', 'image_link' => 'content'),
                'weight' => -1,
            ),
        ),
    ),
    'company_description' => array(
        'field_name' => 'company_description',
        'label' => $t('Company Description'),
        'cardinality' => 1,
        'widget' => array(
            'weight' => '-3',
            'type' => 'text_textfield',
            'module' => 'text',
            'active' => 1,
            'settings' => array(
                'size' => '1000',
            ),
        ),
    ),
    'company_winner' => array(
        'field_name' => 'company_winner',
        'label' => $t('Company Winner'),
        'cardinality' => 1,
        'widget' => array(
            'weight' => '-3',
            'type' => 'text_textfield',
            'module' => 'text',
            'active' => 1,
            'settings' => array(
                'size' => '60',
            ),
        ),
    ),
    'field_autowinnerselection' => array(
        'field_name' => 'field_autowinnerselection',
        'required' => 1,
        'label' => $t('Auto Company Winner Selection'),
        'widget' => array(
            'weight' => '-3',
            'type' => 'options_buttons',
            'module' => 'options',
            'active' => 1,
            'settings' => array(),
        ),
    ),
);
return $instances;
}

function customcompanymodule_uninstall() {
$content_types = array(
    'name1' => 'company',
);
$sql = 'SELECT nid FROM {node} n WHERE n.type = :type1';
$result = db_query($sql, array(':type1' => $content_types['name1']));
$nids = array();
foreach ($result as $row) {
    $nids[] = $row->nid;
}
node_delete_multiple($nids);
node_type_delete($content_types['name1']);
field_purge_batch(1000);
}

```
> 0 votes

# Answer
Try this module if you're looking for a way to create fields programmatically in Drupal 8: https://drupal.org/project/field\_create
> 0 votes

---
Tags: 7, entities
---


title: Add content type field programmatically

text:
# Question
Title: Add content type field programmatically
My module provides a configuration form which allows to select a content type and on submit 2 new fields will be added to the selected content types.

I want to add these fields to the content types programmatically and I tried this using `hook_entity_bundle_field_info` but the fields don't get saved.

How can I save the fields? And how can I delete the fields (if the user changes the content type in the configuration form)?

# Answer
> 20 votes
You can use this example from the node module.

This adds a body field when a content type is created and at the same time configures the display modes (view modes and form modes):

**core/modules/node/node.module:**

```
/**
 * Adds the default body field to a node type.
 *
 * @param \Drupal\node\NodeTypeInterface $type
 *   A node type object.
 * @param string $label
 *   (optional) The label for the body instance.
 *
 * @return \Drupal\field\Entity\FieldConfig
 *   A Body field object.
 */
function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
  // Add or remove the body field, as needed.
  $field_storage = FieldStorageConfig::loadByName('node', 'body');
  $field = FieldConfig::loadByName('node', $type->id(), 'body');
  if (empty($field)) {
    $field = FieldConfig::create([
      'field_storage' => $field_storage,
      'bundle' => $type->id(),
      'label' => $label,
      'settings' => ['display_summary' => TRUE],
    ]);
    $field->save();

    /** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
    $display_repository = \Drupal::service('entity_display.repository');

    // Assign widget settings for the default form mode.
    $display_repository->getFormDisplay('node', $type->id())
      ->setComponent('body', [
        'type' => 'text_textarea_with_summary',
      ])
      ->save();

    // Assign display settings for the 'default' and 'teaser' view modes.
    $display_repository->getViewDisplay('node', $type->id())
      ->setComponent('body', [
        'label' => 'hidden',
        'type' => 'text_default',
      ])
      ->save();

    // The teaser view mode is created by the Standard profile and therefore
    // might not exist.
    $view_modes = \Drupal::service('entity_display.repository')->getViewModes('node');
    if (isset($view_modes['teaser'])) {
      $display_repository->getViewDisplay('node', $type->id(), 'teaser')
        ->setComponent('body', [
          'label' => 'hidden',
          'type' => 'text_summary_or_trimmed',
        ])
        ->save();
    }
  }

  return $field;
}

```

**Edit:** Code updated from 8.8.x to remove deprecated functions, see change record https://www.drupal.org/node/2835616

The field storage itself is not added or deleted because it is shared between all content types. You have to do this once when you install the module. The easiest way is to put a yml file for the storage in /config/install. Example from the node module:

**core/modules/node/config/install/field.storage.node.body.yml:**

```
langcode: en
status: true
dependencies:
  module:
    - node
    - text
id: node.body
field_name: body
entity_type: node
type: text_with_summary
settings: {  }
module: text
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: true
custom_storage: false

```

# Answer
> 12 votes
> **Edit**: Little More Description: For adding entity type (content type, block type, product type, variation type ... ) field programmatically you need

1. **Create Field Storage Configuration**: *only then*
2. **Create Field Configuration**

> You can use Drupal 8 configuration Single export which can be found here -\> **/admin/config/development/configuration/single/export**
>
> > Selecting needed **Field Storage** or **Field** config will give you desired fields and their values.

**Next All Described Very Well**

I like to add, that the node modules code uses some deprecated functions. (We are now 8.5.6).

Here's my part of the code which handles "create a field storage programmatically:

```
if (empty($fieldStorageMicrositesfield = \Drupal\field\Entity\FieldStorageConfig::loadByName('node', $fieldName))) {
  $fieldStorage = \Drupal\field\Entity\FieldStorageConfig::create(
    [
      'field_name'             => $fieldName,
      'langcode'               => 'en',
      'entity_type'            => 'node',
      'type'                   => 'list_string',
      'settings'               => [
        'allowed_values'          => [],
        'allowed_values_function' => 'I_used_a_custum_function_here_which_you_not_need_I_guess',
      ],
      'module'                 => 'options',
      'locked'                 => FALSE,
      'cardinality'            => -1,
      'translatable'           => TRUE,
      'persist_with_no_fields' => FALSE,
      'custom_storage'         => FALSE,
    ]
  );
  $fieldStorageSaved = $fieldStorage->save();
  if ($fieldStorageSaved) {
    $message = t(
      "Field @a storage created.",
      ['@a' => $fieldName,]
    );
  }
  else {
    $message = t(
      "Field @a storage could not be created.",
      ['@a' => $fieldName,]
    );
  }
}
else {
  $message = t(
    "Field @a storage could not be created because the field already exists",
    ['@a' => $fieldName,]
  );
}

```

Here's my part of the code which handles the adding of a field to several content types after I created the storage (`$bundles` holds the array of my content types):

```
$entityTypemanager = \Drupal::entityTypeManager();

foreach ($bundles as $bundle) {
  $field = FieldConfig::loadByName('node', $bundle, $fieldName);
  if (empty($field)) {
    FieldConfig::create(
      [
        'field_name'   => $fieldName,
        'entity_type'  => 'node',
        'bundle'       => $bundle,
        'label'        => $label,
        'required'     => TRUE,
        'translatable' => TRUE,
        'description'  => t(
          $description
        ),
      ]
    )->save();
    $message .= "\n" . t(
        "Field @a created in bundle @b.",
        ['@a' => $fieldName, '@b' => $bundle]
      );

    // Assign widget settings for the 'default' form mode.
    $displayForm = $entityTypemanager
      ->getStorage('entity_form_display')
      ->load('node.' . $bundle . '.default')
      ->setComponent($fieldName, [
        'type'   => 'options_buttons',
        'weight' => 100,
      ]);
    $messagePart = '';
    if ($displayForm->save()) {
      $messagePart .= ' form-';
    }
    else {
      $message .= "\n" . t(
          "The form display of @a in bundle @b could not be set",
          ['@a' => $fieldName, '@b' => $bundle]
        );
    }
    unset($displayForm);

    // Assign display settings for the 'default' and 'teaser' view modes.
    $displayDefault = $entityTypemanager
      ->getStorage('entity_view_display')
      ->load('node.' . $bundle . '.default')
      ->removeComponent($fieldName);
    if ($displayDefault->save()) {
      $messagePart .= ' default-';
    }
    else {
      $message .= "\n" . t(
          "The default display of @a in bundle @b could not be set",
          ['@a' => $fieldName, '@b' => $bundle]
        );
    }
    unset($displayDefault);

    // The teaser view mode is created by the Standard profile and therefore
    // might not exist.
    $viewModes = \Drupal::service('entity_display.repository')
      ->getViewModes('node');
    if (isset($viewModes['teaser'])) {
      $displayTeaser = $entityTypemanager
        ->getStorage('entity_view_display')
        ->load('node.' . $bundle . '.teaser')
        ->removeComponent($fieldName);
      if ($displayTeaser->save()) {
        $messagePart .= ' teaser-';
      }
      else {
        $message .= "\n" . t(
            "The teaser display of @a in bundle @b could not be set",
            ['@a' => $fieldName, '@b' => $bundle]
          );
      }
      unset($displayTeaser);
    }
    $message .= "\n" . t(
        $messagePart . "Display(s) of @a in bundle @b are set.",
        ['@a' => $fieldName, '@b' => $bundle]
      );

  }
  else {
    $message .= "\n" . t(
        "Field @a already exists in bundle @b.",
        ['@a' => $fieldName, '@b' => $bundle]
      );
  }
}

```

# Answer
> 3 votes
```
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;

function module_name_update_9002(){
    FieldStorageConfig::create(array(
        'field_name' => 'example_field',
        'entity_type' => 'node',
        'type' => 'text',
        'cardinality' => -1,
        ))->save();

    FieldConfig::create([
    'field_name' => 'example_field',
    'entity_type' => 'node',
    'bundle' => 'article', // content type
    'label' => 'Example field',
    ])->save();
    // Manage form display
    $form_display = \Drupal::service('entity_display.repository')->getFormDisplay('node', 'article' );
    $form_display = $form_display->setComponent('example_field', ['type' => 'text_textfield']);
    $form_display->save();
    // Manage view display
    $view_display = \Drupal::service('entity_display.repository')->getViewDisplay('node', 'article');
    $view_display->setComponent('example_field', ['type' => 'text_default']);
    $view_display->save();

}

```

Here is one example in Drupal 9, 'example\_fields' is field name and and 'article' is my content type, this can be written in hook\_update\_N or hook\_form\_alter.

# Answer
> 0 votes
You can try this module to create fields programmatically in Drupal 8: https://drupal.org/project/field\_create

Use the provided hook in your module:

```
function mymodule_field_create_alter(&$definitions) { }

```

Add your fields to the list and run the drush command:

```
drush field_create

```

---
Tags: 8, entities
---


title: GMap Module - markers not showing up

text:
# Question
Title: GMap Module - markers not showing up
I can't seem to get my markers to come up in the Gmap module - I've changed permissions, I've checked the gmap\_markers.js file, etc.

The map itself comes up, but I can't get any markers to appear.

What could cause this?

Could it be permission settings on my /default/files directory?

# Answer
> 2 votes
This question is obviously very old, but I spent the last few hours figuring out the same issue and figured this might help someone else who is Googling this problem.

The problem for me was this:

In Modules, "Location Entity" should NOT be enabled. "Location CCK" (in the Fields section) should be.

Then, when modifying the Content Types, do NOT rely on the "Location" field that is there by default (machine name = locations). You have to add your own, additional Location field (field type = Location; widget = Location Field).

This solved the problem for me. I created a View (Page) for a Specific Content Type with Format = GMap and Data Source = Location.module.

Then it finally worked! Hope this helps.

# Answer
> 0 votes
I looked everywhere for a way to fix this issue for me, and none of the answers I found worked. So I thought I'd post my solution here, in case it might help someone else in future. My problem was simply that I had the theme\_debug variable set to 1. As soon as I turned theme debug back off, all my markers worked again! With drush you can just do (in Drupal 7) "drush vset theme\_debug 0". That fixed my issue!

---
Tags: 7, google-maps
---


# Question
Title: entity_form how to programmatically add references and update the form visually (entity_browser)
I´m having an fieldable entity with a reference field to paragraphs `field_paragraphs` and a paragraph\_type with a reference field to content\_type event `field_events`.

What i am trying in the entity form is to have a button in the paragraph\_type event subform which on click prefills the `field_events` of the paragraph\_type with content. The form display of `field_events` uses an entity\_browser to let the user also manually choose or deselect programmatically added events and i guess this is where I am stuck.

I think i am pretty close to the solution, let me try to describe:

When clicking the button, the added events are not visible, if I use the entity\_browser now to insert an event, all the events that i programmatically added get displayed.

So I somehow need to tell the entity\_browser in my callback to return the updated list, i guess (I´m a Drupal beginner, so please go easy on me) But I have no clue how to do so, also i think it should be possible without doing so? I mean just add the references and let the "form rebuild independently of the form display" ... I dont know, here is the code so far:

```
/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function module_field_widget_paragraphs_form_alter(&$element, &$form_state, $context) {

  switch ($element['#paragraph_type']) {
   case 'events':

      $replace_id = $element['subform']['field_events']['widget']['#id'];

      $element["subform"]['add_tomorrows_events_button'] = [
        '#type' => 'button',
        '#attributes' => [
          'name' => 'add_tomorrows_events',
        ],
        '#value' => t('Add tomorrows events'),
        '#ajax' => [
          'callback' => 'module_insert_tomorrows_events_into_paragraph_events',
          'wrapper' => $replace_id,
          'method' => 'replace',
          'event' => 'click',
        ]
      ];

     break;

   default:
     // code...
     break;
 }

}

```

---

```
/**
 * Ajax callback.
 */
function module_insert_tomorrows_events_into_paragraph_events( &$form, FormStateInterface &$form_state) {

  /* Get the index of the paragraph in field_paragraphs */
  $triggering_element = $form_state->getTriggeringElement();
  $paragraph_index = $triggering_element["#parents"][1];

  /* For now just try to add 10 events */
  $results = \Drupal::entityQuery('node')
  ->condition('type', 'event')
  ->range(0, 10)
  ->execute();

  /* Here I´m trying to build up the string like it is in the target_id key of the widget
     e.G "node:3213 node:54354 node:432423"
  */
  $target_ids = "";
  foreach ($results as $res) {
    $target_ids .= " node:".$res;
  }

  $form["field_paragraphs"]['widget'][$paragraph_index]["subform"]["field_events"]["widget"]["target_id"]['#value'] = $target_ids;

  /* just other stuff i tried */
  /*$form["field_paragraphs"]['widget'][$paragraph_index]["subform"]["field_events"]["widget"]["target_id"]['#default_value'] = $target_ids;*/
  /*  $form_state->setValue(['field_paragraphs', $paragraph_index, 'subform', 'field_events', 'target_id'], $target_ids);
  $form_state->setRebuild(true);
    */
/* tried to update the EB but `current` is not updated :/
   $t = EntityReferenceBrowserWidget::updateWidgetCallback($form, $form_state);
   return $t["field_paragraphs"]["widget"][$paragraph_index]["subform"]["field_events"]["widget"];
*/

  return $form["field_paragraphs"]['widget'][$paragraph_index]["subform"]["field_events"]["widget"];
}

```

TL;DR: The events get added but the entity\_form/entity\_browser is not updated visually, after using the entity\_browser all programmatically added events get displayed, how to display them in the first place?

# Answer
I got it working, i´m sharing this if anybody stumbles across the same, in the end it was trivial with using ReplaceCommand and InvokeCommand

```
function module_field_widget_paragraphs_form_alter(&$element, &$form_state, $context) {
  switch ($element['#paragraph_type']) {
    case 'paragraph_events':

      // Add the button only if the paragraph-subform is expanded.
      if ($element['top']['summary']['fields_info']['#expanded']) {
        $element["subform"]['add_tomorrows_events_button'] = [
          '#type' => 'button',
          '#attributes' => [
            'name' => 'add_tomorrows_events',
          ],
          '#value' => t('insert tomorrows events'),
          '#ajax' => [
            'callback' => '_module_insert_tomorrows_events_into_paragraph_events',
            'event' => 'click',
          ],
        ];
      }

      break;

      ...

```

and the callback

```
function _module_insert_tomorrows_events_into_paragraph_events(&$form, FormStateInterface $form_state): AjaxResponse {

  $triggering_element = $form_state->getTriggeringElement();
  $paragraph_index = $triggering_element["#parents"][1];

  // Load results from view.
  $view = Views::getView('events');
  if (!$view || !array_key_exists('tomorrows_events', $view->storage->get('display'))) {
    return "view \"events\" or display \"tomorrows_events\" is missing";
  }

  $view->setDisplay('tomorrows_events');
  $view->execute();
  $results = $view->result;

  $target_ids = "";
  foreach ($results as $res) {
    $target_ids .= " node:" . $res->nid;
  }

  $form["field_paragraphs"]['widget'][$paragraph_index]["subform"]["field_events"]["widget"]["target_id"]['#value'] = $target_ids;
  $response = new AjaxResponse();

  $sel = '#' . $form["field_paragraphs"]["widget"][$paragraph_index]["subform"]['field_events']['widget']['target_id']["#id"];
  $response->addCommand(new ReplaceCommand($sel, $form["field_paragraphs"]["widget"][$paragraph_index]["subform"]['field_events']['widget']['target_id']));
  $response->addCommand(new InvokeCommand($sel, 'trigger', ['entity_browser_value_updated']));

  return $response;

}

```
> 0 votes

---
Tags: forms, ajax, 9
---


# Question
Title: Can users with a custom role approve the user registration?
I have created a site that requires approval of new user registrations. I added the *Manager* role for the site owner. I'd like users with that role to approve the account registrations.

Is there any configuration that will give another role the permission to approve new user registration?

# Answer
On the **Permissions** screen at `/admin/people/permissions`, you can give the permission **Administer users** to the Manager role.

**Administer users** is an administrator permission, but you do not need to give the other administrator permissions to the **Manager** role.

If you really don't want the **Manager** role to have unlimited access to user accounts, you could use the Views Bulk Operations (VBO) module and code a custom action to allow managers to unblock new user accounts. You will need to code a custom action because the VBO module includes an unblock users action by default, but this requires **Administer users** permission.
> 0 votes

---
Tags: users
---


title: View Filters' OR operator not applied

text:
# Question
Title: View Filters' OR operator not applied
I created a content view that has a filter group using the AND operator that is ANDed with another filter group using the OR operator (see image below)

However, the query constructed is all AND operators and groups aren't even applied. Here is the WHERE clause of the query:

```
WHERE
(
  (
    // Content: Type (= On-demand)
    node__field_format.field_format_target_id = '29'
  )
)
AND
(
  (
    (
      // Content: Published (= Yes)
      "node_field_data"."status" = '1'
    )
    AND
    (
      // Content: Content type (in Event, Training)
      "node_field_data"."type" IN ('event', 'training_session')
    )
  )
  AND
  (
    (
      // (field_date_and_location: Paragraph) Paragraph: Date Range (>= + 0 minutes)
      DATE_FORMAT((paragraphs_item_field_data_node__field_date_and_location__paragraph__field_date_range.field_date_range_value + INTERVAL -21600 SECOND), '%Y-%m-%d\T%H:%i:%s') >= DATE_FORMAT(('2021-10-19T18:53:48' + INTERVAL -21600 SECOND), '%Y-%m-%d\T%H:%i:%s')
    )
  )
)

```

This query isn't even remotely close to what I have it configured as... By my configurations, I would expect the WHERE clause to be

```
WHERE
(
  (
    // Content: Published (= Yes)
    "node_field_data"."status" = '1'
  )
  AND
  (
    // Content: Content type (in Event, Training)
    "node_field_data"."type" IN ('event', 'training_session')
  )
)
AND
(
  (
    // Content: Type (= On-demand)
    node__field_format.field_format_target_id = '29'
  )
  OR
  (
    // (field_date_and_location: Paragraph) Paragraph: Date Range (>= + 0 minutes)
    DATE_FORMAT((paragraphs_item_field_data_node__field_date_and_location__paragraph__field_date_range.field_date_range_value + INTERVAL -21600 SECOND), '%Y-%m-%d\T%H:%i:%s') >= DATE_FORMAT(('2021-10-19T18:53:48' + INTERVAL -21600 SECOND), '%Y-%m-%d\T%H:%i:%s')
  )
)

```

What's the issue with my configurations? I feel this should be pretty a straightforward implementation but the degree to which the query is incorrect seems off..

# Answer
It appears that Drupal has a bug in their code. The content type we are displaying has a couple of `Types` which is a taxonomy term. If a record has an `On Demand` taxonomy type, it does not have a Date. However, when displaying this list we need to display all content with a date in the future OR has the 'On Demand' taxonomy type.

In addition, we have an exposed filter that allows a user to filter by this taxonomy term type. Therefore, there are two separate filters on the same field, one is exposed the other is not.

In the first condition group, there exists an exposed filter condition called `Has Taxonomy Term` that is looking at the `Topic` taxonomy term.

In the second condition group, there exists a non-exposed filter condition called `Content: Type` that is also looking at the `Topic` taxonomy term.

However, when Drupal builds up this where clause. it puts the `Content Type == On Demand` condition into the condition group where the similar exposed filter exists.

You MUST fix this in `hook_views_query_alter`. I have reported this as a bug on Drupal.org
> 0 votes

---
Tags: 8, views
---


# Question
Title: How to use migrate process plugin concat on multiple values?
I am trying to import from a csv that has multiple files in the same column, e.g.

```
title,gallery,tag
node1,img1.jpg|img2.jpg|img3.jpg,2
node2,img4.jpg,2
node3,img5.jpg|img6.jpg,3

```

I need to prepend the path to these file names to get something of the form `/path/to/file/img4.jpg`.

I have written a process pipeline similar to the following (which doesn't work):

```
source:
  constants:
    file_source: '/import/images/'
    file_destination: '/path/to/file/'
process:
  title: title
  field_gallery:
    -
      plugin: explode
      source: gallery
      delimiter: '|'
    -
      plugin: concat
      source:
        - constants/file_source
        -
    -
      plugin: image_import
      destination: constants/file_destination

```

The failure comes because the Concat plugin implodes the array containing a string and an array to give an output in the form `/path/to/file/Array`.

I suspect there is a process plugin that I can insert between explode and concat that will solve this, but I can't work out what it is.

I have tried combinations of the plugins `single_value` and `multiple_values` from the Migrate Plus module, but that has not worked either.

For now I have written a custom process plugin to replace concat, but I would prefer a pipeline using pre-existing plugins.

# Answer
> 2 votes
I don't think this is possible with `concat` in a single pipe, because you need to define two sources for concat, and AFAIK you can't fill the source partly with the result from the previous section and partly with a completely new value.

Workaround: Use the str\_replace plugin instead, which is a wrapper for PHP's preg\_replace.

`preg_replace` will detect if `source` respectively `$subject` is an string or an array. If the `$subject` is an array, all elements will be updated, so you can replace all beginnings of a string `^` with `/some/path/`

Something like this:

```
  field_gallery:
    -
      plugin: str_replace
      regex: true
      source: gallery
      search: '/^/'
      replace: '/some/path/'

```

(Note that the slashes in `search` are not path delimiters, they are the enclosing symbol for the regex pattern)

# Answer
> 0 votes
Here are the highlights of the process plugin I wrote, in case anyone is interested in a custom solution:

```
class Prepend extends ProcessPluginBase {

  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    $return = [];
    foreach ($value as $item) {
      $return[] = implode($item);
    }
    return $return;
  }

  public function multiple() {
    return TRUE;
  }

}

```

Note: an important difference between this and the `concat` process plugin is the addition of the `multiple()` function that returns TRUE.

It can be used as follows:

```
field_gallery:
  -
    plugin: explode
    source: gallery_images
    delimiter: '|'
  -
    plugin: prepend
    source:
      - constants/file_source
      -
  -
    plugin: image_import
    destination: constants/file_destination
    uid: '@uid'
    skip_on_missing_source: true

```

**EDIT**: FWIW I have chosen to use the solution suggested by @Hudri.

---
Tags: 8, migrations, plugins
---


# Question
Title: Why can't some fields be moved within details element?
I am trying to move 2 form fields to the advanced sidebar: dismissible and status. Status was already part of the meta container and setting #group='meta' on dismissable also placed it there; but these weren't in the proper order. Nothing I do seems to have any impact on:

* dismissible
* standard meta fields: published, author, revision log
* status

Both dismissible and status are fields added by the Sitewide Alert module which defines the entity which this is the edit form for.

I gave up trying to move my 2 fields (together) so I created my own details block as:

```
  $form['alert_settings'] = [
    '#type' => 'details',
    '#group' => 'advanced',
    '#weight' => -99,
    '#title' => t('Alert settings'),
    '#tree' => TRUE,
    '#access' => TRUE,
    '#open' => TRUE,
  ];

```

and then assigned both fields #group='alert\_settings'. This works fine as it creates a new details group which is placed at the top of the right sidebar. Perfect, except I want status to be the top item in this block, followed by dismissible.

No matter which of the status #weight options I set (or dismissable ones); I can't change the order of these.

I have tried:

```
  $form['status']['#weight'] = -99;
  $form['status']['widget']['#weight'] = -99;
  $form['status']['widget']['value']['#weight'] = -99;

```

What am I missing here?

# Answer
> 2 votes
It seems ultimately to be down to this code in `EntityFormDisplay::processForm()`:

```
// Assign the weights configured in the form display.
foreach ($this->getComponents() as $name => $options) {
  if (isset($element[$name])) {
    $element[$name]['#weight'] = $options['weight'];
  }
}

```

This method is a `#process` callback for the form which runs after form alter hooks, so your changes are lost.

You could add your own process callback and change the weights there, but it might be a bit cleaner to alter it at the component level with `hook_entity_form_display_alter()`, e.g.:

```
function MODULE_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) {
  if ($context['entity_type'] == 'sitewide_alert') {
    $status = $form_display->getComponent('status');
    // 'dismissible' is set to the base field's weight, -10.
    $status['weight'] = -11;
    $form_display->setComponent('status', $status);
  }
}

```

Incidentally, `$form['status']['#weight']` would have been the right choice if the process callback wasn't overriding it.

---
Tags: 8, forms
---


# Question
Title: anchor menu description under each menu in menu.html.twig
I am currently displaying the Menu "description" underneath each link using menu.html.twig. by doing this:

```
{% if item.original_link.getDescription %}
  <span class="navigation__link-description">{{ item.original_link.getDescription() }}</span>
{% endif %}

```

The issue is that it's not anchored with the URL due to it being outside `{{ link(item.title, item.url) }}`. Does anyone know what I need to do?

Here's a small snippet of where my description is:

```
        {% if menu_attributes.link is empty %}
          {{ link(item.title, item.url) }}
          {% if item.original_link.getDescription %}
            <span class="navigation__link-description">{{ item.original_link.getDescription() }}</span>
          {% endif %}
        {% else %}
          {{ link(item.title, item.url, menu_attributes.link) }}
        {% endif %}
        {% if item.below %}
          {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
        {% endif %}
      </li>

```

# Answer
```
{% if item.original_link.getDescription %}
  <span class="navigation__link-description">
    {{ link(item.original_link.getDescription(), item.url, menu_attributes.link) }}
  </span>
{% endif %}

```

Try the above to create another link using your descriptipion as text. If we need link then link() function should be used.
> -1 votes

---
Tags: theming, navigation, 9
---


# Question
Title: What's the equivalent of drupal_build_css_cache()?
Our client uses an external website for some of their pages. This provider does not enable us to theme their website directly, but they do allow us to load a single JS file from the Drupal site that we maintain.

We create this JS file through a Drupal route/controller, assembling the header and footer blocks, including CSS and JS files, and inserting them into the content by appending them to the appropriate elements.

We've ported all of the functionality to Drupal 8 from 7 and it's more efficient than before. However, we used to use drupal\_build\_css\_cache() to aggregate the subset of CSS files from themes and modules that we need before injecting them into the website's head.

Keeping in mind that all we're delivering to the external website is a single JS file (so we can't attach a library in the usual way), is there a way of programatically creating an aggregated CSS file in Drupal 8, as that function used to do?

# Answer
`drupal_build_css_cache()` is a Drupal 7 function that was removed very early in the Drupal 8 development cycle. The change notices back then weren't very good, so simply searching for that function name won't find anything. (Change notices may be found at https://www.drupal.org/list-changes). The relevant change notice is Pluggable CSS & JS preprocessing (aggregation/minification)

This does not say what `drupal_build_css_cache()` was replaced with, but searching the code of the patch that removed the function shows that the code of that function is now in the `asset.css.collection_optimizer` service (implemented in `\Drupal\Core\Asset\CssCollectionOptimizer`)
> 2 votes

# Answer
https://api.drupal.org/api/drupal/core%21includes%21common.inc/function/\_drupal\_flush\_css\_js/8.5.x

Try the above. it will clear all caches of JS and CSS.

https://api.drupal.org/api/drupal/core%21includes%21common.inc/function/drupal\_flush\_all\_caches/8.5.x

It will clear all caches and rebuild.
> -2 votes

---
Tags: 8, css-js-aggregation
---


# Question
Title: How to implement TrustedCallbackInterface
I'm maintaining a module that I've had a 3rd party dev build for me. I D9 this issue has appeared when using the module that otherwise works in D8 and should be compatible with 8 & 9.

The module creates blocks with event dates pulled from the Songkick service but on D9 pages with a songkick block enabled throws this error:

> Drupal\Core\Security\UntrustedCallbackException: Render #pre\_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was \_songkick\_block\_poweredby\_prerender. See https://www.drupal.org/node/2966725 in Drupal\Core\Render\Renderer-\>doTrustedCallback() (line 96 of /var/www/html/web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php).

I'm a mere site builder with limited coding experience so I'm looking for help to fix the issue. The error mentions this page explaining the issue.

The code below from my .module files includes the pre\_render in mention.

```
/**
 * Implements hook_block_view_alter().
 */
function songkick_block_content_view_alter(array &$build) {
    $id = $build['#block_content']->id();
  $block = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  if ($block_type == 'songkick_block') {
        $build['#pre_render'][] = '_songkick_block_poweredby_prerender';
    }
}

/**
 * Get a Upcoming & past events API data.
 */
function _songkick_block_poweredby_prerender(array &$build) {
  $id = $build['#block_content']->id();
  $block = \Drupal\block_content\Entity\BlockContent::load($id);
  $block_type = $block->type[0]->target_id;
  if ($block_type == 'songkick_block') {
    // Get custom Blocks data.
      $artis_id = $block->field_artist_id[0]->value;
      $upcoming_show = $block->field_display_upcoming_shows[0]->value;
      $past_show = $block->field_display_past_shows[0]->value;
      $event_details = $block->field_ticket_button[0]->value;
      $events_data = [
        'event_details' => $event_details,
        'upcoming_show' => $upcoming_show,
        'past_show' => $past_show
      ];
      $events_data = [
          '#theme' => 'songkick_events',
          '#events_data' => $events_data
      ];

        $client = \Drupal::httpClient();
        $api_key = \Drupal::config('songkick.settings')->get('songkick_key');
        $url = 'http://api.songkick.com/api/3.0/artists/';

        // Upcoming event data.
    if ($upcoming_show == '1') {
            $apikey = $url . $artis_id. "/calendar.json" . "?apikey=". $api_key;
            $request = $client->get($apikey);
            $body = $request->getBody()->getContents();
            $AllData = (array)json_decode($body);
            // Last page data
            $per_page = $AllData['resultsPage']->perPage;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $page = (int)($total_entry / $per_page);
            //$mainData = $AllData['resultsPage']->results->event;
            $temp_var = [];
            for ($x = $page; $x >= 0; $x--){
                $final_api_key = $apikey . "&page=" . $x;
                $upcoming_event_request = $client->get($final_api_key);
                $upcoming_event_body = $upcoming_event_request->getBody()->getContents();
                $UpcomingEventAllData = json_decode($upcoming_event_body);
                $mainData = array_reverse($UpcomingEventAllData->resultsPage->results->event);

                //$temp_data[] = $mainData;
                foreach ($mainData as $value) {
                    $temp_var[] = $value;
                }

            }
            $upcoming_events_data = [
          '#theme' => 'songkick_events',
          '#upcoming_event' => $temp_var
        ];
    }
    else{
            $upcoming_events_data = [
          '#theme' => 'songkick_events',
          '#upcoming_event' => ''
        ];
    }

    // Past event data.
    if ($past_show == '1') {
            $apikey = $url . $artis_id. "/gigography.json" . "?apikey=". $api_key;
            $request = $client->get($apikey);
            $body = $request->getBody()->getContents();
            $AllData = (array)json_decode($body);

            // Last page data
            $per_page = $AllData['resultsPage']->perPage;
            $total_entry = $AllData['resultsPage']->totalEntries;
            $page = (int)($total_entry / $per_page);

            $temp_var = [];
            for ($x = $page; $x >= 0; $x--){
                $final_api_key = $apikey . "&page=" . $x;
                $past_event_request = $client->get($final_api_key);
                $past_event_body = $past_event_request->getBody()->getContents();
                $PastEventAllData = json_decode($past_event_body);
                $mainData = array_reverse($PastEventAllData->resultsPage->results->event);

                //$temp_data[] = $mainData;
                foreach ($mainData as $value) {
                    $temp_var[] = $value;
                }
            }
            //$final_api_key = $apikey . "&page=" . $page;
            // $past_event_request = $client->get($final_api_key);
            // $past_event_body = $past_event_request->getBody()->getContents();
            // $PastEventAllData = (array)json_decode($past_event_body);
            // $mainData = array_reverse($PastEventAllData['resultsPage']->results->event);
            $past_events_data = [
          '#theme' => 'songkick_events',
          '#past_event' => $temp_var
        ];
    }
    else{
            $past_events_data = [
          '#theme' => 'songkick_events',
          '#past_event' => ''
        ];
    }

    // Merge Upcoming & past evenst data.
    $event_data = array_merge($upcoming_events_data,$past_events_data,$events_data);

    // Return events data.
        return $event_data;
  }
}

```

I've tried following the instructions in this comment and have added a file named SongkickBlockPoweredByViewBuilder.php in the src folder with this code:

```
<?php

namespace Drupal\Songkick;

use Drupal\Core\Security\TrustedCallbackInterface;

/**
 * Provides a trusted callback for the Songkick Poweredby block.
 *
 */
class SongkickBlockPoweredByViewBuilder implements TrustedCallbackInterface {

    /**
     * {@inheritdoc}
     */
    public static function trustedCallbacks() {
     return ['preRender'];
   }

   /**
    * Sets Songkick - #pre_render callback.
    */
   public static function preRender($build) {
     $count = $build['content']['#count'];
     $build['content']['#count_text'] = \Drupal::translation()->formatPlural($count, '(@count)', '(@count)');
     return $build;
   }

 }

```

And I've added the following to my .module file:

```
use Drupal\Songkick\SongkickBlockPoweredByViewBuilder;

/**
 * Implements TrustedCallbackInterface
 */
function _songkick_block_poweredby_prerender(array &$build, Drupal\Core\Block\BlockPluginInterface $block) {
  $build['#pre_render'][] = [SongkickBlockPoweredByViewBuilder::class, 'preRender'];
}

```

Then the site throws this fatal error:

> Fatal error: Cannot redeclare \_songkick\_block\_poweredby\_prerender() (previously declared in /var/www/html/web/modules/contrib/songkick/songkick.module:14) in /var/www/html/web/modules/contrib/songkick/songkick.module on line 51

The fatal error goes away if I remove the declaration in line 14, but the original error then persist. I'm at a loss about how to define the function in line 51 in a way that resolves the issue. Line 51 begins right after this comment in the above excerpt from the .module file:

> /\*** Get a Upcoming & past events API data. \*/

Any tips?

# Answer
You have the right idea, there are just a few details that need to be fixed.

The TrustedCallbackInterface was first added to Drupal 8.8; it didn't exist before Drupal 8.8. While it is optional in Drupal 8.8 and 8.9, it is *mandatory* in Drupal 9. So your module *isn't* compatible with Drupal 9 until you make this change.

First, copy the entire body of your original version of `_songkick_block_poweredby_prerender()` into your `public static function preRender($build)`. That is all that should be in the body of the `preRender()` method.

Second, delete the function `_songkick_block_poweredby_prerender()` (both copies) from songkick.module. You no longer need it because you have put that code in `Drupal\songkick\SongkickBlockPoweredByViewBuilder`.

Now put the `use Drupal\songkick\SongkickBlockPoweredByViewBuilder;` statement at the top of songkick.module with all the other use statements. Then change this statement:

```
$build['#pre_render'][] = '_songkick_block_poweredby_prerender';

```

to point to your new code instead. Like this:

```
$build['#pre_render'][] = [SongkickBlockPoweredByViewBuilder::class, 'preRender'];

```

Also note that the correct namespace has a lowercase 's' in 'songkick'. This has to be the same as the module's machine name, and machine names don't allow capital letters. So you need to make sure the `namespace` declaration in `SongkickBlockPoweredByViewBuilder` uses the lowercase, and that your `use` statement in songkick.module uses the lowercase.

Drupal is picky about naming, so also be sure that if your .module file is in `songkick/songkick.module`, the class `SongkickBlockPoweredByViewBuilder` is in `songkick/src/SongkickBlockPoweredByViewBuilder.php`
> 4 votes

---
Tags: migrations
---


# Question
Title: Search and pagination in media popup don't work properly
In the /admin/content/media page, I have more than one button for the pagination.

>

The search is working properly.

>

When I edit a media on some node, in the popup, I only have one button in the pagination.

>

The search isn't always working. Here, I'm making the search from the page 2, where the image isn't available directly.

>

It only works when the searched image is on the current page (selected by the pagination).

Here, I'm making the search from the page 1, where the image is available directly.

>

Is this the default behavior for the popup? My client doesn't like it; he'd like to have the "working" behavior.

Do I have some configuration to do?

I'm using the latest version of Drupal 9 (9.2.7) and the latest version of Gin for the admin theme.

I looked in another project of mine, with the same behavior, but it seems that the search only works on page 1 of the modal.

# Answer
> 0 votes
For the pagination, I had to change the pagination from *mini* to *complete* here to have more than one pagination.

> /admin/structure/views/view/media\_library/edit/

---
Tags: media, search, 9, paging
---


# Question
Title: Alternative ways to programmatically add user fields?
Currently i use this to programmatically add user fields:

```
function openid_connect_entity_base_field_info(EntityTypeInterface $entity_type) {
    if ($entity_type->id() === 'user') {
        $fields['field_family_name'] = BaseFieldDefinition::create('string')
          ->setLabel(t('Family Name'))
          ->setDescription(t('Add a description'))
          ->setRevisionable(TRUE)
          ->setTranslatable(TRUE)
          ->setDisplayOptions('form', array(
            'type' => 'string_text_field',
            'weight' => 30,
            'default_value' => 0,
          ))
          ->setDisplayConfigurable('form', TRUE);
      }
return $fields;
}

```

but it results in the admin of the site unable to uninstall my module as shown:

Are there any alternative ways to programmatically add user fields without causing the admin of the website to be unable to uninstall the module that programmatically added the user fields?

# Answer
> 8 votes
I found a solution using .yml files in your modules config/install directory.

**1. Create the user field**

go to Configuration -\> People -\> Account Settings -\> Manage fields and press "+ Add field". I'd recommend giving the field a unique machine-readable name to prevent conflicting user fields.

Enable the user field in Manage Form Display and Manage Display if you want it to appear in the users edit profile and registration page.

**2.Exporting the user field configuration**

go to Configuration -\> Development -\> Configuration Synchronization -\> Export -\> Single Item

Once you get to a screen similar to the one below, set configuration type to "Field" then set the configuration name to the field you have created.

In your modules Config/install folder(create one if needed) create a new file named after filename highlighted in red below.

Finally Copy the yml text into the file you just created.

then set configuration type to "Field Storage" then set the configuration name to the user field you have created.

In your modules Config/install folder(create one if needed) create a new file named after filename highlighted in red below (don't copy the one in the example your user field will have a different name).

Finally Copy the yml text into the file you just created.

**YOU NEED BOTH YML FILES TO PROGRAMMATICALLY CREATE A USER FIELD**

*I recommend doing this for each user field you want to programmatically add rather than copying the configuration and changing a few properties.*

With this method you can uninstall the module that created these user fields.

# Answer
> 0 votes
Updated answer:

You can include the field as default configuration upon installing the module. By adding the field configuration to exportable files (yaml-files) these can then be installed and added. When uninstalling the module the field and data will remain.

In your module create the folders `config/install` and place the configuration files there: For example, if I add a field `field_test_email` I would place the field storage and then the instance on the User entity.

`field.storage.user.field_test_email.yml` `field.field.user.user.field_test_email.yml`

https://www.drupal.org/docs/8/creating-custom-modules/include-default-configuration-in-your-drupal-8-module

Old answer:

If you want to keep the fields and its data the short answer is *No, you cannot and shouldn't*. Field definitions, configuration are coupled to its creator "the module", and when uninstalling everything it did goes away with it.

Drupal used to support disabling a module, but that was removed. See explanation here: https://www.drupal.org/node/2225029

> A huge debate and amount of thought went into this, with strong talk on both sides. Reasons for this include : * Because upgrades of some contrib module don't actually work (and can't \> be made to work) if upgrading when they are disabled. * Because data left behind by a disabled module that is later re-enabled \> causes integrity issues and cruft. * Some upgrades left behind data loss due to things like unexpected \> dependencies, plugins or hooks being unavailable at key times - when things were disabled. .. that issue is several hundred arguments long, so It's unfair to over-summarize.

During an uninstall there are different validators called to ensure the system does not break or keep data that cannot be handled later. For your case it is the `FieldModuleUninstallValidator` validator that gives you those error messages.

So to uninstall the module all data has to be deleted; You can try using the Field API bulk deletion for that: https://api.drupal.org/api/drupal/core!modules!field!field.purge.inc/group/field\_purge/8.2.x

# Answer
> 0 votes
You can use this module to programmatically create fields and attach them to the User entity:

https://drupal.org/project/field\_create

As you can read in the documentation, this module is meant for development purpose only. Enable it, create your fields and then uninstall it. This way, there is no "custom module" to install in order to have your custom fields.

Your website admin does not have to worry about uninstalling anything :)

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


# Question
Title: How can I add items to the Admin Toolbar?
In Drupal 8, I want to add a menu item to the Admin Toolbar with a submenu, with different links.

How can I do it?

# Answer
You can add items to the admin toolbar in two ways:

**As content:**

In ui `/admin/structure/menu/manage/admin`

or in code:

```
$item = \Drupal\menu_link_content\Entity\MenuLinkContent::create([
  'link' => ['uri' => 'internal:/<front>'],
  'title' => 'Front Page',
  'menu_name' => 'admin',
]);
$item->save();

```

**Or in static configuration files:**

```
system.admin:
  title: Administration
  route_name: system.admin
  weight: 9
  menu_name: admin
system.admin_content:
  title: Content
  description: 'Find and manage content.'
  route_name: system.admin_content
  parent: system.admin
  weight: -10
system.admin_structure:
  route_name: system.admin_structure
  parent: system.admin
  description: 'Administer blocks, content types, menus, etc.'
  title: Structure
  weight: -8
system.themes_page:
  route_name: system.themes_page
  title: Appearance
  description: 'Select and configure themes.'
  parent: system.admin
  weight: -6

```

This is the start of **system.links.menu.yml**, which defines the admin menu as we know it from D8. You can add your own entries in **mymodule.links.menu.yml**.

Edit:

To add an item to the top row, use the hook `mymodule_toolbar()`. This is an example from the tour module:

```
/**
 * Implements hook_toolbar().
 */
function tour_toolbar() {
  $items = [];
  $items['tour'] = [
    '#cache' => [
      'contexts' => [
        'user.permissions',
      ],
    ],
  ];

  if (!\Drupal::currentUser()->hasPermission('access tour')) {
    return $items;
  }

  $items['tour'] += array(
    '#type' => 'toolbar_item',
    'tab' => array(
      '#type' => 'html_tag',
      '#tag' => 'button',
      '#value' => t('Tour'),
      '#attributes' => array(
        'class' => array('toolbar-icon', 'toolbar-icon-help'),
        'aria-pressed' => 'false',
      ),
    ),
    '#wrapper_attributes' => array(
      'class' => array('tour-toolbar-tab', 'hidden'),
      'id' => 'toolbar-tab-tour',
    ),
    '#attached' => array(
      'library' => array(
        'tour/tour',
      ),
    ),
  );
 return $items;
}

```
> 26 votes

# Answer
For all who wonder where they may put code from previous answer – You can use it in MYMODULE.install for example

```
function MYMODULE_install(){
    $item = \Drupal\menu_link_content\Entity\MenuLinkContent::create([
      'link' => ['uri' => 'internal:/admin/link'],
      'title' => 'Link title',
      'menu_name' => 'admin',
    ]);
    $item->save();
}

```
> 4 votes

# Answer
In Drupal 9 a top menu item and submenu items can be added in the my\_module.links.menu.yml

See here the example from `group.links.menu.yml`

```
system.admin_group:
  title: 'Groups'
  description: 'Find and manage groups, group types and group settings.'
  route_name: 'entity.group.collection'
  parent: 'system.admin'
  weight: 3

```

And then to add submenu items, use the menu link you defined above as parent

```
another.menu_link:
  title: 'Example submenu'
  description: 'Example description'
  route_name: my_route.name
  parent: 'system.admin_group'
  weight: 0

```
> 3 votes

---
Tags: 8, navigation
---


# Question
Title: Random product variations "not available"
Of ~800 Commerce product variations, ~30 are not available for purchase on their respective display pages. These offending variations are completely set up like their brothers & sisters, Title, pricing, sku, and status. I see nothing wrong with them, through the /admin/ gui. But when visiting the display pages, for these offending products, Add to Cart is displayed as Product not available.

I can't find any information online concerning a similar problem. I'm also novice enough, to not know the best way to go about solving this issue.

Drupal and Commerce are the latest versions. If there's any other information I can offer, please let me know.

# Answer
The actual issue here is that Commerce products cannot have a price of 'NULL' or empty. Commerce has requirements that typically prevents the price field from ever being null or empty, but certain modules or pricing calculations can override this default required behavior and basically leave the Price field "orphaned."

For my use case, it was with the Commerce Pricing Table module. The module removes the default requirement for Price and has a configuration option to hide it so that its pricing tables take precedence. The design flaw in that module is that it operates on Commerce Line Items but forgets to set a price for the Price field, even though that field is never used.

For us, we created a simple Rule.

-\> Event: When saving a new product -\> Condition: if Empty Value = Price field -\> Action: set price to 0

In Commerce 1.x since a variation is simply an independent product with specific attributes, this makes sure that all items have at least a price of 0 and will function as expected.
> 1 votes

# Answer
In my case it depended on which variation I physically have first in the variation list. If the product I have first in the variation list has a price and positive stock number, then I get an Add To Cart button for all variations.

If the product I have first in the variation list does NOT have a price greater than $0 and positive stock number then for ALL variations I get "Product Not Available".

So for me physically dragging and changing the order of the variations is what changed whether I saw Add to Cart, or Product not Available - I had to have an eligible product listed first in the variation order.

The only catch is, it allows you to click the Add To Cart button on products that are not eligible for checkout, however it does not add anything to the cart or functionally mess things up.

Naturally I would prefer the Add To Cart button change dynamically depending on the status and info of that variation, but technically this works.
> 0 votes

---
Tags: commerce
---


# Question
Title: How to use patch request with parameters in custom rest resource?
I am creating a custom rest resource.

```
/**
 * Provides a resource to update nodes.
 *
 * @RestResource(
 *   id = "my_custom_resource",
 *   label = @Translation("Custom rest resource"),
 *   uri_paths = {
 *     "canonical" = "/custom-api/{node}",
 *   }
 * )
 */
class MyCustomResource extends ResourceBase {

  public function patch(EntityInterface $entity, $data = []): ResourceResponse {
    return new ResourceResponse('Some message', 200);
  }

}

```

But when I try to send a patch request from my postman using the URL `http://mysite/custom-api/2169`, I am getting an error

```
RuntimeException: Callable "Drupal\my_module\Plugin\rest\resource\MyCustomResource::patch" requires a value for the "$entity" argument. in Drupal\Component\Utility\ArgumentsResolver->handleUnresolvedArgument() (regel 143 van /var/www/web/core/lib/Drupal/Component/Utility/ArgumentsResolver.php).

```

What can be the problem? How can I get the argument?

# Answer
> 1 votes
Your canonical url should be `"/custom-api/{entity}"`

---
Tags: 9
---


title: Configuring the temporary directory

text:
# Question
Title: Configuring the temporary directory
I have recently moved a site from a localhost to a VPS. I have managed to make the public and private files writable; however, I am not sure where to find the temporary folder and how to change the permissions. I keep getting this message:

> The specified file temporary://file3Hl91E could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.

I am using Virtualmin, Drupal 7, and a Debian server. My current temporary directory is `/tmp`.

# Answer
> 47 votes
Check Administrator -\> Configuration -\> Media -\> File System to personalize your tmp path. Make sure to use relative paths and have the right privileges for the Apache user.

I personally like this article fix file upload. He has good observations. It worked for me.

Recently, I downloaded my site to my Mac computer. It happens that in my Mac I was using `mod_userdir` for Apache and I forgot that in `/etc/apache2/users/nameofuser.conf` I need to set `AllowOverride All`, otherwise I will have the following message:

> The specified file temporary could not be copied because the destination directory is not properly configured.

# Answer
> 23 votes
In your settings.php for older versions of Drupal add:

```
$conf['file_temporary_path'] = '/tmp';

```

Or for newer versions of Drupal add:

```
$settings['file_temp_path'] = '/tmp';

```

This will work on unix systems 99% of the time.

Usually the /tmp directory exists on UNIX systems with open permissions, and it exists specifically for temporary files and is often set up to improve performance.

You can check permissions by running `ls -al /tmp` on the command line.

If you're interested in further reading on this, see https://en.wikipedia.org/wiki/Temporary\_folder

# Answer
> 18 votes
It's important to understand that a permissions problem can exist in BOTH your specified temporary directory (which is defined at admin/config/media/file-system) AND at the folder where that temporary file is going to be copied. I've seen this error a few times and it's usually not an issue with the temporary folder, but the final folder where that file is copied *after* living in the temp folder.

Also ensure that the public file system path is set correctly.

# Answer
> 7 votes
I had this exact problem and made sure to use relative path (sites/default/files/tmp) for my tmp folder location as suggested and i also changed the permissions on the tmp folder to ensure it was writable by apache but my problem still existed. so i decided to check the log messages(Reports\>\>Recent log messages) to see if i could get a better understanding of what the problem was. By doing this i got a more specific message:

> The file permissions could not be set on public://js.

This prompted me to check the permissions on the js folder in sites/default/files and as it turns out apache could not write to it so by changing the permissions to 775 on that folder i got rid of my error message. So i would suggest that you check the permissions for all the sub-folders in sites/default/files and not only the tmp folder if you have not solved your problem as yet. Just thought i would share this info.

# Answer
> 5 votes
you can find file system settings in `admin/config/media/file-system` change it to /tmp

also you can check admin/reports/status for any settings problem

about /tmp permission you can give it 755 and you will find it in /public\_html

# Answer
> 2 votes
The error message can somteimes be misleading

If it says the problem is to do with the destination directory, the apache probably doesn't have the permissions to write to the sites/default/files subfolder that Drupal wants tot put the file in.

A good solution is to make the apache user the owner of all files and directories under sites/default/files

```
cd /path/to/sites/default
sudo chown -R _www:_www files

```

Or something similar should reslove destination directory issues. Double check that the owner has write and execute permissions on all subdirectories.

# Answer
> 2 votes
**The files directory: *Troubleshooting Apache-based Web Servers***

If the directory files is not "owned" by the Web server there are two ways to proceed. These instructions assume you have shell access to the Web server. If you do not have shell access, please contact your hosting provider for additional support.

Ideally you will be able to change the "owner" of the directory files to match the name of the Web server. On a Unix or Linux-based server you may verify "who" the Web server is running as by issuing the following commands:

```
$ ps aux  |grep apache # for Apache 2.x
$ ps aux  |grep httpd # for Apache 1.x

```

Depending on your Web server one of these commands will return a series of lines like this:

```
www-data 13612  0.1  0.9  50640 20340 ? S 12:29   0:08 /usr/sbin/apache2 -k start

```

The first column in the returned text is the "user" that your Web server is operating as. In this case the user is www-data. To make your files directory writeable by the Web server you need to reassign its ownership using the following command:

```
$ chown -R www-data sites/default/files
$ chmod -R 0700 sites/default/files

```

If you do not have sufficient permissions on your server to change the ownership of the folder, the next best option is to provide group-write access to the folder with the following command:

```
$ chmod -R 0770 sites/default/files

```

You should also be able to adjust the directory's permissions using an FTP program as outlined above.

Once you've completed these steps confirm the appropriate permissions have been assigned by navigating to Administer -\> Reports -\> Status report. Scroll to the section labelled, "File system" and confirm your settings are now correct.

Source: The files directory

# Answer
> 2 votes
In some situations this can be easily fixed by deleting the 'ctools' and 'js' folders within default/files. These folders are recreated by the system if needed. Sometimes when making a new install of an existing site these folders existing already cause problems. Also if your CSS isn't working after making a new install of an existing site this can also be fixed by deleting these files and letting drupal recreate them.

# Answer
> 1 votes
Another source of error is that it cannot write to the files folder. In my case I solved it using:

```
$chmod 777 sites/default/files/pictures/

```

# Answer
> 1 votes
My old and **problematic configuration**

```
chmod 664 -R /var/drupal-bc/sites/default/files
chmod 664 -R /var/drupal-bc/sites/default/private

drw-rw-r-- 2 www-data www-data  4096 Jul 31 12:35 files
drw-rw-r-- 3 www-data www-data  4096 Jul  5 15:08 private

```

My new and **work fine** configuration

```
chmod 774 -R /var/drupal-bc/sites/default/files
chmod 774 -R /var/drupal-bc/sites/default/private

drwxrwxr-- 2 www-data www-data  4096 Jul 31 12:35 files
drwxrwxr-- 3 www-data www-data  4096 Jul  5 15:08 private

```

# Answer
> 1 votes
Correct permissions for temporary folder depends on your web server configuration.

If running Drupal with PHP as module of web server, for example Apache, when user which is defined in main web server configuration file using User directive should have write acccess to it.

% grep -i "user" /etc/httpd/conf/httpd.conf

User apache

# Answer
> 1 votes
I had this same problem after moving from one server to another.

I tried everything suggested here, setting folders to 755 and so on.

My temporary folder was set to ""tmp7zXhVVCO" and it actually copied the installation files nicely, after every retry i saw the temp file being copied there, but installation kept failing.

The problem however is the owner not the rights, wich is why 777 removes this error, but we all know that this is not a way to go on production sites.

> What you should do, is change your temporary folder to anything else, such as "temp" or whatever suits you, as long as it **does not exist yet**, drupal will create this new folder with **apache** rights, *not* **user** rights, and your problem will be solved.

# Answer
> 1 votes
I don't really like any of the existing answers so I'm just going to start one myself that I'll probably update over time. Mainly with shell commands.

For now, run this from `sites/example.com`:

```
MYSITE=example.com
FILES=sites/$MYSITE/files
# CSS and JS might also cause trouble and advagg has its own dirs
TMPDIRS=$FILES/tmp $FILES/js $FILES/css $FILES/advagg_*
drush vset file_temporary_path $FILES/tmp # seems better than using /tmp
drush vset file_directory_temp $FILES/tmp
cd $(drush drupal-directory)
chown www-data -R $TMPDIRS
chmod 755 -R $TMPDIRS

```

# Answer
> 1 votes
From Configuration -\> Media -\> File System I removed the / temp-catalogue. After that I didn't have any problems.

# Answer
> 1 votes
I had the same issue on a migration . I have chmod 777 all the sites/default/files but the error still happens. I change permission 775 on sites/default/files and message disappeared . I was not a private path problem , mine is /var/tmp but the 775 permission .

# Answer
> 1 votes
If you run across this problem using Pantheon and continue to get the error after setting the (temp) files directory path(s), you may also need to switch the Connection mode on your dev instance dashboard from Git to SFTP.

Your Drupal site may be attempting to save files to a directory managed by Git (e.g. if you are changing layout settings and the like in an Adaptive Themes theme). In order to do so, switch to SFTP. Once the files have been saved, you can switch back to Git, and the dashboard will prompt you to commit the changes that have been made on the server.

# Answer
> 1 votes
I had the same problem.

I was using IIS in Windows. Finally the problem was for the permissions in folder sites/default/files and, obviously, in sites/default/files/tmp.

Finally I gave again "Full permissions" to the folders, and it worked.

Regards

# Answer
> 1 votes
I am using Drupal 9, in my case the folder where the translations are saved was missing. When I went to "Home -\> Administration -\> Configuration -\> Multimedia", the path of the translations was in "sites / default / files / translations" and I was missing the "translations" folder.

# Answer
> 0 votes
If you getting something like:

```
 Drupal\Core\File\Exception\DirectoryNotReadyException: The specified file 'temporary://somefile' could not be copied because the destination directory () is not properly configured. This may be caused by a problem with file or directory permissions....

```

And you're on Linux (Redhat or Centos) and none of the above solutions work, then check on the "SELinux". Start by looking at logs (which vary). In mine, i found the issue at: /var/log/warn .... says SELinux is preventing the given process.... from write access on the directory....

Then you would have to search how to give the given process SELinux read or write access to the path under questions (usually /var/www/html/xxx).

---
Tags: 7, files
---


# Question
Title: Using root source property within migrate sub_process plugin
I'm performing migration from Drupal 9 into another Drupal 9 project. Let's say "content features" migration.

In a node migration I'm trying to create stubs for media items.

The media source has two id keys: `mid, langcode`. The `mid` key is getting from field's `target_id` property. But there is no `language` property on field's level and I'm trying to pass node's language as second id value for the media lookup.

The migrate\_lookup plugin tries to find media entity by mid and langcode properties: `MigrationLookup::transform()`:

```
if (isset($this->configuration['source_ids'][$lookup_migration_id])) {
  $lookup_value = array_values($row->getMultiple($this->configuration['source_ids'][$lookup_migration_id]));
}

```

then `getMultiple()` tries to get values from the current iteration.

Does someone know how to pass root row instead of iteration row?

```
...
process:
  langcode: langcode
  ...

  field_cover_image:
    - plugin: sub_process
      source: field_cover_image
      process:
        lang:
          plugin: default_value
          default_value: 'en'
        target_id:
          plugin: migration_lookup
          source: target_id
          migration: migrate_media_image
          source_ids:
            migrate_media_image:
              - target_id
              - ROOT_ROW_SOURCE_PROPERTY_LANGCODE

```

I wonder also if it possible to use constants within `sub_process` and `$row->getMultiple()`?

An example:

```
...
      process:
        target_id:
          plugin: migration_lookup
          source: target_id
          migration: migrate_media_image
          source_ids:
            migrate_media_image:
              - target_id
              - constants/default_language

```

# Answer
I figured it out from `sub_process` plugin's documentation:

```
/**
 * Available configuration keys:
 *   ...
 *   - include_source: (optional) If TRUE, all source plugin configuration and
 *     values will be copied into the sub-processed row in a new property named
 *     for the source_key configuration value (see below). Defaults to FALSE.
 *   - source_key: (optional) If include_source is TRUE, this
 *     is the name of the property of the sub-processed row which will contain
 *     the source configuration and values. Ignored if include_source is
 *     FALSE. Defaults to 'source' if no value is provided.
 */

```

And used it as:

```
  field_cover_image:
    - plugin: sub_process
      source: field_cover_image
      include_source: true
      source_key: root
      process:
        target_id:
          plugin: migration_lookup
          source: target_id
          migration: migrate_media_image
          source_ids:
            migrate_media_image:
              - target_id
              - root/langcode # <- get property from the root row

```

And of cause constants also will be available:

```
migrate_media_image:
  - target_id
  - root/constants/default_language

```

An alternative could be creating iteration property as default value:

```
  plugin: sub_process
  source: field_cover_image
  process:
    lang:
      plugin: default_value
      default_value: 'en'

```

and refering to it as current iteration destination property `@lang`:

```
    lang:
      plugin: default_value
      default_value: 'en'
    target_id:
      plugin: migration_lookup
      source: target_id
      source_ids:
        migrate_media_image:
          - target_id
          - '@lang'

```

The content/media types set to be translatable but actually there is just one language and I can "hardcode" it, but it is better to use dynamic value.
> 0 votes

---
Tags: migrations, 9
---


# Question
Title: EntityQuery where multi-value field contains a value
I've been programming for 15 years, 10 with PHP, but on my 1st Drupal project. Using Drupal 9.

I'm trying to retrieve an entity (custom content type) that has 2 multi-value entity (user) fields. If the value I have is in one field I want to get the other one. The problem is I can't figure out how to ask for the entity when the scalar value I have is in the list. Here's what I've got:

```
return \Drupal::entityQuery('node')
  ->condition('type', 'osj_relationships')
  ->condition('field_supervised_reps', [$userId], 'IN')
  ->execute();

```

Which generates this SQL:

```
'SELECT "base_table"."vid" AS "vid", "base_table"."nid" AS "nid"
FROM
"node" "base_table"
INNER JOIN "node_field_data" "node_field_data" ON "node_field_data"."nid" = "base_table"."nid"
INNER JOIN "node__field_supervised_reps" "node__field_supervised_reps" ON "node__field_supervised_reps"."entity_id" = "base_table"."nid"
WHERE ("node_field_data"."type" = 'osj_relationships') AND ("node__field_supervised_reps"."field_supervised_reps_target_id" IN ('2458'))'

```

The 2nd part of the WHERE clause is looking for the field value in my parameter. I need it to look for my parameter in the field. I've also tried CONTAINS but that seems to assume the field value is a string rather than an array. If I could turn that WHERE clause around it would be perfect. ie.

```
(('2458') IN "node__field_supervised_reps"."field_supervised_reps_target_id")

```

I suppose I could use 'CONTAINS' if I could implode the field list but that would risk false hits.

Any suggestions?

# Answer
> 4 votes
You don't even have to use `IN` here, only if you have multiple `$userId`s, otherwise a simple `=` operator will work:

```
return \Drupal::entityQuery('node')
  ->condition('type', 'osj_relationships')
  ->condition('field_supervised_reps', $userId)
  ->execute();

```

The generated query will actually work how you'd like. It works because each value of a multi-value field is stored in its own row in the database.

For example, given a multi-value entity reference field, field\_tags, added to article nodes, if you have an article (with id = 111), referencing two taxonomy terms with ids 222 and 333, the `node__field_tags` table might look like:

| bundle | deleted | entity\_id | revision\_id | langcode | delta | field\_tags\_target\_id |
| --- | --- | --- | --- | --- | --- | --- |
| article | 0 | 111 | 777 | en | 0 | 222 |
| article | 0 | 111 | 777 | en | 1 | 333 |

---
Tags: entities
---