Drupal 9/10: how to create computed field

Profile picture for user a.berramou
Azz-eddine BERRAMOU 9 December, 2023

Imagine you have two fields: "First Name" and "Last Name", and you want to calculate the full name from the values in these fields.

How can you achieve this without creating a new field and using hook_update_N to populate it in old content ?

The solution is to create a computed field. As the name suggests, it is a field that computes its value from other fields' data but does not persist it in the database.

To create a computed field, follow these steps:

  1. Create a class for the computed field. This class should be located at [MODULE_NAME]/src/Plugin/Field/FieldType/FullNameComputedField.php
<?php
namespace Drupal\[MODULE_NAME]\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\TypedData\ComputedItemListTrait;
/**
 * Full name computed field class.
 */
class FullNameComputedField extends FieldItemList {
  use ComputedItemListTrait;
  /**
   * Computes the values for an item list.
   */
  protected function computeValue() {
    $fullName = '';
    $entity = $this->getEntity();
    if (
      $entity->hasField('field_first_name')
      && !$entity->get('field_first_name')->isEmpty()
    ) {
      $fullName .= $entity->get('field_first_name')?->value;
    }
    if (
      $entity->hasField('field_last_name')
      && !$entity->get('field_last_name')->isEmpty()
    ) {
      $fullName .= $entity->get('field_last_name')?->value . ' ';
    }
    // Computed full name.
    /** @var \Drupal\Core\Field\FieldItemInterface $item */
    $item = $this->createItem(0, $fullName);
    $this->list[0] = $item;
  }
}


Now that we have created our class, the next step is to add our new field to our person content. To do this, we need to implement the hook_entity_bundle_field_info.

[MODULE_NAME].module file, add the following code:

<?php
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\[MODULE_NAME]\Plugin\Field\FieldType\FullNameComputedField;
/**
 * Implements hook_entity_bundle_field_info().
 */
function hello_world_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  if ($entity_type->id() == 'node' && $bundle == 'person') {
    $fields = [];
    // Add a property only to nodes of the 'person' bundle.
    $fields['full_name'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Full name'))
      ->setDescription(t('Full name field'))
      // Mark this field as computed.
      ->setComputed(TRUE)
      // Mark your field as read only since it's computed we will never populate it.
      ->setReadOnly(TRUE)
      // Set our class as field class.
      ->setClass(FullNameComputedField::class)
      ->setDisplayConfigurable('view', TRUE)
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayOptions('view', [
        'label'  => 'above',
        'type'   => 'string',
        'weight' => 0,
      ]);
    return $fields;
  }
}

[MODULE_NAME] with the actual name of your module. This code checks if the entity type is 'node' and the bundle is 'person' before defining and creating the computed field for the full name.

That's all! Just clear the cache, go to your content type's field management, and you'll see your new field. Customize, hide, or do anything else you need, just like any other field.

Full name computed fiedl