0

Drupal 8.x

I would like to alter the value of all/any ckeditor/text fields on a node.

Currently working with HOOK_node_presave().

Ideally, I'd like an agnostic approach that doesn't mind where the field is coming from, e.g. paragraph, node, taxonomy, etc.

How can I loop through all fields, check the field type, get and replace the value?


MYMODULE.module

Working with the below code gets me close I think:

use Drupal\Core\Entity\EntityInterface;

function MYMODULE_node_presave(EntityInterface $entity) {
  $fieldsArray = \Drupal::service('entity_field.manager')->getFieldMapByFieldType('text_long');

  foreach($fieldsArray as $longTextName=>$key) {

    kpr($key); // This returns an array of the values I need.
    if ($entity->hasField($key)) {
      $entity->get($result)->value = preg_replace(
        $toReplace,
        $replaceWith,
        $entity->get($result)->value
      );
    }
  }

}

Try #2;

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;

function MYMODULE_presave(EntityInterface $entity) {
  // Get form config.
  // Get config Node field names.
  // Get config Paragraph names.
  // Get config Paraghraph field names.

  // Loop through our Node field names.
  foreach($nodeFieldNames as $fieldName) {
    // Check if the entity has field.
    if ($entity->hasField($fieldName)) {
      // Get the field.
      $entity->get($fieldName)->value = $newValue;
    }
  }

  // Loop through our Paragraph names.
  foreach($paragraphNames as $paragraphName) {
  // Check if the entity has field.
  if ($entity->hasField($paragraphName)) {
    $paragraphs = $entity->$paragraphName->getValue();
    foreach ($paragraphs as $paragraphItem) {
      $p = \Drupal\paragraphs\Entity\Paragraph::load( $paragraphItem['target_id'] );
      foreach($paragraphFieldNames as $paragraphFieldNamesitem) {
        if ($p->get($paragraphFieldNamesitem)->value) {
          // kpr($p->get($paragraphFieldNamesitem)->value);
          $p->get($paragraphFieldNamesitem)->value = $newvalue;
          // kpr($p->get($paragraphFieldNamesitem)->value);
          // This does alter the value, just does not get saved.
        }
      }
    }
  }
}
5
  • 1
    In general this code looks like it belongs in a text filter. For the agnostic way on a field type basis you could extend the field widget of this field type.
    – 4uk4
    Commented Nov 8, 2018 at 9:45
  • Could you expand a bit on the "looks like it belongs in a text filter"? Not sure I follow and would like to... Commented Nov 8, 2018 at 20:26
  • 1
    Create a custom text filter and add it to the text format(s) used in the field.
    – 4uk4
    Commented Nov 8, 2018 at 21:22
  • That is definitely a viable option using the text filters. Not the path for me currently, but a good Drupal way to do it. Great thinking! Commented Nov 9, 2018 at 20:58
  • I've continued to work on this and can say that creating a custom text filter was by far the easiest/best approach for my use case. This doesn't really answer the question, but is the best way for me to go! For others here, issues I faced were that paragraphs use subforms, and I couldn't alter field values via HOOK_entity_presave(). Similar issue with the comment field. Not saying it can't be done. Commented Nov 28, 2018 at 6:23

1 Answer 1

1

You can use FieldConfigInterface to get fields info.
Try the following:

use Drupal\Core\Field\FieldConfigInterface;

function MYMODULE_node_presave($node) {
  //- Call helper function to get all the fields
  $fieldsArray = getContentTypeFields($node->bundle());
  //- Loop through fields 
  foreach ($fieldsArray as $fieldName => $fieldConfig) {
    ///- Example to check if type is text_with_summary
    if ($fieldConfig->getType() == 'text_with_summary') {
      /**
       * @TODO : Something here for field of type text_with_summary
       */
    }
  }
}

/**
 * Helper function to Get all fields of content type:
 *
 * @param $contentType
 *
 * @return array
 */
function getContentTypeFields($contentType) {
  $entityManager = Drupal::service('entity.manager');
  $fields = [];
  if (!empty($contentType)) {
    $fields = array_filter(
      $entityManager->getFieldDefinitions('node', $contentType), function ($field_definition) {
      return $field_definition instanceof FieldConfigInterface;
    }
    );
  }

  return $fields;
}
3
  • This works well for node, yet it does not return fields from paragraph, comment, etc. Commented Nov 8, 2018 at 16:39
  • you are welcome you can adjust the function on your needs. i thought that you need only for nodes.
    – berramou
    Commented Nov 8, 2018 at 17:01
  • I've been working with your answer, and have had some success, but just can't seem to accomplish the final step. Above code may be a little messy right now but feels close. I think maybe if this works for node and paragraph, it could easily for comment fields, etc. Right now I am just using the single helper function. Commented Nov 17, 2018 at 4:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.