Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Current »

CURRENT 230531

Simple XML Sitemap

Setup variants

Install using composer

composer require drupal/simple_sitemap

Enable the module either through drush or through UI.

After that navigate to the configuration page for the module (admin/config/search/simplesitemap)

On the “Settings” tab switch to the “Variants” child tab and create a variant

default | default_hreflang | Default - the first segment is a URL segment - leave blank if you want your sitemap to live in the root of the site /sitemap.xml and you are not planning to use any other sitemap variants (| default_hreflang | Default).

If you are submitting your sitemap to third-party SEO services other than Google, identify their requirements for the path of sitemap.

Configure settings

Switch to the “Settings” tab and configure the settings.

Cron settings:

Allow regeneration of the sitemap on cron.

Reduce the interval to a daily - this is a good default setting, but make sure it is in alignment with the volume of published content on your project. Some projects can have sitemap regenerated less often - some more often.

The bigger your site the higher the chance that sitemap generation will not be completed during one cron run so having the interval set to a higher value helps to alleviate this problem. If the sitemap isn’t finished during one cron run then it can finish during subsequent runs.

Language settings:

If your site is multilingual pay attention to the Language settings. Open “Language settings” fieldset and select “Skip non-existent translations” - this will allow to not include non-existent translation into the sitemap.

Keep the checkbox: “Remove hreflang markup in HTML” - unchecked for site that have global audience.

Advanced configuration:

If you have redirects on your site from multiple domains to one, include base URL setting.

Select “Exclude duplicated links” checkbox.

Set amount of links to a reasonable number ~2000 max - your sitemap will be split into a few pages.

Set a sitemap generation time - it influences performance so make sure it’s not too high or too low. 10 is a reasonable starting number.

Multilingual sites setup

Content Translation Redirect module

This module allows redirecting to the default language if a translation doesn’t exist.

Default settings

Install using composer

composer require drupal/content_translation_redirect

In the configuration section (admin/config/regional/content-translation-redirect)

Set redirect status to 302. Never set it to 301 unless you know the translation will never exist.

Optionally specify the message for redirection.

You can override the default settings by entity in the Entity Settings tab.

Preprocess hreflang attribute

It’s required to have an hreflang attribute per language and region to help Google identify what content needs to be served for visitors in particular geolocation regions. It’s also good practice for SEO. Make sure your sitemap includes an hreflang alternate for every translation. They can be created using hook_page_attachments_alter

/**
 * Implements hook_page_attachments_alter().
 */
function example_page_attachments_alter(array &$attachments) {
  if (isset($attachments['#attached']['html_head_link'])) {
    $node = \Drupal::routeMatch()->getParameter('node');
    $host = \Drupal::request()->getSchemeAndHttpHost();
    if ($node instanceof NodeInterface) {
      $siblings = \Drupal::service('example.context_helpers')->getSiblings($node);
      if (!empty($siblings)) {
        $paths = \Drupal::service('example.context_helpers')->getAliases($siblings);
        if (!empty($paths)) {
          $links = [];
          $props = [];
          foreach ($paths as $i => $path) {
            $props[0]['rel'] = 'alternate';
            $props[0]['hreflang'] = $path['lang'];
            $props[0]['href'] = $host . $path['link'];
            $props[1] = TRUE;
            $links[] = $props;
          }
        }
      }
    }
    foreach ($attachments['#attached']['html_head_link'] as $key => $link) {
      if (isset($link[0]['rel']) && !empty($link[0]['rel']) && $link[0]['rel'] == 'alternate' && isset($link[0]['href'])) {
        $href = $link[0]['href'];
        $href = str_replace('https://', '', $href);
        $href = str_replace('http://', '', $href);
        $href_arr = explode('/', $href);
        if (isset($href_arr[2]) && $href_arr[2] !== 'node') {
          $attachments['#attached']['html_head_link'][$key][0]['hreflang'] = $href_arr[1] . '-' . $href_arr[2];
        }
      }
    }
    
    // Setting default one.
    $attachments['#attached']['html_head_link'][] = [['rel' => 'alternate', 'hreflang' => 'x-default', 'href' => 'https://example.com']];
  }
}

