diff --git a/composer.json b/composer.json index fdb70b8e51f01c04d3ca07deca595ac44d041b1c..7df0a14f6ed0ef23b7553dbde1a5eb8152b58967 100644 --- a/composer.json +++ b/composer.json @@ -137,7 +137,7 @@ "drupal/media_entity_twitter": "2.7", "drupal/menu_block": "1.7", "drupal/menu_breadcrumb": "1.16", - "drupal/metatag": "1.16", + "drupal/metatag": "1.22", "drupal/migrate_devel": "2.0-alpha2", "drupal/migrate_plus": "5.1", "drupal/migrate_tools": "5.0", diff --git a/composer.lock b/composer.lock index 9f77354148422507b345157c7ec0d5e1b573994d..18d3336eddf33dc7dea5bac45a6ee6b6dba79f60 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "34725321c1b77f13acdd41e96c52fb5d", + "content-hash": "5b54bf74b259b7c0da89b3daee4b3177", "packages": [ { "name": "alchemy/zippy", @@ -5638,35 +5638,38 @@ }, { "name": "drupal/metatag", - "version": "1.16.0", + "version": "1.22.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/metatag.git", - "reference": "8.x-1.16" + "reference": "8.x-1.22" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/metatag-8.x-1.16.zip", - "reference": "8.x-1.16", - "shasum": "1c0028f4ff4583dc6601035657dd631c351b290c" + "url": "https://ftp.drupal.org/files/projects/metatag-8.x-1.22.zip", + "reference": "8.x-1.22", + "shasum": "045cd6a4aa5048bfd6d47584eae1210eab9ba1fa" }, "require": { - "drupal/core": "^8 || ^9", + "drupal/core": "^9.3 || ^10", "drupal/token": "^1.0" }, "require-dev": { - "drupal/devel": "^4.0", + "drupal/devel": "^4.0 || ^5.0", + "drupal/hal": "^9 || ^1 || ^2", "drupal/metatag_dc": "*", "drupal/metatag_open_graph": "*", - "drupal/page_manager": "4.x-dev", - "drupal/panelizer": "4.x-dev", - "drupal/redirect": "1.x-dev" + "drupal/page_manager": "^4.0", + "drupal/panelizer": "^4.0", + "drupal/redirect": "^1.0", + "drupal/webprofiler": "^9 || ^10", + "mpyw/phpunit-patch-serializable-comparison": "*" }, "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.16", - "datestamp": "1615820867", + "version": "8.x-1.22", + "datestamp": "1664472988", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -12949,16 +12952,16 @@ }, { "name": "symfony/console", - "version": "v4.4.48", + "version": "v4.4.49", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8e70c1cab07ac641b885ce80385b9824a293c623" + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8e70c1cab07ac641b885ce80385b9824a293c623", - "reference": "8e70c1cab07ac641b885ce80385b9824a293c623", + "url": "https://api.github.com/repos/symfony/console/zipball/33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", "shasum": "" }, "require": { @@ -13019,7 +13022,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.48" + "source": "https://github.com/symfony/console/tree/v4.4.49" }, "funding": [ { @@ -13035,7 +13038,7 @@ "type": "tidelift" } ], - "time": "2022-10-26T16:02:45+00:00" + "time": "2022-11-05T17:10:16+00:00" }, { "name": "symfony/css-selector", @@ -13981,16 +13984,16 @@ }, { "name": "symfony/http-foundation", - "version": "v4.4.48", + "version": "v4.4.49", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "cd4f478e67f7c8776a13b17e7d44241fd66261ad" + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/cd4f478e67f7c8776a13b17e7d44241fd66261ad", - "reference": "cd4f478e67f7c8776a13b17e7d44241fd66261ad", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", "shasum": "" }, "require": { @@ -14029,7 +14032,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v4.4.48" + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" }, "funding": [ { @@ -14045,20 +14048,20 @@ "type": "tidelift" } ], - "time": "2022-10-12T09:40:54+00:00" + "time": "2022-11-04T16:17:57+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.48", + "version": "v4.4.49", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "a6d5229dd9466e046674baad8449ad92ee24eddd" + "reference": "4e36db8103062c62b3882b1bd297b02de6b021c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a6d5229dd9466e046674baad8449ad92ee24eddd", - "reference": "a6d5229dd9466e046674baad8449ad92ee24eddd", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4e36db8103062c62b3882b1bd297b02de6b021c4", + "reference": "4e36db8103062c62b3882b1bd297b02de6b021c4", "shasum": "" }, "require": { @@ -14133,7 +14136,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v4.4.48" + "source": "https://github.com/symfony/http-kernel/tree/v4.4.49" }, "funding": [ { @@ -14149,7 +14152,7 @@ "type": "tidelift" } ], - "time": "2022-10-28T16:49:22+00:00" + "time": "2022-11-28T17:58:43+00:00" }, { "name": "symfony/mime", diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index ffdd21e44532e2cbfd39d705b77904f4e5d20bf4..4b93041f3ef1f8d2c0cb85f42d0a93403e5cab9f 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -5832,36 +5832,39 @@ }, { "name": "drupal/metatag", - "version": "1.16.0", - "version_normalized": "1.16.0.0", + "version": "1.22.0", + "version_normalized": "1.22.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/metatag.git", - "reference": "8.x-1.16" + "reference": "8.x-1.22" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/metatag-8.x-1.16.zip", - "reference": "8.x-1.16", - "shasum": "1c0028f4ff4583dc6601035657dd631c351b290c" + "url": "https://ftp.drupal.org/files/projects/metatag-8.x-1.22.zip", + "reference": "8.x-1.22", + "shasum": "045cd6a4aa5048bfd6d47584eae1210eab9ba1fa" }, "require": { - "drupal/core": "^8 || ^9", + "drupal/core": "^9.3 || ^10", "drupal/token": "^1.0" }, "require-dev": { - "drupal/devel": "^4.0", + "drupal/devel": "^4.0 || ^5.0", + "drupal/hal": "^9 || ^1 || ^2", "drupal/metatag_dc": "*", "drupal/metatag_open_graph": "*", - "drupal/page_manager": "4.x-dev", - "drupal/panelizer": "4.x-dev", - "drupal/redirect": "1.x-dev" + "drupal/page_manager": "^4.0", + "drupal/panelizer": "^4.0", + "drupal/redirect": "^1.0", + "drupal/webprofiler": "^9 || ^10", + "mpyw/phpunit-patch-serializable-comparison": "*" }, "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.16", - "datestamp": "1615820867", + "version": "8.x-1.22", + "datestamp": "1664472988", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -13451,17 +13454,17 @@ }, { "name": "symfony/console", - "version": "v4.4.48", - "version_normalized": "4.4.48.0", + "version": "v4.4.49", + "version_normalized": "4.4.49.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8e70c1cab07ac641b885ce80385b9824a293c623" + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8e70c1cab07ac641b885ce80385b9824a293c623", - "reference": "8e70c1cab07ac641b885ce80385b9824a293c623", + "url": "https://api.github.com/repos/symfony/console/zipball/33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", "shasum": "" }, "require": { @@ -13496,7 +13499,7 @@ "symfony/lock": "", "symfony/process": "" }, - "time": "2022-10-26T16:02:45+00:00", + "time": "2022-11-05T17:10:16+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -13524,7 +13527,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.48" + "source": "https://github.com/symfony/console/tree/v4.4.49" }, "funding": [ { @@ -14522,17 +14525,17 @@ }, { "name": "symfony/http-foundation", - "version": "v4.4.48", - "version_normalized": "4.4.48.0", + "version": "v4.4.49", + "version_normalized": "4.4.49.0", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "cd4f478e67f7c8776a13b17e7d44241fd66261ad" + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/cd4f478e67f7c8776a13b17e7d44241fd66261ad", - "reference": "cd4f478e67f7c8776a13b17e7d44241fd66261ad", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", "shasum": "" }, "require": { @@ -14545,7 +14548,7 @@ "predis/predis": "~1.0", "symfony/expression-language": "^3.4|^4.0|^5.0" }, - "time": "2022-10-12T09:40:54+00:00", + "time": "2022-11-04T16:17:57+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -14573,7 +14576,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v4.4.48" + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" }, "funding": [ { @@ -14593,17 +14596,17 @@ }, { "name": "symfony/http-kernel", - "version": "v4.4.48", - "version_normalized": "4.4.48.0", + "version": "v4.4.49", + "version_normalized": "4.4.49.0", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "a6d5229dd9466e046674baad8449ad92ee24eddd" + "reference": "4e36db8103062c62b3882b1bd297b02de6b021c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a6d5229dd9466e046674baad8449ad92ee24eddd", - "reference": "a6d5229dd9466e046674baad8449ad92ee24eddd", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4e36db8103062c62b3882b1bd297b02de6b021c4", + "reference": "4e36db8103062c62b3882b1bd297b02de6b021c4", "shasum": "" }, "require": { @@ -14652,7 +14655,7 @@ "symfony/console": "", "symfony/dependency-injection": "" }, - "time": "2022-10-28T16:49:22+00:00", + "time": "2022-11-28T17:58:43+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -14680,7 +14683,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v4.4.48" + "source": "https://github.com/symfony/http-kernel/tree/v4.4.49" }, "funding": [ { diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index bddb3ca2ac92d546f00cc08684d0b9f8400d93b0..37855adc02f4b9edff0643ac6abf8dd9183c0793 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'osu-asc-webservices/d8-upstream', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '429f72e15c8ceea994931b8d1abf14e67c0e8c20', + 'reference' => 'b32d6543d3f3958296e85fa3c3e6faf263f8a478', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -983,9 +983,9 @@ 'dev_requirement' => false, ), 'drupal/metatag' => array( - 'pretty_version' => '1.16.0', - 'version' => '1.16.0.0', - 'reference' => '8.x-1.16', + 'pretty_version' => '1.22.0', + 'version' => '1.22.0.0', + 'reference' => '8.x-1.22', 'type' => 'drupal-module', 'install_path' => __DIR__ . '/../../web/modules/metatag', 'aliases' => array(), @@ -1594,7 +1594,7 @@ 'osu-asc-webservices/d8-upstream' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '429f72e15c8ceea994931b8d1abf14e67c0e8c20', + 'reference' => 'b32d6543d3f3958296e85fa3c3e6faf263f8a478', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -2163,9 +2163,9 @@ 'dev_requirement' => false, ), 'symfony/console' => array( - 'pretty_version' => 'v4.4.48', - 'version' => '4.4.48.0', - 'reference' => '8e70c1cab07ac641b885ce80385b9824a293c623', + 'pretty_version' => 'v4.4.49', + 'version' => '4.4.49.0', + 'reference' => '33fa45ffc81fdcc1ca368d4946da859c8cdb58d9', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), @@ -2286,18 +2286,18 @@ 'dev_requirement' => false, ), 'symfony/http-foundation' => array( - 'pretty_version' => 'v4.4.48', - 'version' => '4.4.48.0', - 'reference' => 'cd4f478e67f7c8776a13b17e7d44241fd66261ad', + 'pretty_version' => 'v4.4.49', + 'version' => '4.4.49.0', + 'reference' => '191413c7b832c015bb38eae963f2e57498c3c173', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-foundation', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-kernel' => array( - 'pretty_version' => 'v4.4.48', - 'version' => '4.4.48.0', - 'reference' => 'a6d5229dd9466e046674baad8449ad92ee24eddd', + 'pretty_version' => 'v4.4.49', + 'version' => '4.4.49.0', + 'reference' => '4e36db8103062c62b3882b1bd297b02de6b021c4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-kernel', 'aliases' => array(), diff --git a/vendor/symfony/console/Exception/InvalidOptionException.php b/vendor/symfony/console/Exception/InvalidOptionException.php index b2eec61658d33bbc2ddb1b6bc3c8f00209527308..5cf62792e43c80b1a67c7ebd2644f4853a700397 100644 --- a/vendor/symfony/console/Exception/InvalidOptionException.php +++ b/vendor/symfony/console/Exception/InvalidOptionException.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Console\Exception; /** - * Represents an incorrect option name typed in the console. + * Represents an incorrect option name or value typed in the console. * * @author Jérôme Tamarelle <jerome@tamarelle.net> */ diff --git a/vendor/symfony/http-foundation/IpUtils.php b/vendor/symfony/http-foundation/IpUtils.php index 8f30ee099164fd94db29a49876379018cd337576..de2112cfc70286eda845bf6d79fb8407de709924 100644 --- a/vendor/symfony/http-foundation/IpUtils.php +++ b/vendor/symfony/http-foundation/IpUtils.php @@ -124,6 +124,15 @@ public static function checkIp6($requestIp, $ip) throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".'); } + // Check to see if we were given a IP4 $requestIp or $ip by mistake + if (str_contains($requestIp, '.') || str_contains($ip, '.')) { + return self::$checkedIps[$cacheKey] = false; + } + + if (!filter_var($requestIp, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + return self::$checkedIps[$cacheKey] = false; + } + if (str_contains($ip, '/')) { [$address, $netmask] = explode('/', $ip, 2); diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php index 554e1a1602dd60ef281ca93702e1e84dcc963909..eb9c26a3b7ee8e58a5b4c06d9a7505cb5b00e0d4 100644 --- a/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php @@ -59,7 +59,7 @@ protected function matches($response): bool return false; } - return $this->value === $cookie->getValue(); + return $this->value === (string) $cookie->getValue(); } /** diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php index d4971cc1a507481c54c5f94c8f8c562c93544e69..48ea6e742d519da68f7fbde47900ca9d94d3de48 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php @@ -69,8 +69,9 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable } if (!$this->container->has($controller)) { - $i = strrpos($controller, ':'); - $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); + $controller = (false !== $i = strrpos($controller, ':')) + ? substr($controller, 0, $i).strtolower(substr($controller, $i)) + : $controller.'::__invoke'; } $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); diff --git a/vendor/symfony/http-kernel/Kernel.php b/vendor/symfony/http-kernel/Kernel.php index 54ea465379ba1b1b82ca577ea584d234ad4be367..be36bc63465509379d12cd6b1ee8f3dfe3257256 100644 --- a/vendor/symfony/http-kernel/Kernel.php +++ b/vendor/symfony/http-kernel/Kernel.php @@ -76,11 +76,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '4.4.48'; - public const VERSION_ID = 40448; + public const VERSION = '4.4.49'; + public const VERSION_ID = 40449; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 48; + public const RELEASE_VERSION = 49; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2022'; diff --git a/web/modules/metatag/CHANGELOG.txt b/web/modules/metatag/CHANGELOG.txt index 0631fc90050f28d0e1065af0fe840e448bd58431..4d28c22d9a52a1f21ca11e731c049b3266b4b0a0 100644 --- a/web/modules/metatag/CHANGELOG.txt +++ b/web/modules/metatag/CHANGELOG.txt @@ -1,3 +1,210 @@ +Metatag 8.x-1.22, 2022-09-29 +---------------------------- +#3299228 by DamienMcKenna: Refactor favicon meta tags. +#3298081 by DamienMcKenna: Deprecate Google Plus meta tags. +#3299229 by DamienMcKenna, thejimbirch: Deprecate news_keywords, standout meta + tags. +#3300806 by heddn, DamienMcKenna: hreflang_per_language not in config schema. +#3302675 by DamienMcKenna: Fix $modules definitions in tests. +#3034248 by DanielVeza, chadmandoo, DamienMcKenna, jwilson3, justin2pin, InaW, + ChandeepKhosa, thejimbirch, pianomansam, FiNeX: Promote use of Token Or + module to make tokens more flexible. +#3302685 by DamienMcKenna: Tiny changes from tests refactoring. +#3303196 by DamienMcKenna: Add extra isSOMETHING() methods to MetaNameBase. +#3304779 by luigisa, DamienMcKenna: MetatagManager::processedTokenCache() does + not respect the entity language. +#3302969 by DamienMcKenna: Refactored MetaNameBase output logic. +#3252150 by andregp, DamienMcKenna, phenaproxima, Berdir, elber, japerry, + Kristen Pol: Drupal 10 compatibility. +#3305580 by DamienMcKenna: Deprecate Panelizer integration. +#3304488 by RandalV, DamienMcKenna: metatag_get_route_entity() does not check + if the entity parameter is an actual entity. +#3306039 by DamienMcKenna: Recover lost WebProfiler test script. +#3303424 by DamienMcKenna: Android, iOS app alternate link tags don't work + correctly. +#3306085 by DamienMcKenna, Berdir: Replace "bartik" theme in tests. +#3305322 by DamienMcKenna: Remove the verbose() test methods. +#2767107 by DamienMcKenna, Antares89: Add support for the Diff module. +#3311343 by Anybody, DamienMcKenna: Metatag routes misses package name SEO in + info.yml. +#2901039 by rcodina, tsplash, DamienMcKenna, Wannes DR, mErilainen, + weekbeforenext, natemow, mpp, borisson_, AMDandy, jenniferaube, klmd302: Add + a TypedData plugin to support Search API. +#3311542 by DamienMcKenna, lostcarpark, lucassc: Add new Metatag logo files, + update tests to use them. +#3024450 by DamienMcKenna, DantonMariano, Tаo, michaellenahan, mdmanouwer, + Ahmed.Raza, lexsoft00, ndobromirov, Endika Melero: Log when there are problems + unserializing the meta tag data. +#3309850 by DamienMcKenna: Skip token processing if there are no tokens in the + value. +#3305751 by DamienMcKenna: Fix coding standards issues. +#3311891 by DamienMcKenna, GiorgosK: MaskIcon::setValue() should not set a NULL + value. +#3311911 by DamienMcKenna: TypedData logic has an error. +#3261473 by DamienMcKenna, saidatom, claudiu.cristea, heddn, Evaldas Užkuras, + Eugene Bocharov: Views cache wrapper overrides other modules cache logic. + + +Metatag 8.x-1.21, 2022-07-16 +---------------------------- +#3268439 by Dave Reid: Follow-up to fix the scroll height feature. +#3295600 by DamienMcKenna, saranchuk_hys, Eugene Bocharov, Didier Misson, + loopy1492, Maplinx, W01F, jaydub, kazah: MaskIcon doesn't work properly. +#3295757 by sleitner, DamienMcKenna: Fix regression from Google tag fix. + + +Metatag 8.x-1.20, 2022-07-12 +---------------------------- +#3257588 by Eugene Bocharov, lobodacyril, jippie1948, Kasey_MK, djween, awasson, + DamienMcKenna, Valdes14, laura.florey, stacypendell: DB update hangs at + metatag 8109 - Update mask_icon values to the new structure. +#3258978 by heddn, DamienMcKenna: tokenize not in config schema for + metatag_display_extender. +#3258346 by Eugene Bocharov, jedgar1mx, 4kant, Renrhaf, DamienMcKenna, kriboogh: + Error: Call to a member function __wakeup() on null. +#3113761 by DamienMcKenna, thalles, rokzabukovec, Diego_Mow, urvashi_vora: + Coding standards cleanup. +#3261505 by DamienMcKenna, Eugene Bocharov, Sergiu Stici: In php 8.1 the explode + function throws a notice when default value is null. +#3265679 by DamienMcKenna: Additional coding standards bugs. +#3241256 by ndf, sabina.h, idebr, DamienMcKenna: Remove redundant HTTP headers + for canonical and short_link tags. +#3262308 by YahyaAlHamad, DamienMcKenna: metatag_update_8109 fails because of + unknown column. +#3261467 by DamienMcKenna, HnLn: in php 8.1 preg_match in + metatag_get_route_entity throws notice when route is null. +#3266326 by victoria-marina, Guilherme Rabelo, DamienMcKenna: Use Dependency + Injection in MetatagManager. +#3265567 by DamienMcKenna, Anatolij Zajika, PCate: PHP8 undefined array key + "description". +#3266406 by szato, DamienMcKenna: Don't assume the 'first_row_tokens' cache key + is defined. +#3264449 by DamienMcKenna, gilles_webstanz: Trim og:description doesn't work. +#3258427 by Eugene Bocharov, mrshowerman, saranchuk_hys, phthlaap, apaderno, + Kulturmensch, DamienMcKenna, quicksketch: TypeError: preg_match_all(): + Arg #2 ($subject) must be of type string, array given in preg_match_all(). +#3258358 by Eugene Bocharov, sashken2, DamienMcKenna, modernrockstar: Empty + values saved in 'mask_icon' meta tag. +#3269670 by DamienMcKenna, sd123: Trimming even trims metatags shorter than the + limit. +#3269742 by DamienMcKenna, z3cka: Migrate D7 Product Display node metatag data + to D9 Drupal Commerce Product entities. +#3280904 by DamienMcKenna, 3li: Automatic conversion of false to array is + deprecated. +#3278924 by lamp5, DamienMcKenna: Translation of title metatag is limited to + 128 characters. +#3271284 by Shashwat Purav: Double occurrences of word "the". +#3257520 by er.garg.karan, DamienMcKenna: Default Drupal favicon icon on core + before 9.3. +#3281987 by DamienMcKenna: Sort configuration items prior to saving. +#3284465 by DamienMcKenna, murilohp: Deprecated obsolete meta + http-equiv="content-language". +#3270951 by marciaibanez, tmaiochi, Guilherme Rabelo, chakkche, DamienMcKenna: + Coding standards improvements. +#3112509 by DamienMcKenna, ciprian.stavovei, Renrhaf, sitiveni: Convert + "author" tag to HTML 5.2 spec, deprecate Google+ Author tag. +#3280745 by DamienMcKenna, Anybody: Trimming should use multibyte functions. +#3112509 by DamienMcKenna: Fix regression in Google+ tests. +#2563655 by DamienMcKenna, waldomero: Absorb Metatag Routes module to allow + per-path/route configurations. +#3268439 by chakkche, bygeoffthompson, DamienMcKenna, Ruturaj Chaubey: Optional + overflow control on expanded Metatag field widget. +#3231981 by sanduhrs, DamienMcKenna: Add support for SIWECOS website security + scanner. +#3198100 by thejimbirch, DamienMcKenna, sriharsha.uppuluri: Two Google meta tags + conflict with each other. +#3077442 by daniel.bosen, DamienMcKenna, esdrasterrero, Vivek Panicker, + Supreetam09, rigoucr: Current language through the language manager doesn't + work (decoupled site). +#3295569 by DamienMcKenna: 8.x-1.x tests fail against PHP 7.3. + + +Metatag 8.x-1.19, 2022-01-06 +---------------------------- +#3104170 by DamienMcKenna, tobiasb, marcoliver, hosterholz, Berdir: Do not send + empty Metatag descriptions through translation. +#3255547 by Eugene Bocharov, Thomas Kaisuka, Stephen Ollman, glynster, oxy86, + Matthijs, Mahmoud Barhouma, DamienMcKenna, wells: View preview broken after + Metatag upgrade. +#3255731 by acbramley, DamienMcKenna, tim.anderson: Undefined array key errors + from metatag_update_8109. +#3256373 by DamienMcKenna, Kulturmensch: WebManifest::output() doesn't verify + output is array before adding new element. + + +Metatag 8.x-1.18, 2021-12-21 +---------------------------- +#3255342 by Eugene Bocharov, trickfun, DamienMcKenna, paulocs: Table + 'db.node__field_meta_tags' doesn't exist. + + +Metatag 8.x-1.17, 2021-12-20 +---------------------------- +#3210890 by DamienMcKenna: Convert the README.txt to a markdown file. +#3210433 by DamienMcKenna, byybora: Documented a solution for when the meta tags + are not output. +#2952229 by Charlie ChX Negyesi, DamienMcKenna, joseph.olstad, solide-echt: + Allow Views meta tags to "Use replacement tokens from the first row". +#3223680 by DamienMcKenna, Eugene Bocharov: Test errors 8.x-1.x branch with + Drupal 9.2. +#3219963 by AndyThornton, DamienMcKenna: _metatag_is_entity_route_entity static + cache problematic. +#3227367 by DamienMcKenna: Replace uses of static with drupal_static(). +#3228362 by narendraR, DamienMcKenna: SQL error when migrating non-UTF8 meta + tags. +#3230747 by segovia94, DamienMcKenna: Defaults UI page has malformed HTML + markup. +#3231725 by DamienMcKenna: Replace t() calls with (string) new + TranslatableMarkup(). +#3158395 by Kasey_MK, geekygnr, DamienMcKenna, mherchel: Avoid similar-sounding + links with different purposes. +#3204262 by jplanginier, DamienMcKenna: PHP version declared in composer.json + isn't valid regarding current code. +#3170178 by geekygnr, dionsj, DamienMcKenna: Allow widget to use regular + container instead of details. +#3243815 by DamienMcKenna, jastraat: 401 error on Web Manifest. +#3248439 by lamp5, DamienMcKenna: Schema for icon mask is missing. +#3248361 by COBadger, DamienMcKenna: Correct README.md instruction on adding + bundle defaults. +#3189429 by Eugene Bocharov, bwaindwain, nJim, DamienMcKenna: "title" token + doesn't work as expected. +#3244106 by Nikhilesh Gupta, nJim, DamienMcKenna: New coding standards: Inline + @var declarations should use the /** */ delimiters. +#3252359 by murilohp, DamienMcKenna: Remove workarounds for Drupal 8, update + references to say "Drupal 9". +#3252354 by tijsdeboeck, DamienMcKenna: Fix small typo in + metatag_extended_perms.info.yml. +#3240989 by anagomes, DamienMcKenna, Berdir: Not marking service definitions as + public is deprecated. +#2958193 by Grevil, Anybody, DamienMcKenna, nikhileshpaul: Automatically trim + meta tag lengths. +#3247678 by esolitos, DamienMcKenna: Support migration with multiple "d7_*" + sources. +#2914998 by JeroenT, DamienMcKenna, gngn, ytsurk: Add the mask icon "color" + attribute. +#3205932 by dalin, DamienMcKenna: Add noindex to "403 access denied" defaults. +#3229004 by larisse, Rar9, DamienMcKenna: Undefined index: hreflang in + metatag_hreflang_page_attachments_alter(). +#3190804 by DamienMcKenna, Wim Leers: Allow source counts to be cached: + implement ::doCount() instead of ::count(). +#3252159 by DamienMcKenna, Eugene Bocharov: Fix tests compatibility with Drupal + 9.3.x. +#3253736 by Dave Reid, zebda, DamienMcKenna: favicon meta tag was renamed in + Drupal 9.3.0. +#3223289 by DamienMcKenna, introfini: Added product:retailer_item_id. +#3230393 by introfini, DamienMcKenna: Added product:availability and + product:condition. +#3209938 by Sutharsan, murilohp, DamienMcKenna: Edit form title does not contain + path. +#3218647 by luisrhaas, DamienMcKenna, Anybody: Remove line breaks from meta tag + output. +#3254423 by andregp, DamienMcKenna: Replace deprecated APIs in tests. +#3254597 by DamienMcKenna: Remove Console integration. +#2761909 by roshkovanv, andrewsuth, greenSkin, plach, Boobaa, DamienMcKenna, + lmeurs, seancasey: og:image does not parse url from image field properly when + there is a comma in the alt field. + + Metatag 8.x-1.16, 2021-03-15 ---------------------------- #3186893 by DamienMcKenna: Document how to update from Metatag Access to Metatag diff --git a/web/modules/metatag/README.md b/web/modules/metatag/README.md new file mode 100644 index 0000000000000000000000000000000000000000..77476c6164cbd0e153c37764b98fbd2286ef4c4c --- /dev/null +++ b/web/modules/metatag/README.md @@ -0,0 +1,418 @@ +# Metatag + +This module allows a site's builder to automatically provide structured +metadata, aka "meta tags", about the site and individual pages. + +In the context of search engine optimization, providing an extensive set of +meta tags may help improve the site's and pages' rankings, thus may aid with +achieving a more prominent display of the content within search engine results. +They can also be used to tailor how content is displayed when shared on social +networks. + +For additional information, see the [online documentation](https://www.drupal.org/docs/8/modules/metatag). + +This version should work with all Drupal 9 releases, though it +is always recommended to keep Drupal core installations up to date. + +## Requirements + +Metatag for Drupal 9 requires the following: + +* [Token](https://www.drupal.org/project/token): Provides a popup browser to + see the available tokens for use in meta tag fields. + +## Features + +The primary features include: + +* An administration interface to manage default meta tags. + +* Use of standard fields for entity support, allowing for translation and + revisioning of meta tag values added for individual entities. + +* A large volume of meta tags available, covering commonly used tags, Open + Graph tags, Twitter Cards tags, Dublin Core tags, App Links tags, site + verification tags and more; all but the basic meta tags are kept in separate + submodules. + +* Configuration can be added for individual paths using the Metatag Custom + Routes submodule. + +* The fifteen Dublin Core Basic Element Set 1.1 meta tags may be added by + enabling the "Metatag: Dublin Core" submodule. + +* Forty additional Dublin Core meta tags may be added by enabling the "Metatag: + Dublin Core Advanced" submodule. + +* The Open Graph Protocol meta tags, as used by Facebook, Pinterest, LinkedIn + and other sites, may be added by enabling the "Metatag: Open Graph" submodule. + +* The Twitter Cards meta tags may be added by enabling the "Metatag: Twitter + Cards" submodule. + +* Facebook's fb:app_id, fb:admins and fb:pages meta tags may be added by + enabling the "Metatag: Facebook" submodule. These are useful for sites which + are using Facebook widgets or are building custom integration with Facebook's + APIs, but they are not needed by most sites and have no bearing on the + Open Graph meta tags. + +* The Pinterest meta tags may be added by enabling the "Metatag: Pinterest" + submodule. + +* Site verification meta tags can be added, e.g. as used by the Google search + engine to confirm ownership of the site; see the "Metatag: Verification" + submodule. + +* The Metatag: Mobile & UI Adjustments submodule adds the MobileOptimized, + HandheldFriendly, viewport, cleartype, theme-color, format-detection, + apple-mobile-web-app-capable, apple-mobile-web-app-status-bar-style, the + android-app and ios-app alternative link meta tags, and the Android manifest + tag. + +* The hreflang meta tags are available via the Metatag:hreflang submodule. + +* The App Links meta tags may be added by enabling the Metatag: App Links + submodule. + +* Support for meta tags specific to Google Custom Search Appliance are available + in the "Metatag: Google Custom Search Engine (CSE)" submodule. + +* Meta tags specific to Facebook are included in the "Metatag: Facebook" + submodule. + +* Individual meta tags can be added to the [Search + API](https://www.drupal.org/project/search_api) index if a Metatag field is + added to the entity bundles; see below for further details. + +* A plugin interface allowing for additional meta tags to be easily added via + custom modules. + +* A report page at /admin/reports/metatag-plugins which shows all of the meta + tag plugins provided on the site, and indication as to which module provides + them. + + +## Standard usage scenario + +1. Install the module. +2. Open admin/config/search/metatag. +3. Adjust global and entity defaults. Fill in reasonable default values for any + of the meta tags that need to be customized. Tokens may be used to + automatically assign values. +4. Additional bundle defaults may be added by clicking on "Add default meta + tags" and filling out the form. +5. To adjust meta tags for a specific entity, the Metatag field must be added + first. Follow these steps: + + * Go to the "Manage fields" of the bundle where the Metatag field is to + appear. + + * Select "Meta tags" from the "Add a new field" selector. + + * Fill in a label for the field, e.g. "Meta tags", and set an appropriate + machine name, e.g. "meta_tags". + + * Click the "Save and continue" button. + + * If the site supports multiple languages, and translations have been + enabled for this entity, select "Users may translate this field" to use + Drupal's translation system. + +Please note: no meta tags will be output while the site is in maintenance mode. + + +## Simplify the content administration experience + +This module and its submodules gives a site's content team the ability to add +every meta tag ever. The standard meta tag form added by the Metatag field on +content entities can be overwhelming to content creators and editors who just +need to manage a few options. + +The easiest way of simplifying this for content teams is to add new fields to +the content type for the meta data fields that are needed and skip adding the +Metatag field entirely, then use tokens for those fields in the defaults +(/admin/config/search/metatag). These fields can be used in the entity's +display, or just left hidden. + + +## Indexing meta tags with Search API + +The Search API integration allows indexing the meta tag values from a meta tag +field on an entity bundle. + +### Limitations + +* Each meta tag must be specified individually, there isn't (currently) a way to + add all of them at once. +* This may not work with values stored in Schema.org data structures from the + Schema.org Metatag module. +* Changing the global Metatag defaults will not trigger a reindex of the content + so this will need to be done separately. +* By default meta tags will be added as "string" fields, which will not include + them in the keyword search index; their "Type" selection must be specifically + set to "Fulltext" in order for the meta tags to be included in the keyword + search index, otherwise they will only be useful for doing facets or filters. + +### Setup + +To add meta tags to the Search API: + +* Make sure that a Metatag field is present on the entity bundle(s) that are + being indexed. +* In the index configuration, modify the Fields section. +* Click the "Add fields" button. +* In the "Add fields to index [indexname]" popup, scroll down to find the + Metatag field; it will have the name defined in the field's settings. +* Click the plus `(+)` button beside the field to see which meta tags are + available. +* Click the "Add" button for the meta tags that are needed. +* Click "Done" when all of the meta tags are added. +* Look for the meta tag fields added to the index, change their "type" selector + to "Fulltext"; adjust the "Boost" value if desired. +* Click "Save changes" at the bottom of the Fields admin page. +* Reindex the content with the new settings. + + +## Alternative option to simplify the content administration experience + +On the settings page (/admin/config/search/metatag/settings) are options to +control which meta tag groups are available for each entity bundle. This allows +e.g. the Favicon meta tags to be available for global configurations but to hide +them on entity forms. + + +## Programmatically assign meta tags to an entity + +There are two ways to assign an entity's meta tags in custom module. Both +scenarios require a "Metatag" field be added to the entity's field settings, the +field name "field_meta_tags" is used but this is completely arbitrary. + +Option 1: + +``` $entity_type = 'node'; +$values = [ + 'nid' => NULL, + 'type' => 'article', + 'title' => 'Testing metatag creation', + 'uid' => 1, + 'status' => TRUE, + 'field_meta_tags' => serialize([ + 'title' => 'Some title', + 'description' => 'Some description.', + 'keywords' => 'Some,Keywords', + ]), +]; +$node = \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->create($values); +$node->save(); +``` + +Option 2: + +```$node = Node::create([ + 'type' => article, + 'langcode' => 'en', + 'status' => 1, + 'uid' => 1, +]); +$node->set('title', 'Testing metatag creation'); +$node->set('field_meta_tags', serialize([ + 'title' => 'Some title', + 'description' => 'Some description.', + 'keywords' => 'Some,Keywords', +])); +$node->save(); +``` + +In both examples, the custom meta tag values will still be merged with the +values defined via the global defaults prior to being output - it is not +necessary to copy each value to the new record. + + +## Obtain meta tags for an entity + +For developers needing to access the rendered meta tags for a given entity, a +function is provided to make this easy to do: + +`$metatags = metatag_generate_entity_metatags($entity);` + +This will return an array with the following structure: + +``` + [ + 'title' => [ + '#tag' => 'meta', + '#attributes' => [ + 'name' => 'title', + 'content' => 'The What | D8.4', + ], + ], + 'canonical_url' => [ + '#tag' => 'link', + '#attributes' => [ + 'rel' => 'canonical', + 'href' => 'https://example.com/what', + ], + ], + 'description' => [ + '#tag' => 'meta', + '#attributes' => [ + 'name' => 'description', + 'content' => 'I can't even.', + ], + ], + 'generator' => [ + '#tag' => 'meta', + '#attributes' => [ + 'name' => 'generator', + 'content' => 'Drupal 9!', + ], + ], + ] +``` + +The meta tags are keyed off the meta tag plugin's ID, e.g. "generator". Each +meta tag is then provided as arguments suitable for use in a render array with +the type "html_tag". Extracting the value of the meta tag will depend upon the +type of meta tag, e.g. the generator meta tag uses the "content" attribute while +the link tag uses the "href" attribute. + + +## Migration / Upgrade from Drupal 6 or 7 + +An upgrade path from Nodewords on Drupal 6 or Metatag on Drupal 7 is provided. + +Two migration processes are supported: + +1. A guided migration using either the Migrate Drupal UI from core or the + [Migrate Upgrade](https://www.drupal.org/project/migrate_upgrade) + contributed module. This will automatically create a field named + "field_metatag" and import any meta tag data that existed in Nodewords on D6 + or Metatag on D7. + + This migration configuration is all prepared in + metatag_migration_plugins_alter(), the data is loaded onto the migrated + entity in metatag_migrate_prepare_row(), and then the data is remapped in + either \Drupal\metatag\Plugin\migrate\process\d6\NodewordsEntities or + \Drupal\metatag\Plugin\migrate\process\d7\MetatagEntities depending upon + what the source is. + +2. A custom migration using [Migrate + Plus](https://www.drupal.org/project/migrate_plus) and possibly [Migrate + Tools](https://www.drupal.org/project/migrate_tools). + This will require manually creating the meta tag fields and assigning a + custom process plugin as the source for its data. For example, if the name + of the field is "field_meta_tags" the lines from the "process" section of + the migration yml file would need to look line the following: + + For migrating from Nodewords on D6: + +```process: +... + field_meta_tags: + plugin: d6_nodewords_entities + source: pseudo_metatag_entities +... +``` + + For Migrating from Metatag on D7: + +```process: +... + field_meta_tags: + plugin: d7_metatag_entities + source: pseudo_metatag_entities +... +``` + + The important items are the "plugin" and the "source" values, if these are + not present the migration will not work as expected. + + The data will then be loaded into the migrating entity using + metatag_migrate_prepare_row(). + + See also: + * \Drupal\metatag\Plugin\migrate\process\d6\NodewordsEntities + * \Drupal\metatag\Plugin\migrate\process\d7\MetatagEntities + + +## Related modules + +Some modules are available that extend Metatag with additional or complimentary +functionality: + +* [Token OR](https://www.drupal.org/project/token_or): + Provides a means to output a second token if the first one is empty, which can + be very useful for complex content architectures. + +* [Schema.org Metatag](https://www.drupal.org/project/schema_metatag): + Extensive solution for adding schema.org / JSON-LD support to Metatag. + +* [Context Metadata](https://www.drupal.org/project/context_metadata): + Allow assignment of meta tags based upon different system contexts, e.g. per + path. + +* [Real-time SEO for Drupal](https://www.drupal.org/project/yoast_seo): + Uses the [YoastSEO.js library and service](https://yoast.com/) to provide + realtime feedback on the meta tags. + +* [Metatag Cxense](https://www.drupal.org/project/metatag_cxense): + Adds support for the Cxense meta tags used by their DMP and Insight services. + +* [Metatag Google Scholar](https://www.drupal.org/project/metatag_google_scholar): + Adds support for a number of meta tags used with the Google Scholar system. + + +## Known issues + +### Uninstalling Metatag + +In order to uninstall the module any "Metatag" fields must first be removed +from all entities. In order to see whether there are fields blocking the +module from being uninstalled, load the module uninstall page +(admin/modules/uninstall) and see if any are listed, it will look something +like the following: + +`The Meta tags field type is used in the following field: +node.field_meta_tags` + +In order to uninstall the module, go to the appropriate field settings pages +and remove the Metatag field listed in the message. Once this is done it will +be possible to uninstall the module. + +### Meta tags are not displayed + +In order for the meta tags to be displayed on the page the html.html.twig file +must output the main `{{ page }}` element. If the meta tags are not visible on +the page check, to see if the html.html.twig instead contains this: + +`{{ page.content }}` + +To fix this, simply change that line back to `{{ page }}` and it should work. + +## Credits / contact + +Currently maintained by [Damien +McKenna](https://www.drupal.org/u/damienmckenna). Drupal 7 module originally +written by [Dave Reid](https://www.drupal.org/u/dave-reid). Early work on +Drupal 8 port by Damien McKenna and [Michelle +Cox](https://www.drupal.org/u/michelle), and sponsored by +[Mediacurrent](https://www.mediacurrent.com/); key improvements by [Juampy +Novillo Requena](https://www.drupal.org/u/juampynr) with insights from Dave +Reid and sponsorship by [Lullabot](https://www.lullabot.com/) and +[Acquia](https://www.acquia.com/). Additional contributions to the 8.x-1.0 +release from [cilefen](https://www.drupal.org/u/cilefen), [Daniel +Wehner](https://www.drupal.org/u/dawehner), [Jesus Manuel +Olivas](https://www.drupal.org/u/jmolivas), [Lee +Rowlands](https://www.drupal.org/u/larowlan), [Michael +Kandelaars](https://www.drupal.org/u/mikeyk), [Ivo Van +Geertruyen](https://www.drupal.org/u/mr.baileys), [Nikhilesh +Gupta](https://www.drupal.org/u/nikhilesh-gupta), [Rakesh +James](https://www.drupal.org/u/rakeshgectcr), and many others. + +Ongoing development is sponsored by [Mediacurrent](https://www.mediacurrent.com/). + +The best way to contact the authors is to submit an issue, be it a support +request, a feature request or a bug report, in the [project issue +queue](https://www.drupal.org/project/issues/metatag). diff --git a/web/modules/metatag/README.txt b/web/modules/metatag/README.txt deleted file mode 100644 index 635559b50468a451c614af88c237bc74a535ca4d..0000000000000000000000000000000000000000 --- a/web/modules/metatag/README.txt +++ /dev/null @@ -1,395 +0,0 @@ -Metatag -------- -This module allows a site's builder to automatically provide structured -metadata, aka "meta tags", about the site and individual pages. - -In the context of search engine optimization, providing an extensive set of -meta tags may help improve the site's and pages' rankings, thus may aid with -achieving a more prominent display of the content within search engine results. -They can also be used to tailor how content is displayed when shared on social -networks. - -For additional information, see the online documentation: - https://www.drupal.org/docs/8/modules/metatag - -This version should work with all Drupal 8 releases, though it is always -recommended to keep Drupal core installations up to date. - - -Requirements --------------------------------------------------------------------------------- -Metatag for Drupal 8 requires the following: - -* Token - https://www.drupal.org/project/token - Provides a popup browser to see the available tokens for use in meta tag - fields. - - -Features --------------------------------------------------------------------------------- -The primary features include: - -* An administration interface to manage default meta tags. - -* Use of standard fields for entity support, allowing for translation and - revisioning of meta tag values added for individual entities. - -* A large volume of meta tags available, covering commonly used tags, Open - Graph tags, Twitter Cards tags, Dublin Core tags, Google+ tags, App Links - tags, site verification tags and more; all but the basic meta tags are kept - in separate submodules. - -* The fifteen Dublin Core Basic Element Set 1.1 meta tags may be added by - enabling the "Metatag: Dublin Core" submodule. - -* Forty additional Dublin Core meta tags may be added by enabling the "Metatag: - Dublin Core Advanced" submodule. - -* The Open Graph Protocol meta tags, as used by Facebook, Pinterest, LinkedIn - and other sites, may be added by enabling the "Metatag: Open Graph" submodule. - -* The Twitter Cards meta tags may be added by enabling the "Metatag: Twitter - Cards" submodule. - -* Certain meta tags used by Google+ may be added by enabling the "Metatag: - Google+" submodule. - -* Facebook's fb:app_id, fb:admins and fb:pages meta tags may be added by - enabling the "Metatag: Facebook" submodule. These are useful for sites which - are using Facebook widgets or are building custom integration with Facebook's - APIs, but they are not needed by most sites and have no bearing on the - Open Graph meta tags. - -* The Pinterest meta tags may be added by enabling the "Metatag: Pinterest" - submodule. - -* Site verification meta tags can be added, e.g. as used by the Google search - engine to confirm ownership of the site; see the "Metatag: Verification" - submodule. - -* The Metatag: Mobile & UI Adjustments submodule adds the MobileOptimized, - HandheldFriendly, viewport, cleartype, theme-color, format-detection, - apple-mobile-web-app-capable, apple-mobile-web-app-status-bar-style, the - android-app and ios-app alternative link meta tags, and the Android manifest - tag. - -* The hreflang meta tags are available via the Metatag:hreflang submodule. - -* The App Links meta tags may be added by enabling the Metatag: App Links - submodule. - -* Support for meta tags specific to Google Custom Search Appliance are available - in the "Metatag: Google Custom Search Engine (CSE)" submodule. - -* Meta tags specific to Facebook are included in the "Metatag: Facebook" - submodule. - -* A plugin interface allowing for additional meta tags to be easily added via - custom modules. - -* Integration with DrupalConsole [1] to provide a quick method of generating new - meta tags. - -* A report page at /admin/reports/metatag-plugins which shows all of the meta - tag plugins provided on the site, and indication as to which module provides - them. - - -Standard usage scenario --------------------------------------------------------------------------------- -1. Install the module. -2. Open admin/config/search/metatag. -3. Adjust global and entity defaults. Fill in reasonable default values for any - of the meta tags that need to be customized. Tokens may be used to - automatically assign values. -4. Additional bundle defaults may be added by clicking on "Add metatag - defaults" and filling out the form. -5. To adjust meta tags for a specific entity, the Metatag field must be added - first. Follow these steps: - - 5.1 Go to the "Manage fields" of the bundle where the Metatag field is to - appear. - 5.2 Select "Meta tags" from the "Add a new field" selector. - 5.3 Fill in a label for the field, e.g. "Meta tags", and set an appropriate - machine name, e.g. "meta_tags". - 5.4 Click the "Save and continue" button. - 5.5 If the site supports multiple languages, and translations have been - enabled for this entity, select "Users may translate this field" to use - Drupal's translation system. - -Please note: no meta tags will be output while the site is in maintenance mode. - - -Simplify the content administration experience --------------------------------------------------------------------------------- -This module and its submodules gives a site's content team the ability to add -every meta tag ever. The standard meta tag form added by the Metatag field on -content entities can be overwhelming to content creators and editors who just -need to manage a few options. - -The easiest way of simplifying this for content teams is to add new fields to -the content type for the meta data fields that are needed and skip adding the -Metatag field entirely, then use tokens for those fields in the defaults -(/admin/config/search/metatag). These fields can be used in the entity's -display, or just left hidden. - - -Alternative option to simplify the content administration experience --------------------------------------------------------------------------------- -On the settings page (/admin/config/search/metatag/settings) are options to -control which meta tag groups are available for each entity bundle. This allows -e.g. the Favicon meta tags to be available for global configurations but to hide -them on entity forms. - - -Programmatically assign meta tags to an entity --------------------------------------------------------------------------------- -There are two ways to assign an entity's meta tags in custom module. Both -scenarios require a "Metatag" field be added to the entity's field settings, the -field name "field_meta_tags" is used but this is completely arbitrary. - -Option 1: - - $entity_type = 'node'; - $values = [ - 'nid' => NULL, - 'type' => 'article', - 'title' => 'Testing metatag creation', - 'uid' => 1, - 'status' => TRUE, - 'field_meta_tags' => serialize([ - 'title' => 'Some title', - 'description' => 'Some description.', - 'keywords' => 'Some,Keywords', - ]), - ]; - $node = \Drupal::entityTypeManager() - ->getStorage($entity_type) - ->create($values); - $node->save(); - -Option 2: - - $node = Node::create([ - 'type' => article, - 'langcode' => 'en', - 'status' => 1, - 'uid' => 1, - ]); - $node->set('title', 'Testing metatag creation'); - $node->set('field_meta_tags', serialize([ - 'title' => 'Some title', - 'description' => 'Some description.', - 'keywords' => 'Some,Keywords', - ])); - $node->save(); - -In both examples, the custom meta tag values will still be merged with the -values defined via the global defaults prior to being output - it is not -necessary to copy each value to the new record. - - -Obtain meta tags for an entity --------------------------------------------------------------------------------- -For developers needing to access the rendered meta tags for a given entity, a -function is provided to make this easy to do: - - $metatags = metatag_generate_entity_metatags($entity); - -This will return an array with the following structure: - - [ - 'title' => [ - '#tag' => 'meta', - '#attributes' => [ - 'name' => 'title', - 'content' => 'The What | D8.4', - ], - ], - 'canonical_url' => [ - '#tag' => 'link', - '#attributes' => [ - 'rel' => 'canonical', - 'href' => 'https://example.com/what', - ], - ], - 'description' => [ - '#tag' => 'meta', - '#attributes' => [ - 'name' => 'description', - 'content' => 'I can't even.', - ], - ], - 'generator' => [ - '#tag' => 'meta', - '#attributes' => [ - 'name' => 'generator', - 'content' => 'Drupal 8!', - ], - ], - ] - -The meta tags are keyed off the meta tag plugin's ID, e.g. "generator". Each -meta tag is then provided as arguments suitable for use in a render array with -the type "html_tag". Extracting the value of the meta tag will depend upon the -type of meta tag, e.g. the generator meta tag uses the "content" attribute while -the link tag uses the "href" attribute. - - -Migration / Upgrade from Drupal 6 or 7 --------------------------------------------------------------------------------- -An upgrade path from Nodewords on Drupal 6 or Metatag on Drupal 7 is provided. - -Two migration processes are supported: - - 1. A guided migration using either the Migrate Drupal UI from core or the - Migrate Upgrade [2] contributed module. This will automatically create a - field named "field_metatag" and import any meta tag data that existed in - Nodewords on D6 or Metatag on D7. - - This migration configuration is all prepared in - metatag_migration_plugins_alter(), the data is loaded onto the migrated - entity in metatag_migrate_prepare_row(), and then the data is remapped in - either \Drupal\metatag\Plugin\migrate\process\d6\NodewordsEntities or - \Drupal\metatag\Plugin\migrate\process\d7\MetatagEntities depending upon - what the source is. - - 2. A custom migration using Migrate Plus [3] and possibly Migrate Tools [4]. - This will require manually creating the meta tag fields and assigning a - custom process plugin as the source for its data. For example, if the name - of the field is "field_meta_tags" the lines from the "process" section of - the migration yml file would need to look line the following: - - For migrating from Nodewords on D6: --------------------------------------------------------------------- -process: -... - field_meta_tags: - plugin: d6_nodewords_entities - source: pseudo_metatag_entities -... --------------------------------------------------------------------- - - For Migrating from Metatag on D7: --------------------------------------------------------------------- -process: -... - field_meta_tags: - plugin: d7_metatag_entities - source: pseudo_metatag_entities -... --------------------------------------------------------------------- - - The important items are the "plugin" and the "source" values, if these are - not present the migration will not work as expected. - - The data will then be loaded into the migrating entity using - metatag_migrate_prepare_row(). - - See also: - * \Drupal\metatag\Plugin\migrate\process\d6\NodewordsEntities - * \Drupal\metatag\Plugin\migrate\process\d7\MetatagEntities - - -DrupalConsole integration --------------------------------------------------------------------------------- -Using the DrupalConsole, it is possible to generate new meta tags, either for -use in new custom modules that require custom meta tags, or to create patches -for extending Metatag's options. - -To generate a new tag, install DrupalConsole and then use the following command: - - drupal generate:plugin:metatag:tag - -This will guide the site builder through the necessary steps to create a new -meta tag plugin and add it to a module. - -There is also a command for generating meta tag groups: - - drupal generate:plugin:metatag:group - -Again, this provides a guided process to create a new group. - - -Related modules --------------------------------------------------------------------------------- -Some modules are available that extend Metatag with additional or complimentary -functionality: - -* Schema.org Metatag - https://www.drupal.org/project/schema_metatag - Extensive solution for adding schema.org / JSON-LD support to Metatag. - -* Context Metadata - https://www.drupal.org/project/context_metadata - Allow assignment of meta tags based upon different system contexts, e.g. per - path. - -* Real-time SEO for Drupal - https://www.drupal.org/project/yoast_seo - Uses the YoastSEO.js library and service (https://yoast.com/) to provide - realtime feedback on the meta tags. - -* Metatag Cxense - https://www.drupal.org/project/metatag_cxense - Adds support for the Cxense meta tags used by their DMP and Insight services. - -* Metatag Google Scholar - https://www.drupal.org/project/metatag_google_scholar - Adds support for a number of meta tags used with the Google Scholar system. - - -Known issues --------------------------------------------------------------------------------- -* In order to uninstall the module any "Metatag" fields must first be removed - from all entities. In order to see whether there are fields blocking the - module from being uninstalled, load the module uninstall page - (admin/modules/uninstall) and see if any are listed, it will look something - like the following: - The Meta tags field type is used in the following field: - node.field_meta_tags - In order to uninstall the module, go to the appropriate field settings pages - and remove the Metatag field listed in the message. Once this is done it will - be possible to uninstall the module. - - -Credits / contact --------------------------------------------------------------------------------- -Currently maintained by Damien McKenna [5] and Dave Reid [6]. Drupal 7 module -originally written by Dave Reid. Early work on Drupal 8 port by Damien McKenna -and Michelle Cox [7], and sponsored by Mediacurrent [8]; key improvements by -Juampy Novillo Requena [9] with insights from Dave Reid and sponsorship by -Lullabot [10] and Acquia [11]. Additional contributions to the 8.x-1.0 release -from cilefen [12], Daniel Wehner [13], Jesus Manuel Olivas [14], Lee Rowlands -[15], Michael Kandelaars [16], Ivo Van Geertruyen [17], Nikhilesh Gupta B [18], -Rakesh James [19], and many others. - -Ongoing development is sponsored by Mediacurrent. - -The best way to contact the authors is to submit an issue, be it a support -request, a feature request or a bug report, in the project issue queue: - https://www.drupal.org/project/issues/metatag - - -References --------------------------------------------------------------------------------- -1: https://www.drupal.org/project/console -2: https://www.drupal.org/project/migrate_upgrade -3: https://www.drupal.org/project/migrate_plus -4: https://www.drupal.org/project/migrate_tools -5: https://www.drupal.org/u/damienmckenna -6: https://www.drupal.org/u/dave-reid -7: https://www.drupal.org/u/michelle -8: https://www.mediacurrent.com/ -9: https://www.drupal.org/u/juampynr -10: https://www.lullabot.com/ -11: https://www.acquia.com/ -12: https://www.drupal.org/u/cilefen -13: https://www.drupal.org/u/dawehner -14: https://www.drupal.org/u/jmolivas -15: https://www.drupal.org/u/larowlan -16: https://www.drupal.org/u/mikeyk -17: https://www.drupal.org/u/mr.baileys -18: https://www.drupal.org/u/nikhilesh-gupta -19: https://www.drupal.org/u/rakeshgectcr diff --git a/web/modules/metatag/composer.json b/web/modules/metatag/composer.json index c43f531a9321cceb132396da54196ac62595b140..76dcd34528950c0489dde1bea6c5cbf4211a480c 100644 --- a/web/modules/metatag/composer.json +++ b/web/modules/metatag/composer.json @@ -22,13 +22,16 @@ "docs": "https://www.drupal.org/docs/8/modules/metatag" }, "require": { - "drupal/core": "^8 || ^9", + "drupal/core": "^9.3 || ^10", "drupal/token": "^1.0" }, "require-dev": { - "drupal/devel": "^4.0", - "drupal/redirect": "1.x-dev", - "drupal/page_manager": "4.x-dev", - "drupal/panelizer": "4.x-dev" + "drupal/devel": "^4.0 || ^5.0", + "drupal/hal": "^9 || ^1 || ^2", + "drupal/redirect": "^1.0", + "drupal/page_manager": "^4.0", + "drupal/panelizer": "^4.0", + "drupal/webprofiler": "^9 || ^10", + "mpyw/phpunit-patch-serializable-comparison": "*" } } diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.403.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.403.yml index 3f88243f101fbeaa97a87f451d2b5ac16e737170..5dcc4ef43ee40385bb8c31e7784ea6ff01479f93 100644 --- a/web/modules/metatag/config/install/metatag.metatag_defaults.403.yml +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.403.yml @@ -4,5 +4,6 @@ dependencies: { } id: '403' label: '403 access denied' tags: + robots: noindex canonical_url: '[site:url]' shortlink: '[site:url]' diff --git a/web/modules/metatag/config/schema/metatag.metatag_tag.schema.yml b/web/modules/metatag/config/schema/metatag.metatag_tag.schema.yml index 8ad5e98ccbf641c311854eea838599d27b03d6a7..bc6555702307822c6432e897d4e7df9bcfc12d6d 100644 --- a/web/modules/metatag/config/schema/metatag.metatag_tag.schema.yml +++ b/web/modules/metatag/config/schema/metatag.metatag_tag.schema.yml @@ -69,7 +69,7 @@ metatag.metatag_tag.standout: type: label label: 'Standout' metatag.metatag_tag.title: - type: label + type: text label: 'Page title' metatag.metatag_tag.icbm: type: label @@ -89,3 +89,6 @@ metatag.metatag_tag.set_cookie: metatag.metatag_tag.google: type: label label: 'Google' +metatag.metatag_tag.author: + type: label + label: 'Author' diff --git a/web/modules/metatag/config/schema/metatag.schema.yml b/web/modules/metatag/config/schema/metatag.schema.yml index 437c2c0ae4f80a0f8e27797ca66f616e201c3ddb..581a7809ddf8b0d8a225fee96d4be1009ff82c37 100644 --- a/web/modules/metatag/config/schema/metatag.schema.yml +++ b/web/modules/metatag/config/schema/metatag.schema.yml @@ -14,3 +14,6 @@ field.widget.settings.metatag_firehose: sidebar: type: boolean label: 'Place field in sidebar' + use_details: + type: boolean + label: 'Place field in collapsed details container' diff --git a/web/modules/metatag/config/schema/metatag.settings.schema.yml b/web/modules/metatag/config/schema/metatag.settings.schema.yml index 79133f9b059a4788008491143bdb29f90a8511c3..645608228d119f43dc956859e074ced53f1aad2b 100644 --- a/web/modules/metatag/config/schema/metatag.settings.schema.yml +++ b/web/modules/metatag/config/schema/metatag.settings.schema.yml @@ -14,3 +14,15 @@ metatag.settings: sequence: type: string label: 'Group' + tag_trim_method: + type: string + label: 'Trim method for trimmable tags.' + tag_trim_maxlength: + type: sequence + label: 'Tag-specific maximum length' + sequence: + type: integer + label: 'Tag maximum length in characters' + tag_scroll_max_height: + type: string + label: 'Add max height value' diff --git a/web/modules/metatag/console.services.yml b/web/modules/metatag/console.services.yml deleted file mode 100644 index c93c2aa91210f6b7938320392e982ec1234b5bfb..0000000000000000000000000000000000000000 --- a/web/modules/metatag/console.services.yml +++ /dev/null @@ -1,24 +0,0 @@ -services: - metatag.generate_tag: - class: Drupal\metatag\Command\GenerateTagCommand - arguments: ['@metatag.manager', '@metatag.tag_generator', '@?console.extension_manager', '@?console.string_converter', '@?console.chain_queue', '@console.validator'] - tags: - - { name: drupal.command } - - metatag.generate_group: - class: Drupal\metatag\Command\GenerateGroupCommand - arguments: ['@metatag.group_generator', '@?console.extension_manager', '@?console.chain_queue', '@console.validator'] - tags: - - { name: drupal.command } - - metatag.tag_generator: - class: Drupal\metatag\Generator\MetatagTagGenerator - arguments: ['@?console.extension_manager', '@?console.renderer'] - tags: - - { name: drupal.generator } - - metatag.group_generator: - class: Drupal\metatag\Generator\MetatagGroupGenerator - arguments: ['@?console.extension_manager', '@?console.renderer'] - tags: - - { name: drupal.generator } diff --git a/web/modules/metatag/css/firehose_widget.css b/web/modules/metatag/css/firehose_widget.css new file mode 100644 index 0000000000000000000000000000000000000000..c601bce58636f4e968efbff0ca0dbe7bb68defb6 --- /dev/null +++ b/web/modules/metatag/css/firehose_widget.css @@ -0,0 +1,9 @@ +/** + * @file + * Custom CSS for the Firehose widget. + */ + +.metatags { + max-height: 500px; + overflow-y: overlay; +} diff --git a/web/modules/metatag/metatag-logo.png b/web/modules/metatag/metatag-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..38f601be25220eff8b7bf18c569d7a4bf9eaaa17 --- /dev/null +++ b/web/modules/metatag/metatag-logo.png @@ -0,0 +1,61 @@ +�PNG + +��� IHDR���������æ$����tEXtSoftware�www.inkscape.org��<��� pHYs������}D��VPLTE�t����w� y����}������t����u�`���v¢��o��{đ�䂻�^�����L��}Ş��~Ƴ��w����xÈ��������&��f��������-�������5��2��A�������������H��8��������R��������D��<�����:����������!��������*�������������(��������������#�����������k��/�����������U��O��������z��F�����a�����������[��r�ݰ��������>��T�ի������������ꅽ�X��V��h�����������ǣ1���tRNS��}���IDATx��YCK�!$L�-�r !ȾE�� +� (�l + +.(.|���|��$3]=�=3�}�'3��U�%%(bJ0��n�n��@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�������@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@�����@��|������S�b�����_���$!@� +0FD��x�AD�P���3�� P�� "�{3�H��9""��)P��/zR��z!��� @��[��NB����.����5㟗����������L�Am +p�`�ңt�ܦ��RA�>@���� c_�&�;2-�Q����="cl� �nj@��1��?%2'@l��4�e\��@���Y2)@%�t˼��n��^\�@ 0�����h�& ��T��Wf蝦�+�� �� +'L:�Yں�0�e�\��!����2!@��1�nA� +QR T4�^};`f�ܹ��� @x�a���k7I^��A�d�φ�aI +�G���7�U_�I�ܧF�$)b��dZ��R��a�B������|_&uV+����@(����i[�GgM�y��v��ɺ�n���[ψ�t:e^�* 6)���o +�1.eY��f�pR hR�� v�O����1.@�I��hXu�/2��%?�7� ��@�̼t�-�=%��_�7-@pI����x=���8' v�TR 8x?�� +���I��-iV���A �Ԫ���'�ԧY��ŖaI +#@�����#@�}��g°�$�������������Y�'����� +�1M��O�� +`;)`_��s�[�)���� w� `7)`[��Ɲ�`���Rޚ2+�դ�]�jX���������e�Z��F&^�n_�W�d�x-�!=���l%, +�����{�����G��Y1�ZM +�`�91���f_��������7�����%@;wM�=�NM�د�+]/!I +���S����_0�6O�[�+S�'�0�|6k�N�w�}:i�AV�)��`[��������CO�,s�j6)`\��{o.�^zOS@�t:ʯ6@*D&+L���:�--g��|�Ѥ�Y�y�i����-I�����c~��GQ�F���,��% +��U6��AV�3���q�tRМ&���式�O� o���|'��KjF���z��lm")`J��.+_nq��@����\�I3d���>�uZ��}����捚�&œ&(��)�9��x��BZ�fq�Ȥ�XõzX�ںB3���o�.w$�,@����~����q{X��=�6/J&��u�G���*��hߴX��X*��`�;(�uڟuJ!����R+�r �����1�&^�_�XC���ǻY�WJ>) (�{���kә( ��t���)uK�'����g�C8�T�o�����!������)o� ��U����a���������9��RHi�9E��O +H�!��_���5ߏ�e�'�L +����Y���m��`��q��JI��~d����� +1/�E�;����6Z�}"�7 +5�Tn:�GR����% �u�2��[��S� p�{l=W��^�Y�<��s&2���>Z5��$�?E��_�g�ȜB��Wz?/m�ݞ�+%a(���]BG �WVu����=iaQ�TR�Tm�FR@O��Nn�t�GA�{b���;��:�Srul�)ȝt��g3�%��ۓ��Nfo�EC�I�c��E6���[�v�giV���n9�4p�_8I���nOz�(w'ˣ"�}ѓ� FR�'�&wF����"C�e�[m�vq`w{҈h�J.:L�p�[-U{�����r��Oj)BT8°�Ւ���=%���i��Q`���E��P����--j(R����-�UH +( ��S����&�-N�g�Cz���"�{q�F����h�?��҅�E����"����W?������}����&<`�I��(�5����~�5)P"��~bh?����?��2��b�䅓���=M�8����Z=&�숸PR�M�v�'5�>u;z,��ߌS��\X�v�'u�����=�?7ke 0ĝ��f�~ݳ + ��r����%���n���}E>:fa�gM +�?��G_ǟ^?���EfP�s��/���M��"3&��]��0M����Y8ܬj.�4[@�p،�Z{�s���[�Q>~�s�*�p-�Њc��'�q���Q����J���L���z�Q��c �.2at�x� sf�*��=�����J���GQtl�q�����v��_|����d����aAl��=�+�k���ӛ����� +��ئ��BX�"�&"��.@�.2Ƈ���� +p�@�.2 �����`> +l�. ���+��?m;����Ϸ��u�|��P��������+}��@-�ܲ�Eþ����}�3e2�ܱsCA��?�|�����߯B�����]T؋���S�.��2y��}_舲�C�o�˩CB�@�㫽Y���[��k�����b���l���꺉{Ϩ�j��s_8��C�?��Ƥ�8U�3k�_��6p`�>yu���T�"�د>�9� d7�6���o�lEЋ�h���u/'��v�� �{���Y@nĽe59p&���ܻݺ�?>�)���]�xU��`P{w�� +��̉L\8?z�!y|\o;T�0�D_����Qͅ���ٱ���+m�3=V���[y���R0�5&���f��ŃO��C�#{� ��������Oni��2�ie����?�F��� +flh�;�|�`�?(��U��I����>����kwc��n�b?��hlU��چ��.��S&�o�`�;���x�}'�=���g�P.[0��y�r�`��[t�bn�֣�Njl�}��>������{|@tw �=��|�4�x�侺�F�������U�:K��N��� ��z�Z��(o���5��LD�����_�]"1���M�y9��x��'�Z���߳4j���y�?7��>n%�/S��qΊ8��i� +��v),���I���_� +wZ�]�������-<���;���+D�c���m"�.7�gG�=�<�x�?�C���2X�e[��J�\�I���~DD�1����\�!�ӫM�S��R���������('|/��Gֹ?����e��,_8��CD\�Je}��h��p0�=��ܳhC��0֎�D$}d�㌩��i��yfZ��9F љh���6�J���"K)~��<�����y���!� 2�S��S����'����dp�����P��9�Hɽg�'w�-Ш��O +ܮ���>���c�r'NDtﴁm�-�I����R�ʩ��- ��C���9&h�k[�y��Ҏп0�����X��7�I���2���`���,�S,���������+nV�{�k����ixf2/��3���K��a���ݐ 0�k��٭�����ܤ�LY��r@C��?#pr$���zR���I�.2����p 0�)�����D��b'$ +���%�!u� ��}k�::h$��0����1U��ޭS�t�s�@�c`.��Ƨ���ɝ��.��JM~��t��r={l�}�z�1o���m%�� ;)��Ѐ��������V��?��'������CF�<��ҕ�� +o����{a1�[֮�*���h�)��Bu���/7�Z�z�3�9@*�3:�@#)��ٌW(�qQ�H^����i�=BV�k.~�� ���Q8���y%6��� +}�����fb:� ��������W준~Y�G6�Ch���\�[:S�ݭZK��n`�<����@#)��:5�e�Ƚ�bA)�߲���3� �+%w���� =� +�ûs��c�b���㨌�I�^"�a':�����[��$ +v���/fv��'0t281vR`D's��#v�{��s��9��c�3��b)h$�����B|V��Q�ǽ�f>���m��L +��x�ϕv��%��y��֫��/� �`>���߶ؔWP�~R@����=>ӯ +l�d���nq@�%���$��$�H +��Ȧ�7��M4���o#���hdd��ӝ�<�� :~}r��\� +�O +���5��Z��O7~���������>qW݀�;��v�'�A���IfYՆ�՞�_-��d��3|tP1P�D�8���Ko�-.�FR�w�İ�`'L�7^��7��������[G�L��������2z��ղ�ױ���BMU�ק K����T���y����&�H +p +�[<�5���[ɭ<�O����Ϯ�Ʉ�7�3����-�����3�v�m�"�v�.��2�c� �~?��7�������4c��`3%���ƈn�j��oy��3�|E���k8m5/^d�=��n>��V�l�*-uz���4��]dɧ^�����mY5�.����{������ϟ_�����;� <W�Oc�N�5(�?)�\8����j���"��@}i�EZj�Ǝ����Y��iٕ�8=�2�p4yj�I4���O�$O�Z�����SjF +ϼ+~���Sz���8�Ӗ�(�'��Y��'ZVx���#S����}�T��vU/�|c~�5��&*k�v�z3��w��_�s�W��Sاv��>�ϴ�����R�S�{8v�qf^(�Yw'������i\��&'��n�q��qƖf�=������e� �?)���ʜKP>���$v����z����E*�q�J�ʠ��/�}���G��=s��\m��[�'T�}��#������q��/�VƖ��� �S�c���R� ��2�r��,myfM��߀w���������M�����^W�q��Q��Kc��Ī�ܤ�����H�?G��S��`&TV�&��r�>0u�������Ri��t���s����<�`$�jk�,Yk�ͩԀ� `g����I�⪦���=�����W�C��S*����$�H�gPM +�V��N�����8N�6��)�q���J@0{�r�PL +$�/���-o��M3�����m'S�C6���� f�ӠPJ +����Z��w��b��k��?�q�-�������� +I��N�K�K���[�Qd����o����^��.���:��;)��I�p��W���}YP���ڭK%��,�3ڮ���y�x%��-2�����qU�V����ߙŹ�����f����O��!g��E��� G `ܓL�����`�k��56�6��.z�g��7�B� +�E����I��bo�ܝEgN�8�2�l����/�KR �q� +�^��[�3}�G�T�5�p���M��&@�@B�b�'�S�� �8��ǥ�bI�K�B���(�H�]����X:2��L�98����C���<l��·D��I����&�p�O�c�v�)[����ˏ��J�����=� �M +$��6���=�X�6������?<6z�VY{6~��m�X�T���=#+@��@���&^2K=��?����?4�܆I�I���˵�H֍�w���_*��|6�瞇J��I����5ޕ��� ��%Ƈ�t�C&�դ@B�����|�N��ڊ`J>�'���@B�-[�> +G�{�U�!���\�KI���cC��:�_�ܑ��~ +��h�nv��HH^�}�՜6�P�@�i]A7z���H +$�/�^w���I��:]���Th�_��L +$L\8�2�{�p�w���/Չ�n9� +��=�T����4a��U��c��҉l��8��Mw|�Ϙ�Ŧ���� +�8�[(f���@�����@�����@�����@�����@�����@�����@�����@������� ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ���������@�����@�����@�����@�����@��@���=��~7$h�}����IEND�B`� \ No newline at end of file diff --git a/web/modules/metatag/metatag-logo.svg b/web/modules/metatag/metatag-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..2043eda26a385b912ce5f37c90c032e1852d6e0e --- /dev/null +++ b/web/modules/metatag/metatag-logo.svg @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="500" + height="500" + viewBox="0 0 132.29166 132.29167" + version="1.1" + id="svg5" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs2" /> + <g + id="g5128" + style="display:inline"> + <rect + style="fill:#0074c1;fill-opacity:1;stroke:#808080;stroke-width:0.00265549;stop-color:#000000" + id="rect5126" + width="132.28902" + height="132.28902" + x="0.001327745" + y="0.001327745" + ry="0" /> + </g> + <g + id="layer5" + style="display:inline"> + <g + aria-label="<" + id="text2881" + style="font-size:50.8px;line-height:1.25;stroke-width:0.264583" + transform="matrix(1.3818704,0,0,2.0292938,-16.028486,18.559421)"> + <path + d="M 16.178928,27.465594 V 22.380633 L 40.859592,12.012274 v 3.819922 l -21.282422,9.078515 21.282422,9.10332 v 3.795117 z" + style="font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';fill:#ffffff" + id="path2933" /> + </g> + <g + aria-label="<" + id="g2940" + style="font-size:50.8px;line-height:1.25;stroke-width:0.264583" + transform="matrix(-1.3818704,0,0,-2.0292938,149.38323,119.34111)"> + <path + d="M 16.178928,27.465594 V 22.380633 L 40.859592,12.012274 v 3.819922 l -21.282422,9.078515 21.282422,9.10332 v 3.795117 z" + style="font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';fill:#ffffff" + id="path2938" /> + </g> + </g> + <g + id="layer4" + style="display:inline"> + <path + fill="#00598e" + d="m 78.79926,49.558731 c -2.852021,-1.77714 -5.532063,-2.47223 -8.226436,-4.242204 -1.662486,-1.132209 -3.977066,-3.81225 -5.911855,-6.126831 -0.372626,3.711928 -1.504836,5.216764 -2.794696,6.291647 -2.737368,2.149765 -4.45718,2.794694 -6.821922,4.084555 -1.992116,1.017555 -12.791104,7.466851 -12.791104,21.332838 0,13.865989 11.66606,24.077375 24.614814,24.077375 12.948753,0 24.184861,-9.401643 24.184861,-23.647422 0,-14.245778 -10.53385,-20.695075 -12.253662,-21.769958 z" + id="path2978-6" + style="display:inline;fill:#ffffff;fill-opacity:1;stroke-width:0.0716587" /> + </g> + <g + id="g6607" + style="display:inline"> + <path + fill="#ffffff" + d="m 74.523644,82.860035 c 0.879084,0 1.816774,0.05861 2.476089,0.498147 0.659313,0.439543 1.040252,1.428515 1.260023,1.977942 0.219771,0.549429 0,0.879084 -0.439542,1.098855 -0.380939,0.219772 -0.439544,0.109888 -0.820481,-0.600706 -0.380937,-0.710595 -0.717919,-1.428513 -2.637254,-1.428513 -1.919337,0 -2.527371,0.659315 -3.457736,1.428513 -0.930366,0.769201 -1.260023,1.04025 -1.597005,0.600706 -0.336983,-0.439542 -0.219772,-0.879084 0.380936,-1.428512 0.600709,-0.549429 1.597006,-1.428514 2.527371,-1.816777 0.930364,-0.388261 1.428514,-0.329655 2.307599,-0.329655 z" + id="path6589" + style="fill:#0074c1;fill-opacity:1;stroke-width:0.073257" /> + <path + fill="#ffffff" + d="m 65.410461,89.123516 c 1.098855,0.879085 2.74714,1.597006 6.263481,1.597006 3.516342,0 5.985104,-0.996296 7.083961,-1.816777 0.498149,-0.380936 0.71792,-0.05861 0.7692,0.161167 0.05128,0.219772 0.161166,0.549427 -0.219771,0.937689 -0.278378,0.278378 -2.79842,2.036549 -5.77266,2.307601 -2.974239,0.271052 -6.974076,0.439542 -9.39156,-1.758171 -0.380937,-0.380939 -0.278377,-0.937692 0,-1.157463 0.278377,-0.219772 0.498148,-0.380936 0.82048,-0.380936 0.322331,0 0.278376,0 0.446869,0.109884 z" + id="path6591" + style="fill:#0074c1;fill-opacity:1;stroke-width:0.073257" /> + <path + fill="#ffffff" + d="m 52.443953,79.123922 c 0.05861,-4.285541 4.065769,-8.292704 9.120509,-8.351309 6.431974,-0.05861 10.87868,6.373367 14.123968,6.314762 2.747143,-0.05861 8.021655,-5.435677 10.60763,-5.435677 2.74714,0 3.516341,2.857027 3.516341,4.556591 0,1.699565 -0.54943,4.776364 -1.868057,6.703027 -1.318629,1.926661 -2.139108,2.637256 -3.677507,2.527369 -1.977941,-0.161166 -5.933825,-6.314763 -8.461194,-6.431974 -3.186684,-0.109886 -10.10948,6.651745 -15.545157,6.651745 -3.296571,0 -4.285541,-0.49815 -5.384397,-1.20874 -1.670263,-1.150139 -2.490741,-2.908309 -2.432136,-5.325794 z" + id="path6601" + style="fill:#0074c1;fill-opacity:1;stroke-width:0.073257" /> + </g> +</svg> diff --git a/web/modules/metatag/metatag.info.yml b/web/modules/metatag/metatag.info.yml index cbfc297dfb7cd99a8b11e7c8c4f2cd3436f2f7eb..88427f5f26730a085ec87efa7b7f2148f80f27e8 100644 --- a/web/modules/metatag/metatag.info.yml +++ b/web/modules/metatag/metatag.info.yml @@ -1,7 +1,7 @@ name: Metatag type: module description: Manage meta tags for all entities. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO configure: entity.metatag_defaults.collection dependencies: @@ -10,7 +10,7 @@ dependencies: test_dependencies: - devel:devel -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag.install b/web/modules/metatag/metatag.install index c696a4944277a701adece41c9b2e569f8abc6c21..a814dd80fe073ec249e1ff24123dd2e441f5f586 100644 --- a/web/modules/metatag/metatag.install +++ b/web/modules/metatag/metatag.install @@ -5,6 +5,8 @@ * Requirements and update functions for the Metatag module. */ +use Drupal\Core\StringTranslation\TranslatableMarkup; + /** * Implements hook_requirements(). */ @@ -18,8 +20,8 @@ function metatag_requirements($phase) { $requirements['metatag_maintenance_mode'] = [ 'severity' => REQUIREMENT_WARNING, 'title' => 'Metatag', - 'value' => t('Not enabled while in maintenance mode'), - 'description' => t('Please note that while the site is in maintenance mode none of the usual meta tags will be output.'), + 'value' => new TranslatableMarkup('Not enabled while in maintenance mode'), + 'description' => new TranslatableMarkup('Please note that while the site is in maintenance mode none of the usual meta tags will be output.'), ]; } @@ -28,8 +30,8 @@ function metatag_requirements($phase) { $requirements['metatag_schema'] = [ 'severity' => REQUIREMENT_INFO, 'title' => 'Metatag', - 'value' => t('Schema.org Metatag is recommended'), - 'description' => t('The <a href="@module">Schema.org Metatag</a> module is highly recommended to add <a href="@jsonld">JSON-LD</a> -formatted <a href="@schema">schema.org</a> compatible data structures to the site.', [ + 'value' => new TranslatableMarkup('Schema.org Metatag is recommended'), + 'description' => new TranslatableMarkup('The <a href="@module">Schema.org Metatag</a> module is highly recommended to add <a href="@jsonld">JSON-LD</a> -formatted <a href="@schema">schema.org</a> compatible data structures to the site.', [ '@module' => 'https://www.drupal.org/project/schema_metatag', '@jsonld' => 'https://json-ld.org', '@schema' => 'https://schema.org', @@ -40,12 +42,24 @@ function metatag_requirements($phase) { $requirements['metatag_schema'] = [ 'severity' => REQUIREMENT_OK, 'title' => 'Metatag', - 'value' => t('Schema.org Metatag is installed'), - 'description' => t('The <a href="@module">Schema.org Metatag</a> module is installed.', [ + 'value' => new TranslatableMarkup('Schema.org Metatag is installed'), + 'description' => new TranslatableMarkup('The <a href="@module">Schema.org Metatag</a> module is installed.', [ '@module' => 'https://www.drupal.org/project/schema_metatag', ]), ]; } + + // Suggest the Token OR module. + if (!\Drupal::moduleHandler()->moduleExists('token_or')) { + $requirements['metatag_token_or'] = [ + 'severity' => REQUIREMENT_INFO, + 'title' => 'Metatag', + 'value' => new TranslatableMarkup('Token Or'), + 'description' => new TranslatableMarkup('The <a href="@module">Token OR module</a> is suggested for when the basic content tokens are not flexible enough, e.g. to make a meta tag show the contents of one field if it is filled in or another if the first one is empty.', [ + '@module' => 'https://www.drupal.org/project/token_or', + ]), + ]; + } } return $requirements; @@ -63,12 +77,156 @@ function metatag_update_last_removed() { */ function metatag_update_8107() { \Drupal::service('module_installer')->install(['metatag_open_graph']); - return (string) t("The new Metatag: Open Graph module has been enabled."); + return (string) new TranslatableMarkup("The new Metatag: Open Graph module has been enabled."); } /** * Need to clear caches after updating from 8.x-1.12. */ function metatag_update_8108() { - return (string) t("The sites's caches will need to be rebuild to ensure Metatag works as intended."); + return (string) new TranslatableMarkup("The sites's caches will need to be rebuild to ensure Metatag works as intended."); +} + +/** + * Update mask_icon values to the new structure. + */ +function metatag_update_8109(&$sandbox) { + // This whole top section only needs to be done the first time. + if (!isset($sandbox['records_processed'])) { + $sandbox['records_processed'] = 0; + $sandbox['total_records'] = 0; + $sandbox['current_field'] = 0; + $sandbox['current_record'] = 0; + + // Counter to enumerate the fields so we can access them in the array + // by number rather than name. + $field_counter = 0; + + // Get all of the field storage entities of type metatag. + /** @var \Drupal\field\FieldStorageConfigInterface[] $field_storage_configs */ + $field_storage_configs = \Drupal::entityTypeManager() + ->getStorage('field_storage_config') + ->loadByProperties(['type' => 'metatag']); + + foreach ($field_storage_configs as $field_storage) { + $field_name = $field_storage->getName(); + + // Get the individual fields (field instances) associated with bundles. + $fields = \Drupal::entityTypeManager() + ->getStorage('field_config') + ->loadByProperties([ + 'field_name' => $field_name, + 'entity_type' => $field_storage->getTargetEntityTypeId(), + ]); + + foreach ($fields as $field) { + // Get the bundle this field is attached to. + $bundle = $field->getTargetBundle(); + + // Determine the table and "value" field names. + // @todo The class path to getTableMapping() seems to be invalid? + $table_mapping = Drupal::entityTypeManager() + ->getStorage($field->getTargetEntityTypeId()) + ->getTableMapping(); + $field_table = $table_mapping->getFieldTableName($field_name); + $field_value_field = $table_mapping->getFieldColumnName($field_storage, 'value'); + + // Get all records where the field data does not match the default. + $query = \Drupal::database()->select($field_table); + $query->addField($field_table, 'entity_id'); + $query->addField($field_table, 'revision_id'); + $query->addField($field_table, 'langcode'); + $query->addField($field_table, $field_value_field); + $query->condition('bundle', $bundle, '='); + $result = $query->execute(); + $records = $result->fetchAll(); + + if (empty($records)) { + continue; + } + + // Fill in all the sandbox information so we can batch the individual + // record comparing and updating. + $sandbox['fields'][$field_counter]['field_table'] = $field_table; + $sandbox['fields'][$field_counter]['field_value_field'] = $field_value_field; + $sandbox['fields'][$field_counter]['records'] = $records; + + $sandbox['total_records'] += count($sandbox['fields'][$field_counter]['records'] = $records); + $field_counter++; + } + } + } + + if ($sandbox['total_records'] == 0) { + // No partially overridden fields so we can skip the whole batch process. + $sandbox['#finished'] = 1; + } + else { + // Begin the batch processing of individual field records. + $max_per_batch = 10; + $counter = 1; + + $current_field = $sandbox['current_field']; + $current_field_records = $sandbox['fields'][$current_field]['records']; + $current_record = $sandbox['current_record']; + + $field_table = $sandbox['fields'][$current_field]['field_table']; + $field_value_field = $sandbox['fields'][$current_field]['field_value_field']; + + // Loop through the field(s) and update the mask_icon values if necessary. + while ($counter <= $max_per_batch && isset($current_field_records[$current_record])) { + $record = $current_field_records[$current_record]; + + // Strip any empty tags or ones matching the field's defaults and leave + // only the overridden tags in $new_tags. + $tags = unserialize($record->$field_value_field, ['allowed_classes' => FALSE]); + if (isset($tags['mask-icon'])) { + $tags['mask_icon'] = [ + 'href' => $tags['mask-icon'], + ]; + + $tags_string = serialize($tags); + \Drupal::database()->update($field_table) + ->fields([ + $field_value_field => $tags_string, + ]) + ->condition('entity_id', $record->entity_id) + ->condition('revision_id', $record->revision_id) + ->condition('langcode', $record->langcode) + ->execute(); + } + $counter++; + $current_record++; + } + + // We ran out of records for the field so start the next batch out with the + // next field. + if (!isset($current_field_records[$current_record])) { + $current_field++; + $current_record = 0; + } + + // We have finished all the fields. All done. + if (!isset($sandbox['fields'][$current_field])) { + $sandbox['records_processed'] += $counter - 1; + $sandbox['#finished'] = 1; + } + // Update the sandbox values to prepare for the next round. + else { + $sandbox['current_field'] = $current_field; + $sandbox['current_record'] = $current_record; + $sandbox['records_processed'] += $counter - 1; + $sandbox['#finished'] = $sandbox['records_processed'] / $sandbox['total_records']; + } + } + + if ($sandbox['total_records'] > 0) { + return (string) t('Processed @processed of @total overridden Metatag records.', [ + '@processed' => $sandbox['records_processed'], + '@total' => $sandbox['total_records'], + ]); + } + else { + return (string) t("There were no overridden Metatag records."); + } } diff --git a/web/modules/metatag/metatag.libraries.yml b/web/modules/metatag/metatag.libraries.yml new file mode 100644 index 0000000000000000000000000000000000000000..6db3adf4b7809d924e0fe5c919237a378f58e33e --- /dev/null +++ b/web/modules/metatag/metatag.libraries.yml @@ -0,0 +1,6 @@ +# Custom libraries for the Metatag module. + +firehose_widget: + css: + theme: + css/firehose_widget.css: {} diff --git a/web/modules/metatag/metatag.module b/web/modules/metatag/metatag.module index 565298c83a6c681187b6bd378f7c678a84457745..0200e7045f5db280aed48ba5253a9b06a27ce3f3 100644 --- a/web/modules/metatag/metatag.module +++ b/web/modules/metatag/metatag.module @@ -5,8 +5,8 @@ * Contains metatag.module. */ +use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Component\Plugin\Factory\DefaultFactory; -use Drupal\Component\Utility\Html; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Entity\EntityInterface; @@ -26,7 +26,8 @@ use Drupal\taxonomy\TermInterface; use Drupal\user\Plugin\migrate\source\d6\User as User6; use Drupal\user\Plugin\migrate\source\d7\User as User7; -use Drupal\Core\Render\HtmlResponseAttachmentsProcessor; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\commerce_migrate_commerce\Plugin\migrate\source\commerce1\ProductDisplay; /** * Implements hook_help(). @@ -35,32 +36,32 @@ function metatag_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { // Main module help for the Metatag module. case 'help.page.metatag': - $output = '<h2>' . t('About') . '</h2>'; - $output .= '<p>' . t('This module allows a site to automatically provide structured metadata, aka "meta tags", about the site and individual pages.'); - $output .= '<p>' . t('In the context of search engine optimization, providing an extensive set of meta tags may help improve the site\'s and pages\' rankings, thus may aid with achieving a more prominent display of the content within search engine results. They can also be used to tailor how content is displayed when shared on social networks. For additional information, see the <a href=":online">online documentation for Metatag</a>.', [':online' => 'https://www.drupal.org/node/1774342']) . '</p>'; - $output .= '<h3>' . t('Intended worflow') . '</h3>'; - $output .= '<p>' . t('The module uses <a href=":tokens">"tokens"</a> to automatically fill in values for different meta tags. Specific values may also be filled in.', [':tokens' => Url::fromRoute('help.page', ['name' => 'token'])->toString()]) . '</p>'; - $output .= '<p>' . t('The best way of using Metatag is as follows:') . '</p>'; + $output = '<h2>' . (string) new TranslatableMarkup('About') . '</h2>'; + $output .= '<p>' . (string) new TranslatableMarkup('This module allows a site to automatically provide structured metadata, aka "meta tags", about the site and individual pages.'); + $output .= '<p>' . (string) new TranslatableMarkup('In the context of search engine optimization, providing an extensive set of meta tags may help improve the site\'s and pages\' rankings, thus may aid with achieving a more prominent display of the content within search engine results. They can also be used to tailor how content is displayed when shared on social networks. For additional information, see the <a href=":online">online documentation for Metatag</a>.', [':online' => 'https://www.drupal.org/node/1774342']) . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('Intended worflow') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('The module uses <a href=":tokens">"tokens"</a> to automatically fill in values for different meta tags. Specific values may also be filled in.', [':tokens' => Url::fromRoute('help.page', ['name' => 'token'])->toString()]) . '</p>'; + $output .= '<p>' . (string) new TranslatableMarkup('The best way of using Metatag is as follows:') . '</p>'; $output .= '<ol>'; - $output .= '<li>' . t('Customize the <a href=":defaults">global defaults</a>, fill in the specific values and tokens that every page should have.', [':defaults' => Url::fromRoute('entity.metatag_defaults.edit_form', ['metatag_defaults' => 'global'])->toString()]) . '</li>'; - $output .= '<li>' . t('Override each of the <a href=":defaults">other defaults</a>, fill in specific values and tokens that each item should have by default. This allows e.g. for all nodes to have different values than taxonomy terms.', [':defaults' => Url::fromRoute('entity.metatag_defaults.collection')->toString()]) . '</li>'; - $output .= '<li>' . t('<a href=":add">Add more default configurations</a> as necessary for different entity types and entity bundles, e.g. for different content types or different vocabularies.', [':add' => Url::fromRoute('entity.metatag_defaults.add_form')->toString()]) . '</li>'; - $output .= '<li>' . 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.') . '</li>'; + $output .= '<li>' . (string) new TranslatableMarkup('Customize the <a href=":defaults">global defaults</a>, fill in the specific values and tokens that every page should have.', [':defaults' => Url::fromRoute('entity.metatag_defaults.edit_form', ['metatag_defaults' => 'global'])->toString()]) . '</li>'; + $output .= '<li>' . (string) new TranslatableMarkup('Override each of the <a href=":defaults">other defaults</a>, fill in specific values and tokens that each item should have by default. This allows e.g. for all nodes to have different values than taxonomy terms.', [':defaults' => Url::fromRoute('entity.metatag_defaults.collection')->toString()]) . '</li>'; + $output .= '<li>' . (string) new TranslatableMarkup('<a href=":add">Add more default configurations</a> as necessary for different entity types and entity bundles, e.g. for different content types or different vocabularies.', [':add' => Url::fromRoute('entity.metatag_defaults.add_form')->toString()]) . '</li>'; + $output .= '<li>' . (string) new TranslatableMarkup('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.') . '</li>'; $output .= '</ol>'; return $output; // The main configuration page. case 'entity.metatag_defaults.collection': - $output = '<p>' . t('Configure global meta tag default values below. Meta tags may be left as the default.') . '</p>'; - $output .= '<p>' . t('Meta tag patterns are passed down from one level to the next unless they are overridden. To view a summary of the individual meta tags and the pattern for a specific configuration, click on its name below.') . '</p>'; - $output .= '<p>' . 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.') . '</p>'; - $output .= '<p>' . 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.') . '</p>'; + $output = '<p>' . (string) new TranslatableMarkup('Configure global meta tag default values below. Meta tags may be left as the default.') . '</p>'; + $output .= '<p>' . (string) new TranslatableMarkup('Meta tag patterns are passed down from one level to the next unless they are overridden. To view a summary of the individual meta tags and the pattern for a specific configuration, click on its name below.') . '</p>'; + $output .= '<p>' . (string) new TranslatableMarkup('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.') . '</p>'; + $output .= '<p>' . (string) new TranslatableMarkup('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.') . '</p>'; return $output; // The 'add default meta tags' configuration page. case 'entity.metatag_defaults.add_form': - $output = '<p>' . 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 <em>default values</em> than others.') . '</p>'; - $output .= '<p>' . 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.') . '</p>'; + $output = '<p>' . (string) new TranslatableMarkup('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 <em>default values</em> than others.') . '</p>'; + $output .= '<p>' . (string) new TranslatableMarkup('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.') . '</p>'; return $output; } } @@ -69,6 +70,7 @@ function metatag_help($route_name, RouteMatchInterface $route_match) { * Implements hook_form_FORM_ID_alter() for 'field_storage_config_edit_form'. */ function metatag_form_field_storage_config_edit_form_alter(&$form, FormStateInterface $form_state) { + // @todo Does this actually work? if ($form_state->getFormObject()->getEntity()->getType() == 'metatag') { // Hide the cardinality field. $form['cardinality_container']['#access'] = FALSE; @@ -83,6 +85,7 @@ function metatag_form_field_storage_config_edit_form_alter(&$form, FormStateInte * any values to be saved. */ function metatag_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state) { + // @todo Does this actually work? if ($form_state->getFormObject()->getEntity()->getType() == 'metatag') { // Hide the required and default value fields. $form['required']['#access'] = FALSE; @@ -142,7 +145,6 @@ function metatag_page_attachments(array &$attachments) { $attachments['#attached']['html_head'] = []; } - $head_links = []; foreach ($metatag_attachments['#attached']['html_head'] as $item) { // Do not attach a title meta tag as this unnecessarily duplicates the // title tag. @@ -152,32 +154,6 @@ function metatag_page_attachments(array &$attachments) { } $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 (isset($item[0]['#attributes']['href'])) { - if (in_array($item[1], ['canonical_url', 'shortlink'])) { - $attributes = $item[0]['#attributes']; - - $href = '<' . Html::escape($attributes['href']) . '>'; - unset($attributes['href']); - $param = HtmlResponseAttachmentsProcessor::formatHttpHeaderAttributes($attributes); - if (!empty($param)) { - $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, - ]; } } } @@ -253,7 +229,7 @@ function metatag_entity_view_alter(array &$build, EntityInterface $entity, Entit * The result. */ function _metatag_is_entity_route_entity(EntityInterface $entity): bool { - static $cached_entity_uuid; + $cached_entity_uuid = &drupal_static(__FUNCTION__); if (!$cached_entity_uuid) { foreach (\Drupal::routeMatch()->getParameters() as $route_parameter) { if ($route_parameter instanceof EntityInterface) { @@ -274,6 +250,10 @@ function _metatag_is_entity_route_entity(EntityInterface $entity): bool { * * @return array * The filtered render array. + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3305580 */ function _metatag_panelizer_pre_render(array $element) { _metatag_remove_duplicate_entity_tags($element); @@ -300,11 +280,12 @@ function _metatag_remove_duplicate_entity_tags(array &$build) { // Check to see if the page currently outputs a canonical and/or shortlink // tag. if (isset($metatag_attachments['#attached']['html_head'])) { + $tags_to_look_for = ['canonical', 'shortlink']; foreach ($metatag_attachments['#attached']['html_head'] as $metatag_item) { 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'], ['canonical', 'shortlink'])) { + if (isset($item[0]['rel']) && in_array($item[0]['rel'], $tags_to_look_for)) { // Remove the link rel="canonical" or link rel="shortlink" tag // from the entity's build array. unset($build['#attached']['html_head_link'][$key]); @@ -347,19 +328,28 @@ function metatag_is_current_route_supported() { /** * Returns the entity of the current route. * - * @return Drupal\Core\Entity\EntityInterface + * @return Drupal\Core\Entity\EntityInterface|null * The entity or NULL if this is not an entity route. */ function metatag_get_route_entity() { $route_match = \Drupal::routeMatch(); $route_name = $route_match->getRouteName(); + // In certain circumstances the route can be empty. + if (is_null($route_name)) { + return NULL; + } + // Look for a canonical entity view page, e.g. node/{nid}, user/{uid}, etc. $matches = []; preg_match('/entity\.(.*)\.(latest[_-]version|canonical)/', $route_name, $matches); if (!empty($matches[1])) { $entity_type = $matches[1]; - return $route_match->getParameter($entity_type); + $entity_object = $route_match->getParameter($entity_type); + if (!$entity_object instanceof EntityInterface) { + return NULL; + } + return $entity_object; } // Look for a rest entity view page, e.g. "node/{nid}?_format=json", etc. @@ -368,7 +358,11 @@ function metatag_get_route_entity() { preg_match('/rest\.entity\.(.*)\.(.*)\.(.*)/', $route_name, $matches); if (!empty($matches[1])) { $entity_type = $matches[1]; - return $route_match->getParameter($entity_type); + $entity_object = $route_match->getParameter($entity_type); + if (!$entity_object instanceof EntityInterface) { + return NULL; + } + return $entity_object; } // Look for entity object 'add' pages, e.g. "node/add/{bundle}". @@ -377,7 +371,7 @@ function metatag_get_route_entity() { if (!empty($route_name_matches[2])) { $entity_type = $route_name_matches[2]; $definition = Drupal::entityTypeManager()->getDefinition($entity_type, FALSE); - if (!empty($definition)) { + if (!empty($definition) && $definition->get('bundle_entity_type')) { $type = $route_match->getRawParameter($definition->get('bundle_entity_type')); if (!empty($type)) { return \Drupal::entityTypeManager() @@ -427,15 +421,13 @@ function metatag_get_route_entity() { // one bundle and it's named the same as the entity type, so some shortcuts // can be used. if ($route_name == 'user.admin_create') { - $entity_type = $type = 'user'; + $entity_type = 'user'; $definition = Drupal::entityTypeManager()->getDefinition($entity_type); - if (!empty($type)) { - return \Drupal::entityTypeManager() - ->getStorage($entity_type) - ->create([ - $definition->get('entity_keys')['bundle'] => $type, - ]); - } + return \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->create([ + $definition->get('entity_keys')['bundle'] => $entity_type, + ]); } // Trigger hook_metatag_route_entity(). @@ -454,7 +446,7 @@ function metatag_preprocess_html(&$variables) { return NULL; } - $metatag_attachments = &drupal_static('metatag_attachments'); + $metatag_attachments = &drupal_static('metatag_attachments', NULL); if (is_null($metatag_attachments)) { $metatag_attachments = metatag_get_tags_from_route(); } @@ -539,12 +531,13 @@ function metatag_get_default_tags($entity = NULL) { $global_metatag_manager = \Drupal::entityTypeManager()->getStorage('metatag_defaults'); /** @var \Drupal\metatag\MetatagManager $metatag_manager */ $metatag_manager = \Drupal::service('metatag.manager'); + /** @var \Drupal\Core\Language\LanguageManagerInterface */ + $language_manager = \Drupal::languageManager(); // Load config based on language. $current_language = NULL; if ($entity !== NULL) { /** @var \Drupal\Core\Language\LanguageManagerInterface $language_manager */ - $language_manager = \Drupal::languageManager(); $current_language = $language_manager->getConfigOverrideLanguage(); $language_manager->setConfigOverrideLanguage($entity->language()); } @@ -623,55 +616,6 @@ function metatag_entity_base_field_info(EntityTypeInterface $entity_type) { 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. * @@ -702,15 +646,21 @@ function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, M } // Work out what sort of migration to do. Cache the results of this logic so - // that it isn't checked on every single row being processed. - static $metatag_table_exists, $nodewords_table_exists; - if (!isset($metatag_table_exists)) { - $metatag_table_exists = $source->getDatabase()->schema()->tableExists('metatag'); - $nodewords_table_exists = $source->getDatabase()->schema()->tableExists('nodewords'); + // that it isn't checked on every single row being processed. Store this as + // separate keys to work with situations where the source changes during the + // migration. + $metatag_table_exists = &drupal_static('metatag_migrate_prepare_row_metatag_table_exists', []); + $nodewords_table_exists = &drupal_static('metatag_migrate_prepare_row_nodewords_table_exists', []); + $source_db_key = $source->getDatabase()->getKey(); + if (!isset($metatag_table_exists[$source_db_key])) { + $metatag_table_exists[$source_db_key] = $source->getDatabase()->schema()->tableExists('metatag'); + } + if (!isset($nodewords_table_exists[$source_db_key])) { + $nodewords_table_exists[$source_db_key] = $source->getDatabase()->schema()->tableExists('nodewords'); } // The source is Metatag-D7. - if ($metatag_table_exists) { + if ($metatag_table_exists[$source_db_key]) { // @todo Write a more general version rather than hard-coded. // Support a know subset of D7 sources. if (is_a($source, Node7::class)) { @@ -725,6 +675,11 @@ function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, M // E.g. d7_user. $source_type = 'user'; } + // Custom handling for Drupal Commerce. + elseif (\Drupal::moduleHandler()->moduleExists('commerce_migrate_commerce') && is_a($source, ProductDisplay::class)) { + // Products were nodes in Drupal 7 so map the $source_type to node. + $source_type = 'node'; + } else { // Not supported now, nothing to do. return; @@ -775,7 +730,7 @@ function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, M } // The source is Nodewords-D6. - elseif ($nodewords_table_exists) { + elseif ($nodewords_table_exists[$source_db_key]) { // @todo Write a more general version rather than hard-coded. // Support a know subset of D6 sources. if (is_a($source, Node6::class)) { @@ -801,24 +756,31 @@ function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, M // @todo Write a more general version rather than a switch statement. switch ($source_type) { case 'node': - // define('NODEWORDS_TYPE_NODE', 5); + // @code + // define('NODEWORDS_TYPE_NODE', 5); + // @endcode $nodeword_type = 5; $entity_id = $row->getSourceProperty('nid'); break; case 'taxonomy_term': - // define('NODEWORDS_TYPE_TERM', 6); + // @code + // define('NODEWORDS_TYPE_TERM', 6); + // @endcode $nodeword_type = 6; $entity_id = $row->getSourceProperty('tid'); break; case 'user': - // define('NODEWORDS_TYPE_USER', 8); + // @code + // define('NODEWORDS_TYPE_USER', 8); + // @endcode $nodeword_type = 8; $entity_id = $row->getSourceProperty('uid'); break; } - // @todo + // @todo Migrate these configuration items. + // @code // define('NODEWORDS_TYPE_BLOG', 13); // define('NODEWORDS_TYPE_DEFAULT', 1); // define('NODEWORDS_TYPE_ERRORPAGE', 2); @@ -830,7 +792,7 @@ function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, M // define('NODEWORDS_TYPE_PAGER', 4); // define('NODEWORDS_TYPE_TRACKER', 7); // define('NODEWORDS_TYPE_VOCABULARY', 9); - + // @endcode /** @var \Drupal\migrate\Plugin\migrate\source\SqlBase $source */ /** @var \Drupal\Core\Database\Query\SelectInterface $query */ $query = $source->getDatabase()->select('nodewords', 'nw') @@ -840,7 +802,7 @@ function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, M ->orderBy('nw.name'); $value = $query->execute()->fetchAllKeyed(); - $row->setSourceProperty('pseudo_metatag_entities', $value); + $row->setSourceProperty('pseudo_metatag_entities', $value); } } } @@ -994,7 +956,7 @@ function _metatag_is_migration_plugin_supported(array $definition) { return FALSE; } } - catch (\Drupal\Component\Plugin\Exception\PluginNotFoundException $e) { + catch (PluginNotFoundException $e) { // If the entity type doesn't exist, neither with the migration plugin. return FALSE; } diff --git a/web/modules/metatag/metatag.post_update.php b/web/modules/metatag/metatag.post_update.php new file mode 100644 index 0000000000000000000000000000000000000000..5b3dfce61d17a2911ac1516ef11ccbd632a3b5ed --- /dev/null +++ b/web/modules/metatag/metatag.post_update.php @@ -0,0 +1,186 @@ +<?php + +/** + * @file + * Post update functions for Metatag. + */ + +use Drupal\Core\Config\Entity\ConfigEntityUpdater; +use Drupal\metatag\Entity\MetatagDefaults; + +/** + * Convert mask-icon to array values. + */ +function metatag_post_update_convert_mask_icon_to_array_values(&$sandbox) { + $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class); + $config_entity_updater->update($sandbox, 'metatag_defaults', function (MetatagDefaults $metatag_defaults) { + if ($metatag_defaults->hasTag('mask-icon')) { + $tags = $metatag_defaults->get('tags'); + $tags['mask_icon'] = [ + 'href' => $metatag_defaults->getTag('mask-icon'), + ]; + unset($tags['mask-icon']); + $metatag_defaults->set('tags', $tags); + return TRUE; + } + return FALSE; + }); +} + +/** + * The author meta tag was moved into the main module: configuration. + */ +function metatag_post_update_convert_author_config(&$sandbox) { + $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class); + $config_entity_updater->update($sandbox, 'metatag_defaults', function (MetatagDefaults $metatag_defaults) { + if ($metatag_defaults->hasTag('google_plus_author')) { + $tags = $metatag_defaults->get('tags'); + $tags['author'] = $metatag_defaults->getTag('google_plus_author'); + unset($tags['google_plus_author']); + $metatag_defaults->set('tags', $tags); + return TRUE; + } + return FALSE; + }); +} + +/** + * The author meta tag was moved into the main module: entity data. + */ +function metatag_post_update_convert_author_data(&$sandbox) { + // This whole top section only needs to be done the first time. + if (!isset($sandbox['records_processed'])) { + $sandbox['records_processed'] = 0; + $sandbox['total_records'] = 0; + $sandbox['current_field'] = 0; + $sandbox['current_record'] = 0; + + // Counter to enumerate the fields so we can access them in the array + // by number rather than name. + $field_counter = 0; + + // Get all of the field storage entities of type metatag. + /** @var \Drupal\field\FieldStorageConfigInterface[] $field_storage_configs */ + $field_storage_configs = \Drupal::entityTypeManager() + ->getStorage('field_storage_config') + ->loadByProperties(['type' => 'metatag']); + + foreach ($field_storage_configs as $field_storage) { + $field_name = $field_storage->getName(); + + // Get the individual fields (field instances) associated with bundles. + $fields = \Drupal::entityTypeManager() + ->getStorage('field_config') + ->loadByProperties([ + 'field_name' => $field_name, + 'entity_type' => $field_storage->getTargetEntityTypeId(), + ]); + + foreach ($fields as $field) { + // Get the bundle this field is attached to. + $bundle = $field->getTargetBundle(); + + // Determine the table and "value" field names. + // @todo The class path to getTableMapping() seems to be invalid? + $table_mapping = Drupal::entityTypeManager() + ->getStorage($field->getTargetEntityTypeId()) + ->getTableMapping(); + $field_table = $table_mapping->getFieldTableName($field_name); + $field_value_field = $table_mapping->getFieldColumnName($field_storage, 'value'); + + // Get all records where the field data does not match the default. + $query = \Drupal::database()->select($field_table); + $query->addField($field_table, 'entity_id'); + $query->addField($field_table, 'revision_id'); + $query->addField($field_table, 'langcode'); + $query->addField($field_table, $field_value_field); + $query->condition('bundle', $bundle, '='); + $result = $query->execute(); + $records = $result->fetchAll(); + + if (empty($records)) { + continue; + } + + // Fill in all the sandbox information so we can batch the individual + // record comparing and updating. + $sandbox['fields'][$field_counter]['field_table'] = $field_table; + $sandbox['fields'][$field_counter]['field_value_field'] = $field_value_field; + $sandbox['fields'][$field_counter]['records'] = $records; + + $sandbox['total_records'] += count($sandbox['fields'][$field_counter]['records'] = $records); + $field_counter++; + } + } + } + + if ($sandbox['total_records'] == 0) { + // No partially overridden fields so we can skip the whole batch process. + $sandbox['#finished'] = 1; + } + else { + // Begin the batch processing of individual field records. + $max_per_batch = 10; + $counter = 1; + + $current_field = $sandbox['current_field']; + $current_field_records = $sandbox['fields'][$current_field]['records']; + $current_record = $sandbox['current_record']; + + $field_table = $sandbox['fields'][$current_field]['field_table']; + $field_value_field = $sandbox['fields'][$current_field]['field_value_field']; + + // Loop through the field(s) and update the mask_icon values if necessary. + while ($counter <= $max_per_batch && isset($current_field_records[$current_record])) { + $record = $current_field_records[$current_record]; + + // Strip any empty tags or ones matching the field's defaults and leave + // only the overridden tags in $new_tags. + $tags = unserialize($record->$field_value_field); + if (isset($tags['google_plus_author'])) { + $tags['author'] = $tags['google_plus_author']; + $tags_string = serialize($tags); + \Drupal::database()->update($field_table) + ->fields([ + $field_value_field => $tags_string, + ]) + ->condition('entity_id', $record->entity_id) + ->condition('revision_id', $record->revision_id) + ->condition('langcode', $record->langcode) + ->execute(); + } + $counter++; + $current_record++; + } + + // We ran out of records for the field so start the next batch out with the + // next field. + if (!isset($current_field_records[$current_record])) { + $current_field++; + $current_record = 0; + } + + // We have finished all the fields. All done. + if (!isset($sandbox['fields'][$current_field])) { + $sandbox['records_processed'] += $counter - 1; + $sandbox['#finished'] = 1; + } + // Update the sandbox values to prepare for the next round. + else { + $sandbox['current_field'] = $current_field; + $sandbox['current_record'] = $current_record; + $sandbox['records_processed'] += $counter - 1; + $sandbox['#finished'] = $sandbox['records_processed'] / $sandbox['total_records']; + } + } + + if ($sandbox['total_records'] > 0) { + return (string) t('Processed @processed of @total overridden Metatag records.', [ + '@processed' => $sandbox['records_processed'], + '@total' => $sandbox['total_records'], + ]); + } + else { + return (string) t("There were no overridden Metatag records."); + } +} diff --git a/web/modules/metatag/metatag.routing.yml b/web/modules/metatag/metatag.routing.yml index 46a1ae93e23764e488bcb05b29449b2a48a617da..0a46ed9b23ef4607e85d441fddba791971e905b3 100644 --- a/web/modules/metatag/metatag.routing.yml +++ b/web/modules/metatag/metatag.routing.yml @@ -23,7 +23,7 @@ entity.metatag_defaults.edit_form: path: '/admin/config/search/metatag/{metatag_defaults}' defaults: _entity_form: 'metatag_defaults.edit' - _title: 'Edit default meta tags' + _title_callback: '\Drupal\metatag\Form\MetatagDefaultsForm::getTitle' requirements: _permission: 'administer meta tags' options: diff --git a/web/modules/metatag/metatag.services.yml b/web/modules/metatag/metatag.services.yml index ad93bfed07d54721c169b12981498f7089cd999f..823172bd7b8686850d8e925b2eca683902c87599 100644 --- a/web/modules/metatag/metatag.services.yml +++ b/web/modules/metatag/metatag.services.yml @@ -9,8 +9,22 @@ services: metatag.token: class: Drupal\metatag\MetatagToken - arguments: ['@token', '@token.entity_mapper'] + arguments: + - '@token' + - '@token.entity_mapper' metatag.manager: class: Drupal\metatag\MetatagManager - arguments: ['@plugin.manager.metatag.group', '@plugin.manager.metatag.tag', '@metatag.token', '@logger.factory', '@entity_type.manager'] + arguments: + - '@plugin.manager.metatag.group' + - '@plugin.manager.metatag.tag' + - '@metatag.token' + - '@logger.factory' + - '@entity_type.manager' + - '@path.matcher' + - '@current_route_match' + - '@request_stack' + - '@language_manager' + + metatag.trimmer: + class: Drupal\metatag\MetatagTrimmer diff --git a/web/modules/metatag/metatag.tokens.inc b/web/modules/metatag/metatag.tokens.inc index 8b1674d35c747e3c9286c16ecaf9bd4772a38c2e..5d88305224a3b1ccd70c3c514031ef95fd525aa4 100644 --- a/web/modules/metatag/metatag.tokens.inc +++ b/web/modules/metatag/metatag.tokens.inc @@ -8,6 +8,7 @@ use Drupal\Component\Utility\Html; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Render\BubbleableMetadata; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_token_info(). @@ -20,14 +21,14 @@ function metatag_token_info() { $tag_definitions = $tag_manager->getDefinitions(); $info['types']['metatag'] = [ - 'name' => t('Metatags'), - 'description' => t('Tokens related to Metatags.'), + 'name' => new TranslatableMarkup('Metatags'), + 'description' => new TranslatableMarkup('Tokens related to Metatags.'), 'needs-data' => 'metatag', ]; foreach ($tag_definitions as $tag_id => $tag_definition) { $label = $tag_definition['label']; - $description = $tag_definition['description']; + $description = $tag_definition['description'] ?? ''; $multiple = $tag_definition['multiple']; $metatag_token_name = 'metatag-' . $tag_id; @@ -37,8 +38,8 @@ function metatag_token_info() { } $info['tokens']['current-page']['metatag'] = [ - 'name' => t('Metatags'), - 'description' => t('Metatag values for the current page.'), + 'name' => new TranslatableMarkup('Metatags'), + 'description' => new TranslatableMarkup('Metatag values for the current page.'), 'type' => 'metatag', ]; $info['tokens']['metatag'][$tag_id] = [ @@ -49,7 +50,7 @@ function metatag_token_info() { $info['types'][$metatag_token_name] = [ 'name' => Html::escape($label), - 'description' => t('@label tokens.', ['@label' => Html::escape($label)]), + 'description' => new TranslatableMarkup('@label tokens.', ['@label' => Html::escape($label)]), 'needs-data' => $metatag_token_name, 'nested' => TRUE, ]; @@ -63,8 +64,8 @@ function metatag_token_info() { // Tag list token type. if ($multiple) { $info['types']["list<$metatag_token_name>"] = [ - 'name' => t('List of @type values', ['@type' => Html::escape($label)]), - 'description' => t('Tokens for lists of @type values.', ['@type' => Html::escape($label)]), + 'name' => new TranslatableMarkup('List of @type values', ['@type' => Html::escape($label)]), + 'description' => new TranslatableMarkup('Tokens for lists of @type values.', ['@type' => Html::escape($label)]), 'needs-data' => "list<$metatag_token_name>", 'nested' => TRUE, ]; @@ -73,7 +74,7 @@ function metatag_token_info() { // Since we don't know how many there will be, we will just show 3. for ($delta = 0; $delta < 3; $delta++) { $info['tokens']["list<$metatag_token_name>"][$delta] = [ - 'name' => t('@type type with delta @delta', [ + 'name' => new TranslatableMarkup('@type type with delta @delta', [ '@type' => Html::escape($label), '@delta' => $delta, ]), @@ -110,7 +111,7 @@ function metatag_token_info_alter(&$info) { $field_token_name = $token_type . '-' . $field->getName(); $info['types'][$field_token_name] = [ 'name' => Html::escape($field->getName()), - 'description' => t('@label tokens.', ['@label' => Html::escape($field->getName())]), + 'description' => new TranslatableMarkup('@label tokens.', ['@label' => Html::escape($field->getName())]), 'needs-data' => $field_token_name, 'nested' => TRUE, 'type' => 'metatag', @@ -128,7 +129,7 @@ function metatag_tokens($type, $tokens, array $data, array $options, BubbleableM switch ($type) { case 'current-page': - /** @var \Drupal\token\TokenInterface $token_service */ + /** @var \Drupal\Core\Utility\Token $token_service */ $token_service = \Drupal::token(); $metatag_tokens = $token_service->findWithPrefix($tokens, 'metatag'); if (!empty($metatag_tokens) && metatag_is_current_route_supported()) { @@ -141,7 +142,7 @@ function metatag_tokens($type, $tokens, array $data, array $options, BubbleableM case 'entity': if (!empty($data['entity_type']) && !empty($data['entity']) && !empty($data['token_type'])) { - /* @var \Drupal\Core\Entity\ContentEntityInterface $entity */ + /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ $entity = $data['entity']; if (!($entity instanceof ContentEntityInterface)) { return $replacements; @@ -157,7 +158,7 @@ function metatag_tokens($type, $tokens, array $data, array $options, BubbleableM } if (!empty($metatag_fields)) { - /** @var \Drupal\token\TokenInterface $token_service */ + /** @var \Drupal\Core\Utility\Token $token_service */ $token_service = \Drupal::token(); $metatag_tokens = []; foreach ($metatag_fields as $metatag_field) { @@ -172,7 +173,7 @@ function metatag_tokens($type, $tokens, array $data, array $options, BubbleableM $metatag_manager = \Drupal::service('metatag.manager'); $entity = $options['entity'] ?? metatag_get_route_entity(); - $tags = metatag_get_default_tags($entity); + $tags = []; if ($entity instanceof ContentEntityInterface) { // If content entity does not have an ID the page is likely an "Add" // page, so skip processing for entity which has not been created yet. @@ -180,8 +181,9 @@ function metatag_tokens($type, $tokens, array $data, array $options, BubbleableM return NULL; } - $tags += $metatag_manager->tagsFromEntity($entity); + $tags = $metatag_manager->tagsFromEntity($entity); } + $tags += metatag_get_default_tags($entity); // Trigger hook_metatags_alter(). // Allow modules to override tags or the entity used for token @@ -206,7 +208,7 @@ function metatag_tokens($type, $tokens, array $data, array $options, BubbleableM // For [metatag:tag_name:0], [metatag:tag_name:0:value] and // [metatag:tag_name:value] tokens. else { - list($tag_name, $delta) = explode(':', $name, 2); + [$tag_name, $delta] = explode(':', $name, 2); if (!is_numeric($delta)) { unset($delta); } @@ -225,7 +227,7 @@ function metatag_tokens($type, $tokens, array $data, array $options, BubbleableM } else { if (is_array($processed_tags[$tag_name])) { - $replacements[$original] = implode(',', $processed_tags[$tag_name]); + $replacements[$original] = implode(',', array_filter($processed_tags[$tag_name])); } else { $replacements[$original] = $processed_tags[$tag_name]; diff --git a/web/modules/metatag/metatag_app_links/metatag_app_links.info.yml b/web/modules/metatag/metatag_app_links/metatag_app_links.info.yml index b5a57a087c4c9b778da787184bcd57eed9c6dc48..7b925788451309879dba8ba078b35c3d700d04be 100644 --- a/web/modules/metatag/metatag_app_links/metatag_app_links.info.yml +++ b/web/modules/metatag/metatag_app_links/metatag_app_links.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: App Links' type: module description: Provides support for applinks.org meta tags. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_app_links/metatag_app_links.module b/web/modules/metatag/metatag_app_links/metatag_app_links.module index a350752bc8f14c37ae6113d3f9b7598228bf04f7..eab86390d301cb6d227e77649880aed2e0cbc26b 100644 --- a/web/modules/metatag/metatag_app_links/metatag_app_links.module +++ b/web/modules/metatag/metatag_app_links/metatag_app_links.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_app_links_help($route_name, RouteMatchInterface $route_match) { // Main module help for the metatag_app_links module. case 'help.page.metatag_app_links': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Provides support for applinks.org meta tags.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Provides support for applinks.org meta tags.') . '</p>'; return $output; default: diff --git a/web/modules/metatag/metatag_dc/config/schema/metatag_dc.metatag_tag.schema.yml b/web/modules/metatag/metatag_dc/config/schema/metatag_dc.metatag_tag.schema.yml index afda126fbac9d66b966ae58bbc345b95ee300233..a6e1255e0e7374d6f163b48b6fd9728b605b0293 100644 --- a/web/modules/metatag/metatag_dc/config/schema/metatag_dc.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_dc/config/schema/metatag_dc.metatag_tag.schema.yml @@ -42,7 +42,7 @@ metatag.metatag_tag.dcterms_subject: type: label label: 'Dublin Core: Subject' metatag.metatag_tag.dcterms_title: - type: label + type: text label: 'Dublin Core: Title' metatag.metatag_tag.dcterms_type: type: label diff --git a/web/modules/metatag/metatag_dc/metatag_dc.info.yml b/web/modules/metatag/metatag_dc/metatag_dc.info.yml index e084b6bf31801655157da36fe8ef0f385e5010a0..fa7f8013f9e4c94f7ae8795115ddc54005a80584 100644 --- a/web/modules/metatag/metatag_dc/metatag_dc.info.yml +++ b/web/modules/metatag/metatag_dc/metatag_dc.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Dublin Core' type: module description: Provides the fifteen <a href="https://dublincore.org/documents/dces/">Dublin Core Metadata Element Set 1.1</a> meta tags from the <a href="https://dublincore.org/">Dublin Core Metadata Institute</a>. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Description.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Description.php index 8ea944f48b3d65bad1b9ce2f149afa92d860a21b..49a7d97962136b6c5f19547b4415c4eb24083ca7 100644 --- a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Description.php +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Description.php @@ -16,7 +16,8 @@ * weight = 4, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class Description extends MetaNameBase { diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Title.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Title.php index cfafb4081aa2a16d92426f836e9ec4caeeb8b1d9..313bfac685f0354b362aa9426c32def6acab6051 100644 --- a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Title.php +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Title.php @@ -16,7 +16,8 @@ * weight = 1, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class Title extends MetaNameBase { diff --git a/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.info.yml b/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.info.yml index 73aa8bae7a611373de4e91094ac4bf637d3946f4..6c3114339c88b1fb5130a32c75283c0eb60cb5fc 100644 --- a/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.info.yml +++ b/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.info.yml @@ -1,13 +1,13 @@ name: 'Metatag: Dublin Core Advanced' type: module description: 'Provides forty additional meta tags from the <a href="https://dublincore.org/">Dublin Core Metadata Institute</a>.' -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag - metatag:metatag_dc -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.module b/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.module index 407f08fac003b751ffe64d42a055381e02c9c589..f0c6e47650a78095dae5c9423d13461c9454a8d5 100644 --- a/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.module +++ b/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_dc_advanced_help($route_name, RouteMatchInterface $route_match) // Main module help for the metatag_dc_advanced module. case 'help.page.metatag_dc_advanced': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Provides forty additional meta tags from the <a href="https://dublincore.org/">Dublin Core Metadata Institute</a>.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Provides forty additional meta tags from the <a href="https://dublincore.org/">Dublin Core Metadata Institute</a>.') . '</p>'; return $output; default: diff --git a/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.info.yml b/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.info.yml index 928385acb9b475259ae2d134c58e2524689f38ac..9ae0541949d3e9d5a115612ab356df193d68196f 100644 --- a/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.info.yml +++ b/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.info.yml @@ -1,12 +1,12 @@ name: Metatag Extended Permissions type: module -description: "Adds individual permissions for each meta tag, allowing for fine-grained access to the meta tags. Note: this may nead to performance issues on the permissions admin page, please see the included README.txt file for details." -core_version_requirement: '^8.7.7 || ^9' +description: "Adds individual permissions for each meta tag, allowing for fine-grained access to the meta tags. Note: this may lead to performance issues on the permissions admin page, please see the included README.txt file for details." +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - - metatag + - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.module b/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.module index 9061ab9594ed1e1ffba8d568db5d57c24d31c55c..17adc04853225ace3c23e3523d39d62a1a521dfa 100644 --- a/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.module +++ b/web/modules/metatag/metatag_extended_perms/metatag_extended_perms.module @@ -10,9 +10,9 @@ use Drupal\metatag\Plugin\Field\FieldWidget\MetatagFirehose; /** - * Implements hook_field_widget_form_alter(). + * Implements hook_field_widget_single_element_form_alter(). */ -function metatag_extended_perms_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) { +function metatag_extended_perms_field_widget_single_element_form_alter(&$element, FormStateInterface $form_state, $context) { if ($context['widget'] instanceof MetatagFirehose) { $group_manager = \Drupal::getContainer()->get('plugin.manager.metatag.group'); diff --git a/web/modules/metatag/metatag_extended_perms/tests/src/Functional/PermissionsTest.php b/web/modules/metatag/metatag_extended_perms/tests/src/Functional/PermissionsTest.php index 392cb0c960c53939274353ed66fbe76b42d93e93..ba1ab3f9e85fe20ef31721c5d7fe751549e437d5 100644 --- a/web/modules/metatag/metatag_extended_perms/tests/src/Functional/PermissionsTest.php +++ b/web/modules/metatag/metatag_extended_perms/tests/src/Functional/PermissionsTest.php @@ -3,6 +3,8 @@ namespace Drupal\Tests\metatag_extended_perms\Functional; use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\metatag\Functional\MetatagHelperTrait; +use Drupal\node\Entity\NodeType; /** * Verify the new permissions are added. @@ -12,7 +14,7 @@ class PermissionsTest extends BrowserTestBase { // Contains helper methods. - use \Drupal\Tests\metatag\Functional\MetatagHelperTrait; + use MetatagHelperTrait; /** * {@inheritdoc} @@ -22,7 +24,7 @@ class PermissionsTest extends BrowserTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Modules for core functionality. 'node', @@ -70,17 +72,19 @@ class PermissionsTest extends BrowserTestBase { 'revisit_after' => 'Revisit After', 'rights' => 'Rights', // This one is more complicated, so skip it. + // @code // 'robots' => 'Robots', + // @endcode 'set_cookie' => 'Set cookie', 'shortlink' => 'Shortlink URL', 'standout' => 'Standout', - ] + ], ]; /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Log in as the super admin. @@ -88,7 +92,6 @@ protected function setUp() { // Create a content type with a Metatag field. $this->createContentType(); - $this->drupalGet('admin/people/permissions'); } /** @@ -164,8 +167,6 @@ public function testUserPerms() { $perms_yes[] = "access metatag {$group_yes}__{$tag_name}"; } - $this->verbose($perms_yes); - // Create a user account with the above permissions. $user = $this->createUser($perms_yes); $this->drupalLogin($user); @@ -193,8 +194,8 @@ public function testUserPerms() { /** * {@inheritdoc} */ - protected function createContentType(array $values = []) { - parent::createContentType(['type' => 'page']); + protected function createContentType(array $values = []): NodeType { + $type = parent::createContentType(['type' => 'page']); // Load a node form. $this->drupalGet('node/add/page'); @@ -207,11 +208,13 @@ protected function createContentType(array $values = []) { 'field_name' => 'metatag', 'new_storage_type' => 'metatag', ]; - $this->drupalPostForm(NULL, $edit, 'Save and continue'); - $this->drupalPostForm(NULL, [], 'Save field settings'); + $this->submitForm($edit, 'Save and continue'); + $this->submitForm([], 'Save field settings'); // Clear all settings. $this->container->get('entity_field.manager')->clearCachedFieldDefinitions(); + + return $type; } } diff --git a/web/modules/metatag/metatag_facebook/metatag_facebook.info.yml b/web/modules/metatag/metatag_facebook/metatag_facebook.info.yml index ed5f9b5d5649c7dba354bd245b307ea0ead725c1..07a2be755f888e31d4d95e5a4b94f3dccf00fc6a 100644 --- a/web/modules/metatag/metatag_facebook/metatag_facebook.info.yml +++ b/web/modules/metatag/metatag_facebook/metatag_facebook.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Facebook' type: module description: A set of meta tags specially for controlling advanced functionality with Facebook. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_favicons/config/schema/metatag_favicons.metatag_tag.schema.yml b/web/modules/metatag/metatag_favicons/config/schema/metatag_favicons.metatag_tag.schema.yml index e426a0bb63958aa3a3b55e79d38692a1d0a0deff..c69f86cb401d2f968376102ab1a790e57e9a9972 100644 --- a/web/modules/metatag/metatag_favicons/config/schema/metatag_favicons.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_favicons/config/schema/metatag_favicons.metatag_tag.schema.yml @@ -5,9 +5,16 @@ metatag.metatag_tag.shortcut_icon: type: label label: 'Default shortcut icon' -metatag.metatag_tag.mask_ico: - type: label +metatag.metatag_tag.mask_icon: + type: mapping label: 'Icon: SVG' + mapping: + href: + type: label + label: 'href' + color: + type: label + label: 'Color' metatag.metatag_tag.icon_16x16: type: label label: 'Icon: 16px x 16px' diff --git a/web/modules/metatag/metatag_favicons/metatag_favicons.info.yml b/web/modules/metatag/metatag_favicons/metatag_favicons.info.yml index 4b3940f9344b251b737187cc8b00da137c1906af..a7131d3cc8a36ed6fd183486097b8893204c55ff 100644 --- a/web/modules/metatag/metatag_favicons/metatag_favicons.info.yml +++ b/web/modules/metatag/metatag_favicons/metatag_favicons.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Favicons' type: module description: Provides support for many different favicons. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_favicons/metatag_favicons.module b/web/modules/metatag/metatag_favicons/metatag_favicons.module index 39a0b19eea182e070995dca73b3bc432767a40d7..25035109a2a9542b225a62bfffbe31fed82cfa98 100644 --- a/web/modules/metatag/metatag_favicons/metatag_favicons.module +++ b/web/modules/metatag/metatag_favicons/metatag_favicons.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_favicons_help($route_name, RouteMatchInterface $route_match) { // Main module help for the metatag_favicons module. case 'help.page.metatag_favicons': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Provides support for many different favicons.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Provides support for many different favicons.') . '</p>'; return $output; default: @@ -33,10 +34,11 @@ function metatag_favicons_page_attachments_alter(array &$attachments) { } // Remove the default shortcut icon if one was set by Metatag. + $valid_meta_tags = ['shortcut icon', 'shortcut_icon', 'icon']; foreach ($attachments['#attached']['html_head'] as $element) { - if (isset($element[1]) && $element[1] == 'shortcut_icon') { + if (isset($element[1]) && in_array($element[1], $valid_meta_tags)) { foreach ($attachments['#attached']['html_head_link'] as $key => $value) { - if (isset($value[0]['rel']) && $value[0]['rel'] == 'shortcut icon') { + if (isset($value[0]['rel']) && in_array($value[0]['rel'], $valid_meta_tags)) { unset($attachments['#attached']['html_head_link'][$key]); } } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon114x114.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon114x114.php index 5c97c57d4811cf8103da8ef8f368a2c15e9ed0e7..c22a024af69a1ddacb2ba3c11292c3e7b6656231 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon114x114.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon114x114.php @@ -22,7 +22,7 @@ class AppleTouchIcon114x114 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '114x114'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon120x120.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon120x120.php index ae44e26df708c0d4a3971e580752280502ab03a1..c87682632fcce3c0ab1345fb6822179cba1921fe 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon120x120.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon120x120.php @@ -22,7 +22,7 @@ class AppleTouchIcon120x120 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '120x120'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon144x144.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon144x144.php index 77570fd290115d0ab31d5e1f191a73c31ed445c0..3e0ed045f89dcf2d19b1360af3a17b129b226984 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon144x144.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon144x144.php @@ -22,7 +22,7 @@ class AppleTouchIcon144x144 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '144x144'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon152x152.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon152x152.php index a4bc9f497c74ed5f045afc793bc2fff5cf2183ee..b01dab2419b8819c4fa9a76b739d45c4e3508057 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon152x152.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon152x152.php @@ -22,7 +22,7 @@ class AppleTouchIcon152x152 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '152x152'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon180x180.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon180x180.php index e1e50f152be4f3932f7666d9a12dfa8db83e071a..c0395afa0f5cc69e32c6835b0e8de16784274ec9 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon180x180.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon180x180.php @@ -22,7 +22,7 @@ class AppleTouchIcon180x180 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '180x180'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon72x72.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon72x72.php index 0bcaa83d1939e58ae3affc08e49dc86de64b0562..d759e76f5b1594e881c50fb40f0bba6075af72ae 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon72x72.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon72x72.php @@ -22,7 +22,7 @@ class AppleTouchIcon72x72 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '72x72'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon76x76.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon76x76.php index afe12a3abfdaf4611f31098a5a9d3136bf9526c0..ddd005a8b07b2e44697a24c88fb3ee165bf216c3 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon76x76.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon76x76.php @@ -22,7 +22,7 @@ class AppleTouchIcon76x76 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '76x76'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed.php index 8b7eaa39e61eedbd75467a683e3609110cb0373a..5b881c3cfb461d3e678a6c3f5e39f8d6c3ac59dc 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed.php @@ -2,11 +2,11 @@ namespace Drupal\metatag_favicons\Plugin\metatag\Tag; -use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; - /** * The Favicons "apple-touch-icon-precomposed" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed", * label = @Translation("Apple touch icon (precomposed): 57px x 57px"), @@ -19,6 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed extends LinkRelBase { +class AppleTouchIconPrecomposed extends AppleTouchIcon { // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed114x114.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed114x114.php index d6ca574772319ac156859cd6fc976e566f35465f..f7ba7cf07cbb27bf297c2ca77a46dc067a2a434c 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed114x114.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed114x114.php @@ -5,6 +5,8 @@ /** * The Favicons "apple-touch-icon-precomposed_114x114" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed_114x114", * label = @Translation("Apple touch icon (precomposed): 114px x 114px"), @@ -17,13 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed114x114 extends LinkSizesBase { - - /** - * {@inheritdoc} - */ - protected function sizes() { - return '114x114'; - } - +class AppleTouchIconPrecomposed114x114 extends AppleTouchIcon114x114 { + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed120x120.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed120x120.php index 2ffc607b148d7ebff145bba9fe33d99972bcdb50..b1e41981e6c4e61b7f2dadbc4b21c83a03f78ffa 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed120x120.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed120x120.php @@ -5,6 +5,8 @@ /** * The Favicons "apple-touch-icon-precomposed_120x120" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed_120x120", * label = @Translation("Apple touch icon (precomposed): 120px x 120px"), @@ -17,13 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed120x120 extends LinkSizesBase { - - /** - * {@inheritdoc} - */ - protected function sizes() { - return '120x120'; - } - +class AppleTouchIconPrecomposed120x120 extends AppleTouchIcon120x120 { + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed144x144.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed144x144.php index e087a433a4e3ab0e8f6dc3089755f661bba57401..1bab89d9eb5595c9c321ecd26b66c72049620a4d 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed144x144.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed144x144.php @@ -5,6 +5,8 @@ /** * The Favicons "apple-touch-icon-precomposed_144x144" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed_144x144", * label = @Translation("Apple touch icon (precomposed): 144px x 144px"), @@ -17,13 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed144x144 extends LinkSizesBase { - - /** - * {@inheritdoc} - */ - protected function sizes() { - return '144x144'; - } - +class AppleTouchIconPrecomposed144x144 extends AppleTouchIcon144x144 { + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed152x152.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed152x152.php index 1bd597613c45aec0c15a2c1f0833e33fab701a84..176c7a432288ca712192bfa9a4716dd83a67d42f 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed152x152.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed152x152.php @@ -5,6 +5,8 @@ /** * The Favicons "apple-touch-icon-precomposed_152x152" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed_152x152", * label = @Translation("Apple touch icon (precomposed): 152px x 152px"), @@ -17,13 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed152x152 extends LinkSizesBase { - - /** - * {@inheritdoc} - */ - protected function sizes() { - return '152x152'; - } - +class AppleTouchIconPrecomposed152x152 extends AppleTouchIcon152x152 { + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed180x180.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed180x180.php index d4ac4c7657e998eb3825a88dbbc81d8b1c105d06..4867118c6666d6cfe3609dab32fbaae591fb9b59 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed180x180.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed180x180.php @@ -5,6 +5,8 @@ /** * The Favicons "apple-touch-icon-precomposed_180x180" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed_180x180", * label = @Translation("Apple touch icon (precomposed): 180px x 180px"), @@ -17,13 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed180x180 extends LinkSizesBase { - - /** - * {@inheritdoc} - */ - protected function sizes() { - return '180x180'; - } - +class AppleTouchIconPrecomposed180x180 extends AppleTouchIcon180x180 { + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed72x72.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed72x72.php index ce1fed66b99132c5cc01465382257a78fee404b6..9bfe121c35d78ce14be722c9cb6a88f97071a3c1 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed72x72.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed72x72.php @@ -5,6 +5,8 @@ /** * The Favicons "apple-touch-icon-precomposed_72x72" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed_72x72", * label = @Translation("Apple touch icon (precomposed): 72px x 72px"), @@ -17,13 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed72x72 extends LinkSizesBase { - - /** - * {@inheritdoc} - */ - protected function sizes() { - return '72x72'; - } - +class AppleTouchIconPrecomposed72x72 extends AppleTouchIcon72x72 { + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed76x76.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed76x76.php index a735e61f8b891a42a780b92f4a01f2eb3cbf9af8..bc331070cb650a85f8333d318ee2019d265fadb8 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed76x76.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed76x76.php @@ -5,6 +5,8 @@ /** * The Favicons "apple-touch-icon-precomposed_76x76" meta tag. * + * This is basically a clone of the non-precomposed class. + * * @MetatagTag( * id = "apple_touch_icon_precomposed_76x76", * label = @Translation("Apple touch icon (precomposed): 76px x 76px"), @@ -17,13 +19,6 @@ * multiple = FALSE * ) */ -class AppleTouchIconPrecomposed76x76 extends LinkSizesBase { - - /** - * {@inheritdoc} - */ - protected function sizes() { - return '76x76'; - } - +class AppleTouchIconPrecomposed76x76 extends AppleTouchIcon76x76 { + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon16x16.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon16x16.php index a7d4c54dfe53f1a882a3111d02a8af1a080e8020..83235ab929df256f73c99c497f01e0b374ef0231 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon16x16.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon16x16.php @@ -23,7 +23,7 @@ class Icon16x16 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '16x16'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon192x192.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon192x192.php index 81f28923a38714c3ed6dae7969fd39dcebd4da07..f30cfff75effbd8fd899fa02640019039807e7d6 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon192x192.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon192x192.php @@ -22,7 +22,7 @@ class Icon192x192 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '192x192'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon32x32.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon32x32.php index e0cc4a00f545fe9bf5e5f63e5f713d7d679158e0..dc51148361eced07e8f8f0377242f5abc33440ab 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon32x32.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon32x32.php @@ -22,7 +22,7 @@ class Icon32x32 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '32x32'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon96x96.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon96x96.php index a0a940acb1f19f24fbd96ec55914b499cb6bebf1..678ddd3661a4caf3d376c508319e11b9c13f3786 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon96x96.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon96x96.php @@ -22,7 +22,7 @@ class Icon96x96 extends LinkSizesBase { /** * {@inheritdoc} */ - protected function sizes() { + protected function iconSize() { return '96x96'; } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/LinkSizesBase.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/LinkSizesBase.php index d4f0f766da6d32fe8bed7ab6cde4d20ea3469680..f90136eaecbbc03875eb6a15f7a38dc54bb2d8e9 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/LinkSizesBase.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/LinkSizesBase.php @@ -18,7 +18,7 @@ public function output() { if ($element) { $element['#attributes'] = [ 'rel' => $this->name(), - 'sizes' => $this->sizes(), + 'sizes' => $this->iconSize(), 'href' => $element['#attributes']['href'], ]; } @@ -32,8 +32,22 @@ public function output() { * @return string * A string in the format "XxY" for a given width and height. */ - protected function sizes() { + protected function iconSize() { return ''; } + /** + * The dimensions supported by this icon. + * + * @return string + * A string in the format "XxY" for a given width and height. + * + * @deprecated in 8.x-1.22 and removed in 2.0.0. Use iconSize() instead. + * + * @see https://www.drupal.org/node/3300522 + */ + protected function sizes() { + return $this->iconSize(); + } + } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/MaskIcon.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/MaskIcon.php index fc5689ce1d46bd6ef129e0fea998ecd5d7e47fee..09a91504c6e025d134a8b7c6b5adf622bd3a15aa 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/MaskIcon.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/MaskIcon.php @@ -8,8 +8,8 @@ * The Favicons "mask-icon" meta tag. * * @MetatagTag( - * id = "mask-icon", - * label = @Translation("Icon: SVG"), + * id = "mask_icon", + * label = @Translation("Mask icon (SVG)"), * description = @Translation("A grayscale scalable vector graphic (SVG) file."), * name = "mask-icon", * group = "favicons", @@ -20,5 +20,94 @@ * ) */ class MaskIcon extends LinkRelBase { - // Nothing here yet. Just a placeholder class for a plugin. + + /** + * {@inheritdoc} + */ + public function form(array $element = []) { + $form['#container'] = TRUE; + $form['#tree'] = TRUE; + + // Backwards compatibility. + $defaults = $this->value; + if (is_string($defaults)) { + $defaults = [ + 'href' => $defaults, + 'color' => '', + ]; + } + + // The main icon value. + $form['href'] = [ + '#type' => 'textfield', + '#title' => $this->label(), + '#default_value' => $defaults['href'] ?? '', + '#maxlength' => 255, + '#required' => $element['#required'] ?? FALSE, + '#description' => $this->description(), + '#element_validate' => [[get_class($this), 'validateTag']], + ]; + + // New form element for color. + $form['color'] = [ + '#type' => 'textfield', + '#title' => $this->t('Mask icon color'), + '#default_value' => $defaults['color'] ?? '', + '#required' => FALSE, + '#description' => $this->t("Color attribute for SVG (mask) icon in hexadecimal format, e.g. '#0000ff'. Setting it will break HTML validation. If not set macOS Safari ignores the Mask Icon entirely, making the Icon: SVG completely useless."), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function output() { + $values = $this->value; + + // Make sure the value is an array, if it is not then assume it was assigned + // before the "color" attribute was added, so place the original string as + // the 'href' element and leave the 'color' element blank. + if (!is_array($values)) { + $values = [ + 'href' => $values, + 'color' => '', + ]; + } + + // Build the output. + $href = $this->tidy($values['href']); + if ($href != '') { + $this->tidy($values['href']); + $element['#tag'] = 'link'; + $element['#attributes'] = [ + 'rel' => $this->name(), + 'href' => $href, + ]; + + // Add the 'color' element. + if (!empty($values['color'])) { + $element['#attributes']['color'] = $this->tidy($values['color']); + } + + return $element; + } + + return ''; + } + + /** + * {@inheritdoc} + */ + public function setValue($value) { + // Do not store array with empty values. + if (is_array($value) && empty(array_filter($value))) { + $this->value = []; + } + else { + $this->value = $value; + } + } + } diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/ShortcutIcon.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/ShortcutIcon.php index 730a34e6aefea9088bae800e7f7243f6ffeeb471..86365ae5ee95351b22d736b7deb81a67edc814fc 100644 --- a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/ShortcutIcon.php +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/ShortcutIcon.php @@ -9,9 +9,9 @@ * * @MetatagTag( * id = "shortcut_icon", - * label = @Translation("Default shortcut icon"), + * label = @Translation("Default icon"), * description = @Translation("The traditional favicon, must be either a GIF, ICO, JPG/JPEG or PNG image."), - * name = "shortcut icon", + * name = "icon", * group = "favicons", * weight = 1, * type = "image", diff --git a/web/modules/metatag/metatag_favicons/tests/src/Functional/MetatagFaviconsTagsTest.php b/web/modules/metatag/metatag_favicons/tests/src/Functional/MetatagFaviconsTagsTest.php index aec9f6bf6ab85ed128bb3baef2965cceab8d3b20..4a7dde16c4ddb1d120b306d84a8c97219945edf1 100644 --- a/web/modules/metatag/metatag_favicons/tests/src/Functional/MetatagFaviconsTagsTest.php +++ b/web/modules/metatag/metatag_favicons/tests/src/Functional/MetatagFaviconsTagsTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\metatag_favicons\Functional; use Drupal\Tests\metatag\Functional\MetatagTagsTestBase; +use Drupal\metatag\Entity\MetatagDefaults; /** * Tests that each of the Metatag Favicons tags work correctly. @@ -10,18 +11,34 @@ * @group metatag */ class MetatagFaviconsTagsTest extends MetatagTagsTestBase { + + public function testTagsArePresent() {return;} + /** + * Confirm that each tag can be saved and that the output is correct. + * + * Each tag is passed in one at a time (using the dataProvider) to make it + * easier to distinguish when a problem occurs. + * + * @param string $tag_name + * The tag to test. + * + * @dataProvider tagsInputOutputProvider + */ + public function testTagsInputOutput($tag_name) {return;} + public function tagsInputOutputProvider() { + return []; + } /** * {@inheritdoc} */ - protected static $modules = ['metatag_favicons']; + protected static $modules = ['metatag_favicons', 'field_ui']; /** * {@inheritdoc} */ protected $tags = [ 'shortcut_icon', - // 'mask_icon'. 'icon_16x16', 'icon_32x32', 'icon_96x96', @@ -221,17 +238,101 @@ protected function appleTouchIcon76x76TestOutputXpath() { } /** - * Implements {tag_name}TestOutputXpath for 'mask-icon'. + * Implements {tag_name}TestTagName for 'shortcut icon'. */ - protected function maskIconTestTagName() { - return 'mask-icon'; + protected function shortcutIconTestTagName() { + return 'icon'; } /** - * Implements {tag_name}TestTagName for 'shortcut icon'. + * Test mask_icon as it currently works. + * + * The mask_icon is a separate test case because of it's unusual structure. + * Mask_icon exists of 2 parts, an href and a color. */ - protected function shortcutIconTestTagName() { - return 'shortcut icon'; + public function _testMaskIconCurrent() { + // Test that mask icon fields are available. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->fieldExists('mask_icon[href]'); + $this->assertSession()->fieldExists('mask_icon[color]'); + + // Test that a mask_icon is saved successfully and is correctly shown in + // the meta tags. + $edit = [ + 'mask_icon[href]' => 'mask_icon_href', + ]; + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains('Saved the Global Metatag defaults.'); + + $this->drupalGet('user'); + $xpath = $this->xpath("//link[@rel='mask-icon' and @href='mask_icon_href']"); + self::assertEquals((string) $xpath[0]->getAttribute('href'), 'mask_icon_href'); + + // Add a mask_icon color and check if it's correctly shown in the meta + // tags. + $this->drupalGet('admin/config/search/metatag/global'); + $edit = [ + 'mask_icon[color]' => '#FFFFFF', + ]; + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains('Saved the Global Metatag defaults.'); + + $this->drupalGet('user'); + $xpath = $this->xpath("//link[@rel='mask-icon' and @href='mask_icon_href' and @color='#FFFFFF']"); + self::assertEquals((string) $xpath[0]->getAttribute('href'), 'mask_icon_href'); + } + + /** + * Legacy data for the MaskIcon tag just stored a single string, not an array. + */ + public function testMaskIconLegacy() { + $this->loginUser1(); + // Add a metatag field to the entity type test_entity. + $this->createContentType(['type' => 'page']); + $this->drupalGet('admin/structure/types/manage/page/fields/add-field'); + $this->assertSession()->statusCodeEquals(200); + $edit = [ + 'label' => 'Metatag', + 'field_name' => 'metatag', + 'new_storage_type' => 'metatag', + ]; + $this->submitForm($edit, 'Save and continue'); + $this->submitForm([], 'Save field settings'); + + // Create a demo node of this content type so it can be tested. + $this->drupalGet('node/add/page'); + $this->assertSession()->statusCodeEquals(200); + $edit = [ + 'title[0][value]' => 'Hello, world!', + 'field_metatag[0][favicons][mask_icon][href]' => 'mask_icon_href', + ]; + $this->submitForm($edit, 'Save'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains('page Hello, World! has been created.'); + $xpath = $this->xpath("//link[@rel='mask-icon' and @href='mask_icon_href']"); + self::assertEquals((string) $xpath[0]->getAttribute('href'), 'mask_icon_href'); + + // Update the database record. + \Drupal::database()->update('node__field_metatag') + ->fields([ + 'field_metatag_value' => serialize([ + 'mask_icon' => 'mask_icon_href', + ]), + ]) + ->condition('entity_id', 1) + ->execute(); + + // Clear caches to make sure the node is reloaded. + drupal_flush_all_caches(); + + // Reload the node. + $this->drupalGet('node/1'); + $this->assertSession()->statusCodeEquals(200); + + // Confirm the mask icon value. + $xpath = $this->xpath("//link[@rel='mask-icon' and @href='mask_icon_href']"); + self::assertEquals((string) $xpath[0]->getAttribute('href'), 'mask_icon_href'); } } diff --git a/web/modules/metatag/metatag_google_cse/metatag_google_cse.info.yml b/web/modules/metatag/metatag_google_cse/metatag_google_cse.info.yml index 9cfe7ce4d10b4d1b536670df21b0a7b5898ee70c..86b8410d29f8939f04cab709d229fa92a39192f5 100644 --- a/web/modules/metatag/metatag_google_cse/metatag_google_cse.info.yml +++ b/web/modules/metatag/metatag_google_cse/metatag_google_cse.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Google Custom Search Engine (CSE)' type: module description: Provides support for meta tags used for Google Custom Search Engine. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_google_cse/metatag_google_cse.module b/web/modules/metatag/metatag_google_cse/metatag_google_cse.module index 4d1d49eaddb20194fd9c7485ffaca28fafec0756..b25ba341c759d785cb52fdeb00e0ce1786983bbb 100644 --- a/web/modules/metatag/metatag_google_cse/metatag_google_cse.module +++ b/web/modules/metatag/metatag_google_cse/metatag_google_cse.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_google_cse_help($route_name, RouteMatchInterface $route_match) // Main module help for the metatag_google_cse module. case 'help.page.metatag_google_cse': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Provides support for meta tags used for Google Custom Search Engine.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Provides support for meta tags used for Google Custom Search Engine.') . '</p>'; return $output; default: diff --git a/web/modules/metatag/metatag_google_plus/metatag_google_plus.info.yml b/web/modules/metatag/metatag_google_plus/metatag_google_plus.info.yml index 746077905af562fd4dc0ebc3dfcf755bda138dd9..bdd2f4d6fee00cdb6f452ff9e272b548bb5709c2 100644 --- a/web/modules/metatag/metatag_google_plus/metatag_google_plus.info.yml +++ b/web/modules/metatag/metatag_google_plus/metatag_google_plus.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Google Plus' type: module -description: Provides support for Google's Plus meta tags. -core_version_requirement: '^8.7.7 || ^9' +description: Provides support for Google's Plus meta tags. Deprecated, will be removed in Metatag 2.0.0. +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Group/GooglePlus.php b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Group/GooglePlus.php index 1744f672d91366eb75519811656773b24d2b6ea5..2726a9eabd31251e7f53db8324411999266ac4f2 100644 --- a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Group/GooglePlus.php +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Group/GooglePlus.php @@ -13,6 +13,10 @@ * description = @Translation("A set of meta tags specially for controlling the summaries displayed when content is shared on <a href=':plus'>Google Plus</a>.", arguments = { ":plus" = "https://plus.google.com/" }), * weight = 4 * ) + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3065441 */ class GooglePlus extends GroupBase { // Inherits everything from Base. diff --git a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Author.php b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Author.php index 2cbfa3ada5906c5d8c65b331ba26bd92b3fd3373..4fb9b6cf319116b697ba0f160f6bd8a490f9ea61 100644 --- a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Author.php +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Author.php @@ -10,7 +10,7 @@ * @MetatagTag( * id = "google_plus_author", * label = @Translation("Author"), - * description = @Translation("Used by some search engines to confirm authorship of the content on a page. Should be either the full URL for the author's Google+ profile page or a local page with information about the author."), + * description = @Translation("DEPRECATED, use Advanced-Author instead."), * name = "author", * group = "google_plus", * weight = 4, @@ -18,6 +18,10 @@ * secure = FALSE, * multiple = FALSE * ) + * + * @deprecated in metatag:8.x-1.20 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3284464 */ class Author extends LinkRelBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Description.php b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Description.php index 92fbd8ed8c591944a721719fb197547581de9bfc..7e9325d5c40cc87b74aa3e0d5d8b5adbfab49e83 100644 --- a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Description.php +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Description.php @@ -16,8 +16,13 @@ * weight = 2, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3065441 */ class Description extends MetaItempropBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Image.php b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Image.php index 190d035df5b59aa8c613d31661d5a77b386eb211..dde336f9fe753d950de71d584e497c24e3c16a69 100644 --- a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Image.php +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Image.php @@ -18,6 +18,10 @@ * secure = FALSE, * multiple = TRUE * ) + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3065441 */ class Image extends MetaItempropBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Name.php b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Name.php index 1cebf62b64be7def20a8856ed80dbbb764c9a075..e35d04efb9e77614cee6b4f0045a345eb27d0810 100644 --- a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Name.php +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Name.php @@ -16,8 +16,13 @@ * weight = 1, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3065441 */ class Name extends MetaItempropBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Publisher.php b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Publisher.php index 2e15fd60af1992b18e13c4556830a15cfdfd27b5..b5caa1a4bd1f405d3810a46953745d5de0f0173a 100644 --- a/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Publisher.php +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Publisher.php @@ -18,6 +18,10 @@ * secure = FALSE, * multiple = FALSE * ) + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3065441 */ class Publisher extends LinkRelBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/metatag_google_plus/tests/src/Functional/MetatagGooglePlusTagsTest.php b/web/modules/metatag/metatag_google_plus/tests/src/Functional/MetatagGooglePlusTagsTest.php index c85c3adf6568f9d6a51295c780305b5a6b24b447..db0acd21c9696f62c2419c44fc876133129a821d 100644 --- a/web/modules/metatag/metatag_google_plus/tests/src/Functional/MetatagGooglePlusTagsTest.php +++ b/web/modules/metatag/metatag_google_plus/tests/src/Functional/MetatagGooglePlusTagsTest.php @@ -8,6 +8,10 @@ * Tests that each of the Metatag Google Plus tags work correctly. * * @group metatag + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3065441 */ class MetatagGooglePlusTagsTest extends MetatagTagsTestBase { diff --git a/web/modules/metatag/metatag_hreflang/config/schema/metatag_hreflang.metatag_tag.schema.yml b/web/modules/metatag/metatag_hreflang/config/schema/metatag_hreflang.metatag_tag.schema.yml index 20ee6303c04c8428dfc4468762a836ff46e92fa3..7e1ba4af85e66fcdbadc03cdfd760f6529422ff8 100644 --- a/web/modules/metatag/metatag_hreflang/config/schema/metatag_hreflang.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_hreflang/config/schema/metatag_hreflang.metatag_tag.schema.yml @@ -5,3 +5,6 @@ metatag.metatag_tag.hreflang_xdefault: type: label label: 'Default locale (x-default)' +metatag.metatag_tag.hreflang_per_language:*: + type: label + label: 'Href per language' diff --git a/web/modules/metatag/metatag_hreflang/metatag_hreflang.info.yml b/web/modules/metatag/metatag_hreflang/metatag_hreflang.info.yml index 08f4d821bd22099fa8607f6ced07539e01337da4..d5e03a409604d72ab67e08a01386ee94c95dad99 100644 --- a/web/modules/metatag/metatag_hreflang/metatag_hreflang.info.yml +++ b/web/modules/metatag/metatag_hreflang/metatag_hreflang.info.yml @@ -1,12 +1,12 @@ name: "Metatag: Hreflang" type: module description: Provides support for the hreflang meta tag with some extra logic to simplify it. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_hreflang/metatag_hreflang.module b/web/modules/metatag/metatag_hreflang/metatag_hreflang.module index f7873f3d3442339b6ca1decb0e990ca0fe7460c7..fe3a46bf05d02b2fe074449161036c64ea0a7901 100644 --- a/web/modules/metatag/metatag_hreflang/metatag_hreflang.module +++ b/web/modules/metatag/metatag_hreflang/metatag_hreflang.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_hreflang_help($route_name, RouteMatchInterface $route_match) { // Main module help for the metatag_hreflang module. case 'help.page.metatag_hreflang': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Provides support for the hreflang meta tag with some extra logic to simplify it.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Provides support for the hreflang meta tag with some extra logic to simplify it.') . '</p>'; return $output; default: @@ -36,7 +37,7 @@ function metatag_hreflang_page_attachments_alter(array &$attachments) { foreach ($attachments['#attached']['html_head'] as $element) { // Check for Metatag's identifier "hreflang_per_language". if (!empty($element[1])) { - if (strpos($element[1], 'hreflang_per_language') !== false) { + if (strpos($element[1], 'hreflang_per_language') !== FALSE && isset($element[0]['#attributes']['hreflang'])) { $hreflang_per_language[] = $element[0]['#attributes']['hreflang']; } } diff --git a/web/modules/metatag/metatag_hreflang/tests/src/Functional/MetatagHreflangTagsTest.php b/web/modules/metatag/metatag_hreflang/tests/src/Functional/MetatagHreflangTagsTest.php index 8423cf4ba1b36917efd42713d57d91ea36e39450..c29765372a8e6b19b8eb39cc60bb90698113ecfb 100644 --- a/web/modules/metatag/metatag_hreflang/tests/src/Functional/MetatagHreflangTagsTest.php +++ b/web/modules/metatag/metatag_hreflang/tests/src/Functional/MetatagHreflangTagsTest.php @@ -46,7 +46,7 @@ class MetatagHreflangTagsTest extends MetatagTagsTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Enable additional languages. diff --git a/web/modules/metatag/metatag_mobile/config/schema/metatag_mobile.metatag_tag.schema.yml b/web/modules/metatag/metatag_mobile/config/schema/metatag_mobile.metatag_tag.schema.yml index ef95ca6ea483d2ba67d7ff809a75fb9e2c575850..a5bd38dd3ff594ecf0754b4c3b886e0fd8ed73b4 100644 --- a/web/modules/metatag/metatag_mobile/config/schema/metatag_mobile.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_mobile/config/schema/metatag_mobile.metatag_tag.schema.yml @@ -21,7 +21,7 @@ metatag.metatag_tag.apple_mobile_web_app_status_bar_style: type: label label: 'Apple Mobile: Web App Status bar color' metatag.metatag_tag.apple_mobile_web_app_title: - type: label + type: text label: 'Apple Mobile: Web App Title' metatag.metatag_tag.application_name: type: label diff --git a/web/modules/metatag/metatag_mobile/metatag_mobile.info.yml b/web/modules/metatag/metatag_mobile/metatag_mobile.info.yml index d572a64b87e16694139699076eb3086c4064871b..815661428d4ca43610edc2c2361e317af1ebfe7e 100644 --- a/web/modules/metatag/metatag_mobile/metatag_mobile.info.yml +++ b/web/modules/metatag/metatag_mobile/metatag_mobile.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Mobile & UI Adjustments' type: module description: Provides support for meta tags used to control the mobile browser experience. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_mobile/metatag_mobile.module b/web/modules/metatag/metatag_mobile/metatag_mobile.module index dfe0ff94c7ea26bd6ec34444180b865a282b1bf5..e09b53d2eb982f67104a2acb6641f6e4e56208e3 100644 --- a/web/modules/metatag/metatag_mobile/metatag_mobile.module +++ b/web/modules/metatag/metatag_mobile/metatag_mobile.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_mobile_help($route_name, RouteMatchInterface $route_match) { // Main module help for the metatag_mobile module. case 'help.page.metatag_mobile': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Provides support for meta tags used to control the mobile browser experience.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Provides support for meta tags used to control the mobile browser experience.') . '</p>'; return $output; default: @@ -25,6 +26,10 @@ function metatag_mobile_help($route_name, RouteMatchInterface $route_match) { /** * Implements hook_theme(). + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3303424 */ function metatag_mobile_theme() { $info['metatag_mobile_android_app'] = [ @@ -82,6 +87,10 @@ function metatag_mobile_page_attachments_alter(array &$attachments) { * The format is (all on oneline): * <link rel="alternate" href="android-app://com.example.Example * /sitesection/sitepage/thispage" /> + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3303424 */ function theme_metatag_mobile_android_app($variables) { // Pass everything through to the normal 'link' tag theme. @@ -96,6 +105,10 @@ function theme_metatag_mobile_android_app($variables) { * * The format is: * <link rel="alternate" href="ios-app://123456/example/hello-screen" /> + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3303424 */ function theme_metatag_mobile_ios_app($variables) { // Pass everything through to the normal 'link' tag theme. diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidAppLinkAlternative.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidAppLinkAlternative.php index a3729435c283b1ca1b8166e88cdd0c8e5dc74aca..4fb055640cf46766eec82a0950afc9b2c06380db 100644 --- a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidAppLinkAlternative.php +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidAppLinkAlternative.php @@ -20,5 +20,22 @@ * ) */ class AndroidAppLinkAlternative extends LinkRelBase { - // Nothing here yet. Just a placeholder class for a plugin. + + /** + * {@inheritdoc} + */ + public function output() { + $element = parent::output(); + + // Add the "android-app://" prefix on the href value. + if (isset($element['#attributes']['href']) && $element['#attributes']['href'] != '') { + // Don't add the prefix if it's already present. + if (strpos($element['#attributes']['href'], 'android-app://') === FALSE) { + $element['#attributes']['href'] = 'android-app://' . (string) $element['#attributes']['href']; + } + } + + return $element; + } + } diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/IosAppLinkAlternative.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/IosAppLinkAlternative.php index 6efa753130ef46e52e994240aad3586d0d59a496..8c7c70b678cd7695ec409546671f5dc1c554d05d 100644 --- a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/IosAppLinkAlternative.php +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/IosAppLinkAlternative.php @@ -20,5 +20,22 @@ * ) */ class IosAppLinkAlternative extends LinkRelBase { - // Nothing here yet. Just a placeholder class for a plugin. + + /** + * {@inheritdoc} + */ + public function output() { + $element = parent::output(); + + // Add the "ios-app://" prefix on the href value. + if (isset($element['#attributes']['href']) && $element['#attributes']['href'] != '') { + // Don't add the prefix if it's already present. + if (strpos($element['#attributes']['href'], 'ios-app://') === FALSE) { + $element['#attributes']['href'] = 'ios-app://' . (string) $element['#attributes']['href']; + } + } + + return $element; + } + } diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTaskSeparator.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTaskSeparator.php index 25d502f31a7ee38e5577742df34522830e3a15f5..751c6f053133ac1a4e08ab2b029efb9055c2d385 100644 --- a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTaskSeparator.php +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTaskSeparator.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "msapplication_task_separator", * label = @Translation("MSApplication - Task separator"), - * description = @Translation(""), * name = "msapplication-task-separator", * group = "windows_mobile", * weight = 107, diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/WebManifest.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/WebManifest.php index 5028cae018c82dede43996560134961790f07365..d31e9bac224e314341d8ece45ca4b33c1c81b4fc 100644 --- a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/WebManifest.php +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/WebManifest.php @@ -20,5 +20,22 @@ * ) */ class WebManifest extends LinkRelBase { - // Nothing here yet. Just a placeholder class for a plugin. + + /** + * {@inheritdoc} + */ + public function output() { + // Get the standard LinkRelBase output. + $element = parent::output(); + + // This attribute is required on the tag to avoid errors in Chrome. + // @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin + // @see https://developer.chrome.com/docs/extensions/mv2/xhr/ + if (!empty($element) && is_array($element)) { + $element['#attributes']['crossorigin'] = 'use-credentials'; + } + + return $element; + } + } diff --git a/web/modules/metatag/metatag_mobile/tests/src/Functional/MetatagMobileTagsTest.php b/web/modules/metatag/metatag_mobile/tests/src/Functional/MetatagMobileTagsTest.php index ccb246fd4d21db4006f3fdc76852f765388bb35d..8c0a6b9e8425f8bd7818154846c116645c54028c 100644 --- a/web/modules/metatag/metatag_mobile/tests/src/Functional/MetatagMobileTagsTest.php +++ b/web/modules/metatag/metatag_mobile/tests/src/Functional/MetatagMobileTagsTest.php @@ -68,6 +68,8 @@ protected function getTestTagName($tag_name) { $tag_name = str_replace('_', '-', $tag_name); // Fix a few specific tags. + $tag_name = str_replace('android-app-link-alternative', 'android_app_link_alternative', $tag_name); + $tag_name = str_replace('ios-app-link-alternative', 'ios_app_link_alternative', $tag_name); $tag_name = str_replace('android_manifest', 'manifest', $tag_name); $tag_name = str_replace('handheldfriendly', 'HandheldFriendly', $tag_name); $tag_name = str_replace('mobileoptimized', 'MobileOptimized', $tag_name); @@ -93,14 +95,21 @@ protected function alternateHandheldTestValueAttribute() { * Implements {tag_name}TestValue() for 'android_app_link_alternative'. */ protected function androidAppLinkAlternativeTestValue() { - return 'android-app:' . $this->randomMachineName(); + return $this->randomImageUrl(); + } + + /** + * Implements {tag_name}TestOutput() for 'android_app_link_alternative'. + */ + protected function androidAppLinkAlternativeTestOutput($string) { + return 'android-app://' . $string; } /** - * Implements {tag_name}TestOutputXpath() for 'android-app-link-alternative'. + * Implements {tag_name}TestOutputXpath() for 'android_app_link_alternative'. */ protected function androidAppLinkAlternativeTestOutputXpath() { - return "//link[@rel='alternate' and starts-with(@href, 'android-app:')]"; + return "//link[@rel='alternate' and starts-with(@href, 'android-app://')]"; } /** @@ -123,14 +132,21 @@ protected function cleartypeTestNameAttribute() { * Implements {tag_name}TestValue() for 'ios_app_link_alternative'. */ protected function iosAppLinkAlternativeTestValue() { - return 'ios-app:' . $this->randomMachineName(); + return $this->randomImageUrl(); + } + + /** + * Implements {tag_name}TestOutput() for 'ios_app_link_alternative'. + */ + protected function iosAppLinkAlternativeTestOutput($string) { + return 'ios-app://' . $string; } /** * Implements {tag_name}TestOutputXpath() for 'ios_app_link_alternative'. */ protected function iosAppLinkAlternativeTestOutputXpath() { - return "//link[@rel='alternate' and starts-with(@href, 'ios-app:')]"; + return "//link[@rel='alternate' and starts-with(@href, 'ios-app://')]"; } /** diff --git a/web/modules/metatag/metatag_open_graph/config/schema/metatag_open_graph.metatag_tag.schema.yml b/web/modules/metatag/metatag_open_graph/config/schema/metatag_open_graph.metatag_tag.schema.yml index 68bdff47f9a0f285aeb1764c2e45f01aac13b80b..6481f98e153c5629cd3ada9117dea08f6505e1c7 100644 --- a/web/modules/metatag/metatag_open_graph/config/schema/metatag_open_graph.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_open_graph/config/schema/metatag_open_graph.metatag_tag.schema.yml @@ -114,7 +114,7 @@ metatag.metatag_tag.og_street_address: type: label label: 'Open Graph: Street address' metatag.metatag_tag.og_title: - type: label + type: text label: 'Open Graph: Title' metatag.metatag_tag.og_type: type: label diff --git a/web/modules/metatag/metatag_open_graph/metatag_open_graph.info.yml b/web/modules/metatag/metatag_open_graph/metatag_open_graph.info.yml index 01bfba11eb24340c9600bf471355e7b5126f4354..182f1b8860ef38a90e4c11857de68bce0f1cafae 100644 --- a/web/modules/metatag/metatag_open_graph/metatag_open_graph.info.yml +++ b/web/modules/metatag/metatag_open_graph/metatag_open_graph.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Open Graph' type: module description: Provides support for Open Graph Protocol meta tags. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_open_graph/metatag_open_graph.install b/web/modules/metatag/metatag_open_graph/metatag_open_graph.install index 28baa7a4e42754ab2f04c1e679244967fb331b5e..90d6017ff9e1e0d697dc70f21a3fd31ef0b0cbe7 100644 --- a/web/modules/metatag/metatag_open_graph/metatag_open_graph.install +++ b/web/modules/metatag/metatag_open_graph/metatag_open_graph.install @@ -16,7 +16,7 @@ * The "article:tags" meta tag was renamed to the correct "article:tag". */ function metatag_open_graph_update_8101() { - /* @var $configs Drupal\metatag\Entity\MetatagDefaults */ + /** @var Drupal\metatag\Entity\MetatagDefaults $configs */ $configs = MetatagDefaults::loadMultiple(); foreach ($configs as $config) { @@ -72,7 +72,7 @@ function metatag_open_graph_update_8102(&$sandbox) { foreach ($sandbox['todo'] as $entity_type => $fields) { - /* @var $def Drupal\Core\Entity\ContentEntityType */ + /** @var Drupal\Core\Entity\ContentEntityType $def */ $def = Drupal::entityTypeManager()->getDefinition($entity_type); // Grab the primary key field for this entity type @@ -95,17 +95,17 @@ function metatag_open_graph_update_8102(&$sandbox) { $entities = $etm->getStorage($entity_type)->loadMultiple($res); foreach ($entities as $entity) { - /* @var $entity ContentEntityBase */ + /** @var \Drupal\Core\Entity\ContentEntityBase $entity */ if ($entity instanceof ContentEntityBase) { if ($entity->hasField($field_name)) { - /* @var LanguageInterface $langcode */ + /** @var \Drupal\Core\Language\LanguageInterface $langcode */ foreach ($entity->getTranslationLanguages() as $langcode) { // For each translation of this entity (including the source)... $trans = $entity->getTranslation($langcode->getId()); $tags_serialized = $trans->get($field_name)->value; if ($tags_serialized) { // Change key from article_tags to article_tag. - $tags = unserialize($tags_serialized); + $tags = unserialize($tags_serialized, ['allowed_classes' => FALSE]); if (array_key_exists("article_tags", $tags)) { $tags['article_tag'] = $tags['article_tags']; unset($tags['article_tags']); diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgCountryName.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgCountryName.php index de064a0f031deb447d195cf28dd82a77ffda6f0b..5fc366d6ec9fc730577ae894ebb6b6adafd5ae03 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgCountryName.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgCountryName.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_country_name", * label = @Translation("Country name"), - * description = @Translation(""), * name = "og:country_name", * group = "open_graph", * weight = 22, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDescription.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDescription.php index a3b01ffcf135caacc1957e2ed830814722a13600..2e22b08e72cfaaef47f99dbdb8124b98ad5cc06d 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDescription.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDescription.php @@ -18,6 +18,7 @@ * secure = FALSE, * multiple = FALSE, * long = TRUE, + * trimmable = TRUE * ) */ class OgDescription extends MetaPropertyBase { diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgEmail.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgEmail.php index b0d8060cab0a4c61b4479e9b2df9acc936151e0b..e342547092f7ab247a1f924fe1a01dc8224c5360 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgEmail.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgEmail.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_email", * label = @Translation("Email address"), - * description = @Translation(""), * name = "og:email", * group = "open_graph", * weight = 23, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgFaxNumber.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgFaxNumber.php index 42516b2538310ffedf631acb4286e5cdc4f2408a..0f80f221223e520f937adbebdde452d045892ce7 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgFaxNumber.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgFaxNumber.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_fax_number", * label = @Translation("Fax number"), - * description = @Translation(""), * name = "og:fax_number", * group = "open_graph", * weight = 25, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLatitude.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLatitude.php index b84745d016d0fd88d0c01ec5adaba05578b4223b..db039d3271cafe54f09674f792a6369a38086c03 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLatitude.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLatitude.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_latitude", * label = @Translation("Latitude"), - * description = @Translation(""), * name = "place:location:latitude", * group = "open_graph", * weight = 16, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocality.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocality.php index 6311367ee2fca00b26f467fadc7c50ad3e4e1eb2..196e1e66dba93e56052091be2872226e6071fa0d 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocality.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocality.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_locality", * label = @Translation("Locality"), - * description = @Translation(""), * name = "og:locality", * group = "open_graph", * weight = 19, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLongitude.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLongitude.php index 551bac4b852086ab07eb62ffb16add10a78def38..5bf877d13408d1a45abb475070659f73ba74d70f 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLongitude.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLongitude.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_longitude", * label = @Translation("Longitude"), - * description = @Translation(""), * name = "place:location:longitude", * group = "open_graph", * weight = 16, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPhoneNumber.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPhoneNumber.php index 27f8503c2a3fae804b4f956708f52b1cb9ce55cd..8df9f1ef878a3128652e7ca3895014894e6c67b1 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPhoneNumber.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPhoneNumber.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_phone_number", * label = @Translation("Phone number"), - * description = @Translation(""), * name = "og:phone_number", * group = "open_graph", * weight = 24, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPostalCode.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPostalCode.php index 3e3f2fe007964cd4f4314d6fb1ac7473be1f1e9c..6a201d724beef2c3dfffc98b633d5523a2fe54ae 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPostalCode.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPostalCode.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_postal_code", * label = @Translation("Postal/ZIP code"), - * description = @Translation(""), * name = "og:postal_code", * group = "open_graph", * weight = 21, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgRegion.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgRegion.php index 7bda64b5bccbcf19dc2bcf839d69f6e02bb322be..8505dffc3eba603903a51f2255dd6007522c85e3 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgRegion.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgRegion.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_region", * label = @Translation("Region"), - * description = @Translation(""), * name = "og:region", * group = "open_graph", * weight = 20, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSiteName.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSiteName.php index ce1e1fdbd5b3dd9542892c2e434969d92a50284a..b979cfd65ff5ae0e71aa4ee836cb6202092dabc1 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSiteName.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSiteName.php @@ -16,7 +16,8 @@ * weight = 1, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class OgSiteName extends MetaPropertyBase { diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgStreetAddress.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgStreetAddress.php index 79795a94e8902cb6743af0f479c5ecebff4f4377..9470fa491bf641039f9679ecf7d2f4d796aa651c 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgStreetAddress.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgStreetAddress.php @@ -10,7 +10,6 @@ * @MetatagTag( * id = "og_street_address", * label = @Translation("Street address"), - * description = @Translation(""), * name = "og:street_address", * group = "open_graph", * weight = 18, diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgTitle.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgTitle.php index 8929887bf0d01064ed466fcfbf660b9ca270d6e7..0fab965f8d770085e92f5df18db739cff9f9fd56 100644 --- a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgTitle.php +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgTitle.php @@ -16,7 +16,8 @@ * weight = 4, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class OgTitle extends MetaPropertyBase { diff --git a/web/modules/metatag/metatag_open_graph_products/config/schema/metatag_open_graph_products.metatag_tag.schema.yml b/web/modules/metatag/metatag_open_graph_products/config/schema/metatag_open_graph_products.metatag_tag.schema.yml index 888ffe0d53e9678b61f1194c109c09d1e734e55a..dffa8725673a0061b3ed01978b7d07a2e3de82f5 100644 --- a/web/modules/metatag/metatag_open_graph_products/config/schema/metatag_open_graph_products.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_open_graph_products/config/schema/metatag_open_graph_products.metatag_tag.schema.yml @@ -1,6 +1,15 @@ +metatag.metatag_tag.product_availability: + type: label + label: 'Open Graph Product: Price availability' +metatag.metatag_tag.product_condition: + type: label + label: 'Open Graph Product: Product condition' metatag.metatag_tag.product_price_amount: type: label label: 'Open Graph Product: Price amount' metatag.metatag_tag.product_price_currency: type: label label: 'Open Graph Product: Price currency' +metatag.metatag_tag.product_retailer_item_id: + type: label + label: 'Open Graph Product: Retailer Item ID' diff --git a/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.info.yml b/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.info.yml index 8c6c2c020b575e80c1aaf82a64bbace840b5cdd1..ba547b43c263ebe92de54a27cd2851492afa66c3 100644 --- a/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.info.yml +++ b/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.info.yml @@ -1,13 +1,13 @@ name: 'Metatag: Open Graph Products' type: module description: Provides additional Open Graph Protocol meta tags for describing products. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag - metatag:metatag_open_graph -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.module b/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.module index e059787b058cc3c562d206dd602d971addabf856..0efbebac2c730b88b1e29d455cc38f3c5704e458 100644 --- a/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.module +++ b/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_open_graph_products_help($route_name, RouteMatchInterface $rout // Main module help for the metatag_open_graph_products module. case 'help.page.metatag_open_graph_products': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Provides additional Open Graph Protocol meta tags for describing products.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Provides additional Open Graph Protocol meta tags for describing products.') . '</p>'; return $output; default: diff --git a/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductAvailability.php b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductAvailability.php new file mode 100644 index 0000000000000000000000000000000000000000..f6ea6d9ea4f8a40ddfc081dc64ee7598b6ff8902 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductAvailability.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph_products\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'product:availability' meta tag. + * + * @MetatagTag( + * id = "product_availability", + * label = @Translation("Product availability"), + * description = @Translation("The availability of the product."), + * name = "product:availability", + * group = "open_graph_products", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ProductAvailability extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductCondition.php b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductCondition.php new file mode 100644 index 0000000000000000000000000000000000000000..ec5d626e70e092b9a056874bf94dd0fe97721a59 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductCondition.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph_products\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'product:condition' meta tag. + * + * @MetatagTag( + * id = "product_condition", + * label = @Translation("Product condition"), + * description = @Translation("The condition of the product."), + * name = "product:condition", + * group = "open_graph_products", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ProductCondition extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductRetailerItemId.php b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductRetailerItemId.php new file mode 100644 index 0000000000000000000000000000000000000000..90ad105f7f00ca85930be6355b77839ea1e9a070 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductRetailerItemId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph_products\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'product:retailer_item_id' meta tag. + * + * @MetatagTag( + * id = "product_retailer_item_id", + * label = @Translation("Retailer Item ID"), + * description = @Translation("The ID of the product as provided by the retailer."), + * name = "product:retailer_item_id", + * group = "open_graph_products", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ProductRetailerItemId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph_products/tests/src/Functional/MetatagOpenGraphProductsTagsTest.php b/web/modules/metatag/metatag_open_graph_products/tests/src/Functional/MetatagOpenGraphProductsTagsTest.php index 3f1acdfa5205d7a27937d8e244e765a18ea27ccd..2aa1fc5d62146c2b7e4e253b25bb3177e6fd762d 100644 --- a/web/modules/metatag/metatag_open_graph_products/tests/src/Functional/MetatagOpenGraphProductsTagsTest.php +++ b/web/modules/metatag/metatag_open_graph_products/tests/src/Functional/MetatagOpenGraphProductsTagsTest.php @@ -20,8 +20,11 @@ class MetatagOpenGraphProductsTagsTest extends MetatagTagsTestBase { * {@inheritdoc} */ protected $tags = [ + 'product_availability', + 'product_condition', 'product_price_amount', 'product_price_currency', + 'product_retailer_item_id', ]; /** @@ -38,8 +41,11 @@ class MetatagOpenGraphProductsTagsTest extends MetatagTagsTestBase { * Each of these meta tags has a different tag name vs its internal name. */ protected function getTestTagName($tag_name) { - // Replace the underlines with a colon. - $tag_name = str_replace('_', ':', $tag_name); + // Replace the first underline with a colon. + $tag_name = str_replace('product_', 'product:', $tag_name); + + // Additional meta tags. + $tag_name = str_replace('price_', 'price:', $tag_name); return $tag_name; } diff --git a/web/modules/metatag/metatag_page_manager/metatag_page_manager.info.yml b/web/modules/metatag/metatag_page_manager/metatag_page_manager.info.yml index c469bb375ae113b39dcd5659f368488765f7c85f..721bc12c15b448db916c2847d982e4e1ba0af562 100644 --- a/web/modules/metatag/metatag_page_manager/metatag_page_manager.info.yml +++ b/web/modules/metatag/metatag_page_manager/metatag_page_manager.info.yml @@ -1,13 +1,13 @@ name: 'Metatag: Page Manager' type: module description: Provides metatag support for Page Manager variants. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - page_manager:page_manager - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_page_manager/tests/src/Functional/MetatagPageManagerTest.php b/web/modules/metatag/metatag_page_manager/tests/src/Functional/MetatagPageManagerTest.txt similarity index 94% rename from web/modules/metatag/metatag_page_manager/tests/src/Functional/MetatagPageManagerTest.php rename to web/modules/metatag/metatag_page_manager/tests/src/Functional/MetatagPageManagerTest.txt index 5cccbb4af81d6617546b123281ab3414f4c81d82..fa35a9411b252cc52238350e2c50c23bd20ed8a0 100644 --- a/web/modules/metatag/metatag_page_manager/tests/src/Functional/MetatagPageManagerTest.php +++ b/web/modules/metatag/metatag_page_manager/tests/src/Functional/MetatagPageManagerTest.txt @@ -40,7 +40,7 @@ class MetatagPageManagerTest extends BrowserTestBase { /** * {@inheritdoc} */ - public function setUp() { + public function setUp(): void { parent::setUp(); $this->assertSession = $this->assertSession(); @@ -80,7 +80,8 @@ public function testSingleVariantPage() { 'title' => 'My title', ]; - $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + $this->drupalGet('/admin/config/search/metatag/add'); + $this->submitForm($edit, 'Save'); $this->assertSession->pageTextContains('Page Variant: Metatag Page: Metatag Variant'); // Clear caches to load the right metatags. @@ -152,7 +153,8 @@ public function testMultipleVariantPage() { 'title' => 'My title', ]; - $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + $this->drupalGet('/admin/config/search/metatag/add'); + $this->submitForm($edit, 'Save'); $this->assertSession->pageTextContains('Page Variant: Metatag Page: Metatag Variant'); // Clear caches to load the right metatags. @@ -180,7 +182,8 @@ public function testMultipleVariantPage() { 'title' => 'My title anonymous', ]; - $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + $this->drupalGet('/admin/config/search/metatag/add'); + $this->submitForm($edit, 'Save'); // The first-weighted variant (Anonymous variant) will receive the Metatag // defaults. $this->assertSession->pageTextContains('Page Variant: Metatag Page: Anonymous variant'); diff --git a/web/modules/metatag/metatag_pinterest/metatag_pinterest.info.yml b/web/modules/metatag/metatag_pinterest/metatag_pinterest.info.yml index f870cf8761c7576f68079ba439eb07f1aad55770..e3d863e7119aea61114dc99a259a69151ef4b812 100644 --- a/web/modules/metatag/metatag_pinterest/metatag_pinterest.info.yml +++ b/web/modules/metatag/metatag_pinterest/metatag_pinterest.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Pinterest' type: module description: Provides support for Pinterest's custom meta tags. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestDescription.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestDescription.php index bd3fe2e6c28a0f34e1d2ed9cd6bda3c971047885..a85cd26c11c8b85a7ecf9a13b902b46918c51c19 100644 --- a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestDescription.php +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestDescription.php @@ -16,7 +16,8 @@ * weight = 8, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class PinterestDescription extends MetaPropertyBase { diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNohover.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNohover.php index f725e441aadc84279cec48c418841d2913836c74..1d7b29a0ec5ee9331c799f905231354732453f55 100644 --- a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNohover.php +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNohover.php @@ -30,7 +30,7 @@ public function form(array $element = []) { '#title' => $this->label(), '#description' => $this->description(), '#default_value' => ($this->value === 'nohover') ?: '', - '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#required' => $element['#required'] ?? FALSE, '#element_validate' => [[get_class($this), 'validateTag']], '#return_value' => 'nohover', ]; diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNopin.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNopin.php index 5e0265340613ec2f2947e649c87f0b4438317d48..362eb69d86ee21b999ab6f2d346f8b34a4659b42 100644 --- a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNopin.php +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNopin.php @@ -30,7 +30,7 @@ public function form(array $element = []) { '#title' => $this->label(), '#description' => $this->description(), '#default_value' => ($this->value === 'nopin') ?: '', - '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#required' => $element['#required'] ?? FALSE, '#element_validate' => [[get_class($this), 'validateTag']], '#return_value' => 'nopin', ]; diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNosearch.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNosearch.php index 9c0c9437ba6dfdc8c346bfe04c15f2f41b87d15a..714ed6881a866b8ce778ee6f17170ab973731b87 100644 --- a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNosearch.php +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNosearch.php @@ -30,7 +30,7 @@ public function form(array $element = []) { '#title' => $this->label(), '#description' => $this->description(), '#default_value' => ($this->value === 'nosearch') ?: '', - '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#required' => $element['#required'] ?? FALSE, '#element_validate' => [[get_class($this), 'validateTag']], '#return_value' => 'nosearch', ]; diff --git a/web/modules/metatag/metatag_routes/README.md b/web/modules/metatag/metatag_routes/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8181a453eaa68b0acccfa78327c8442365319d3c --- /dev/null +++ b/web/modules/metatag/metatag_routes/README.md @@ -0,0 +1,25 @@ +# Metatag Routes + +The Metatag Routes module allows a user to configure metatags for custom +controllers generated by code. + +It uses the metatags entity to store a configuration for any route using the +metatags administration. + +The module adds a button in the default metatag dashboard page giving the user +the option to enter the route path and validates if the path has a defined +route, the route is not administrative and the route is "metatag-able". + +## Configuration + +1. Navigate to Administration > Extend and enable the module. +2. Navigate to Administration > Configuration > Search and Metadata > + Metatag to configure metatags. +3. Select "Add meta tag for custom route" and enter the path for which you + want to add the metatags. +4. Submit. + +## Credits / contact + +Written by [Walter Velasquez (waldomero)](https://www.drupal.org/u/waldomero) +and sponsored by [Globant](https://www.drupal.org/globant). diff --git a/web/modules/metatag/metatag_routes/metatag_routes.info.yml b/web/modules/metatag/metatag_routes/metatag_routes.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..844911e920288097a5dfe759843353060f0fc502 --- /dev/null +++ b/web/modules/metatag/metatag_routes/metatag_routes.info.yml @@ -0,0 +1,12 @@ +name: 'Metatag Custom Routes (Paths)' +type: module +description: Allows assigning meta tags to be used on custom routes, equivalent to customn paths. +core_version_requirement: '^9.3 || ^10' +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' +project: 'metatag' +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_routes/metatag_routes.links.action.yml b/web/modules/metatag/metatag_routes/metatag_routes.links.action.yml new file mode 100644 index 0000000000000000000000000000000000000000..99b259f3abbb2e8d0bdd5c50d645538a0d9c39d7 --- /dev/null +++ b/web/modules/metatag/metatag_routes/metatag_routes.links.action.yml @@ -0,0 +1,6 @@ +metatag_routes.create_custom_metatag.action: + route_name: metatag_routes.create + title: 'Add meta tag for custom route' + weight: 1 + appears_on: + - entity.metatag_defaults.collection diff --git a/web/modules/metatag/metatag_routes/metatag_routes.module b/web/modules/metatag/metatag_routes/metatag_routes.module new file mode 100644 index 0000000000000000000000000000000000000000..6cf44ff863fcb38ee1497897d6b15afd50b41b81 --- /dev/null +++ b/web/modules/metatag/metatag_routes/metatag_routes.module @@ -0,0 +1,46 @@ +<?php + +/** + * @file + * Default hook implementations for the Metatag Routes module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_routes_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // Main module help for the ok_metatag_custom module. + case 'help.page.metatag_routes': + $output = ''; + $output .= '<h3>' . t('About') . '</h3>'; + $output .= '<p>' . t('Enables metatags for custom routes') . '</p>'; + return $output; + + default: + } +} + +/** + * Implements hook_metatags_alter(). + */ +function metatag_routes_metatags_alter(array &$metatags, array $context) { + // Ignore some system routes that are not approrpriate for meta tags. + if (metatag_is_current_route_supported()) { + // Look to see if a configuration was assigned for this route. + $current_route = \Drupal::routeMatch()->getRouteName(); + if (!empty($current_route)) { + $defaults = \Drupal::entityTypeManager() + ->getStorage('metatag_defaults') + ->load($current_route); + if (!empty($defaults)) { + $tags = $defaults->get('tags'); + + // Replace the new values and keep on the global values. + $metatags = array_merge($metatags, $tags); + } + } + } +} diff --git a/web/modules/metatag/metatag_routes/metatag_routes.routing.yml b/web/modules/metatag/metatag_routes/metatag_routes.routing.yml new file mode 100644 index 0000000000000000000000000000000000000000..13b8898de170bac7ffe73feab75d93a16a0a3371 --- /dev/null +++ b/web/modules/metatag/metatag_routes/metatag_routes.routing.yml @@ -0,0 +1,9 @@ +metatag_routes.create: + path: '/admin/config/search/metatag/custom/create' + defaults: + _form: '\Drupal\metatag_routes\Form\MetatagCustomCreateForm' + _title: 'Add custom metatag' + requirements: + _permission: 'administer meta tags' + options: + _admin_route: TRUE diff --git a/web/modules/metatag/metatag_routes/src/Form/MetatagCustomCreateForm.php b/web/modules/metatag/metatag_routes/src/Form/MetatagCustomCreateForm.php new file mode 100644 index 0000000000000000000000000000000000000000..6ab77f597d7e94bc2b43c972e5623d4b7396392e --- /dev/null +++ b/web/modules/metatag/metatag_routes/src/Form/MetatagCustomCreateForm.php @@ -0,0 +1,194 @@ +<?php + +namespace Drupal\metatag_routes\Form; + +use Drupal\Core\Form\FormBase; +use Drupal\Core\Form\FormStateInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Routing\RouteProvider; +use Drupal\Core\Path\PathValidator; +use Drupal\Core\Routing\AdminContext; + +/** + * Form for creating custom definitions. + * + * @package Drupal\metatag_routes\Form + */ +class MetatagCustomCreateForm extends FormBase { + + /** + * Drupal\Core\Entity\EntityTypeManagerInterface definition. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * Drupal\Core\Routing\RouteProvider definition. + * + * @var \Drupal\Core\Routing\RouteProvider + */ + protected $routeProvider; + + /** + * Drupal\Core\Path\PathValidator definition. + * + * @var \Drupal\Core\Path\PathValidator + */ + protected $pathValidator; + + /** + * Drupal\Core\Routing\AdminContext definition. + * + * @var \Drupal\Core\Routing\AdminContext + */ + protected $adminContext; + + /** + * {@inheritdoc} + */ + public function __construct( + EntityTypeManagerInterface $entity_type_manager, + RouteProvider $route_provider, + PathValidator $path_validator, + AdminContext $admin_context + ) { + $this->entityTypeManager = $entity_type_manager; + $this->routeProvider = $route_provider; + $this->pathValidator = $path_validator; + $this->adminContext = $admin_context; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity_type.manager'), + $container->get('router.route_provider'), + $container->get('path.validator'), + $container->get('router.admin_context') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'metatag_custom_create_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $form['metatag_url'] = [ + '#type' => 'textfield', + '#title' => $this->t('Route / Path'), + '#description' => $this->t('Enter the route (path) for this new configuration, starting with a leading slash.<br />Note: this must already exist as a path in Drupal.'), + '#maxlength' => 200, + '#required' => TRUE, + ]; + + $form['route_name'] = [ + '#type' => 'hidden', + ]; + + $form['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Submit'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + parent::validateForm($form, $form_state); + + // Get the path given by the user. + $url = trim($form_state->getValue('metatag_url')); + + // Validate the url format. + if (strpos($url, '/') === FALSE) { + $form_state->setErrorByName('metatag_url', $this->t('The path must begin with /')); + return FALSE; + } + + // Get route name from path. + $url_object = $this->pathValidator->getUrlIfValid($url); + if ($url_object) { + $route_name = $url_object->getRouteName(); + $route_object = $this->routeProvider->getrouteByName($route_name); + // Avoid administrative routes to have metatags. + if ($this->adminContext->isAdminRoute($route_object)) { + $form_state->setErrorByName('metatag_url', + $this->t('The admin routes should not have metatags.')); + return FALSE; + } + + // Avoid including entity routes. + $params = $url_object->getRouteParameters(); + $entity_type = !empty($params) ? key($params) : NULL; + $entity_types = ['node', 'taxonomy_term', 'user']; + if (isset($entity_type) && in_array($entity_type, $entity_types)) { + $form_state->setErrorByName('metatag_url', + $this->t('The entities routes metatags must be added by fields. @entity_type - @id', [ + '@entity_type' => $entity_type, + '@id' => $params[$entity_type], + ])); + return FALSE; + } + + // Validate that the route doesn't have metatags created already. + $ids = $this->entityTypeManager->getStorage('metatag_defaults')->getQuery()->condition('id', $route_name)->execute(); + if ($ids) { + $form_state->setErrorByName('metatag_url', + $this->t('There are already metatags created for this route.')); + return FALSE; + } + $form_state->setValue('route_name', $route_name); + } + else { + $form_state->setErrorByName('metatag_url', $this->t('The path does not exist as an internal Drupal route.')); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Get values for form submission. + $route_name = $form_state->getValue('route_name'); + $url = $form_state->getValue('metatag_url'); + if ($route_name && $url) { + // Create the new metatag entity. + $entity = $this->entityTypeManager->getStorage('metatag_defaults')->create([ + 'id' => $route_name, + 'label' => $url, + ]); + $entity->save(); + $this->messenger()->addStatus($this->t('Created metatags for the path: @url. Internal route: @route.', [ + '@url' => $url, + '@route' => $route_name, + ])); + + // Redirect to metatag edit page. + $form_state->setRedirect('entity.metatag_defaults.edit_form', [ + 'metatag_defaults' => $route_name, + ]); + } + else { + $this->messenger()->addError($this->t('The metatags could not be created for the path: @url.', [ + '@url' => $url, + ])); + + // Redirect to metatag edit page. + $form_state->setRedirect('entity.metatag_defaults.collection'); + } + } + +} diff --git a/web/modules/metatag/metatag_twitter_cards/config/schema/metatag_twitter_cards.metatag_tag.schema.yml b/web/modules/metatag/metatag_twitter_cards/config/schema/metatag_twitter_cards.metatag_tag.schema.yml index 78ce79f2fa8583daa881cedad274d3db29c169bd..19b3e68aca83186050ce786811b59463227051af 100644 --- a/web/modules/metatag/metatag_twitter_cards/config/schema/metatag_twitter_cards.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_twitter_cards/config/schema/metatag_twitter_cards.metatag_tag.schema.yml @@ -105,7 +105,7 @@ metatag.metatag_tag.twitter_cards_site_id: type: label label: "Twitter Cards: Site's Twitter account ID" metatag.metatag_tag.twitter_cards_title: - type: label + type: text label: 'Twitter Cards: Title' metatag.metatag_tag.twitter_cards_type: type: label diff --git a/web/modules/metatag/metatag_twitter_cards/metatag_twitter_cards.info.yml b/web/modules/metatag/metatag_twitter_cards/metatag_twitter_cards.info.yml index 48fbb2accf10b3f2bed538335c3e06dbfc72faf2..011eb6a82a7a21d5d220777746be7513f866575d 100644 --- a/web/modules/metatag/metatag_twitter_cards/metatag_twitter_cards.info.yml +++ b/web/modules/metatag/metatag_twitter_cards/metatag_twitter_cards.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Twitter Cards' type: module description: Provides support for Twitter's Card meta tags. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDescription.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDescription.php index eb3cdbb4bc75aa6698ef1d88cdcb9cbf3721702f..fc4f515434054df8f772b98f52392f839a2a1693 100644 --- a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDescription.php +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDescription.php @@ -16,7 +16,8 @@ * weight = 2, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class TwitterCardsDescription extends MetaNameBase { diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel1.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel1.php index d6ecaa5bfeeb31f108706736fe0e4b950f1295e2..453d699df083a84ae5bfc1bee3e3737080e88930 100644 --- a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel1.php +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel1.php @@ -16,7 +16,8 @@ * weight = 500, * type = "string", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class TwitterCardsLabel1 extends MetaNameBase { diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel2.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel2.php index 294345f4139b8f665557aca37776b893895396d7..0338db7f4deb3c76c27d51f43903ab7e2bb9910a 100644 --- a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel2.php +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel2.php @@ -16,7 +16,8 @@ * weight = 502, * type = "string", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class TwitterCardsLabel2 extends MetaNameBase { diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsTitle.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsTitle.php index 268dfa4bd8fc4548d841374e537ee1cb38759e37..8260edaf2829a3b0baa4bb9395e10c10f11c2f64 100644 --- a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsTitle.php +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsTitle.php @@ -16,7 +16,8 @@ * weight = 2, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class TwitterCardsTitle extends MetaNameBase { diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsType.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsType.php index eeeac57f1b64b3a4c20f8f1724c84e393bc6a6c7..c905a51638c3738eb6320379f65809767bcdbd7a 100644 --- a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsType.php +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsType.php @@ -32,23 +32,33 @@ public function form(array $element = []) { '#type' => 'select', '#title' => $this->label(), '#description' => $this->description(), - '#options' => [ - 'summary' => $this->t('Summary Card'), - 'summary_large_image' => $this->t('Summary Card with large image'), - 'photo' => $this->t('Photo Card'), - 'gallery' => $this->t('Gallery Card'), - 'app' => $this->t('App Card'), - 'player' => $this->t('Player Card'), - 'product' => $this->t('Product Card'), - ], + '#options' => $this->formValues(), '#empty_option' => $this->t('- None -'), '#empty_value' => '', '#default_value' => $this->value(), - '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#required' => $element['#required'] ?? FALSE, '#element_validate' => [[get_class($this), 'validateTag']], ]; return $form; } + /** + * The list of select values. + * + * @return array + * A list of values available for this select tag. + */ + protected function formValues() { + return [ + 'summary' => $this->t('Summary Card'), + 'summary_large_image' => $this->t('Summary Card with large image'), + 'photo' => $this->t('Photo Card'), + 'gallery' => $this->t('Gallery Card'), + 'app' => $this->t('App Card'), + 'player' => $this->t('Player Card'), + 'product' => $this->t('Product Card'), + ]; + } + } diff --git a/web/modules/metatag/metatag_verification/config/schema/metatag_verification.metatag_tag.schema.yml b/web/modules/metatag/metatag_verification/config/schema/metatag_verification.metatag_tag.schema.yml index 177592d8853bb195fc29605d4282172b10ee3c16..711f8fe71d47b56bd45893c31741dd0b07df5fae 100644 --- a/web/modules/metatag/metatag_verification/config/schema/metatag_verification.metatag_tag.schema.yml +++ b/web/modules/metatag/metatag_verification/config/schema/metatag_verification.metatag_tag.schema.yml @@ -14,7 +14,7 @@ metatag.metatag_tag.bing: metatag.metatag_tag.facebook_domain_verification: type: label label: 'Site validation: Facebook' -metatag.metatag_tag.google: +metatag.metatag_tag.google_site_verification: type: label label: 'Site validation: Google' metatag.metatag_tag.norton_safe_web: @@ -26,6 +26,9 @@ metatag.metatag_tag.pinterest: metatag.metatag_tag.pocket: type: label label: 'Site validation: Pocket' +metatag.metatag_tag.siwecos: + type: label + label: 'Site validation: SIWECOS' metatag.metatag_tag.yahoo: type: label label: 'Site validation: Yahoo' diff --git a/web/modules/metatag/metatag_verification/metatag_verification.info.yml b/web/modules/metatag/metatag_verification/metatag_verification.info.yml index b575b8036bc0c112db19fc591686c8a26b83ca3f..25014f4cc313fdcc0df651dcb6cb37457f3642ef 100644 --- a/web/modules/metatag/metatag_verification/metatag_verification.info.yml +++ b/web/modules/metatag/metatag_verification/metatag_verification.info.yml @@ -1,12 +1,12 @@ name: 'Metatag: Verification' type: module description: Verifies ownership of a site for search engines and other services. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_verification/metatag_verification.post_update.php b/web/modules/metatag/metatag_verification/metatag_verification.post_update.php new file mode 100644 index 0000000000000000000000000000000000000000..555ba18a322d91de02befe8e196e22f3f95883de --- /dev/null +++ b/web/modules/metatag/metatag_verification/metatag_verification.post_update.php @@ -0,0 +1,41 @@ +<?php + +/** + * @file + * Post update functions for Metatag Verification. + */ + +use Drupal\Core\Config\Entity\ConfigEntityUpdater; +use Drupal\metatag\Entity\MetatagDefaults; + +/** + * Fix regressions from when the duplicate "google" meta tag fixed. + */ +function metatag_verification_post_update_fix_google_tag_regression(&$sandbox) { + $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class); + $config_entity_updater->update($sandbox, 'metatag_defaults', function (MetatagDefaults $metatag_defaults) { + if ($metatag_defaults->hasTag('google')) { + $tags = $metatag_defaults->get('tags'); + + // Don't do anything if the google_site_verification tag is already + // defined. + if (!empty($tags['google_site_verification'])) { + return FALSE; + } + + // Only change the data if the 'google' value is not one of the accepted + // values for that tag. + if (strpos($tags['google'], 'nositelinkssearchbox') === FALSE + && strpos($tags['google'], 'nopagereadaloud') === FALSE + && strpos($tags['google'], 'notranslate') === FALSE) { + // Set the verification tag to the old value, delete the old value and + // then update the record. + $tags['google_site_verification'] = $tags['google']; + unset($tags['google']); + $metatag_defaults->set('tags', $tags); + return TRUE; + } + } + return FALSE; + }); +} diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Google.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Google.php index c57152d3a29365e2e3f78d48f316771e6c47d30a..6154dbe780f3232a396089198d859d5985ee8bb5 100644 --- a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Google.php +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Google.php @@ -8,8 +8,8 @@ * Provides a plugin for the 'google-site-verification' meta tag. * * @MetatagTag( - * id = "google", - * label = @Translation("Google"), + * id = "google_site_verification", + * label = @Translation("Google Site Verification"), * description = @Translation("A string provided by <a href=':google'>Google</a>, full details are available from the <a href=':verify_url'>Google online help</a>.", arguments = { ":google" = "https://www.google.com/", ":verify_url" = "https://support.google.com/webmasters/answer/35179?hl=en" }), * name = "google-site-verification", * group = "site_verification", diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Siwecos.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Siwecos.php new file mode 100644 index 0000000000000000000000000000000000000000..bcf3181f7b4087ed25e2cb41eb0c47841112541e --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Siwecos.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_verification\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'siwecostoken' meta tag. + * + * @MetatagTag( + * id = "siwecos", + * label = @Translation("SIWECOS"), + * description = @Translation("A string provided by <a href=':siwecos'>SIWECOS</a>, the free website security scanner.", arguments = {":siwecos" = "https://siwecos.de/"}), + * name = "siwecostoken", + * group = "site_verification", + * weight = 7, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Siwecos extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_verification/tests/src/Functional/MetatagVerificationTagsTest.php b/web/modules/metatag/metatag_verification/tests/src/Functional/MetatagVerificationTagsTest.php index 9e01deb5dc23735aa414cdccc9ccb4342bf8bd3c..fe823c56baff5b187560e77b74fb7649e2567cd0 100644 --- a/web/modules/metatag/metatag_verification/tests/src/Functional/MetatagVerificationTagsTest.php +++ b/web/modules/metatag/metatag_verification/tests/src/Functional/MetatagVerificationTagsTest.php @@ -25,10 +25,11 @@ class MetatagVerificationTagsTest extends MetatagTagsTestBase { 'baidu', 'bing', 'facebook_domain_verification', - 'google', + 'google_site_verification', 'norton_safe_web', 'pinterest', 'pocket', + 'siwecos', 'yandex', 'zoom_domain_verification', ]; @@ -46,7 +47,7 @@ protected function getTestTagName($tag_name) { elseif ($tag_name == 'facebook_domain_verification') { $tag_name = 'facebook-domain-verification'; } - elseif ($tag_name == 'google') { + elseif ($tag_name == 'google_site_verification') { $tag_name = 'google-site-verification'; } elseif ($tag_name == 'norton_safe_web') { @@ -58,6 +59,9 @@ protected function getTestTagName($tag_name) { elseif ($tag_name == 'pocket') { $tag_name = 'pocket-site-verification'; } + elseif ($tag_name == 'siwecos') { + $tag_name = 'siwecostoken'; + } elseif ($tag_name == 'yandex') { $tag_name = 'yandex-verification'; } diff --git a/web/modules/metatag/metatag_views/config/schema/metatag_views.views.schema.yml b/web/modules/metatag/metatag_views/config/schema/metatag_views.views.schema.yml index b98db8cadcf5d8f17aa640ba2a895d3e078044af..e4e3eb23e5984f351695ed00a327f58fd0c13c8e 100644 --- a/web/modules/metatag/metatag_views/config/schema/metatag_views.views.schema.yml +++ b/web/modules/metatag/metatag_views/config/schema/metatag_views.views.schema.yml @@ -6,3 +6,6 @@ views.display_extender.metatag_display_extender: label: 'Metatags' sequence: type: metatag.metatag_tag.[%key] + tokenize: + type: boolean + label: 'Should replacement tokens be used from the first row' diff --git a/web/modules/metatag/metatag_views/metatag_views.info.yml b/web/modules/metatag/metatag_views/metatag_views.info.yml index 66c98dd3a14102ff56c8fa4409fa2d4b975009e4..1e7332187e80489ac4272a2a0dfa04a99517ffa7 100644 --- a/web/modules/metatag/metatag_views/metatag_views.info.yml +++ b/web/modules/metatag/metatag_views/metatag_views.info.yml @@ -1,13 +1,13 @@ name: 'Metatag: Views' type: module description: Provides views integration for metatags. -core_version_requirement: '^8.7.7 || ^9' +core_version_requirement: '^9.3 || ^10' package: SEO dependencies: - metatag:metatag - drupal:views -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/metatag_views/metatag_views.install b/web/modules/metatag/metatag_views/metatag_views.install index f743437240dcfe0d4647364cfc609b9108532fb0..0e74de055c4af27ff221f1517b080a34ddd4d158 100644 --- a/web/modules/metatag/metatag_views/metatag_views.install +++ b/web/modules/metatag/metatag_views/metatag_views.install @@ -5,6 +5,8 @@ * Various install/uninstall hooks for the Metatag Views module. */ +use Drupal\Core\StringTranslation\TranslatableMarkup; + /** * Implements hook_install(). */ @@ -41,5 +43,12 @@ function metatag_views_uninstall() { * Notify admins that the custom admin pages were (temporarily) disabled. */ function metatag_views_update_8100() { - return (string) t("The custom admin pages for managing Views meta tags at /admin/config/search/metatag/views have been disabled for now, hopefully they'll be back in a future release. Until then, the meta tags can be managed directly on each individual view via the \"Meta tags\" section."); + return (string) new TranslatableMarkup("The custom admin pages for managing Views meta tags at /admin/config/search/metatag/views have been disabled for now, hopefully they'll be back in a future release. Until then, the meta tags can be managed directly on each individual view via the \"Meta tags\" section."); +} + +/** + * Empty update script to trigger a cache clear. + */ +function metatag_views_update_8101() { + return (string) new TranslatableMarkup("Empty update script to clear the site's caches so the new token replacement functionality will work."); } diff --git a/web/modules/metatag/metatag_views/metatag_views.module b/web/modules/metatag/metatag_views/metatag_views.module index 7d8d1b5394366f9bfc8dea969ecee9ac51649eb1..aa3d57063d25670e5acbe6d5c5427680d69ddbea 100644 --- a/web/modules/metatag/metatag_views/metatag_views.module +++ b/web/modules/metatag/metatag_views/metatag_views.module @@ -6,6 +6,9 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\metatag_views\MetatagViewsCacheWrapper; +use Drupal\metatag_views\Plugin\views\display_extender\MetatagDisplayExtender; +use Drupal\views\Plugin\views\cache\CachePluginBase; use Drupal\views\ViewEntityInterface; use Drupal\views\ViewExecutable; use Drupal\views\Views; @@ -47,7 +50,9 @@ function metatag_get_view_tags($view, $display_id = NULL, $args = []) { } // Retrieve the metatag settings from the extender. - return $extenders['metatag_display_extender']->getMetatags(); + /** @var \Drupal\metatag_views\Plugin\views\display_extender\MetatagDisplayExtender */ + $extender = $extenders['metatag_display_extender']; + return $extender->getMetatags(); } /** @@ -93,3 +98,16 @@ function metatag_views_metatag_route_entity(RouteMatchInterface $route_match) { return $entity; } } + +/** + * Implements hook_views_post_render(). + */ +function metatag_views_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) { + $extenders = $view->getDisplay()->getExtenders(); + if (isset($extenders['metatag_display_extender'])) { + $first_row_tokens = MetatagDisplayExtender::getFirstRowTokensFromStylePlugin($view); + /** @var \Drupal\metatag_views\Plugin\views\display_extender\MetatagDisplayExtender */ + $extender = $extenders['metatag_display_extender']; + $extender->setFirstRowTokens($first_row_tokens); + } +} diff --git a/web/modules/metatag/metatag_views/src/Controller/MetatagViewsController.php b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsController.php index 2ddf0b824e43183c81ac437f8174479f9f31dc20..01978aa50b4464fedad5dc143e6745bd98f51f1a 100644 --- a/web/modules/metatag/metatag_views/src/Controller/MetatagViewsController.php +++ b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsController.php @@ -10,7 +10,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Class MetatagViewsController. + * Controller for managing the Views integration. * * @package Drupal\metatag_views\Controller */ @@ -45,7 +45,7 @@ public function __construct(EntityStorageInterface $viewStorage, MetatagManagerI $this->metatagManager = $metatagManager; // Generate the labels for views and displays. - $this->labels = $this->getViewsAndDisplaysLabels(); + $this->viewLabels = $this->getViewsAndDisplaysLabels(); } /** @@ -101,7 +101,7 @@ public function listViews() { foreach ($tagged_views as $view_id => $displays) { $elements[$view_id] = [ '#type' => 'details', - '#title' => $this->t($this->viewLabels[$view_id]['#label']), + '#title' => $this->t(':label', [':label' => $this->viewLabels[$view_id]['#label']]), 'details' => $this->buildViewDetails($view_id, $displays), ]; } diff --git a/web/modules/metatag/metatag_views/src/Controller/MetatagViewsTranslationController.php b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsTranslationController.php index cf23142781cd8082b7532a838d46b28a1ef5f33b..9de54ba8ef1f108e09fc6f29249fa043c9935264 100644 --- a/web/modules/metatag/metatag_views/src/Controller/MetatagViewsTranslationController.php +++ b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsTranslationController.php @@ -36,7 +36,7 @@ class MetatagViewsTranslationController extends ControllerBase { * @var \Drupal\Core\Language\LanguageManagerInterface */ protected $languageManager; - + /** * The request stack. * @@ -82,7 +82,9 @@ public static function create(ContainerInterface $container) { * Page render array. */ public function itemPage() { + // @todo This method doesn't exist? $view_id = $this->requestStack->get('view_id'); + // @todo This method doesn't exist? $display_id = $this->requestStack->get('display_id'); $view = $this->viewStorage->load($view_id); @@ -123,6 +125,7 @@ public function itemPage() { } else { // Get the metatag translation for this language. + // @todo The getLanguageConfigOverride() method doesn't exist? $config_translation = $this->languageManager ->getLanguageConfigOverride($langcode, $config_name) ->get($config_path); @@ -161,9 +164,9 @@ public function itemPage() { '#links' => $operations, // Even if the mapper contains multiple language codes, the source // configuration can still be edited. - // {@code} + // @code // '#access' => ($langcode == $original_langcode) || $operations_access, - // {@endcode} + // @endcode ]; } diff --git a/web/modules/metatag/metatag_views/src/Form/MetatagViewsAddForm.php b/web/modules/metatag/metatag_views/src/Form/MetatagViewsAddForm.php index 476293df95b34836d24122b0a0723a83a2fb7afb..b46d93b0dc94886fe0e71955d6454ce5b5e74fcf 100644 --- a/web/modules/metatag/metatag_views/src/Form/MetatagViewsAddForm.php +++ b/web/modules/metatag/metatag_views/src/Form/MetatagViewsAddForm.php @@ -7,7 +7,7 @@ use Drupal\views\Views; /** - * Class MetatagViewsAddForm. + * The add form for the Metatag field, which extends the edit form. * * @package Drupal\metatag_views\Form */ diff --git a/web/modules/metatag/metatag_views/src/Form/MetatagViewsEditForm.php b/web/modules/metatag/metatag_views/src/Form/MetatagViewsEditForm.php index 59ddb01dc633bcdd86f5fc3df647ba72c08d5402..60a671e67509a3f73e19a6c980e44d41fb59ee04 100644 --- a/web/modules/metatag/metatag_views/src/Form/MetatagViewsEditForm.php +++ b/web/modules/metatag/metatag_views/src/Form/MetatagViewsEditForm.php @@ -10,7 +10,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Class MetatagViewsEditForm. + * The edit form for the Metatag field. * * @package Drupal\metatag_views\Form */ @@ -116,9 +116,10 @@ public function form(array $values, array $element, array $token_types = [], arr '#type' => 'details', ]; + // @todo This needs to be added via DI. $element += $this->tokenService->tokenBrowser($token_types, $verbose_help); - $groups_and_tags = $this->sortedGroupsWithTags(); + $groups_and_tags = $this->metatagManager->sortedGroupsWithTags(); $first = TRUE; foreach ($groups_and_tags as $group_id => $group) { @@ -136,10 +137,11 @@ public function form(array $values, array $element, array $token_types = [], arr // Only act on tags in the included tags list, unless that is null. if (is_null($included_tags) || in_array($tag_id, $included_tags)) { // Make an instance of the tag. + // @todo This needs to be added via DI. $tag = $this->tagPluginManager->createInstance($tag_id); // Set the value to the stored value, if any. - $tag_value = isset($values[$tag_id]) ? $values[$tag_id] : NULL; + $tag_value = $values[$tag_id] ?? NULL; $tag->setValue($tag_value); // Create the bit of form for this tag. @@ -158,7 +160,7 @@ public function form(array $values, array $element, array $token_types = [], arr public function submitForm(array &$form, FormStateInterface $form_state) { // Get the submitted form values. $view_name = $form_state->getValue('view'); - list($view_id, $display_id) = explode(':', $view_name); + [$view_id, $display_id] = explode(':', $view_name); $metatags = $form_state->getValues(); unset($metatags['view']); @@ -178,6 +180,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $configuration->clear($config_path); } else { + // Sort the values prior to saving. so that they are easier to manage. + ksort($metatags); + $configuration->set($config_path, $metatags); } $configuration->save(); diff --git a/web/modules/metatag/metatag_views/src/Form/MetatagViewsRevertForm.php b/web/modules/metatag/metatag_views/src/Form/MetatagViewsRevertForm.php index 70397a21223a626649c6469dc2a591325e7ad242..496c541f98a2908621bd48164c5ca5305b6ccb34 100644 --- a/web/modules/metatag/metatag_views/src/Form/MetatagViewsRevertForm.php +++ b/web/modules/metatag/metatag_views/src/Form/MetatagViewsRevertForm.php @@ -101,7 +101,8 @@ public function getCancelText() { /** * {@inheritdoc} */ - public function buildForm(array $form, FormStateInterface $form_state, $view_id = NULL, $display_id = NUL) { + public function buildForm(array $form, FormStateInterface $form_state, $view_id = NULL, $display_id = NULL) { + // @todo This method doesn't exist. $this->view = $this->viewsManager->load($view_id); $this->displayId = $display_id; diff --git a/web/modules/metatag/metatag_views/src/MetatagViewsCachePluginManager.php b/web/modules/metatag/metatag_views/src/MetatagViewsCachePluginManager.php new file mode 100644 index 0000000000000000000000000000000000000000..418cae7afa14fb18dd649b0b05bdf3bd0dab059d --- /dev/null +++ b/web/modules/metatag/metatag_views/src/MetatagViewsCachePluginManager.php @@ -0,0 +1,119 @@ +<?php + +namespace Drupal\metatag_views; + +use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface; +use Drupal\Component\Plugin\PluginManagerInterface; +use Drupal\Core\Cache\CacheableDependencyInterface; +use Drupal\views\Plugin\views\cache\CachePluginBase; +use Drupal\views\Plugin\ViewsPluginManager; + +/** + * Custom cache plugin system for Views. + */ +class MetatagViewsCachePluginManager implements PluginManagerInterface, CachedDiscoveryInterface, CacheableDependencyInterface { + + /** + * {@inheritdoc} + * + * @var \Drupal\views\Plugin\ViewsPluginManager + */ + protected $viewsPluginManager; + + /** + * MetatagViewsCachePluginManager constructor. + * + * @param \Drupal\views\Plugin\ViewsPluginManager $views_plugin_manager + * The ViewsPluginManager as argument. + */ + public function __construct(ViewsPluginManager $views_plugin_manager) { + $this->viewsPluginManager = $views_plugin_manager; + } + + /** + * {@inheritdoc} + * + * @param \Drupal\views\Plugin\views\cache\CachePluginBase $plugin + * The CachePluginBase as argument. + * + * @return \Drupal\metatag_views\MetatagViewsCacheWrapper + * Return new MetatagViewsCacheWrapper + */ + protected function wrap(CachePluginBase $plugin) { + return new MetatagViewsCacheWrapper($plugin); + } + + /** + * {@inheritdoc} + */ + public function createInstance($plugin_id, array $configuration = []) { + $plugin = $this->viewsPluginManager->createInstance($plugin_id, $configuration); + return $plugin_id === 'none' ? $plugin : $this->wrap($plugin); + } + + /** + * {@inheritdoc} + */ + public function getInstance(array $options) { + /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $plugin */ + $plugin = $this->viewsPluginManager->getInstance($options); + return $plugin->getPluginId() === 'none' ? $plugin : $this->wrap($plugin); + } + + /** + * {@inheritdoc} + */ + public function getCacheContexts() { + return $this->viewsPluginManager->getCacheContexts(); + } + + /** + * {@inheritdoc} + */ + public function getCacheTags() { + return $this->viewsPluginManager->getCacheTags(); + } + + /** + * {@inheritdoc} + */ + public function getCacheMaxAge() { + return $this->viewsPluginManager->getCacheMaxAge(); + } + + /** + * {@inheritdoc} + */ + public function clearCachedDefinitions() { + $this->viewsPluginManager->clearCachedDefinitions(); + } + + /** + * {@inheritdoc} + */ + public function useCaches($use_caches = FALSE) { + $this->viewsPluginManager->useCaches($use_caches); + } + + /** + * {@inheritdoc} + */ + public function getDefinition($plugin_id, $exception_on_invalid = TRUE) { + return $this->viewsPluginManager->getDefinition($plugin_id, $exception_on_invalid); + } + + /** + * {@inheritdoc} + */ + public function getDefinitions() { + return $this->viewsPluginManager->getDefinitions(); + } + + /** + * {@inheritdoc} + */ + public function hasDefinition($plugin_id) { + return $this->viewsPluginManager->hasDefinition($plugin_id); + } + +} diff --git a/web/modules/metatag/metatag_views/src/MetatagViewsCacheWrapper.php b/web/modules/metatag/metatag_views/src/MetatagViewsCacheWrapper.php new file mode 100644 index 0000000000000000000000000000000000000000..f58317834e0f5806e5e4e0a0908c5b7695bd18ea --- /dev/null +++ b/web/modules/metatag/metatag_views/src/MetatagViewsCacheWrapper.php @@ -0,0 +1,400 @@ +<?php + +namespace Drupal\metatag_views; + +use Drupal\Core\Cache\Cache; +use Drupal\Core\Cache\CacheableMetadata; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Messenger\MessengerInterface; +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\metatag_views\Plugin\views\display_extender\MetatagDisplayExtender; +use Drupal\views\Plugin\views\cache\CachePluginBase; +use Drupal\views\Plugin\views\display\DisplayPluginBase; +use Drupal\views\ResultRow; +use Drupal\views\ViewExecutable; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * This class wraps a Views cache plugin. + */ +class MetatagViewsCacheWrapper extends CachePluginBase { + + /** + * The cache type we are interested in. + */ + const RESULTS = 'results'; + + /** + * {@inheritdoc} + * + * @var \Drupal\views\Plugin\views\cache\CachePluginBase + */ + protected $plugin; + + /** + * MetatagViewsCacheWrapper constructor. + * + * @param \Drupal\views\Plugin\views\cache\CachePluginBase $plugin + * The cache plugin being wrapped. + */ + public function __construct(CachePluginBase $plugin) { + $this->plugin = $plugin; + } + + /** + * {@inheritdoc} + */ + public function cacheSet($type) { + if ($type === self::RESULTS) { + $plugin = $this->plugin; + $view = $plugin->view; + $data = [ + 'result' => $plugin->prepareViewResult($view->result), + 'total_rows' => $view->total_rows ?? 0, + 'current_page' => $view->getCurrentPage(), + 'first_row_tokens' => MetatagDisplayExtender::getFirstRowTokensFromStylePlugin($view), + ]; + $cache_set_max_age = $this->cacheSetMaxAge('results'); + $expire = ($cache_set_max_age === Cache::PERMANENT) ? Cache::PERMANENT : (int) $view->getRequest()->server->get('REQUEST_TIME') + $cache_set_max_age; + \Drupal::cache($plugin->resultsBin) + ->set($plugin->generateResultsKey(), $data, $expire, $plugin->getCacheTags()); + } + else { + $this->plugin->cacheSet($type); + } + } + + /** + * {@inheritdoc} + */ + public function cacheGet($type) { + switch ($type) { + case self::RESULTS: + $cutoff = $this->plugin->cacheExpire($type); + // Values to set: $view->result, $view->total_rows, $view->execute_time, + // $view->current_page and pass row tokens to metatag display extender. + if ($cache = \Drupal::cache($this->plugin->resultsBin)->get($this->plugin->generateResultsKey())) { + if (!$cutoff || $cache->created > $cutoff) { + $view = $this->plugin->view; + $view->result = $cache->data['result']; + // Load entities for each result. + $view->query->loadEntities($view->result); + $view->total_rows = $cache->data['total_rows']; + $view->setCurrentPage($cache->data['current_page'], TRUE); + $view->execute_time = 0; + $extenders = $view->getDisplay()->getExtenders(); + if (isset($extenders['metatag_display_extender'])) { + $extenders['metatag_display_extender']->setFirstRowTokens($cache->data['first_row_tokens']); + } + return TRUE; + } + } + return FALSE; + + default: + return $this->plugin->cacheGet($type); + } + } + + /** + * {@inheritdoc} + */ + public function getResultsKey() { + return $this->plugin->getResultsKey(); + } + + /** + * {@inheritdoc} + */ + public function summaryTitle() { + return $this->plugin->summaryTitle(); + } + + /** + * {@inheritdoc} + */ + public function cacheFlush() { + $this->plugin->cacheFlush(); + } + + /** + * {@inheritdoc} + */ + public function postRender(&$output) { + $this->plugin->postRender($output); + } + + /** + * {@inheritdoc} + */ + public function generateResultsKey() { + return $this->plugin->generateResultsKey(); + } + + /** + * {@inheritdoc} + */ + public function getCacheTags() { + return $this->plugin->getCacheTags(); + } + + /** + * {@inheritdoc} + */ + public function getCacheMaxAge() { + return $this->plugin->getCacheMaxAge(); + } + + /** + * {@inheritdoc} + */ + public function alterCacheMetadata(CacheableMetadata $cache_metadata) { + $this->plugin->alterCacheMetadata($cache_metadata); + } + + /** + * {@inheritdoc} + */ + public function getRowCacheTags(ResultRow $row) { + return $this->plugin->getRowCacheTags($row); + } + + /** + * {@inheritdoc} + */ + public function getRowCacheKeys(ResultRow $row) { + return $this->plugin->getRowCacheKeys($row); + } + + /** + * {@inheritdoc} + */ + public function getRowId(ResultRow $row) { + return $this->plugin->getRowId($row); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + CachePluginBase::create($container, $configuration, $plugin_id, $plugin_definition); + } + + /** + * {@inheritdoc} + */ + public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { + $this->plugin->init($view, $display, $options); + } + + /** + * {@inheritdoc} + */ + public function filterByDefinedOptions(array &$storage) { + $this->plugin->filterByDefinedOptions($storage); + } + + /** + * {@inheritdoc} + */ + public function unpackOptions(&$storage, $options, $definition = NULL, $all = TRUE, $check = TRUE) { + $this->plugin->unpackOptions($storage, $options, $definition, $all, $check); + } + + /** + * {@inheritdoc} + */ + public function destroy() { + $this->plugin->destroy(); + } + + /** + * {@inheritdoc} + */ + public function buildOptionsForm(&$form, FormStateInterface $form_state) { + $this->plugin->buildOptionsForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public static function trustedCallbacks() { + CachePluginBase::trustedCallbacks(); + } + + /** + * {@inheritdoc} + */ + public function validateOptionsForm(&$form, FormStateInterface $form_state) { + $this->plugin->validateOptionsForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitOptionsForm(&$form, FormStateInterface $form_state) { + $this->plugin->submitOptionsForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function query() { + $this->plugin->query(); + } + + /** + * {@inheritdoc} + */ + public function themeFunctions() { + return $this->plugin->themeFunctions(); + } + + /** + * {@inheritdoc} + */ + public function validate() { + return $this->plugin->validate(); + } + + /** + * {@inheritdoc} + */ + public function pluginTitle() { + return $this->plugin->pluginTitle(); + } + + /** + * {@inheritdoc} + */ + public function usesOptions() { + return $this->plugin->usesOptions(); + } + + /** + * {@inheritdoc} + */ + public function globalTokenReplace($string = '', array $options = []) { + return $this->plugin->globalTokenReplace($string, $options); + } + + /** + * {@inheritdoc} + */ + public function getAvailableGlobalTokens($prepared = FALSE, array $types = []) { + return $this->plugin->getAvailableGlobalTokens($prepared, $types); + } + + /** + * {@inheritdoc} + */ + public function globalTokenForm(&$form, FormStateInterface $form_state) { + $this->plugin->globalTokenForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public static function preRenderAddFieldsetMarkup(array $form) { + CachePluginBase::preRenderAddFieldsetMarkup($form); + } + + /** + * {@inheritdoc} + */ + public static function preRenderFlattenData($form) { + CachePluginBase::preRenderFlattenData($form); + } + + /** + * {@inheritdoc} + */ + public function calculateDependencies() { + return $this->plugin->calculateDependencies(); + } + + /** + * {@inheritdoc} + */ + public function getProvider() { + return $this->plugin->getProvider(); + } + + /** + * {@inheritdoc} + */ + public static function queryLanguageSubstitutions() { + CachePluginBase::queryLanguageSubstitutions(); + } + + /** + * {@inheritdoc} + */ + public function getPluginId() { + return $this->plugin->getPluginId(); + } + + /** + * {@inheritdoc} + */ + public function getBaseId() { + return $this->plugin->getBaseId(); + } + + /** + * {@inheritdoc} + */ + public function getDerivativeId() { + return $this->plugin->getDerivativeId(); + } + + /** + * {@inheritdoc} + */ + public function getPluginDefinition() { + return $this->plugin->getPluginDefinition(); + } + + /** + * {@inheritdoc} + */ + public function isConfigurable() { + return $this->plugin->isConfigurable(); + } + + /** + * {@inheritdoc} + */ + public function setStringTranslation(TranslationInterface $translation) { + return $this->plugin->setStringTranslation($translation); + } + + /** + * {@inheritdoc} + */ + public function setMessenger(MessengerInterface $messenger) { + $this->plugin->setMessenger($messenger); + } + + /** + * {@inheritdoc} + */ + public function messenger() { + $this->plugin->messenger(); + } + + /** + * {@inheritdoc} + */ + public function __get($name) { + return $this->plugin->$name; + } + + /** + * {@inheritdoc} + */ + public function __set($name, $value) { + $this->plugin->$name = $value; + } + +} diff --git a/web/modules/metatag/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php b/web/modules/metatag/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php index 6306b95410e0f814a084fa3d52cd76c5057c5933..592be74ea7981c9c499cb5f601f6ee02b3a9ef45 100644 --- a/web/modules/metatag/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php +++ b/web/modules/metatag/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php @@ -4,8 +4,11 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase; +use Drupal\views\Plugin\views\style\StylePluginBase; +use Drupal\views\ViewExecutable; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Metatag display extender plugin. @@ -37,6 +40,13 @@ class MetatagDisplayExtender extends DisplayExtenderPluginBase { */ protected $metatagTagManager; + /** + * The first row tokens on the style plugin. + * + * @var array + */ + protected static $firstRowTokens; + /** * {@inheritdoc} */ @@ -49,6 +59,18 @@ public static function create(ContainerInterface $container, array $configuratio return $instance; } + /** + * {@inheritdoc} + */ + protected function defineOptions() { + $options = parent::defineOptions(); + + $options['metatags'] = ['default' => []]; + $options['tokenize'] = ['default' => FALSE]; + + return $options; + } + /** * Provide a form to edit options for this plugin. */ @@ -56,10 +78,11 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { if ($form_state->get('section') == 'metatags') { $form['#title'] .= $this->t('The meta tags for this display'); - $metatags = $this->getMetatags(); + $metatags = $this->getMetatags(TRUE); // Build/inject the Metatag form. $form['metatags'] = $this->metatagManager->form($metatags, $form, ['view']); + $this->tokenForm($form['metatags'], $form_state); } } @@ -77,6 +100,8 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) { // Process submitted metatag values and remove empty tags. $tag_values = []; $metatags = $form_state->cleanValues()->getValues(); + $this->options['tokenize'] = $metatags['tokenize'] ?? FALSE; + unset($metatags['tokenize']); foreach ($metatags as $tag_id => $tag_value) { // Some plugins need to process form input before storing it. // Hence, we set it and then get it. @@ -90,6 +115,61 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) { } } + /** + * Verbatim copy of TokenizeAreaPluginBase::tokenForm(). + */ + public function tokenForm(&$form, FormStateInterface $form_state) { + $form['tokenize'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Use replacement tokens from the first row'), + '#default_value' => $this->options['tokenize'], + ]; + + // Get a list of the available fields and arguments for token replacement. + $options = []; + $optgroup_arguments = (string) new TranslatableMarkup('Arguments'); + $optgroup_fields = (string) new TranslatableMarkup('Fields'); + foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) { + $options[$optgroup_fields]["{{ $field }}"] = $handler->adminLabel(); + } + + foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) { + $options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', ['@argument' => $handler->adminLabel()]); + $options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', ['@argument' => $handler->adminLabel()]); + } + + if (!empty($options)) { + $form['tokens'] = [ + '#type' => 'details', + '#title' => $this->t('Replacement patterns'), + '#open' => TRUE, + '#id' => 'edit-options-token-help', + '#states' => [ + 'visible' => [ + ':input[name="options[tokenize]"]' => ['checked' => TRUE], + ], + ], + ]; + $form['tokens']['help'] = [ + '#markup' => '<p>' . $this->t('The following tokens are available. You may use Twig syntax in this field.') . '</p>', + ]; + foreach (array_keys($options) as $type) { + if (!empty($options[$type])) { + $items = []; + foreach ($options[$type] as $key => $value) { + $items[] = $key . ' == ' . $value; + } + $form['tokens'][$type]['tokens'] = [ + '#theme' => 'item_list', + '#items' => $items, + ]; + } + } + } + + $this->globalTokenForm($form, $form_state); + } + /** * Set up any variables on the view prior to execution. */ @@ -140,16 +220,32 @@ protected function hasMetatags() { /** * Get the Metatag configuration for this display. * + * @param bool $raw + * TRUE to suppress tokenization. + * * @return array * The meta tag values. */ - public function getMetatags() { + public function getMetatags($raw = FALSE) { + $view = $this->view; $metatags = []; if (!empty($this->options['metatags'])) { $metatags = $this->options['metatags']; } + if ($this->options['tokenize'] && !$raw) { + if (self::$firstRowTokens) { + self::setFirstRowTokensOnStylePlugin($view, self::$firstRowTokens); + } + // This is copied from TokenizeAreaPluginBase::tokenizeValue(). + $style = $view->getStyle(); + foreach ($metatags as $key => $metatag) { + $metatag = $style->tokenizeValue($metatag, 0); + $metatags[$key] = $this->globalTokenReplace($metatag); + } + } + return $metatags; } @@ -163,4 +259,57 @@ public function setMetatags(array $metatags) { $this->options['metatags'] = $metatags; } + /** + * Store first row tokens on the class. + * + * The function metatag_views_metatag_route_entity() loads the View fresh, to + * avoid rebuilding and re-rendering it, preserve the first row tokens. + */ + public function setFirstRowTokens(array $first_row_tokens) { + self::$firstRowTokens = $first_row_tokens; + } + + /** + * Set the first row tokens on the style plugin. + * + * @param \Drupal\views\ViewExecutable $view + * The view. + * @param array $first_row_tokens + * The first row tokens. + */ + public static function setFirstRowTokensOnStylePlugin(ViewExecutable $view, array $first_row_tokens) { + $style = $view->getStyle(); + self::getFirstRowTokensReflection($style)->setValue($style, [$first_row_tokens]); + } + + /** + * Get the first row tokens from the style plugin. + * + * @param \Drupal\views\ViewExecutable $view + * The view. + * + * @return array + * The first row tokens. + */ + public static function getFirstRowTokensFromStylePlugin(ViewExecutable $view) { + $style = $view->getStyle(); + return self::getFirstRowTokensReflection($style)->getValue($style)[0] ?? []; + } + + /** + * Get the first row tokens for this Views object iteration. + * + * @param \Drupal\views\Plugin\views\style\StylePluginBase $style + * The style plugin used for this request. + * + * @return \ReflectionProperty + * The rawTokens property. + */ + protected static function getFirstRowTokensReflection(StylePluginBase $style): \ReflectionProperty { + $r = new \ReflectionObject($style); + $p = $r->getProperty('rowTokens'); + $p->setAccessible(TRUE); + return $p; + } + } diff --git a/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsBasicsTest.php b/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsBasicsTest.php index 728295d4a8d27b16209701a3a34d38e02db549ff..fea29ed6945ab67321e0586d7162823171bbdaeb 100644 --- a/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsBasicsTest.php +++ b/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsBasicsTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\metatag_views\Functional; use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\metatag\Functional\MetatagHelperTrait; /** * Confirm the defaults functionality works. @@ -12,7 +13,7 @@ class MetatagViewsBasicsTest extends BrowserTestBase { // Contains helper methods. - use \Drupal\Tests\metatag\Functional\MetatagHelperTrait; + use MetatagHelperTrait; /** * {@inheritdoc} @@ -41,26 +42,19 @@ class MetatagViewsBasicsTest extends BrowserTestBase { /** * {@inheritdoc} */ - protected $defaultTheme = 'bartik'; + protected $defaultTheme = 'claro'; /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); - // Enable the Bartik theme and make it the default. - // @todo remove this once 8.8 is required and $defaultTheme can be - // relied upon. - $theme = 'bartik'; - \Drupal::service('theme_installer')->install([$theme]); - $this->config('system.theme')->set('default', $theme); - // Place the local actions block in the theme so that we can assert the // presence of local actions and such. $this->drupalPlaceBlock('local_actions_block', [ 'region' => 'content', - 'theme' => $theme, + 'theme' => $this->defaultTheme, ]); } @@ -107,21 +101,21 @@ public function testViewsUi() { $this->clickLink('Page'); // Confirm that no changes have been made yet. - $this->assertNoText('Overridden'); + $this->assertSession()->pageTextNotContains('Overridden'); // Open the settings dialog. $this->clickLink('Using defaults'); // Confirm the settings opened and it has some basic fields. $this->assertSession()->pageTextContains('Configure the meta tags below.'); - $this->assertFieldByName('title'); - $this->assertFieldByName('description'); - $this->assertFieldByName('op'); + $this->assertSession()->fieldExists('title'); + $this->assertSession()->fieldExists('description'); + $this->assertSession()->fieldExists('op'); $edit = [ 'title' => 'Metatag title', 'description' => 'Metatag description.', ]; - $this->drupalPostForm(NULL, $edit, 'Apply'); + $this->submitForm($edit, 'Apply'); // Confirm the Metatag settings are now overridden. $this->assertSession()->pageTextContains('Overridden'); @@ -129,7 +123,7 @@ public function testViewsUi() { // @todo Confirm there's now a "save" button. // Save the changes. $edit = []; - $this->drupalPostForm(NULL, $edit, 'Save'); + $this->submitForm($edit, 'Save'); // @todo Confirm the page saved. // Load the archives page again. @@ -142,13 +136,13 @@ public function testViewsUi() { // Load the Metatag admin page to confirm it still works. $this->drupalGet('admin/config/search/metatag'); $this->assertSession()->statusCodeEquals(200); - $this->assertLinkByHref('/admin/config/search/metatag/global'); - $this->assertLinkByHref('/admin/config/search/metatag/front'); - $this->assertLinkByHref('/admin/config/search/metatag/403'); - $this->assertLinkByHref('/admin/config/search/metatag/404'); - $this->assertLinkByHref('/admin/config/search/metatag/node'); - $this->assertLinkByHref('/admin/config/search/metatag/taxonomy_term'); - $this->assertLinkByHref('/admin/config/search/metatag/user'); + $this->assertSession()->linkByHrefExists('/admin/config/search/metatag/global'); + $this->assertSession()->linkByHrefExists('/admin/config/search/metatag/front'); + $this->assertSession()->linkByHrefExists('/admin/config/search/metatag/403'); + $this->assertSession()->linkByHrefExists('/admin/config/search/metatag/404'); + $this->assertSession()->linkByHrefExists('/admin/config/search/metatag/node'); + $this->assertSession()->linkByHrefExists('/admin/config/search/metatag/taxonomy_term'); + $this->assertSession()->linkByHrefExists('/admin/config/search/metatag/user'); } } diff --git a/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsTokenTest.php b/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsTokenTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f500b5e1907c1df4ddb0091bead23870641d4d50 --- /dev/null +++ b/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsTokenTest.php @@ -0,0 +1,126 @@ +<?php + +namespace Drupal\Tests\metatag_views\Functional; + +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\metatag\Functional\MetatagHelperTrait; + +/** + * Confirm the tokenization functionality works. + * + * @group metatag + */ +class MetatagViewsTokenTest extends BrowserTestBase { + + // Contains helper methods. + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + protected static $modules = [ + // Modules for core functionality. + 'block', + 'field', + 'field_ui', + 'help', + 'node', + 'user', + + // Views. Duh. Enable the Views UI so it can be fully tested. + 'views', + 'views_ui', + + // Contrib dependencies. + 'token', + 'metatag', + + // This module. + 'metatag_views', + ]; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'claro'; + + /** + * Confirm the Views tokenization functionality works, including UI. + */ + public function testTokenization() { + $this->loginUser1(); + $page_path = $this->randomMachineName(); + $this->drupalGet('/admin/structure/views/add'); + // @todo Also verify the form loads correctly. + $this->assertSession()->statusCodeEquals(200); + $edit = [ + 'label' => $this->randomString(), + 'id' => 'test', + 'page[create]' => 1, + 'page[path]' => $page_path, + 'page[style][row_plugin]' => 'titles', + ]; + $this->submitForm($edit, 'Save and edit'); + $title_prefix = $this->updateView(TRUE); + $node_title = $this->randomString(); + $this->createContentTypeNode($node_title); + $this->drupalGet("/$page_path"); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->titleEquals("$title_prefix $node_title"); + + // Test caching by asserting a change of the View changes the page as well. + $title_prefix = $this->updateView(); + $this->drupalGet("/$page_path"); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->titleEquals("$title_prefix $node_title"); + + // Reload the page and confirm the values persist. + $this->drupalGet("/$page_path"); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->titleEquals("$title_prefix $node_title"); + } + + /** + * Update the view. + * + * @param bool $assert_ui + * Also assert the Views UI behaves correctly. + * + * @return string + * The title with its full prefix. + */ + protected function updateView(bool $assert_ui = FALSE): string { + $title_prefix = $this->randomMachineName(); + $edit = [ + 'title' => $title_prefix . ' {{ title }}', + 'tokenize' => 1, + ]; + $metatag_settings_path = '/admin/structure/views/nojs/display/test/page_1/metatags'; + $this->drupalGet($metatag_settings_path); + $this->assertSession()->statusCodeEquals(200); + $this->submitForm($edit, 'Apply'); + // @todo Also verify the page contains the correct response. + $this->assertSession()->statusCodeEquals(200); + + // Make sure the UI does not tokenize away {{ title }}. + if ($assert_ui) { + // Reload the form. + $this->drupalGet($metatag_settings_path); + $this->assertSession()->statusCodeEquals(200); + $actual = $this->getSession() + ->getPage() + ->find('css', '#edit-title') + ->getAttribute('value'); + $this->assertSame($edit['title'], $actual); + } + $this->drupalGet('/admin/structure/views/view/test'); + // @todo Also verify the page contains the correct response. + $this->assertSession()->statusCodeEquals(200); + $this->submitForm([], 'Save'); + // @todo Also verify the page contains the correct response. + $this->assertSession()->statusCodeEquals(200); + + return $title_prefix; + } + +} diff --git a/web/modules/metatag/src/Command/GenerateGroupCommand.php b/web/modules/metatag/src/Command/GenerateGroupCommand.php deleted file mode 100644 index ca8cbab07171e98eceeeea152cfe516ebcf15483..0000000000000000000000000000000000000000 --- a/web/modules/metatag/src/Command/GenerateGroupCommand.php +++ /dev/null @@ -1,223 +0,0 @@ -<?php - -namespace Drupal\metatag\Command; - -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; -use Drupal\Console\Core\Command\Shared\CommandTrait; -use Drupal\Console\Command\Shared\ModuleTrait; -use Drupal\Console\Command\Shared\FormTrait; -use Drupal\Console\Command\Shared\ConfirmationTrait; -use Drupal\Console\Core\Style\DrupalStyle; -use Drupal\metatag\Generator\MetatagGroupGenerator; -use Drupal\Console\Extension\Manager; -use Drupal\Console\Core\Utils\ChainQueue; -use Drupal\Console\Core\Command\Command; -use Drupal\Console\Utils\Validator; - -/** - * Class GenerateGroupCommand. - * - * Generate a Metatag group plugin. - * - * @package Drupal\metatag - */ -class GenerateGroupCommand extends Command { - - use ModuleTrait; - use ConfirmationTrait; - - /** - * The metatag group generator. - * - * @var \Drupal\metatag\Generator\MetatagGroupGenerator - */ - protected $generator; - - /** - * The console extension manager. - * - * @var \Drupal\Console\Extension\Manager - */ - protected $extensionManager; - - /** - * The console chain queue. - * - * @var \Drupal\Console\Core\Utils\ChainQueue - */ - protected $chainQueue; - - /** - * @var Validator - */ - protected $validator; - - /** - * The GenerateTagCommand constructor. - * - * @param \Drupal\metatag\Generator\MetatagGroupGenerator $generator - * The generator object. - * @param \Drupal\Console\Extension\Manager $extensionManager - * The extension manager object. - * @param \Drupal\Console\Core\Utils\ChainQueue $chainQueue - * The chain queue object. - * @param Validator $validator - */ - public function __construct( - MetatagGroupGenerator $generator, - Manager $extensionManager, - ChainQueue $chainQueue, - Validator $validator - ) { - $this->generator = $generator; - $this->extensionManager = $extensionManager; - $this->chainQueue = $chainQueue; - $this->validator = $validator; - - parent::__construct(); - } - - /** - * {@inheritdoc} - */ - protected function configure() { - $this - ->setName('generate:plugin:metatag:group') - ->setDescription($this->trans('commands.generate.metatag.group.description')) - ->setHelp($this->trans('commands.generate.metatag.group.help')) - ->addOption( - 'base_class', - null, - InputOption::VALUE_REQUIRED, - $this->trans('commands.common.options.base_class') - ) - ->addOption( - 'module', - null, - InputOption::VALUE_REQUIRED, - $this->trans('commands.common.options.module') - ) - ->addOption( - 'label', - null, - InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.group.options.label') - ) - ->addOption( - 'description', - null, - InputOption::VALUE_OPTIONAL, - $this->trans('commands.generate.metatag.group.options.description') - ) - ->addOption( - 'plugin-id', - null, - InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.group.options.plugin_id') - ) - ->addOption( - 'class-name', - null, - InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.group.options.class_name') - ) - ->addOption( - 'weight', - null, - InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.group.options.weight') - ); - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) { - - $module = $this->validateModule($input->getOption('module')); - $base_class = $input->getOption('base_class'); - $label = $input->getOption('label'); - $description = $input->getOption('description'); - $plugin_id = $input->getOption('plugin-id'); - $class_name = $this->validator->validateClassName($input->getOption('class-name')); - $weight = $input->getOption('weight'); - - $this->generator - ->generate($base_class, $module, $label, $description, $plugin_id, $class_name, $weight); - - $this->chainQueue->addCommand('cache:rebuild', ['cache' => 'discovery']); - } - - /** - * {@inheritdoc} - */ - protected function interact(InputInterface $input, OutputInterface $output) { - // --base_class option. - // @todo Turn this into a choice() option. - $base_class = $input->getOption('base_class'); - if (empty($base_class)) { - $base_class = $this->getIo()->ask( - $this->trans('commands.generate.metatag.group.questions.base_class'), - 'GroupBase' - ); - } - $input->setOption('base_class', $base_class); - - // --module option - $this->getModuleOption(); - - // --label option. - $label = $input->getOption('label'); - if (empty($label)) { - $label = $this->getIo()->ask( - $this->trans('commands.generate.metatag.group.questions.label') - ); - } - $input->setOption('label', $label); - - // --description option. - $description = $input->getOption('description'); - if (empty($description)) { - $description = $this->getIo()->ask( - $this->trans('commands.generate.metatag.group.questions.description') - ); - } - $input->setOption('description', $description); - - // --plugin-id option. - $plugin_id = $input->getOption('plugin-id'); - if (empty($plugin_id)) { - $plugin_id = $this->getIo()->ask( - $this->trans('commands.generate.metatag.group.questions.plugin_id') - ); - } - $input->setOption('plugin-id', $plugin_id); - - // --class-name option. - $class_name = $input->getOption('class-name'); - if (!$class_name) { - $class_name = $this->getIo()->ask( - $this->trans('commands.generate.metatag.group.questions.class_name'), - '', - function ($class_name) { - return $this->validator->validateClassName($class_name); - } - ); - $input->setOption('class-name', $class_name); - } - - // --weight option. - // @todo Automatically get the next int value based upon the current group. - $weight = $input->getOption('weight'); - if (is_null($weight)) { - $weight = $this->getIo()->ask( - $this->trans('commands.generate.metatag.group.questions.weight'), - 0 - ); - } - $input->setOption('weight', $weight); - } - -} diff --git a/web/modules/metatag/src/Command/GenerateTagCommand.php b/web/modules/metatag/src/Command/GenerateTagCommand.php deleted file mode 100644 index 02b1bbaa600e40e58104bd2886b56e5045be665d..0000000000000000000000000000000000000000 --- a/web/modules/metatag/src/Command/GenerateTagCommand.php +++ /dev/null @@ -1,347 +0,0 @@ -<?php - -namespace Drupal\metatag\Command; - -use Drupal\Console\Command\Shared\ConfirmationTrait; -use Drupal\Console\Command\Shared\FormTrait; -use Drupal\Console\Command\Shared\ModuleTrait; -use Drupal\Console\Core\Command\Shared\CommandTrait; -use Drupal\Console\Core\Style\DrupalStyle; -use Drupal\Console\Core\Utils\ChainQueue; -use Drupal\Console\Core\Utils\StringConverter; -use Drupal\Console\Extension\Manager; -use Drupal\metatag\Generator\MetatagTagGenerator; -use Drupal\metatag\MetatagManagerInterface; -use Drupal\Console\Core\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; -use Drupal\Console\Utils\Validator; - -/** - * Class GenerateTagCommand. - * - * Generate a Metatag tag plugin. - * - * @package Drupal\metatag - */ -class GenerateTagCommand extends Command { - - use ModuleTrait; - use FormTrait; - use ConfirmationTrait; - - /** - * The Metatag manager. - * - * @var \Drupal\metatag\MetatagManagerInterface - */ - protected $metatagManager; - - /** - * The Metatag tag generator. - * - * @var \Drupal\metatag\Generator\MetatagTagGenerator - */ - protected $generator; - - /** - * An extension manager. - * - * @var \Drupal\Console\Extension\Manager - */ - protected $extensionManager; - - /** - * The string converter. - * - * @var \Drupal\Console\Core\Utils\StringConverter - */ - protected $stringConverter; - - /** - * The console chain queue. - * - * @var \Drupal\Console\Core\Utils\ChainQueue - */ - protected $chainQueue; - - /** - * @var Validator - */ - protected $validator; - - /** - * The GenerateTagCommand constructor. - * - * @param \Drupal\metatag\MetatagManagerInterface $metatagManager - * The metatag manager object. - * @param \Drupal\metatag\Generator\MetatagTagGenerator $generator - * The tag generator object. - * @param \Drupal\Console\Extension\Manager $extensionManager - * The extension manager object. - * @param \Drupal\Console\Core\Utils\StringConverter $stringConverter - * The string converter object. - * @param \Drupal\Console\Core\Utils\ChainQueue $chainQueue - * The chain queue object. - * @param Validator $validator - */ - public function __construct( - MetatagManagerInterface $metatagManager, - MetatagTagGenerator $generator, - Manager $extensionManager, - StringConverter $stringConverter, - ChainQueue $chainQueue, - Validator $validator - ) { - $this->metatagManager = $metatagManager; - $this->generator = $generator; - $this->extensionManager = $extensionManager; - $this->stringConverter = $stringConverter; - $this->chainQueue = $chainQueue; - $this->validator = $validator; - - parent::__construct(); - } - - /** - * {@inheritdoc} - */ - protected function configure() { - $this - ->setName('generate:plugin:metatag:tag') - ->setDescription($this->trans('commands.generate.metatag.tag.description')) - ->setHelp($this->trans('commands.generate.metatag.tag.help')) - ->addOption('base_class', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.common.options.base_class')) - ->addOption('module', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.common.options.module')) - ->addOption('name', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.name')) - ->addOption('label', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.label')) - ->addOption('description', null, InputOption::VALUE_OPTIONAL, - $this->trans('commands.generate.metatag.tag.options.description')) - ->addOption('plugin-id', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.plugin_id')) - ->addOption('class-name', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.class_name')) - ->addOption('group', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.group')) - ->addOption('weight', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.weight')) - ->addOption('type', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.type')) - ->addOption('secure', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.secure')) - ->addOption('multiple', null, InputOption::VALUE_REQUIRED, - $this->trans('commands.generate.metatag.tag.options.multiple')); - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) { - $base_class = $input->getOption('base_class'); - $module = $this->validateModule($input->getOption('module')); - $name = $input->getOption('name'); - $label = $input->getOption('label'); - $description = $input->getOption('description'); - $plugin_id = $input->getOption('plugin-id'); - $class_name = $this->validator->validateClassName($input->getOption('class-name')); - $group = $input->getOption('group'); - $weight = $input->getOption('weight'); - $type = $input->getOption('type'); - $secure = $input->getOption('secure'); - $multiple = $input->getOption('multiple'); - - $this->generator - ->generate($base_class, $module, $name, $label, $description, $plugin_id, $class_name, $group, $weight, $type, $secure, $multiple); - - $this->chainQueue->addCommand('cache:rebuild', ['cache' => 'discovery']); - } - - /** - * {@inheritdoc} - */ - protected function interact(InputInterface $input, OutputInterface $output) { - - $boolean_options = [ - 'FALSE', - 'TRUE', - ]; - - // @todo Take this from typed data, so it can be extended? - $type_options = [ - 'integer', - 'string', - 'label', - 'uri', - 'image', - ]; - - // --base_class option. - // @todo Turn this into a choice() option. - $base_class = $input->getOption('base_class'); - if (empty($base_class)) { - $base_class = $this->getIo()->ask( - $this->trans('commands.generate.metatag.tag.questions.base_class'), - 'MetaNameBase' - ); - } - $input->setOption('base_class', $base_class); - - // --module option. - $this->getModuleOption(); - - // --name option. - // @todo Add validation. - $name = $input->getOption('name'); - if (empty($name)) { - $name = $this->getIo()->ask( - $this->trans('commands.generate.metatag.tag.questions.name') - ); - } - $input->setOption('name', $name); - - // --label option. - $label = $input->getOption('label'); - if (empty($label)) { - $label = $this->getIo()->ask( - $this->trans('commands.generate.metatag.tag.questions.label'), - $name - ); - } - $input->setOption('label', $label); - - // --description option. - $description = $input->getOption('description'); - if (empty($description)) { - $description = $this->getIo()->ask( - $this->trans('commands.generate.metatag.tag.questions.description') - ); - } - $input->setOption('description', $description); - - // --plugin-id option. - $plugin_id = $input->getOption('plugin-id'); - if (empty($plugin_id)) { - $plugin_id = $this->nameToPluginId($name); - $plugin_id = $this->getIo()->ask( - $this->trans('commands.generate.metatag.tag.questions.plugin_id'), - $plugin_id - ); - } - $input->setOption('plugin-id', $plugin_id); - - // --class-name option. - $class_name = $input->getOption('class-name'); - if (!$class_name) { - $class_name = $this->getIo()->ask( - $this->trans('commands.generate.metatag.tag.questions.class_name'), - $this->nameToClassName($name), - function ($class_name) { - return $this->validator->validateClassName($class_name); - } - ); - $input->setOption('class-name', $class_name); - } - - - // --group option. - $group = $input->getOption('group'); - if (empty($group)) { - $groups = $this->getGroups(); - $group = $this->getIo()->choice( - $this->trans('commands.generate.metatag.tag.questions.group'), - $groups - ); - } - $input->setOption('group', $group); - - // --weight option. - // @todo Automatically get the next int value based upon the current group. - $weight = $input->getOption('weight'); - if (is_null($weight)) { - $weight = $this->getIo()->ask( - $this->trans('commands.generate.metatag.tag.questions.weight'), - 0 - ); - } - $input->setOption('weight', $weight); - - // --type option. - // @todo Turn this into an option. - $type = $input->getOption('type'); - if (is_null($type)) { - $type = $this->getIo()->choice( - $this->trans('commands.generate.metatag.tag.questions.type'), - $type_options, - 0 - ); - } - $input->setOption('type', $type); - - // --secure option. - // @todo Turn this into an option. - $secure = $input->getOption('secure'); - if (is_null($secure)) { - $secure = $this->getIo()->choice( - $this->trans('commands.generate.metatag.tag.questions.secure'), - $boolean_options, - 0 - ); - } - $input->setOption('secure', $secure); - - // --multiple option. - $multiple = $input->getOption('multiple'); - if (is_null($multiple)) { - $multiple = $this->getIo()->choice( - $this->trans('commands.generate.metatag.tag.questions.multiple'), - $boolean_options, - 0 - ); - } - $input->setOption('multiple', $multiple); - } - - /** - * Convert the meta tag's name to a plugin ID. - * - * @param string $name - * The meta tag name to convert. - * - * @return string - * The original string with all non-alphanumeric characters converted to - * underline chars. - */ - private function nameToPluginId($name) { - return $this->stringConverter->createMachineName($name); - } - - /** - * Convert the meta tag's name to a class name. - * - * @param string $name - * The meta tag name to convert. - * - * @return string - * The original string with all non-alphanumeric characters removed and - * converted to CamelCase. - */ - private function nameToClassName($name) { - return $this->stringConverter->humanToCamelCase($name); - } - - /** - * All of the meta tag groups. - * - * @return array - * A list of the available groups. - */ - private function getGroups() { - return array_keys($this->metatagManager->sortedGroups()); - } - -} diff --git a/web/modules/metatag/src/Controller/MetatagController.php b/web/modules/metatag/src/Controller/MetatagController.php index 897697330d5cc24e091bd0c965f47eb5198150a1..b3cc732e36d5c890958d3ef1c361a926188f79d2 100644 --- a/web/modules/metatag/src/Controller/MetatagController.php +++ b/web/modules/metatag/src/Controller/MetatagController.php @@ -61,7 +61,10 @@ public static function create(ContainerInterface $container) { public function reportPlugins() { // Get tags. $tag_definitions = $this->tagManager->getDefinitions(); - uasort($tag_definitions, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']); + uasort($tag_definitions, [ + 'Drupal\Component\Utility\SortArray', + 'sortByWeightElement', + ]); $tags = []; foreach ($tag_definitions as $tag_name => $tag_definition) { $tags[$tag_definition['group']][$tag_name] = $tag_definition; @@ -69,7 +72,10 @@ public function reportPlugins() { // Get groups. $group_definitions = $this->groupManager->getDefinitions(); - uasort($group_definitions, ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']); + uasort($group_definitions, [ + 'Drupal\Component\Utility\SortArray', + 'sortByWeightElement', + ]); // Build plugin by group. $build = []; @@ -83,7 +89,7 @@ public function reportPlugins() { ]; // Group description. $build[$group_name]['description'] = [ - '#markup' => $group_definition['description'], + '#markup' => $group_definition['description'] ?? '', '#prefix' => '<p>', '#suffix' => '</p>', ]; @@ -115,7 +121,7 @@ public function reportPlugins() { $row = []; $row['description'] = [ 'data' => [ - '#markup' => $definition['description'], + '#markup' => $definition['description'] ?? '', ], 'colspan' => 8, ]; diff --git a/web/modules/metatag/src/Entity/MetatagDefaults.php b/web/modules/metatag/src/Entity/MetatagDefaults.php index d6fba8a6552dc52bf6381c83641dc3d42eb28b25..30517b1d923d38ce057eff8c39adf04cdd80fea6 100644 --- a/web/modules/metatag/src/Entity/MetatagDefaults.php +++ b/web/modules/metatag/src/Entity/MetatagDefaults.php @@ -99,7 +99,7 @@ public function getTag($tag_id) { * Reverts an entity to its default values. */ public function revert() { - $default_install_path = drupal_get_path('module', 'metatag') . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY; + $default_install_path = \Drupal::service('extension.list.module')->getPath('metatag') . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY; $storage = new FileStorage($default_install_path, StorageInterface::DEFAULT_COLLECTION); $default_config_data = $storage->read('metatag.metatag_defaults.' . $this->id()); if ($default_config_data) { diff --git a/web/modules/metatag/src/Form/MetatagDefaultsForm.php b/web/modules/metatag/src/Form/MetatagDefaultsForm.php index 98212411d760972dc7eb254d8a439063a823a941..aeebb3ad96b339d90dc1c3bfd604c64d39d01664 100644 --- a/web/modules/metatag/src/Form/MetatagDefaultsForm.php +++ b/web/modules/metatag/src/Form/MetatagDefaultsForm.php @@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\metatag\MetatagDefaultsInterface; use Drupal\metatag\MetatagManager; use Drupal\metatag\MetatagManagerInterface; use Drupal\metatag\MetatagTagPluginManager; @@ -16,7 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Class MetatagDefaultsForm. + * Form handler for the Metatag Defaults entity type. * * @package Drupal\metatag\Form */ @@ -108,7 +109,7 @@ public function form(array $form, FormStateInterface $form_state) { $form['#suffix'] = '</div>'; $default_type = NULL; - if (!empty($metatag_defaults)) { + if ($metatag_defaults) { $default_type = $metatag_defaults->getOriginalId(); } else { @@ -156,16 +157,17 @@ public function form(array $form, FormStateInterface $form_state) { $entity_type_groups = $settings->get('entity_type_groups'); // Find the current entity type and bundle. + $entity_bundle = NULL; $metatag_defaults_id = $metatag_defaults->id(); - $type_parts = explode('__', $metatag_defaults_id); - $entity_type = $type_parts[0]; - $entity_bundle = isset($type_parts[1]) ? $type_parts[1] : NULL; + if (!empty($metatag_defaults_id)) { + $type_parts = explode('__', $metatag_defaults_id); + $entity_type = $type_parts[0]; + $entity_bundle = $type_parts[1] ?? NULL; + } // See if there are requested groups for this entity type and bundle. - $groups = !empty($entity_type_groups[$entity_type]) && !empty($entity_type_groups[$entity_type][$entity_bundle]) ? $entity_type_groups[$entity_type][$entity_bundle] : []; - // Limit the form to requested groups, if any. - if (!empty($groups)) { - $form = $this->metatagManager->form($values, $form, [$entity_type], $groups, NULL, TRUE); + if (isset($entity_type) && !empty($entity_type_groups[$entity_type]) && !empty($entity_type_groups[$entity_type][$entity_bundle])) { + $form = $this->metatagManager->form($values, $form, [$entity_type], $entity_type_groups[$entity_type][$entity_bundle], NULL, TRUE); } // Otherwise, display all groups. else { @@ -239,7 +241,7 @@ public function save(array $form, FormStateInterface $form_state) { $type_parts = explode('__', $metatag_defaults_id); $entity_type = $type_parts[0]; - $entity_bundle = isset($type_parts[1]) ? $type_parts[1] : NULL; + $entity_bundle = $type_parts[1] ?? NULL; // Get the entity label. $entity_info = $this->entityTypeManager->getDefinitions(); @@ -282,7 +284,12 @@ public function save(array $form, FormStateInterface $form_state) { } } } + + // Sort the values prior to saving. so that they are easier to manage. + ksort($tag_values); + $metatag_defaults->set('tags', $tag_values); + /** @var int $status */ $status = $metatag_defaults->save(); switch ($status) { @@ -299,6 +306,8 @@ public function save(array $form, FormStateInterface $form_state) { } $form_state->setRedirectUrl($metatag_defaults->toUrl('collection')); + + return $status; } /** @@ -396,4 +405,19 @@ public static function getEntityTypeLabel(EntityTypeInterface $entityType) { return $label; } + /** + * Route title callback. + * + * @param \Drupal\metatag\MetatagDefaultsInterface $metatag_defaults + * Metatags default entity. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup + * Translated route title. + */ + public function getTitle(MetatagDefaultsInterface $metatag_defaults) { + return $this->t('Edit default meta tags for @path', [ + '@path' => $metatag_defaults->label(), + ]); + } + } diff --git a/web/modules/metatag/src/Form/MetatagDefaultsRevertForm.php b/web/modules/metatag/src/Form/MetatagDefaultsRevertForm.php index 01e930bb06a1cd6234ec9fdee1dd11e29a5db1cd..1596d526a4f93730ee37fd3740a6448d963cd328 100644 --- a/web/modules/metatag/src/Form/MetatagDefaultsRevertForm.php +++ b/web/modules/metatag/src/Form/MetatagDefaultsRevertForm.php @@ -36,6 +36,7 @@ public function getConfirmText() { * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { + /** @var \Drupal\metatag\Entity\MetatagDefaults $this->entity */ $this->entity->revert(); $this->messenger()->addMessage( diff --git a/web/modules/metatag/src/Form/MetatagSettingsForm.php b/web/modules/metatag/src/Form/MetatagSettingsForm.php index ee8335cd77fd1cf51ac304ca33ac412d01f0ef90..1f61f879662c8b2433e9261bed0c80c84c1b60f9 100644 --- a/web/modules/metatag/src/Form/MetatagSettingsForm.php +++ b/web/modules/metatag/src/Form/MetatagSettingsForm.php @@ -2,10 +2,8 @@ namespace Drupal\metatag\Form; -use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\metatag\MetatagManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -34,6 +32,13 @@ class MetatagSettingsForm extends ConfigFormBase { */ protected $state; + /** + * The tag plugin manager. + * + * @var \Drupal\metatag\MetatagTagPluginManager + */ + protected $tagPluginManager; + /** * {@inheritdoc} */ @@ -45,6 +50,7 @@ public static function create(ContainerInterface $container) { $instance->entityTypeBundleInfo = $container->get('entity_type.bundle.info'); $instance->metatagManager = $container->get('metatag.manager'); $instance->state = $container->get('state'); + $instance->tagPluginManager = $container->get('plugin.manager.metatag.tag'); return $instance; } @@ -70,8 +76,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { if ($this->state->get('system.maintenance_mode')) { $this->messenger()->addMessage($this->t('Please note that while the site is in maintenance mode none of the usual meta tags will be output.')); } - $settings = $this->config('metatag.settings')->get('entity_type_groups'); - + $entitySettings = $this->config('metatag.settings')->get('entity_type_groups'); $form['entity_type_groups'] = [ '#type' => 'details', '#open' => TRUE, @@ -98,11 +103,74 @@ public function buildForm(array $form, FormStateInterface $form_state) { $form['entity_type_groups'][$entity_type][$bundle_id][] = [ '#type' => 'checkboxes', '#options' => $options, - '#default_value' => isset($settings[$entity_type]) && isset($settings[$entity_type][$bundle_id]) ? $settings[$entity_type][$bundle_id] : [], + '#default_value' => isset($entitySettings[$entity_type]) && isset($entitySettings[$entity_type][$bundle_id]) ? $entitySettings[$entity_type][$bundle_id] : [], + ]; + } + } + + $trimSettingsMaxlength = $this->config('metatag.settings')->get('tag_trim_maxlength'); + $trimMethod = $this->config('metatag.settings')->get('tag_trim_method'); + $metatags = $this->tagPluginManager->getDefinitions(); + + $form['tag_trim'] = [ + '#title' => $this->t('Metatag Trimming Options'), + '#type' => 'details', + '#tree' => TRUE, + '#open' => TRUE, + '#description' => $this->t("Many Meta-Tags can be trimmed on a specific length for search engine optimization.<br/>If the value is set to '0' or left empty, the whole Metatag will be untrimmed."), + ]; + + $form['tag_trim']['maxlength'] = [ + '#title' => $this->t('Tags'), + '#type' => 'fieldset', + '#tree' => TRUE, + ]; + + // Name the variable "metatag_id" to avoid confusing this with the "name" + // value from the meta tag plugin as it's actually the plugin ID. + foreach ($metatags as $metatag_id => $metatag_info) { + if (!empty($metatag_info['trimmable'])) { + + $form['tag_trim']['maxlength']['metatag_maxlength_' . $metatag_id] = [ + '#title' => $this->t('Meta Tags:') . ' ' . $metatag_id . ' ' . $this->t('length'), + '#type' => 'number', + '#required' => FALSE, + '#default_value' => $trimSettingsMaxlength['metatag_maxlength_' . $metatag_id] ?? NULL, + '#min' => 0, + '#step' => 1, ]; } } + $form['tag_trim']['tag_trim_method'] = [ + '#title' => $this->t('Meta Tags: Trimming Options'), + '#type' => 'select', + '#required' => TRUE, + '#default_value' => $trimMethod ?? 'beforeValue', + '#options' => [ + 'afterValue' => $this->t('Trim the Meta Tag after the word on the given value'), + 'onValue' => $this->t('Trim the Meta Tag on the given value'), + 'beforeValue' => $this->t('Trim the Meta Tag before the word on the given value'), + ], + ]; + + $scrollheight = $this->config('metatag.settings')->get('tag_scroll_max_height'); + + $form['firehose_widget'] = [ + '#title' => $this->t('Metatag widget options'), + '#type' => 'details', + '#tree' => TRUE, + '#open' => TRUE, + '#description' => $this->t("Various options for the field widget used on entity forms, e.g. on content type forms."), + ]; + + $form['firehose_widget']['tag_scroll_max_height'] = [ + '#title' => $this->t('Scroll maximum height'), + '#type' => 'textfield', + '#default_value' => $scrollheight, + '#placeholder' => $this->t('eg 500px or 8rem'), + '#description' => $this->t("To enable scrolling please enter a value and its units, e.g. 500px, 8rem, etc. Removing this value will remove the scroll."), + ]; return parent::buildForm($form, $form_state); } @@ -111,15 +179,27 @@ public function buildForm(array $form, FormStateInterface $form_state) { */ public function submitForm(array &$form, FormStateInterface $form_state) { $settings = $this->config('metatag.settings'); - $value = $form_state->getValue('entity_type_groups'); - $value = static::arrayFilterRecursive($value); + // entity_type_groups handling: + $entityTypeGroupsValues = $form_state->getValue('entity_type_groups'); + $entityTypeGroupsValues = static::arrayFilterRecursive($entityTypeGroupsValues); // Remove the extra layer created by collapsible fieldsets. - foreach ($value as $entity_type => $bundle) { + foreach ($entityTypeGroupsValues as $entity_type => $bundle) { foreach ($bundle as $bundle_id => $groups) { - $value[$entity_type][$bundle_id] = $groups[0]; + $entityTypeGroupsValues[$entity_type][$bundle_id] = $groups[0]; } } - $settings->set('entity_type_groups', $value); + $settings->set('entity_type_groups', $entityTypeGroupsValues); + + // tag_trim handling: + $trimmingMethod = $form_state->getValue(['tag_trim', 'tag_trim_method']); + $settings->set('tag_trim_method', $trimmingMethod); + $trimmingValues = $form_state->getValue(['tag_trim', 'maxlength']); + $settings->set('tag_trim_maxlength', $trimmingValues); + + // Widget settings. + $scrollheightvalue = $form_state->getValue(['firehose_widget', 'tag_scroll_max_height']); + $settings->set('tag_scroll_max_height', $scrollheightvalue); + $settings->save(); parent::submitForm($form, $form_state); } diff --git a/web/modules/metatag/src/Generator/MetatagGroupGenerator.php b/web/modules/metatag/src/Generator/MetatagGroupGenerator.php deleted file mode 100644 index 9b737e30239f5c3747ba1ec7de89f22455e06682..0000000000000000000000000000000000000000 --- a/web/modules/metatag/src/Generator/MetatagGroupGenerator.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php - -namespace Drupal\metatag\Generator; - -use Drupal\Console\Core\Generator\Generator; -use Drupal\Console\Extension\Manager; -use Drupal\Console\Core\Utils\TwigRenderer; - -/** - * Drupal Console plugin for generating a group. - */ -class MetatagGroupGenerator extends Generator { - - /** - * The console manager. - * - * @var \Drupal\Console\Extension\Manager - */ - protected $extensionManager; - - /** - * The twig renderer. - * - * @var \Drupal\Console\Core\Utils\TwigRenderer - */ - protected $renderer; - - /** - * MetatagGroupGenerator constructor. - * - * @param \Drupal\Console\Extension\Manager $extensionManager - * An extension manager. - * @param \Drupal\Console\Core\Utils\TwigRenderer $renderer - * Twig renderer. - */ - public function __construct(Manager $extensionManager, TwigRenderer $renderer) { - $this->extensionManager = $extensionManager; - - $renderer->addSkeletonDir(__DIR__ . '/../../templates/'); - $this->setRenderer($renderer); - } - - /** - * Generator plugin. - * - * @param string $base_class - * Base class. - * @param string $module - * Module name. - * @param string $label - * Group label. - * @param string $description - * Group description. - * @param string $plugin_id - * Plugin ID. - * @param string $class_name - * Class name. - * @param string $weight - * Group weight. - */ - public function generate($base_class, $module, $label, $description, $plugin_id, $class_name, $weight) { - $parameters = [ - 'base_class' => $base_class, - 'module' => $module, - 'label' => $label, - 'description' => $description, - 'plugin_id' => $plugin_id, - 'class_name' => $class_name, - 'weight' => $weight, - 'prefix' => '<' . '?php', - ]; - - $this->renderFile( - 'group.php.twig', - $this->extensionManager->getPluginPath($module, 'metatag/Group') . '/' . $class_name . '.php', - $parameters - ); - } - -} diff --git a/web/modules/metatag/src/Generator/MetatagTagGenerator.php b/web/modules/metatag/src/Generator/MetatagTagGenerator.php deleted file mode 100644 index ba089b64a285b5898a1f6c6b2b53d5002a5d7a79..0000000000000000000000000000000000000000 --- a/web/modules/metatag/src/Generator/MetatagTagGenerator.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -namespace Drupal\metatag\Generator; - -use Drupal\Console\Core\Generator\Generator; -use Drupal\Console\Extension\Manager; -use Drupal\Console\Core\Utils\TwigRenderer; - -/** - * Drupal Console plugin for generating a tag. - */ -class MetatagTagGenerator extends Generator { - - /** - * An extension manager. - * - * @var \Drupal\Console\Extension\Manager - */ - protected $extensionManager; - - /** - * The twig renderer. - * - * @var \Drupal\Console\Core\Utils\TwigRenderer - */ - protected $render; - - /** - * MetatagTagGenerator constructor. - * - * @param \Drupal\Console\Extension\Manager $extensionManager - * An extension manager. - * @param \Drupal\Console\Core\Utils\TwigRenderer $render - * Twig renderer. - */ - public function __construct(Manager $extensionManager, TwigRenderer $render) { - $this->extensionManager = $extensionManager; - - $render->addSkeletonDir(__DIR__ . '/../../templates/'); - $this->setRenderer($render); - } - - /** - * Generator plugin. - * - * @param string $base_class - * Base class. - * @param string $module - * Module name. - * @param string $name - * Tag name. - * @param string $label - * Tag label. - * @param string $description - * Tag description. - * @param string $plugin_id - * Plugin ID. - * @param string $class_name - * Class name. - * @param string $group - * Tag group. - * @param string $weight - * Tag weight. - * @param string $type - * Tag type. - * @param bool $secure - * Is secure. - * @param bool $multiple - * Is multiple. - */ - public function generate($base_class, $module, $name, $label, $description, $plugin_id, $class_name, $group, $weight, $type, $secure, $multiple) { - $parameters = [ - 'base_class' => $base_class, - 'module' => $module, - 'name' => $name, - 'label' => $label, - 'description' => $description, - 'plugin_id' => $plugin_id, - 'class_name' => $class_name, - 'group' => $group, - 'weight' => $weight, - 'type' => $type, - 'secure' => $secure, - 'multiple' => $multiple, - 'prefix' => '<' . '?php', - ]; - - $this->renderFile( - 'tag.php.twig', - $this->extensionManager->getPluginPath($module, 'metatag/Tag') . '/' . $class_name . '.php', - $parameters - ); - - $this->renderFile( - 'metatag_tag.schema.yml.twig', - $this->extensionManager->getModule($module)->getPath() . '/config/schema/' . $module . '.metatag_tag.schema.yml', - $parameters, - FILE_APPEND - ); - } - -} diff --git a/web/modules/metatag/src/MetatagDefaultsListBuilder.php b/web/modules/metatag/src/MetatagDefaultsListBuilder.php index 2fcbb069fa43b4d09b6d80e759bab1fccbafd6ff..dd154a188874147068000848170c44e9a95801cd 100644 --- a/web/modules/metatag/src/MetatagDefaultsListBuilder.php +++ b/web/modules/metatag/src/MetatagDefaultsListBuilder.php @@ -28,7 +28,16 @@ protected function getEntityIds() { $entity_ids = $query->execute(); // Load global entity always. - return $entity_ids + $this->getParentIds($entity_ids); + $parents = $this->getParentIds($entity_ids); + if (!empty($parents)) { + if (empty($entity_ids)) { + $entity_ids = $parents; + } + else { + $entity_ids = array_merge($entity_ids, $parents); + } + } + return $entity_ids; } /** @@ -67,6 +76,7 @@ public function buildHeader() { * {@inheritdoc} */ public function buildRow(EntityInterface $entity) { + /** @var \Drupal\metatag\Entity\MetatagDefaults $entity */ $row['label'] = $this->getLabelAndConfig($entity); $row['status'] = $entity->status() ? $this->t('Active') : $this->t('Disabled'); return $row + parent::buildRow($entity); @@ -101,6 +111,7 @@ public function getOperations(EntityInterface $entity) { * Render array for a table cell. */ public function getLabelAndConfig(EntityInterface $entity) { + /** @var \Drupal\metatag\Entity\MetatagDefaults $entity */ $output = '<div>'; $prefix = ''; $inherits = ''; @@ -124,12 +135,15 @@ public function getLabelAndConfig(EntityInterface $entity) { $output .= '<table> <tbody>'; foreach ($tags as $tag_id => $tag_value) { + if (is_array($tag_value)) { + $tag_value = implode(', ', array_filter($tag_value)); + } $output .= '<tr><td>' . $tag_id . ':</td><td>' . $tag_value . '</td></tr>'; } $output .= '</tbody></table>'; } - $output .= '</div></div>'; + $output .= '</div>'; return [ 'data' => [ diff --git a/web/modules/metatag/src/MetatagManager.php b/web/modules/metatag/src/MetatagManager.php index 18cac1947f29c1aa15094c2e914a6258a2da2d05..775f49fc366a6efe1905bd6e53613e2149e00fda 100644 --- a/web/modules/metatag/src/MetatagManager.php +++ b/web/modules/metatag/src/MetatagManager.php @@ -10,9 +10,13 @@ use Drupal\Core\Render\BubbleableMetadata; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\views\ViewEntityInterface; +use Drupal\Core\Path\PathMatcherInterface; +use Drupal\Core\Routing\RouteMatchInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Drupal\Core\Language\LanguageManagerInterface; /** - * Class MetatagManager. + * Primary logic for the Metatag module. * * @package Drupal\metatag */ @@ -37,7 +41,7 @@ class MetatagManager implements MetatagManagerInterface { /** * The Metatag defaults. * - * @var array + * @var \Drupal\metatag\Entity\MetatagDefaults */ protected $metatagDefaults; @@ -55,6 +59,34 @@ class MetatagManager implements MetatagManagerInterface { */ protected $logger; + /** + * The path matcher. + * + * @var \Drupal\Core\Path\PathMatcherInterface + */ + protected $pathMatcher; + + /** + * The route match. + * + * @var \Drupal\Core\Routing\RouteMatchInterface + */ + protected $routeMatch; + + /** + * The request stack. + * + * @var \Symfony\Component\HttpFoundation\RequestStack + */ + protected $requestStack; + + /** + * The language manager. + * + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + /** * Caches processed strings, keyed by tag name. * @@ -68,32 +100,48 @@ class MetatagManager implements MetatagManagerInterface { * @param \Drupal\metatag\MetatagGroupPluginManager $groupPluginManager * The MetatagGroupPluginManager object. * @param \Drupal\metatag\MetatagTagPluginManager $tagPluginManager - * The MetatagTagPluginMπanager object. + * The MetatagTagPluginManager object. * @param \Drupal\metatag\MetatagToken $token * The MetatagToken object. * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $channelFactory * The LoggerChannelFactoryInterface object. * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager * The EntityTypeManagerInterface object. + * @param \Drupal\Core\Path\PathMatcherInterface $pathMatcher + * The path matcher. + * @param \Drupal\Core\Routing\RouteMatchInterface $routeMatch + * The route match. + * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack + * The request stack. + * @param \Drupal\Core\Language\LanguageManagerInterface $languageManager + * The language manager. */ public function __construct(MetatagGroupPluginManager $groupPluginManager, MetatagTagPluginManager $tagPluginManager, MetatagToken $token, LoggerChannelFactoryInterface $channelFactory, - EntityTypeManagerInterface $entityTypeManager + EntityTypeManagerInterface $entityTypeManager, + PathMatcherInterface $pathMatcher, + RouteMatchInterface $routeMatch, + RequestStack $requestStack, + LanguageManagerInterface $languageManager ) { $this->groupPluginManager = $groupPluginManager; $this->tagPluginManager = $tagPluginManager; $this->tokenService = $token; $this->logger = $channelFactory->get('metatag'); $this->metatagDefaults = $entityTypeManager->getStorage('metatag_defaults'); + $this->pathMatcher = $pathMatcher; + $this->routeMatch = $routeMatch; + $this->requestStack = $requestStack; + $this->languageManager = $languageManager; } /** * Returns the list of protected defaults. * * @return array - * Th protected defaults. + * The protected defaults. */ public static function protectedDefaults() { return [ @@ -115,7 +163,7 @@ public function tagsFromEntity(ContentEntityInterface $entity) { $fields = $this->getFields($entity); - /* @var \Drupal\field\Entity\FieldConfig $field_info */ + /** @var \Drupal\field\Entity\FieldConfig $field_info */ foreach ($fields as $field_name => $field_info) { // Get the tags from this field. $tags = $this->getFieldTags($entity, $field_name); @@ -186,7 +234,7 @@ public function sortedGroups() { foreach ($metatag_groups as $group_name => $group_info) { $groups[$group_name]['id'] = $group_info['id']; $groups[$group_name]['label'] = $group_info['label']->render(); - $groups[$group_name]['description'] = $group_info['description']; + $groups[$group_name]['description'] = $group_info['description'] ?? ''; $groups[$group_name]['weight'] = $group_info['weight']; } @@ -243,7 +291,10 @@ public function sortedGroupsWithTags() { if (!isset($groups[$tag_group])) { // If the tag is claiming a group that has no matching plugin, log an // error and force it to the basic group. - $this->logger->error("Undefined group '%group' on tag '%tag'", ['%group' => $tag_group, '%tag' => $tag_name]); + $this->logger->error("Undefined group '%group' on tag '%tag'", [ + '%group' => $tag_group, + '%tag' => $tag_name, + ]); $tag['group'] = 'basic'; $tag_group = 'basic'; } @@ -280,7 +331,7 @@ public function form(array $values, array $element, array $token_types = [], arr // Create the fieldset. $element[$group_name]['#type'] = 'details'; $element[$group_name]['#title'] = $group['label']; - $element[$group_name]['#description'] = $group['description']; + $element[$group_name]['#description'] = $group['description'] ?? ''; $element[$group_name]['#open'] = FALSE; foreach ($group['tags'] as $tag_name => $tag) { @@ -290,7 +341,7 @@ public function form(array $values, array $element, array $token_types = [], arr $tag = $this->tagPluginManager->createInstance($tag_name); // Set the value to the stored value, if any. - $tag_value = isset($values[$tag_name]) ? $values[$tag_name] : NULL; + $tag_value = $values[$tag_name] ?? NULL; $tag->setValue($tag_value); // Open any groups that have non-empty values. @@ -333,7 +384,7 @@ protected function getFields(ContentEntityInterface $entity) { $field_type = $definition->getType(); // Check the field type against our list of fields. - if (isset($field_type) && in_array($field_type, $field_types)) { + if (!empty($field_type) && in_array($field_type, $field_types)) { $field_list[$field_name] = $definition; } } @@ -359,7 +410,18 @@ protected function getFieldTags(ContentEntityInterface $entity, $field_name) { // Get serialized value and break it into an array of tags with values. $serialized_value = $item->get('value')->getValue(); if (!empty($serialized_value)) { - $tags += unserialize($serialized_value); + $new_tags = unserialize($serialized_value); + if (!empty($new_tags)) { + if (is_array($new_tags)) { + $tags += $new_tags; + } + else { + $this->logger->error("This was expected to be an array but it is not: \n%value", ['%value' => print_r($new_tags, TRUE)]); + } + } + else { + $this->logger->error("This could not be unserialized: \n%value", ['%value' => print_r($serialized_value, TRUE)]); + } } } @@ -380,7 +442,7 @@ public function getDefaultMetatags(ContentEntityInterface $entity = NULL) { $metatags = $this->getGlobalMetatags(); // If that is empty something went wrong. if (!$metatags) { - return; + return []; } // Check if this is a special page. @@ -430,13 +492,13 @@ public function getGlobalMetatags() { public function getSpecialMetatags() { $metatags = NULL; - if (\Drupal::service('path.matcher')->isFrontPage()) { + if ($this->pathMatcher->isFrontPage()) { $metatags = $this->metatagDefaults->load('front'); } - elseif (\Drupal::service('current_route_match')->getRouteName() == 'system.403') { + elseif ($this->routeMatch->getRouteName() == 'system.403') { $metatags = $this->metatagDefaults->load('403'); } - elseif (\Drupal::service('current_route_match')->getRouteName() == 'system.404') { + elseif ($this->routeMatch->getRouteName() == 'system.404') { $metatags = $this->metatagDefaults->load('404'); } @@ -478,15 +540,7 @@ public function getEntityDefaultMetatags(ContentEntityInterface $entity) { } /** - * Generate the elements that go in the hook_page_attachments attached array. - * - * @param array $tags - * The array of tags as plugin_id => value. - * @param object $entity - * Optional entity object to use for token replacements. - * - * @return array - * Render array with tag elements. + * {@inheritdoc} */ public function generateElements(array $tags, $entity = NULL) { $elements = []; @@ -505,21 +559,11 @@ public function generateElements(array $tags, $entity = NULL) { } /** - * Generate the actual meta tag values. - * - * @param array $tags - * The array of tags as plugin_id => value. - * @param object $entity - * Optional entity object to use for token replacements. - * @param \Drupal\Core\Render\BubbleableMetadata|null $cache - * (optional) Cacheability metadata. - * - * @return array - * Render array with tag elements. + * {@inheritdoc} */ public function generateRawElements(array $tags, $entity = NULL, BubbleableMetadata $cache = NULL) { // Ignore the update.php path. - $request = \Drupal::request(); + $request = $this->requestStack->getCurrentRequest(); if ($request->getBaseUrl() == '/update.php') { return []; } @@ -527,6 +571,7 @@ public function generateRawElements(array $tags, $entity = NULL, BubbleableMetad // Prepare any tokens that might exist. $token_replacements = []; if ($entity) { + // @todo This needs a better way of discovering the context. if ($entity instanceof ViewEntityInterface) { // Views tokens require the ViewExecutable, not the config entity. @@ -537,16 +582,15 @@ public function generateRawElements(array $tags, $entity = NULL, BubbleableMetad $token_replacements = [$entity->getEntityTypeId() => $entity]; } } - - // Ge the current language code. - $langcode = \Drupal::languageManager() - ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT) - ->getId(); - $rawTags = []; - $metatag_tags = $this->tagPluginManager->getDefinitions(); + // Use the entity's language code, if one is defined. + $langcode = NULL; + if ($entity) { + $langcode = $entity->language()->getId(); + } + // Order metatags based on the group and weight. $group = array_column($metatag_tags, 'group'); $weight = array_column($metatag_tags, 'weight'); @@ -567,14 +611,8 @@ public function generateRawElements(array $tags, $entity = NULL, BubbleableMetad // Get an instance of the plugin. $tag = $this->tagPluginManager->createInstance($tag_name); - // Set the value as sometimes the data needs massaging, such as when - // field defaults are used for the Robots field, which come as an array - // that needs to be filtered and converted to a string. - // @see Robots::setValue() - $tag->setValue($value); - - // Obtain the processed value. - $processed_value = htmlspecialchars_decode($this->tokenService->replace($tag->value(), $token_replacements, ['langcode' => $langcode], $cache)); + // Prepare value. + $processed_value = $this->processTagValue($tag, $value, $token_replacements, FALSE, $langcode); // Now store the value with processed tokens back into the plugin. $tag->setValue($processed_value); @@ -615,14 +653,21 @@ public function generateRawElements(array $tags, $entity = NULL, BubbleableMetad */ public function generateTokenValues(array $tags, $entity = NULL) { // Ignore the update.php path. - $request = \Drupal::request(); + $request = $this->requestStack->getCurrentRequest(); if ($request->getBaseUrl() == '/update.php') { return []; } $entity_identifier = '_none'; if ($entity) { - $entity_identifier = $entity->getEntityTypeId() . ':' . ($entity->uuid() ?: $entity->id()); + $entity_identifier = $entity->getEntityTypeId() . ':' . ($entity->uuid() ?? $entity->id()) . ':' . $entity->language() + ->getId(); + } + + // Use the entity's language code, if one is defined. + $langcode = NULL; + if ($entity) { + $langcode = $entity->language()->getId(); } if (!isset($this->processedTokenCache[$entity_identifier])) { @@ -649,15 +694,8 @@ public function generateTokenValues(array $tags, $entity = NULL) { $token_replacements = [$entity->getEntityTypeId() => $entity]; } } - - // Set the value as sometimes the data needs massaging, such as when - // field defaults are used for the Robots field, which come as an - // array that needs to be filtered and converted to a string. - // @see Robots::setValue() - $tag->setValue($value); - $langcode = \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(); - $value = PlainTextOutput::renderFromHtml(htmlspecialchars_decode($this->tokenService->replace($value, $token_replacements, ['langcode' => $langcode]))); - $this->processedTokenCache[$entity_identifier][$tag_name] = $tag->multiple() ? explode(',', $value) : $value; + $processed_value = $this->processTagValue($tag, $value, $token_replacements, TRUE); + $this->processedTokenCache[$entity_identifier][$tag_name] = $tag->multiple() ? explode(',', $processed_value) : $processed_value; } } } @@ -677,4 +715,71 @@ protected function fieldTypes() { return ['metatag']; } + /** + * Sets tag value and returns sanitized value with token replaced. + * + * @param \Drupal\metatag\Plugin\metatag\Tag\MetaNameBase|object $tag + * Metatag object. + * @param array|string $value + * Value to process. + * @param array $token_replacements + * Arguments for token->replace(). + * @param bool $plain_text + * (optional) If TRUE, value will be formatted as a plain text. Defaults to + * FALSE. + * @param string $langcode + * (optional) The language code to use for replacements; if not provided the + * current interface language code will be used. + * + * @return array|string + * Processed value. + */ + protected function processTagValue($tag, $value, array $token_replacements, bool $plain_text = FALSE, $langcode = '') { + // Set the value as sometimes the data needs massaging, such as when + // field defaults are used for the Robots field, which come as an array + // that needs to be filtered and converted to a string. + // @see Robots::setValue() + $tag->setValue($value); + + // Obtain the processed value. Some meta tags will store this as a + // string, so support that option. + // @todo Is there a better way of doing this? It seems unclean. + $value = $tag->value(); + + // Make sure the value is always handled as an array, but track whether it + // was actually passed in as an array. + $is_array = is_array($value); + if (!$is_array) { + $value = [$value]; + } + + // If a langcode was not specified, use the current interface language. + if (empty($langcode)) { + $langcode = $this->languageManager + ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT) + ->getId(); + } + + // Loop over each item in the array. + foreach ($value as $key => $value_item) { + // Process the tokens in this value and decode any HTML characters that + // might be found. + if (!empty($value_item) && is_string($value_item)) { + if (strpos($value_item, '[') !== FALSE) { + $value[$key] = $this->tokenService->replace($value_item, $token_replacements, ['langcode' => $langcode]); + } + $value[$key] = htmlspecialchars_decode($value[$key]); + } + + // If requested, run the value through the render system. + if ($plain_text && !empty($value[$key])) { + $value[$key] = PlainTextOutput::renderFromHtml($value[$key]); + } + } + + // If the original value was passed as an array return the whole value, + // otherwise return the first item from the array. + return $is_array ? $value : reset($value); + } + } diff --git a/web/modules/metatag/src/MetatagManagerInterface.php b/web/modules/metatag/src/MetatagManagerInterface.php index dd0f7ca1c340cf09f77b639c91121fafa2faf891..5bd7b1bb0d4e3859c9ce1b683fd870a5fec8731c 100644 --- a/web/modules/metatag/src/MetatagManagerInterface.php +++ b/web/modules/metatag/src/MetatagManagerInterface.php @@ -3,6 +3,7 @@ namespace Drupal\metatag; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Render\BubbleableMetadata; /** * Class MetatagManager. @@ -98,4 +99,32 @@ public function sortedGroupsWithTags(); */ public function form(array $values, array $element, array $token_types = [], array $included_groups = NULL, array $included_tags = NULL, $verbose_help = FALSE); + /** + * Generate the elements that go in the hook_page_attachments attached array. + * + * @param array $tags + * The array of tags as plugin_id => value. + * @param object $entity + * Optional entity object to use for token replacements. + * + * @return array + * Render array with tag elements. + */ + public function generateElements(array $tags, $entity = NULL); + + /** + * Generate the actual meta tag values. + * + * @param array $tags + * The array of tags as plugin_id => value. + * @param object $entity + * Optional entity object to use for token replacements. + * @param \Drupal\Core\Render\BubbleableMetadata|null $cache + * (optional) Cacheability metadata. + * + * @return array + * Render array with tag elements. + */ + public function generateRawElements(array $tags, $entity = NULL, BubbleableMetadata $cache = NULL); + } diff --git a/web/modules/metatag/src/MetatagServiceProvider.php b/web/modules/metatag/src/MetatagServiceProvider.php index aa1ac3051b88fe454699db32f0aa77c27414f8b0..48e224cb62209a4782f1f03b50b0df0dad01bd7e 100644 --- a/web/modules/metatag/src/MetatagServiceProvider.php +++ b/web/modules/metatag/src/MetatagServiceProvider.php @@ -23,10 +23,12 @@ public function alter(ContainerBuilder $container) { // Priority of the metatag normalizer must be higher than other // general-purpose typed data and field item normalizers. $metatag = new Definition(MetatagNormalizer::class); + $metatag->setPublic(TRUE); $metatag->addTag('normalizer', ['priority' => 30]); $container->setDefinition('metatag.normalizer.metatag', $metatag); $metatag_hal = new Definition(MetatagHalNormalizer::class); + $metatag_hal->setPublic(TRUE); $metatag_hal->addTag('normalizer', ['priority' => 31]); $container->setDefinition('metatag.normalizer.metatag.hal', $metatag_hal); } diff --git a/web/modules/metatag/src/MetatagTrimmer.php b/web/modules/metatag/src/MetatagTrimmer.php new file mode 100644 index 0000000000000000000000000000000000000000..6fe035ba43a8f8003ade1c587604de8a9ff824dd --- /dev/null +++ b/web/modules/metatag/src/MetatagTrimmer.php @@ -0,0 +1,101 @@ +<?php + +namespace Drupal\metatag; + +use PHPUnit\Framework\Exception; + +/** + * MetatagTrimmer service class for trimming metatags. + */ +class MetatagTrimmer { + + /** + * Trims a given string after the word on the given length. + * + * @param string $string + * The string to trim. + * @param int $maxlength + * The maximum length where the string approximately gets trimmed. + * + * @return string + * The trimmed string. + */ + public function trimAfterValue($string, $maxlength) { + // If the string is shorter than the max length then skip the rest of the + // logic. + if ($maxlength > mb_strlen($string)) { + return $string; + } + + $spacePos = mb_strpos($string, ' ', $maxlength - 1); + if (FALSE === $spacePos) { + return $string; + } + $subString = mb_substr($string, 0, $spacePos); + + return trim($subString); + } + + /** + * Trims a given string before the word on the given length. + * + * @param string $string + * The string to trim. + * @param int $maxlength + * The maximum length where the string approximately gets trimmed. + * + * @return string + * The trimmed string. + */ + public function trimBeforeValue($string, $maxlength) { + // If the string is shorter than the max length then skip the rest of the + // logic. + if ($maxlength > mb_strlen($string)) { + return $string; + } + + $subString = mb_substr($string, 0, $maxlength + 1); + if (' ' === mb_substr($subString, -1)) { + return trim($subString); + } + $spacePos = mb_strrpos($subString, ' ', 0); + if (FALSE === $spacePos) { + return $string; + } + $returnedString = mb_substr($string, 0, $spacePos); + + return trim($returnedString); + } + + /** + * Trims a value based on the given length and the given method. + * + * @param string $value + * The string to trim. + * @param int $maxlength + * The maximum length where the string approximately gets trimmed. + * @param string $method + * The trim method to use for the trimming. + * Allowed values: 'afterValue', 'onValue' and 'beforeValue'. + */ + public function trimByMethod($value, $maxlength, $method) { + if (empty($value) || empty($maxlength)) { + return $value; + } + + switch ($method) { + case 'afterValue': + return $this->trimAfterValue($value, $maxlength); + + case 'onValue': + return trim(mb_substr($value, 0, $maxlength)); + + case 'beforeValue': + return $this->trimBeforeValue($value, $maxlength); + + default: + throw new Exception('Unknown trimming method: ' . $method); + } + } + +} diff --git a/web/modules/metatag/src/Normalizer/MetatagNormalizer.php b/web/modules/metatag/src/Normalizer/MetatagNormalizer.php index 32837dcd68897f70671666db91559c1a0cd6f666..dbed42f721ab75e4d6522ca8df8b941aa4ee52ed 100644 --- a/web/modules/metatag/src/Normalizer/MetatagNormalizer.php +++ b/web/modules/metatag/src/Normalizer/MetatagNormalizer.php @@ -46,7 +46,7 @@ public function normalize($field_item, $format = NULL, array $context = []) { /** * {@inheritdoc} */ - public function supportsDenormalization($data, $type, $format = NULL) { + public function supportsDenormalization($data, $type, $format = NULL, $context = []): bool { return FALSE; } diff --git a/web/modules/metatag/src/Plugin/Field/FieldType/MetatagFieldItem.php b/web/modules/metatag/src/Plugin/Field/FieldType/MetatagFieldItem.php index 32584acf2a4fc9146dad0d8eb7483ec2b414788e..f860e3c9cc87a059af0d1f2f135b135e3a62ed70 100644 --- a/web/modules/metatag/src/Plugin/Field/FieldType/MetatagFieldItem.php +++ b/web/modules/metatag/src/Plugin/Field/FieldType/MetatagFieldItem.php @@ -46,6 +46,20 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel ->setLabel(t('Metatag')) ->setRequired(TRUE); + $sorted_tags = \Drupal::service('metatag.manager')->sortedGroupsWithTags(); + + foreach ($sorted_tags as $group_id => $group) { + if (isset($group['tags'])) { + foreach ($group['tags'] as $tag_id => $tag) { + $properties[$tag_id] = DataDefinition::create('string') + ->setLabel(t('@label', ['@label' => $tag['label']])) + ->setComputed(TRUE) + ->setClass('\Drupal\metatag\TypedData\IndividualTag') + ->setSetting('tag_name', $tag_id); + } + } + } + return $properties; } @@ -67,10 +81,12 @@ public function preSave() { $default_tags = metatag_get_default_tags($this->getEntity()); // Get the value about to be saved. + // @todo Does this need to be rewritten to use $this->getValue()? $current_value = $this->value; + // Only unserialize if still serialized string. if (is_string($current_value)) { - $current_tags = unserialize($current_value); + $current_tags = unserialize($current_value, ['allowed_classes' => FALSE]); } else { $current_tags = $current_value; @@ -85,6 +101,9 @@ public function preSave() { } } + // Sort the values prior to saving. so that they are easier to manage. + ksort($tags_to_save); + // Update the value to only save overridden tags. $this->value = serialize($tags_to_save); } diff --git a/web/modules/metatag/src/Plugin/Field/FieldWidget/MetatagFirehose.php b/web/modules/metatag/src/Plugin/Field/FieldWidget/MetatagFirehose.php index 7cfcb415f35886a2fc8edca15557308bc8541aba..f336d590f2d990a23d823bc7f498b6149fc465b1 100644 --- a/web/modules/metatag/src/Plugin/Field/FieldWidget/MetatagFirehose.php +++ b/web/modules/metatag/src/Plugin/Field/FieldWidget/MetatagFirehose.php @@ -2,16 +2,16 @@ namespace Drupal\metatag\Plugin\Field\FieldWidget; +use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\WidgetBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\metatag\MetatagManagerInterface; use Drupal\metatag\MetatagTagPluginManager; -use Drupal\Core\Config\ConfigFactoryInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Advanced widget for metatag field. @@ -71,6 +71,7 @@ public static function create(ContainerInterface $container, array $configuratio public static function defaultSettings() { return [ 'sidebar' => TRUE, + 'use_details' => TRUE, ] + parent::defaultSettings(); } @@ -84,6 +85,17 @@ public function settingsForm(array $form, FormStateInterface $form_state) { '#default_value' => $this->getSetting('sidebar'), '#description' => $this->t('If checked, the field will be placed in the sidebar on entity forms.'), ]; + $element['use_details'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Wrap the meta tags in a collapsed details container.'), + '#default_value' => $this->getSetting('use_details'), + '#description' => $this->t('If checked, the contents of the field will be placed inside a collapsed details container.'), + '#states' => [ + 'visible' => [ + 'input[name$="[sidebar]"]' => ['checked' => FALSE], + ], + ], + ]; return $element; } @@ -93,10 +105,17 @@ public function settingsForm(array $form, FormStateInterface $form_state) { */ public function settingsSummary() { if ($this->getSetting('sidebar')) { - $summary[] = $this->t('Use sidebar: Yes'); + $summary['sidebar'] = $this->t('Use sidebar: Yes'); } else { - $summary[] = $this->t('Use sidebar: No'); + $summary['sidebar'] = $this->t('Use sidebar: No'); + + if ($this->getSetting('use_details')) { + $summary['use_details'] = $this->t('Use details container: Yes'); + } + else { + $summary['use_details'] = $this->t('Use details container: No'); + } } return $summary; @@ -116,13 +135,21 @@ public function __construct($plugin_id, $plugin_definition, FieldDefinitionInter * {@inheritdoc} */ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { + // @todo Does this need to be rewritten to use $items->getValue()? $item = $items[$delta]; $default_tags = metatag_get_default_tags($items->getEntity()); // Retrieve the values for each metatag from the serialized array. $values = []; if (!empty($item->value)) { - $values = unserialize($item->value); + $values = unserialize($item->value, ['allowed_classes' => FALSE]); + } + + // Make sure that this variable is always an array to avoid problems when + // unserializing didn't work correctly and it as returned as FALSE. + // @see https://www.php.net/unserialize + if (!is_array($values)) { + $values = []; } // Populate fields which have not been overridden in the entity. @@ -158,14 +185,31 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element = $this->metatagManager->form($values, $element, [$entity_type]); } - // If the "sidebar" option was checked on the field widget, put the - // form element into the form's "advanced" group. Otherwise, let it - // default to the main field area. + // If the "sidebar" option was checked on the field widget, put the form + // element into the form's "advanced" group. Otherwise, let it default to + // the main field area. $sidebar = $this->getSetting('sidebar'); if ($sidebar) { $element['#group'] = 'advanced'; } + // If the "use_details" option was not checked on the field widget, put the + // form element into normal container. Otherwise, let it default to a + // detail's container. + $details = $this->getSetting('use_details'); + if (!$sidebar && !$details) { + $element['#type'] = 'container'; + } + + // Scroll height configuration. + $scroll_height = $settings->get('tag_scroll_max_height'); + if (!empty($scroll_height)) { + $form['#attached']['drupalSettings']['metatag']['max_height'] = $scroll_height; + $form['#attached']['library'][] = 'metatag/firehose_widget'; + $element['#attributes']['class'][] = 'metatags'; + $element['#attributes']['style'][] = 'max-height:' . $scroll_height . ';'; + } + return $element; } diff --git a/web/modules/metatag/src/Plugin/Field/MetatagEntityFieldItemList.php b/web/modules/metatag/src/Plugin/Field/MetatagEntityFieldItemList.php index f48c90dd6670050d77c2723cf750769fc6263a02..bdc6a3e719dcb96b81a80852b113559e843e505a 100644 --- a/web/modules/metatag/src/Plugin/Field/MetatagEntityFieldItemList.php +++ b/web/modules/metatag/src/Plugin/Field/MetatagEntityFieldItemList.php @@ -22,5 +22,4 @@ protected function computeValue() { return NULL; } - } diff --git a/web/modules/metatag/src/Plugin/diff/Field/MetatagFieldBuilder.php b/web/modules/metatag/src/Plugin/diff/Field/MetatagFieldBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..f7a03b19fc3177c150810c68fe2ee8a8e818586f --- /dev/null +++ b/web/modules/metatag/src/Plugin/diff/Field/MetatagFieldBuilder.php @@ -0,0 +1,45 @@ +<?php + +namespace Drupal\metatag\Plugin\diff\Field; + +use Drupal\diff\FieldDiffBuilderBase; +use Drupal\Core\Field\FieldItemListInterface; + +/** + * Plugin to diff metatag fields. + * + * @FieldDiffBuilder( + * id = "metatag_field_diff_builder", + * label = @Translation("Metatag Field Diff"), + * field_types = { + * "metatag" + * }, + * ) + */ +class MetatagFieldBuilder extends FieldDiffBuilderBase { + + /** + * {@inheritdoc} + */ + public function build(FieldItemListInterface $field_items) { + $result = []; + + // Every item from $field_items is of type FieldItemInterface. + foreach ($field_items as $field_key => $field_item) { + if (!$field_item->isEmpty()) { + $values = $field_item->getValue(); + if (isset($values['value'])) { + // Metatag data store as serialize string + $metatag_data = unserialize($values['value']); + + foreach ($metatag_data as $key => $value) { + $result[$field_key][] = (string) $value; + } + } + } + } + + return $result; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Group/GroupBase.php b/web/modules/metatag/src/Plugin/metatag/Group/GroupBase.php index 0c2770ce8d168b72b243a8c86c80930a36789304..eac73d587b052adf2cbcc12392e5c932643634c2 100644 --- a/web/modules/metatag/src/Plugin/metatag/Group/GroupBase.php +++ b/web/modules/metatag/src/Plugin/metatag/Group/GroupBase.php @@ -42,7 +42,7 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi // @todo Should we have setProperty() methods for each of these? $this->id = $plugin_definition['id']; $this->label = $plugin_definition['label']; - $this->description = $plugin_definition['description']; + $this->description = $plugin_definition['description'] ?? ''; } /** diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/AbstractTag.php b/web/modules/metatag/src/Plugin/metatag/Tag/AbstractTag.php index 19451a75dd4853fedd3e69630b85bc510a2ed4b0..a637b3600ad80a51f44241c8ccd89a746a4026f7 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/AbstractTag.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/AbstractTag.php @@ -15,6 +15,7 @@ * type = "label", * secure = FALSE, * multiple = FALSE, + * trimmable = TRUE, * long = TRUE, * ) */ diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Author.php b/web/modules/metatag/src/Plugin/metatag/Tag/Author.php new file mode 100644 index 0000000000000000000000000000000000000000..3c9084614bd0a5e3b7c43606fb1510ce4adf58d2 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Author.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The advanced Author meta tag. + * + * @MetatagTag( + * id = "author", + * label = @Translation("Author"), + * description = @Translation("Define the author of a page."), + * name = "author", + * group = "advanced", + * weight = 4, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ + +class Author extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/ContentLanguage.php b/web/modules/metatag/src/Plugin/metatag/Tag/ContentLanguage.php index dfc0942e20a0b713c76a2102bdfcf73527a19018..d1a4f75f18426efa12ad5960d8005a538a97e041 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/ContentLanguage.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/ContentLanguage.php @@ -8,7 +8,7 @@ * @MetatagTag( * id = "content_language", * label = @Translation("Content Language"), - * description = @Translation("Used to define this page's language code. May be the two letter language code, e.g. ""de"" for German, or the two letter code with a dash and the two letter ISO country code, e.g. ""de-AT"" for German in Austria. Still used by Bing."), + * description = @Translation("DEPRECATED. Used to define this page's language code. May be the two letter language code, e.g. ""de"" for German, or the two letter code with a dash and the two letter ISO country code, e.g. ""de-AT"" for German in Austria. Still used by Bing."), * name = "content-language", * group = "advanced", * weight = 1, @@ -16,6 +16,10 @@ * secure = FALSE, * multiple = FALSE * ) + * + * @deprecated in metatag:8.x-1.20 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3217263 */ class ContentLanguage extends MetaHttpEquivBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Description.php b/web/modules/metatag/src/Plugin/metatag/Tag/Description.php index ee2866ed09bf28c673191d3fb41cbdf584d28dee..5688a33b78a697061afecd5d8c73845e4c301498 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/Description.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Description.php @@ -16,6 +16,7 @@ * secure = FALSE, * multiple = FALSE, * long = TRUE, + * trimmable = TRUE * ) */ class Description extends MetaNameBase { diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/GeoPosition.php b/web/modules/metatag/src/Plugin/metatag/Tag/GeoPosition.php index c50d7c6b220603576ec5afa4392ea17da60cc8c4..e1c889debb84a7df710c78c46faba6097dbda0b6 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/GeoPosition.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/GeoPosition.php @@ -8,7 +8,7 @@ * @MetatagTag( * id = "geo_position", * label = @Translation("Geographical position"), - * description = @Translation("Geo-spatial information in 'latitude; longitude' format, e.g. '50.167958; -97.133185'; <a href='https://en.wikipedia.org/wiki/Geographic_coordinate_system'>see Wikipedia for details</a>."), + * description = @Translation("Geo-spatial information in 'latitude; longitude' format, e.g. '50.167958; -97.133185'; <a href='https://en.wikipedia.org/wiki/Geographic_coordinate_system' aria-label='see Wikipedia for details on the geographic coordinate system'>see Wikipedia for details</a>."), * name = "geo.position", * group = "advanced", * weight = 0, diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Icbm.php b/web/modules/metatag/src/Plugin/metatag/Tag/Icbm.php index 078d2c7a968a27aa3697964b72e130b3df673a7b..a27b680dccea0f6bfc871bdb4a4ccfbc9fbaefc0 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/Icbm.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Icbm.php @@ -8,7 +8,7 @@ * @MetatagTag( * id = "icbm", * label = @Translation("ICBM"), - * description = @Translation("Geo-spatial information in 'latitude, longitude' format, e.g. '50.167958, -97.133185'; <a href='https://en.wikipedia.org/wiki/ICBM_address'>see Wikipedia for details</a>."), + * description = @Translation("Geo-spatial information in 'latitude, longitude' format, e.g. '50.167958, -97.133185'; <a href='https://en.wikipedia.org/wiki/ICBM_address' aria-label='see Wikipedia for details on ICBM addresses'>see Wikipedia for details</a>."), * name = "icbm", * group = "advanced", * weight = 0, diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/LinkRelBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/LinkRelBase.php index 449ce2fb4991cfe45d6bff2834323c277cc69a16..39e63f9e6fa30ed888b27cebba2d163170866323 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/LinkRelBase.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/LinkRelBase.php @@ -8,20 +8,24 @@ abstract class LinkRelBase extends MetaNameBase { /** - * {@inheritdoc} + * The string this tag uses for the tag itself. + * + * @var string */ - public function output() { - $element = parent::output(); - if (!empty($element['#attributes']['content'])) { - $element['#tag'] = 'link'; - $element['#attributes'] = [ - 'rel' => $this->name(), - 'href' => $element['#attributes']['content'], - ]; - unset($element['#attributes']['content']); - } + protected $htmlTag = 'link'; - return $element; - } + /** + * The attribute this tag uses for the name. + * + * @var string + */ + protected $htmlNameAttribute = 'rel'; + + /** + * The attribute this tag uses for the contents. + * + * @var string + */ + protected $htmlValueAttribute = 'href'; } diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaHttpEquivBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaHttpEquivBase.php index 607d6bf75ee9b0fae1c39f54d18c190295950874..0311602d4a968f55f646d5b99b561e45706a6402 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/MetaHttpEquivBase.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaHttpEquivBase.php @@ -14,4 +14,9 @@ abstract class MetaHttpEquivBase extends MetaNameBase { */ protected $nameAttribute = 'http-equiv'; + /** + * {@inheritdoc} + */ + protected $htmlNameAttribute = 'http-equiv'; + } diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaItempropBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaItempropBase.php index 802e247fae2223e55e09ecd52b5e66b21d114122..18dcd4a97a71e549e762345504661c86d3abb77f 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/MetaItempropBase.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaItempropBase.php @@ -14,4 +14,9 @@ abstract class MetaItempropBase extends MetaNameBase { */ protected $nameAttribute = 'itemprop'; + /** + * {@inheritdoc} + */ + protected $htmlNameAttribute = 'itemprop'; + } diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaNameBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaNameBase.php index da00613588a5968030229883730966ffb4786ea4..bb71bc76c17ec648f94007ea4d1979e2f100cbbf 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/MetaNameBase.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaNameBase.php @@ -81,6 +81,13 @@ abstract class MetaNameBase extends PluginBase { */ protected $long; + /** + * True if the tag should be trimmable. + * + * @var bool + */ + protected $trimmable; + /** * True if the URL value(s) must be absolute. * @@ -102,13 +109,45 @@ abstract class MetaNameBase extends PluginBase { */ protected $value; + /** + * The sort order for this meta tag. + * + * @var int + */ + protected $weight; + /** * The attribute this tag uses for the name. * * @var string + * + * @deprecated in metatag:8.x-1.20 and is removed from metatag:2.0.0. Use $this->htmlTagNameAttribute instead. + * + * @see https://www.drupal.org/node/3303208 */ protected $nameAttribute = 'name'; + /** + * The string this tag uses for the tag itself. + * + * @var string + */ + protected $htmlTag = 'meta'; + + /** + * The attribute this tag uses for the name. + * + * @var string + */ + protected $htmlNameAttribute = 'name'; + + /** + * The attribute this tag uses for the contents. + * + * @var string + */ + protected $htmlValueAttribute = 'content'; + /** * {@inheritdoc} */ @@ -120,12 +159,13 @@ public function __construct(array $configuration, $plugin_id, array $plugin_defi $this->id = $plugin_definition['id']; $this->name = $plugin_definition['name']; $this->label = $plugin_definition['label']; - $this->description = $plugin_definition['description']; + $this->description = $plugin_definition['description'] ?? ''; $this->group = $plugin_definition['group']; $this->weight = $plugin_definition['weight']; $this->type = $plugin_definition['type']; - $this->secure = $plugin_definition['secure']; - $this->multiple = $plugin_definition['multiple']; + $this->secure = !empty($plugin_definition['secure']); + $this->multiple = !empty($plugin_definition['multiple']); + $this->trimmable = !empty($plugin_definition['trimmable']); $this->long = !empty($plugin_definition['long']); $this->absoluteUrl = !empty($plugin_definition['absolute_url']); $this->request = \Drupal::request(); @@ -154,7 +194,7 @@ public function label() { /** * The meta tag's description. * - * @return bool + * @return string * This meta tag's description. */ public function description() { @@ -201,6 +241,16 @@ public function type() { return $this->type; } + /** + * Determine whether this meta tag is an image tag. + * + * @return bool + * Whether this meta tag is an image. + */ + public function isImage(): bool { + return $this->type() == 'image'; + } + /** * Whether or not this meta tag must output secure (HTTPS) URLs. * @@ -211,6 +261,16 @@ public function secure() { return $this->secure; } + /** + * Whether or not this meta tag must output secure (HTTPS) URLs. + * + * @return bool + * Whether or not this meta tag must output secure (HTTPS) URLs. + */ + public function isSecure(): bool { + return (bool) $this->secure; + } + /** * Whether or not this meta tag supports multiple values. * @@ -221,6 +281,16 @@ public function multiple() { return $this->multiple; } + /** + * Whether or not this meta tag supports multiple values. + * + * @return bool + * Whether or not this meta tag supports multiple values. + */ + public function isMultiple(): bool { + return (bool) $this->multiple; + } + /** * Whether or not this meta tag should use a text area. * @@ -231,6 +301,38 @@ public function isLong() { return $this->long; } + /** + * Whether or not this meta tag stores a URL or URI value. + * + * @return bool + * Whether or not this meta tag should contain a URL or URI value. + */ + public function isUrl(): bool { + // Secure URLs are URLs. + if ($this->isSecure()) { + return TRUE; + } + // Absolute URLs are URLs. + if ($this->requiresAbsoluteUrl()) { + return TRUE; + } + // URIs are URL-adjacent. + if ($this->type == 'uri') { + return TRUE; + } + return FALSE; + } + + /** + * Get the HTML attribute used to store this meta tag's value. + * + * @return string + * The HTML attribute used to store this meta tag's value. + */ + public function getHtmlValueAttribute() { + return $this->htmlValueAttribute; + } + /** * Whether or not this meta tag must output required absolute URLs. * @@ -266,7 +368,7 @@ public function form(array $element = []) { '#title' => $this->label(), '#default_value' => $this->value(), '#maxlength' => 1024, - '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#required' => $element['#required'] ?? FALSE, '#description' => $this->description(), '#element_validate' => [[get_class($this), 'validateTag']], ]; @@ -316,13 +418,19 @@ public function setValue($value) { /** * Make the string presentable. * + * This removes whitespace from either side of the string, and removes extra + * whitespace inside the string so that it only contains one single space, + * all line breaks and tabs are replaced by spaces. + * * @param string $value * The raw string to process. * * @return string * The meta tag value after processing. */ - private function tidy($value) { + protected function tidy($value) { + $value = str_replace(["\r\n", "\n", "\r", "\t"], ' ', $value); + $value = preg_replace('/\s+/', ' ', $value); return trim($value); } @@ -366,11 +474,13 @@ public function output() { $value = str_replace('http://', 'https://', $value); } + $value = $this->trimValue($value); + $elements[] = [ - '#tag' => 'meta', + '#tag' => $this->htmlTag, '#attributes' => [ - $this->nameAttribute => $this->name, - 'content' => $value, + $this->htmlNameAttribute => $this->name, + $this->htmlValueAttribute => $value, ], ]; } @@ -403,13 +513,21 @@ protected function parseImageUrl($value) { // If image tag src is relative (starts with /), convert to an absolute // link; ignore protocol-relative URLs. + $image_tag = FALSE; if (strpos($value, '<img src="/') !== FALSE && strpos($value, '<img src="//') === FALSE) { $value = str_replace('<img src="/', '<img src="' . $base_root . '/', $value); + $image_tag = TRUE; } if ($this->multiple()) { // Split the string into an array, remove empty items. - $values = array_filter(explode(',', $value)); + if ($image_tag) { + preg_match_all('%\s*(|,\s*)(<\s*img\s+[^>]+>)%m', $value, $matches); + $values = array_filter($matches[2] ?? []); + } + else { + $values = array_filter(explode(',', $value)); + } } else { $values = [$value]; @@ -437,4 +555,35 @@ protected function parseImageUrl($value) { return implode(',', $values); } + /** + * Trims a value if it is trimmable. + * + * This method uses metatag settings and the MetatagTrimmer service. + * + * @param string $value + * The string value to trim. + * + * @return string + * The trimmed string value. + */ + protected function trimValue($value) { + if (TRUE === $this->trimmable) { + $settings = \Drupal::config('metatag.settings'); + $trimMethod = $settings->get('tag_trim_method'); + $trimMaxlengthArray = $settings->get('tag_trim_maxlength'); + if (empty($trimMethod) || empty($trimMaxlengthArray)) { + return $value; + } + $currentMaxValue = 0; + foreach ($trimMaxlengthArray as $metaTagName => $maxValue) { + if ($metaTagName == 'metatag_maxlength_' . $this->id) { + $currentMaxValue = $maxValue; + } + } + $trimmerService = \Drupal::service('metatag.trimmer'); + $value = $trimmerService->trimByMethod($value, $currentMaxValue, $trimMethod); + } + return $value; + } + } diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaPropertyBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaPropertyBase.php index c242d23cf15a1bc1476e2c3b87986f2ed0837ab3..c4e2a88e042e8f1398583ab1bde9c902525e4533 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/MetaPropertyBase.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaPropertyBase.php @@ -14,4 +14,9 @@ abstract class MetaPropertyBase extends MetaNameBase { */ protected $nameAttribute = 'property'; + /** + * {@inheritdoc} + */ + protected $htmlNameAttribute = 'property'; + } diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/NewsKeywords.php b/web/modules/metatag/src/Plugin/metatag/Tag/NewsKeywords.php index 081debd6ea5427e9200b43108c40cc29169176f4..5ec717d669b06934e050dfc234eb754dd6ac0f1b 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/NewsKeywords.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/NewsKeywords.php @@ -16,6 +16,10 @@ * secure = FALSE, * multiple = FALSE * ) + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/2973351 */ class NewsKeywords extends MetaNameBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Referrer.php b/web/modules/metatag/src/Plugin/metatag/Tag/Referrer.php index def080a51c904607fa183b5808a15d4116eca282..848b9bc5eac95fc746817b7042899e93dfa72551 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/Referrer.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Referrer.php @@ -31,24 +31,34 @@ public function form(array $element = []) { '#type' => 'select', '#title' => $this->label(), '#description' => $this->description(), - '#options' => [ - 'no-referrer' => $this->t('No Referrer'), - 'no-referrer-when-downgrade' => $this->t('No Referrer When Downgrade'), - 'origin' => $this->t('Origin'), - 'origin-when-cross-origin' => $this->t('Origin When Cross-Origin'), - 'same-origin' => $this->t('Same Origin'), - 'strict-origin' => $this->t('Strict Origin'), - 'strict-origin-when-cross-origin' => $this->t('Strict Origin When Cross-Origin'), - 'unsafe-url' => $this->t('Unsafe URL'), - ], + '#options' => $this->formValues(), '#empty_option' => $this->t('- None -'), '#empty_value' => '', '#default_value' => $this->value(), - '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#required' => $element['#required'] ?? FALSE, '#element_validate' => [[get_class($this), 'validateTag']], ]; return $form; } + /** + * The list of select values. + * + * @return array + * A list of values available for this select tag. + */ + protected function formValues() { + return [ + 'no-referrer' => $this->t('No Referrer'), + 'no-referrer-when-downgrade' => $this->t('No Referrer When Downgrade'), + 'origin' => $this->t('Origin'), + 'origin-when-cross-origin' => $this->t('Origin When Cross-Origin'), + 'same-origin' => $this->t('Same Origin'), + 'strict-origin' => $this->t('Strict Origin'), + 'strict-origin-when-cross-origin' => $this->t('Strict Origin When Cross-Origin'), + 'unsafe-url' => $this->t('Unsafe URL'), + ]; + } + } diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Robots.php b/web/modules/metatag/src/Plugin/metatag/Tag/Robots.php index 492546a67e4914a12341369fb938a28cf38dad50..d9cd686262eac50f655c562dab0eac7c99c28b3a 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/Robots.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Robots.php @@ -54,18 +54,7 @@ public function form(array $element = []) { '#type' => 'checkboxes', '#title' => $this->label(), '#description' => $this->description(), - '#options' => [ - 'index' => $this->t('index - Allow search engines to index this page (assumed).'), - 'follow' => $this->t('follow - Allow search engines to follow links on this page (assumed).'), - 'noindex' => $this->t('noindex - Prevents search engines from indexing this page.'), - 'nofollow' => $this->t('nofollow - Prevents search engines from following links on this page.'), - 'noarchive' => $this->t('noarchive - Prevents cached copies of this page from appearing in search results.'), - 'nosnippet' => $this->t('nosnippet - Prevents descriptions from appearing in search results, and prevents page caching.'), - 'noodp' => $this->t('noodp - Blocks the <a href=":opendirectory">Open Directory Project</a> description from appearing in search results.', [':opendirectory' => 'http://www.dmoz.org/']), - 'noydir' => $this->t('noydir - Prevents Yahoo! from listing this page in the <a href=":ydir">Yahoo! Directory</a>.', [':ydir' => 'http://dir.yahoo.com/']), - 'noimageindex' => $this->t('noimageindex - Prevent search engines from indexing images on this page.'), - 'notranslate' => $this->t('notranslate - Prevent search engines from offering to translate this page in search results.'), - ], + '#options' => $this->formValues(), 'index' => [ '#states' => [ 'disabled' => [ @@ -103,11 +92,32 @@ public function form(array $element = []) { ], ], '#default_value' => $default_value, - '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#required' => $element['#required'] ?? FALSE, '#element_validate' => [[get_class($this), 'validateTag']], ]; return $form; } + /** + * The list of select values. + * + * @return array + * A list of values available for this select tag. + */ + protected function formValues() { + return [ + 'index' => $this->t('index - Allow search engines to index this page (assumed).'), + 'follow' => $this->t('follow - Allow search engines to follow links on this page (assumed).'), + 'noindex' => $this->t('noindex - Prevents search engines from indexing this page.'), + 'nofollow' => $this->t('nofollow - Prevents search engines from following links on this page.'), + 'noarchive' => $this->t('noarchive - Prevents cached copies of this page from appearing in search results.'), + 'nosnippet' => $this->t('nosnippet - Prevents descriptions from appearing in search results, and prevents page caching.'), + 'noodp' => $this->t('noodp - Blocks the <a href=":opendirectory">Open Directory Project</a> description from appearing in search results.', [':opendirectory' => 'http://www.dmoz.org/']), + 'noydir' => $this->t('noydir - Prevents Yahoo! from listing this page in the <a href=":ydir">Yahoo! Directory</a>.', [':ydir' => 'http://dir.yahoo.com/']), + 'noimageindex' => $this->t('noimageindex - Prevent search engines from indexing images on this page.'), + 'notranslate' => $this->t('notranslate - Prevent search engines from offering to translate this page in search results.'), + ]; + } + } diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Standout.php b/web/modules/metatag/src/Plugin/metatag/Tag/Standout.php index 131f0a4c71a250e5c416e85ae8828aa64ac495eb..b65d8393ee56d68b6e03ab172222f6b7ab378b41 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/Standout.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Standout.php @@ -16,6 +16,10 @@ * secure = FALSE, * multiple = FALSE * ) + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/2973351 */ class Standout extends MetaNameBase { // Nothing here yet. Just a placeholder class for a plugin. diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Title.php b/web/modules/metatag/src/Plugin/metatag/Tag/Title.php index d1dd70b98b2da2358c197d898702f1c484997551..f2a4f2ec408844b0e10cedaf38a5b275cae5b5af 100644 --- a/web/modules/metatag/src/Plugin/metatag/Tag/Title.php +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Title.php @@ -14,32 +14,10 @@ * weight = -1, * type = "label", * secure = FALSE, - * multiple = FALSE + * multiple = FALSE, + * trimmable = TRUE * ) */ class Title extends MetaNameBase { - - /** - * Override the output of this tag so it's an actual TITLE tag. - * - * @todo Override the existing title tag X-) - */ - // {@code} - // public function output() { - // if (empty($this->value)) { - // // If there is no value, we don't want a tag output. - // $element = ''; - // } - // else { - // $element = [ - // '#theme' => 'hidden', - // // '#tag' => 'title', - // '#value' => $this->value(), - // ]; - // } - // - // return $element; - // } - // {@endcode} - + // Nothing here yet. Just a placeholder class for a plugin. } diff --git a/web/modules/metatag/src/Plugin/migrate/process/d6/NodewordsEntities.php b/web/modules/metatag/src/Plugin/migrate/process/d6/NodewordsEntities.php index b6544d1b5a22237874dd8c02cc48787a72836c62..1e0a8ca7f91e62f605db8a63ea75f35e31cc467b 100644 --- a/web/modules/metatag/src/Plugin/migrate/process/d6/NodewordsEntities.php +++ b/web/modules/metatag/src/Plugin/migrate/process/d6/NodewordsEntities.php @@ -38,7 +38,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable // Re-shape D6 entries into for D8 entries. $old_tags = array_map(static function ($value) { - return unserialize($value); + return unserialize($value, ['allowed_classes' => FALSE]); }, $value); foreach ($old_tags as $d6_metatag_name => $metatag_value) { diff --git a/web/modules/metatag/src/Plugin/migrate/process/d7/MetatagEntities.php b/web/modules/metatag/src/Plugin/migrate/process/d7/MetatagEntities.php index d8ea723993078910cda5787b241e66aeb3e2948b..f5a1e11bce9508acbe3ce4fec7effa27322958a8 100644 --- a/web/modules/metatag/src/Plugin/migrate/process/d7/MetatagEntities.php +++ b/web/modules/metatag/src/Plugin/migrate/process/d7/MetatagEntities.php @@ -2,6 +2,7 @@ namespace Drupal\metatag\Plugin\migrate\process\d7; +use Drupal\Component\Utility\Unicode; use Drupal\migrate\MigrateException; use Drupal\migrate\MigrateExecutableInterface; use Drupal\migrate\ProcessPluginBase; @@ -27,7 +28,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable } // Re-shape D7 entries into for D8 entries. - $old_tags = unserialize($value); + $old_tags = unserialize($value, ['allowed_classes' => FALSE]); // This is expected to be an array, if it isn't then something went wrong. if (!is_array($old_tags)) { @@ -66,11 +67,17 @@ public function transform($value, MigrateExecutableInterface $migrate_executable else { $metatag_value = $metatag_value['value']; } + if (!Unicode::validateUtf8($metatag_value)) { + $metatag_value = Unicode::convertToUtf8($metatag_value, 'Windows-1252'); + } // Keep the entire data structure. $metatags[$d8_metatag_name] = $metatag_value; } + // Sort the meta tags alphabetically to make testing easier. + ksort($metatags); + return serialize($metatags); } @@ -345,9 +352,11 @@ protected function tagsMap() { 'video:writer' => 'video_writer', // From metatag_opengraph_products.metatag.inc: - // https://www.drupal.org/project/metatag/issues/2835925 'product:price:amount' => 'product_price_amount', 'product:price:currency' => 'product_price_currency', + // Not supported in D7. + // @todo '' => 'product_retailer_item_id, + // Not yet supported in D9. // @todo 'product:availability' => '', // @todo 'product:brand' => '', // @todo 'product:upc' => '', @@ -423,8 +432,8 @@ protected function tagsMap() { // From metatag_verification.metatag.inc: 'baidu-site-verification' => 'baidu', 'facebook-domain-verification' => 'facebook_domain_verification', - 'google-site-verification' => 'bing', - 'msvalidate.01' => 'google', + 'google-site-verification' => 'google_site_verification', + 'msvalidate.01' => 'bing', 'norton-safeweb-site-verification' => 'norton_safe_web', 'p:domain_verify' => 'pinterest', // @todo '' => 'pocket', diff --git a/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsField.php b/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsField.php index 00a1c7f89393485cc133332d8a00a04a24ba5bda..e03225d2307b711fb752aed536ce9f120d16a08b 100644 --- a/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsField.php +++ b/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsField.php @@ -30,17 +30,23 @@ public function initializeIterator() { $instances = []; foreach (parent::initializeIterator() as $instance) { switch ($instance['type']) { + // @code // define('NODEWORDS_TYPE_NODE', 5); + // @endcode case 5: $instance['entity_type'] = 'node'; break; + // @code // define('NODEWORDS_TYPE_TERM', 6); + // @endcode case 6: $instance['entity_type'] = 'taxonomy_term'; break; + // @code // define('NODEWORDS_TYPE_USER', 8); + // @endcode case 8: $instance['entity_type'] = 'user'; break; diff --git a/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsFieldInstance.php b/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsFieldInstance.php index 8f249de650ad53fab1f6aecc4914ed86dd991e25..c24099b907cc2c2766f970544d6fb0c66c0f3194 100644 --- a/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsFieldInstance.php +++ b/web/modules/metatag/src/Plugin/migrate/source/d6/NodewordsFieldInstance.php @@ -71,18 +71,24 @@ public function initializeIterator() { foreach (parent::initializeIterator() as $instance) { $entity_type = NULL; switch ($instance['type']) { + // @code + // define('NODEWORDS_TYPE_NODE', 5); + // @endcode case 5: - // define('NODEWORDS_TYPE_NODE', 5); $entity_type = 'node'; break; + // @code + // define('NODEWORDS_TYPE_TERM', 6); + // @endcode case 6: - // define('NODEWORDS_TYPE_TERM', 6); $entity_type = 'taxonomy_term'; break; + // @code + // define('NODEWORDS_TYPE_USER', 8); + // @endcode case 8: - // define('NODEWORDS_TYPE_USER', 8); $entity_type = 'user'; break; @@ -115,7 +121,18 @@ public function getIds() { * {@inheritdoc} */ public function count($refresh = FALSE) { - return $this->initializeIterator()->count(); + /** @var \ArrayIterator $items */ + $items = $this->initializeIterator(); + return $items->count(); + } + + /** + * {@inheritdoc} + */ + protected function doCount() { + /** @var \ArrayIterator $items */ + $items = $this->initializeIterator(); + return $items->count(); } } diff --git a/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldDeriver.php b/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldDeriver.php index 294dc2b476d7b25a154d23b23d275ea3945a96b2..1f4c0be00a3d5d1d2a9a6830ab72800437898bdd 100644 --- a/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldDeriver.php +++ b/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldDeriver.php @@ -4,18 +4,16 @@ use Drupal\Component\Plugin\Derivative\DeriverBase; use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\migrate\Exception\RequirementsException; use Drupal\migrate\Plugin\MigrationDeriverTrait; use Drupal\migrate_drupal\MigrationConfigurationTrait; -use Drupal\migrate_drupal\NodeMigrateType; use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase; use Symfony\Component\DependencyInjection\ContainerInterface; /** - * @todo. + * Creates field plugins for each entity type. */ class MetatagFieldDeriver extends DeriverBase implements ContainerDeriverInterface { diff --git a/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstance.php b/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstance.php index 015f28ce9a097c5736e5104d5d785a4b303ce66a..760adf3a5ef7dbc64087aeb0f193addd923e51e3 100644 --- a/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstance.php +++ b/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstance.php @@ -60,8 +60,8 @@ public function query() { $bundle = $this->configuration['bundle']; switch ($entity_type_id) { case 'node': - // We want to get a per-node-type metatag migration. So we inner join - // the base query on node table based on the parsed node ID. + // We want to get a per-node-type metatag migration. So we inner + // join the base query on node table based on the parsed node ID. $base_query->join('node', 'n', "n.nid = m.entity_id"); $base_query->condition('n.type', $bundle); $base_query->addField('n', 'type', 'bundle'); @@ -101,6 +101,9 @@ public function fields() { /** * Returns each entity_type/bundle pair. + * + * @return \ArrayIterator + * An array iterator object containing the entity type and bundle. */ public function initializeIterator() { $bundles = []; @@ -138,7 +141,18 @@ public function getIds() { * {@inheritdoc} */ public function count($refresh = FALSE) { - return $this->initializeIterator()->count(); + /** @var \ArrayIterator $iterator */ + $iterator = $this->initializeIterator(); + return $iterator->count(); + } + + /** + * {@inheritdoc} + */ + protected function doCount() { + /** @var \ArrayIterator $iterator */ + $iterator = $this->initializeIterator(); + return $iterator->count(); } } diff --git a/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstanceDeriver.php b/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstanceDeriver.php index 832559232a1a1770b3f5ebf1e8b4402066cba50a..8c49395c011a3365ba6a75e5ca9382ca7a35e53c 100644 --- a/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstanceDeriver.php +++ b/web/modules/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstanceDeriver.php @@ -13,7 +13,10 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Deriver for d7_metatag_field_instance and d7_metatag_field_instance_widget_settings. + * Deriver for Metatag-D7 field instances. + * + * Covers d7_metatag_field_instance and + * d7_metatag_field_instance_widget_settings. */ class MetatagFieldInstanceDeriver extends DeriverBase implements ContainerDeriverInterface { @@ -170,6 +173,7 @@ public function getDerivativeDefinitions($base_plugin_definition) { case 'node': $this->derivatives[$derivative_id]['migration_dependencies']['required'][] = "d7_node_type:$bundle_id"; break; + case 'taxonomy_term': $this->derivatives[$derivative_id]['migration_dependencies']['required'][] = "d7_taxonomy_vocabulary:$bundle_id"; break; diff --git a/web/modules/metatag/src/TypedData/IndividualTag.php b/web/modules/metatag/src/TypedData/IndividualTag.php new file mode 100644 index 0000000000000000000000000000000000000000..e44f1d803973b5be2922d20b1530725adaa507d1 --- /dev/null +++ b/web/modules/metatag/src/TypedData/IndividualTag.php @@ -0,0 +1,101 @@ +<?php + +namespace Drupal\metatag\TypedData; + +use Drupal\Core\TypedData\DataDefinitionInterface; +use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Core\TypedData\TypedData; +use Drupal\Core\DependencyInjection\DependencySerializationTrait; + +/** + * A computed property for each meta tag. + * + * Required settings (below the definition's 'settings' key) are: + * - tag_name: The tag to be processed. + * Examples: "title", "description". + */ +class IndividualTag extends TypedData { + + use DependencySerializationTrait; + + /** + * Cached processed value. + */ + protected $value; + + /** + * {@inheritdoc} + */ + public function __construct(DataDefinitionInterface $definition, $name = NULL, TypedDataInterface $parent = NULL) { + parent::__construct($definition, $name, $parent); + + if ($definition->getSetting('tag_name') === NULL) { + throw new \InvalidArgumentException("The definition's 'tag_name' key has to specify the name of the meta tag to be processed."); + } + } + + /** + * {@inheritdoc} + */ + public function getValue() { + if (isset($this->value)) { + return $this->value; + } + + // The Metatag plugin ID. + $property_name = $this->definition->getSetting('tag_name'); + + // The item is the parent. + $item = $this->getParent(); + $entity = $item->getEntity(); + + // Rendered values. + $metatagManager = \Drupal::service('metatag.manager'); + $defaultTags = $metatagManager->tagsFromEntityWithDefaults($entity); + if (!isset($defaultTags[$property_name])) { + \Drupal::service('logger.factory') + ->get('metatag') + ->notice('No default for "%tag_name" - entity_type: %type, entity_bundle: %bundle, id: %id. See src/TypedData/Metatags.php.', [ + '%tag_name' => $property_name, + '%type' => $entity->getEntityTypeId(), + '%bundle' => $entity->bundle(), + '%id' => $entity->id(), + ]); + return FALSE; + } + $tags = [ + $property_name => $defaultTags[$property_name], + ]; + $values = $metatagManager->generateRawElements($tags, $entity); + + $all_tags = []; + foreach (\Drupal::service('plugin.manager.metatag.tag')->getDefinitions() as $tag_name => $tag_spec) { + $all_tags[$tag_name] = new $tag_spec['class']([], $tag_name, $tag_spec); + } + + // If this tag has a value set the property value. + if (isset($values[$property_name])) { + $attribute_name = $all_tags[$property_name]->getHtmlValueAttribute(); + + // It should be possible to extract the HTML attribute that stores the + // value, but in some cases it might not be possible. + if (isset($values[$property_name]['#attributes'][$attribute_name])) { + $this->value = $values[$property_name]['#attributes'][$attribute_name]; + } + else { + \Drupal::service('logger.factory') + ->get('metatag') + ->notice('Attribute value not mapped for "%property_name" - entity_type: %type, entity_bundle: %bundle, id: %id. See src/TypedData/Metatags.php.', [ + '%property_name' => $property_name, + '%type' => $entity->getEntityTypeId(), + '%bundle' => $entity->bundle(), + '%id' => $entity->id(), + ]); + return FALSE; + } + } + + return $this->value; + } + +} diff --git a/web/modules/metatag/templates/generator.php.twig b/web/modules/metatag/templates/generator.php.twig deleted file mode 100644 index 4c9857c678500ee8b0e92427db81500938188b22..0000000000000000000000000000000000000000 --- a/web/modules/metatag/templates/generator.php.twig +++ /dev/null @@ -1,9 +0,0 @@ -{% block prefix %}{% endblock %} - -{% block namespace_class %}{% endblock %} - -{% block use_class %}{% endblock %} - -{% block class_declaration %}{% endblock -%}{ - // Nothing here yet. Just a placeholder class for a plugin. -} diff --git a/web/modules/metatag/templates/group.php.twig b/web/modules/metatag/templates/group.php.twig deleted file mode 100644 index 1d1bbc34de1c3eaec64d77da3dbf4dd60fcc5424..0000000000000000000000000000000000000000 --- a/web/modules/metatag/templates/group.php.twig +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "generator.php.twig" %} - -{% block prefix %}{{ prefix }} -{% endblock %} - -{% block namespace_class %} -namespace Drupal\{{ module }}\Plugin\metatag\Group; -{% endblock %} - -{% block use_class %} -use Drupal\metatag\Plugin\metatag\Group\{{ base_class }}; -{% endblock %} - -{% block class_declaration %} -/** - * Provides a plugin for the '{{ label }}' meta tag group. - * - * @MetatagGroup( - * id = "{{ plugin_id }}", - * label = @Translation("{{ label }}"), - * description = @Translation("{{ description }}"), - * weight = {{ weight }}, - * ) - */ -class {{ class_name }} extends {{ base_class }} {% endblock %} diff --git a/web/modules/metatag/templates/metatag_tag.schema.yml.twig b/web/modules/metatag/templates/metatag_tag.schema.yml.twig deleted file mode 100644 index d5e23275976f0966d630d8e45388ddfc3655e157..0000000000000000000000000000000000000000 --- a/web/modules/metatag/templates/metatag_tag.schema.yml.twig +++ /dev/null @@ -1,3 +0,0 @@ -metatag.metatag_tag.{{ plugin_id }}: - type: label - label: '{{ label }}' diff --git a/web/modules/metatag/templates/tag.php.twig b/web/modules/metatag/templates/tag.php.twig deleted file mode 100644 index f990b4be6fce5cdea92afa2e270fabb65951afed..0000000000000000000000000000000000000000 --- a/web/modules/metatag/templates/tag.php.twig +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "generator.php.twig" %} - -{% block prefix %}{{ prefix }} -{% endblock %} - -{% block namespace_class %} -namespace Drupal\{{ module }}\Plugin\metatag\Tag; -{% endblock %} - -{% block use_class %} -use Drupal\metatag\Plugin\metatag\Tag\{{ base_class }}; -{% endblock %} - -{% block class_declaration %} -/** - * Provides a plugin for the '{{ name }}' meta tag. - * - * @MetatagTag( - * id = "{{ plugin_id }}", - * label = @Translation("{{ label }}"), - * description = @Translation("{{ description }}"), - * name = "{{ name }}", - * group = "{{ group }}", - * weight = {{ weight }}, - * type = "{{ type }}", - * secure = {{ secure }}, - * multiple = {{ multiple }} - * ) - */ -class {{ class_name }} extends {{ base_class }} {% endblock %} diff --git a/web/modules/metatag/tests/fixtures/d7_metatag.php b/web/modules/metatag/tests/fixtures/d7_metatag.php index ebfd3e0184df80491c6703b48582e6b9188788b6..c6adbc17f1a245461793f6b46509215451b9d69e 100644 --- a/web/modules/metatag/tests/fixtures/d7_metatag.php +++ b/web/modules/metatag/tests/fixtures/d7_metatag.php @@ -125,6 +125,7 @@ 'data' => serialize([ 'keywords' => ['value' => 'a user'], 'canonical' => ['value' => 'the-user'], + 'description' => ['value' => 'Drupal' . chr(0x99) . ' user'], ]), ]) ->values([ diff --git a/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.info.yml b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.info.yml index 9d53e177698de88e6463341ee22f3845307a1f89..050fe6fb17e255c1c42052a8bdd49c49a30b2305 100644 --- a/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.info.yml +++ b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.info.yml @@ -1,12 +1,11 @@ name: "Metatag: Test Custom Route" type: module description: Support module for testing handling of a custom route that only inherits the global configuration. -core_version_requirement: '^8.7.7 || ^9' package: Testing dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.module b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.module index 3c6ed8a85a5a8e578a8f50f99ab22ee0c0c7fbc5..df8929053d605c3db3723b0b5c33f39cc7a67955 100644 --- a/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.module +++ b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Implements hook_help(). @@ -15,8 +16,8 @@ function metatag_test_custom_route_help($route_name, RouteMatchInterface $route_ // Main module help for the metatag_test_custom_route module. case 'help.page.metatag_test_custom_route': $output = ''; - $output .= '<h3>' . t('About') . '</h3>'; - $output .= '<p>' . t('Support module for testing handling of a custom route.') . '</p>'; + $output .= '<h3>' . (string) new TranslatableMarkup('About') . '</h3>'; + $output .= '<p>' . (string) new TranslatableMarkup('Support module for testing handling of a custom route.') . '</p>'; return $output; default: diff --git a/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.info.yml b/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.info.yml index faf3cf0561c6cb8963a27918d57a28ceb37f5fdc..b7661b73e8be538a48e5eac4a2d1b29f51ffc377 100644 --- a/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.info.yml +++ b/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.info.yml @@ -5,7 +5,7 @@ package: Testing dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.module b/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.module index 42b8eae763b3391af664167d3be915b741bee5d9..bf668758ed61e031ef9786443be341fb39616c01 100644 --- a/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.module +++ b/web/modules/metatag/tests/modules/metatag_test_integration/metatag_test_integration.module @@ -10,9 +10,7 @@ */ function metatag_test_integration_metatags_attachments_alter(array &$attachments) { $title = "This is the title I want | [site:name] | Yeah!"; - if (isset($title)) { - _metatag_test_integration_replace_tag('title', \Drupal::token()->replace($title), $attachments); - } + _metatag_test_integration_replace_tag('title', \Drupal::token()->replace($title), $attachments); } /** diff --git a/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.info.yml b/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.info.yml index 12d764ca311f446836508f00e05e1344313d4bc2..7eb0910029eac253deec7856e6887987657e4028 100644 --- a/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.info.yml +++ b/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.info.yml @@ -1,12 +1,11 @@ name: 'Metatag Tests: Tag' type: module description: 'Support module for testing handling of a custom meta tag.' -core_version_requirement: '^8.7.7 || ^9' package: Testing dependencies: - metatag:metatag -# Information added by Drupal.org packaging script on 2021-03-15 -version: '8.x-1.16' +# Information added by Drupal.org packaging script on 2022-09-29 +version: '8.x-1.22' project: 'metatag' -datestamp: 1615820871 +datestamp: 1664472821 diff --git a/web/modules/metatag/tests/src/Functional/DefaultTags.php b/web/modules/metatag/tests/src/Functional/DefaultTags.php index 6375b2530e334a73de47a15bc01380d2548152ca..279fbaca46479651df9cce79ce56955f9df51ad2 100644 --- a/web/modules/metatag/tests/src/Functional/DefaultTags.php +++ b/web/modules/metatag/tests/src/Functional/DefaultTags.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\metatag\Functional; use Drupal\Tests\BrowserTestBase; +use Drupal\user\Entity\User; /** * Verify that the configured defaults load as intended. @@ -44,7 +45,7 @@ class DefaultTags extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Set the front page to the main /node page, so that the front page is not @@ -61,6 +62,7 @@ protected function setUp() { public function testFrontpage() { $this->drupalGet('<front>'); $this->assertSession()->statusCodeEquals(200); + // @todo Expand this selection to cover additional meta tags. $xpath = $this->xpath("//link[@rel='canonical']"); $this_page_url = $this->buildUrl('<front>'); self::assertEquals((string) $xpath[0]->getAttribute('href'), $this_page_url); @@ -75,6 +77,7 @@ public function testCustomRoute() { $this->assertSession()->pageTextContains('Hello world!'); // Check the meta tags. + // @todo Expand this selection to cover additional meta tags. $xpath = $this->xpath("//link[@rel='canonical']"); $this_page_url = $this->buildUrl('/metatag_test_custom_route'); self::assertEquals((string) $xpath[0]->getAttribute('href'), $this_page_url); @@ -92,6 +95,7 @@ public function testNode() { $this->assertSession()->statusCodeEquals(200); // Check the meta tags. + // @todo Expand this selection to cover additional meta tags. $xpath = $this->xpath("//link[@rel='canonical']"); self::assertEquals((string) $xpath[0]->getAttribute('href'), $this_page_url); } @@ -107,6 +111,7 @@ public function testTerm() { $this->assertSession()->statusCodeEquals(200); // Check the meta tags. + // @todo Expand this selection to cover additional meta tags. $xpath = $this->xpath("//link[@rel='canonical']"); self::assertEquals((string) $xpath[0]->getAttribute('href'), $this_page_url); } @@ -115,15 +120,16 @@ public function testTerm() { * Test the default values for a User entity. */ public function testUser() { - $this->loginUser1(); - $account = \Drupal::currentUser()->getAccount(); + // Log in as user 1. + $account = $this->loginUser1(); $this_page_url = $account->toUrl('canonical', ['absolute' => TRUE])->toString(); - // Load the user's entity page. + // Load the user/1 entity page. $this->drupalGet($this_page_url); $this->assertSession()->statusCodeEquals(200); // Check the meta tags. + // @todo Expand this selection to cover additional meta tags. $xpath = $this->xpath("//link[@rel='canonical']"); self::assertEquals((string) $xpath[0]->getAttribute('href'), $this_page_url); $this->drupalLogout(); @@ -133,7 +139,7 @@ public function testUser() { * Test the default values for the user login page, etc. */ public function testUserLoginPages() { - $front_url = $this->buildUrl('<front>', ['absolute' => TRUE]);; + $front_url = $this->buildUrl('<front>', ['absolute' => TRUE]); // A list of paths to examine. $routes = [ @@ -152,6 +158,7 @@ public function testUserLoginPages() { $this->assertSession()->statusCodeEquals(200); // Check the meta tags. + // @todo Expand this selection to cover additional meta tags. $xpath = $this->xpath("//link[@rel='canonical']"); $this->assertNotEquals((string) $xpath[0]->getAttribute('href'), $front_url); self::assertEquals((string) $xpath[0]->getAttribute('href'), $this_page_url); diff --git a/web/modules/metatag/tests/src/Functional/DisabledDefaultTags.php b/web/modules/metatag/tests/src/Functional/DisabledDefaultTags.php index 52a23c189a27f60e039780284af0eda7c2f3dce9..473fdf7ec258861e5728321aad07d0d3953bd6d6 100644 --- a/web/modules/metatag/tests/src/Functional/DisabledDefaultTags.php +++ b/web/modules/metatag/tests/src/Functional/DisabledDefaultTags.php @@ -44,7 +44,7 @@ class DisabledDefaultTags extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Set the front page to the main /node page, so that the front page is not @@ -71,7 +71,6 @@ protected function loadMetatagDefault($id) { /** @var \Drupal\Core\Entity\EntityStorageInterface $global_metatag_manager */ $global_metatag_manager = \Drupal::entityTypeManager() ->getStorage('metatag_defaults'); - /** @var \Drupal\metatag\Entity\MetatagDefaults $entity_metatags */ return $global_metatag_manager->load($id); } @@ -79,6 +78,7 @@ protected function loadMetatagDefault($id) { * Test that a disabled Frontpage metatag default doesn't load. */ public function testFrontpage() { + /** @var \Drupal\metatag\Entity\MetatagDefaults $metatag */ $metatag = $this->loadMetatagDefault('front'); $metatag->overwriteTags(['canonical_url' => 'https://test.canonical']); $metatag->save(); @@ -106,6 +106,7 @@ public function testFrontpage() { * Test that a disabled 404 metatag default doesn't load. */ public function test404() { + /** @var \Drupal\metatag\Entity\MetatagDefaults $metatag */ $metatag = $this->loadMetatagDefault('404'); $metatag->overwriteTags(['canonical_url' => 'https://test.canonical']); $metatag->save(); @@ -133,6 +134,7 @@ public function test404() { * Test that a disabled 403 metatag default doesn't load. */ public function test403() { + /** @var \Drupal\metatag\Entity\MetatagDefaults $metatag */ $metatag = $this->loadMetatagDefault('403'); $metatag->overwriteTags(['canonical_url' => 'https://test.canonical']); $metatag->save(); diff --git a/web/modules/metatag/tests/src/Functional/EnsureDevelWebProfilerWorks.php b/web/modules/metatag/tests/src/Functional/EnsureDevelWebProfilerWorks.php index 901dc0d045bf9317b2f027e8f8ab43dc9624df84..015f810a3858879aeb6b33ffceb80202705e2c2a 100644 --- a/web/modules/metatag/tests/src/Functional/EnsureDevelWebProfilerWorks.php +++ b/web/modules/metatag/tests/src/Functional/EnsureDevelWebProfilerWorks.php @@ -12,7 +12,7 @@ class EnsureDevelWebProfilerWorks extends EnsureDevelWorks { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Modules for core functionality. 'node', 'field', diff --git a/web/modules/metatag/tests/src/Functional/EnsureDevelWorks.php b/web/modules/metatag/tests/src/Functional/EnsureDevelWorks.php index 7fb43a271b99d51d582f2be9e86e2d764ed28d45..9a492900d6e2a66ac0bd1d2f06c3a0b03d0bc7d3 100644 --- a/web/modules/metatag/tests/src/Functional/EnsureDevelWorks.php +++ b/web/modules/metatag/tests/src/Functional/EnsureDevelWorks.php @@ -22,7 +22,7 @@ class EnsureDevelWorks extends BrowserTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Modules for core functionality. 'node', 'field', @@ -47,8 +47,8 @@ class EnsureDevelWorks extends BrowserTestBase { */ public function testCustomRoute() { $this->drupalGet('metatag_test_custom_route'); - $this->assertResponse(200); - $this->assertText('Hello world!'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Hello world!'); } /** @@ -57,7 +57,7 @@ public function testCustomRoute() { public function testNode() { $node = $this->createContentTypeNode(); $this->drupalGet($node->toUrl()); - $this->assertResponse(200); + $this->assertSession()->statusCodeEquals(200); } } diff --git a/web/modules/metatag/tests/src/Functional/LanguageHandlingTest.php b/web/modules/metatag/tests/src/Functional/LanguageHandlingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..28e5b20311009f8b952d9c9df726f06a3132e32e --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/LanguageHandlingTest.php @@ -0,0 +1,116 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\Tests\BrowserTestBase; +use Drupal\user\Entity\User; +use Drupal\Tests\Traits\Core\PathAliasTestTrait; + +/** + * Testing the language handling. + * + * @group metatag + */ +class LanguageHandlingTest extends BrowserTestBase { + + use PathAliasTestTrait; + + /** + * The admin user. + * + * @var \Drupal\user\Entity\User + */ + protected $adminAccount; + + /** + * Modules to enable. + * + * @var array + */ + protected static $modules = [ + 'node', + 'locale', + 'path_alias', + 'path', + 'token', + 'metatag', + ]; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->drupalCreateContentType(['type' => 'article']); + + // Setup admin user. + $this->adminAccount = $this->drupalCreateUser([ + 'access administration pages', + 'access content', + 'administer languages', + 'administer url aliases', + 'create article content', + 'edit any article content', + 'edit own article content', + ]); + + $this->drupalLogin($this->adminAccount); + + // Add the German language. + $this->drupalGet('admin/config/regional/language/add'); + $this->submitForm(['predefined_langcode' => 'de'], 'Add language'); + $this->assertSession()->pageTextContains('The language German has been created and can now be used.'); + + // Set admin user language to German. + $this->adminAccount->set('preferred_langcode', 'de')->save(); + + // Set up detection and selection to not use URL detection. + $this->drupalGet('admin/config/regional/language/detection'); + $this->submitForm([ + 'language_interface[enabled][language-url]' => 0, + 'language_interface[enabled][language-user]' => 1, + ], 'Save settings'); + + $this->assertSession()->pageTextContains('Language detection configuration saved.'); + + $this->drupalLogout(); + } + + /** + * Tests URL aliases work. + */ + public function testPathAlias() { + // Login as admin with German as site language. + $this->drupalLogin($this->adminAccount); + + // Create article with alias in sites default language (English). + $this->drupalGet('node/add/article'); + $this->assertSession()->statusCodeEquals(200); + $alias = '/test-content'; + $edit = [ + 'path[0][alias]' => $alias, + 'title[0][value]' => 'Test content', + ]; + $this->submitForm($edit, 'Save'); + + // Check that article was created and check address. + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->addressEquals($alias); + + // Test that the canonical link is the same as address. + $xpath = $this->assertSession()->buildXPathQuery("//link[@rel=:rel and contains(@href, :href)]", [ + ':href' => $alias, + ':rel' => 'canonical', + ]); + $links = $this->getSession()->getPage()->findAll('xpath', $xpath); + + $this->assertNotEmpty($links); + } + +} diff --git a/web/modules/metatag/tests/src/Functional/MetatagAdminTest.php b/web/modules/metatag/tests/src/Functional/MetatagAdminTest.php index 867e0c30560fa61c065f1b283a7453c5936d5564..9e450cd69ec432fe2f8d1a471a01d7d6e700eb89 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagAdminTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagAdminTest.php @@ -53,7 +53,7 @@ class MetatagAdminTest extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Use the test page as the front page. @@ -99,7 +99,7 @@ public function testDefaults() { // entity. $this->drupalGet('admin/config/search/metatag/global'); $session->statusCodeEquals(200); - $this->assertFieldById('edit-title', $metatag_defaults->get('title'), $this->t('Metatag defaults were injected into the Global configuration entity.')); + $this->assertSession()->fieldExists('edit-title', $metatag_defaults->get('title')); // Update the Global defaults and test them. $this->drupalGet('admin/config/search/metatag/global'); $session->statusCodeEquals(200); @@ -107,12 +107,12 @@ public function testDefaults() { 'title' => 'Test title', 'description' => 'Test description', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); $this->drupalGet('hit-a-404'); $session->statusCodeEquals(404); - foreach ($values as $metatag => $value) { - $session->responseContains($value, $this->t('Updated metatag @tag was found in the HEAD section of the page.', ['@tag' => $metatag])); + foreach ($values as $value) { + $session->responseContains($value); } // Check that tokens are processed. @@ -122,14 +122,14 @@ public function testDefaults() { 'title' => '[site:name] | Test title', 'description' => '[site:name] | Test description', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); drupal_flush_all_caches(); $this->drupalGet('hit-a-404'); $session->statusCodeEquals(404); foreach ($values as $metatag => $value) { $processed_value = \Drupal::token()->replace($value); - $session->responseContains($processed_value, $this->t('Processed token for metatag @tag was found in the HEAD section of the page.', ['@tag' => $metatag])); + $session->responseContains($processed_value); } // Test the Robots plugin. @@ -140,7 +140,7 @@ public function testDefaults() { foreach ($robots_values as $value) { $values['robots[' . $value . ']'] = TRUE; } - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); drupal_flush_all_caches(); @@ -148,12 +148,12 @@ public function testDefaults() { $this->drupalGet('hit-a-404'); $session->statusCodeEquals(404); $robots_value = implode(', ', $robots_values); - $session->responseContains($robots_value, $this->t('Robots metatag has the expected values.')); + $session->responseContains($robots_value); // Test reverting global configuration to its defaults. $this->drupalGet('admin/config/search/metatag/global/revert'); $session->statusCodeEquals(200); - $this->drupalPostForm(NULL, [], 'Revert'); + $this->submitForm([], 'Revert'); $session->pageTextContains('Reverted Global defaults.'); $session->pageTextContains($default_title); @@ -214,11 +214,11 @@ public function testSpecialPages() { $values = [ 'description' => 'Front page description', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Front page Metatag defaults.'); $this->drupalGet('<front>'); $session->statusCodeEquals(200); - $session->responseContains($values['description'], $this->t('Front page defaults are used at the front page.')); + $session->responseContains($values['description']); // Adjust the 403 page and test it. $this->drupalGet('admin/config/search/metatag/403'); @@ -226,12 +226,12 @@ public function testSpecialPages() { $values = [ 'description' => '403 page description.', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the 403 access denied Metatag defaults.'); $this->drupalLogout(); $this->drupalGet('admin/config/search/metatag'); $session->statusCodeEquals(403); - $session->responseContains($values['description'], $this->t('403 page defaults are used at 403 pages.')); + $session->responseContains($values['description']); // Adjust the 404 page and test it. $this->drupalLogin($account); @@ -240,11 +240,11 @@ public function testSpecialPages() { $values = [ 'description' => '404 page description.', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the 404 page not found Metatag defaults.'); $this->drupalGet('foo'); $session->statusCodeEquals(404); - $session->responseContains($values['description'], $this->t('404 page defaults are used at 404 pages.')); + $session->responseContains($values['description']); $this->drupalLogout(); } @@ -273,7 +273,7 @@ public function testOverrides() { 'title' => 'Test title for a node.', 'description' => 'Test description for a node.', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Content Metatag defaults.'); // Create a test node. @@ -285,8 +285,8 @@ public function testOverrides() { // Check that the new values are found in the response. $this->drupalGet('node/' . $node->id()); $session->statusCodeEquals(200); - foreach ($values as $metatag => $value) { - $session->responseContains($value, $this->t('Node metatag @tag overrides Global defaults.', ['@tag' => $metatag])); + foreach ($values as $value) { + $session->responseContains($value); } // Check that when the node defaults don't define a metatag, the Global one @@ -298,7 +298,7 @@ public function testOverrides() { 'title' => '', 'description' => '', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Content Metatag defaults.'); // Then, set global ones. @@ -308,7 +308,7 @@ public function testOverrides() { 'title' => 'Global title', 'description' => 'Global description', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); // Next, test that global defaults are rendered since node ones are empty. @@ -323,8 +323,8 @@ public function testOverrides() { ]); $this->drupalGet('node/' . $node->id()); $session->statusCodeEquals(200); - foreach ($values as $metatag => $value) { - $session->responseContains($value, $this->t('Found global @tag tag as Node does not set it.', ['@tag' => $metatag])); + foreach ($values as $value) { + $session->responseContains($value); } // Now create article overrides and then test them. @@ -335,7 +335,7 @@ public function testOverrides() { 'title' => 'Article title override', 'description' => 'Article description override', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains(strip_tags('Created the Content: Article Metatag defaults.')); // Confirm the fields load properly on the node/add/article page. @@ -346,14 +346,14 @@ public function testOverrides() { $this->drupalGet('node/' . $node->id()); $session->statusCodeEquals(200); unset($values['id']); - foreach ($values as $metatag => $value) { - $session->responseContains($value, $this->t('Found bundle override for tag @tag.', ['@tag' => $metatag])); + foreach ($values as $value) { + $session->responseContains($value); } // Test deleting the article defaults. $this->drupalGet('admin/config/search/metatag/node__article/delete'); $session->statusCodeEquals(200); - $this->drupalPostForm(NULL, [], 'Delete'); + $this->submitForm([], 'Delete'); $session->pageTextContains('Deleted Content: Article defaults.'); } @@ -387,10 +387,10 @@ public function testEntityDefaultInheritence() { 'label' => 'Meta tags', 'field_name' => 'meta_tags', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save and continue')); - $this->drupalPostForm(NULL, [], $this->t('Save field settings')); + $this->submitForm($edit, $this->t('Save and continue')); + $this->submitForm([], $this->t('Save field settings')); $session->pageTextContains(strip_tags('Updated field Meta tags field settings.')); - $this->drupalPostForm(NULL, [], $this->t('Save settings')); + $this->submitForm([], $this->t('Save settings')); $session->pageTextContains(strip_tags('Saved Meta tags configuration.')); // Try creating an article, confirm the fields are present. This should be @@ -408,7 +408,7 @@ public function testEntityDefaultInheritence() { 'title' => 'Article title override', 'description' => 'Article description override', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains(strip_tags('Created the Content: Article Metatag defaults.')); // Try creating an article, this time with the overridden defaults. @@ -432,7 +432,8 @@ public function testDefaultProtected() { $edit = [ 'id' => 'node__article', ]; - $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + $this->drupalGet('/admin/config/search/metatag/add'); + $this->submitForm($edit, 'Save'); // Check that protected defaults contains "Revert" link instead of "Delete". foreach (MetatagManager::protectedDefaults() as $protected) { @@ -507,4 +508,39 @@ public function testListPager() { $session->linkByHrefExists('/admin/config/search/metatag/user'); } + /** + * Tests for the trim config. + */ + public function testTrimSettings() { + $this->loginUser1(); + $this->drupalGet('/admin/config/search/metatag/settings'); + $session = $this->assertSession(); + $page = $this->getSession()->getPage(); + $session->statusCodeEquals(200); + // Test if option for a metatag that shouldn't be trimmable exists: + $session->pageTextNotContains('Meta Tags: robots length'); + // Test if option for a trimmable metatag exists: + $session->pageTextContains('Meta Tags: description length'); + // Test if the title,abstract and description header gets trimmed: + // Change description abstract and title on the front page: + $this->drupalGet('/admin/config/search/metatag/front'); + $page->fillField('edit-title', 'my wonderful drupal test site'); + $page->fillField('edit-description', '[site:name] [site:slogan] [random:number]'); + $page->fillField('edit-abstract', 'my wonderful drupal test site abstract'); + $page->pressButton('edit-submit'); + // Set the new trim settings: + $this->drupalGet('/admin/config/search/metatag/settings'); + $page->fillField('edit-tag-trim-maxlength-metatag-maxlength-description', '5'); + $page->fillField('edit-tag-trim-maxlength-metatag-maxlength-title', '5'); + $page->fillField('edit-tag-trim-maxlength-metatag-maxlength-abstract', '5'); + $page->fillField('edit-tag-trim-tag-trim-method', 'afterValue'); + $page->pressButton('edit-submit'); + // See if on the front page the metatags are correctly trimmed: + $this->drupalGet(''); + $session->statusCodeEquals(200); + $session->titleEquals('my wonderful'); + $session->elementAttributeContains('css', 'meta[name=description]', 'content', 'Drupal'); + $session->elementAttributeContains('css', 'meta[name=abstract]', 'content', 'my wonderful'); + } + } diff --git a/web/modules/metatag/tests/src/Functional/MetatagConfigTranslationTest.php b/web/modules/metatag/tests/src/Functional/MetatagConfigTranslationTest.php index 43388a082b22e9a3aa6de8d564ecc9dceab39dd7..32fab439d7dffc1329d83b835a6a7bb8383d3a30 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagConfigTranslationTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagConfigTranslationTest.php @@ -67,7 +67,7 @@ class MetatagConfigTranslationTest extends BrowserTestBase { /** * Sets the test up. */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->adminUser = $this->drupalCreateUser($this->permissions); $this->drupalLogin($this->adminUser); @@ -107,13 +107,12 @@ public function testConfigTranslationsExist() { // Confirm that each config translation page can be loaded. foreach ($defaults as $config_name) { - if ($config_entity = $config_manager->loadConfigEntityByName($config_name)) { + $config_entity = $config_manager->loadConfigEntityByName($config_name); + $this->assertNotNull($config_entity); + if (!empty($config_entity)) { $this->drupalGet('admin/config/search/metatag/' . $config_entity->id() . '/translate'); $session->statusCodeEquals(200); } - else { - $this->error('Unable to load a Metatag default config: ' . $config_name); - } } } @@ -129,7 +128,7 @@ public function testConfigTranslations() { 'title' => 'Test title', 'description' => 'Test description', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save')); + $this->submitForm($edit, $this->t('Save')); $session->statusCodeEquals(200); $session->pageTextContains('Saved the Global Metatag defaults.'); @@ -154,7 +153,7 @@ public function testConfigTranslations() { 'translation[config_names][metatag.metatag_defaults.global][tags][title]' => 'Le title', 'translation[config_names][metatag.metatag_defaults.global][tags][description]' => 'Le description', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save translation')); + $this->submitForm($edit, $this->t('Save translation')); $session->statusCodeEquals(200); $session->pageTextContains('Successfully saved French translation'); diff --git a/web/modules/metatag/tests/src/Functional/MetatagFieldNodeTest.php b/web/modules/metatag/tests/src/Functional/MetatagFieldNodeTest.php index 24645aeda73dbee16feb1f847f0577147c1ec747..2d850a5ea4c5d832d500d87d58da6e1f45f3fa1e 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagFieldNodeTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagFieldNodeTest.php @@ -79,11 +79,6 @@ class MetatagFieldNodeTest extends MetatagFieldTestBase { */ protected function setUpEntityType() { $this->createContentType(['type' => 'page']); - - // 8.3 has the label 'Save and publish'. - if ((floatval(\Drupal::VERSION) <= 8.3)) { - $this->entitySaveButtonLabel = 'Save and publish'; - } } } diff --git a/web/modules/metatag/tests/src/Functional/MetatagFieldTermTest.php b/web/modules/metatag/tests/src/Functional/MetatagFieldTermTest.php index 9ffa9f7e851eefb2ee56774cc3687c6f3d2c5d53..51a094e53817bddc2af96412257af485eb418ba4 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagFieldTermTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagFieldTermTest.php @@ -96,7 +96,7 @@ protected function setUpEntityType() { 'name' => 'Tags', 'vid' => 'tags', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save')); + $this->submitForm($edit, $this->t('Save')); $this->drupalLogout(); } diff --git a/web/modules/metatag/tests/src/Functional/MetatagFieldTestBase.php b/web/modules/metatag/tests/src/Functional/MetatagFieldTestBase.php index f84239fa1ed9cb3f14daefa75fa04e537f4d7527..ca6f1d3342184f804d8599aba7b07672eaef4c6b 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagFieldTestBase.php +++ b/web/modules/metatag/tests/src/Functional/MetatagFieldTestBase.php @@ -2,9 +2,10 @@ namespace Drupal\Tests\metatag\Functional; +use Drupal\Component\Utility\Html; use Drupal\Core\Cache\Cache; -use Drupal\Tests\BrowserTestBase; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Tests\BrowserTestBase; /** * Base class for ensuring that the Metatag field works correctly. @@ -131,7 +132,7 @@ abstract class MetatagFieldTestBase extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Any additional configuration that's neede for this entity type. @@ -146,23 +147,6 @@ protected function setUp() { $this->drupalLogin($this->adminUser); } - /** - * {@inheritdoc} - */ - protected function verbose($message, $title = NULL) { - // Handle arrays, objects, etc. - if (!is_string($message)) { - $message = "<pre>\n" . print_r($message, TRUE) . "\n</pre>\n"; - } - - // Optional title to go before the output. - if (!empty($title)) { - $title = '<h2>' . Html::escape($title) . "</h2>\n"; - } - - parent::verbose($title . $message); - } - /** * Any additional configuration that's needed for this entity type. */ @@ -171,13 +155,13 @@ protected function setUpEntityType() {} /** * A list of default values to add to the entity being created. * - * Defaults to "{$entityTitleField}[0][value]" => $title. - * * @return array * Default values. */ - protected function entityDefaultValues() { - return []; + protected function entityDefaultValues($title = 'Barfoo') { + return [ + $this->entityTitleField . '[0][value]' => $title, + ]; } /** @@ -192,8 +176,8 @@ protected function addField() { 'field_name' => 'metatag', 'new_storage_type' => 'metatag', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save and continue')); - $this->drupalPostForm(NULL, [], $this->t('Save field settings')); + $this->submitForm($edit, $this->t('Save and continue')); + $this->submitForm([], $this->t('Save field settings')); // Clear all settings. $this->container->get('entity_field.manager')->clearCachedFieldDefinitions(); @@ -212,7 +196,7 @@ public function testGlobalDefaultsInheritance() { $global_values = [ 'metatag_test_tag' => 'Global description', ]; - $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->submitForm($global_values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); // Add the field to this entity type. @@ -241,7 +225,7 @@ public function testEntityDefaultsInheritance() { $global_values = [ 'metatag_test_tag' => 'Global description', ]; - $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->submitForm($global_values, 'Save'); $session->pageTextContains(strip_tags('Saved the Global Metatag defaults.')); // Set an entity default. @@ -250,7 +234,7 @@ public function testEntityDefaultsInheritance() { $entity_values = [ 'metatag_test_tag' => 'Entity description', ]; - $this->drupalPostForm(NULL, $entity_values, 'Save'); + $this->submitForm($entity_values, 'Save'); $session->pageTextContains(strip_tags("Saved the $this->entityLabel Metatag defaults.")); // Add the field to this entity type. @@ -262,13 +246,7 @@ public function testEntityDefaultsInheritance() { $session->pageTextNotContains('Fatal error'); // Allow the fields to be customized if needed. - $title = 'Barfoo'; - $edit = $this->entityDefaultValues(); - if (empty($edit)) { - $edit = [ - $this->entityTitleField . '[0][value]' => $title, - ]; - } + $edit = $this->entityDefaultValues('Barfoo'); // If this entity type supports defaults then verify the global default is // not present but that the entity default *is* present. @@ -281,7 +259,7 @@ public function testEntityDefaultsInheritance() { * * When there is no field for overriding the defaults. * - * @todo + * @todo Write this. */ public function testBundleDefaultsInheritance() { } @@ -324,17 +302,18 @@ public function testEntityFieldValuesOldEntity() { $global_values = [ 'metatag_test_tag' => 'Global description', ]; - $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->submitForm($global_values, 'Save'); $session->pageTextContains(strip_tags('Saved the Global Metatag defaults.')); // Set an entity default if it's supported by the entity type. + $entity_values = []; if ($this->entitySupportsDefaults) { $this->drupalGet('admin/config/search/metatag/' . $this->entityType); $session->statusCodeEquals(200); $entity_values = [ 'metatag_test_tag' => 'Entity description', ]; - $this->drupalPostForm(NULL, $entity_values, 'Save'); + $this->submitForm($entity_values, 'Save'); $session->pageTextContains(strip_tags("Saved the $this->entityLabel Metatag defaults.")); } @@ -345,15 +324,10 @@ public function testEntityFieldValuesOldEntity() { $session->pageTextNotContains('Fatal error'); // Allow the fields to be customized if needed. - $edit = $this->entityDefaultValues(); - if (empty($edit)) { - $edit = [ - $this->entityTitleField . '[0][value]' => $title, - ]; - } + $edit = $this->entityDefaultValues($title); // Create a new entity object. - $this->drupalPostForm(NULL, $edit, $this->t($this->entitySaveButtonLabel)); + $this->submitForm($edit, $this->entitySaveButtonLabel); $entities = \Drupal::entityTypeManager() ->getStorage($this->entityType) ->loadByProperties([$this->entityTitleField => $title]); @@ -375,6 +349,7 @@ public function testEntityFieldValuesOldEntity() { $session->fieldValueEquals('field_metatag[0][basic][metatag_test_tag]', $entity_values['metatag_test_tag']); } else { + // @todo This won't work. $session->fieldValueEquals('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); } @@ -394,17 +369,17 @@ public function testEntityFieldValuesNewEntity() { $global_values = [ 'metatag_test_tag' => 'Global description', ]; - $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->submitForm($global_values, 'Save'); $session->pageTextContains(strip_tags('Saved the Global Metatag defaults.')); // Set an entity default if it's supported by the entity type. + $entity_values = [ + 'metatag_test_tag' => 'Entity description', + ]; if ($this->entitySupportsDefaults) { $this->drupalGet('admin/config/search/metatag/' . $this->entityType); $session->statusCodeEquals(200); - $entity_values = [ - 'metatag_test_tag' => 'Entity description', - ]; - $this->drupalPostForm(NULL, $entity_values, 'Save'); + $this->submitForm($entity_values, 'Save'); $session->pageTextContains(strip_tags("Saved the $this->entityLabel Metatag defaults.")); } @@ -428,15 +403,10 @@ public function testEntityFieldValuesNewEntity() { } // Allow the fields to be customized if needed. - $edit = $this->entityDefaultValues(); - if (empty($edit)) { - $edit = [ - $this->entityTitleField . '[0][value]' => $title, - ]; - } + $edit = $this->entityDefaultValues($title); // Create a new entity object. - $this->drupalPostForm(NULL, $edit, $this->t($this->entitySaveButtonLabel)); + $this->submitForm($edit, $this->entitySaveButtonLabel); $entities = \Drupal::entityTypeManager() ->getStorage($this->entityType) ->loadByProperties([$this->entityTitleField => $title]); @@ -475,10 +445,10 @@ public function tofixTestEntityField() { $session = $this->assertSession(); $session->statusCodeEquals(200); $session->pageTextNotContains('Fatal error'); - $edit = $this->entityDefaultValues($title) + [ + $edit = $this->entityDefaultValues() + [ 'field_metatag[0][basic][metatag_test_tag]' => 'Kilimanjaro', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save')); + $this->submitForm($edit, $this->t('Save')); $entities = \Drupal::entityTypeManager() ->getStorage('entity_test') ->loadByProperties([$this->entityTitleField => 'Barfoo']); @@ -503,13 +473,12 @@ public function tofixTestEntityField() { $values = [ 'metatag_test_tag' => 'Purple monkey dishwasher', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); $this->drupalGet($entity->toUrl()); $session->statusCodeEquals(200); $elements = $this->cssSelect('meta[name=metatag_test_tag]'); $this->assertCount(1, $elements, 'Found test metatag from defaults'); - $this->verbose('<pre>' . print_r($elements, TRUE) . '</pre>'); $this->assertEquals((string) $elements[0]['content'], $values['metatag_test_tag']); } diff --git a/web/modules/metatag/tests/src/Functional/MetatagFieldUserTest.php b/web/modules/metatag/tests/src/Functional/MetatagFieldUserTest.php index baa76318a1e3e863f6a4714efd3f084b40c68843..5ffda1b7e4ffed451ad15528e0e06297e49fce0f 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagFieldUserTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagFieldUserTest.php @@ -95,14 +95,14 @@ protected function entityDefaultValues($title = 'Barfoo') { /** * Confirm the metatag field can be shown on a user registration page. * - * @todo + * @todo Write this. */ public function testFieldsOnUserRegistrationForm() {} /** * Confirm the metatag field can be shown on a normal user's own edit form. * - * @todo + * @todo Write this. */ public function testFieldsOnUserEditForm() {} diff --git a/web/modules/metatag/tests/src/Functional/MetatagForumTest.php b/web/modules/metatag/tests/src/Functional/MetatagForumTest.php index a0b1c96df4ded38929a615d90cf0d7505b76cbbd..cc7d528658b18527c891c57fcf2f7060a225e76a 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagForumTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagForumTest.php @@ -37,10 +37,17 @@ class MetatagForumTest extends BrowserTestBase { */ protected $adminUser; + /** + * The nid of a node that is being tested. + * + * @var int + */ + protected $nodeId; + /** * Setup basic environment. */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $admin_permissions = [ @@ -56,7 +63,10 @@ protected function setUp() { $this->drupalLogin($this->adminUser); // Create content type. - $this->drupalCreateContentType(['type' => 'page', 'display_submitted' => FALSE]); + $this->drupalCreateContentType([ + 'type' => 'page', + 'display_submitted' => FALSE, + ]); $this->nodeId = $this->drupalCreateNode( [ 'title' => $this->randomMachineName(8), @@ -78,8 +88,7 @@ public function testForumPost() { 'taxonomy_forums' => 1, 'body[0][value]' => 'Just testing.', ]; - $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); $session->statusCodeEquals(200); $session->pageTextContains('Forum topic Testing forums has been created.'); } diff --git a/web/modules/metatag/tests/src/Functional/MetatagFrontpageTest.php b/web/modules/metatag/tests/src/Functional/MetatagFrontpageTest.php index ae839d1f769c86363b569eed83c51a7b87191c07..9f729f856105cca00b325deb6dcf5aa48c4cb103 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagFrontpageTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagFrontpageTest.php @@ -41,21 +41,26 @@ class MetatagFrontpageTest extends BrowserTestBase { /** * Setup basic environment. */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Login user 1. $this->loginUser1(); // Create content type. - $this->drupalCreateContentType(['type' => 'page', 'display_submitted' => FALSE]); + $this->drupalCreateContentType([ + 'type' => 'page', + 'display_submitted' => FALSE, + ]); $this->nodeId = $this->drupalCreateNode( [ 'title' => $this->randomMachineName(8), 'promote' => 1, ])->id(); - $this->config('system.site')->set('page.front', '/node/' . $this->nodeId)->save(); + $this->config('system.site') + ->set('page.front', '/node/' . $this->nodeId) + ->save(); } /** @@ -71,7 +76,7 @@ public function testFrontPageMetatagsEnabledConfig() { 'description' => 'Test description', 'keywords' => 'testing,keywords', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save')); + $this->submitForm($edit, $this->t('Save')); $session->statusCodeEquals(200); $session->pageTextContains('Saved the Front page Metatag defaults.'); @@ -116,7 +121,7 @@ public function testFrontPageMetatagsEnabledConfig() { ]; $this->drupalGet('admin/config/system/site-information'); $session->statusCodeEquals(200); - $this->drupalPostForm(NULL, $site_edit, $this->t('Save configuration')); + $this->submitForm($site_edit, $this->t('Save configuration')); $session->pageTextContains('The configuration options have been saved.'); return; @@ -139,7 +144,7 @@ public function testFrontPageMetatagDisabledConfig() { $this->drupalGet('admin/config/search/metatag/front/delete'); $session = $this->assertSession(); $session->statusCodeEquals(200); - $this->drupalPostForm(NULL, [], $this->t('Delete')); + $this->submitForm([], $this->t('Delete')); $session->statusCodeEquals(200); $session->pageTextContains('Deleted Front page defaults.'); @@ -150,7 +155,7 @@ public function testFrontPageMetatagDisabledConfig() { 'title' => 'Test title for a node.', 'description' => 'Test description for a node.', ]; - $this->drupalPostForm(NULL, $edit, 'Save'); + $this->submitForm($edit, 'Save'); $session->pageTextContains('Saved the Content Metatag defaults.'); $this->drupalGet('<front>'); foreach ($edit as $metatag => $metatag_value) { @@ -174,7 +179,7 @@ public function testFrontPageMetatagDisabledConfig() { $edit = [ 'site_frontpage' => '/test-page', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save configuration')); + $this->submitForm($edit, $this->t('Save configuration')); $session->pageTextContains('The configuration options have been saved.'); // Front page is custom route. @@ -185,7 +190,7 @@ public function testFrontPageMetatagDisabledConfig() { 'title' => 'Test title.', 'description' => 'Test description.', ]; - $this->drupalPostForm(NULL, $edit, 'Save'); + $this->submitForm($edit, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); // Test Metatags. diff --git a/web/modules/metatag/tests/src/Functional/MetatagHelperTrait.php b/web/modules/metatag/tests/src/Functional/MetatagHelperTrait.php index 84234d62a763f03c4a6b305a1ca6518deb75050e..32a55c83b74433ae1452ebf2831decda94a83fc8 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagHelperTrait.php +++ b/web/modules/metatag/tests/src/Functional/MetatagHelperTrait.php @@ -15,10 +15,13 @@ trait MetatagHelperTrait { /** * Log in as user 1. + * + * @return \Drupal\user\Entity\User + * The full user object for user 1, after logging in. */ protected function loginUser1() { // Load user 1. - /* @var \Drupal\user\Entity\User $account */ + /** @var \Drupal\user\Entity\User $account */ $account = User::load(1); // Reset the password. @@ -31,23 +34,8 @@ protected function loginUser1() { // Login. $this->drupalLogin($account); - } - - /** - * {@inheritdoc} - */ - protected function verbose($message, $title = NULL) { - // Handle arrays, objects, etc. - if (!is_string($message)) { - $message = "<pre>\n" . print_r($message, TRUE) . "\n</pre>\n"; - } - - // Optional title to go before the output. - if (!empty($title)) { - $title = '<h2>' . Html::escape($title) . "</h2>\n"; - } - parent::verbose($title . $message); + return $account; } /** @@ -111,12 +99,7 @@ private function createVocabulary(array $values = []) { $vocab = Vocabulary::create($values); $status = $vocab->save(); - if ($this instanceof \PHPUnit_Framework_TestCase) { - $this->assertSame($status, SAVED_NEW, (new FormattableMarkup('Created vocabulary %type.', ['%type' => $vocab->id()]))->__toString()); - } - else { - self::assertEquals($status, SAVED_NEW, (new FormattableMarkup('Created vocabulary %type.', ['%type' => $vocab->id()]))->__toString()); - } + $this->assertSame($status, SAVED_NEW, (new FormattableMarkup('Created vocabulary %type.', ['%type' => $vocab->id()]))->__toString()); return $vocab; } @@ -127,7 +110,7 @@ private function createVocabulary(array $values = []) { * @param array $values * Items passed to the term. Requires the 'vid' element. * - * @return Drupal\taxonomy\Entity\Term + * @return \Drupal\taxonomy\Entity\Term * A fully formatted term object. */ private function createTerm(array $values = []) { @@ -144,12 +127,7 @@ private function createTerm(array $values = []) { $term = Term::create($values); $status = $term->save(); - if ($this instanceof \PHPUnit_Framework_TestCase) { - $this->assertSame($status, SAVED_NEW, (new FormattableMarkup('Created term %name.', ['%name' => $term->label()]))->__toString()); - } - else { - self::assertEquals($status, SAVED_NEW, (new FormattableMarkup('Created term %name.', ['%name' => $term->label()]))->__toString()); - } + $this->assertSame($status, SAVED_NEW, (new FormattableMarkup('Created term %name.', ['%name' => $term->label()]))->__toString()); return $term; } diff --git a/web/modules/metatag/tests/src/Functional/MetatagNodeTranslationTest.php b/web/modules/metatag/tests/src/Functional/MetatagNodeTranslationTest.php index 01b97cb6f63ee469dde6340c3e7f51c6595f282f..0cfb47a49eeb6cca9e425bf66aee27187c9793e9 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagNodeTranslationTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagNodeTranslationTest.php @@ -56,7 +56,7 @@ class MetatagNodeTranslationTest extends BrowserTestBase { /** * Setup basic environment. */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $admin_permissions = [ @@ -85,14 +85,7 @@ protected function setUp() { * Tests the metatag value translations. */ public function testMetatagValueTranslation() { - if (floatval(\Drupal::VERSION) <= 8.3) { - $save_label = $this->t('Save and publish'); - $save_label_i18n = $this->t('Save and keep published (this translation)'); - } - else { - $save_label = $this->t('Save'); - $save_label_i18n = $this->t('Save (this translation)'); - } + $save_label_i18n = 'Save (this translation)'; // Set up a content type. $name = $this->randomMachineName() . ' ' . $this->randomMachineName(); @@ -109,7 +102,7 @@ public function testMetatagValueTranslation() { 'language_configuration[language_alterable]' => TRUE, 'language_configuration[content_translation]' => TRUE, ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save content type')); + $this->submitForm($edit, $this->t('Save content type')); $session->statusCodeEquals(200); $this->drupalGet('admin/structure/types/manage/metatag_node/fields/add-field'); @@ -119,14 +112,14 @@ public function testMetatagValueTranslation() { 'field_name' => 'meta_tags', 'new_storage_type' => 'metatag', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save and continue')); + $this->submitForm($edit, $this->t('Save and continue')); $session->statusCodeEquals(200); - $this->drupalPostForm(NULL, [], $this->t('Save field settings')); + $this->submitForm([], $this->t('Save field settings')); $session->statusCodeEquals(200); $edit = [ 'translatable' => TRUE, ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save settings')); + $this->submitForm($edit, $this->t('Save settings')); $session->statusCodeEquals(200); $this->drupalGet('admin/structure/types/manage/metatag_node/fields/node.metatag_node.field_meta_tags'); $session->statusCodeEquals(200); @@ -147,7 +140,7 @@ public function testMetatagValueTranslation() { 'title[0][value]' => 'Node Français', 'body[0][value]' => 'French summary.', ]; - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); $session->statusCodeEquals(200); $xpath = $this->xpath("//meta[@name='description']"); @@ -165,7 +158,7 @@ public function testMetatagValueTranslation() { 'title[0][value]' => 'Node Español', 'body[0][value]' => 'Spanish summary.', ]; - $this->drupalPostForm(NULL, $edit, $save_label_i18n); + $this->submitForm($edit, $save_label_i18n); $session->statusCodeEquals(200); $this->drupalGet('es/node/1'); @@ -189,7 +182,7 @@ public function testMetatagValueTranslation() { $edit = [ 'field_meta_tags[0][basic][description]' => 'Overridden French description.', ]; - $this->drupalPostForm(NULL, $edit, $save_label_i18n); + $this->submitForm($edit, $save_label_i18n); $session->statusCodeEquals(200); $xpath = $this->xpath("//meta[@name='description']"); @@ -204,7 +197,7 @@ public function testMetatagValueTranslation() { $edit = [ 'field_meta_tags[0][basic][description]' => 'Overridden Spanish description.', ]; - $this->drupalPostForm(NULL, $edit, $save_label_i18n); + $this->submitForm($edit, $save_label_i18n); $session->statusCodeEquals(200); $xpath = $this->xpath("//meta[@name='description']"); diff --git a/web/modules/metatag/tests/src/Functional/MetatagPanelizerTest.php b/web/modules/metatag/tests/src/Functional/MetatagPanelizerTest.php index 3defee9648942fae192fb7c1b85090cf48129018..d6588851634ccd65ea0302f690d1875fff171edc 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagPanelizerTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagPanelizerTest.php @@ -8,6 +8,10 @@ * Verify that the JSON output from core works as intended. * * @group panelizer_metatag + * + * @deprecated in metatag:8.x-1.22 and is removed from metatag:2.0.0. No replacement is provided. + * + * @see https://www.drupal.org/project/metatag/issues/3305580 */ class MetatagPanelizerTest extends BrowserTestBase { @@ -17,7 +21,7 @@ class MetatagPanelizerTest extends BrowserTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Modules for core functionality. 'node', 'field', @@ -35,15 +39,15 @@ class MetatagPanelizerTest extends BrowserTestBase { /** * {@inheritdoc} */ - protected $defaultTheme = 'bartik'; + protected $defaultTheme = 'claro'; /** * Create an entity, view its JSON output, confirm Metatag data exists. */ public function testPanelizerMetatagPreRender() { - /* @var\Drupal\node\NodeInterface $node */ $title = 'Panelizer Metatag Test Title'; $body = 'Testing JSON output for a content type'; + /** @var \Drupal\node\NodeInterface $node */ $node = $this->createContentTypeNode($title, $body); $url = $node->toUrl(); @@ -53,8 +57,8 @@ public function testPanelizerMetatagPreRender() { $this->drupalLogin($account); // Load the node's page. - $this->drupalPostForm( - 'admin/structure/types/manage/metatag_test/display', + $this->drupalGet('admin/structure/types/manage/metatag_test/display'); + $this->submitForm( ['panelizer[enable]' => TRUE], 'Save' ); diff --git a/web/modules/metatag/tests/src/Functional/MetatagStringTest.php b/web/modules/metatag/tests/src/Functional/MetatagStringTest.php index 35429786732769d23f478a83351aec602996ef9f..a58c8b72b907b3d920f44b5ca843c9b1d6a5fe09 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagStringTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagStringTest.php @@ -58,12 +58,15 @@ class MetatagStringTest extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->adminUser = $this->drupalCreateUser($this->permissions); $this->drupalLogin($this->adminUser); - $this->drupalCreateContentType(['type' => 'page', 'display_submitted' => FALSE]); + $this->drupalCreateContentType([ + 'type' => 'page', + 'display_submitted' => FALSE, + ]); // Add a Metatag field to the content type. $this->drupalGet('admin/structure/types'); @@ -75,8 +78,8 @@ protected function setUp() { 'field_name' => 'metatag_field', 'new_storage_type' => 'metatag', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save and continue')); - $this->drupalPostForm(NULL, [], $this->t('Save field settings')); + $this->submitForm($edit, $this->t('Save and continue')); + $this->submitForm([], $this->t('Save field settings')); $this->container->get('entity_field.manager')->clearCachedFieldDefinitions(); } @@ -134,7 +137,7 @@ public function checkConfig($string) { 'title' => $title_original, 'description' => $desc_original, ]; - $this->drupalPostForm(NULL, $edit, 'Save'); + $this->submitForm($edit, 'Save'); $session->statusCodeEquals(200); $metatag_defaults = \Drupal::config('metatag.metatag_defaults.front'); @@ -161,8 +164,7 @@ public function checkConfig($string) { 'title[0][value]' => $title_original, 'body[0][value]' => $desc_original, ]; - $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); $this->config('system.site')->set('page.front', '/node/1')->save(); @@ -179,9 +181,9 @@ public function checkConfig($string) { // The page title should be HTML encoded; have to do this check manually // because assertRaw() checks the raw HTML, not the parsed strings like // xpath does. - $session->responseContains('<title>' . $title_encoded . '</title>', 'Confirmed the node title tag is available in its encoded format.'); - $session->responseNotContains('<title>' . $title_original . '</title>', 'Confirmed the node title tag is not available in its original format.'); - $session->responseNotContains('<title>' . $title_encodeded . '</title>', 'Confirmed the node title tag is not double-double-encoded?'); + $session->responseContains('<title>' . $title_encoded . '</title>'); + $session->responseNotContains('<title>' . $title_original . '</title>'); + $session->responseNotContains('<title>' . $title_encodeded . '</title>'); // Again, with xpath the HTML entities will be parsed automagically. $xpath = $this->xpath("//meta[@name='description']"); @@ -194,8 +196,6 @@ public function checkConfig($string) { * Tests that a specific node string is not double escaped. */ public function checkNode($string) { - $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); - // The original strings. $title_original = 'Title: ' . $string; $desc_original = 'Description: ' . $string; @@ -216,7 +216,7 @@ public function checkNode($string) { 'title' => $title_original, 'description' => $desc_original, ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save')); + $this->submitForm($edit, $this->t('Save')); $session->statusCodeEquals(200); // Set up a node without explicit metatag description. This causes the @@ -229,7 +229,7 @@ public function checkNode($string) { 'title[0][value]' => $title_original, 'body[0][value]' => $desc_original, ]; - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); $session->statusCodeEquals(200); // Load the node page. @@ -245,7 +245,7 @@ public function checkNode($string) { // The page title should be HTML encoded; have to do this check manually // because assertRaw() checks the raw HTML, not the parsed strings like // xpath does. - $session->responseContains('<title>' . $title_encoded . '</title>', 'Confirmed the node title tag is encoded.'); + $session->responseContains('<title>' . $title_encoded . '</title>'); // Again, with xpath the HTML entities will be parsed automagically. $xpath = $this->xpath("//meta[@name='description']"); $value = $xpath[0]->getAttribute('content'); @@ -254,20 +254,18 @@ public function checkNode($string) { $this->assertNotEquals($value, $desc_encodeded); // Normal meta tags should be encoded properly. - $session->responseContains('"' . $desc_encoded . '"', 'Confirmed the node "description" meta tag string was encoded properly.'); + $session->responseContains('"' . $desc_encoded . '"'); // Normal meta tags with HTML entities should be displayed in their original // format. - $session->responseNotContains('"' . $desc_original . '"', 'Confirmed the node "description" meta tag string does not show in its original form.'); + $session->responseNotContains('"' . $desc_original . '"'); // Normal meta tags should not be double-encoded. - $session->responseNotContains('"' . $desc_encodeded . '"', 'Confirmed the node "description" meta tag string was not double-encoded.'); + $session->responseNotContains('"' . $desc_encodeded . '"'); } /** * Tests that fields with encoded HTML entities will not be double-encoded. */ public function checkEncodedField($string) { - $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); - // The original strings. $title_original = 'Title: ' . $string; $desc_original = 'Description: ' . $string; @@ -286,7 +284,7 @@ public function checkEncodedField($string) { 'title' => $title_original, 'description' => $desc_original, ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save')); + $this->submitForm($edit, $this->t('Save')); $session->statusCodeEquals(200); // Set up a node without explicit metatag description. This causes the @@ -299,7 +297,7 @@ public function checkEncodedField($string) { 'title[0][value]' => $title_original, 'body[0][value]' => $desc_original, ]; - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); $session->statusCodeEquals(200); // Load the node page. @@ -314,14 +312,14 @@ public function checkEncodedField($string) { $this->assertNotEquals($value, $desc_encodeded); // Normal meta tags should be encoded properly. - $session->responseContains('"' . $desc_encoded . '"', 'Confirmed the node "description" meta tag string was encoded properly.'); + $session->responseContains('"' . $desc_encoded . '"'); // Normal meta tags with HTML entities should be displayed in their original // format. - $session->responseNotContains('"' . $desc_original . '"', 'Confirmed the node "description" meta tag string does not show in its original form.'); + $session->responseNotContains('"' . $desc_original . '"'); // Normal meta tags should not be double-encoded. - $session->responseNotContains('"' . $desc_encodeded . '"', 'Confirmed the node "description" meta tag string was not double-encoded.'); + $session->responseNotContains('"' . $desc_encodeded . '"'); } } diff --git a/web/modules/metatag/tests/src/Functional/MetatagTagTypesTest.php b/web/modules/metatag/tests/src/Functional/MetatagTagTypesTest.php index 475e8b148c1e2e148a9cceb6effb9de78f150c41..404f0dbf14a13aded45a459ea0cbdc9cccecdc3b 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagTagTypesTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagTagTypesTest.php @@ -77,7 +77,7 @@ class MetatagTagTypesTest extends BrowserTestBase { /** * Sets the test up. */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->adminUser = $this->drupalCreateUser($this->permissions); $this->drupalLogin($this->adminUser); @@ -90,9 +90,10 @@ protected function setUp() { 'field_name' => 'metatag', 'new_storage_type' => 'metatag', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save and continue')); - $this->drupalPostForm(NULL, [], $this->t('Save field settings')); - $this->container->get('entity_field.manager')->clearCachedFieldDefinitions(); + $this->submitForm($edit, $this->t('Save and continue')); + $this->submitForm([], $this->t('Save field settings')); + $this->container->get('entity_field.manager') + ->clearCachedFieldDefinitions(); } /** @@ -112,15 +113,15 @@ public function testHtmlIsRemoved() { 'keywords' => '<html><body><p class="test">Surrounded by escaped HTML</p></body></html>', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); drupal_flush_all_caches(); $this->drupalGet('hit-a-404'); $session->statusCodeEquals(404); - $session->responseContains('<meta name="abstract" content="No HTML here" />', $this->t('Test with no HTML content')); - $session->responseContains('<meta name="description" content="Surrounded by raw HTML" />', $this->t('Test with raw HTML content')); - $session->responseContains('<meta name="keywords" content="Surrounded by escaped HTML" />', $this->t('Test with escaped HTML content')); + $session->responseContains('<meta name="abstract" content="No HTML here" />'); + $session->responseContains('<meta name="description" content="Surrounded by raw HTML" />'); + $session->responseContains('<meta name="keywords" content="Surrounded by escaped HTML" />'); } /** @@ -139,14 +140,14 @@ public function testSecureTagOption() { 'og_image' => 'https://blahblahblah.com/insecure.jpg', 'og_image_secure_url' => 'https://blahblahblah.com/secure.jpg', ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); drupal_flush_all_caches(); $this->drupalGet(''); $session->statusCodeEquals(200); - $session->responseContains('<meta property="og:image" content="https://blahblahblah.com/insecure.jpg" />', $this->t('Test og:image with regular https:// link')); - $session->responseContains('<meta property="og:image:secure_url" content="https://blahblahblah.com/secure.jpg" />', $this->t('Test og:image:secure_url updated regular https:// link to https://')); + $session->responseContains('<meta property="og:image" content="https://blahblahblah.com/insecure.jpg" />'); + $session->responseContains('<meta property="og:image:secure_url" content="https://blahblahblah.com/secure.jpg" />'); } /** @@ -173,7 +174,7 @@ public function testContactForm() { * @todo Finish. */ public function todoTestUrl() { - // {@code} + // @code // $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); // // Tests meta tags with URLs work. // $this->drupalGet($this->entity_add_path); @@ -183,7 +184,7 @@ public function todoTestUrl() { // 'user_id[0][target_id]' => 'foo (' . $this->adminUser->id() . ')', // 'field_metatag[0][advanced][original_source]' => 'https://example.com/foo.html', // ]; - // $this->drupalPostForm(NULL, $edit, $save_label); + // $this->submitForm($edit, $save_label); // $entities = entity_load_multiple_by_properties('entity_test', [ // 'name' => 'UrlTags', // ]); @@ -194,7 +195,7 @@ public function todoTestUrl() { // $elements = $this->cssSelect("meta[name='original-source']"); // $this->assertTrue(count($elements) === 1, 'Found original source metatag from defaults'); // $this->assertEquals($edit['field_metatag[0][advanced][original_source]'], (string) $elements[0]['content']); - // {@endcode} + // @endcode } } diff --git a/web/modules/metatag/tests/src/Functional/MetatagTagsTest.php b/web/modules/metatag/tests/src/Functional/MetatagTagsTest.php index 09b31628d6e09b80bf126e99dfb5749d18d5353a..25f1aafcf22a0eca02847b291bc874e3dc10c6d1 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagTagsTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagTagsTest.php @@ -14,6 +14,7 @@ class MetatagTagsTest extends MetatagTagsTestBase { */ protected $tags = [ 'abstract', + 'author', 'cache_control', 'canonical_url', 'content_language', @@ -84,20 +85,6 @@ protected function abstractTestFieldXpath() { return "//textarea[@name='abstract']"; } - /** - * Implements {tag_name}TestNameAttribute() for 'author'. - */ - protected function authorTestOutputXpath() { - return "//link[@rel='author']"; - } - - /** - * Implements {tag_name}TestValueAttribute() for 'author'. - */ - protected function authorTestValueAttribute() { - return 'href'; - } - /** * Implements {tag_name}TestNameAttribute() for 'canonical_url'. */ diff --git a/web/modules/metatag/tests/src/Functional/MetatagTagsTestBase.php b/web/modules/metatag/tests/src/Functional/MetatagTagsTestBase.php index d781c8b3229f72b2d0bea2ada3a0a2987e306e8c..ec297cc67114ec058d044370ec8fa644ac53d1fc 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagTagsTestBase.php +++ b/web/modules/metatag/tests/src/Functional/MetatagTagsTestBase.php @@ -69,7 +69,7 @@ abstract class MetatagTagsTestBase extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Use the test page as the front page. @@ -180,9 +180,23 @@ public function testTagsInputOutput($tag_name) { $test_value = $this->randomMachineName() . ' ' . $this->randomMachineName(); } + // Look for a custom method named "{$tagname}TestOutput", if found use + // that method to get the intended output string for this meta tag, + // otherwise it defaults to just using the value submitted on the field. + $method = $this->getMethodFromTagCallback($tag_name, 'TestOutput'); + if (method_exists($this, $method)) { + $test_output = $this->$method($test_value); + } + else { + // By default just use the value that was submitted. + $test_output = $test_value; + } + $values[$test_key] = $test_value; - $all_values[$tag_name] = $test_value; - $this->drupalPostForm(NULL, $values, 'Save'); + $all_values[$tag_name] = $test_output; + $this->submitForm($values, 'Save'); + // Note: if this line fails then check that the failing meta tag has a + // definition in the relevant *.metatag_tag.schema.yml file. $session->pageTextContains($save_message); // Load the test page. @@ -193,9 +207,9 @@ public function testTagsInputOutput($tag_name) { // Look for a custom method named "{$tag_name}TestOutputXpath", if // found use that method to get the xpath definition for this meta tag, // otherwise it defaults to just looking for a meta tag matching: - // {@code} + // @code // <$testTag $testNameAttribute=$tag_name $testValueAttribute=$value /> - // {@endcode} + // @endcode $method = $this->getMethodFromTagCallback($tag_name, 'TestOutputXpath'); if (method_exists($this, $method)) { $xpath_string = $this->$method(); @@ -251,10 +265,11 @@ public function testTagsInputOutput($tag_name) { // Extract the meta tag from the HTML. $xpath = $this->xpath($xpath_string); - $this->assertCount(1, $xpath, new FormattableMarkup('One @tag tag found using @xpath.', ['@tag' => $tag_name, '@xpath' => $xpath_string])); - if (count($xpath) !== 1) { - $this->verbose($xpath, $tag_name . ': ' . $xpath_string); - } + $message = new FormattableMarkup('One @tag tag found using @xpath.', [ + '@tag' => $tag_name, + '@xpath' => $xpath_string, + ]); + $this->assertCount(1, $xpath, $message); // Run various tests on the output variables. // Most meta tags have an attribute, but some don't. @@ -262,25 +277,20 @@ public function testTagsInputOutput($tag_name) { $this->assertNotEmpty($xpath_value_attribute); $this->assertTrue($xpath[0]->hasAttribute($xpath_value_attribute)); // Help with debugging. - if (!$xpath[0]->hasAttribute($xpath_value_attribute)) { - $this->verbose($xpath, $tag_name . ': ' . $xpath_string); - } - else { - if ((string) $xpath[0]->getAttribute($xpath_value_attribute) != $all_values[$tag_name]) { - $this->verbose($xpath, $tag_name . ': ' . $xpath_string); - } + if ($xpath[0]->hasAttribute($xpath_value_attribute)) { $this->assertNotEmpty($xpath[0]->getAttribute($xpath_value_attribute)); $this->assertEquals($xpath[0]->getAttribute($xpath_value_attribute), $all_values[$tag_name], "The '{$tag_name}' tag was found with the expected value."); } } else { - $this->verbose($xpath, $tag_name . ': ' . $xpath_string); - $this->assertTrue((string) $xpath[0]); - $this->assertEquals((string) $xpath[0], $all_values[$tag_name], new FormattableMarkup("The '@tag' tag was found with the expected value '@value'.", ['@tag' => $tag_name, '@value' => $all_values[$tag_name]])); + $this->assertNotNull($xpath[0]); + $message = new FormattableMarkup("The '@tag' tag was found with the expected value '@value'.", [ + '@tag' => $tag_name, + '@value' => $all_values[$tag_name], + ]); + $this->assertEquals($xpath[0]->getHtml(), $all_values[$tag_name], $message); } } - - $this->drupalLogout(); } /** diff --git a/web/modules/metatag/tests/src/Functional/MetatagTokenStatus.php b/web/modules/metatag/tests/src/Functional/MetatagTokenStatus.php index 892a8ec230c297597da4a16f28e6adb268363776..4d6a13b7be1e1b0d3180c98b91a09c619caac8a3 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagTokenStatus.php +++ b/web/modules/metatag/tests/src/Functional/MetatagTokenStatus.php @@ -10,13 +10,12 @@ * * @group metatag */ -class MetatagTokenStatus extends BrowserTestBase -{ +class MetatagTokenStatus extends BrowserTestBase { /** * {@inheritdoc} */ - public static $modules = ['metatag']; + protected static $modules = ['metatag']; /** * {@inheritdoc} @@ -28,8 +27,7 @@ class MetatagTokenStatus extends BrowserTestBase * * @see token_get_token_problems */ - function testStatusReportTypesWarning() - { + public function testStatusReportTypesWarning() { $this->drupalLogin($this->rootUser); $this->drupalGet(Url::fromRoute('system.status')); @@ -41,8 +39,7 @@ function testStatusReportTypesWarning() * * @see token_get_token_problems */ - function testStatusReportTokensWarning() - { + public function testStatusReportTokensWarning() { $this->drupalLogin($this->rootUser); $this->drupalGet(Url::fromRoute('system.status')); diff --git a/web/modules/metatag/tests/src/Functional/MetatagTokenTest.php b/web/modules/metatag/tests/src/Functional/MetatagTokenTest.php index bf81357b9aec8f599153b49f9a302384852ccef5..2ad0b017fb681ededf81c026d16acd60844188c0 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagTokenTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagTokenTest.php @@ -27,6 +27,7 @@ class MetatagTokenTest extends BrowserTestBase { 'token_module_test', 'metatag', 'metatag_open_graph', + 'metatag_favicons', ]; /** @@ -46,6 +47,11 @@ public function setUp(): void { $this->drupalLogin($this->rootUser); $this->fieldUIAddNewField('/admin/config/people/accounts', 'metatags', 'Metatags', 'metatag'); + + // This extra step is necessary due to changes in core that removed a cache + // invalidation step. + // @see https://www.drupal.org/project/drupal/issues/2189411 + $this->container->get('entity_field.manager')->clearCachedFieldDefinitions(); } /** @@ -90,6 +96,8 @@ public function testMetatagEntityTokens() { 'field_metatags[0][basic][abstract]' => 'My abstract', 'field_metatags[0][open_graph][og_title]' => 'My OG Title', 'field_metatags[0][open_graph][og_image]' => 'Image 1,Image 2', + // @todo Update this to use the full URL. + 'field_metatags[0][favicons][mask_icon][href]' => 'metatag-logo.svg', ], 'Save'); $tokens = [ @@ -105,6 +113,27 @@ public function testMetatagEntityTokens() { '[user:field_metatags:og_image]' => 'Image 1,Image 2', '[user:field_metatags:og_image:0]' => 'Image 1', '[user:field_metatags:og_image:1]' => 'Image 2', + // Test metatags that store value as an array. + '[user:field_metatags:mask_icon]' => 'metatag-logo.svg', + ]; + + $this->assertPageTokens($user->toUrl(), $tokens, ['user' => $user]); + } + + /** + * Test precedence overridden tags over defaults in tokens. + */ + public function testTokenOverriddenMetatagPrecedence() { + $user = $this->createUser(); + $this->drupalGet($user->toUrl('edit-form')); + $this->submitForm([ + 'field_metatags[0][basic][title]' => 'My Title', + 'field_metatags[0][basic][description]' => 'My Description', + ], 'Save'); + + $tokens = [ + '[current-page:metatag:title]' => 'My Title', + '[current-page:metatag:description]' => 'My Description', ]; $this->assertPageTokens($user->toUrl(), $tokens, ['user' => $user]); diff --git a/web/modules/metatag/tests/src/Functional/MetatagXssTest.php b/web/modules/metatag/tests/src/Functional/MetatagXssTest.php index 0ab5ec674357c19062b67ad14baf2242fc2b5f21..588d8f8c002d40a77c043b992f6f79571ce7b3dc 100644 --- a/web/modules/metatag/tests/src/Functional/MetatagXssTest.php +++ b/web/modules/metatag/tests/src/Functional/MetatagXssTest.php @@ -80,7 +80,7 @@ class MetatagXssTest extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Create a user that can manage content types and create content. @@ -101,7 +101,10 @@ protected function setUp() { $this->drupalLogin($this->adminUser); // Set up a content type. - $this->drupalCreateContentType(['type' => 'metatag_node', 'name' => 'Test Content Type']); + $this->drupalCreateContentType([ + 'type' => 'metatag_node', + 'name' => 'Test Content Type', + ]); // Add a metatag field to the content type. $this->drupalGet('admin/structure/types/manage/metatag_node/fields/add-field'); @@ -111,8 +114,8 @@ protected function setUp() { 'field_name' => 'metatag_field', 'new_storage_type' => 'metatag', ]; - $this->drupalPostForm(NULL, $edit, $this->t('Save and continue')); - $this->drupalPostForm(NULL, [], $this->t('Save field settings')); + $this->submitForm($edit, $this->t('Save and continue')); + $this->submitForm([], $this->t('Save field settings')); } /** @@ -127,7 +130,7 @@ public function testXssMetatagConfig() { 'abstract' => $this->xssString, 'image_src' => $this->xssImageString, ]; - $this->drupalPostForm(NULL, $values, 'Save'); + $this->submitForm($values, 'Save'); $session->pageTextContains('Saved the Global Metatag defaults.'); $this->rebuildAll(); @@ -154,7 +157,6 @@ public function testXssMetatagConfig() { * Verify XSS injected in the entity metatag override field is not rendered. */ public function testXssEntityOverride() { - $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); $this->drupalGet('node/add/metatag_node'); $session = $this->assertSession(); @@ -165,7 +167,7 @@ public function testXssEntityOverride() { 'field_metatag_field[0][basic][abstract]' => $this->xssString, 'field_metatag_field[0][advanced][image_src]' => $this->xssImageString, ]; - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); // Check for the title tag, which will have the HTML tags removed and then // be lightly HTML encoded. @@ -185,7 +187,6 @@ public function testXssEntityOverride() { * Verify XSS injected in the entity titles are not rendered. */ public function testXssEntityTitle() { - $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); $this->drupalGet('node/add/metatag_node'); $session = $this->assertSession(); @@ -194,7 +195,7 @@ public function testXssEntityTitle() { 'title[0][value]' => $this->xssTitleString, 'body[0][value]' => $this->randomString() . ' ' . $this->randomString(), ]; - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); // Check for the title tag, which will have the HTML tags removed and then // be lightly HTML encoded. @@ -206,7 +207,6 @@ public function testXssEntityTitle() { * Verify XSS injected in the entity fields are not rendered. */ public function testXssEntityBody() { - $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? $this->t('Save and publish') : $this->t('Save'); $this->drupalGet('node/add/metatag_node'); $session = $this->assertSession(); @@ -215,12 +215,12 @@ public function testXssEntityBody() { 'title[0][value]' => $this->randomString(), 'body[0][value]' => $this->xssTitleString, ]; - $this->drupalPostForm(NULL, $edit, $save_label); + $this->submitForm($edit, 'Save'); // Check the body text. - // {@code} + // @code // $this->assertNoTitle($this->xssTitleString); - // {@endcode} + // @endcode $session->responseNotContains($this->xssTitleString); } diff --git a/web/modules/metatag/tests/src/Functional/NodeJsonOutput.php b/web/modules/metatag/tests/src/Functional/NodeJsonOutput.php index 41476177af64c151ea3e69cc782eb18c72ae4089..34b4ac8330986cd6e7cf50ddda4bd2ff9ca64918 100644 --- a/web/modules/metatag/tests/src/Functional/NodeJsonOutput.php +++ b/web/modules/metatag/tests/src/Functional/NodeJsonOutput.php @@ -41,7 +41,7 @@ class NodeJsonOutput extends BrowserTestBase { /** * {@inheritdoc} */ - protected $defaultTheme = 'bartik'; + protected $defaultTheme = 'claro'; /** * Create an entity, view its JSON output, confirm Metatag data exists. @@ -49,7 +49,7 @@ class NodeJsonOutput extends BrowserTestBase { public function testNode() { $this->provisionResource(); - /* @var\Drupal\node\NodeInterface $node */ + /** @var \Drupal\node\NodeInterface $node */ $node = $this->createContentTypeNode('Test JSON output', 'Testing JSON output for a content type'); $url = $node->toUrl(); @@ -66,7 +66,6 @@ public function testNode() { $response = $this->getSession()->getPage()->getContent(); $this->assertNotEmpty($response); $json = json_decode($response); - $this->verbose($json, 'JSON output'); $this->assertNotEmpty($json); // Confirm the JSON object's values. @@ -93,7 +92,8 @@ public function testNode() { * ['basic_auth']. */ protected function provisionResource($entity_type = 'node', array $formats = [], array $authentication = []) { - $this->resourceConfigStorage = $this->container + /** @var \Drupal\Core\Entity\EntityStorageInterface */ + $esource_config_storage = $this->container ->get('entity_type.manager') ->getStorage('rest_resource_config'); @@ -105,7 +105,7 @@ protected function provisionResource($entity_type = 'node', array $formats = [], $authentication[] = 'basic_auth'; } - $this->resourceConfigStorage->create([ + $esource_config_storage->create([ 'id' => 'entity.' . $entity_type, 'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY, 'configuration' => [ diff --git a/web/modules/metatag/tests/src/Functional/NodeTranslation.php b/web/modules/metatag/tests/src/Functional/NodeTranslation.php index 2e720c98e27f9df30a02a8ddc8af2ba2be4ee05c..bd2207f35e55e02dcd4306a646e8b68999b36afe 100644 --- a/web/modules/metatag/tests/src/Functional/NodeTranslation.php +++ b/web/modules/metatag/tests/src/Functional/NodeTranslation.php @@ -42,7 +42,7 @@ class NodeTranslation extends BrowserTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); // Login. @@ -54,7 +54,7 @@ protected function setUp() { $edit = [ 'predefined_langcode' => 'hu', ]; - $this->drupalPostForm(NULL, $edit, 'Add language'); + $this->submitForm($edit, 'Add language'); // Set up a content type. $this->drupalCreateContentType(['type' => 'article']); @@ -63,7 +63,7 @@ protected function setUp() { $edit = [ 'language_configuration[content_translation]' => TRUE, ]; - $this->drupalPostForm(NULL, $edit, 'Save content type'); + $this->submitForm($edit, 'Save content type'); } /** @@ -73,7 +73,7 @@ public function testContentTranslationForm() { $this->drupalGet('/admin/config/regional/content-language'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('Content language'); - $this->drupalPostForm(NULL, [], 'Save configuration'); + $this->submitForm([], 'Save configuration'); $this->assertSession()->statusCodeEquals(200); $this->assertSession()->pageTextContains('Settings successfully updated.'); } diff --git a/web/modules/metatag/tests/src/Functional/RemoveCoreMetaTags.php b/web/modules/metatag/tests/src/Functional/RemoveCoreMetaTags.php index 2a27226a7290fce7055ab23e991cd42e84a2f500..69ce1681e69e2f8e35d09feb2da4e85397d79ce2 100644 --- a/web/modules/metatag/tests/src/Functional/RemoveCoreMetaTags.php +++ b/web/modules/metatag/tests/src/Functional/RemoveCoreMetaTags.php @@ -52,7 +52,8 @@ public function testTaxonomyPage() { $edit = [ 'canonical_url' => '[current-page:url:unaliased]', ]; - $this->drupalPostForm('admin/config/search/metatag/taxonomy_term', $edit, 'Save'); + $this->drupalGet('admin/config/search/metatag/taxonomy_term'); + $this->submitForm($edit, 'Save'); // Ensure there is only 1 canonical metatag. $this->drupalGet('taxonomy/term/' . $term->id()); diff --git a/web/modules/metatag/tests/src/FunctionalJavascript/MetatagAvailableTokensTest.php b/web/modules/metatag/tests/src/FunctionalJavascript/MetatagAvailableTokensTest.php index 0b27bd1205ec63445e6e27d1857499bff86164f7..9b10b97455b06e264769192203701ff03af2c90b 100644 --- a/web/modules/metatag/tests/src/FunctionalJavascript/MetatagAvailableTokensTest.php +++ b/web/modules/metatag/tests/src/FunctionalJavascript/MetatagAvailableTokensTest.php @@ -15,7 +15,7 @@ class MetatagAvailableTokensTest extends WebDriverTestBase { /** * {@inheritdoc} */ - public static $modules = ['metatag', 'node']; + protected static $modules = ['metatag', 'node']; /** * {@inheritdoc} @@ -25,7 +25,7 @@ class MetatagAvailableTokensTest extends WebDriverTestBase { /** * Test the node metatag defaults page. */ - function testNodeMetatagDefaultsPage() { + public function testNodeMetatagDefaultsPage() { $this->drupalLogin($this->rootUser); $this->drupalGet(Url::fromRoute('entity.metatag_defaults.edit_form', ['metatag_defaults' => 'node'])); $page = $this->getSession()->getPage(); @@ -33,6 +33,8 @@ function testNodeMetatagDefaultsPage() { $token_dialog_link = $page->find('css', '.token-dialog'); $token_dialog_link->click(); + // @todo This method exists on JsWebAssert() and is not available from the + // assertSession() object? $this->assertSession()->assertWaitOnAjaxRequest(); $token_dialog = $page->find('css', '.token-tree-dialog'); diff --git a/web/modules/metatag/tests/src/Kernel/Form/MetatagSettingsFormTest.php b/web/modules/metatag/tests/src/Kernel/Form/MetatagSettingsFormTest.php index 5797ae9d01ebfb80fe4df4117f55e5aeb628a915..39f5c033bff5493ec4112f2188a56fc70237a9ae 100644 --- a/web/modules/metatag/tests/src/Kernel/Form/MetatagSettingsFormTest.php +++ b/web/modules/metatag/tests/src/Kernel/Form/MetatagSettingsFormTest.php @@ -43,7 +43,7 @@ class MetatagSettingsFormTest extends KernelTestBase { * * @covers ::__construct */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->installConfig(static::$modules); diff --git a/web/modules/metatag/tests/src/Kernel/MetatagManagerTest.php b/web/modules/metatag/tests/src/Kernel/MetatagManagerTest.php index 28e861876036cc495a2fbf5ff9badf398943bc6c..4f5891f39f3e963443b51ad92ee6faf78bbb967a 100644 --- a/web/modules/metatag/tests/src/Kernel/MetatagManagerTest.php +++ b/web/modules/metatag/tests/src/Kernel/MetatagManagerTest.php @@ -46,13 +46,20 @@ class MetatagManagerTest extends KernelTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->entityTypeManager = $this->container->get('entity_type.manager'); $this->metatagManager = $this->container->get('metatag.manager'); - $this->installConfig(['system', 'field', 'text', 'user', 'metatag', 'metatag_open_graph']); + $this->installConfig([ + 'system', + 'field', + 'text', + 'user', + 'metatag', + 'metatag_open_graph', + ]); $this->installEntitySchema('user'); $this->installSchema('user', ['users_data']); } @@ -81,6 +88,7 @@ public function testMetatagOrder() { $tags = $this->metatagManager->generateElements([ 'og_image_width' => 100, 'og_image_height' => 100, + // @todo Update this to use the metatag-logo.png file. 'og_image_url' => 'https://www.example.com/example/foo.png', ]); diff --git a/web/modules/metatag/tests/src/Kernel/MetatagSerializationTest.php b/web/modules/metatag/tests/src/Kernel/MetatagSerializationTest.php index 4f06b368a241fa8aa8fca0c0eabaf58667c8f946..7d6f0955839d1ad7347145bbe68d96091c958e67 100644 --- a/web/modules/metatag/tests/src/Kernel/MetatagSerializationTest.php +++ b/web/modules/metatag/tests/src/Kernel/MetatagSerializationTest.php @@ -17,7 +17,7 @@ class MetatagSerializationTest extends FieldKernelTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Core modules. 'serialization', @@ -38,7 +38,7 @@ class MetatagSerializationTest extends FieldKernelTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->installEntitySchema('user'); diff --git a/web/modules/metatag/tests/src/Kernel/MetatagSettingsTest.php b/web/modules/metatag/tests/src/Kernel/MetatagSettingsTest.php index 37be98f2d283e00ca0623dc1606a5a8ddac7de49..542121ea157a8c265792e04cea00a7d40993a5cc 100644 --- a/web/modules/metatag/tests/src/Kernel/MetatagSettingsTest.php +++ b/web/modules/metatag/tests/src/Kernel/MetatagSettingsTest.php @@ -39,7 +39,7 @@ class MetatagSettingsTest extends KernelTestBase { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->metatagManager = $this->container->get('metatag.manager'); diff --git a/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsEntitiesTest.php b/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsEntitiesTest.php index a189c5f129b48c9a2bd7b64703e5d4b9e592e060..e28dcec09424dc86404b97fa96621e771129dacd 100644 --- a/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsEntitiesTest.php +++ b/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsEntitiesTest.php @@ -22,7 +22,7 @@ class NodewordsEntitiesTest extends MigrateDrupal6TestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Core modules. // @see testAvailableConfigEntities 'comment', @@ -75,7 +75,7 @@ protected function fileMigrationSetup() { /** * {@inheritdoc} */ - protected function setUp() { + protected function setUp(): void { parent::setUp(); $this->loadFixture(__DIR__ . '/../../../../fixtures/d6_nodewords.php'); diff --git a/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsFieldTest.php b/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsFieldTest.php index 0b0eb92982800d6db989b6fb09344a05fc1910a9..b800fcc04feff799caf4efda75ccc51980faa532 100644 --- a/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsFieldTest.php +++ b/web/modules/metatag/tests/src/Kernel/Migrate/d6/NodewordsFieldTest.php @@ -21,7 +21,7 @@ class NodewordsFieldTest extends MigrateSqlSourceTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ 'metatag', 'migrate_drupal', 'token', diff --git a/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagEntitiesTest.php b/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagEntitiesTest.php index 2584e14fd264247ea45c41e3a344572a36bdf4d5..b19d186d6006cc535f0c1328bd4dcabbcd3b19ab 100644 --- a/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagEntitiesTest.php +++ b/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagEntitiesTest.php @@ -22,12 +22,13 @@ class MetatagEntitiesTest extends MigrateDrupal7TestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Core modules. // @see testAvailableConfigEntities 'comment', 'content_translation', 'datetime', + 'datetime_range', 'filter', 'image', 'language', @@ -77,10 +78,7 @@ protected function fileMigrationSetup() { /** * {@inheritdoc} */ - protected function setUp() { - if (version_compare(\Drupal::VERSION, '8.9', '<')) { - $this->markTestSkipped('This test requires at least Drupal 8.9'); - } + protected function setUp(): void { parent::setUp(); $this->loadFixture(__DIR__ . '/../../../../fixtures/d7_metatag.php'); @@ -125,8 +123,8 @@ public function testMetatag() { // This should have the "current revision" keywords value, indicating it is // the current revision. $expected = [ - 'keywords' => 'current revision', 'canonical_url' => 'the-node', + 'keywords' => 'current revision', 'robots' => 'noindex, nofollow', ]; $this->assertSame(serialize($expected), $node->field_metatag->value); @@ -137,8 +135,8 @@ public function testMetatag() { // This should have the "old revision" keywords value, indicating it is // a non-current revision. $expected = [ - 'keywords' => 'old revision', 'canonical_url' => 'the-node', + 'keywords' => 'old revision', 'robots' => 'noindex, nofollow', ]; $this->assertSame(serialize($expected), $node->field_metatag->value); @@ -147,9 +145,11 @@ public function testMetatag() { $user = User::load(2); $this->assertInstanceOf(UserInterface::class, $user); $this->assertTrue($user->hasField('field_metatag')); + // This should have the Utf8 converted description value. $expected = [ - 'keywords' => 'a user', 'canonical_url' => 'the-user', + 'description' => 'Drupal™ user', + 'keywords' => 'a user', ]; $this->assertSame(serialize($expected), $user->field_metatag->value); @@ -158,8 +158,8 @@ public function testMetatag() { $this->assertInstanceOf(TermInterface::class, $term); $this->assertTrue($term->hasField('field_metatag')); $expected = [ - 'keywords' => 'a taxonomy', 'canonical_url' => 'the-term', + 'keywords' => 'a taxonomy', ]; $this->assertSame(serialize($expected), $term->field_metatag->value); } diff --git a/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagFieldTest.php b/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagFieldTest.php index c335fcd93a068c29d5727294b75d05994894298e..80559dfdc0ec6ee0c9969d98825f9eeee340d93a 100644 --- a/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagFieldTest.php +++ b/web/modules/metatag/tests/src/Kernel/Migrate/d7/MetatagFieldTest.php @@ -15,7 +15,7 @@ class MetatagFieldTest extends MigrateSqlSourceTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ 'token', 'metatag', 'migrate_drupal', diff --git a/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d6/NodewordsFieldInstanceTest.php b/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d6/NodewordsFieldInstanceTest.php index 553216fdaadff6831b27bd14a2c8fefed6eefb45..2fdef25e0e27fc018dc32e7679e1617e686170e4 100644 --- a/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d6/NodewordsFieldInstanceTest.php +++ b/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d6/NodewordsFieldInstanceTest.php @@ -2,8 +2,8 @@ namespace Drupal\Tests\metatag\Kernel\Plugin\migrate\source\d6; -use Drupal\Node\Entity\NodeType; use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase; +use Drupal\node\Entity\NodeType; use Drupal\taxonomy\Entity\Term; use Drupal\taxonomy\Entity\Vocabulary; @@ -22,7 +22,7 @@ class NodewordsFieldInstanceTest extends MigrateSqlSourceTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Core modules. 'field', 'migrate_drupal', @@ -39,7 +39,10 @@ class NodewordsFieldInstanceTest extends MigrateSqlSourceTestBase { 'metatag', ]; - public function setUp() { + /** + * {@inheritdoc} + */ + public function setUp(): void { parent::setUp(); $this->installEntitySchema('node'); $this->installEntitySchema('taxonomy_term'); diff --git a/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d7/MetatagFieldInstanceTest.php b/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d7/MetatagFieldInstanceTest.php index df9be4c1a17c1fbfde9e68a66ae56a681b8367ad..5b56c8e03bdb1feda8a5a129cc6f7cc87133f24c 100644 --- a/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d7/MetatagFieldInstanceTest.php +++ b/web/modules/metatag/tests/src/Kernel/Plugin/migrate/source/d7/MetatagFieldInstanceTest.php @@ -19,7 +19,7 @@ class MetatagFieldInstanceTest extends MigrateSqlSourceTestBase { /** * {@inheritdoc} */ - public static $modules = [ + protected static $modules = [ // Core modules. 'field', 'migrate_drupal', @@ -36,7 +36,10 @@ class MetatagFieldInstanceTest extends MigrateSqlSourceTestBase { 'metatag', ]; - public function setUp() { + /** + * {@inheritdoc} + */ + public function setUp(): void { parent::setUp(); $this->installEntitySchema('node'); $this->installEntitySchema('taxonomy_term'); @@ -54,8 +57,10 @@ public function setUp() { ]); $node_type->save(); } + // @code // ['taxonomy_term', ['test_vocabulary' => 'test_vocabulary']], // Vocabulary::create(['name' => 'test_vocabulary']); + // @endcode // Setup vocabulary. Vocabulary::create([ 'vid' => 'test_vocabulary', @@ -63,7 +68,7 @@ public function setUp() { ])->save(); // Create a term and a comment. - $term = Term::create([ + Term::create([ 'vid' => 'test_vocabulary', 'name' => 'term', ])->save(); diff --git a/web/modules/metatag/tests/src/Unit/MetaNameBaseTest.php b/web/modules/metatag/tests/src/Unit/MetaNameBaseTest.php new file mode 100644 index 0000000000000000000000000000000000000000..df65716af125c72473eb723770181cec9d94d665 --- /dev/null +++ b/web/modules/metatag/tests/src/Unit/MetaNameBaseTest.php @@ -0,0 +1,66 @@ +<?php + +namespace Drupal\metatag\Unit; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; +use Drupal\Tests\UnitTestCase; + +/** + * This class provides methods for testing the MetaNameBase class. + * + * @group metatag + */ +class MetaNameBaseTest extends UnitTestCase { + + /** + * The MetaNameBase Mocked Object. + * + * @var \Drupal\metatag\Plugin\metatag\Tag\MetaNameBase|\PHPUnit\Framework\MockObject\MockObject + */ + protected $metaNameBase; + + /** + * {@inheritDoc} + */ + protected function setUp(): void { + parent::setUp(); + + // Mocking cause it's an abstract class. + $this->metaNameBase = $this->getMockBuilder(MetaNameBase::class) + ->setConstructorArgs([[], 'test', []]) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + } + + /** + * Tests the tidy method. + */ + public function testTidy() { + $method = "tidy"; + $class = new \ReflectionClass(get_class($this->metaNameBase)); + $method = $class->getMethod($method); + // Set the protected method tidy to be accessible. + $method->setAccessible(TRUE); + + $filterResult1 = $method->invoke($this->metaNameBase, " Test 123 "); + $this->assertEquals('Test 123', $filterResult1); + $filterResult2 = $method->invoke($this->metaNameBase, ' Test 123 Test'); + $this->assertEquals('Test 123 Test', $filterResult2); + $filterResult3 = $method->invoke( + $this->metaNameBase, + "Test \n\n123\n Test \n " + ); + $this->assertEquals('Test 123 Test', $filterResult3); + $filterResult4 = $method->invoke( + $this->metaNameBase, + "Test \r\n\r\n 123 \r\n " + ); + $this->assertEquals('Test 123', $filterResult4); + $filterResult5 = $method->invoke( + $this->metaNameBase, + "Test \t\t123 \tTest" + ); + $this->assertEquals('Test 123 Test', $filterResult5); + } + +} diff --git a/web/modules/metatag/tests/src/Unit/MetatagTrimmerTest.php b/web/modules/metatag/tests/src/Unit/MetatagTrimmerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ec56551d2105403b3d58f87810399f507ba351f3 --- /dev/null +++ b/web/modules/metatag/tests/src/Unit/MetatagTrimmerTest.php @@ -0,0 +1,93 @@ +<?php + +namespace Drupal\metatag\Unit; + +use Drupal\metatag\MetatagTrimmer; +use Drupal\Tests\UnitTestCase; +use PHPUnit\Framework\Exception; + +/** + * This class provides methods for testing the MetaTagtrimmer service. + * + * @group metatag + */ +class MetatagTrimmerTest extends UnitTestCase { + + /** + * The Metatagtrimmer Object. + * + * @var \Drupal\metatag\MetatagTrimmer + */ + protected $metatagTrimmer; + + /** + * {@inheritDoc} + */ + protected function setUp() : void { + parent::setUp(); + $this->metatagTrimmer = new MetatagTrimmer(); + } + + /** + * Tests the trimBeforeValue method. + */ + public function testTrimBeforeValue() { + $trimResult1 = $this->metatagTrimmer->trimBeforeValue('Test 123', 7); + $this->assertEquals('Test', $trimResult1); + $trimResult2 = $this->metatagTrimmer->trimBeforeValue('Test 123 123', 8); + $this->assertEquals('Test 123', $trimResult2); + $trimResult3 = $this->metatagTrimmer->trimBeforeValue('Test', 2); + $this->assertEquals('Test', $trimResult3); + $trimResult4 = $this->metatagTrimmer->trimBeforeValue('Test 123 123', 10); + $this->assertEquals('Test 123', $trimResult4); + $trimResult5 = $this->metatagTrimmer->trimBeforeValue('Test 123 123', 20); + $this->assertEquals('Test 123 123', $trimResult5); + } + + /** + * Tests the trimAferValue method. + */ + public function testTrimAfterValue() { + $trimResult1 = $this->metatagTrimmer->trimAfterValue('Test 123', 7); + $this->assertEquals($trimResult1, 'Test 123'); + $trimResult2 = $this->metatagTrimmer->trimAfterValue('Test 123 123', 8); + $this->assertEquals($trimResult2, 'Test 123'); + $trimResult3 = $this->metatagTrimmer->trimAfterValue('Test 123', 5); + $this->assertEquals($trimResult3, 'Test'); + $trimResult4 = $this->metatagTrimmer->trimAfterValue('Test 123 123', 10); + $this->assertEquals('Test 123 123', $trimResult4); + $trimResult5 = $this->metatagTrimmer->trimAfterValue('Test 123 123', 20); + $this->assertEquals('Test 123 123', $trimResult5); + } + + /** + * Tests the trimOnValue method. + */ + public function testTrimOnValue() { + $trimResult1 = $this->metatagTrimmer->trimByMethod('Test 123', 7, 'onValue'); + $this->assertEquals('Test 12', $trimResult1); + $trimResult2 = $this->metatagTrimmer->trimByMethod('Test 123 123', 5, 'onValue'); + $this->assertEquals('Test', $trimResult2); + } + + /** + * Tests if trimByMethod will throw an error when given a non existing method. + */ + public function testTrimByMethodError() { + $this->expectException(Exception::class); + $this->metatagTrimmer->trimByMethod('test', 4, 'noValue'); + } + + /** + * Tests the testTrimByMethod method. + */ + public function testTrimByMethod() { + $trimResult1 = $this->metatagTrimmer->trimByMethod("Test 123", 7, 'beforeValue'); + $this->assertEquals('Test', $trimResult1); + $trimResult2 = $this->metatagTrimmer->trimByMethod("Test 123", 7, 'onValue'); + $this->assertEquals('Test 12', $trimResult2); + $trimResult3 = $this->metatagTrimmer->trimByMethod("Test 123", 7, 'afterValue'); + $this->assertEquals('Test 123', $trimResult3); + } + +}