title: Invalidating Paragraph Cache

text:
# Question
Title: Invalidating Paragraph Cache
I'm working on a paragraph type that will need to display on a very limited number of pages but has some specific functionality where the preprocess function will need to run each time.

In my preprocess function, I've tried various iterations of the following:

```
$variables['elements']['#cache']['max-age'] = '0';
$variables['elements']['#cache']['contexts'][] = 'url.path';
$variables['elements']['#cache']['contexts'][] = 'url.query_args:r';
$variables['elements']['#cache'] = ['tags' => ['my_paragraph']];
Cache::invalidateTags(['my_paragraph']);
\Drupal::service('page_cache_kill_switch')->trigger();

```

However, the preprocess function runs once after a cache clear and then doesn't run again.

What am I doing incorrectly here? How can I get this to run each time?

# Answer
My understanding is that you're trying to set a cache max-age of 0 (don't cache) for a paragraph. I think your issue here is that the max-age doesn't bubble up to the page level and the page cache still caches your paragraph. This makes it so your paragraph is not processed again.

My understanding is that cache max-age data doesn't bubble up to the page level from subelements. There are a couple open issues on d.o for this.

To me, it looks as though this is something that may not be resolved in core for a while (or maybe ever?). There is a contributed module, Cache Control Override that will bubble up the correct cache data to the page level. From the module's description:

> In Drupal 8 core Page Cache max age settings are applied globally to all pages, and there is no way to set a different max age per page or leverage cache metadata max-age to override Cache-Control max-age value. This means that if you're hosting your website behind a reverse proxy that honors Cache-Control header, all pages are cached with equal TTL. You can either disable cache with response policies, or cache it for the same global value.
>
> This module is intended to solve that problem by leveraging cacheability metadata bubbled up to the page response level to override Cache-Control max-age parameter.

If you install the Cache Control Override module, then set the max-age in your preprocess function, e.g. `$variables['elements']['#cache']['max-age'] = '0';`, you should see your preprocess run every page load. However this will also ensure your pages with your paragraph never get cached at the page level. This could be a problem.

Depending on your site, it may be more prudent to use an alternative solution and render a placeholder in your paragraph and then use an ajax request to load the dynamic data into the placeholder. This will allow your full pages to stay cached while also allowing you to load dynamic data into your paragraph.
> 2 votes

# Answer
You've got a logic error in your PHP. You're doing the following and setting some variables:

```
$variables['elements']['#cache']['max-age'] = '0';
$variables['elements']['#cache']['contexts'][] = 'url.path';
$variables['elements']['#cache']['contexts'][] = 'url.query_args:r';

```

But then in the next line you're redeclaring `$variables['elements']['#cache']` as a new array of `['tags' => ['my_paragraph']];` So everything you were doing previously in the `$variables['elements']['#cache']` is now gone

So your max-age declaration doesn't exist now. Try with just these 2 items and that should be all you need. The first to tell drupal not to cache the paragraph. The 2nd to disable anonymous page caching as setting max-age 0 doesnt disable the page cache:

```
$variables['elements']['#cache']['max-age'] = '0';
\Drupal::service('page_cache_kill_switch')->trigger();

```
> 0 votes

# Answer
```
function themename_preprocess_paragraph(&$variables) {
  $paragraph = $variables['paragraph'];
  if ($paragraph->bundle() === 'your_para_machine_name') {
    $variables['#cache']['max-age'] = 0;
  }
}

```

after adding this code clear the cache.
> 0 votes

# Answer
This worked for me. The idea behind is to invalidate both node and paragraph entity caches.

```
$variables['elements']['#cache']['max-age'] = '0';
Cache::invalidateTags(['paragraph:' . $par->id()]);
Cache::invalidateTags(['node:' . $node->id()]);
\Drupal::service('page_cache_kill_switch')->trigger();

```

The context is hook\_preprocess\_paragraph\__TYPEID(&$variables)
> -1 votes

---
Tags: 8, caching
---


title: Before login hook

text:
# Question
Title: Before login hook
Is there a Drupal 8 hook for pre-login? I would like to redirect the login information of a user on a web server by URL.

I know there is `hook_user_login()`, but this one only looks called once the user is connected to the database. I would like to retrieve the step before, so the login and password information.

# Answer
> 2 votes
You can solve this by implementing `hook_form_alter`, something like this;

```
function MY_MODULE_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'user_login_form') {
    $form['#validate'][] = 'my_module_user_login_validate';
  }
}

function my_module_user_login_validate(&$form, $form_state) {
  //Do something...
}

```

# Answer
> 0 votes
you can alter for using `hook_form_alter`. Login page form id is `user_login_form` so use that and add your extra validation handler like below :

```
function MY_MODULE_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'user_login_form') {
    $form['#validate'][] = 'my_module_user_login_validate';
  }
}

function my_module_user_login_validate(&$form, $form_state) {
  //Do something...
}

```

---
Tags: 8, hooks, authentication-authorization
---


# Question
Title: What is the difference between normal filter and contextual filter in views?
I am using Drupal 7.34. I have used Views module many time but I don't know difference between normal filter and contextual filter. So can you tell me **What is the difference between normal filter and contextual filter in Views?**

# Answer
> 2 votes
In simplified language to understand.

**Normal Filter:** Normal filter takes the `fixed data` from the available data. For example, you have created a views with `Content: Title` which will show all the title of nodes available on the site. But if you provide the `Filter: Content type(Articles)`, then it will show only the Node title of `Articles`. Hence here filter, filters all data and gives only data which belong to Articles. So this is the Normal filter.

**Contextual Filter:** Now, Sometimes, you do not have the fixed filter value, suppose, `Logged-in-user`, `value available in URL`, `Author name` of currently loaded page. So, this kind of filter values are dynamic and keep changing, so Contextual filter provides the way to solve this. To visualize this you can see the following UI image of contextual filter. Which has mainly two section.

`1. WHEN THE FILTER VALUE IS NOT AVAILABLE`

`2. WHEN THE FILTER VALUE IS AVAILABLE OR DEFAULT IS PROVIDED.`

Now, in the first option `WHEN THE FILTER VALUE IS NOT AVAILABLE` itself defines `what is Contextual filter is`\- **So, Contextual filter SAYS to you, "*I can fetch value from following listed areas*(as you can see in image)*, you select from where shall I fetch. And I will take it as Filter value."***

**Example to understand Contextual filter:** Now your site has the Taxonomy terms- `BMW`, `AUDI`, `HONDA`. So, in fixed value filter you can take only one value. But, what you will do when that value is keep on changing based on browsing.

So, suppose, I select contextual filter and select `Taxonomy term ID from URL` So, if URL will have BMW is will take BMW as filter, If URL will have AUDI it will take AUDI as filter value. So, filter value keep on changing here, hence Contextual filter provides the way for this.

# Answer
> 0 votes
I'm just quoting d.o. and accentuate:

> Contextual filters work similarly to regular filters, but there is one important difference. Instead of setting a filter value manually, the value is fetched from variables sent programmatically to the view. A regular filter could give you all nodes written by a specified user. A contextual filter for a node author would be able to display all nodes written by the currently viewed user, or the same user who wrote the currently viewed node. The concept is that contextual filters prepare a view for filtering, **but the filter value is not yet determined**. When the view is eventually called, it is also provided with data used to complete the contextual filters.

Recommended further reading: Contextual Filters on d.o.

# Answer
> 0 votes
In short, both filter the data shown from the view, but a contextual filter filters the data basing on the values passed in the view's URL.
It is also true that it is possible to tell the view what to do when a value is not present in the URL (so that the view can handle two different URLs like *blogs* and *blogs/%user*), but this is essentially the difference between the two kind of view filters.

Also, normal filters can be exposed to the user, so that they can change the data shown in a view by changing the value of the filter. This cannot be done for contextual filters.

# Answer
> 0 votes
That seems inaccurate as exposed filters too allow URL params. Contextual seemingly includes an existing context e.g. (currently logged in user, current time); however, it also allows variable defaults.

---
Tags: 7, views
---


# Question
Title: Can module feature be implemented through theme
In our specific website project use case - we want to implement "module" features implemented through theme.

**Use case :** In our website project, we want to create custom content type programmatically(through module), but in our use case - can we create the same through theme.

There could be many use cases for the above requirement, but we want to make our site more manageable and cleaner for the system admin.

If the above can be done through theme - how to implement the above. Is there any limitation doing this way.

If someone could shed light on this.

# Answer
To put it simply:

* Themes provide the look and feel of the site (how the pages are styled).
* Modules provide functionality to the site.
* A content type is a way of storing data in the database.

A theme doesn't contain, for example, code to allow users to log in, or to change how users log in, which is code that instead into a module. Similarly, the logical place for a content type is a module, not a theme.

In your case, I would add one custom theme and one custom module; this will not make the site significantly more complicated for the admin. In fact, if the module merely provides the content type, then the admin will have no configuration to perform other than enabling the module.
> 1 votes

---
Tags: 9
---


title: default email for guest checkout

text:
# Question
Title: default email for guest checkout
I am using the Commerce Kickstart 2.x demo. When the guest checkout option is selected, the default guest email demo+1614916499@commercekickstart.com.

Is there a way to change what's displayed as default contact email for guest?

# Answer
> 0 votes
answering my own question. was able to figure this one. the guest email is prepopulated in orderEventsSubscriber.php.

---
Tags: commerce
---


title: Disable links to username and date

text:
# Question
Title: Disable links to username and date
One of my tasks requires me to disable the links to username and date fields generated from `diff_diffs_show()` whose output is rendered as in the following screenshot.

>

The code outputting those links is the following one.

```
// Generate table header (date, username, log message).
$old_header = t('!date by !username', array(
  '!date' => l(format_date($old_node->revision_timestamp), "node/$node->nid/revisions/$old_node->vid/view", array('absolute' => 1)),
  '!username' => theme('username', array('account' => $node_revisions[$old_vid])),
));
$new_header = t('!date by !username', array(
  '!date' => l(format_date($new_node->revision_timestamp), "node/$node->nid/revisions/$new_node->vid/view", array('absolute' => 1)),
  '!username' => theme('username', array('account' => $node_revisions[$new_vid])),
));

```

How I can change the output of the function so that it doesn't output links?

Basically, I want the username and date fields in plain texts instead of links.

# Answer
> 0 votes
`diff_diffs_show()` is the page callback for the *node/%node/revisions/view* route. The only way to change the output for that route is changing the page callback with `hook_menu_alter()`.

