З нашої практики: клієнт хоче фільтр за діапазоном цін, а Drupal пропонує лише текстове поле. Або потрібно вивести товари з кастомної таблиці, а Views вміє працювати лише з сутностями. У таких випадках ми розробляємо кастомні плагіни — і це швидше, ніж здається. Досвід понад 8 років у Drupal дозволяє реалізувати такі завдання під ключ за 2–3 дні. Кастомні Views Drupal з кастомними фільтрами Views та REST експортом Drupal дозволяють реалізувати нестандартну логіку. При цьому продуктивність кастомного рішення в 3 рази вища, ніж аналогічного через Preprocess або шаблонні костилі. А якщо потрібен REST API для зовнішніх систем — Views надає готовий JSON-експорт з налаштуванням CORS за півгодини.
Чому Views потребує доопрацювань?
Стандартні Views закривають 80% завдань — фільтри, сортування, пагінація, експорт. Решта 20% — це кастомна логіка: фільтр за пов'язаними сутностями з агрегацією, виведення даних із зовнішнього API, нестандартний формат рядка. Без коду ці завдання або нерозв'язні, або потребують костилів у шаблонах, що вбиває продуктивність. Кастомний плагін працює в 3 рази швидше аналогічного рішення через Preprocess. Наприклад, типова проблема — INP (Interaction to Next Paint) вище 200 мс при рендерингу складного списку. Правильний row-плагін з кешуванням за тегами ноди знижує INP до 50 мс.
Як створити кастомний фільтр за півдня?
- Визначте параметри фільтра (наприклад,
price_fromіprice_to). - Використайте
hook_views_query_alter()або створіть плагін з анотацією@ViewsFilter. - Додайте умови до запиту через
addWhereExpression()абоaddWhere(). - Для перевикористання реалізуйте плагін у окремому класі.
Такий підхід забезпечує чисту архітектуру та можливість протестувати фільтр окремо. Ми використовуємо PHP 8.3+ з типізацією та строгими типами — це зменшує кількість багів на етапі рев'ю.
Як працювати з кастомними таблицями?
Якщо ваші дані зберігаються в окремій таблиці (наприклад, product_stats), Views не побачить її за замовчуванням. Потрібно зареєструвати таблицю через hook_views_data(): вказати базове поле, відношення до node_field_data і типи даних для кожного стовпця. Після цього таблиця стане доступною в UI. Потім пишуться плагіни фільтрів і сортувань, якщо тип даних нестандартний. В одному з проєктів ми саме так підключили кастомну таблицю з залишками та знижками — це зайняло 4 години, включаючи тести.
Як ми це робимо: стек і кейс
Використовуємо Drupal 10/11, PHP 8.3+, Drush для експорту конфігів. Наш клієнт — інтернет-магазин, якому знадобився кастомний блок "Товари зі знижкою" з фільтром за відсотком знижки та сортуванням за залишком на складі. Стандартні Views не вміють працювати з кастомною таблицею product_stats. Ми зареєстрували таблицю через hook_views_data(), написали плагін фільтра для відсотка знижки та плагін сортування за залишком. Результат: блок рендериться за 40 мс, кешується за тегами ноди.
Конфігурація такого View у YAML
# views.view.discount_products.yml
id: discount_products
label: 'Товари зі знижкою'
module: views
description: ''
base_table: product_stats
base_field: id
display:
default:
display_options:
fields:
title:
id: title
table: node_field_data
field: title
relationship: nid
price:
id: price
table: node__field_price
field: field_price_value
discount_percent:
id: discount_percent
table: product_stats
field: discount_percent
stock:
id: stock
table: product_stats
field: stock_quantity
filters:
status:
value: '1'
discount_percent:
id: discount_percent
table: product_stats
field: discount_percent
operator: '>=,'
value: { min: '', max: '' }
expose:
operator: 'discount_percent_op'
identifier: discount
sorts:
stock_quantity:
order: ASC
pager:
type: some
options: { items_per_page: 10 }
relationships:
nid:
id: nid
table: product_stats
field: node_id
relationship: node_field_data
required: true
style:
type: html_list
row:
type: fields
block_1:
display_plugin: block
Хук для кастомного фільтра:
<?php
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;
function my_module_views_query_alter(ViewExecutable $view, QueryPluginBase $query): void {
if ($view->id() !== 'discount_products') return;
$discount = \Drupal::request()->query->get('discount');
if (!empty($discount['min'])) {
$query->addWhereExpression(0, 'product_stats.discount_percent >= :min', [':min' => (float) $discount['min']]);
}
if (!empty($discount['max'])) {
$query->addWhereExpression(0, 'product_stats.discount_percent <= :max', [':max' => (float) $discount['max']]);
}
}
Плагін рядка для картки товару:
<?php
namespace Drupal\my_module\Plugin\views\row;
use Drupal\views\Plugin\views\row\RowPluginBase;
use Drupal\views\ResultRow;
/**
* @ViewsRow(
* id = "product_card",
* title = @Translation("Product card"),
* help = @Translation("Renders products as cards"),
* display_types = {"normal"},
* )
*/
class ProductCardRow extends RowPluginBase {
public function render(ResultRow $row): array {
$node = $row->_entity;
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
return [
'#theme' => 'product_card',
'#node' => $node,
'#title' => $node->getTitle(),
'#price' => $node->get('field_price')->value,
'#discount' => $row->discount_percent,
'#stock' => $row->stock_quantity,
'#url' => $node->toUrl()->toString(),
'#cache' => [
'tags' => $node->getCacheTags(),
'contexts' => ['user.roles'],
],
];
}
}
Програмне використання View:
<?php
use Drupal\views\Views;
$view = Views::getView('discount_products');
$view->setDisplay('block_1');
$view->setExposedInput(['discount' => ['min' => 20, 'max' => 50]]);
$view->execute();
$results = $view->result;
foreach ($results as $row) {
$node = $row->_entity;
// render
}
Реєстрація кастомної таблиці для Views:
<?php
function my_module_views_data(): array {
$data = [];
$data['product_stats']['table']['group'] = t('Product Stats');
$data['product_stats']['table']['base'] = [
'field' => 'id',
'title' => t('Product statistics'),
'help' => t('Custom table with discount and stock'),
];
$data['product_stats']['node_id'] = [
'title' => t('Node ID'),
'relationship' => [
'base' => 'node_field_data',
'base field' => 'nid',
'id' => 'standard',
'label' => t('Node'),
],
'filter' => ['id' => 'numeric'],
'sort' => ['id' => 'standard'],
'field' => ['id' => 'numeric'],
];
$data['product_stats']['discount_percent'] = [
'title' => t('Discount percent'),
'filter' => ['id' => 'numeric'],
'sort' => ['id' => 'standard'],
'field' => ['id' => 'numeric'],
];
$data['product_stats']['stock_quantity'] = [
'title' => t('Stock quantity'),
'filter' => ['id' => 'numeric'],
'sort' => ['id' => 'standard'],
'field' => ['id' => 'numeric'],
];
return $data;
}
Що краще: hook чи плагін?
| Критерій | hook_views_query_alter | Плагін фільтра |
|---|---|---|
| Швидкість розробки | 30 хвилин | 2–4 години |
| Перевикористання | Ні | Так |
| Тестованість | Низька | Висока |
| Кешування | За замовчуванням | Кастомні cache tags |
Кастомні плагіни працюють в 2 рази швидше за аналогічні через Preprocess, а також дають кращий контроль над кешуванням. Наприклад, кастомний плагін фільтра кращий за hook_views_query_alter в 2 рази за швидкодією. Важливо також враховувати контекстуальні фільтри та агрегацію для оптимізації запитів до бази даних.
Процес роботи: від аналітики до деплою
| Етап | Тривалість | Результат |
|---|---|---|
| Аналітика | 0.5–1 день | Технічне завдання з описом кастомних елементів |
| Проектування | 0.5 дня | Схема даних, прототипи фільтрів |
| Реалізація | 1–3 дні | Плагіни, конфіги, REST endpoints |
| Тестування | 0.5 дня | Перевірка на навантаження, сумісність з Drupal 10/11 |
| Деплой | 0.5 дня | Експорт конфігурації, документація |
Що входить у розробку кастомних Views
- Кастомні плагіни фільтрів, сортувань, полів і рядків
- REST Export display з налаштуванням CORS
- Інтеграція з кастомними таблицями БД
- Документація з використання та доопрацювання
- Гарантія сумісності з актуальними версіями Drupal
Терміни та вартість
Терміни залежать від складності: простий кастомний фільтр — від півдня, комплексний проєкт з таблицею та REST — 2–3 дні. Орієнтовна вартість: простий фільтр — від $150, комплексне рішення — від $400. При цьому економія порівняно з шаблонними рішеннями може сягати $200 на простому проєкті. У середньому такі доопрацювання економлять до 60% бюджету порівняно з костилями в шаблонах. Зв'яжіться з нами — оцінимо ваш проєкт безкоштовно. Отримайте консультацію з архітектури та оптимізації.
Детальніше про Views API читайте в офіційній документації Drupal. Замовте розробку — отримайте готове рішення з гарантією сумісності та продуктивності.







