Commit 7772128b authored by mark burdett's avatar mark burdett
Browse files

Issue #2995378 by BAHbKA, mfb, zweishar, nedsbeds, Adam_M: Defer to core...

Issue #2995378 by BAHbKA, mfb, zweishar, nedsbeds, Adam_M: Defer to core content_translation handling of hreflang tags for content entities
parent b8653004
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
x_default: TRUE
defer_to_content_translation: FALSE
+3 −0
Original line number Diff line number Diff line
@@ -5,3 +5,6 @@ hreflang.settings:
    x_default:
      type: boolean
      label: 'Add x-default hreflang tag for default language'
    defer_to_content_translation:
      type: boolean
      label: 'Defer to Content Translation hreflang tags on content entity pages'
+56 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 * Adds hreflang link elements to the header of each page.
 */

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;

@@ -16,18 +17,39 @@ function hreflang_page_attachments(array &$page) {
  if (\Drupal::request()->attributes->has('exception')) {
    return;
  }

  $config = \Drupal::config('hreflang.settings');
  $addXDefault = $config->get('x_default');
  $is_front_page = \Drupal::service('path.matcher')->isFrontPage();
  if ($config->get('defer_to_content_translation') && $entity = hreflang_content_translation_get_entity()) {
    if ($addXDefault) {
      $url = $is_front_page ? Url::fromRoute('<front>') : $entity->toUrl();
      $page['#attached']['html_head_link'][] = [
        [
          'rel' => 'alternate',
          'hreflang' => 'x-default',
          'href' => $url
            ->setOption('language', $entity->getUntranslated()->language())
            ->setAbsolute()
            ->toString(),
        ],
        TRUE,
      ];
    }
    return;
  }

  $language_manager = \Drupal::languageManager();
  if (!$language_manager->isMultilingual()) {
    return;
  }
  $route = \Drupal::service('path.matcher')->isFrontPage() ? '<front>' : '<current>';
  $route = $is_front_page ? '<front>' : '<current>';
  $links = $language_manager->getLanguageSwitchLinks(LanguageInterface::TYPE_INTERFACE, Url::fromRoute($route));
  if (empty($links->links)) {
    return;
  }

  // Adding x-default if option checked.
  $addXDefault = \Drupal::config('hreflang.settings')->get('x_default');
  $defaultLanguageId = $language_manager->getDefaultLanguage()->getId();

  foreach ($links->links as $langcode => $link) {
@@ -57,6 +79,38 @@ function hreflang_page_attachments(array &$page) {
  $page['#cache']['contexts'][] = 'url.query_args';
}

/**
 * Get source content_translation entity used for hreflang links.
 *
 * @see content_translation_page_attachments()
 *
 * @return \Drupal\Core\Entity\ContentEntityInterface|null
 *   Get an entity from route, that will be used as a source for the hreflang
 *   links by the content_translation module.
 */
function hreflang_content_translation_get_entity() {
  if (!\Drupal::service('module_handler')->moduleExists('content_translation')) {
    return NULL;
  }

  $route_match = \Drupal::routeMatch();
  if ($parameters = $route_match->getRouteObject()->getOption('parameters')) {
    // Determine if the current route displays a content entity. If it does,
    // defer to logic in content_translation_page_attachments().
    foreach ($parameters as $name => $options) {
      if (!isset($options['type']) || strpos($options['type'], 'entity:') !== 0) {
        continue;
      }
      $entity = $route_match->getParameter($name);
      if ($entity instanceof ContentEntityInterface && $entity->hasLinkTemplate('canonical')) {
        return $entity;
      }
    }
  }

  return NULL;
}

/**
 * Implements hook_help().
 */
+9 −0
Original line number Diff line number Diff line
@@ -37,6 +37,14 @@ class ModuleConfigurationForm extends ConfigFormBase {
      '#default_value' => $config->get('x_default'),
      '#description' => $this->t('If enabled, an additional <a href="https://en.wikipedia.org/wiki/Hreflang#X-Default" rel="noreferrer">@html</a> tag will be created, pointing at the site default language.', ['@html' => 'hreflang="x-default"']),
    ];

    $form['defer_to_content_translation'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Defer to Content Translation hreflang tags on content entity pages'),
      '#default_value' => $config->get('defer_to_content_translation'),
      '#description' => $this->t("If enabled, and Content Translation module is enabled, Hreflang module will not add hreflang tags to content entity pages (aside from the x-default tag, if enabled above). As a result, hreflang tags will be added only for languages that have a translation (and to which the user has view access), or for the content's designated language if it is not translatable, although the content could still be accessible under other languages with a translated user interface. Note that Content Translation module does not add query arguments to its hreflang tags, so pages with query arguments will not have a valid set of hreflang tags; this will, however, improve cache efficiency by not creating separate caches for each set of query arguments."),
    ];

    return parent::buildForm($form, $form_state);
  }

@@ -46,6 +54,7 @@ class ModuleConfigurationForm extends ConfigFormBase {
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->config('hreflang.settings')
      ->set('x_default', $form_state->getValue('x_default'))
      ->set('defer_to_content_translation', $form_state->getValue('defer_to_content_translation'))
      ->save();
    parent::submitForm($form, $form_state);
  }
+39 −0
Original line number Diff line number Diff line
@@ -33,12 +33,20 @@ class HreflangContentTranslationTest extends NodeTestBase {
      'administer languages',
      'administer site configuration',
      'create page content',
      'administer content types',
      'translate any entity',
    ]);
    $this->drupalLogin($admin_user);
    // Add predefined language.
    $this->drupalGet('admin/config/regional/language/add');
    $edit = ['predefined_langcode' => 'fr'];
    $this->submitForm($edit, 'Add language');
    // Enable translation for a page content type.
    \Drupal::service('content_translation.manager')->setEnabled('node', 'page', TRUE);
    $this->drupalGet('admin/structure/types/manage/page');
    $edit = ['language_configuration[language_alterable]' => TRUE];
    $this->submitForm($edit, 'Save content type');

    // Add node.
    $this->drupalGet('node/add/page');
    $edit = ['title[0][value]' => 'Test front page'];