```
function mymodule_menu_alter(&$items) {
  $items['node/%node/revisions/view']['page callback'] = 'mymodule_diffs_show';
}

function mymodule_diffs_show($node, $old_vid, $new_vid, $state = NULL) {
  // Attaches the CSS.
  $build['#attached'] = diff_build_attachments();

  $default_state = variable_get('diff_default_state_node', 'raw');
  if (empty($state)) {
    $state = $default_state;
  }
  $state = str_replace('-', '_', $state);
  if (!array_key_exists($state, diff_available_states())) {
    $state = $default_state;
  }

  // Same title as the 'Revisions' tab. Blocked by non-page requests.
  if (node_is_page($node)) {
    drupal_set_title(t('Revisions for %title', array('%title' => $node->title)), PASS_THROUGH);
  }
  $node_revisions = node_revision_list($node);

  $old_node = node_load($node->nid, $old_vid);
  $new_node = node_load($node->nid, $new_vid);

  // Generate table header (date, username, log message).
  $old_header = t('!date by !username', array(
    '!date' => format_date($old_node->revision_timestamp),
    '!username' => format_username($node_revisions[$old_vid]),
  ));
  $new_header = t('!date by !username', array(
    '!date' => (format_date($new_node->revision_timestamp),
    '!username' => format_username($node_revisions[$new_vid]),
  ));

  $old_log = $old_node->log != '' ? '<p class="revision-log">' . filter_xss($old_node->log) . '</p>' : '';
  $new_log = $new_node->log != '' ? '<p class="revision-log">' . filter_xss($new_node->log) . '</p>' : '';

  // Generate previous diff/next diff links.
  $nav_suffix = ($default_state != $state) ? '/' . str_replace('_', '-', $state) : '';
  $next_vid = _diff_get_next_vid($node_revisions, $new_vid);
  if ($next_vid) {
    $next_link = l(t('Next difference >'), 'node/' . $node->nid . '/revisions/view/' . $new_vid . '/' . $next_vid . $nav_suffix, array('absolute' => 1));
  }
  else {
    $next_link = '';
  }
  $prev_vid = _diff_get_previous_vid($node_revisions, $old_vid);
  if ($prev_vid) {
    $prev_link = l(t('< Previous difference'), 'node/' . $node->nid . '/revisions/view/' . $prev_vid . '/' . $old_vid . $nav_suffix, array('absolute' => 1));
  }
  else {
    $prev_link = '';
  }

  $header = _diff_default_header($old_header, $new_header);
  $rows = array();
  if ($old_log || $new_log) {
    $rows['logs'] = array(
      array(
        'data' => $old_log,
        'colspan' => 2,
      ),
      array(
        'data' => $new_log,
        'colspan' => 2,
      ),
    );
  }
  $rows['navigation'] = array(
    array(
      'data' => $prev_link,
      'class' => array('diff-prevlink'),
      'colspan' => 2,
    ),
    array(
      'data' => $next_link,
      'class' => array('diff-nextlink'),
      'colspan' => 2,
    ),
  );

  $links = array();
  foreach (diff_available_states('node') as $alternative_state => $label) {
    $links[$alternative_state] = array(
      'title' => $label,
      'href' => "node/{$node->nid}/revisions/view/{$old_vid}/{$new_vid}" . ($alternative_state == $default_state ? '' : '/' . str_replace('_', '-', $alternative_state)),
    );
  }
  if (count($links) > 1) {
    $state_links = theme('links', array(
      'links' => $links,
      'attributes' => array('class' => array('links', 'inline')),
    ));
    $rows['states'] = array(
      array(
        'data' => $state_links,
        'class' => 'diff-links',
        'colspan' => 4,
      ),
    );
  }
  $rows = array_merge($rows, _diff_body_rows($old_node, $new_node, $state));

  $build['diff_table'] = array(
    '#theme' => 'table__diff__standard',
    '#header' => $header,
    '#rows' => $rows,
    '#attributes' => array('class' => array('diff')),
    '#colgroups' => _diff_default_cols(),
    '#sticky' => FALSE,
  );

  // Allow users to hide or set the display mode of the preview.
  if (node_is_page($node) && $view_mode = variable_get('diff_view_mode_preview_node_' . $new_node->type, 'full')) {
    $header = '';
    if ($node->vid == $new_vid) {
      $header .= '<div class="diff-section-title">' . t('Current revision:') . '</div>';
    }
    else {
      $header .= '<div class="diff-section-title">' . t('Revision of @new_date:', array('@new_date' => format_date($new_node->revision_timestamp))) . '</div>';
    }
    $build['diff_preview']['header']['#markup'] = $header;
    // Don't include node links or comments when viewing the diff.
    $build['diff_preview']['content'] = function_exists('entity_view') ? entity_view('node', array($new_node), $view_mode) : node_view($new_node, $view_mode);
    if (isset($build['diff_preview']['content']['links'])) {
      unset($build['diff_preview']['content']['links']);
    }
    if (isset($build['diff_preview']['content']['comments'])) {
      unset($build['diff_preview']['content']['comments']);
    }
  }
  return $build;
}

```

The part getting the username is simplified: The code should check the username length, and truncate it if it's longer than 20 characters; the username should also be sanitized via `check_plain()`.
See `template_preprocess_username()` to understand how that can be implemented.

I would rather not implement the code shown in this answer, since:

* The *node/%node/revisions/view* route is accessible by the users who have the *administer nodes* permission, who should be allowed to see any link to revision pages
* The users without the *access user profiles* permission wouldn't see links to user accounts in any case, but the users with the *administer users* permission should be allowed to see link to user accounts in any page, as that simplifies their work

---
Tags: 7
---


# Question
Title: Exposed filter in view should display all available values in select box
I added an exposed filter to my view where users can enter the desired value to filter the results accordingly. But I want to make it easier for them by changing this filter to a select box style dropdown where they can select a value out of all available values.

To make this more clear; I'm talking about a year, so each article has a field "year" and because there are many articles published in many years, I want to group all available years from all articles and show them to the user in this select box.

But I can only make this possible by adding the years in the grouped filters manually, that means each year I have to add a new option to the filter manually. And if there are articles added later which originally were published earlier than years available in the options, I probably will never cover all years in this set of static options.

So is there a way to get all years of all articles and showing them in a select box?