Service helper functions you should place in your service class:

  /**
   * Helper function to get siblings of the node if sibling relationship exists.
   *
   * @param Node $node
   *    node interface.
   *
   * @return array $siblings
   *    array of node siblings ids.
   */
  public function getSiblings(Node $node) {
    $siblings = [];
    if (isset($node->field_master_node)) {
      $master = $node->field_master_node->target_id;
      if (isset($master)) {
        $siblings = $this->getChildNodes($master);
      }
    }
    return $siblings;
  }
  /**
   * Helper function to get node aliases and language / region prefix by nid.
   *
   * @param array $nids
   *    Node ids.
   *
   * @return array $aliases
   *    Array of aliases.
   */
  public function getAliases($nids) {
    $languages = \Drupal::languageManager()->getLanguages();
    if (!is_array($nids)) {
      $nids = [$nids];
    }
    $aliases = [];
    $i = 0;
    foreach ($nids as $nid) {
      foreach ($languages as $lng_code => $lang) {
        $alias = \Drupal::service('path.alias_manager')->getAliasByPath('/node/' . $nid, $lng_code);
        if (strpos($alias, '/node/') === FALSE) {
          $al_arr = explode('/', $alias);
          $alias = '/' . $lng_code . $alias;
          $aliases[$i]['link'] = $alias;
  
          $aliases[$i]['lang'] = $al_arr[1] . '-' . $lng_code;
          $i++;
        }
      }
    }
    return $aliases;
  }

Rabbit Hole

Rabbit hole is a module that allows you to prevent bots and users from accessing nodes and other entities that shouldn’t have a full page display. The example would be CTA content type nodes used inside views but not necessarily requiring full page display.

Install using composer

composer require drupal/rabbit_hole

Enable Rabbit Hole, Rabbit Hole Nodes, Rabbit Hole Taxonomies, and Rabbit Hole Users.

Configuration for each of these entity types can be found on the content type, user or vocabulary edit pages. Set them to default to Access Denied. These settings can be overridden on each respectful entity form.

The permission allows admins to still have full access to the page views of the rabbit-holed entities.

A nice side effect of using this module is that is can be used to allow to create page previews for internal review.

Metatag ecosystem

Make sure the metatag module is installed. Global options are configured as well as options for content. Add a metatag field to the content types to allow editors to override keywords and descriptions as needed.

Make sure metatag is set up for views especially if you are using page displays on the site.

Install using composer

composer require drupal/metatag

Google Tag

It is preferable to install the Google Tag module vs Google Analytics since this module provides more control and flexibility in terms of installing not only Analytics tags but also any additional trackers that might be required for SEO.

Install using composer

composer require drupal/google_tag

Make sure to adjust the configuration to exclude any undesired tracking paths and to not track administrators and editors.

If you don’t redirect b’s needs, exclude tracking on dev and stage environments domains.

Redirect

Setup and install redirect module.

Install using composer

composer require drupal/redirect

Setup default settings (admin/config/search/redirect/settings). For the first launch of a site make sure that the settings are set to 302 not 301 status. Check "Automatically create redirects when URL aliases are changed." and "Retain query string through redirect."

Make sure that you are enforcing clean and canonical URLs.

Pathauto

Install using composer

composer require drupal/pathauto

Update the settings for pathauto (admin/config/search/path/settings)

Make sure that all publicly accessible entities have a URL pattern setup.

Work with the client to ensure the patterns strategy works for their business needs and minimizes the redirection effort where possible.

Pre-launch set it up so that pathauto creates a new alias and deletes the old one.

Make sure that strings that are set to be removed don’t impact existing aliases, contribute to the creation of awkward aliases because of the removal of the conjunction word, or change the meaning. Work with clients to identify potential risks.

Breadcrumbs modules

Easy Breadcrumb

Provides additional easy customization for breadcrumbs. Useful when breadcrumbs don’t have to match menu active trail.

Install using composer

composer require drupal/easy_breadcrumb

Adds current page as an unlinked crumb. Edit / Hide home link, exclude pages, display unlinked paths.

Menu Breadcrumb

Allows constructing a breadcrumb trail based on the active menu trail. Useful when aliases don’t match the menu trail and it is important to use the menu as a primary reference for the breadcrumb.

Install using composer

composer require drupal/menu_breadcrumb

Allows for easy exclusion of certain menus.

Review History

Who

When

Status

Bob

20230531

Current

  • No labels