diff --git a/plugins/content/vote/src/Extension/Vote.php b/plugins/content/vote/src/Extension/Vote.php index fcc4866b08cb..29fd8bd81dde 100644 --- a/plugins/content/vote/src/Extension/Vote.php +++ b/plugins/content/vote/src/Extension/Vote.php @@ -12,6 +12,7 @@ use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Plugin\PluginHelper; +use Joomla\CMS\Uri\Uri; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; @@ -123,4 +124,110 @@ private function displayVotingData($context, &$row, &$params, $page) return $html; } + + /** + * Create SchemaOrg AggregateRating + * + * @param object $schema The schema of the content being passed to the plugin + * @param string $context The context of the content being passed to the plugin + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function onSchemaBeforeCompileHead($schema, $context): void + { + $graph = $schema->get('@graph'); + $baseId = Uri::root() . '#/schema/'; + $schemaId = $baseId . str_replace('.', '/', $context); + + foreach ($graph as &$entry) { + if (!isset($entry['@type']) || !isset($entry['@id'])) { + continue; + } + if ($entry['@id'] !== $schemaId) { + continue; + } + + switch ($entry['@type']) { + case 'Book': + case 'Brand': + case 'CreativeWork': + case 'Event': + case 'Offer': + case 'Organization': + case 'Place': + case 'Product': + case 'Recipe': + case 'Service': + $rating = $this->prepareAggregateRating($context); + break; + case 'Article': + case 'BlogPosting': + $rating = $this->prepareProductAggregateRating($context); + break; + } + } + + if (isset($rating) && $rating) { + $graph[] = $rating; + $schema->set('@graph', $graph); + } + } + + /** + * Prepare AggregateRating + * + * @param string $context + * + * @return ?string + * + * @since __DEPLOY_VERSION__ + */ + protected function prepareAggregateRating($context) + { + [$extension, $view, $id] = explode('.', $context); + + if ($view === 'article') { + $baseId = Uri::root() . '#/schema/'; + $schemaId = $baseId . str_replace('.', '/', $context); + + $component = $this->getApplication()->bootComponent('com_content')->getMVCFactory(); + $model = $component->createModel('Article', 'Site'); + $article = $model->getItem($id); + if ($article->rating_count > 0) { + return ['@isPartOf' => ['@id' => $schemaId, 'aggregateRating' => ['@type' => 'AggregateRating','ratingCount' => (string) $article->rating_count,'ratingValue' => (string) $article->rating]]]; + } + } + + return false; + } + + /** + * Prepare Product AggregateRating + * + * @param string $context + * + * @return ?string + * + * @since __DEPLOY_VERSION__ + */ + protected function prepareProductAggregateRating($context) + { + [$extension, $view, $id] = explode('.', $context); + + if ($view === 'article') { + $baseId = Uri::root() . '#/schema/'; + $schemaId = $baseId . str_replace('.', '/', $context); + + $component = $this->getApplication()->bootComponent('com_content')->getMVCFactory(); + $model = $component->createModel('Article', 'Site'); + $article = $model->getItem($id); + if ($article->rating_count > 0) { + return ['@isPartOf' => ['@id' => $schemaId, '@type' => 'Product', 'name' => $article->title, 'aggregateRating' => ['@type' => 'AggregateRating', 'ratingCount' => (string) $article->rating_count, 'ratingValue' => (string) $article->rating]]]; + } + } + + return false; + } } diff --git a/plugins/content/vote/tmpl/rating.php b/plugins/content/vote/tmpl/rating.php index 2362dfa1b6c6..73eddd83d2a9 100644 --- a/plugins/content/vote/tmpl/rating.php +++ b/plugins/content/vote/tmpl/rating.php @@ -83,10 +83,8 @@ ?>