# Answer
> 1 votes
A little bit more research would have helped, I found out myself how to do this. (Though I don't know if it would work without custom code.)

I hooked into `hook_form_FORM_ID_alter()` inside my theme (would also work in a custom module) and altered the form like this:

```
function MYTHEME_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {
  if ($form['#id'] == 'views-exposed-form-MYVIEWID-MYFORMID') {
    $nids = \Drupal::entityQuery('node')->condition('type', 'article')->execute();
    $nodes = \Drupal\node\Entity\Node::loadMultiple($nids);
    $options = ['' => 'All'];

    foreach($nodes as $nid => $node) {
      $value = $node->get('field_article_year')->getString();

      if (isset($value)) {
        $options[$value] = $value;
      }
    }

    asort($options, SORT_NUMERIC);

    if (isset($form['article_year'])) {
      $form['article_year']['#type'] = 'select';
      $form['article_year']['#options'] = $options;
      $form['article_year']['#size'] = 1;
    }
  }
}

```

---
Tags: views
---


# Question
Title: Why jquery menu collapse on all pages except front page
I have a Drupal 8 site and them (upgraded from Drupal 7) and the main menu collapses to a button when the page is narrow enough (i.e. on a mobile device). Or at least it is supposed to. I did not design the theme.

**SITUATION**

Unfortunately when the menu is collapsed into a button, clicking on the button does NOT open the menu.

**SITE SETUP**

It seems that the old theme used jQuery to handle the collapse of the menu.

I have installed the jquery\_ui module.

I added jquery to the .libraries.yml file

```
  dependencies:
    - core/jquery
    - core/jquery.ui
    - core/jquery.once

```

There are 4 template files which the only reason I can see is so that the main menu (which is hardcoded) can style the active menu item for the page.

* page--node--2.html.twig
* page--node--3.html.twig
* page--node--6.html.twig
* page.html.twig

Each of those pages has as the last line of the page a reference to the JavaScript file located in the site as

`<script src="sites/all/themes/custom/mytheme/js/main.js"></script>`

**FIXED SOME OF IT**

Adding **jquery.main.js** to the /js directory and adding the reference to it in the .library.yml file as

```
  js:
    js/main.js: {}
    js/jquery.main.js: {}

```

was enough to get all of the pages to collapse and open the menu *EXCEPT THE FRONT PAGE.*

**JURY-RIG**

I can get the front page menu to work if I add a reference to the bottom of the page to the jquery.main.js file I manually added to the local /js directory.

`<script src="sites/all/themes/custom/mytheme/js/main.js"></script>`

But then the other pages (not node 2, 3 or 6) which should use *page.html.twig* are run, it does NOT un-collapse the menu.

So for now I make a *page--front.html.twig* file which includes BOTH script referecnes to the JavaScript files, and all other pages have just the one (to main.js).

**QUESTION** I have a couple:

1. What is the more standard way to situate this? I don't imagine that having a local *jquery.main.js* file is the best solution but it wasn't working with out it.
2. Why would the front page not operate like the other pages in accessing the JavaScript and jQuery?

Thank you for any insight.

# Answer
> 0 votes
Doing

> `<script src="sites/all/themes/custom/mytheme/js/main.js"></script>`

is bad Drupal practice. As per the docs you should be doing

**my\_theme.libraries.yml**

```
menu-collapse:
  version: 1.x
  js:
    js/main.js: {}
  dependencies:
    - core/jquery
    - core/jquery.ui
    - core/jquery.once

```

**page--node--2.html.twig
page--node--3.html.twig
page--node--6.html.twig
page.html.twig**

```
{{ attach_library('theme_name/menu-collapse') }}

```

inside the template file(s).

**Note:** If this functionality is meant to be for every single page, rather then having to always add this to every variation of page.html.twig, add this in html.html.twig instead.

---

If after doing the above, the issue still persists

> Why would the front page not operate like the other pages in accessing the JavaScript and jQuery?

Possibly due to jQuery being loaded twice.

Go to `/admin/config/development/performance` and uncheck **Aggregate JavaScript files** (remember to turn back on after your're finished debugging)

Then on your front page, right mouse click, and select inspect

Go to network, and select JS, then refresh the page with the inspector open. You'll be able to see all the JS files that are loaded.

---

If there are no jQuery duplicates, in the inspector go to the "Console tab" and see if there is a JS error.

---
Tags: 8, javascript
---


title: Country code in taxonomy shown as flag

text:
# Question
Title: Country code in taxonomy shown as flag
I am using ISO 3166-1 alpha-2 codes for countries as a taxonomy in several pages of a given type.

When listing those pages in a view, I would like to display the corresponding country flag, rather than the two-letter code, e.g.

`<img src="https://lipis.github.io/flag-icon-css/flags/4x3/it.svg" width="5px">`

for

`it`

Is that possible, perhaps using CSS+JavaScript?

Many thanks!

# Answer
> 1 votes
For example code for a Drupal-based approach, check out the Flags module.

Also take a look at the Language Icons module, although this particular module works on languages, not taxonomy.

If you just want a CSS + JS solution, you should be asking on Stack Overflow, not here.

---
Tags: theming, taxonomy-terms, javascript
---


title: Dependent dropdown into an Ajax AddMore

text:
# Question
Title: Dependent dropdown into an Ajax AddMore
I used a dependent dropdown into an Ajax AddMore, so I checked the code of Ajax Examples, class AjaxAddMore and more. I have several versions that all have a problem; on this one, the behavior of the AddMore overwrites the first form.

Does someone with experience have a solution, please?

```
namespace Drupal\export\Form;

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

class TestFilteringStep6Form extends FormBase {

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

  public function buildForm(array $form, FormStateInterface $form_state) {
    $num_of_filter = $form_state->get('counter');
    if ($num_of_filter === NULL) {
      $form_state->set('counter', 1);
      $num_of_filter = 1;
    }

    $form['#tree'] = TRUE;

    for ($i = 1; $i <= $num_of_filter; $i++) {
      $form['filter_fieldset'][$i] = [
        '#type' => 'fieldset',
        '#title' => $this->t('Filtre ' . $num_of_filter . ' :'),
        '#prefix' => '<div id="add-remove-wrapper">',
        '#suffix' => '</div>',
      ];

      $form['filter_fieldset'][$i]['field'] = [
        '#type' => 'select',
        '#options' => ['(Activités) Nom' => '(Activités) Nom', '(Résultats) Score' => '(Résultats) Score'],
        '#empty_option' => $this->t('- Sélection d\'un champs -'),
        '#ajax' => [
          'wrapper' => 'conditiontype-container-wrapper',
          'callback' => '::promptConditionTypeCallback',
        ],
      ];
      $selected_field[$i] = $form_state->getValue(array('filter_fieldset', $i, 'field'));

      // container :
      $form['filter_fieldset'][$i]['conditiontype_container'] = [
        '#type' => 'container',
        '#attributes' => ['id' => 'conditiontype-container-wrapper'],
      ];

      if (!empty($selected_field[$i])) {
        if ($selected_field[$i] == '(Activités) Nom') {
          $form['filter_fieldset'][$i]['conditiontype_container']['type'] = [
            '#type' => 'select',
            '#options' => ['Activité1' => 'Activité1', 'Activité2' => 'Activité2', 'Activité3' => 'Activité3'],
            '#empty_option' => $this->t('- Sélection d\'un type -'),
            '#default_value' => !empty($form_state->getValue(array('filter_fieldset', $i, 'conditiontype_container', 'type'))) ? $form_state->getValue(array('filter_fieldset', $i, 'conditiontype_container', 'type')) : '',
          ];
        }
        if ($selected_field[$i] == '(Résultats) Score') {
          $form['filter_fieldset'][$i]['conditiontype_container']['type'] = [
            '#type' => 'select',
            '#options' => ['Score1' => 'Score1', 'Score2' => 'Score2', 'Score3' => 'Score3'],
            '#empty_option' => $this->t('- Sélection d\'un type -'),
            '#default_value' => !empty($form_state->getValue(array('filter_fieldset', $i, 'conditiontype_container', 'type'))) ? $form_state->getValue(array('filter_fieldset', $i, 'conditiontype_container', 'type')) : '',
          ];
        }

        if ($form_state->get('counter') > 1) {
          $form['filter_fieldset'][$i]['conditiontype_container']['remove_filter'] = [
            '#type' => 'submit',
            '#value' => $this->t('Supprimer le filtre ' . $num_of_filter),
            '#submit' => ['::subtractOneToCounter'],
            '#ajax' => [
              'callback' => '::returnFilterFieldsetCallback',
              'wrapper' => 'add-remove-wrapper',
            ],
          ];
        }
      }
    }
    $form_state->setCached(FALSE);

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

    $form['actions']['add_filter'] = [
      '#type' => 'submit',
      '#value' => $this->t('Ajouter un filtre'),
      '#submit' => ['::addOneToCounter'],
      '#ajax' => [
        'callback' => '::returnFilterFieldsetCallback',
        'wrapper' => 'add-remove-wrapper',
      ],
    ];

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

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {}

  /**
   * Callback des select
   */
  public function promptConditionTypeCallback(array &$form, FormStateInterface $form_state) {
    $num_of_filter = $form_state->get('counter');
    $form_state->setRebuild();
    return $form['filter_fieldset'][$num_of_filter]['conditiontype_container'];
  }

  /**
   * Callback des boutons add_filter et remove_filter
   */
  public function returnFilterFieldsetCallback(array &$form, FormStateInterface $form_state) {
    return $form['filter_fieldset'];
  }

  public function addOneToCounter(array &$form, FormStateInterface $form_state) {
    $num_of_filter = $form_state->get('counter');
    $form_state->set('counter', $num_of_filter + 1);
    $form_state->setRebuild();
  }

  public function subtractOneToCounter(array &$form, FormStateInterface $form_state) {
    $num_of_filter = $form_state->get('counter');
    if ($num_of_filter > 1) {
      $form_state->set('counter', $num_of_filter - 1);
    }
    $form_state->setRebuild();
  }

  /**
   * Fonction pour remplir le menu déroulant du type.
   */
  public static function getTypeDropdownOptions($selected_field) {
    switch ($selected_field) {
      case '(Activités) Nom':
        $options = ['Activité1' => 'Activité1', 'Activité2' => 'Activité2', 'Activité3' => 'Activité3'];
        break;

      case '(Résultats) Score':
        $options = ['Résultat1' => 'Résultat1', 'Résultat2' => 'Résultat2', 'Résultat3' => 'Résultat3'];
        break;
    }
    return $options;
  }
}

```

# Answer
Finally, here is my solution

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

class TestFilteringStep8Form extends FormBase
{

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

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

    $num_of_filter = $form_state->get('counter');
    if ($num_of_filter === NULL) {
      $field = $form_state->set('counter', 1);
      $num_of_filter = 1;
    }

    $form['#tree'] = TRUE;

    $form['filter_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Filtres :'),
      '#prefix' => '<div id="add-remove-wrapper">',
      '#suffix' => '</div>',
    ];

    $form['filter_fieldset']['conditiontype_container'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'conditiontype-container-wrapper'],
    ];

    for ($i = 1; $i <= $num_of_filter; $i++) {

      $form['filter_fieldset']['conditiontype_container']['field'][$i] = [
        '#type' => 'select',
        '#options' => ['(Activités) Nom' => '(Activités) Nom', '(Résultats) Score' => '(Résultats) Score'],
        '#empty_option' => $this->t('- Sélection d\'un champs -'),
        '#ajax' => [
          'callback' => '::promptConditionTypeCallback',
          'wrapper' => 'conditiontype-container-wrapper',
        ],
      ];

      $selected_field = $form_state->getValue(['filter_fieldset', 'conditiontype_container', 'field', $i]);
      $type_options = static::getTypeDropdownOptions($selected_field);

      if (!empty($selected_field)) {
          $form['filter_fieldset']['conditiontype_container']['type'][$i] = [
            '#type' => 'select',
            '#options' => $type_options,
            '#empty_option' => $this->t('- Sélection d\'un type -'),
          ];
      }
    }

    $form['filter_fieldset']['actions'] = [
      '#type' => 'actions',
    ];
    $form['filter_fieldset']['actions']['add_name'] = [
      '#type' => 'submit',
      '#value' => $this->t('Ajouter un filtre'),
      '#submit' => ['::addOneToCounter'],
      '#ajax' => [
        'callback' => '::returnFilterFieldsetCallback',
        'wrapper' => 'add-remove-wrapper',
      ],
    ];
    // If there is more than one name, add the remove button.
    if ($num_of_filter > 1) {
      $form['filter_fieldset']['actions']['remove_name'] = [
        '#type' => 'submit',
        '#value' => $this->t('Supprimer le filtre ' . $num_of_filter),
        '#submit' => ['::subtractOneToCounter'],
        '#ajax' => [
          'callback' => '::returnFilterFieldsetCallback',
          'wrapper' => 'add-remove-wrapper',
        ],
      ];
    }
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state)
  {
  }

  /**
   * Callback des select conditions et type.
   */
  public function promptConditionTypeCallback(array $form, FormStateInterface $form_state)
  {
    return $form['filter_fieldset']['conditiontype_container'];
  }

  /**
   * Callback des boutons add et remove.
   */
  public function returnFilterFieldsetCallback(array &$form, FormStateInterface $form_state)
  {
    return $form['filter_fieldset'];
  }

  /**
   * Incrémente le compteur
   */
  public function addOneToCounter(array &$form, FormStateInterface $form_state)
  {
    $num_of_filter = $form_state->get('counter');
    $add_button = $num_of_filter + 1;
    $form_state->set('counter', $add_button);
    $form_state->setRebuild();
  }

  /**
   * Decrémente le compteur.
   */
  public function subtractOneToCounter(array &$form, FormStateInterface $form_state)
  {
    $num_of_filter = $form_state->get('counter');
    if ($num_of_filter > 1) {
      $remove_button = $num_of_filter - 1;
      $form_state->set('counter', $remove_button);
    }
    $form_state->setRebuild();
  }

  /**
   * Fonction pour remplir le menu déroulant du type.
   */
  public static function getTypeDropdownOptions($selected_field)
  {
    switch ($selected_field) {
      case '(Activités) Nom':
        $options = ['Activité1' => 'Activité1', 'Activité2' => 'Activité2', 'Activité3' => 'Activité3'];
        break;

      case '(Résultats) Score':
        $options = ['Résultat1' => 'Résultat1', 'Résultat2' => 'Résultat2', 'Résultat3' => 'Résultat3'];
        break;
    }
    return $options;
  }
}

