19 Dec.2017

Drupal 8 & 9 [archived]: How to Get Your Star Ratings in Google Search Results

How to Get Your Star Ratings in Google Search Results

I've been looking for a long way to add structured data to Google Search Results. At first, I waited for the community to implement LD+JSON directly in "Metatag" module. Then, to my happiness, I found "Schema.org Metatag" module in which this functional is already implemented. And although this module cannot add the necessary AggregateRating data... Hooray. Now we can start and do it ourselves.

For this we need to install and enable several modules and their dependencies:

drush -y en metatag schema_metatag schema_article votingapi votingapi_widgets

After enabling the modules, the first thing, we should add the "rating" field with type "Voting api field" to your content type and make basically set up. In my case, I choose to use "Fivestar rating".

The setting of the Vote field

Congratulations. You created a field, set it up and now visitors can and will definitely vote your content! But this is not enough. "Schema.org Metatag" module still does not know anything about the rating and does not know how to add data to JSON. Let's teach this module to see the data, for this we need only one metatag plugin file with a small custom code.

File
modules/custom/easydrupal_common/src/Plugin/metatag/Tag/SchemaArticleCustomAggregateRating.php
<?php
 
namespace Drupal\easydrupal_common\Plugin\metatag\Tag;
 
use Drupal\schema_metatag\Plugin\metatag\Tag\SchemaNameBase;
 
/**
 * Provides a plugin for the 'schema.org AggregateRating' meta tag.
 *
 * - 'id' should be a globally unique id.
 * - 'name' should match the Schema.org element name.
 * - 'group' should match the id of the group that defines the Schema.org type.
 *
 * @MetatagTag(
 *   id = "schema_article_custom_aggregate_rating",
 *   label = @Translation("Custom AggregateRating"),
 *   description = @Translation("Attach to JSON the aggregate rating of the article provided by the Voting API module."),
 *   name = "aggregateRating",
 *   group = "schema_article",
 *   weight = 11,
 *   type = "string",
 *   secure = FALSE,
 *   multiple = FALSE
 * )
 */
class SchemaArticleCustomAggregateRating extends SchemaNameBase {
 
  /**
   * Basic info about votingapi.
   *
   * @var bool
   */
  protected $votingapiEnabled;
 
  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
 
    $moduleHandler = \Drupal::service('module_handler');
    if ($moduleHandler->moduleExists('votingapi')) {
      $this->votingapiEnabled = TRUE;
    }
  }
 
  /**
   * Generate a form element for this meta tag.
   */
  public function form(array $element = []) {
    $form = [];
 
    if ($this->votingapiEnabled) {
      $form = [
        '#type' => 'checkbox',
        '#title' => $this->label(),
        '#description' => $this->description(),
        '#default_value' => $this->value(),
      ];
    }
 
    return $form;
  }
 
  /**
   * {@inheritDoc}
   */
  public function output() {
    $element = parent::output();
 
    if (!empty($element['#attributes']['content'])) {
      // Load the current node.
      $node = \Drupal::routeMatch()->getParameter('node');
 
      // Get rating from votingapi.
      $voting_service = \Drupal::service('plugin.manager.votingapi.resultfunction');
      $results = $voting_service->getResults('node', $node->id());
 
      if (!empty($results)) {
        $element['#attributes']['content'] = [
          "@type" => "AggregateRating",
          "ratingValue" => $results['vote']['vote_average'],
          "bestRating" => 5,
          "worstRating" => 1,
          "ratingCount" => $results['vote']['vote_count'],
        ];
      }
      else {
        return FALSE;
      }
    }
 
    return $element;
  }
 
}

This file adds an additional setting for the module Schema.org Metatag.

Metatag Settings

<script type="application/ld+json">{
    "@context": "http://schema.org",
    "@graph": [
        {
            "@type": "TechArticle",
            "headline": "[Tips \u0026 Tricks] Drupal 8: How to Get Your Review\u2019s Star Ratings in Google Search Results",
            "aggregateRating": {
                "@type": "AggregateRating",
                "ratingValue": "5",
                "bestRating": 5,
                "worstRating": 1,
                "ratingCount": "2"
            }
        }
    ]
}</script>

The above is an approximate result that will be added to the source code of the page. Also, you can see the source code of the current page and see more data and useful settings for the SEO.

Conclusion

I also look forward to new comments and advice on how to make this code better. In the end, I add the full version of the module to the article in the attachment. Enjoy & Good luck! ))

Update: On Drupal.org I proposed to integrate my solution as a patch for "Schema.org Metatag", maybe this will be useful for someone. You can have a look at https://www.drupal.org/project/schema_metatag/issues/2916438 (schema_metatag-SchemaArticleAggregateRating-2916438-9.patch).

Attachments

Ruslan Piskarov

Ukraine
PHP/WEB Developer / Drupal Expert. More than 11 years of experience delivering Drupal based General Purpose solutions for different sectors such as Job Boards, Product Portfolios, Geo Coding, Real Estate solutions, E-Commerce, Classifieds, Corporate and online Magazines/Newspapers.

Versions