- Issue created by @nicodh
- 🇫🇷France nicodh
I have made some changes that seems to work for me: https://git.drupalcode.org/issue/json_ld_schema-3488126/-/commit/82e49d8...
I use a custom JsonLdSource plugin to output FAQPage schema at the bottom of the page.
In a custom hook_entity_view, I collect viewed entities (in my case some paragraphs), and then reuse them in getData of my plugin.
In this case, isApplicable and getCacheableMetadata are called too earlier, before my entities are collected, so the correct output is not used (before I collect entities, isApplicable is always false).
In a custom .module:
/**
* Implements hook_entity_view().
*/
function custom_metatags_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
if ($entity->getEntityTypeId() === 'paragraph' && $entity->bundle() === 'faq' && !$entity->get('field_title')->isEmpty() && !$entity->get('field_text')->isEmpty()) {
\Drupal::service('custom_metatags.faqs')->addEntity($entity);
}
}
My custom plugin file:
<?php
namespace Drupal\custom_metatags\Plugin\JsonLdSource;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Render\RendererInterface;
use Drupal\custom_metatags\Service\MetatagsFaqs;
use Drupal\json_ld_schema\Source\JsonLdSourceBase;
use Spatie\SchemaOrg\Schema;
use Spatie\SchemaOrg\Type;
/**
* Organization source.
*
* @JsonLdSource(
* label = "FAQ Source",
* id = "custom_faq_source",
* )
*/
class FaqSource extends JsonLdSourceBase {
/** @var MetatagsFaqs */
protected $faqsManager;
/** @var array|null */
protected $questions = null;
/** @var RendererInterface */
protected $renderer = null;
/** @var RenderContext */
protected $renderContext = null;
public function getManager(): MetatagsFaqs {
if (!$this->faqsManager) {
$this->faqsManager = \Drupal::service('custom_metatags.faqs');
}
return $this->faqsManager;
}
public function getRenderer(): RendererInterface {
if (!$this->renderer) {
$this->renderer = \Drupal::service('renderer');
}
return $this->renderer;
}
public function getQuestions(): array {
if ($this->questions === null) {
$this->questions = [];
$this->renderContext = $this->renderContext ?? new RenderContext();
$renderer = $this->getRenderer();
$entities = $this->getManager()->getEntities();
foreach ($entities as $entity) {
if (!$entity->get('field_title')->isEmpty() && !$entity->get('field_text')->isEmpty()) {
$text = $renderer->executeInRenderContext($this->renderContext, function() use ($renderer, $entity) {
$build = $entity->get('field_text')->view(['label' => 'hidden']);
return $renderer->render($build);
});
$this->questions[] = Schema::Question()
->name($entity->get('field_title')->first()->value)
->acceptedAnswer(
Schema::Answer()->text($text)
);
}
}
}
return $this->questions;
}
public function isApplicable(): bool
{
return !empty($this->getQuestions());
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata(): CacheableMetadata {
$cacheable = parent::getCacheableMetadata();
$cacheable->addCacheContexts(['url']);
$entities = $this->getManager()->getEntities();
foreach ($entities as $entity) {
$cacheable->addCacheableDependency($entity);
}
if ($this->renderContext instanceof RenderContext && !$this->renderContext->isEmpty()) {
$cacheable->merge($this->renderContext->pop());
}
return $cacheable;
}
/**
* {@inheritdoc}
*/
public function getData(): Type {
return !empty($this->getQuestions()) ? Schema::FAQPage()
->mainEntity($this->getQuestions()) : Schema::thing();
}
}
Always includes source elements in page_bottom hok, but checks isApplicable / cacheable metadata in pre_render.
Active
2.0
Code
I have made some changes that seems to work for me: https://git.drupalcode.org/issue/json_ld_schema-3488126/-/commit/82e49d8...