```
> 0 votes

---
Tags: ajax
---


# Question
Title: Value in my custom base field added to user entity isn't saved
I've created a new custom basefield for `user` entity type like this:

```
function hd_is_integration_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'user') {
    $fields['is_uid'] = BaseFieldDefinition::create('text')
      ->setName('is_uid')
      ->setLabel(t('IS User ID'))
      ->setDescription(t('ID of this user in HD IS.'))
      ->setSettings([
        'max_length' => 50,
        'text_processing' => 0,
      ])
      ->setDefaultValue('')
      ->setDisplayOptions('view', [
        'label' => 'above',
        'type' => 'string',
        'weight' => 0,
      ])
      ->setDisplayOptions('form', [
        'type' => 'string_textfield',
        'weight' => 0,
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
  }
}

```

I've also updated the entity schema with update hook:

```
function hd_is_integration_update_8001(&$sandbox) {
  $field_storage_definition = BaseFieldDefinition::create('string')
    ->setName('is_uid')
    ->setLabel(t('IS User ID'))
    ->setDescription(t('ID of this user in HD IS.'))
    ->setSettings([
      'max_length' => 50,
      'text_processing' => 0,
    ])
    ->setDefaultValue('')
    ->setDisplayOptions('view', [
      'label' => 'above',
      'type' => 'string',
      'weight' => 0,
    ])
    ->setDisplayOptions('form', [
      'type' => 'string_textfield',
      'weight' => 0,
    ])
    ->setDisplayConfigurable('form', TRUE)
    ->setDisplayConfigurable('view', TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('is_uid', 'user', 'user', $field_storage_definition);
}

```

The field is displaying fine in the user edit form, but any value added in it isn't saved. What am I missing, please?

# Answer
In the end, I mofified my approach using https://www.drupal.org/project/one\_time\_password as an example. The difference is probably in the installation of the field definition - `hook_install()` works just fine.
> 1 votes

---
Tags: entities
---


# Question
Title: In which contrib file/function should a class_alias() statement be placed so that it is always processed, regardless of the url being served?
To main backwards-compatibility I need to define two class aliases in my contrib module. Both of the source and target classes are within the same namespace within my module's namespace.

I placed the `class_alias( )` statements at the top of my\_module.module in open code, not a function, and this works for everything in the module, and also mostly for everything everywhere. I have created a second module which uses the original classes to check this. The second module has the first as a dependency. This works most of the time, however, there are a few places where I get a 'class not found' error, meaning that the alias statements have not been processed. For example, when viewing a few admin urls e.g admin/config/regional/language

So is there a better place than my\_module.module where I can put the `class_alias( )` statements, such that they are always processed?

My fall-back solution would be to re-create the two original class files, in the original locations, and each of them have the class alias statement, so that autoloading finds them. But that's a bit untidy and they will cause confusion as they are named incorrectly. It would be nicer to be able to have the two alias statements somewhere, and not have two nearly empty files left around.

# Answer
> 1 votes
> So is there a better place than my\_module.module where I can put the class\_alias( ) statements, such that they are always processed?

Put `class_alias()` in the class file (after the use statements before class {} or at the end of the class file).

\*.module files are not loaded by the class loader, they are included later in the kernel bootstrap process.

---
Tags: 8
---


title: Installing a v8 module

text:
# Question
Title: Installing a v8 module
If a contrib module's info.yml contains `core: 8.x` and not `core_version_requirement: ^8.8 || ^9`, how can a site be upgraded to Drupal 9 using composer?

`composer update` downloads modules in `"require": {` which needs to be before `"patches": {` because there needs to be a module before it can be patched. Assume the patch patches the info.yml file with `core_version_requirement: ^8.8 || ^9`.

So `composer update` can't resolve to an installable set of packages and throws errors like this:

```
- Root composer.json requires drupal/entity_jump_menu 1.1 -> satisfiable by drupal/entity_jump_menu[1.1.0].
- drupal/entity_jump_menu 1.1.0 requires drupal/core ~8.0 -> found drupal/core[8.0.0-beta6, ..., 8.9.x-dev] but it conflicts with your root composer.json require (^9.1).

```

It looked like the answer was changing `drupal/core` and `drupal/core-dev` to a value of `"^8.8||^9.1"`. composer update will now run, except the site is still building in version 8.9.13.

---

Following the suggestions on the mediacurrent blog post, I changed composer.json to the following

```
  "repositories": [
      {
          "type": "composer",
          "url": "https://packages.drupal.org/8",
          "exclude": ["drupal/entity_jump_menu"]
      },
      {
          "type": "git",
          "url": "git@git.drupal.org:issue/entity_jump_menu-3130218.git"
      }
  ],
  "require": {
      ...
      "drupal/entity_jump_menu": "dev-3130218-drupal-9-deprecated",
      ...
  },

```

Which downloads the fork of the module, into `vendor/drupal/entity_jump_menu`. Unfortunately Drupal and/or Drush don't see the module in that directory.

I'm going to try the computerminds solution next.

---

The solution from computerminds adds the fork of the module to the modules/contrib directory. Here's the code.

```
"repositories": [
    {
        "type": "package",
        "package": {
            "name": "drupal/entity_jump_menu",
            "type": "drupal-module",
            "version": "dev-3130218-drupal-9-deprecated",
            "source": {
                "type": "git",
                "url": "git@git.drupal.org:issue/entity_jump_menu-3130218.git",
                "reference": "268adc649cfb4ad716751a8643e60f5df4dbb80d"
            }
        }
    },
    {
        "type": "composer",
        "url": "https://packages.drupal.org/8"
    }
],
"require": {
    ...
    "drupal/entity_jump_menu": "dev-3130218-drupal-9-deprecated",
    ...
},

```

Thanks for pointing me in the right direction.

# Answer
You'll need to fork the module. This is more of a pain than patching but it's much better now that you can make issue forks on drupal.org.

Here's a detailed tutorial.

The basic workflow is this:

1. Make an issue fork on drupal.org that updates the version requirement.
2. Add the forked repo to your `composer.json` and update your site that way.
3. When the module gets a real Drupal 9 release, switch your `composer.json` back to the release.
> 2 votes

---
Tags: composer, 9
---


# Question
Title: Attach view of content by author only to the user page
I am using the EVA: Entity Views Attachment module to create a view of content by author, to attach it to each author's user page. So, for example, when viewing /user/1, I will see a list of all the content created by user #1.

I've been able to do this successfully, but too successfully: Not only does this list show up on the author's user page, but it also shows up on every single piece of content that user has written.
Obviously, I don't want it to show up there.

How can I fix this, so that it only shows up on the user page?

These are my settings.

* Entiti content settings
    + Entity type: User
    + Bundles: User
    + Arguments: id
* Contextual filters
* Content: Author UID
    + When the filter value is not available
        - Provide a default value: *Type: User ID* from route context

I'm working with Drupal 9, if that makes any difference.

# Answer
I haven't used this module, but according to the project page:

> The placement of the view in the entity's content can be reordered on the "Field Display" administration page for that entity, like other fields added using the Field UI module.

So you should be able to configure this at **Manage Display** for users: `/admin/config/people/accounts/display`. You can customize the display separately for `Default` and `Compact`, and you can create more view modes (different display configurations) as necessary.

Another way to do what you're doing (attach a view to users only on the user page) would be to use Layout Builder, which is included standard with Drupal.

1. Make a view that shows the user's content with contextual filters in a block.
2. Enable Layout Builder module.
3. On `/admin/config/people/accounts/display`, check **Use Layout Builder**, open Layout Builder, and then add the block.
> 1 votes

# Answer
In addition to the other answers you could (for the single user page) provide a single twig template in your theme and then exclude the field from rendering (with the "without" twig filter function).

https://www.drupal.org/docs/theming-drupal/twig-in-drupal/filters-modifying-variables-in-twig-templates
> 0 votes

---
Tags: views, 9
---


# Question
Title: Message shown in popup whenever any error log is registered
I want the administrator users to see a popup whenever an error log is generated. I researched and already completed the first step following Additional actions when logging using watchdog.

BetterMonitoring is my custom module. This the code I am using.

### BetterMonitoring.service.yml

```
services:

  logger.BetterMonitoring:
    class: Drupal\BetterMonitoring\Logger\BetterMonitoring
    tags:
      - { name: logger_custom }

```

### BetterMonitoring.php

```
namespace Drupal\BetterMonitoring\Logger;

use Drupal\Core\Logger\RfcLoggerTrait;
use Psr\Log\LoggerInterface;

class BetterMonitoring implements LoggerInterface {
  use RfcLoggerTrait;

  /**
   * {@inheritdoc}
   */
  public function log($level, $message, array $context = array()) {
    // I want to check  whether the message is an error; if it is, show it in a popup.
  }

}

```

How do I check whether the message is an error message inside this log function and then show it in the popup?

# Answer
While the documentation for `LoggerInterface::log()` doesn't make clear what value the `$level` parameter gets, the code used from `RfcLoggerTrait::error()` makes that clearer.

```
public function error($message, array $context = []) {
  $this->log(RfcLogLevel::ERROR, $message, $context);
}

```

`RfcLogLevel::ERROR` is the value passed for error messages.

```
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Logger\RfcLoggerTrait;
use Psr\Log\LoggerInterface;

class BetterMonitoring implements LoggerInterface {
  use RfcLoggerTrait;

  /**
   * {@inheritdoc}
   */
  public function log($level, $message, array $context = array()) {
    if ($level == RfcLogLevel::ERROR) {
      $this->storeMessage($message, $context);
    }
  }

}

```

As for showing the message in a popup, since the logger cannot render markup in a page, I would do as the `Messenger` class does: Instantiate an object implementing `FlashBagInterface` and store the messages in that object. For a logger, which is a service, it's enough to add *@session.flash\_bag* between its arguments.

```
services:

  logger.BetterMonitoring:
    class: Drupal\BetterMonitoring\Logger\BetterMonitoring
    arguments:
      - '@session.flash_bag'
    tags:
      - { name: logger_custom }

```

In this case, the logger also needs a class constructor.

```
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;

public function __construct(FlashBagInterface $flash_bag) {
  $this->flashBag = $flash_bag;
}

```
> 0 votes

---
Tags: 8, log-messages
---


# Question
Title: Controlling a dependent field in a multi-instance paragraph
The fields below are part of the node/add node/edit forms of my custom node type.

The paragraph `field_para_city` contain one `field_city`. (I later need to add other fields in the paragraph).

The user can add multiple instances from `field_para_city`.

`field_city` has an allowed\_values\_function defined in a YML file, which returns all possible cities from all countries.

I created a `class MyNodeTypeForm extends NodeForm`, with a `public function buildForm()`. This function adds AJAX to `field_country` so that when it changes (i.e. the user chooses a country) it (re-)populates all the **existing** instances of field\_city (inside the `field_para_city` instances) with corresponding list of cities (e.g., London and Cardiff for the UK).

In MY\_MODULE.module, I added the following so that the above code is executed on the node/add and node/edit forms.

```
function MY_MODULE_entity_type_alter(array &$entity_types) {
  $handlers = $entity_types['node']->get('handlers');
  $handlers['form']['default']  = 'Drupal\MY_MODULE\Form\MyNodeTypeForm';
  $handlers['form']['edit']     = 'Drupal\MY_MODULE\Form\MyNodeTypeForm';
  $entity_types['node']->set('handlers', $handlers);
}

```

All works fine, **except when the user add or remove instances of `field_para_city`** ("Add city" or "Remove"), then all instances of the `field_para_city` are refreshed and `field_city` instances inside them are reset to the allowed values (all cities), ignoring the state of `field_country`.

The user would then need to re-select from `field_country` to get the correct cities again.

I found that although adding/removing a `field_para_city` triggered the above mentioned `buildForm()` function, the `$form_state->getValue('field_country')` was then empty, unlike when `buildForm()` is triggered through the `field_country` AJAX.

I tried to capture the state of `field_country` in the `field_city`'s allowed\_values\_function, so that the allowed options are dynamically and directly set based on the user choice of country, but `$form_state` was not recognised there.

---

I know this is an incorrect approach!

What is the correct better approach to implement this simple use case?

# Answer
I managed to make it work using a different approach; instead of overriding the NodeFrom, I used hook\_field\_widget\_WIDGET\_TYPE\_form\_alter and edited the `subform` array there.
Example:
`/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function MY_MODULE_field_widget_entity_reference_paragraphs_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context)
{
 //Logic to exclude other Paragraph types
 if ($element['#paragraph_type'] !== 'YOUR_PARAGRAPH_TYPE'){ //e.g. cities
 return;
 }
 $element['subform']['field_places']['#states'] = [
 'visible' => [
 [
 //It worked for me with the ID of the select, I think you can use the name also
 '#edit-field-cities-0-subform-field-city' => array('value' => 'Cairo'),
 ]
 ]
 ];
}` When I add another paragraph, the ajax is fired and the selection is still preserved.
I haven't tried with other Ajax fields present though.
> 0 votes

# Answer
You can do it by setting **unique id** for each dependent select box & replace its options whenever the parent select box is changed by setting this **unique id** as ajax wrapper in parent

**These are three important things to make it working**

A. Set **unique id** for child select box (dependent)

B. On parent select box set **unique id**(same uniqueid which is set in child dropdown) as \[#ajax\]\[wrapper\], use \[#ajax\]\[method\] as **html** .

C. In the Ajax callback use **HtmlCommand()** as Ajax response .

```
<?php

 use \Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Ajax\HtmlCommand;
 use Drupal\Core\Ajax\AjaxResponse;
/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
*/
 function modulename_field_widget_entity_reference_paragraphs_form_alter(&$element, &$form_state, $context) {
 if ($element['#paragraph_type'] == 'country_select') {
  $form_state->setRebuild(FALSE);
// Generating Unique id for each state by using parents & delta
$gen_id = 'edit-state-';
foreach ($element['subform']['field_state']['widget']['#parents'] as $value) {
   $gen_id .= is_integer($value) ? "-". $value : "";
}
$gen_id .= "-".$element['subform']['field_state']['widget']["#delta"];
$element['subform']['field_state']['widget']['#attributes']["id"] = $gen_id;
 // Add ajax
 $element['subform']['field_country']['widget']['#ajax'] = [
      'callback' => 'update_state_dropdown', //ajax call back
      'event' => 'change',
      'method' => 'html', // html method
      'wrapper' => $gen_id, // unique id
      'progress' => [
            'type' => 'throbber',
             'message' => NULL,
            ],
      ];
  // Set default value options for state when the country_select  paragraph is loaded
  $default_country = $element['subform']['field_country']['widget']['#default_value'];
  if(isset($default_country[0])) {
     $options = get_state_options_by_country($default_country[0]); // replace with you function
    $element['subform']['field_state']['widget']['#options'] = $options;
  }
 }
}

// Ajax call back

function update_state_dropdown(array &$element, FormStateInterface $form_state) {
 $triggeringElement = $form_state->getTriggeringElement();
 $value = $triggeringElement['#value'];
 $options = get_state_options_by_country($value); // replace with you function
 $wrapper_id = $triggeringElement["#ajax"]["wrapper"];
 $renderedField = '';
 foreach ($options as $key => $value) {
   $renderedField .= "<option value='".$key."'>".$value."</option>";
 }
 $response = new AjaxResponse();
 $response->addCommand(new HtmlCommand("#".$wrapper_id, $renderedField));
 return $response;
}

```

as per link. it also have github link for source
> 0 votes

# Answer
Have you tried using the Business Rules module? It provides this functionality. You may need a patch from Add AJAX support to Paragraphs if it hasn't been merged yet.
> 0 votes

---
Tags: 8, forms, ajax, paragraphs
---


# Question
Title: Can the confirmation URL be different based on different selections made using conditionals?
Hello all of you super helpful people. :)

Drupal 8

Webform: Version: 8.x-5.19

I have created a webform which requires the person completing the form to select one of 4 options and whatever they select determines what fields they see or not.

One of the fields, when selected, needs to take the person to a different URL upon submission, but I am having a difficult time finding out if this is even possible to do...

EXAMPLE

Select:

* Home (submit button takes you to the confirmation page)
* Work (submit button takes you to the confirmation page)
* Campaign (submit button would take you to a different URL (internal or external)

Does this make sense? Is this even possible to do?

Any assistance with this would be greatly appreciated!

Thank you!

# Answer
As there is nothing out of the box that will support this the good news it is quite straight forward in a custom module.

in this example i have admin/structure/webform/manage/WEBFORMID/settings/confirmation

Confirmation type: -\> Page (redirects to new page and displays the confirmation message) aka normal in your case for "Home" and "Work"

then you need a custom module to do ...

```
/**
 * Implements hook_form_alter().
 */
function MYODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // You will need your $form_id.
  // dump($form_id);
  if ($form_id == 'webform_submission_test1_add_form') {
    $form['actions']['submit']['#submit'][] = 'MYODULE_test_form_submit';
  }
}
/**
 * Implements hook_form_submit(). ish.
 */
function MYODULE_test_form_submit(&$form, FormStateInterface $form_state) {
  $form_values = $form_state->getValues();
  // this needs to be your element key.
  if (!empty($form_values['select_one'])) {
    if ($form_values['select_one'] === 'campaign') {
      // Redirect to some page
      $form_state->setRedirect('entity.node.canonical', [
        'node' => 7
      ]);
    }
  }
}

```
> 3 votes

---
Tags: 8, webforms
---


# Question
Title: How to hide Input Format Options and help text under a textarea?
How to hide Input Format Options and help text under a textarea when adding|editing a node?

# Answer
> 27 votes
You can use hook\_form\_alter in a custom module to do this.

For instance, in drupal 7:

```
// hook_form_alter function
function CUSTOM_MODULE_form_alter(&$form, &$form_state, $form_id) {
    // We want this on a specific node type
    if ($form_id == 'NODE_TYPE_node_form') {
        $form['#after_build'][] = 'CUSTOM_MODULE_NODE_TYPE_node_form_after_build';
    }
}

// afterbuild function
function CUSTOM_MODULE_NODE_TYPE_node_form_after_build($form) {
    // We want this on a specific field
    $form['YOUR_FIELD']['und']['0']['format']['#access'] = FALSE;
    return $form;
}

```

# Answer
> 27 votes
For Drupal 7, you can use the Simplify module. It allows you to hide the Text Format options textarea, as well as other elements on node forms.

# Answer
> 12 votes
In drupal 6 there is the module Better Formats which does exactly what you want, there is a 7 dev version but it comes with a warning that it's under heavy development. If you site is still in development then it might be worth giving it a shot.

# Answer
> 9 votes
You can actually just kill the format form item.

```
function MY_THEME_form_comment_form_alter(&$form, &$form_state, &$form_id) {
  $form['comment_body']['#after_build'][] = 'MY_THEME_configure_comment_form';
}

function MY_THEME_configure_comment_form(&$form) {
  unset($form[LANGUAGE_NONE][0]['format']);
  return $form;
}

```

# Answer
> 7 votes
I think the best solution is, to disallow the access to the text format selection element. If you completely unset it, you will face unwanted side effects as a disappearing WYSIWYG editor. So I propose the following code.

```
function MY_MODULE_form_comment_form_alter(&$form, &$form_state, &$form_id) {
  $form['comment_body']['#after_build'][] = 'MY_MODULE_hide_text_format';
}

function MY_MODULE_hide_text_format(&$form) {
  $form[LANGUAGE_NONE][0]['format']['#access'] = false;
  return $form;
}

```

# Answer
> 6 votes
Use CSS, the easiest way.

```
#body-add-more-wrapper #edit-body-und-0-format {display: none;}

```

Good luck.

# Answer
> 5 votes
FOR Drupal 7

```
function MODULENAME_element_info_alter(&$type) {
  if (isset($type['text_format']['#process'])) {
    foreach ($type['text_format']['#process'] as &$callback) {

      if ($callback === 'filter_process_format') {
        $callback = 'MODULENAME_filter_process_format';
      }
    }
  }
}

function MODULENAME_filter_process_format($element) {
  $element = filter_process_format($element);

  // Change input format to "Filtered HTML" for body fields of NODETYPE_NAME

  if ($element['#bundle'] == 'NODETYPE_NAME' && $element['#field_name'] == 'body') {

    $element['format']['format']['#default_value'] = 'filtered_html';
    $element['format']['format']['#format'] = 'filtered_html';
    $element['format']['format']['#value']  = 'filtered_html';
    $element['#format'] = 'filtered_html';

  }
  return $element;
}

```

# Answer
> 2 votes
The another simple way to hide the input format option is removing all other input format from the user profiles you want to hide the option. For this, go admin-\>configuration-\>input formats and remove all the user roles from all other input format except one you want to give by default.

# Answer
> 2 votes
I did this:

Unchecked "Use the Filtered HTML text format" and "Administer text formats and filters" from people \> permissions for anonymous and authorized users so that they couldn't use CKeditor.

Of course you can disable it from CSS by "display: none;" for particular div class (it's .filter-wrapper) and hide all area you have pointed upper but in this case the area is hidden for everyone including superuser.

# Answer
> 1 votes
Install CSS Injector module (currently there is only a working development version for Drupal 8).

Then go to the administration page of CSS Injector (/admin/config/development/css-injector). Create a new CSS rule with this code (or any code that apply to a class of the formating area text):

```
.filter-guidelines {
    display: none;
}

```

Choose to apply it on *Seven* theme (or any admin theme in use). Save and enjoy!

# Answer
> 0 votes
You can't remove the "Plain text" input format. And the RTE is not showing when you use the "Plain Text" input format.

I will be using the CSS option.

# Answer
> 0 votes
```
/ hook_form_alter function
function CUSTOM_MODULE_form_alter(&$form, &$form_state, $form_id) {
    // We want this on a specific node type
    if ($form_id == 'NODE_TYPE_node_form') {
        $form['#after_build'][] = 'CUSTOM_MODULE_NODE_TYPE_node_form_after_build';
    }
}

// afterbuild function
function CUSTOM_MODULE_NODE_TYPE_node_form_after_build($form) {

    // We want to hide input formats and we can do it like following
    $form['body']['und']['0']['format']= '<div style="display:none;">';
    $form['body']['und']['0']['format']= '</div>';

    return $form;
}

```

Mostly Worked for me with these small changes.

```
$form['body'][LANGUAGE_NONE][0]['format']['#prefix']<br>
$form['body'][LANGUAGE_NONE][0]['format']['#suffix']

```

# Answer
> 0 votes
I use both "removing all other input format from the user profiles" and css way.

# Answer
> 0 votes
You can also use the Hide formats module.

> Hide Formats allows you to collapse the "text format" or "input format" dropdowns to clean up the UI.

# Answer
> 0 votes
Try out simplify module .

> Simplify allows particular fields to be hidden from the user interface. This helps to de-clutter forms and present a more user-friendly experience to content editors.

# Answer
> 0 votes
If you want to hide the formats but still keep them available, try the "Simplified formats" module: https://www.drupal.org/project/simplified\_formats

It hides the formats details in a little question mark icon next to the format selection dropdown. For many text format filters it really does no good to completely hide the instructions that tell one how to use them. Other filters are more automatic. I think we need a module that allows us to choose what shows up to the end user and what does not.

# Answer
> 0 votes
For Drupal 8. This removes the format area for two fields.

```
/**
 * Implements hook_form_FORM_ID_alter().
 */
function CUSTOM_MODULE_form_FORM_ID_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  $form['#after_build'][] = 'CUSTOM_MODULE_eform_application_after_build';
}

function CUSTOM_MODULE_eform_application_after_build ($form) {
  unset($form['field_experience']['widget'][0]['format']);
  unset($form['field_miscellaneous']['widget'][0]['format']);
  return ($form);
}

```

# Answer
> 0 votes
For Drupal 7, you can:

1) Use `hook_theme_registry_alter(&$theme_registry)` from within a module to alter the theme registry, eq. the theme processors definition.

2) Then alter three theme functions, `theme_filter_tips`, `theme_filter_tips_more_info`, and `theme_filter_guidelines`, and force them to return nothing. As follows:

This is the target function. All of the above theme functions will be redirected to that.

```
function _mymodule_filter_tips($tips, $long = FALSE, $extra = ''){
  return '';
}

/**
 * Implements hook_theme_registry_alter
 */
function mymodule_theme_registry_alter(&$theme_registry) {
  $theme_registry['filter_tips']['theme path'] = drupal_get_path( 'module', 'mymodule' );
  $theme_registry['filter_tips']['function'] = '_mymodule_filter_tips';
  $theme_registry['filter_guidelines']['theme path'] = drupal_get_path( 'module', 'mymodule' );
  $theme_registry['filter_guidelines']['function'] = '_mymodule_filter_tips';
  $theme_registry['filter_tips_more_info']['theme path'] = drupal_get_path( 'module', 'mymodule' );
  $theme_registry['filter_tips_more_info']['function'] = '_mymodule_filter_tips';
}

```

When you clear your cache, Drupal will seek those filter definitions on the path of your module of choice (see `drupal_get_path`), and return nothing for each filter. Hence, no more text format descriptions.

# Answer
> 0 votes
Simplest solution is to just make the field "Text (plain, long)".

Done, no code, no modules, no headaches.
If you must allow  *some roles*  to have formatting while others plain text then the closest you can get without extra code or modules is to disable all other formats for that role that just needs plain text.

```
admin/config/content/formats

```

It still leaves the bar and the Help on Text Formats question mark. But eh, it's worth not having extra code.

---
Tags: 7, wysiwyg, input-formats
---


title: View not displayed for other roles

text:
# Question
Title: View not displayed for other roles
I have a block view that displays own articles created (this view is inside a panel page). But this view didn't displayed for other users except administrators, or when I check the permission 'Bypass content access control' to the other roles.

You know that this permission is a risk when it's checked, and I won't that other users have access to everything for nodes.

I checked the permissions like that :

* inside the Views UI edit page : access option =\> View published content (I changed to 'none' also)
* inside user permission page : "View published content" && "View own unpublished content" of "node" section are checked (also other permissions : create new article, edit own article ...)
* there is no restriction in the block settings for a specific role.

Is really weird what happen here. doese anyone have this problem before? Or how you can advise me to resolve this permission issue?

Thanks in advance.

**ADD:**

this is a list of modules in the website:

**EDIT**

I found from where is this problem : my articles are not yet published and only published articles are shown in the view content. I made sure that the permission "view own unpublished content" is checked, but content still not shown when i unpublish again the articles (views content is not shown to the AUTHOR of these nodes)

I found this module to grant users to see all unpublished content but this is not good for me, because i need users to see only their content.

Any ideas ? Thanks in advance.

# Answer
> 0 votes
My best guess is that you haven't configured the contextual filter on author\_id in views. and take it for logged users. In that case it will show the other users pages aswell

# Answer
> 0 votes
You can turn off rewriting sql and make conditionals on your own in the view. Then relationship to author\_id will show you nodes which he saved in the system.

Turning off rewriting for this block will turn off node\_access check.

---
Tags: 7, views, nodes, panels
---


# Question
Title: My page is in hook_admin_paths(), but doesn't show admin theme
```
function mymodule_admin_paths() {
  $paths = array(
    'admin-dvr/*' => TRUE,
  );
  return $paths;
}

```

I have a module which generates a page and I want that page to be themed with the admin theme. I implemented the above hook so that when I browse to `admin-dvr/dvr/manage` it should be displaying with the admin theme.

On my dev server, this works just fine. When I push that code to production, and flush all the caches, I'll sometimes see it load with the admin theme ONCE, but then every time after that it loads with the mainsite theme.

What am I doing wrong? Why won't it load my page with the admin theme?

# Answer
I would suggest you place your admin pages under `admin/dvr`. In that way you should not need to implement `hook_admin_paths()` at all.
> 0 votes

# Answer
The code used from that hook implementation is correct. It's similar to the code implemented from Drupal core, for example in `system_admin_paths()` or `overlay_admin_paths()`.

```
function system_admin_paths() {
  $paths = array(
    'admin' => TRUE,
    'admin/*' => TRUE,
    'batch' => TRUE,
    // This page should not be treated as administrative since it outputs its
    // own content (outside of any administration theme).
    'admin/reports/status/php' => FALSE,
  );
  return $paths;
}

```

```
function overlay_admin_paths() {
  $paths = array(
    // This is marked as an administrative path so that if it is visited from
    // within the overlay, the user will stay within the overlay while the
    // callback is being processed.
    'overlay/dismiss-message' => TRUE,
  );
  return $paths;
}

```

The explanation about the *admin-dvr/dvr/manage* path being shown sometimes with the administrative theme and sometimes with the default theme I could find is that there is a module that is setting the theme to use with `hook_custom_theme()`.
The `hook_admin_paths()` implementations are, indirectly, invoked by `system_custom_theme()`, which is a `hook_custom_theme()` implementation.

```
function system_custom_theme() {
  if (user_access('view the administration theme') && path_is_admin(current_path())) {
    return variable_get('admin_theme');
  }
}

```

Alternatively, basing on the code used by `menu_get_custom_theme()` and the comment before it, a theme callback could exist for that path, and that theme callback sometimes return the name of the default theme as name of the theme to use for that path.

```
// If there is a theme callback function for the current page, execute it.
// If this returns a valid theme, it will override any theme that was set
// by a hook_custom_theme() implementation above.
$router_item = menu_get_item();
if (!empty($router_item['access']) && !empty($router_item['theme_callback']) && function_exists($router_item['theme_callback'])) {
  $theme_name = call_user_func_array($router_item['theme_callback'], $router_item['theme_arguments']);
  if (drupal_theme_access($theme_name)) {
    $custom_theme = $theme_name;
  }
}

```
> 0 votes

---
Tags: 7
---


# Question
Title: How can I disable Webform submit button after being clicked
I've been trying to resolve an issue with no luck. For some reason there are no submission indicators out of the box with D7 Webforms and from what i've found it doesn't look like they have any plans to implement this as they have already added this 'feature' in D8.

I wrote a handler in javascript that will just replace the input with another, but it doesn't appear that the script is firing because the actual submit is taking priority

```
var form = document.getElementsByClassName("webform-client-form")[0];
var isValidForm = form.checkValidity();
var submitBtn = document.getElementsByClassName('webform-submit')[0];
function preventExtraSubmits() {
    if (isValidForm) {
        var fakeBtn = document.createElement("input");
        fakeBtn.value = "Submitting...";
        fakeBtn.classList.add('webform-submit button-primary form-submit')
        insertAfter(submitBtn, fakeBtn);
        submitBtn.style.display = 'none';
    }
}
function insertAfter(referenceNode, newNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
submitBtn.onsubmit = function(){preventExtraSubmits()}

```

From what i've seen is that this might need to be handled server side, but I can't seem figure out how to override webforms submit function.

Fairly new to Drupal and this has been a very frustrating battle to get this working

Drupal v 7.77 Webform v 7.x-4.23

# Answer
> 0 votes
You could try this module: https://www.drupal.org/project/hide\_submit Be aware that this module has an issue with Ajax forms and file uploads.

---
Tags: 7, webforms
---


# Question
Title: What instantiates a CacheBackendInterface?
I am working on upgrading a module and there is a use statement

```
use Drupal\Core\Cache\CacheBackendInterface;

```

What is the point of using an interface like that? Interfaces dont have actual code and this .module file doesnt inherit from that interface.

Now when the module is in enabled i get

```
Error: Cannot instantiate interface Drupal\Core\Cache\CacheBackendInterface in /srv/www/mydev/current/core/lib/Drupal/Component/DependencyInjection/Container.php, line 265

```

and the only lines I can find relating to the cache interface are

```
\Drupal::cache('libraries')->deleteAll();
\Drupal::cache('libraries')->set($name, $library);

```

So I am confused as to why this is supposed to clear the cache?

Or is it that it is not supposed work and the latest version of the module is not complete yet?

# Answer
You're using an old version of libraries module it seems. There was a core change that changed how the cache backends are defined.

Update it, clear caches and it should work.
> 1 votes

# Answer
> ```
> use Drupal\Core\Cache\CacheBackendInterface;
>
> ```
>
> What is the point of using an interface like that? Interfaces dont have actual code and this .module file doesnt inherit from that interface.

Interfaces are 'contracts' that any class implementing it must follow. An interface declares a number of functions. Any class that implements that interface must implement all the functions described in the interface, otherwise an error is thrown. Using interfaces as type hints, rather than using the actual class as a type hint, means that any class implementing the interface can be passed rather than just the original class, making your code more flexible.

For example, imagine three classes. Here are their declarations:

```
class Truck {
  ...
}

class Car implements CarInterface {
  ...
}

class Sedan extends Car {
  ...
}

```

Now let's look at a function that uses type hinting for arguments:

```
function doSomething(Car $vehicle) {
  ...
}

```

Now look at code that uses this function:

```
$car = new Truck();
doSomething($car);

```

This will force an error, as the `Truck` class does not implement `CarInterface`, and `doSomething()` requires an object that implements `CarInteface`. Next:

```
$car = new Car();
doSomething($car);

```

This will work, as `doSomething()` expects an object of type `Car`. The problem comes here:

```
$car = new Sedan();
doSomething($car);

```

This will thrown an error, as the `Sedan` class is not a `Car`, which `doSomething()` requires. Even though `Sedan` extends `Car`, and therefore has all the same properties and methods as `car`, and will therefore work as a replacement to `Car`, the code fails. This is not desirable, as you would have to write a new function to handle `Sedan`. It's also no good if your code is to be extensible by other developers that may not have the ability to contact you.

To get around this, instead of type hinting a class for the function, the interface is type hinted:

```
function doSomething(CarInterface $vehicle) {
  ...
}

```

Now that `doSomething()` expects a `CarInterface` rather than a `Car`, the following will work without errors:

```
$car = new Car();
doSomething($car);
$sedan = new Sedan();
doSometing($sedan);

```

This is because the `Sedan` class extends `Car`, and since `Car` implements `CarInterface`, so does `Sedan`. Now your code is extensible, because any developer can create a new class that either implements `CarInterface`, or extends `Car` (therefore implementing `CarInterface`), and use it with `doSomething()`, rather than only being able to pass a `Car` object.

To understand this a little deeper, take a look at a bit more code:

```
function doSomething(CarInterface $vehicle) {
  $doors = $vehicle->getNumberOfDoors();
}

```

This function calls the `getNumberOfDoors()` method on `$vehicle`. This means that if the object `$vehicle` does not have this method, an error will be thrown. To ensure that any value passed for `$vehicle` will have the method `getNumberOfDoors()`, this method is declared in the interface:

```
interface CarInterface {

  /**
   * Retrieves the number of doors on the car.
   *
   * @return int
   *   The number of doors on the car.
   */
  public function getNumberOfDoors(): int;
}

```

No code is declared in the interface, as this is only a contract, not the code definition. This contract requires that any class implementing `CarInterface` must have the method `getNumberOfDoors()`. If this method does not exist, a fatal error is thrown. So with this function:

```
function doSomething(CarInterface $vehicle) {
  $doors = $vehicle->getNumberOfDoors();
}

```

... we know that $vehicle will always have a `getNumberOfDoors()` method, as the `CarInterface` contract requires it. How that class implements this method is up to the class, as long as the return value is an integer
> 0 votes

---
Tags: 8
---


# Question
Title: Bullets and numbers not visible in CKeditor
When I edit something in CKeditor and insert a list, the bullets or numbers are not rendered in the result.
Is it possible to correct it?

# Answer
CKeditor uses CSS from either your default theme or it's own stylesheet. If you are are using your site theme maybe it is set to hide the bullets and numbers.
> 2 votes

# Answer
I had the same problem. It was related to my theme css. I solved it by changing the ckeditor css editor settings under admin/config/content/wysiwyg from "use theme css" to "editor default css".
> 1 votes

# Answer
li { display: list-item !important; }

Adding this in a custom css works. But this works only for a)node view pages & b) preview modes, and not in the a) dialogue box & b) text editors .
> 1 votes

# Answer
Are just the bullets not showing up or the list itself. ie is it putting or tags within the content result? If not it may be an issue of your input format stripping out the tags.

If the tags are there then the bullets or numbers showing up is most likely a css issue. look for list-style: none; for example.
> 0 votes

# Answer
If you're using your own theme's CSS styles (which is often a great idea!) make sure you're not embedding HTML elements within elements that might not exist in CKEditor. For example, this:

`.node-inner ul li {
 list-style-type: disc;
}`

will never show up in CKEditor because there's no `<div class="node-inner">` within it. You'll need to just use `ul li {...}`.

Sometimes I create a "ckeditor.css" file in my theme that defines only the styles I care about in this context, such as those that would appear within the body of a node.
> 0 votes

# Answer
Add

```
list-style-position: inside;

```

to your ol, ul css
> -1 votes

---
Tags: wysiwyg
---


# Question
Title: Unset email address requirement on User Form not taking
The scope of our project doesn't require users to have an email (they can use phone instead), therefore, I'm trying to unset the email requirement like so:

```
function my_module_form_user_form_alter(&$form, &$form_state, $form_id) {
   $form['account']['mail']['#required'] = false;
}

```

However, this doesn't seem to actually change the requirement because when I submit the form without an Email I still get the error `Email field is required`... I used `kint` to view the form object `$form['account']['mail']` and it shows that the required attribute is set to false, yet I still get the error that it's required...

How can I make it so that I can save a user record without an email using this form?

# Answer
> 2 votes
The email field is one of the entity fields added by User::baseFieldDefinitions(), which sets it with a constraint.

```
$fields['mail'] = BaseFieldDefinition::create('email')
  ->setLabel(t('Email'))
  ->setDescription(t('The email of this user.'))
  ->setDefaultValue('')
  ->addConstraint('UserMailUnique')
  ->addConstraint('UserMailRequired')
  ->addConstraint('ProtectedUserField');

```

The `UserMailRequired` constraint does what its name suggest: It checks if the user's email address is provided if required. It isn't required if the account originally had no mail set and the user editing the account has the *administer users* permission.

That constraint needs to be removed from the entity field, to allow the email field to be empty. (It still necessary to mark the email form field as not required, though.)

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

function mymodule_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'user' && !empty($fields['mail'])) {
    $constraints = $fields['mail']->getConstraints();
    unset($constraints['UserMailRequired']);
    $fields['mail']->setConstraints($constraints);
  }
}

```

# Answer
> 0 votes
In Drupal 8 the form requirement is not the only piece involved. The Email requirement is implemented as an Entity Constraint so that it is also enforced if someone uses the REST API.

Therefore your answer should be in this question: Alter the entity constraints for the User entity. The alteration can be done via hook\_validation\_constraint\_alter. It should also be possible to use hook\_entity\_type\_alter. That is what is used to add a constraint.

---
Tags: 8, forms
---


title: Twig template for content in body

text:
# Question
Title: Twig template for content in body
I want to put some custom information in the content area of book pages (so, after the author info and before the add child page, etc. links). In the node template, the content comes in with both the body content and the following links already merged. I've dug through the core template directories and I can't find the template for just the body content itself. Anyone know what it is? Thanks!

# Answer
> 2 votes
The correct answer is you need to look at how to turn on twig debugging Please read and understand:

https://www.drupal.org/docs/theming-drupal/twig-in-drupal/debugging-twig-templates

once you have fully read the above and have set it up you will be able to find the correct template and copy the default form the core to your theme and edit away.

---
Tags: theming, nodes
---


title: views_query_alter add condition

text:
# Question
Title: views_query_alter add condition
This looks appropriate for D7, but `add_where` doesn't exist in D8. What should I use?

```
/**
 * Filter out the current node from the view query
 */
if ($view->id() == 'videos') {
    $node = \Drupal::routeMatch()->getParameter('node');
    if ($node) {
        $query->add_where(0, $node->ID(), 'nid', 'NOT IN');
    }
}

```

# Answer
> 2 votes
You try code:

```
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\query\QueryPluginBase;
....

   /**
    * Implements hook_views_query_alter().
    */
    function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
     $query->addWhere(0, 'node__field_data.nid', [1,2,3], 'IN');
    }

```

---
Tags: 8
---


# Question
Title: Print the node author's full name on a custom node template
I have a content type "Blog entry" which I have overridden the template. (node--blog\_entry.tpl.php)

The target is to display the node author's full name (as a link) which will take the user to a page (produced by a view) which shows all the other articles they have written.

In my template file, I have the following code:

```
 function bootstrap_mysite_preprocess_node(&$vars) {
   $vars['author_name'] = $vars['name'];
   $vars['submitted_dt'] = format_date($vars['node']->created, 'custom', 'jS F Y');
 }

```

The view that I have created which shows the author's other articles takes the UserID as an argument, so what I need is to display a link which which shows the author's full name, but passes their UserID.

the code I have in my custom content template is:

```
<div class="author-name">
    WRITTEN BY <a href="/user-posts/<?php print $uid; ?>"> <?php print $author_name; ?></a>
  </div>

```

But author name is not only the author's username (not their full name) but it is output as a link which is no good for me. I simply want to output the author's full name as plain text.

So, to summarise - What can I use instead of `$vars['name']; (which produces`a username that links to a profile) that will instead produce some plain text of the user's full name ?

# Answer
Your question doesn't indicate whether you are storing the user's full name anywhere. You can add fields to the user profile (at `/admin/config/people/accounts/fields`). Suppose you add a firstname field (field\_user\_fname) and lastname field (field\_user\_lname), you could then write a custom function in your template file, like this:

```
function _get_author_name($uid) {
  $wrapper = entity_metadata_wrapper('user', $uid);
  $fname = $wrapper->field_user_fname->value();
  $lname = $wrapper->field_user_lname->value();
  return "$fname $lname";
}

```

And then, since you already know the UID, you could call the function from your content template:

```
<div class="author-name">
    WRITTEN BY <a href="/user-posts/<?php print $uid; ?>">
    <?php print _get_author_name($uid); ?></a>
  </div>

```

You could also investigate the Realname module.
> 2 votes

# Answer
Update the nme variable by fetching the admin/config/people/accounts/fields first\_name and last\_name (if existing or else add and use same machine name in below code snippet)

```
use Drupal\Core\Session\AnonymousUserSession;

/**
 * Implements template_preprocess_username() for username.html.twig.
 */
function MYTHEME_preprocess_username(&$variables) {
  $account = $variables['account'] ?: new AnonymousUserSession();

  $variables['extra'] = '';
  $variables['uid'] = $account->id();
  if (empty($variables['uid'])) {
    if (theme_get_setting('features.comment_user_verification')) {
      $variables['extra'] = ' (' . t('Anonymous') . ')';
    }
  }

 // that $variables['name'] is safe for printing.
 // Use machine name of Fields First Name and Last Name
 $name = $account->get('first_name')->value.' '.$account->get('last_name')->value;

 if (mb_strlen($name) > 20) {
    $name = Unicode::truncate($name, 15, FALSE, TRUE);
 }

  $variables['name'] = $name;
  // {{ username }} and {{extra}} will be available within username.html.twig.
}

```
> 0 votes

---
Tags: 7, theming, configuration
---


title: JS not run with custom module

text:
# Question
Title: JS not run with custom module
I have created custom module with drupal 8 after successfully installation on my module run properly with java script but after its not working till now , i have done multiple changes in my module controller file but module has not run .

my controller file code is here :

```
<?php

/**
 * @file
 * Controller for generating JSON response.
 */

namespace Drupal\ipew\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\Core\Database\Database;

/**
 * Controller for d3 ipew.
 */
class ipewController extends ControllerBase {
  /**
   * Display the markup.
   *
   * @return array
   */

   public function content() {

      return [
      '#title' => 'Hello World',
      '#markup' => 'Welcome to this World',
    ];
   }

}

```

\*.info.yml file code is here :

```
name: ipew
type: module
description: Attack map
core: 8.x
package: Custom

```

\*.liabraries.yml code is here :

```
ipew:
  version: 1.x
  js:
    js/d3.v3.min.js: {}
    js/ipew.js: {}
    js/d3.geo.projection.v0.min.js: {}
    js/topojson.v1.min.js: {}
    js/datamaps.world.min.js: {}
    js/jquery-2.1.1.min.js: {}
    js/jquery.simplemodal-1.4.4.js: {}
  dependencies:
    - core/drupal
    - core/jquery
    - core/drupalSettings

```

\*.routing.yml is here :

```
ipew.list:
  path: '/ipew'
  defaults:
    _controller: '\Drupal\ipew\Controller\ipewController::content'
    _title_callback: '\Drupal\ipew\Controller\ipewController::getTitle'
  requirements:
    _permission: 'access content'

```

\*.html.twig file is here :

```
{# ipew/templates/ipew.html.twig #}
<p>IPEW</p>

<svg width="960" height="600"></svg>

```

This module only show hello world in output .

# Answer
You need to attach your library:

```
return [
  '#title' => 'Hello World',
  '#markup' => 'Welcome to this World',
  '#attached' => [
    // Add the ipew library from the ipew module
    // in the format [MODULE]/[LIBRARY].
    'library' => 'ipew/ipew',
  ],
];

```
> 3 votes

# Answer
As japan told you, you need to attach the library.

You need also to configure your `ipew.libraries.yml`

```
lorem_ipsum:
  version: 1
  js:
    js/your-file.min.js: {minified: true}
  dependencies:
    - core/jquery

```

And in your js file :

```
(function ($, Drupal) {
    Drupal.behaviors.ipew = {
        attach: function (context, settings) {
             // your js code

        }
    };
})(jQuery, Drupal);

```

The advantage of Behaviors over document.ready() is that they are automatically re-applied to any content loaded through AJAX : Better understanding of Drupal behaviors
> 0 votes

---
Tags: javascript
---


# Question
Title: What is the purpose of a configuration schema file?
I created a /config/schema/drupolo.yml file with the following content.

```
drupolo.social_network.setting:
  type: config_object
  label: 'Sacd Menu module settings.'
  mapping:
    facebook_page:
      type: string #Type: can be string | integer |  boolean
      label: 'Facebook page'
    twiiter_page:
      type: string
      label: 'Twitter page'

```

I created the /config/install/drupolo.social\_network.setting.yml file with a key that doesn't exist in the schema file.

The problem is that the module is installed and the configuration is stored in the configuration table, and it doesn't respect the schema file.

```
facebook_page: 'https://facebook.com/default'
twitter_page: 'https://twiiter.com/default'
linkedn_page: 'http://linkedin.com' # key that don't respect the "drupolo.social_network.setting" structure that has been declared in the drupolo.yml

```

What is the purpose of the /config/schema/{module}.yml file if the config/install won't respect that structure?

# Answer
Drupal does not check the configuration schema at runtime when the configuration is loaded - the configuration is assumed to be correct.

The schema is used in the tests - when running tests, configurations are automatically validated against the schema to ensure they are correct. Presumably you have developed your module with tests, and by the time you make your module publicly available you will have your tests running and verifying that the configurations you are shipping are valid.

The contributed config\_inspector module is very useful for validating and debugging configuration and configuration schema.
> 1 votes

---
Tags: configuration
---


# Question
Title: Missing formatter options for field from a custom table defined in hook_views_data()
I integrated a custom database table to views using `hook_views_data()`.

```
$data['custom_watchdog']['message'] = [
    'title' => 'Message',
    'help' => 'Full log message.',
    'field' => [
        'id' => 'standard',
    ],
    'filter' => [
        'id' => 'string',
    ],
];

```

It works, as I can display values in a view, but it misses a formatter option.
For example, the *Taxonomy term: Description* field has formatter options which allows to select *Default* or *Trimmed*.

Why isn't it available for my custom field?

# Answer
> 2 votes
You are comparing a standard Views field with an entity field. Only entity fields have field formatters. Create a custom entity instead of a custom table if you want to use this feature. For a standard field you have to use the options provided by Views. There is a trim option as well, but it is named differently, `trim` in the `alter` section. You see it in Views UI. Try to configure it and check the exported View.

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


# Question
Title: Editing a node deletes body content reproducibly if Locale module enabled
I am experiencing a pretty serious problem leading to data-loss in D7. Editing any existing node leads to empty body content and newly created nodes have no body content whatsoever.

**Update: The error is reproducibly linked to the Locale module** (v 7.78), disabling Locale leads to normal behavior, enabling it leads to data-loss when editing.

However, Locale has been enabled for a long time, so I am suspecting one of the updates since May 2020 (last time new content was added without problems) introduced a bug or a failed database update. So, there might be a bug in Locale that only shows under certain circumstances, e.g. PostgreSQL, a site migrated from D6 or Locale activated after content was already created, ...

The following observations are with Locale enabled:

Tracking an existing node in Postgres shows the node body content in `field_data_body` before an edit. After an edit, `field_data_body` has no entry with the entity\_id. I can put back the data using SQL and then the body content is displayed. Newly created nodes never get an entry in `field_data_body`.

Therefore, I am suspecting something might be odd with HTML filtering (Filtered HTML, Plain text, ...) or the content edit form or language settings.

This is the original data of an existing node:

```
select * from field_data_body where entity_id = 745959;
 entity_type | bundle | deleted | entity_id | revision_id | language | delta |

    body_value               | body_summary | body_format
-------------+--------+---------+-----------+-------------+----------+-------+----------------------------------------+--------------+-------------
 node        | blog   |       0 |    745959 |      745959 | und      |     0 | The genome browser is not working TEST |              | 1

```

After editing:

```
select * from field_data_body where entity_id = 745959;
 entity_type | bundle | deleted | entity_id | revision_id | language | delta | body_value | body_summary | body_format
-------------+--------+---------+-----------+-------------+----------+-------+------------+--------------+-------------
(0 rows)

```

Also, the node.language and field language are different:

```
select nid, n.language as "node-language", b.language as "field-language" from node as n left join field_data_body as b on n.nid=b.entity_id  where nid = 745959;
  nid   | node-language | field-language
--------+---------------+----------------
 745959 | en            | und
(1 row)

```

Looks like it could indeed be a language setting conflict. When looking at the $form data, the values entered into body are found as such and only there.

So it indeed appears to be a language setting problem:

* create a new Page node: node.language is initially set to "en", the site default, no body data entry is created or saved upon edit (in form\_data\_body)
* In postgres, change node.language to "und"
* The body content is now saved upon edit and displayed properly

# Answer
> 0 votes
Implement `hook_form_submit()` and either set a breakpoint there, output to the messages or log the `form_state` values to see what's actually being submitted. Implement `hook_node_presave()` and do the same to see what's actually going to be saved to the database.

There is a chance the client-side JS or some validation hook changes the value for the field, so you will have to either dig or debug through all your modules. It's hard to tell something specifically, because any module, either contrib or custom one, can put its own hook and empty the content for some reason.

---
Tags: 7, nodes, i18n-l10n
---


# Question
Title: Allow user to fill out node form, then force registration
I'm making a classified website.

Have a button that say "Make a ad" I would like the Anonymous user to be able to fill in the text for the ad.

But the Anonymous users after filling in advert. has to sign up for the ad to be posted

How can do this with drupal please?

many thanks for your help

Best Regards Charles

# Answer
There are many ways to achieve this. Two suggestions:
> 0 votes

# Answer
As a custom solution, you can do something like this.

1. Create your content (or entity) type. Let's assume two fields: title and body
2. Create a custom form, with fields for title and body.
3. In the form submission, programmatically create a node, and add the submitted title and body to the node. Don't save the node. Instead, store it in the session:

```
$session = \Drupal::request()->getSession();
$session->set('my_module_registration_node', $node);
$value = $session->get('my_module_registration_node);

```
4. Also in the form submission, redirect the user to the registration form
5. On registration, check for the existence of the node in the session. If it's there, retrieve it, add the new user as the owner, save it, and clear the session.

Alter as necessary. The `tempstore.private` service is an alternative to using the session. It is more powerful, so if you run into problems storing your node in the session, the private tempstore may serve you better.

You can also create a multistep form with two (or more) steps, collecting both the node data and the user data, and in the final submission, programmatically create the user and node at the same time. This way you can have an ajax form that is customized exactly to your system needs.
> 0 votes

---
Tags: forms, nodes, users
---


# Question
Title: Views Data Export print feed icon in template file
I created a template for my view (views-view-fields-xxx.tpl.php). On my view page I use the 'Views Data Export Module' to export filtered views in XLS format.

I cannot figure out how to display the button on the top of the page. I tried printing it out in my template file using :

```
<?php print $view->feed_icon ?>

```

but then it prints out the button on every field view. Is there a way to print this field only once? Or another way to move the "feed-icon" to the top of my page?

# Answer
Solution from: https://www.drupal.org/node/2117433#comment-9422881

1. Copy the views-view.tpl.php file from views into your theme (or its templates directory if it has one). Note that you can rename the file in certain ways to make it specific to an individual view or display. The "Theme: Information" section of the views UI will give you more information. Also see the blog post for more information on that.
2. Clear the cache so the site starts using your new template file instead of the default views one. The "Theme: Information" part of the views UI should now indicate that your file is being used.
3. In your theme's version of the template file move the feed icon section wherever you want it. Potentially you would put it under the exposed filters or something. Currently the the feed icon part of the template looks like this (move this whole section):

`<?php if ($feed_icon): ?>
 <div class="feed-icon">
 <?php print $feed_icon; ?>
 </div>
 <?php endif; ?>`
> 3 votes

# Answer
Another alternative (if you can't override the `views-view.html.twig`) would be to use a preprocess function:

```
// mysite.module

/**
 * Implements hook_preprocess_views_view().
 */
function mysite_preprocess_views_view(array &$variables) {
  // Move feed icon to the top of the result, instead of buttom.
  if (isset($variables['feed_icons'])) {
    $variables['attachment_before'] = array_merge($variables['attachment_before'], $variables['feed_icons']);
    unset($variables['feed_icons']);
  }
}

```
> 2 votes

---
Tags: views, theming, importing-exporting
---


# Question
Title: How can I avoid users can change the "Make revision" field?
My users can edit any content, but I really need to know what they did. I need revisions. I tried the *Hide revision* module, but when the *Make revision* field is unchecked, the revision isn't created. They see that field, they uncheck it, and the revision isn't created.

How can I avoid they uncheck that field?

# Answer
> 0 votes
You can try Hide Revision field module with this patch. See issue \[#3001097\]

---
Tags: nodes
---


# Question
Title: What is the safe way to update to latest version?
I am taking over a Drupal project that's running on Drupal 8.8.5.

Can I upgrade to Drupal 9.1.5, or do I need to upgrade for each version that's been missed?

# Answer
> 4 votes
In theory you should update to the latest recommended version of your current site's minor release. So in this case you should update to version 8.9.13 then you should be good upgrade. Remember to also make sure you do the same for all contributed modules and themes. You might find using the Upgrade Status module helpful before upgrading.

As with everything you do, make sure you create a full backup of the sites files and database/s before attempting any updates.

---
Tags: upgrading
---