Oct 08, 2020 in Drupal 8
Metatags can be hard when abandoning the body field in favor of paragraphs. This post gives you a generic solution for the problem.
We want to create a custom module that, after saving the content, scrapes the first <p>-tag and saves them to the node as the meta description. In this way, we make sure a description is set, and we no longer have to worry about the first paragraph not being a textfield. In custom_meta.module, add the following. The script will check if there is a summary, otherwise scrape the node for a <p>-tag and save it to the node.
<?php
/**
* @param \Drupal\Core\Entity\EntityInterface $entity
*/
function custom_meta_node_presave(Drupal\node\NodeInterface $entity) {
if(in_array($entity->bundle(), ['article','page'])) {
$summary = $entity->get('body')->summary;
if(strlen($summary) < 8) {
$nid = $entity->id();
$entity_type = 'node';
$view_mode = 'full';
$view_builder = \Drupal::entityTypeManager()->getViewBuilder($entity_type);
$storage = \Drupal::entityTypeManager()->getStorage($entity_type);
$node = $storage->load($nid);
if($node) {
$build = $view_builder->view($node, $view_mode);
$summary = custom_meta_get_paragraph_from_html($build);
} else {
$summary = '';
}
}
if(strlen($summary) > 8) {
$entity->set('field_meta_tags', serialize([
'description' => $summary,
]));
}
if(strlen($summary) > 240) {
$entity->set('field_meta_tags', serialize([
'description' => substr($summary,0,250).'...'
]));
}
}
}
/**
* Gets html, sends one sentence back.
*/
function custom_meta_get_paragraph_from_html($html) {
$output = render($build);
$first_paragraph = substr($output, strpos($output, "<p"), strpos($output, "</p>")+4);
$first_paragraph = strip_tags($first_paragraph);
$first_paragraph = preg_replace('/<!--(.|\s)*?-->/', '', $first_paragraph);
$first_paragraph = htmlentities($first_paragraph, null, 'utf-8');
$first_paragraph = str_replace(" ", "", $first_paragraph);
$first_paragraph = html_entity_decode($first_paragraph);
$summary = substr($first_paragraph,0,150).'...';
return $summary;
}