Created
October 30, 2018 15:30
-
-
Save ahebrank/0e205c339078396222a78668df12d10a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php | |
| index efadf83126..42685c79f3 100644 | |
| --- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php | |
| +++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php | |
| @@ -6,6 +6,7 @@ | |
| use Drupal\Core\Form\FormStateInterface; | |
| use Drupal\taxonomy\Entity\Term; | |
| use Drupal\taxonomy\TermStorageInterface; | |
| +use Drupal\taxonomy\VocabularyInterface; | |
| use Drupal\taxonomy\VocabularyStorageInterface; | |
| use Drupal\views\ViewExecutable; | |
| use Drupal\views\Plugin\views\display\DisplayPluginBase; | |
| @@ -78,7 +79,10 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o | |
| parent::init($view, $display, $options); | |
| if (!empty($this->definition['vocabulary'])) { | |
| - $this->options['vid'] = $this->definition['vocabulary']; | |
| + $this->options['vids'] = [$this->definition['vocabulary']]; | |
| + } | |
| + if (empty($this->options['vids']) && !empty($this->options['vid'])) { | |
| + $this->options['vids'] = [$this->options['vid']]; | |
| } | |
| } | |
| @@ -98,13 +102,16 @@ protected function defineOptions() { | |
| $options['type'] = ['default' => 'textfield']; | |
| $options['limit'] = ['default' => TRUE]; | |
| - $options['vid'] = ['default' => '']; | |
| + $options['vids'] = ['default' => []]; | |
| $options['hierarchy'] = ['default' => FALSE]; | |
| $options['error_message'] = ['default' => TRUE]; | |
| return $options; | |
| } | |
| + /** | |
| + * {@inheritdoc} | |
| + */ | |
| public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) { | |
| $vocabularies = $this->vocabularyStorage->loadMultiple(); | |
| $options = []; | |
| @@ -114,18 +121,19 @@ public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) { | |
| if ($this->options['limit']) { | |
| // We only do this when the form is displayed. | |
| - if (empty($this->options['vid'])) { | |
| + if (empty($this->options['vids'])) { | |
| $first_vocabulary = reset($vocabularies); | |
| - $this->options['vid'] = $first_vocabulary->id(); | |
| + $this->options['vids'] = $first_vocabulary->id(); | |
| } | |
| if (empty($this->definition['vocabulary'])) { | |
| - $form['vid'] = [ | |
| - '#type' => 'radios', | |
| + $form['vids'] = [ | |
| + '#type' => 'checkboxes', | |
| '#title' => $this->t('Vocabulary'), | |
| '#options' => $options, | |
| '#description' => $this->t('Select which vocabulary to show terms for in the regular options.'), | |
| - '#default_value' => $this->options['vid'], | |
| + '#default_value' => $this->options['vids'], | |
| + '#required' => TRUE, | |
| ]; | |
| } | |
| } | |
| @@ -133,7 +141,10 @@ public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) { | |
| $form['type'] = [ | |
| '#type' => 'radios', | |
| '#title' => $this->t('Selection type'), | |
| - '#options' => ['select' => $this->t('Dropdown'), 'textfield' => $this->t('Autocomplete')], | |
| + '#options' => [ | |
| + 'select' => $this->t('Dropdown'), | |
| + 'textfield' => $this->t('Autocomplete'), | |
| + ], | |
| '#default_value' => $this->options['type'], | |
| ]; | |
| @@ -149,19 +160,31 @@ public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) { | |
| ]; | |
| } | |
| + /** | |
| + * {@inheritdoc} | |
| + */ | |
| + public function submitExtraOptionsForm($form, FormStateInterface $form_state) { | |
| + $vids = $form_state->getValue(['options', 'vids']); | |
| + $form_state->setValue(['options', 'vids'], array_keys(array_filter($vids))); | |
| + } | |
| + | |
| protected function valueForm(&$form, FormStateInterface $form_state) { | |
| - $vocabulary = $this->vocabularyStorage->load($this->options['vid']); | |
| - if (empty($vocabulary) && $this->options['limit']) { | |
| + $vocabularies = $this->vocabularyStorage->loadMultiple($this->options['vids']); | |
| + if (empty($vocabularies) && $this->options['limit']) { | |
| $form['markup'] = [ | |
| '#markup' => '<div class="js-form-item form-item">' . $this->t('An invalid vocabulary is selected. Please change it in the options.') . '</div>', | |
| ]; | |
| return; | |
| } | |
| + $vocabulary_labels = array_map(function (VocabularyInterface $vocabulary) { | |
| + return $vocabulary->label(); | |
| + }, $vocabularies); | |
| + | |
| if ($this->options['type'] == 'textfield') { | |
| $terms = $this->value ? Term::loadMultiple(($this->value)) : []; | |
| $form['value'] = [ | |
| - '#title' => $this->options['limit'] ? $this->t('Select terms from vocabulary @voc', ['@voc' => $vocabulary->label()]) : $this->t('Select terms'), | |
| + '#title' => $this->options['limit'] ? $this->t('Select terms from vocabularies @vocs', ['@vocs' => implode(', ', $vocabulary_labels)]) : $this->t('Select terms'), | |
| '#type' => 'textfield', | |
| '#default_value' => EntityAutocomplete::getEntityLabels($terms), | |
| ]; | |
| @@ -169,21 +192,26 @@ protected function valueForm(&$form, FormStateInterface $form_state) { | |
| if ($this->options['limit']) { | |
| $form['value']['#type'] = 'entity_autocomplete'; | |
| $form['value']['#target_type'] = 'taxonomy_term'; | |
| - $form['value']['#selection_settings']['target_bundles'] = [$vocabulary->id()]; | |
| + $form['value']['#selection_settings']['target_bundles'] = array_keys($vocabularies); | |
| $form['value']['#tags'] = TRUE; | |
| $form['value']['#process_default_value'] = FALSE; | |
| } | |
| } | |
| else { | |
| if (!empty($this->options['hierarchy']) && $this->options['limit']) { | |
| - $tree = $this->termStorage->loadTree($vocabulary->id(), 0, NULL, TRUE); | |
| $options = []; | |
| - | |
| - if ($tree) { | |
| - foreach ($tree as $term) { | |
| - $choice = new \stdClass(); | |
| - $choice->option = [$term->id() => str_repeat('-', $term->depth) . \Drupal::entityManager()->getTranslationFromContext($term)->label()]; | |
| - $options[] = $choice; | |
| + foreach ($vocabularies as $vocabulary) { | |
| + $tree = $this->termStorage->loadTree($vocabulary->id(), 0, NULL, TRUE); | |
| + if ($tree) { | |
| + foreach ($tree as $term) { | |
| + $choice = new \stdClass(); | |
| + $choice->option = [ | |
| + $term->id() => str_repeat('-', $term->depth) . \Drupal::entityManager() | |
| + ->getTranslationFromContext($term) | |
| + ->label() | |
| + ]; | |
| + $options[] = $choice; | |
| + } | |
| } | |
| } | |
| } | |
| @@ -195,12 +223,18 @@ protected function valueForm(&$form, FormStateInterface $form_state) { | |
| ->sort('weight') | |
| ->sort('name') | |
| ->addTag('taxonomy_term_access'); | |
| - if ($this->options['limit']) { | |
| - $query->condition('vid', $vocabulary->id()); | |
| + $conditions = $query->orConditionGroup(); | |
| + foreach ($vocabularies as $vocabulary) { | |
| + if ($this->options['limit']) { | |
| + $conditions->condition('vid', $vocabulary->id()); | |
| + } | |
| } | |
| + $query->condition($conditions); | |
| $terms = Term::loadMultiple($query->execute()); | |
| foreach ($terms as $term) { | |
| - $options[$term->id()] = \Drupal::entityManager()->getTranslationFromContext($term)->label(); | |
| + $options[$term->id()] = \Drupal::entityManager() | |
| + ->getTranslationFromContext($term) | |
| + ->label(); | |
| } | |
| } | |
| @@ -238,7 +272,7 @@ protected function valueForm(&$form, FormStateInterface $form_state) { | |
| } | |
| $form['value'] = [ | |
| '#type' => 'select', | |
| - '#title' => $this->options['limit'] ? $this->t('Select terms from vocabulary @voc', ['@voc' => $vocabulary->label()]) : $this->t('Select terms'), | |
| + '#title' => $this->options['limit'] ? $this->t('Select terms from vocabulary @vocs', ['@vocs' => implode(', ', $vocabulary_labels)]) : $this->t('Select terms'), | |
| '#multiple' => TRUE, | |
| '#options' => $options, | |
| '#size' => min(9, count($options)), | |
| @@ -365,7 +399,9 @@ public function adminSummary() { | |
| $this->value = array_filter($this->value); | |
| $terms = Term::loadMultiple($this->value); | |
| foreach ($terms as $term) { | |
| - $this->valueOptions[$term->id()] = \Drupal::entityManager()->getTranslationFromContext($term)->label(); | |
| + $this->valueOptions[$term->id()] = \Drupal::entityManager() | |
| + ->getTranslationFromContext($term) | |
| + ->label(); | |
| } | |
| } | |
| return parent::adminSummary(); | |
| @@ -390,8 +426,10 @@ public function getCacheContexts() { | |
| public function calculateDependencies() { | |
| $dependencies = parent::calculateDependencies(); | |
| - $vocabulary = $this->vocabularyStorage->load($this->options['vid']); | |
| - $dependencies[$vocabulary->getConfigDependencyKey()][] = $vocabulary->getConfigDependencyName(); | |
| + $vocabularies = $this->vocabularyStorage->loadMultiple($this->options['vids']); | |
| + foreach ($vocabularies as $vocabulary) { | |
| + $dependencies[$vocabulary->getConfigDependencyKey()][] = $vocabulary->getConfigDependencyName(); | |
| + } | |
| foreach ($this->termStorage->loadMultiple($this->options['value']) as $term) { | |
| $dependencies[$term->getConfigDependencyKey()][] = $term->getConfigDependencyName(); | |
| diff --git a/core/modules/taxonomy/taxonomy.post_update.php b/core/modules/taxonomy/taxonomy.post_update.php | |
| index 12a5962783..e311452fc0 100644 | |
| --- a/core/modules/taxonomy/taxonomy.post_update.php | |
| +++ b/core/modules/taxonomy/taxonomy.post_update.php | |
| @@ -125,3 +125,31 @@ function taxonomy_post_update_handle_publishing_status_addition_in_views(&$sandb | |
| return TRUE; | |
| }); | |
| } | |
| + | |
| +/** | |
| + * Update views using taxonomy_index_tid to use vids instead of vid. | |
| + */ | |
| +function taxonomy_post_update_taxonomy_index_filter_multiple_vocabularies() { | |
| + // Load all views. | |
| + $views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple(); | |
| + /** @var \Drupal\views\Entity\View[] $views */ | |
| + foreach ($views as $view) { | |
| + $save = FALSE; | |
| + $displays = $view->get('display'); | |
| + foreach (array_keys($displays) as $display_id) { | |
| + $display =& $view->getDisplay($display_id); | |
| + if (!empty($display['display_options']['filters'])) { | |
| + foreach ($display['display_options']['filters'] as &$filter) { | |
| + if ($filter['plugin_id'] === 'taxonomy_index_tid' && empty($filter['vids']) && !empty($filter['vid'])) { | |
| + $filter['vids'] = [$filter['vid']]; | |
| + unset($filter['vid']); | |
| + $save = TRUE; | |
| + } | |
| + } | |
| + } | |
| + } | |
| + if ($save) { | |
| + $view->save(); | |
| + } | |
| + } | |
| +} | |
| diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml | |
| index ab5e1d8968..ed6f3585f2 100644 | |
| --- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml | |
| +++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid.yml | |
| @@ -166,7 +166,8 @@ display: | |
| reduce_duplicates: false | |
| type: select | |
| limit: true | |
| - vid: tags | |
| + vids: | |
| + - tags | |
| hierarchy: true | |
| error_message: true | |
| plugin_id: taxonomy_index_tid | |
| diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml | |
| index a5c5828c2b..0fe8db8082 100644 | |
| --- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml | |
| +++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid__non_existing_dependency.yml | |
| @@ -167,7 +167,8 @@ display: | |
| reduce_duplicates: false | |
| type: select | |
| limit: true | |
| - vid: tags | |
| + vids: | |
| + - tags | |
| hierarchy: true | |
| error_message: true | |
| plugin_id: taxonomy_index_tid | |
| diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml | |
| index 856543adc8..0ca41c930e 100644 | |
| --- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml | |
| +++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_filter_taxonomy_index_tid_depth.yml | |
| @@ -165,7 +165,8 @@ display: | |
| reduce_duplicates: false | |
| type: select | |
| limit: true | |
| - vid: views_testing_tags | |
| + vids: | |
| + - views_testing_tags | |
| hierarchy: true | |
| depth: -2 | |
| error_message: true | |
| diff --git a/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php b/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php | |
| index 8b1b822e3e..edf0c03ab8 100644 | |
| --- a/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php | |
| +++ b/core/modules/taxonomy/tests/src/Functional/Views/TaxonomyIndexTidUiTest.php | |
| @@ -24,14 +24,23 @@ class TaxonomyIndexTidUiTest extends UITestBase { | |
| * | |
| * @var array | |
| */ | |
| - public static $testViews = ['test_filter_taxonomy_index_tid', 'test_taxonomy_term_name']; | |
| + public static $testViews = [ | |
| + 'test_filter_taxonomy_index_tid', | |
| + 'test_taxonomy_term_name', | |
| + ]; | |
| /** | |
| * Modules to enable. | |
| * | |
| * @var array | |
| */ | |
| - public static $modules = ['node', 'taxonomy', 'views', 'views_ui', 'taxonomy_test_views']; | |
| + public static $modules = [ | |
| + 'node', | |
| + 'taxonomy', | |
| + 'views', | |
| + 'views_ui', | |
| + 'taxonomy_test_views', | |
| + ]; | |
| /** | |
| * A nested array of \Drupal\taxonomy\TermInterface objects. | |
| @@ -46,13 +55,30 @@ class TaxonomyIndexTidUiTest extends UITestBase { | |
| protected function setUp($import_test_views = TRUE) { | |
| parent::setUp($import_test_views); | |
| - $this->adminUser = $this->drupalCreateUser(['administer taxonomy', 'administer views']); | |
| + $this->adminUser = $this->drupalCreateUser([ | |
| + 'administer taxonomy', | |
| + 'administer views', | |
| + ]); | |
| $this->drupalLogin($this->adminUser); | |
| + $this->terms = $this->createVocabularyAndTerms('tags'); | |
| + ViewTestData::createTestViews(get_class($this), ['taxonomy_test_views']); | |
| + | |
| Vocabulary::create([ | |
| - 'vid' => 'tags', | |
| - 'name' => 'Tags', | |
| + 'vid' => 'empty_vocabulary', | |
| + 'name' => 'Empty Vocabulary', | |
| ])->save(); | |
| + } | |
| + | |
| + /** | |
| + * Creates a vocabulary and terms for it. | |
| + * | |
| + * @param string $vocab_id | |
| + * The vocabulary ID. | |
| + * | |
| + * @return \Drupal\taxonomy\TermInterface[][] | |
| + */ | |
| + protected function createVocabularyAndTerms($vocab_id) { | |
| // Setup a hierarchy which looks like this: | |
| // term 0.0 | |
| @@ -61,22 +87,18 @@ protected function setUp($import_test_views = TRUE) { | |
| // term 2.0 | |
| // - term 2.1 | |
| // - term 2.2 | |
| + $terms = []; | |
| for ($i = 0; $i < 3; $i++) { | |
| for ($j = 0; $j <= $i; $j++) { | |
| - $this->terms[$i][$j] = $term = Term::create([ | |
| - 'vid' => 'tags', | |
| + $terms[$i][$j] = $term = Term::create([ | |
| + 'vid' => $vocab_id, | |
| 'name' => "Term $i.$j", | |
| 'parent' => isset($terms[$i][0]) ? $terms[$i][0]->id() : 0, | |
| ]); | |
| $term->save(); | |
| } | |
| } | |
| - ViewTestData::createTestViews(get_class($this), ['taxonomy_test_views']); | |
| - | |
| - Vocabulary::create([ | |
| - 'vid' => 'empty_vocabulary', | |
| - 'name' => 'Empty Vocabulary', | |
| - ])->save(); | |
| + return $terms; | |
| } | |
| /** | |
| @@ -126,6 +148,75 @@ public function testFilterUI() { | |
| $this->assertIdentical($expected, $view->calculateDependencies()->getDependencies()); | |
| } | |
| + public function testFilterUIWithMoreVocabularies() { | |
| + $terms2 = $this->createVocabularyAndTerms('tags2'); | |
| + $node_type = $this->drupalCreateContentType(['type' => 'page']); | |
| + // Create the tag field itself. | |
| + $field_name = 'taxonomy_tags'; | |
| + $this->createEntityReferenceField('node', $node_type->id(), $field_name, NULL, 'taxonomy_term'); | |
| + $node0 = $this->drupalCreateNode([ | |
| + 'type' => 'page', | |
| + 'taxonomy_tags' => $this->terms[0][0]->id(), | |
| + ]); | |
| + $node0->save(); | |
| + $node1 = $this->drupalCreateNode([ | |
| + 'type' => 'page', | |
| + 'taxonomy_tags' => $terms2[0][0]->id(), | |
| + ]); | |
| + $node1->save(); | |
| + $node2 = $this->drupalCreateNode([ | |
| + 'type' => 'page', | |
| + 'taxonomy_tags' => [$this->terms[0][0]->id(), $terms2[0][0]->id()], | |
| + ]); | |
| + $node2->save(); | |
| + $edit = [ | |
| + 'options[vids][tags]' => TRUE, | |
| + 'options[vids][tags2]' => TRUE, | |
| + 'options[type]' => 'textfield', | |
| + ]; | |
| + $this->drupalPostForm('admin/structure/views/nojs/handler-extra/test_filter_taxonomy_index_tid/default/filter/tid', $edit, 'Apply'); | |
| + $this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_taxonomy_index_tid/default/filter/tid', [], 'Expose filter'); | |
| + $edit = [ | |
| + 'options[operator]' => 'and', | |
| + 'options[value]' => '', | |
| + 'options[reduce_duplicates]' => TRUE | |
| + ]; | |
| + $this->drupalPostForm(NULL, $edit, 'Apply'); | |
| + $this->drupalPostForm(NULL, [], 'Save'); | |
| + $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => '']]); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a'); | |
| + $this->assertIdentical(3, count($xpath)); | |
| + $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => "t1 ({$this->terms[0][0]->id()})"]]); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a'); | |
| + $this->assertIdentical(2, count($xpath)); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [ | |
| + ':href' => $node0->toUrl()->toString() | |
| + ]); | |
| + $this->assertIdentical(1, count($xpath)); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [ | |
| + ':href' => $node2->toUrl()->toString() | |
| + ]); | |
| + $this->assertIdentical(1, count($xpath)); | |
| + $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => "t2 ({$terms2[0][0]->id()})"]]); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a'); | |
| + $this->assertIdentical(2, count($xpath)); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [ | |
| + ':href' => $node1->toUrl()->toString() | |
| + ]); | |
| + $this->assertIdentical(1, count($xpath)); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [ | |
| + ':href' => $node2->toUrl()->toString() | |
| + ]); | |
| + $this->assertIdentical(1, count($xpath)); | |
| + $this->drupalGet('test-filter-taxonomy-index-tid', ['query' => ['tid' => "t1 ({$this->terms[0][0]->id()}), t2 ({$terms2[0][0]->id()})"]]); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a'); | |
| + $this->assertIdentical(1, count($xpath)); | |
| + $xpath = $this->xpath('//div[@class="view-content"]//a[@href=:href]', [ | |
| + ':href' => $node2->toUrl()->toString() | |
| + ]); | |
| + $this->assertIdentical(1, count($xpath)); | |
| + } | |
| + | |
| /** | |
| * Tests exposed taxonomy filters. | |
| */ | |
| diff --git a/core/modules/views/views.module b/core/modules/views/views.module | |
| index b82f36d4a5..09a5bc594f 100644 | |
| --- a/core/modules/views/views.module | |
| +++ b/core/modules/views/views.module | |
| @@ -29,7 +29,9 @@ function views_help($route_name, RouteMatchInterface $route_match) { | |
| $output .= '<h3>' . t('About') . '</h3>'; | |
| $output .= '<p>' . t('The Views module provides a back end to fetch information from content, user accounts, taxonomy terms, and other entities from the database and present it to the user as a grid, HTML list, table, unformatted list, etc. The resulting displays are known generally as <em>views</em>.') . '</p>'; | |
| $output .= '<p>' . t('For more information, see the <a href=":views">online documentation for the Views module</a>.', [':views' => 'https://www.drupal.org/documentation/modules/views']) . '</p>'; | |
| - $output .= '<p>' . t('In order to create and modify your own views using the administration and configuration user interface, you will need to enable either the Views UI module in core or a contributed module that provides a user interface for Views. See the <a href=":views-ui">Views UI module help page</a> for more information.', [':views-ui' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('help.page', ['name' => 'views_ui']) : '#']) . '</p>'; | |
| + $output .= '<p>' . t('In order to create and modify your own views using the administration and configuration user interface, you will need to enable either the Views UI module in core or a contributed module that provides a user interface for Views. See the <a href=":views-ui">Views UI module help page</a> for more information.', [ | |
| + ':views-ui' => (\Drupal::moduleHandler()->moduleExists('views_ui')) ? \Drupal::url('help.page', ['name' => 'views_ui']) : '#' | |
| + ]) . '</p>'; | |
| $output .= '<h3>' . t('Uses') . '</h3>'; | |
| $output .= '<dl>'; | |
| $output .= '<dt>' . t('Adding functionality to administrative pages') . '</dt>'; | |
| @@ -91,7 +93,12 @@ function views_theme($existing, $type, $theme, $path) { | |
| // Our extra version of pager from pager.inc | |
| $hooks['views_mini_pager'] = $base + [ | |
| - 'variables' => ['tags' => [], 'quantity' => 9, 'element' => 0, 'parameters' => []], | |
| + 'variables' => [ | |
| + 'tags' => [], | |
| + 'quantity' => 9, | |
| + 'element' => 0, | |
| + 'parameters' => [], | |
| + ], | |
| ]; | |
| $variables = [ | |
| @@ -113,8 +120,18 @@ function views_theme($existing, $type, $theme, $path) { | |
| 'attachment_before' => [], | |
| 'attachment_after' => [], | |
| ], | |
| - 'style' => ['view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL], | |
| - 'row' => ['view' => NULL, 'options' => NULL, 'row' => NULL, 'field_alias' => NULL], | |
| + 'style' => [ | |
| + 'view' => NULL, | |
| + 'options' => NULL, | |
| + 'rows' => NULL, | |
| + 'title' => NULL, | |
| + ], | |
| + 'row' => [ | |
| + 'view' => NULL, | |
| + 'options' => NULL, | |
| + 'row' => NULL, | |
| + 'field_alias' => NULL, | |
| + ], | |
| 'exposed_form' => ['view' => NULL, 'options' => NULL], | |
| 'pager' => [ | |
| 'view' => NULL, | |
| @@ -131,7 +148,13 @@ function views_theme($existing, $type, $theme, $path) { | |
| 'variables' => ['view' => NULL, 'field' => NULL, 'row' => NULL], | |
| ]; | |
| $hooks['views_view_grouping'] = $base + [ | |
| - 'variables' => ['view' => NULL, 'grouping' => NULL, 'grouping_level' => NULL, 'rows' => NULL, 'title' => NULL], | |
| + 'variables' => [ | |
| + 'view' => NULL, | |
| + 'grouping' => NULL, | |
| + 'grouping_level' => NULL, | |
| + 'rows' => NULL, | |
| + 'title' => NULL, | |
| + ], | |
| ]; | |
| // Only display, pager, row, and style plugins can provide theme hooks. | |
| @@ -241,9 +264,10 @@ function views_preprocess_node(&$variables) { | |
| // If a node is being rendered in a view, and the view does not have a path, | |
| // prevent drupal from accidentally setting the $page variable: | |
| if (!empty($variables['view']->current_display) | |
| - && $variables['page'] | |
| - && $variables['view_mode'] == 'full' | |
| - && !$variables['view']->display_handler->hasPath()) { | |
| + && $variables['page'] | |
| + && $variables['view_mode'] == 'full' | |
| + && !$variables['view']->display_handler->hasPath() | |
| + ) { | |
| $variables['page'] = FALSE; | |
| } | |
| } | |
| @@ -872,6 +896,23 @@ function views_view_presave(ViewEntityInterface $view) { | |
| $displays = $view->get('display'); | |
| $changed = FALSE; | |
| foreach ($displays as $display_name => &$display) { | |
| + if (isset($display['display_options']['filters'])) { | |
| + foreach ($display['display_options']['filters'] as $filter_name => $filter) { | |
| + if (isset($filter['plugin_id']) && $filter['plugin_id'] === 'boolean') { | |
| + $new_value = FALSE; | |
| + // Update all boolean and integer values to strings. | |
| + if ($filter['value'] === TRUE || $filter['value'] === 1) { | |
| + $new_value = '1'; | |
| + } | |
| + elseif ($filter['value'] === FALSE || $filter['value'] === 0) { | |
| + $new_value = '0'; | |
| + } | |
| + if ($new_value !== FALSE) { | |
| + $view->set("display.$display_name.display_options.filters.$filter_name.value", $new_value); | |
| + } | |
| + } | |
| + } | |
| + } | |
| if (isset($display['display_options']['fields'])) { | |
| foreach ($display['display_options']['fields'] as $field_name => &$field) { | |
| if (isset($field['plugin_id']) && $field['plugin_id'] === 'entity_link') { | |
| diff --git a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php | |
| index 8e71123389..ff7f53ce6b 100644 | |
| --- a/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php | |
| +++ b/core/modules/views_ui/src/Form/Ajax/ConfigHandlerExtra.php | |
| @@ -95,6 +95,10 @@ public function buildForm(array $form, FormStateInterface $form_state) { | |
| */ | |
| public function validateForm(array &$form, FormStateInterface $form_state) { | |
| $form_state->get('handler')->validateExtraOptionsForm($form['options'], $form_state); | |
| + | |
| + if ($form_state->getErrors()) { | |
| + $form_state->set('rerender', TRUE); | |
| + } | |
| } | |
| /** |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment