3 namespace Drupal\ctools_views\Plugin\Display;
5 use Drupal\Core\Form\FormState;
6 use Drupal\Core\Form\FormStateInterface;
7 use Drupal\views\Plugin\Block\ViewsBlock;
8 use Drupal\views\Plugin\views\display\Block as CoreBlock;
9 use Drupal\views\Plugin\views\filter\InOperator;
12 * Provides a Block display plugin that allows for greater control over Views
15 class Block extends CoreBlock {
20 public function optionsSummary(&$categories, &$options) {
21 parent::optionsSummary($categories, $options);
22 $filtered_allow = array_filter($this->getOption('allow'));
24 'items_per_page' => $this->t('Items per page'),
25 'offset' => $this->t('Pager offset'),
26 'pager' => $this->t('Pager type'),
27 'hide_fields' => $this->t('Hide fields'),
28 'sort_fields' => $this->t('Reorder fields'),
29 'disable_filters' => $this->t('Disable filters'),
30 'configure_sorts' => $this->t('Configure sorts')
32 $filter_intersect = array_intersect_key($filter_options, $filtered_allow);
34 $options['allow'] = array(
35 'category' => 'block',
36 'title' => $this->t('Allow settings'),
37 'value' => empty($filtered_allow) ? $this->t('None') : implode(', ', $filter_intersect),
44 public function buildOptionsForm(&$form, FormStateInterface $form_state) {
45 parent::buildOptionsForm($form, $form_state);
46 $options = $form['allow']['#options'];
47 $options['offset'] = $this->t('Pager offset');
48 $options['pager'] = $this->t('Pager type');
49 $options['hide_fields'] = $this->t('Hide fields');
50 $options['sort_fields'] = $this->t('Reorder fields');
51 $options['disable_filters'] = $this->t('Disable filters');
52 $options['configure_sorts'] = $this->t('Configure sorts');
53 $form['allow']['#options'] = $options;
54 // Update the items_per_page if set.
55 $defaults = array_filter($form['allow']['#default_value']);
56 if (isset($defaults['items_per_page'])) {
57 $defaults['items_per_page'] = 'items_per_page';
59 $form['allow']['#default_value'] = $defaults;
65 public function blockForm(ViewsBlock $block, array &$form, FormStateInterface $form_state) {
66 $form = parent::blockForm($block, $form, $form_state);
68 $allow_settings = array_filter($this->getOption('allow'));
69 $block_configuration = $block->getConfiguration();
71 // Modify "Items per page" block settings form.
72 if (!empty($allow_settings['items_per_page'])) {
74 $form['override']['items_per_page']['#type'] = 'number';
75 unset($form['override']['items_per_page']['#options']);
78 // Provide "Pager offset" block settings form.
79 if (!empty($allow_settings['offset'])) {
80 $form['override']['pager_offset'] = [
82 '#title' => $this->t('Pager offset'),
83 '#default_value' => isset($block_configuration['pager_offset']) ? $block_configuration['pager_offset'] : 0,
84 '#description' => $this->t('For example, set this to 3 and the first 3 items will not be displayed.'),
88 // Provide "Pager type" block settings form.
89 if (!empty($allow_settings['pager'])) {
91 'view' => $this->t('Inherit from view'),
92 'some' => $this->t('Display a specified number of items'),
93 'none' => $this->t('Display all items')
95 $form['override']['pager'] = [
97 '#title' => $this->t('Pager'),
98 '#options' => $pager_options,
99 '#default_value' => isset($block_configuration['pager']) ? $block_configuration['pager'] : 'view'
103 // Provide "Hide fields" / "Reorder fields" block settings form.
104 if (!empty($allow_settings['hide_fields']) || !empty($allow_settings['sort_fields'])) {
105 // Set up the configuration table for hiding / sorting fields.
106 $fields = $this->getHandlers('field');
108 if (!empty($allow_settings['hide_fields'])) {
109 $header['hide'] = $this->t('Hide');
111 $header['label'] = $this->t('Label');
112 if (!empty($allow_settings['sort_fields'])) {
113 $header['weight'] = $this->t('Weight');
115 $form['override']['order_fields'] = [
117 '#header' => $header,
120 if (!empty($allow_settings['sort_fields'])) {
121 $form['override']['order_fields']['#tabledrag'] = [
124 'relationship' => 'sibling',
125 'group' => 'field-weight',
128 $form['override']['order_fields']['#attributes'] = ['id' => 'order-fields'];
131 // Sort available field plugins by their currently configured weight.
133 if (!empty($allow_settings['sort_fields']) && isset($block_configuration['fields'])) {
134 uasort($block_configuration['fields'], '\Drupal\ctools_views\Plugin\Display\Block::sortFieldsByWeight');
135 foreach (array_keys($block_configuration['fields']) as $field_name) {
136 if (!empty($fields[$field_name])) {
137 $sorted_fields[$field_name] = $fields[$field_name];
138 unset($fields[$field_name]);
141 if (!empty($fields)) {
142 foreach ($fields as $field_name => $field_info) {
143 $sorted_fields[$field_name] = $field_info;
148 $sorted_fields = $fields;
151 // Add each field to the configuration table.
152 foreach ($sorted_fields as $field_name => $plugin) {
153 $field_label = $plugin->adminLabel();
154 if (!empty($plugin->options['label'])) {
155 $field_label .= ' (' . $plugin->options['label'] . ')';
157 if (!empty($allow_settings['sort_fields'])) {
158 $form['override']['order_fields'][$field_name]['#attributes']['class'][] = 'draggable';
160 $form['override']['order_fields'][$field_name]['#weight'] = !empty($block_configuration['fields'][$field_name]['weight']) ? $block_configuration['fields'][$field_name]['weight'] : '';
161 if (!empty($allow_settings['hide_fields'])) {
162 $form['override']['order_fields'][$field_name]['hide'] = [
163 '#type' => 'checkbox',
164 '#default_value' => !empty($block_configuration['fields'][$field_name]['hide']) ? $block_configuration['fields'][$field_name]['hide'] : 0,
167 $form['override']['order_fields'][$field_name]['label'] = [
168 '#markup' => $field_label,
170 if (!empty($allow_settings['sort_fields'])) {
171 $form['override']['order_fields'][$field_name]['weight'] = [
173 '#title' => $this->t('Weight for @title', ['@title' => $field_label]),
174 '#title_display' => 'invisible',
176 '#default_value' => !empty($block_configuration['fields'][$field_name]['weight']) ? $block_configuration['fields'][$field_name]['weight'] : 0,
177 '#attributes' => ['class' => ['field-weight']],
183 // Provide "Configure filters" / "Disable filters" block settings form.
184 if (!empty($allow_settings['disable_filters'])) {
186 foreach ((array) $this->getOption('filters') as $filter_name => $item) {
187 $item['value'] = isset($block_configuration["filter"][$filter_name]['value']) ? $block_configuration["filter"][$filter_name]['value'] : '';
188 $items[$filter_name] = $item;
190 $this->setOption('filters', $items);
191 $filters = $this->getHandlers('filter');
193 // Add a settings form for each exposed filter to configure or hide it.
194 foreach ($filters as $filter_name => $plugin) {
195 if ($plugin->isExposed() && $exposed_info = $plugin->exposedInfo()) {
196 $form['override']['filters'][$filter_name] = [
197 '#type' => 'details',
198 '#title' => $exposed_info['label'],
200 $form['override']['filters'][$filter_name]['plugin'] = [
204 // Render "Disable filters" settings form.
205 if (!empty($allow_settings['disable_filters'])) {
206 $form['override']['filters'][$filter_name]['disable'] = [
207 '#type' => 'checkbox',
208 '#title' => $this->t('Disable'),
209 '#default_value' => !empty($block_configuration['filter'][$filter_name]['disable']) ? $block_configuration['filter'][$filter_name]['disable'] : 0,
216 // Provide "Configure sorts" block settings form.
217 if (!empty($allow_settings['configure_sorts'])) {
218 $sorts = $this->getHandlers('sort');
220 'ASC' => $this->t('Sort ascending'),
221 'DESC' => $this->t('Sort descending'),
223 foreach ($sorts as $sort_name => $plugin) {
224 $form['override']['sort'][$sort_name] = [
225 '#type' => 'details',
226 '#title' => $plugin->adminLabel(),
228 $form['override']['sort'][$sort_name]['plugin'] = [
232 $form['override']['sort'][$sort_name]['order'] = array(
233 '#title' => $this->t('Order'),
235 '#options' => $options,
236 '#default_value' => $plugin->options['order']
239 // Set default values for sorts for this block.
240 if (!empty($block_configuration["sort"][$sort_name])) {
241 $form['override']['sort'][$sort_name]['order']['#default_value'] = $block_configuration["sort"][$sort_name];
252 public function blockSubmit(ViewsBlock $block, $form, FormStateInterface $form_state) {
253 // Set default value for items_per_page if left blank.
254 if (empty($form_state->getValue(array('override', 'items_per_page')))) {
255 $form_state->setValue(array('override', 'items_per_page'), "none");
258 parent::blockSubmit($block, $form, $form_state);
259 $configuration = $block->getConfiguration();
260 $allow_settings = array_filter($this->getOption('allow'));
262 // Save "Pager type" settings to block configuration.
263 if (!empty($allow_settings['pager'])) {
264 if ($pager = $form_state->getValue(['override', 'pager'])) {
265 $configuration['pager'] = $pager;
269 // Save "Pager offset" settings to block configuration.
270 if (!empty($allow_settings['offset'])) {
271 $configuration['pager_offset'] = $form_state->getValue(['override', 'pager_offset']);
274 // Save "Hide fields" / "Reorder fields" settings to block configuration.
275 if (!empty($allow_settings['hide_fields']) || !empty($allow_settings['sort_fields'])) {
276 if ($fields = array_filter($form_state->getValue(['override', 'order_fields']))) {
277 uasort($fields, '\Drupal\ctools_views\Plugin\Display\Block::sortFieldsByWeight');
278 $configuration['fields'] = $fields;
282 // Save "Configure filters" / "Disable filters" settings to block
284 unset($configuration['filter']);
285 if (!empty($allow_settings['disable_filters'])) {
286 if ($filters = $form_state->getValue(['override', 'filters'])) {
287 foreach ($filters as $filter_name => $filter) {
288 /** @var \Drupal\views\Plugin\views\filter\FilterPluginBase $plugin */
289 $plugin = $form_state->getValue(['override', 'filters', $filter_name, 'plugin']);
290 $configuration["filter"][$filter_name]['type'] = $plugin->getPluginId();
292 // Check if we want to disable this filter.
293 if (!empty($allow_settings['disable_filters'])) {
294 $disable = $form_state->getValue(['override', 'filters', $filter_name, 'disable']);
295 // If marked disabled, we don't really care about other stuff.
297 $configuration["filter"][$filter_name]['disable'] = $disable;
305 // Save "Configure sorts" settings to block configuration.
306 if (!empty($allow_settings['configure_sorts'])) {
307 $sorts = $form_state->getValue(['override', 'sort']);
308 foreach ($sorts as $sort_name => $sort) {
309 $plugin = $sort['plugin'];
310 // Check if we want to override the default sort order
311 if ($plugin->options['order'] != $sort['order']) {
312 $configuration['sort'][$sort_name] = $sort['order'];
317 $block->setConfiguration($configuration);
323 public function preBlockBuild(ViewsBlock $block) {
324 parent::preBlockBuild($block);
326 $allow_settings = array_filter($this->getOption('allow'));
327 $config = $block->getConfiguration();
328 list(, $display_id) = explode('-', $block->getDerivativeId(), 2);
330 // Change pager offset settings based on block configuration.
331 if (!empty($allow_settings['offset'])) {
332 $this->view->setOffset($config['pager_offset']);
335 // Change pager style settings based on block configuration.
336 if (!empty($allow_settings['pager'])) {
337 $pager = $this->view->display_handler->getOption('pager');
338 if (!empty($config['pager']) && $config['pager'] != 'view') {
339 $pager['type'] = $config['pager'];
341 $this->view->display_handler->setOption('pager', $pager);
344 // Change fields output based on block configuration.
345 if (!empty($allow_settings['hide_fields']) || !empty($allow_settings['sort_fields'])) {
346 if (!empty($config['fields']) && $this->view->getStyle()->usesFields()) {
347 $fields = $this->view->getHandlers('field');
348 uasort($config['fields'], '\Drupal\ctools_views\Plugin\Display\Block::sortFieldsByWeight');
349 $iterate_fields = !empty($allow_settings['sort_fields']) ? $config['fields'] : $fields;
350 foreach (array_keys($iterate_fields) as $field_name) {
351 // Remove each field in sequence and re-add them to sort
352 // appropriately or hide if disabled.
353 $this->view->removeHandler($display_id, 'field', $field_name);
354 if (empty($allow_settings['hide_fields']) || (!empty($allow_settings['hide_fields']) && empty($config['fields'][$field_name]['hide']))) {
355 $this->view->addHandler($display_id, 'field', $fields[$field_name]['table'], $fields[$field_name]['field'], $fields[$field_name], $field_name);
361 // Change filters output based on block configuration.
362 if (!empty($allow_settings['disable_filters'])) {
363 $filters = $this->view->getHandlers('filter', $display_id);
364 foreach ($filters as $filter_name => $filter) {
365 // If we allow disabled filters and this filter is disabled, disable it
367 if (!empty($allow_settings['disable_filters']) && !empty($config["filter"][$filter_name]['disable'])) {
368 $this->view->removeHandler($display_id, 'filter', $filter_name);
374 // Change sorts based on block configuration.
375 if (!empty($allow_settings['configure_sorts'])) {
376 $sorts = $this->view->getHandlers('sort', $display_id);
377 foreach ($sorts as $sort_name => $sort) {
378 if (!empty($config["sort"][$sort_name])) {
379 $sort['order'] = $config["sort"][$sort_name];
380 $this->view->setHandler($display_id, 'sort', $sort_name, $sort);
386 protected function getFilterOptionsValue(array $filter, array $config) {
387 $plugin_definition = \Drupal::service('plugin.manager.views.filter')->getDefinition($config['type']);
388 if (is_subclass_of($plugin_definition['class'], '\Drupal\views\Plugin\views\filter\InOperator')) {
389 return array_values($config['value']);
391 return $config['value'][$filter['expose']['identifier']];
397 public function usesExposed() {
398 $filters = $this->getHandlers('filter');
399 foreach ($filters as $filter_name => $filter) {
400 if ($filter->isExposed() && !empty($filter->exposedInfo())) {
408 * Exposed widgets typically only work with ajax in Drupal core, however
409 * #2605218 totally breaks the rest of the functionality in this display and
410 * in Core's Block display as well, so we allow non-ajax block views to use
411 * exposed filters and manually set the #action to the current request uri.
413 public function elementPreRender(array $element) {
414 /** @var \Drupal\views\ViewExecutable $view */
415 $view = $element['#view'];
416 if (!empty($view->exposed_widgets['#action']) && !$view->ajaxEnabled()) {
417 $view->exposed_widgets['#action'] = \Drupal::request()->getRequestUri();
419 return parent::elementPreRender($element);
423 * Sort field config array by weight.
429 public static function sortFieldsByWeight($a, $b) {
430 $a_weight = isset($a['weight']) ? $a['weight'] : 0;
431 $b_weight = isset($b['weight']) ? $b['weight'] : 0;
432 if ($a_weight == $b_weight) {
435 return ($a_weight < $b_weight) ? -1 : 1;