@@ -65,6 +73,37 @@ class HreflangContentTranslationTest extends NodeTestBase {
    $this->assertSession()->responseNotContains('<link rel="alternate" hreflang="en" href="' . $base_url . '/node/1" />');
    // French hreflang found on French page.
    $this->assertSession()->responseNotContains('<link rel="alternate" hreflang="fr" href="' . $base_url . '/fr/node/1" />');

    // Enable the "Defer to Content Translation hreflang tags on content entity
    // pages" option.
    $this->drupalGet('admin/config/search/hreflang');
    $edit = ['defer_to_content_translation' => TRUE];
    $this->submitForm($edit, 'Save configuration');
    $this->drupalGet('');
    // French hreflang shouldn't be set as node doesn't have corresponding
    // translation.
    $this->assertSession()->responseNotContains('<link rel="alternate" hreflang="fr" href="' . $base_url . '/fr" />');
    // Make sure that x-default points to the en version of the node.
    $this->assertSession()->responseContains('<link rel="alternate" hreflang="x-default" href="' . $base_url . '/" />');

    // Translate node to the french language.
    $this->drupalGet('node/1/translations/add/en/fr');
    $edit = ['title[0][value]' => 'FR: Test front page'];
    $this->submitForm($edit, 'Save (this translation)');

    $this->drupalGet('fr');
    // Node should have both hreflangs and x-default that points to "/".
    $this->assertSession()->responseContains('<link rel="alternate" hreflang="fr" href="' . $base_url . '/fr" />');
    $this->assertSession()->responseContains('<link rel="alternate" hreflang="en" href="' . $base_url . '/" />');
    // Make sure that x-default hreflang points to the source translation.
    $this->assertSession()->responseContains('<link rel="alternate" hreflang="x-default" href="' . $base_url . '/" />');
    // Disable x-default configuration option.
    $this->drupalGet('admin/config/search/hreflang');
    $edit = ['x_default' => FALSE];
    $this->submitForm($edit, 'Save configuration');
    $this->drupalGet('/admin');
    // Make sure that x-default link not added.
    $this->assertSession()->responseNotContains('<link rel="alternate" hreflang="x-default" href="' . $base_url . '/" />');
  }

}