X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fmodules%2Fcontrib%2Fmetatag%2Fmetatag.module;fp=web%2Fmodules%2Fcontrib%2Fmetatag%2Fmetatag.module;h=2732fcc068b42577fa5dff2743882dcbf825f495;hp=0cf71ec0e779b3d8affae1cd4a21302efd8ccb37;hb=af6d1fb995500ae68849458ee10d66abbdcfb252;hpb=680c79a86e3ed402f263faeac92e89fb6d9edcc0 diff --git a/web/modules/contrib/metatag/metatag.module b/web/modules/contrib/metatag/metatag.module index 0cf71ec0e..2732fcc06 100644 --- a/web/modules/contrib/metatag/metatag.module +++ b/web/modules/contrib/metatag/metatag.module @@ -7,11 +7,14 @@ use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; +use Drupal\taxonomy\TermInterface; +use Drupal\Component\Utility\Html; /** * Implements hook_help(). @@ -33,7 +36,6 @@ function metatag_help($route_name, RouteMatchInterface $route_match) { $output .= '
  • ' . t('To override the meta tags for individual entities, e.g. for individual nodes, add the "Metatag" field via the field settings for that entity or bundle type.') . '
  • '; $output .= ''; return $output; - break; // The main configuration page. case 'entity.metatag_defaults.collection': @@ -42,14 +44,12 @@ function metatag_help($route_name, RouteMatchInterface $route_match) { $output .= '

    ' . t('If the top-level configuration is not specific enough, additional default meta tag configurations can be added for a specific entity type or entity bundle, e.g. for a specific content type.') . '

    '; $output .= '

    ' . t('Meta tags can be further refined on a per-entity basis, e.g. for individual nodes, by adding the "Metatag" field to that entity type through its normal field settings pages.') . '

    '; return $output; - break; // The 'add default meta tags' configuration page. case 'entity.metatag_defaults.add_form': $output = '

    ' . t('Use the following form to override the global default meta tags for a specific entity type or entity bundle. In practical terms, this allows the meta tags to be customized for a specific content type or taxonomy vocabulary, so that its content will have different meta tags default values than others.') . '

    '; $output .= '

    ' . t('As a reminder, if the "Metatag" field is added to the entity type through its normal field settings, the meta tags can be further refined on a per entity basis; this allows each node to have its meta tags customized on an individual basis.') . '

    '; return $output; - break; } } @@ -112,22 +112,73 @@ function metatag_page_attachments(array &$attachments) { if (is_null($metatag_attachments)) { // Load the meta tags from the route. $metatag_attachments = metatag_get_tags_from_route(); - if (!$metatag_attachments) { - return NULL; + } + if (!$metatag_attachments) { + return NULL; + } + + // If any Metatag items were found, append them. + if (!empty($metatag_attachments['#attached']['html_head'])) { + if (empty($attachments['#attached'])) { + $attachments['#attached'] = []; + } + if (empty($attachments['#attached']['html_head'])) { + $attachments['#attached']['html_head'] = []; } - // If any Metatag items were found, append them. - if (!empty($metatag_attachments['#attached']['html_head'])) { - if (empty($attachments['#attached'])) { - $attachments['#attached'] = []; - } - if (empty($attachments['#attached']['html_head'])) { - $attachments['#attached']['html_head'] = []; - } - foreach ($metatag_attachments['#attached']['html_head'] as $item) { - $attachments['#attached']['html_head'][] = $item; + $head_links = []; + foreach ($metatag_attachments['#attached']['html_head'] as $item) { + $attachments['#attached']['html_head'][] = $item; + + // Also add a HTTP header "Link:" for canonical URLs and shortlinks. + // See HtmlResponseAttachmentsProcessor::processHtmlHeadLink() for the + // implementation of the functionality in core. + if (in_array($item[1], ['canonical_url', 'shortlink'])) { + $attributes = $item[0]['#attributes']; + + $href = '<' . Html::escape($attributes['href']) . '>'; + unset($attributes['href']); + if ($param = drupal_http_header_attributes($attributes)) { + $href .= ';' . $param; + } + $head_links[] = $href; } } + + // If any HTTP Header items were found, add them too. + if (!empty($head_links)) { + $attachments['#attached']['http_header'][] = [ + 'Link', + implode(', ', $head_links), + FALSE, + ]; + } + } +} + +/** + * Implements hook_module_implements_alter(). + */ +function metatag_module_implements_alter(&$implementations, $hook) { + if ($hook == 'page_attachments_alter') { + // Move metatag_page_attachments_alter() to the end of the list. This is so + // the canonical and shortlink tags can be removed that are added by + // taxonomy_page_attachments_alter(). + // @todo Remove once https://www.drupal.org/node/2282029 is fixed. + $group = $implementations['metatag']; + unset($implementations['metatag']); + $implementations['metatag'] = $group; + } +} + +/** + * Implements hook_page_attachments_alter(). + */ +function metatag_page_attachments_alter(array &$attachments) { + $route_match = \Drupal::routeMatch(); + // Can be removed once https://www.drupal.org/node/2282029 is fixed. + if ($route_match->getRouteName() == 'entity.taxonomy_term.canonical' && ($term = $route_match->getParameter('taxonomy_term')) && $term instanceof TermInterface) { + _metatag_remove_duplicate_entity_tags($attachments); } } @@ -135,22 +186,41 @@ function metatag_page_attachments(array &$attachments) { * Implements hook_entity_view_alter(). */ function metatag_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) { - // Some entities are built with a link rel="canonical" and/or link rel="shortlink" tag attached. + // If this is a 403 or 404 page then don't output these meta tags. + // @todo Make the default meta tags load properly so this is unnecessary. + if ($display->getOriginalId() == 'node.403.default' || $display->getOriginalId() == 'node.404.default') { + $build['#attached']['html_head_link'] = []; + return; + } + + _metatag_remove_duplicate_entity_tags($build); +} + +/** + * Remove duplicate entity tags from a build. + * + * @param array $build + * The build. + */ +function _metatag_remove_duplicate_entity_tags(array &$build) { + // Some entities are built with a link rel="canonical" and/or link + // rel="shortlink" tag attached. // If metatag provides them, remove the ones built with the entity. if (isset($build['#attached']['html_head_link'])) { - $metatag_attachments = drupal_static('metatag_attachments'); + $metatag_attachments = &drupal_static('metatag_attachments'); if (is_null($metatag_attachments)) { // Load the meta tags from the route. $metatag_attachments = metatag_get_tags_from_route(); } - // Check to see if the page currently outputs a canonical and/or shortlink tag. + // Check to see if the page currently outputs a canonical and/or shortlink + // tag. if (isset($metatag_attachments['#attached']['html_head'])) { foreach ($metatag_attachments['#attached']['html_head'] as $metatag_item) { - if (in_array($metatag_item[1], array('canonical_url', 'shortlink'))) { + if (in_array($metatag_item[1], ['canonical_url', 'shortlink'])) { // Metatag provides rel="canonical" and/or rel="shortlink" tags. foreach ($build['#attached']['html_head_link'] as $key => $item) { - if (isset($item[0]['rel']) && in_array($item[0]['rel'], array('canonical', 'shortlink'))) { + if (isset($item[0]['rel']) && in_array($item[0]['rel'], ['canonical', 'shortlink'])) { // Remove the link rel="canonical" or link rel="shortlink" tag // from the entity's build array. unset($build['#attached']['html_head_link'][$key]); @@ -187,7 +257,7 @@ function metatag_is_current_route_supported() { /** * Returns the entity of the current route. * - * @return EntityInterface + * @return Drupal\Core\Entity\EntityInterface * The entity or NULL if this is not an entity route. */ function metatag_get_route_entity() { @@ -196,22 +266,22 @@ function metatag_get_route_entity() { // Look for a canonical entity view page, e.g. node/{nid}, user/{uid}, etc. $matches = []; - preg_match('/entity\.(.*)\.canonical/', $route_name, $matches); + preg_match('/entity\.(.*)\.(latest[_-]version|canonical)/', $route_name, $matches); if (!empty($matches[1])) { $entity_type = $matches[1]; return $route_match->getParameter($entity_type); } - // Look for a rest entity view page, e.g. node/{nid}?_format=json, etc. + // Look for a rest entity view page, e.g. "node/{nid}?_format=json", etc. $matches = []; - // ie: rest.entity.node.GET.json + // Matches e.g. "rest.entity.node.GET.json". preg_match('/rest\.entity\.(.*)\.(.*)\.(.*)/', $route_name, $matches); if (!empty($matches[1])) { $entity_type = $matches[1]; return $route_match->getParameter($entity_type); } - // Look for entity object 'add' pages, e.g. node/add/{bundle}. + // Look for entity object 'add' pages, e.g. "node/add/{bundle}". $route_name_matches = []; preg_match('/(entity\.)?(.*)\.add(_form)?/', $route_name, $route_name_matches); if (!empty($route_name_matches[2])) { @@ -229,7 +299,7 @@ function metatag_get_route_entity() { } } - // Look for entity object 'edit' pages, e.g. node/{entity_id}/edit. + // Look for entity object 'edit' pages, e.g. "node/{entity_id}/edit". $route_name_matches = []; preg_match('/entity\.(.*)\.edit_form/', $route_name, $route_name_matches); if (!empty($route_name_matches[1])) { @@ -244,7 +314,7 @@ function metatag_get_route_entity() { } // Look for entity object 'add content translation' pages, e.g. - // node/{nid}/translations/add/{source_lang}/{translation_lang} + // "node/{nid}/translations/add/{source_lang}/{translation_lang}". $route_name_matches = []; preg_match('/(entity\.)?(.*)\.content_translation_add/', $route_name, $route_name_matches); if (!empty($route_name_matches[2])) { @@ -294,7 +364,7 @@ function metatag_preprocess_html(&$variables) { return NULL; } - $attachments = drupal_static('metatag_attachments'); + $attachments = &drupal_static('metatag_attachments'); if (is_null($attachments)) { $attachments = metatag_get_tags_from_route(); } @@ -315,8 +385,10 @@ function metatag_preprocess_html(&$variables) { $variables['head_title'] = []; $variables['head_title']['title'] = html_entity_decode($attachment[0]['#attributes']['content'], ENT_QUOTES); // Original: - // $variables['head_title_array']['title'] = $attachment[0]['#attributes']['content']; - // $variables['head_title'] = implode(' | ', $variables['head_title_array']); + // $variables['head_title_array']['title'] = + // $attachment[0]['#attributes']['content']; + // $variables['head_title'] = implode(' | ', + // $variables['head_title_array']); break; } } @@ -327,20 +399,29 @@ function metatag_preprocess_html(&$variables) { * Load the meta tags by processing the route parameters. * * @return mixed - * Array of metatags or NULL. + * Array of meta tags or NULL. */ -function metatag_get_tags_from_route() { +function metatag_get_tags_from_route($entity = NULL) { $metatag_manager = \Drupal::service('metatag.manager'); // First, get defaults. - $metatags = metatag_get_default_tags(); + $metatags = metatag_get_default_tags($entity); if (!$metatags) { return NULL; } // Then, set tag overrides for this particular entity. - $entity = metatag_get_route_entity(); + if (!$entity) { + $entity = metatag_get_route_entity(); + } + if (!empty($entity) && $entity instanceof ContentEntityInterface) { + // If content entity does not have an ID the page is likely an "Add" page, + // so do not generate meta tags for entity which has not been created yet. + if (!$entity->id()) { + return NULL; + } + foreach ($metatag_manager->tagsFromEntity($entity) as $tag => $data) { $metatags[$tag] = $data; } @@ -362,7 +443,7 @@ function metatag_get_tags_from_route() { * @return mixed * Array of tags or NULL; */ -function metatag_get_default_tags() { +function metatag_get_default_tags($entity = NULL) { /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $global_metatag_manager */ $global_metatag_manager = \Drupal::entityTypeManager()->getStorage('metatag_defaults'); // First we load global defaults. @@ -379,9 +460,11 @@ function metatag_get_default_tags() { // Next check if there is this page is an entity that has meta tags. else { - $entity = metatag_get_route_entity(); + if (!$entity) { + $entity = metatag_get_route_entity(); + } - if (!empty($entity)) { + if (!empty($entity) && $entity instanceof ContentEntityInterface) { $entity_metatags = $global_metatag_manager->load($entity->getEntityTypeId()); if ($entity_metatags != NULL) { // Merge with global defaults. @@ -399,3 +482,100 @@ function metatag_get_default_tags() { return $metatags->get('tags'); } + +/** + * Implements hook_entity_base_field_info(). + */ +function metatag_entity_base_field_info(EntityTypeInterface $entity_type) { + $fields = []; + $base_table = $entity_type->getBaseTable(); + $canonical_template_exists = $entity_type->hasLinkTemplate('canonical'); + // Certain classes are just not supported. + $original_class = $entity_type->getOriginalClass(); + $classes_to_skip = [ + 'Drupal\comment\Entity\Comment', + ]; + + // If the entity type doesn't have a base table, has no link template then + // there's no point in supporting it. + if (!empty($base_table) && $canonical_template_exists && !in_array($original_class, $classes_to_skip)) { + $fields['metatag'] = BaseFieldDefinition::create('map') + ->setLabel(t('Metatags')) + ->setDescription(t('The meta tags for the entity.')) + ->setClass('\Drupal\metatag\Plugin\Field\MetatagEntityFieldItemList') + ->setQueryable(FALSE) + ->setComputed(TRUE) + ->setTargetEntityTypeId($entity_type->id()); + } + + return $fields; +} + +/** + * Implements hook_entity_diff_options(). + */ +function metatag_entity_diff_options($entity_type) { + if (metatag_entity_supports_metatags($entity_type)) { + $options = [ + 'metatag' => t('Metatags'), + ]; + return $options; + } +} + +/** + * Implements hook_entity_diff(). + */ +function metatag_entity_diff($old_entity, $new_entity, $context) { + $result = []; + $entity_type = $context['entity_type']; + $options = variable_get('diff_additional_options_' . $entity_type, []); + if (!empty($options['metatag']) && metatag_entity_supports_metatags($entity_type)) { + // Find meta tags that are set on either the new or old entity. + $tags = []; + foreach (['old' => $old_entity, 'new' => $new_entity] as $entity_key => $entity) { + $language = metatag_entity_get_language($entity_type, $entity); + if (isset($entity->metatags[$language])) { + foreach ($entity->metatags[$language] as $key => $value) { + $tags[$key][$entity_key] = $value['value']; + } + } + } + + $init_weight = 100; + foreach ($tags as $key => $values) { + $id = ucwords('Meta ' . $key); + // @todo Find the default values and show these if not set. + $result[$id] = [ + '#name' => $id, + '#old' => [empty($values['old']) ? '' : $values['old']], + '#new' => [empty($values['new']) ? '' : $values['new']], + '#weight' => $init_weight++, + '#settings' => [ + 'show_header' => TRUE, + ], + ]; + } + } + return $result; +} + +/** + * Turn the meta tags for an entity into a human readable structure. + * + * @param object $entity + * The entity object. + * + * @return array + * All of the meta tags in a nested structure. + */ +function metatag_generate_entity_metatags($entity) { + $values = []; + $raw = metatag_get_tags_from_route($entity); + if (!empty($raw['#attached']['html_head'])) { + foreach ($raw['#attached']['html_head'] as $tag) { + $values[$tag[1]] = $tag[0]; + } + } + return $values; +}