Programmatic modification
18. Programmatic View Modification
When to Use
When config-based approach isn't sufficient: runtime view modification, dynamic filter injection, custom display logic.
Philosophy: Config-first is preferred. Only use programmatic modification when config can't solve the problem.
Loading Views
Load View Config Entity
$view = \Drupal\views\Entity\View::load('my_view');
// Returns ViewEntityInterface (config entity)
// Use for: reading config, checking existence, deleting
Load Executable View
$view = \Drupal::service('views.executable')->get('my_view');
// Returns ViewExecutable
// Use for: executing, altering, rendering
Reference: core/modules/views/src/Entity/View.php lines 123-130
Executing Views Programmatically
Basic Execution
$view = \Drupal\views\Views::getView('my_view');
$view->setDisplay('page_1');
$view->execute();
$results = $view->result;
Rendering View
$view = \Drupal\views\Views::getView('my_view');
$view->setDisplay('block_1');
$view->setArguments([123]); // Contextual filter values
$render_array = $view->render();
With Filters
$view = \Drupal\views\Views::getView('my_view');
$view->setDisplay('default');
$view->setExposedInput(['type' => 'article']);
$view->execute();
Altering Views with Hooks
hook_views_pre_view()
Runs before view execution.
/**
* Implements hook_views_pre_view().
*/
function mymodule_views_pre_view(\Drupal\views\ViewExecutable $view, $display_id, array &$args) {
if ($view->id() == 'my_view' && $display_id == 'page_1') {
// Modify view before execution
$view->setItemsPerPage(20);
}
}
hook_views_pre_render()
Runs after query execution, before rendering.
/**
* Implements hook_views_pre_render().
*/
function mymodule_views_pre_render(\Drupal\views\ViewExecutable $view) {
if ($view->id() == 'my_view') {
// Modify results before rendering
foreach ($view->result as $row) {
// Manipulate row data
}
}
}
hook_views_post_render()
Runs after rendering.
/**
* Implements hook_views_post_render().
*/
function mymodule_views_post_render(\Drupal\views\ViewExecutable $view, &$output, \Drupal\views\Plugin\views\cache\CachePluginBase $cache) {
if ($view->id() == 'my_view') {
// Modify render array
$output['#suffix'] = '<div class="custom-footer">Footer text</div>';
}
}
Creating Views Programmatically
Create View Entity
$view = \Drupal\views\Entity\View::create([
'id' => 'my_custom_view',
'label' => 'My Custom View',
'module' => 'mymodule',
'base_table' => 'node_field_data',
'base_field' => 'nid',
'display' => [
'default' => [
'display_plugin' => 'default',
'id' => 'default',
'display_title' => 'Default',
'position' => 0,
'display_options' => [],
],
],
]);
$view->save();
Reference: core/modules/views/src/Entity/View.php lines 374-390
Pattern: Dynamic Contextual Filter
function mymodule_views_pre_view(\Drupal\views\ViewExecutable $view, $display_id, array &$args) {
if ($view->id() == 'related_content') {
// Inject current node ID as argument
$node = \Drupal::routeMatch()->getParameter('node');
if ($node) {
$args[0] = $node->id();
}
}
}
Common Mistakes
- Creating views programmatically instead of using config → Config is exportable, versionable; code is not
- Not checking view existence before loading →
Views::getView()returns NULL if view doesn't exist; always check - Modifying view in wrong hook →
hook_views_pre_view()for query changes,hook_views_pre_render()for result changes,hook_views_post_render()for output changes - Forgetting to set display →
setDisplay()required beforeexecute()orrender() - Not calling
execute()before accessing results →$view->resultis empty untilexecute()runs
See Also
- Section 17: Views Config Export & Recipes — config-first approach
- Section 10: Sort & Contextual Filters — argument configuration
- Reference: ViewExecutable API