How to create a Custom Views Pseudo Field on Drupal
Auteur(s) de l'article

hook_views_data().Instead, they allow the data to be preprocessed at render time.
This could mean performing a calculation, combining multiple fields into one, loading related entity data or anything else you can express in Drupal.
- First, you use
hook_views_data_alter(orhook_views_data) to register your pseudo field against a base table — telling Views “this field exists and here is its plugin ID”. - Second, you provide the corresponding Views field plugin class that implements the actual logic.
The code
The examples use the module machine name my_module. Replace this with your own module's machine name throughout.
For this article, I will build a pseudo field that displays a node’s title in its original source language. The standard Views Title field renders in the currently active interface language, which means translated nodes and their source all look identical in the listing. A dedicated Title (original language) column solves that instantly.
Step 1 — Register the Pseudo Field
The code targets Drupal 11. It uses Object-Oriented Hooks, a modern way to implement Drupal hooks introduced recently and replacing procedural functions Class.
Views discovers available fields by scanning the data registered through hook_views_data and hook_views_data_alter. We use the alter variant here because we want to attach our pseudo field to an existing base table — node_field_data — that is already registered by Drupal core.
The field.id key in the registration array is the plugin ID of our Views field plugin. We will create that plugin in the next step.
<?php
namespace Drupal\my_module\Hook;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Hook Views Data implementations.
*/
#[Hook('views_data_alter')]
final class ViewsData {
use StringTranslationTrait;
/**
* Implements hook_views_data_alter().
*
* Registers the my_module_node_original_title field on the node_field_data
* base table so it is available in any View that uses Content as its base.
*/
public function __invoke(array &$data): void {
$data['node_field_data']['my_module_node_original_title'] = [
'title' => $this->t('Title (original language)'),
'help' => $this->t('The node title rendered in its original (source) language, regardless of the current interface language.'),
'field' => [
'id' => 'my_module_node_original_title',
],
];
}
}Step 2 — Implement the Views Field Plugin
All Views field plugins extend FieldPluginBase and are placed in
src/Plugin/views/field/.query()— called by Views when building the SQL query. Because our field does not need an extra database column (we retrieve the data from the already-loaded entity), we leave this empty.render()— called for each row in the result set. This is where we retrieve the node entity from the result row and return its untranslated title usinggetUntranslated()->getTitle().usesGroupBy()— we returnFALSEbecause grouping by a computed pseudo field does not make sense.
<?php
namespace Drupal\my_module\Plugin\views\field;
use Drupal\node\NodeInterface;
use Drupal\views\Attribute\ViewsField;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;
/**
* A Views field that always renders the node title in its original language.
*
* Useful when Views is displaying a translated context but the original
* (source) language title is needed regardless of the current UI language.
*/
#[ViewsField('my_module_node_original_title')]
final class NodeOriginalTitle extends FieldPluginBase {
/**
* {@inheritdoc}
*/
#[\Override]
public function query(): void {
// No extra query needed - the title is fetched from the loaded entity.
}
/**
* {@inheritdoc}
*/
#[\Override]
public function render(ResultRow $values): string {
$entity = $this->getEntity($values);
if (!$entity instanceof NodeInterface) {
return '';
}
return $entity->getUntranslated()->getTitle() ?? '';
}
/**
* {@inheritdoc}
*/
#[\Override]
public function usesGroupBy(): bool {
return FALSE;
}
}Wrapup
web/modules/custom/my_module/
├── my_module.info.yml # updated: added drupal:views dependency
└── src/
├── Hook/
│ └── ViewsData.php # new: hook_views_data_alter() implementation
└── Plugin/
└── views/
└── field/
└── NodeOriginalTitle.php # new: Views field pluginSources
https://drupalize.me/tutorial/define-custom-views-pseudo-field-plugin
https://www.webomelette.com/creating-custom-views-field-drupal-8