Розробка користувальницьких Views Drupal
Views — найпотужніший інструмент у Drupal для відображення списків контенту. Фільтри, сортування, пов'язані сущності, різні формати виведення, ajax-пагінація, exposed filters — все налаштовується без коду. Користувальницький код потрібен там, де UI не достатньо: користувальницькі фільтри, користувальницькі форматери полів, програмна маніпуляція з query.
Створення View через UI
Шлях: /admin/structure/views/add. Основні параметри:
- View name — машинне імя, використовується в коді
- Show — тип сущності (Content, Users, Taxonomy terms...)
- Tagged with — фільтр по тегу при створенні
- Display — Page (URL), Block, REST Export, Feed, Attachment
Конфігурація View в YAML
Після налаштування в UI експортуємо:
drush config:export
# створюється views.view.{machine_name}.yml
Фрагмент конфігурації складного View:
# views.view.news_list.yml
id: news_list
label: 'Список новостей'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
display:
default:
display_options:
fields:
title:
id: title
table: node_field_data
field: title
entity_type: node
link_to_entity: true
label: ''
element_label_colon: false
field_image:
id: field_image
table: node__field_image
field: field_image
image_style: news_teaser
image_link: content
created:
id: created
date_format: custom
custom_date_format: 'd.m.Y'
filters:
status:
value: '1'
table: node_field_data
field: status
type:
value: { news: news }
table: node_field_data
field: type
field_category_target_id:
id: field_category_target_id
exposed: true
expose:
label: 'Категорія'
identifier: category
sorts:
created:
order: DESC
pager:
type: full
options:
items_per_page: 12
style:
type: html_list
row:
type: 'fields'
use_ajax: true
page_1:
display_plugin: page
path: /news
display_options:
menu:
type: normal
title: Новини
Exposed Filters (фільтри для користувача)
Exposed filters рендеряться як форма — користувач може фільтрувати список без перезавантаження (з AJAX) або з перезавантаженням. Налаштовуються в UI для кожного фільтра галочкою «Expose this filter to visitors».
Користувальницький обробник exposed filter через hook_views_query_alter:
// my_module.module
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;
/**
* Implements hook_views_query_alter().
*/
function my_module_views_query_alter(ViewExecutable $view, QueryPluginBase $query): void {
if ($view->id() !== 'news_list') return;
// Додаємо додаткову умову на основі GET-параметра
$price_from = \Drupal::request()->query->get('price_from');
if ($price_from && is_numeric($price_from)) {
$query->addWhereExpression(
0,
"node__field_price.field_price_value >= :price_from",
[':price_from' => (float) $price_from]
);
}
}
Користувальницький плагін стилю рядка
Стандартні стилі: Fields, Entity, HTML list, Table. Для користувальницького рендера — плагін:
// src/Plugin/views/row/ArticleCardRow.php
namespace Drupal\my_module\Plugin\views\row;
use Drupal\views\Plugin\views\row\RowPluginBase;
use Drupal\views\ResultRow;
/**
* @ViewsRow(
* id = "article_card",
* title = @Translation("Карточка статті"),
* help = @Translation("Рендерить статті як карточки"),
* display_types = {"normal"},
* )
*/
class ArticleCardRow extends RowPluginBase {
public function render(ResultRow $row): array {
$node = $row->_entity;
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
return [
'#theme' => 'article_card',
'#node' => $node,
'#title' => $node->getTitle(),
'#image' => $node->hasField('field_image')
? $view_builder->viewField($node->get('field_image'), 'card')
: NULL,
'#url' => $node->toUrl()->toString(),
'#cache' => [
'tags' => $node->getCacheTags(),
'contexts' => ['user.roles'],
],
];
}
}
Програмне використання Views
use Drupal\views\Views;
// Отримати View програмно і виконати
$view = Views::getView('news_list');
$view->setDisplay('block_1');
$view->setArguments([42]); // contextual filter аргументи
$view->setExposedInput(['category' => 'tech']);
$view->execute();
// Отримати результати
$results = $view->result;
foreach ($results as $row) {
$node = $row->_entity;
// ...
}
// Рендер блока View
$view->preExecute();
$view->execute();
$rendered = $view->buildRenderable('block_1');
Views та користувальницькі таблиці
Якщо потрібно показувати дані з користувальницької таблиці БД, реєструємо її для Views:
// my_module.views.inc
/**
* Implements hook_views_data().
*/
function my_module_views_data(): array {
$data = [];
$data['my_module_stats']['table']['group'] = t('My Module');
$data['my_module_stats']['table']['base'] = [
'field' => 'id',
'title' => t('My Module Stats'),
'help' => t('Statistics data from my module'),
];
$data['my_module_stats']['node_id'] = [
'title' => t('Node ID'),
'help' => t('Related node'),
'relationship' => [
'base' => 'node_field_data',
'base field' => 'nid',
'id' => 'standard',
'label' => t('Node'),
],
'filter' => ['id' => 'numeric'],
'sort' => ['id' => 'standard'],
'field' => ['id' => 'numeric'],
];
$data['my_module_stats']['view_count'] = [
'title' => t('View count'),
'field' => ['id' => 'numeric'],
'filter' => ['id' => 'numeric'],
'sort' => ['id' => 'standard'],
];
return $data;
}
REST Export Display
Views умеють експортувати дані в JSON через REST Export display:
/api/news.json?page=0&items_per_page=20&category=tech
Налаштовується в UI або YAML. Заголовки CORS налаштовуються в services.yml:
# web/sites/default/services.yml
cors.config:
enabled: true
allowedHeaders: ['*']
allowedMethods: []
allowedOrigins: ['https://frontend.example.com']
exposedHeaders: false
maxAge: false
supportsCredentials: false
Терміни
Простий View з exposed filters через UI + експорт конфігурації: полдня. Користувальницький плагін (row, filter, sort), користувальницька таблиця даних, REST export: 2–3 дні.







