diff --git a/composer.json b/composer.json index 49c075403eb2a2adb0cdd237a9905d9219fb6db3..a192bff95a941713dfdcc43215c7862f0414fce9 100644 --- a/composer.json +++ b/composer.json @@ -114,6 +114,7 @@ "drupal/media_entity_browser": "2.0-alpha1", "drupal/media_entity_twitter": "2.0-alpha2", "drupal/menu_block": "1.4", + "drupal/metatag": "^1.7", "drupal/migrate_plus": "4.0", "drupal/migrate_tools": "4.0", "drupal/paragraphs": "1.5", diff --git a/composer.lock b/composer.lock index d2e78011d81fede67956d7d43ed45517b2965348..220ac70d0c43a3fd26165ed3a5455b0173c12bb8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "5ab70c86e4a38136de859e4d0db779c9", + "content-hash": "4c34794188864f69fe7bacbbb0c2e2d7", "packages": [ { "name": "alchemy/zippy", @@ -1656,6 +1656,9 @@ "status": "covered", "message": "Covered by Drupal's security advisory policy" } + }, + "patches_applied": { + "2962965": "https://www.drupal.org/files/issues/2018-09-01/block-permissions-2962965-4.patch" } }, "notification-url": "https://packages.drupal.org/8/downloads", @@ -4483,6 +4486,9 @@ "status": "covered", "message": "Covered by Drupal's security advisory policy" } + }, + "patches_applied": { + "2809699": "https://www.drupal.org/files/issues/2018-10-26/menu_block-label_configuration-2809699-82.patch" } }, "notification-url": "https://packages.drupal.org/8/downloads", @@ -4517,6 +4523,74 @@ "source": "http://cgit.drupalcode.org/menu_block" } }, + { + "name": "drupal/metatag", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://git.drupal.org/project/metatag", + "reference": "8.x-1.7" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/metatag-8.x-1.7.zip", + "reference": "8.x-1.7", + "shasum": "93decaefd053c524918ceae5b5ef05dd77de0857" + }, + "require": { + "drupal/core": "*", + "drupal/token": "^1.0" + }, + "require-dev": { + "drupal/devel": "^1.0", + "drupal/metatag_dc": "*", + "drupal/metatag_open_graph": "*", + "drupal/page_manager": "^4.0", + "drupal/redirect": "^1.0", + "drupal/restui": "^1.0", + "drupal/schema_metatag": "^1.0", + "drupal/schema_web_page": "*" + }, + "type": "drupal-module", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + }, + "drupal": { + "version": "8.x-1.7", + "datestamp": "1535726393", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "See contributors", + "homepage": "https://www.drupal.org/node/640498/committers", + "role": "Developer" + }, + { + "name": "Dave Reid", + "homepage": "https://www.drupal.org/user/53892" + } + ], + "description": "Manage meta tags for all entities.", + "homepage": "https://www.drupal.org/project/metatag", + "keywords": [ + "Drupal", + "seo" + ], + "support": { + "source": "http://cgit.drupalcode.org/metatag", + "issues": "http://drupal.org/project/issues/metatag" + } + }, { "name": "drupal/migrate_plus", "version": "4.0.0", diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 8ec31de059bcc6631d21a487a3def93831d14fe6..46570fd38ef4605c793d9e7509a62d7ae721367d 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -4662,6 +4662,76 @@ "source": "http://cgit.drupalcode.org/menu_block" } }, + { + "name": "drupal/metatag", + "version": "1.7.0", + "version_normalized": "1.7.0.0", + "source": { + "type": "git", + "url": "https://git.drupal.org/project/metatag", + "reference": "8.x-1.7" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/metatag-8.x-1.7.zip", + "reference": "8.x-1.7", + "shasum": "93decaefd053c524918ceae5b5ef05dd77de0857" + }, + "require": { + "drupal/core": "*", + "drupal/token": "^1.0" + }, + "require-dev": { + "drupal/devel": "^1.0", + "drupal/metatag_dc": "*", + "drupal/metatag_open_graph": "*", + "drupal/page_manager": "^4.0", + "drupal/redirect": "^1.0", + "drupal/restui": "^1.0", + "drupal/schema_metatag": "^1.0", + "drupal/schema_web_page": "*" + }, + "type": "drupal-module", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + }, + "drupal": { + "version": "8.x-1.7", + "datestamp": "1535726393", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + } + }, + "installation-source": "dist", + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "See contributors", + "homepage": "https://www.drupal.org/node/640498/committers", + "role": "Developer" + }, + { + "name": "Dave Reid", + "homepage": "https://www.drupal.org/user/53892" + } + ], + "description": "Manage meta tags for all entities.", + "homepage": "https://www.drupal.org/project/metatag", + "keywords": [ + "Drupal", + "seo" + ], + "support": { + "source": "http://cgit.drupalcode.org/metatag", + "issues": "http://drupal.org/project/issues/metatag" + } + }, { "name": "drupal/migrate_plus", "version": "4.0.0", diff --git a/web/modules/metatag/.codeclimate.yml b/web/modules/metatag/.codeclimate.yml new file mode 100644 index 0000000000000000000000000000000000000000..e8b0bd077e5c241bb3886d7ef423511101bb0a9f --- /dev/null +++ b/web/modules/metatag/.codeclimate.yml @@ -0,0 +1,25 @@ +--- +engines: + csslint: + enabled: true + duplication: + enabled: true + config: + languages: + - javascript + - php + eslint: + enabled: true + fixme: + enabled: true + phpmd: + enabled: true +ratings: + paths: + - "**.css" + - "**.inc" + - "**.install" + - "**.js" + - "**.module" + - "**.php" + - "**.test" diff --git a/web/modules/metatag/.csslintrc b/web/modules/metatag/.csslintrc new file mode 100644 index 0000000000000000000000000000000000000000..aacba956e5bbede1c195ce554fcad3e200b24ff8 --- /dev/null +++ b/web/modules/metatag/.csslintrc @@ -0,0 +1,2 @@ +--exclude-exts=.min.css +--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes diff --git a/web/modules/metatag/.eslintignore b/web/modules/metatag/.eslintignore new file mode 100644 index 0000000000000000000000000000000000000000..96212a3593bac8c93f624b77185a8d11018efd96 --- /dev/null +++ b/web/modules/metatag/.eslintignore @@ -0,0 +1 @@ +**/*{.,-}min.js diff --git a/web/modules/metatag/.eslintrc b/web/modules/metatag/.eslintrc new file mode 100644 index 0000000000000000000000000000000000000000..9faa37508e533c82089e0485dd9e9907370a309d --- /dev/null +++ b/web/modules/metatag/.eslintrc @@ -0,0 +1,213 @@ +ecmaFeatures: + modules: true + jsx: true + +env: + amd: true + browser: true + es6: true + jquery: true + node: true + +# http://eslint.org/docs/rules/ +rules: + # Possible Errors + comma-dangle: [2, never] + no-cond-assign: 2 + no-console: 0 + no-constant-condition: 2 + no-control-regex: 2 + no-debugger: 2 + no-dupe-args: 2 + no-dupe-keys: 2 + no-duplicate-case: 2 + no-empty: 2 + no-empty-character-class: 2 + no-ex-assign: 2 + no-extra-boolean-cast: 2 + no-extra-parens: 0 + no-extra-semi: 2 + no-func-assign: 2 + no-inner-declarations: [2, functions] + no-invalid-regexp: 2 + no-irregular-whitespace: 2 + no-negated-in-lhs: 2 + no-obj-calls: 2 + no-regex-spaces: 2 + no-sparse-arrays: 2 + no-unexpected-multiline: 2 + no-unreachable: 2 + use-isnan: 2 + valid-jsdoc: 0 + valid-typeof: 2 + + # Best Practices + accessor-pairs: 2 + block-scoped-var: 0 + complexity: [2, 6] + consistent-return: 0 + curly: 0 + default-case: 0 + dot-location: 0 + dot-notation: 0 + eqeqeq: 2 + guard-for-in: 2 + no-alert: 2 + no-caller: 2 + no-case-declarations: 2 + no-div-regex: 2 + no-else-return: 0 + no-empty-label: 2 + no-empty-pattern: 2 + no-eq-null: 2 + no-eval: 2 + no-extend-native: 2 + no-extra-bind: 2 + no-fallthrough: 2 + no-floating-decimal: 0 + no-implicit-coercion: 0 + no-implied-eval: 2 + no-invalid-this: 0 + no-iterator: 2 + no-labels: 0 + no-lone-blocks: 2 + no-loop-func: 2 + no-magic-number: 0 + no-multi-spaces: 0 + no-multi-str: 0 + no-native-reassign: 2 + no-new-func: 2 + no-new-wrappers: 2 + no-new: 2 + no-octal-escape: 2 + no-octal: 2 + no-proto: 2 + no-redeclare: 2 + no-return-assign: 2 + no-script-url: 2 + no-self-compare: 2 + no-sequences: 0 + no-throw-literal: 0 + no-unused-expressions: 2 + no-useless-call: 2 + no-useless-concat: 2 + no-void: 2 + no-warning-comments: 0 + no-with: 2 + radix: 2 + vars-on-top: 0 + wrap-iife: 2 + yoda: 0 + + # Strict + strict: 0 + + # Variables + init-declarations: 0 + no-catch-shadow: 2 + no-delete-var: 2 + no-label-var: 2 + no-shadow-restricted-names: 2 + no-shadow: 0 + no-undef-init: 2 + no-undef: 0 + no-undefined: 0 + no-unused-vars: 0 + no-use-before-define: 0 + + # Node.js and CommonJS + callback-return: 2 + global-require: 2 + handle-callback-err: 2 + no-mixed-requires: 0 + no-new-require: 0 + no-path-concat: 2 + no-process-exit: 2 + no-restricted-modules: 0 + no-sync: 0 + + # Stylistic Issues + array-bracket-spacing: 0 + block-spacing: 0 + brace-style: 0 + camelcase: 0 + comma-spacing: 0 + comma-style: 0 + computed-property-spacing: 0 + consistent-this: 0 + eol-last: 0 + func-names: 0 + func-style: 0 + id-length: 0 + id-match: 0 + indent: 0 + jsx-quotes: 0 + key-spacing: 0 + linebreak-style: 0 + lines-around-comment: 0 + max-depth: 0 + max-len: 0 + max-nested-callbacks: 0 + max-params: 0 + max-statements: [2, 30] + new-cap: 0 + new-parens: 0 + newline-after-var: 0 + no-array-constructor: 0 + no-bitwise: 0 + no-continue: 0 + no-inline-comments: 0 + no-lonely-if: 0 + no-mixed-spaces-and-tabs: 0 + no-multiple-empty-lines: 0 + no-negated-condition: 0 + no-nested-ternary: 0 + no-new-object: 0 + no-plusplus: 0 + no-restricted-syntax: 0 + no-spaced-func: 0 + no-ternary: 0 + no-trailing-spaces: 0 + no-underscore-dangle: 0 + no-unneeded-ternary: 0 + object-curly-spacing: 0 + one-var: 0 + operator-assignment: 0 + operator-linebreak: 0 + padded-blocks: 0 + quote-props: 0 + quotes: 0 + require-jsdoc: 0 + semi-spacing: 0 + semi: 0 + sort-vars: 0 + space-after-keywords: 0 + space-before-blocks: 0 + space-before-function-paren: 0 + space-before-keywords: 0 + space-in-parens: 0 + space-infix-ops: 0 + space-return-throw-case: 0 + space-unary-ops: 0 + spaced-comment: 0 + wrap-regex: 0 + + # ECMAScript 6 + arrow-body-style: 0 + arrow-parens: 0 + arrow-spacing: 0 + constructor-super: 0 + generator-star-spacing: 0 + no-arrow-condition: 0 + no-class-assign: 0 + no-const-assign: 0 + no-dupe-class-members: 0 + no-this-before-super: 0 + no-var: 0 + object-shorthand: 0 + prefer-arrow-callback: 0 + prefer-const: 0 + prefer-reflect: 0 + prefer-spread: 0 + prefer-template: 0 + require-yield: 0 diff --git a/web/modules/metatag/CHANGELOG.txt b/web/modules/metatag/CHANGELOG.txt new file mode 100644 index 0000000000000000000000000000000000000000..512dc592738af3dcdcd54f0003c46610449deb3e --- /dev/null +++ b/web/modules/metatag/CHANGELOG.txt @@ -0,0 +1,513 @@ +Metatag 8.x-1.7, 2018-08-31 +--------------------------- +#2994979 by DamienMcKenna, dspachos, ynotpeanutbutter, oxy86, IT-Cru, kdeds, + zenimagine: Fixed backwards compatibility break when support for multiple- + value tags was added. +#2990923 by th_tushar, DamienMcKenna: Fixed coding standards. + + +Metatag 8.x-1.6, 2018-08-21 +--------------------------- +#2961777 by thejimbirch, Baysaa: "Geographical position" (geo.position) should + use semi-colon instead of comma. +#2964626 by idebr: og:image:secure_url allows for multiple values. +#2865267 by DamienMcKenna, okonvicka, aldibier: <title> tags empty after + installing Metatag. +#2962426 by dragonwize: Image URL double encoded. +#2973277 by mvantuch, DamienMcKenna: Support for og:image:alt. +#2977002 by DamienMcKenna, maxoid: Enable testing on the two og product meta + tags. +#2977545 by pmelab, bappa.sarkar, DamienMcKenna: GraphQL throws an error due to + Metatag's use of a custom data structure. +#2925714 by acbramley, vakulrai, Berdir, nkoporec: Replace deprecated + BaseFieldDefinition ::setQueryable. +#2957411 by pmelab: Field item empty check on empty arrays. +#2958743 by DamienMcKenna, AdamEvertsson, StepanISK, trong.nguyen.tcec, + chiefme, quixxel, rjg, CProfessionals: Ignore update.php requests when + loading entities; error message when updating from 8.x-1.0 to 8.x-1.5. +#2961918 by thejimbirch, Michelle: Add the site.webmanifest meta tag. +#2895577 by plopesc, drupallogic: Error loading + /admin/config/search/metatag?page=1. +#2943954 by thejimbirch, DamienMcKenna: Document an approach to simplify + overriding meta tags on a per-entity basis. +#2968902 by DamienMcKenna, Berdir: Default user page title token should use + [user:display-name]. +#2977197 by justin., DamienMcKenna: Allow modules to override the entity used + for token replacements. +#2691313 by KarenS, carstenG, DamienMcKenna, Michelle, marysmech: New option to + control which meta tag groups are used on each form. +#2563657 by plopesc, scotthooker, dawehner, ryanissamson, KevinVb, dobrzyns, + PieterDC, peter.keppert, piggito, DamienMcKenna, Grayle, kunal.kursija, + Citizen Dan, al0a, kaushashah, yohanaraujo07@gmail.com, markandrewsutton, + fuzzyjared, igalafate, PascoS, rybchynski: Panels / Page Manager + integration. +#2989295 by JKerschner: Coding style improvements. +#2987852 by Chris Burge: Allow meta tags to be altered before page attachment. +#2989543 by JKerschner: Remove unused variables and imports. +#2753595 by sinn, thejimbirch: W3C validation error on xmlns attribute. +#2988072 by juanolalla: Allow contex entity to be overriden in alter hook. +#2628934 by nikunjkotecha, smaz, e.escribano, idebr, DamienMcKenna, + ZapevalovAnton, caspervoogt: Full support for meta tags that allow multiple + values. +#2987904 by thejimbirch: Remove groups redundantly stored in the main module. +#2987107 by ziomizar: Add support for bubbeable metadata in the MetatagToken + service. +#2978106 by Rolf van de Krol: Translated metatags not showing in normalized + entity representations (i.e. REST). +#2799861 by kalpaitch, DamienMcKenna, dmitry.yankouski, ckaotik: Canonical links + repeated when using Panels pages. +#2532596 by alzz, DamienMcKenna, thejimbirch: Add new meta tag: google. + + +Metatag 8.x-1.5, 2018-03-29 +--------------------------- +#2932596 by yo30, Punk_UnDeaD: Wrong method in abstract class LinkSizesBase. +#2933940 by DamienMcKenna: og:image must be at least 200x200 otherwise it is + ignored by Facebook. +#2936371 by gaurav.kapoor: Unused variable in metatag defaults class revert + function. +#2923080 by DamienMcKenna, pingwin4eg, pazhyn: Undefined offset: 1 in + metatag_mobile_page_attachments_alter. +#2930037 by smurrayatwork, rbayliss, moshe weitzman: Missing ampersand with + drupal_static causes multiple calls to metatag_get_tags_from_route(). +#2899234 by DamienMcKenna, JeffM2001, twang, heddn, edurenye, ShaunDychko: + Missing dependency (drupal:serialization) / Fatal error: Class NormalizerBase + not found. +#2945799 by DamienMcKenna, webfaqtory: Undefined variable: tag_id in + MetatagManager->sortedGroupsWithTags(). +#2953313 by DamienMcKenna: Add a function for getting the meta tags in a human + readable format - metatag_generate_entity_metatags(). +#2953635 by DamienMcKenna: MetatagStringTest has the wrong @group. +#2937683 by prafullsranjan, DamienMcKenna: Further improve module's coding + standards compliance. +#2939608 by alberto56: Invalid argument supplied for foreach() in + MetatagNormalizer. +#2936876 by bonus, DamienMcKenna: Add support for Pinterest meta namespace. +#2938025 by DamienMcKenna, Oliver Eyton-Williams: Incorrect rel attribute on + hreflang tags. +#2954214 by DamienMcKenna: composer.json improvements. +#2908119 by LEalex, DamienMcKenna, jeffam, BenStallings: Set "link" HTTP header + for canonical URL and shortlink tags. +#2954169 by yasmeensalah, DamienMcKenna: Translations of description meta tags + shouldn't be limited to 128 characters. +#2897450 by edurenye: Add product:price:amount and product:price:currency OG + tags. +#2922581 by roborew: Metatag causes error when used with Replication Modules to + deploy content. +#2947493 by DamienMcKenna, kala4ek: Adding forms of custom entities are broken. +#2828607 by pingevt, DamienMcKenna: Add OG book meta tags. +#2954522 by DamienMcKenna: Correct spelling of "meta tags". +#2809351 by DamienMcKenna, thejimbirch: Add the advanced Dublin Core meta tags. +#2956199 by DamienMcKenna: Remove separate admin pages for Views integration. +#2956227 by DamienMcKenna: Test improvements from 2883718-20. +#2900368 by plopesc: Don't allow certain defaults to be removed. +#2840751 by ocastle, ElegguaDP, Wim Leers, keopx, adamzimmermann: + Protocol-relative URLs are broken. +#2925974 by keopx, ocastle, DamienMcKenna, Wim Leers, mangy.fox: Twitter Cards + (and others) require absolute URLs. + + +Metatag 8.x-1.4, 2017-12-21 +--------------------------- +#2882769 by DamienMcKenna: Added a hook_requirements() message about the + Schema.org Metatag module. +#2864079 by DamienMcKenna: Resolve coding standards violations. +#2928394 by DamienMcKenna, mattlt: Error: Trait metatag_views\ + MetatagViewsValuesCleanerTrait not found. +#2932110 by thejimbirch: Update Description's meta description to 320 chars + (for 2018). +#2932285 by DamienMcKenna, Sophie.SK: After updating Redirect to 1.0, config + import fails: route does not exist. +#2932316 by DamienMcKenna, Sophie.SK: Error on main defaults page if no config + objects exist. +#2932361 by DamienMcKenna: Improve coding standards on Metatag 8.x-1.x. +#2930001 by Aurif3x, DamienMcKenna: New meta tag: Set-Cookie. +#2810635 by DamienMcKenna: Automatically add hreflang meta tags for each enabled + language. + + +Metatag 8.x-1.3, 2017-09-29 +--------------------------- +#2898975 by DamienMcKenna: Correct restui entry in composer.json. +#2899045 by DamienMcKenna: Fixed problems in MetatagNodeTranslationTest. +#2899234 by DamienMcKenna: Expand Devel/WebProfiler tests to make sure they work + when a content type and node are present. +#2898805 by DamienMcKenna: Small improvements to the test suite, working + towards fixing the 8.4.x support. +#2898805 by DamienMcKenna: Fixes to MetatagNodeTranslationTest to make it work + with 8.4.x. +By DamienMcKenna: Reenable \Drupal\metatag\Tests\MetatagFrontpageTest:: + testFrontPageMetatagsEnabledConfig(). +#2905925 by DamienMcKenna: The Normalizer shouldn't assume all meta tags have a + 'content' attribute; also support the 'href' attribute. +#2906312 by DamienMcKenna: Added the twitter:dnt meta tag. +#2909390/2894868 by Perignon, StijnStroobants: Small typo in MetatagToken. +#2903661 by DamienMcKenna: Don't output 403/404 page node's meta tags on + 403/404 pages. +#2905769 by DamienMcKenna: Improved defaults for the canonical URL meta tag. +#2899752 by DamienMcKenna, huzooka, deepak_zyxware, samuel.mortenson, wanjee, + giangi.vigazzola: Creating a new field bundle inside + hook_entity_base_field_info_alter() is a bad idea and causes problems. +#2906180 by John Lawter: Incorrect Wikipedia link for Advanced > Geographical + position. +#2859111 by acbramley, DamienMcKenna: Remove the second canonical tag on + taxonomy term pages because of a bug in core. +By DamienMcKenna: Changed codebase to only use short array syntax, fixed some + comments. +#2911435 by DamienMcKenna, AdamPS: Streamline the HTML output logic. +#2860088 by AdamPS, DamienMcKenna: Comma separated list in og:image breaks if + one component is empty. +#2905769 by DamienMcKenna: Added tests for how default meta tags are displayed. +#2872382 by Vlad_Bo, DamienMcKenna: Error if there is no node object (custom + node view implementation). +#2217549 by Alan D., Kuldeep K, DamienMcKenna: Integration with the Diff module. + + +Metatag 8.x-1.2, 2017-07-31 +--------------------------- +#2882954 by DamienMcKenna: Added Devel as a test dependency. +#2882954, #2877737 by DamienMcKenna, RenĂ©-Marc Simard, a.henry: Fixed + compatibility with WebProfiler, added tests to ensure site still works when it + or Devel is enabled. +#2878158 by DamienMcKenna: Listed Context Metadata as a related module. +#2894566 by StijnStroobants: Make all routes start with a leading slash. +By DamienMcKenna: Use ComposerCat to update composer.json. +By DamienMcKenna: Don't list Drupal core as a dependency in composer.json. +#2636852 by hanoii, DamienMcKenna, Grayside, pcho, skorzh, fjgarlin, vincic: + Make Metatag fields available as JSON. +#2893448 by Sam152: Add correct meta tags to latest-version route to support + content moderation. + + +Metatag 8.x-1.1, 2017-05-31 +--------------------------- +#2852737 by DamienMcKenna: Added CodeClimate config files. +#2853252 by dawehner: Ensure the meta tags are ordered correctly. +#2856454 by dbungard: Improvements to UI text, meta tag descriptions, etc. +#2781485 by kalpaitch: Changed MetatagManager to use the instance name rather + than plugin ID to identify plugin instances. +By DamienMcKenna: Ensure all drupalPostForm() calls are preceeded by a + drupalGet() call, and that all drupalGet() calls have an assertResponse(). +#2858057 by nicrodgers: Wrong default values are displayed in the node form when + adding a translation. +#2855445 by rocket.man: Replace deprecated functions (database functions, + format_string()). +#2851582 by mtodor: Filled out missing attributes on the default configuration. +#2862277 by DamienMcKenna: Fixed filename of the MsapplicationStartUrl plugin. +#2864524 by JamesK: Improve field description for the abstract meta tag. +#2848353 by DamienMcKenna, grisendo: Only output one shortlink tag; extended tag + tests to cover an example entity. +#2706941 by ckaotik, monika.de, DamienMcKenna, mariancalinro, adinac: Allow + translations to be longer than 128 characters for tags which use textarea + fields. +#2868750 by DamienMcKenna: List Metatag Cxense as a related module. +#2563633 by ziomizar, DamienMcKenna, ruloweb: Add all of the Favicon meta tags. +#2853515 by ohthehugemanatee: Add default handling to metatag manager. +#2857544 by fjgarlin: Default values not returned on REST default routes. +#2636852 by Greyside: MetatagToken::replace() options array shouldn't assume the + 'clear' attribute is always needed. +By DamienMcKenna: Allow MetatagJsonOutputTest to run. +#2563633 by ziomizar: Misc fixes for the Favicon meta tags. +#2563647 by delta, tom_ek, DamienMcKenna, monika.de, ckaotik, martins.bertins, + cgmonroe, danquah, blazey, paulmckibben, stijn.blomme, danquah, Alex Bukah, + guarav.goyal, kducharm: Views integration. +#2882769 by DamienMcKenna: List Schema Metatag as a related module. +#2856416 by DamienMcKenna: List Metatag Google Scholar as a related module. +#2848543 by DamienMcKenna: Add missing people to README.txt. + + +Metatag 8.x-1.0, 2017-01-31 +--------------------------- +#2841139 by jmolivas: Relocated commands services registration to + console.services.yml file. +#2844429 by DamienMcKenna: There's only one hreflang meta tag so far and it does + not yet support custom tokens like the D7 version does. +#2844504 by DamienMcKenna: Add project names to all dependencies. +#2563631 by DamienMcKenna: Added all AppLinks meta tags. +#2841737 by DamienMcKenna: Renamed the DrupalConsole commands. +#2838175 by dawehner: Allow supported entity routes to be changed through the + new hook_metatag_route_entity(). +#2825867 by Grayside: Improve support for the Typed Data API. +#2649592 by ziomizar, DamienMcKenna: Write tests to cover apostrophe handling. +By DamienMcKenna: Shortened some verbose variable syntax. +#2835752 by DamienMcKenna: Improved hook_help(). +#2789511 by DamienMcKenna: It is a known issue that all Metatag fields must be + removed prior to uninstalling the module. +#2809915 by nicxvan, DamienMcKenna: Document how to programmatically assign + meta tags when creating entities. +#2563645 by DamienMcKenna, Michelle: Improved documentation. + + +Metatag 8.x-1.0-beta12, 2017-01-03 +---------------------------------- +#2823811 by Michelle: metatag_open_graph_preprocess_html() was misspelled. +#2654148 by penyaskito, DamienMcKenna: Not all entity.*.add paths are tied to a + specific entity form, so don't assume they are; this fixes compatibility with + the Lingotek module, possibly others. +By DamienMcKenna: Fixed a typo in README.txt. +#2824442 by jiff: image_src should be a 'link' tag. +#2821476 by DamienMcKenna, Daniel_Rose: Added tests to confirm entity defaults + inherit properly. +#2836124 by DamienMcKenna: Fixed tests for the Dublin Core meta tags. +#2786625 by DamienMcKenna: Added the hreflang=x-default meta tag. +#2532588 by DamienMcKenna, renatog, cebasqueira: Added the Google CSE meta tags. +#2563631 by DamienMcKenna: Added a placeholder to store the AppLinks meta tags. +#2809351 by DamienMcKenna: Added a placeholder to store the DC Advanced meta + tags. +#2835925 by DamienMcKenna: Added a placeholder to store the OG Products meta + tags. +#2563633 by DamienMcKenna: Added a placeholder to store the favicon meta tags. +#2532588 by DamienMcKenna: Follow-up to fix the group assignment of the Google + CSE meta tags. +#2786625 by DamienMcKenna: Follow-up to fix the group assignment of the hreflang + x-default meta tag. +#2563635 by jlbellido, DamienMcKenna: Ported all of the mobile meta tags to the + new Metatag Mobile submodule. +#2840222 by jmolivas: Update for Drupal Console rc13 namespace changes. + + +Metatag 8.x-1.0-beta11, 2016-10-31 +---------------------------------- +#2786795 by agoradesign, heddn: Temporarily disable the DrupalConsole + integration. +#2709985 by DamienMcKenna: Moved the two FB meta tags into a new submodule, + Metatag Facebook, added the fb_pages meta tag. +#2709985 by DamienMcKenna: Fixed the fb:pages meta tag description. +By DamienMcKenna: Updated the description of content-language to clarify its + usage and the fact that Bing may still use it. +#1865228 by DamienMcKenna: Moved the Author meta tag into the GoolgePlus + submodule. +#2797069 by Internet, DamienMcKenna: Corrected the URL to Wikipedia's ICBM page. +#2801023 by trobey: Provide namespaces in dependencies to avoid ambiguity. +#2563627 by gaurav.goyal, DamienMcKenna, cilefen: Added all of the basic Dublin + Core meta tags. +#2795983 by dbungard: Improved help message on the main configuration page. +#2786795 by -enzo-: Fixed Drupal Console integration; now requires rc1. +#2663974 by dawehmer, DamienMcKenna: Added the og:video meta tags. +#2819549 by chr.fritsch: Fixed entity API changes in metatag_update_8103. +#2817309 by chr.fritsch, DamienMcKenna: Fixed default value handling for all + entity forms. Greatly extended the entity field tests for nodes, terms, users + and the entity_test entity. +#2654148 by bmcclure, DamienMcKenna, miiimooo, JeroenT, agoradesign: Improved + support for all entities, exclude certain core entity types, only support + ContentEntityType entities that have 'links' defined. +#2816553 by andyrigby: Renamed article:tags to be article:tag. +#2796701 by jiff, DamienMcKenna: Added tests to cover XSS via meta tag values. +#2796701 by DamienMcKenna: Added tests to cover XSS on the page title and entity + values. + + +Metatag 8.x-1.0-beta10, 2016-08-22 +---------------------------------- +#2747793 by rajeshwari10, cilefen, DamienMcKenna: Removed the @file docblocks. +#2764163 by chrisfree, markdorison: Allow the 'referrer' meta tag to not have a + value selected. +#2762981 by felribeiro, DamienMcKenna: Changed codebase to only use short array + syntax. +#2753595 by sylus: Moved the extra XML namespaces to the OpenGraph module. +#2765137 by balsama: Don't display the installation message during site install, + it looks funny. +#2759843 by DamienMcKenna: Removed the Alexa verification tag. +#2759855 by DamienMcKenna: Removed the Yahoo verification tag. +#2759917 by Nikhilesh Gupta, cilefen: Remove unused imports / 'use' statements. +#2759927 by Nikhilesh Gupta: Replace deprecated \Drupal::entityManager() + with \Drupal::entityTypeManager(). +#2759919 by Nikhilesh Gupta: Replace deprecated entity->urlInfo() with + entity->toUrl(). +#2755225 by jlbellido: Corrected the 'type' tag generator definition in + tag.php.twig. +#2759931 by Nikhilesh Gupta: Replace deprecated ConfigEntityListBuilder:: + getLabel() with entity->label(). +#2761231 by ashwin.shaharkar: Minor fix to image tag form selection logic. +#2745177 by DamienMcKenna, cilefen: Added tests for each submodule to ensure + they can be enabled and that each meta tag can be used. +#2750705 by susannecoates, jalpesh: Updated description of the Google Play app + ID meta tag. +#2752239 by Saphyel, sylus, DamienMcKenna: Temporary fix for DrupalConsole + integration. +#2775245 by DamienMcKenna: Fix tests. +#2776407 by cilefen: Module names must be wrapped in quotes if they contain + certain characters. +By DamienMcKenna: Renamed the custom routes module. +#2745173 by jibellido: Tag generator now appends metatag_tag.schema.yml. +#2673902 by DamienMcKenna: Confirm that forum posts can be loaded when the + module is enabled and outputting meta tags. +#2707791 by ashwin.shaharkar, DamienMcKenna, Shreya Shetty, MattDanger: Changed + the Description and Abstract meta tags to use a textarea, matching the D7 + branch. +#2780025 by DamienMcKenna: Basic tests for the output of every meta tag. Fixes + the output of all Google Plus tags. Fixed the test route module. +#2746031 by jalpesh, cilefen, DamienMcKenna, susannecoates: Fixed output of all + Twitter Cards meta tags. +#2780109 by DamienMcKenna: Always run drupalGet() before drupalPostForm() to + ensure the form loads correctly. +#2748615 by yannickoo, DamienMcKenna, agentrickard, SteffenR, paulmckibben: Try + generating an empty entity on entity-add (e.g. node/add/*) so default values + can be filled in. +#2775441 by tom_ek, DamienMcKenna: Replace deprecated core entity APIs with the + newer ones. +#2762981 by DamienMcKenna: More codebase changes to only use short array syntax. +#2774807 by DamienMcKenna, Berdir, hussainweb: Token browser showed items that + were irrelevant, and didn't show the correct entities on default config forms. +#2748615 by yannickoo, DamienMcKenna, SteffenR: The default configurations were + not loading properly in entity form fields. +#2752239 by DamienMcKenna: Fixes to Drupal:Console integration. +#1865228 by DamienMcKenna, greggles: Added the Author meta tag. +#2493711 by DamienMcKenna: Added the geographical meta tags. +#1343914 by DamienMcKenna, Dave Reid: Added the (Google+) Publisher meta tag. +By DamienMcKenna: Corrected the changelog comment for #2759927. + + +Metatag 8.x-1.0-beta9, 2016-06-02 +--------------------------------- +#2725895 by DamienMcKenna: Fixed the name of the Validation submodule to avoid + YAML validation errors. Yes, somewhat ironic. +#2725989 by dbt102, DamienMcKenna, neerusrijan: Improve hook_help(). + + +Metatag 8.x-1.0-beta8, 2016-05-14 +--------------------------------- +#2723319 by itmaybejj: Fixed misspelling of 'its'. +#2619450 by paulmckibben: Remove core's Canonical URL tag if Metatag is adding + one. +#2712277 by markdorison: Twitter Card Type meta tag wasn't updating. +#2650408 by Raphael Apard, DamienMcKenna, gaurav.goyal, dpacassi, kyberman: + A node's meta tags should not override the front page defaults unless the + defaults are disabled/deleted. +#2684479 by mikeyk, DamienMcKenna, aspilicious: Added 'secure' option as some + meta tags require HTTPS URLs. +#2699297 by DamienMcKenna: Added tests to ensure submodules can be enabled. +#2663974 by IT-Cru, DamienMcKenna: Added the og 'article' meta tags. +#2650848 by ivanjaros, DamienMcKenna: Only show appropriate entities in the + token browser. +#2705851 by vasi: Load field definitions, not field values, when getting a list + of Metatag fields on an entity. +#2708511 by DamienMcKenna: Added the referrer meta tag. +#2563629 by Jim.M, DamienMcKenna: Added site verification tags. +#2721857 by marvin_B8, DamienMcKenna: Added Google+ meta tags. + + +Metatag 8.x-1.0-beta7, 2016-04-03 +--------------------------------- +#2699173 by DamienMcKenna: Fixed OgUpdatedTime annotations. + + +Metatag 8.x-1.0-beta6, 2016-04-02 +--------------------------------- +#2689543 by kplanz: Fixed paths in image meta tags when the site is in a + subdirectory. +By DamienMcKenna: Added a CODE_OF_CONDUCT.txt file that references the Drupal + code of conduct page. +#2690973 by DamienMcKenna: Added schema.yml values for all meta tags to make + them more easily translatable. +#2688963 by DamienMcKenna: Added a note about the Yoast SEO module. +#2696445 by DuaelFr, Simon Georges, DamienMcKenna: Added the twitter:image:alt + meta tag. +#2692117 by penyaskito, DamienMcKenna: Replaced the 'image' attribute with a + general 'type' attribute. + + +Metatag 8.x-1.0-beta5, 2016-03-11 +--------------------------------- +#2563623/2674732/2675208 by DamienMcKenna, esclapes, NickWilde, achton: Quote + submodule strings to avoid YAML compatibility problems. +#2658242 by mr.baileys: Default meta tags were not translated into the entity's + language. +By DamienMcKenna: Added mr.baileys to the D8 contributors list :) +#2664276 by DamienMcKenna, StevenPatz, rajeev_drupal: Wrong default base class + for generated tag plugins. +#2665790 by benjy, Sam152: Use StringTranslationTrait in MetaNameBase. +#2666384 by mr.baileys, Rudrasis, danisha: Added 'configure' link to the module + on the Extend page. +#2563625 by mr.baileys, juliencarnot: All Twitter Cards have been ported. +#2674078 by Raphael Apard: The Generator meta tag is a META tag, not a LINK tag. +#2664448 by mr.baileys: DrupalConsole generator for meta tag groups. +#2663650 by mr.baileys: Caught another small bug in the tag generator. +#2672892 by borisson_: Replaced usage of LoggerChannelFactory with + LoggerChannelFactoryInterface. +#2678196 by mr.baileys: Simplified usage of isAdminRoute(). +#2631408 by mikeyk, juampynr, DamienMcKenna: Filter out HTML from meta tags and + improve image meta tag handling. +#2631826 by juampynr, DamienMcKenna, pguillard: Require the Token module. +#2667850 by mikeyk: Token method was not renamed properly. +By DamienMcKenna: Fixed group name on MetatagTranslationTest. +#2684495 by mikeyk, DamienMcKenna: Fixed bug in translations that was causing + the tests to fail. Also tidied up the tests a little. +#2685355 by mikeyk: Fix image identification. + + +Metatag 8.x-1.0-beta4, 2016-02-06 +--------------------------------- +#2634844 by swentel: Only load entity meta tags on actual content entity pages. +#2648752 by juampynr: Fixed the token browser integration. +#2642430 by juampynr: Moved settings pages under admin/config. +#2646706 by heykarthikwithu: Removed unused 'use' statements. +#2645338 by Dane Powell: Fixed variable assumptions in MetatagFirehose. +#2643370 by flocondetoile: Fixed hook_block(). +#2631408 by juampynr: Filter HTML from the meta tag output. +#2653512 by DamienMcKenna, ivanjaros: Missing ampersand in drupal_static call. +#2630068 by jaxxed, DamienMcKenna: Moved the meta tags fields into the + 'advanced' section of the entity form. +#2657142 by TravisCarden: Incorrect path in MetatagDefaults annotations. +#2656494 by DamienMcKenna, webflo, cyb.tachyon, alexdmccabe: Added translation + support for the default configs. +#2634844 by mr.baileys: Ensure that the entity system doesn't break entity + pages that don't have meta tags enabled. +#2659854 by mr.baileys: The config inheritance info was displayed when not + needed and was not translatable. +#2624422 by mr.baileys: Added tests to confirm meta tag handling is loaded + correctly when there is no default value available. +#2658902 by swentel, DamienMcKenna: Renamed 'Add Metatag defaults' to something + more easily understood. +#2636348 by DamienMcKenna: Config entity not working correctly after updating + from beta2. +By DamienMcKenna: Note in the README.txt that Token is now required. +#2663874 by mr.baileys: Fixed arguments to annotation translations for two + Google meta tags. +#2663650 by DamienMcKenna: Updated/fixed the DrupalConsole integration. +#2663650 by mr.baileys: Further fixes to the DrupalConsole integration. +#2563623 by DamienMcKenna: Moved OG tags to new submodule, added several more. + + +Metatag 8.x-1.0-beta3, 2015-12-08 +--------------------------------- +#2613654 by Michelle, DamienMcKenna: Automatically parse fields for images. +#2563639 by juampynr, DamienMcKenna: Global configurations system. + + +Metatag 8.x-1.0-beta2, 2015-11-23 +--------------------------------- +#2572469 by Berdir, platinum1, rakesh.gectcr, DamienMcKenna: Fixed the + composer.json file. + + +Metatag 8.x-1.0-beta1, 2015-11-19 +--------------------------------- +Initial port by Damien McKenna and Michelle Cox. +#2563663 by kikoalonsob: Don't convert the title to a string. +#2563621 by jmolivas: Fixed DrupalConsole integration. +#2579865 by afi13: Fixed definition of MetatagEmptyFormatter::viewElements(). +#2563667 by vincic: MetatagManager should only be used for objects implementing + ContentEntityInterface. +#2569043 by Michelle: Field defaults weren't loading (core API change). +#2579295 by Michelle: Fixed the field cardinality limitation. +#2563667 by Michelle: Follow-up to add missing namespace. +#2584835 by DamienMcKenna: Fixed double-HTML encoding of the page title. +#2563637 by larowlan: Added some initial tests for the field type. +#2596753 by Michelle: Don't encode apostrophes in the page title. +#2576695 by Andrej Galuf, larowlan, DamienMcKenna: Double slashes in URLs were + being replaced. +#2603548 by DuaelFr: Clear our the head_title array to avoid the site name being + added a second time. +#2617192 by larowlan: Fixed tests due to a core API change. +#2609138 by rakesh.gectcr: Removed unnecessary 'use' statements. +#2593149 by larowlan: Inject dependencies into MetatagManager. +#2593153 by larowlan: Inject dependencies into MetatagToken. +#2593141 by larowlan: Add a MetatagManagerInterface to avoid type-hinting + concrete implementation. +#2581351 by Michelle, larowlan, DamienMcKenna: Don't save default values to the + field, allow them to inherit from the default field settings. +By DamienMcKenna: Updates to the README.txt file. +#2572469 by rakesh.gectcr, DamienMcKenna, jaxxed, timmillwood: Added a + composer.json file. +By DamienMcKenna: Added a LICENSE.txt to enforce the license on git mirrors. diff --git a/web/modules/metatag/CODE_OF_CONDUCT.txt b/web/modules/metatag/CODE_OF_CONDUCT.txt new file mode 100644 index 0000000000000000000000000000000000000000..587ba66b7c38a2ecd3cbd53ac09e43e4445807a2 --- /dev/null +++ b/web/modules/metatag/CODE_OF_CONDUCT.txt @@ -0,0 +1,3 @@ +Contributor Code of Conduct +--------------------------- +See: https://www.drupal.org/dcoc diff --git a/web/modules/metatag/LICENSE.txt b/web/modules/metatag/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1 --- /dev/null +++ b/web/modules/metatag/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/web/modules/metatag/README.txt b/web/modules/metatag/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..da936bf71f347a57f4ce699634f99f9fb5c37da1 --- /dev/null +++ b/web/modules/metatag/README.txt @@ -0,0 +1,331 @@ +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. + + +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. + + +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' => 'http://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. + + +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 [2] and Dave Reid [3]. Drupal 7 module +originally written by Dave Reid. Early work on Drupal 8 port by Damien McKenna +and Michelle Cox [4], and sponsored by Mediacurrent [5]; key improvements by +Juampy Novillo Requena [6] with insights from Dave Reid and sponsorship by +Lullabot [7] and Acquia [8]. Additional contributions to the 8.x-1.0 release +from cilefen [9], Daniel Wehner [10], Jesus Manuel Olivas [11], Lee Rowlands +[12], Michael Kandelaars [13], Ivo Van Geertruyen [14], Nikhilesh Gupta B [15], +Rakesh James [16], 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/u/damienmckenna +3: https://www.drupal.org/u/dave-reid +4: https://www.drupal.org/u/michelle +5: https://www.mediacurrent.com/ +6: https://www.drupal.org/u/juampynr +7: https://www.lullabot.com/ +8: https://www.acquia.com/ +9: https://www.drupal.org/u/cilefen +10: https://www.drupal.org/u/dawehner +11: https://www.drupal.org/u/jmolivas +12: https://www.drupal.org/u/larowlan +13: https://www.drupal.org/u/mikeyk +14: https://www.drupal.org/u/mr.baileys +15: https://www.drupal.org/u/nikhilesh-gupta +16: https://www.drupal.org/u/rakeshgectcr diff --git a/web/modules/metatag/composer.json b/web/modules/metatag/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..0e7921859e5ded8f09c6070b720d5df8b4f1e55c --- /dev/null +++ b/web/modules/metatag/composer.json @@ -0,0 +1,32 @@ +{ + "name": "drupal/metatag", + "description": "Manage meta tags for all entities.", + "type": "drupal-module", + "license": "GPL-2.0+", + "keywords": [ + "Drupal", + "seo" + ], + "homepage": "https://www.drupal.org/project/metatag", + "authors": [ + { + "name": "See contributors", + "homepage": "https://www.drupal.org/node/640498/committers", + "role": "Developer" + } + ], + "support": { + "issues": "http://drupal.org/project/issues/metatag", + "source": "http://cgit.drupalcode.org/metatag" + }, + "require": { + "drupal/token": "^1.0" + }, + "require-dev": { + "drupal/devel": "^1.0", + "drupal/redirect": "^1.0", + "drupal/restui": "^1.0", + "drupal/page_manager": "^4.0", + "drupal/schema_metatag": "^1.0" + } +} diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.403.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.403.yml new file mode 100644 index 0000000000000000000000000000000000000000..3f88243f101fbeaa97a87f451d2b5ac16e737170 --- /dev/null +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.403.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +id: '403' +label: '403 access denied' +tags: + canonical_url: '[site:url]' + shortlink: '[site:url]' diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.404.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.404.yml new file mode 100644 index 0000000000000000000000000000000000000000..2e44127e991e95b38bdfc8029af5a4fdaf8fecc1 --- /dev/null +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.404.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +id: '404' +label: '404 page not found' +tags: + canonical_url: '[site:url]' + shortlink: '[site:url]' diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.front.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.front.yml new file mode 100644 index 0000000000000000000000000000000000000000..3d928f86fd4d10068914f4f73c81ba34ac3076d6 --- /dev/null +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.front.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +id: front +label: 'Front page' +tags: + canonical_url: '[site:url]' + shortlink: '[site:url]' diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.global.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.global.yml new file mode 100644 index 0000000000000000000000000000000000000000..b0ccb81ddf29300e848537d97796c3b7a094bcd0 --- /dev/null +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.global.yml @@ -0,0 +1,8 @@ +langcode: en +status: true +dependencies: { } +id: global +label: Global +tags: + canonical_url: '[current-page:url]' + title: '[current-page:title] | [site:name]' diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.node.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.node.yml new file mode 100644 index 0000000000000000000000000000000000000000..5e7841a46e084e45249c072c9d21802cafbd24cd --- /dev/null +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.node.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: { } +id: node +label: Content +tags: + title: '[node:title] | [site:name]' + description: '[node:summary]' + canonical_url: '[node:url]' diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.taxonomy_term.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.taxonomy_term.yml new file mode 100644 index 0000000000000000000000000000000000000000..a562d1fa1fee5f24dd01ec75a4e4815470c27041 --- /dev/null +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.taxonomy_term.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: { } +id: taxonomy_term +label: 'Taxonomy term' +tags: + canonical_url: '[term:url]' + description: '[term:description]' + title: '[term:name] | [site:name]' diff --git a/web/modules/metatag/config/install/metatag.metatag_defaults.user.yml b/web/modules/metatag/config/install/metatag.metatag_defaults.user.yml new file mode 100644 index 0000000000000000000000000000000000000000..06dfbe3d13e09a10d9173c16e8a3bda3ca6cc0eb --- /dev/null +++ b/web/modules/metatag/config/install/metatag.metatag_defaults.user.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: { } +id: user +label: User +tags: + canonical_url: '[user:url]' + description: '[site:name]' + title: '[user:display-name] | [site:name]' diff --git a/web/modules/metatag/config/schema/metatag.metatag_defaults.schema.yml b/web/modules/metatag/config/schema/metatag.metatag_defaults.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..4d36bc9272f69fbce0617f2890e9e4e872b778b9 --- /dev/null +++ b/web/modules/metatag/config/schema/metatag.metatag_defaults.schema.yml @@ -0,0 +1,15 @@ +metatag.metatag_defaults.*: + type: config_entity + label: 'Metatag defaults' + mapping: + id: + type: string + label: 'ID' + label: + type: label + label: 'Type' + tags: + type: sequence + label: 'Tags' + sequence: + type: metatag.metatag_tag.[%key] diff --git a/web/modules/metatag/config/schema/metatag.metatag_tag.schema.yml b/web/modules/metatag/config/schema/metatag.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..19c84e4292267aef9352ff282ce232786e58399d --- /dev/null +++ b/web/modules/metatag/config/schema/metatag.metatag_tag.schema.yml @@ -0,0 +1,67 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.abstract: + type: text + label: 'Abstract' +metatag.metatag_tag.canonical_url: + type: label + label: 'Canonical URL' +metatag.metatag_tag.content_language: + type: label + label: 'Content Language' +metatag.metatag_tag.description: + type: text + label: 'Description' +metatag.metatag_tag.generator: + type: label + label: 'Generator' +metatag.metatag_tag.image_src: + type: label + label: 'Image SRC' +metatag.metatag_tag.keywords: + type: text + label: 'Keywords' +metatag.metatag_tag.news_keywords: + type: label + label: 'Google News Keywords' +metatag.metatag_tag.original_source: + type: label + label: 'Original source' +metatag.metatag_tag.rights: + type: label + label: 'Rights' +metatag.metatag_tag.referrer: + type: label + label: 'Referrer policy' +metatag.metatag_tag.robots: + type: label + label: 'Robots' +metatag.metatag_tag.shortlink: + type: label + label: 'Shortlink' +metatag.metatag_tag.standout: + type: label + label: 'Standout' +metatag.metatag_tag.title: + type: label + label: 'Page title' +metatag.metatag_tag.icbm: + type: label + label: 'ICBM' +metatag.metatag_tag.geo_region: + type: label + label: 'Geographical region' +metatag.metatag_tag.geo_placename: + type: label + label: 'Geographical place name' +metatag.metatag_tag.geo_position: + type: label + label: 'Geographical position' +metatag.metatag_tag.set_cookie: + type: label + label: 'Set Cookie' +metatag.metatag_tag.google: + type: label + label: 'Google' diff --git a/web/modules/metatag/config/schema/metatag.schema.yml b/web/modules/metatag/config/schema/metatag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..78c0d71beecdfd9ccb870d412e25489dc514a645 --- /dev/null +++ b/web/modules/metatag/config/schema/metatag.schema.yml @@ -0,0 +1,8 @@ +# Schema for metatag. +field.value.metatag: + type: mapping + label: 'Default value' + mapping: + value: + type: string + label: 'Metatags' diff --git a/web/modules/metatag/config/schema/metatag.settings.schema.yml b/web/modules/metatag/config/schema/metatag.settings.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..e7dd555500ff0b2671f185a64d716bc3cf42394b --- /dev/null +++ b/web/modules/metatag/config/schema/metatag.settings.schema.yml @@ -0,0 +1,7 @@ +metatag.settings: + type: mapping + label: 'Metatag settings' + mapping: + entity_type_groups: + type: mapping + label: 'Metatag groups that apply to each entity type' diff --git a/web/modules/metatag/console.services.yml b/web/modules/metatag/console.services.yml new file mode 100644 index 0000000000000000000000000000000000000000..fd8622d31937f97c9d67edb0fb7e0f308bfa8996 --- /dev/null +++ b/web/modules/metatag/console.services.yml @@ -0,0 +1,24 @@ +services: + metatag.generate_tag: + class: Drupal\metatag\Command\GenerateTagCommand + arguments: ['@metatag.manager', '@metatag.tag_generator', '@?console.extension_manager', '@?console.string_converter', '@?console.chain_queue'] + tags: + - { name: drupal.command } + + metatag.generate_group: + class: Drupal\metatag\Command\GenerateGroupCommand + arguments: ['@metatag.group_generator', '@?console.extension_manager', '@?console.chain_queue'] + 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/console/translations/en/generate.metatag.group.yml b/web/modules/metatag/console/translations/en/generate.metatag.group.yml new file mode 100644 index 0000000000000000000000000000000000000000..a5c5c6a51ad07456820397d15d967d20133969a7 --- /dev/null +++ b/web/modules/metatag/console/translations/en/generate.metatag.group.yml @@ -0,0 +1,17 @@ +description: Generate a meta tag group. +help: The <info>generate:plugin:metatag:group</info> command helps generate a new metatag group for use with the Metatag module. +welcome: Welcome to the Metatag group generator +options: + label: The user-friendly name for this meta tag group. + description: A long explanation of this meta tag group. + plugin_id: Internal (machine) name for the meta tag group. + class_name: Internal camel-case version of the meta tag group's name. + weight: The sort order for this meta tag group. +questions: + base_class: Enter the base class to use + class_name: Enter the class name for the meta tag group class + module: common.questions.module + weight: Enter the sort order for the meta tag group + label: Enter the label for the meta tag group + description: Enter a longer explanation of what the meta tag group is and how to use it + plugin_id: Enter the internal (machine) name for the meta tag group plugin diff --git a/web/modules/metatag/console/translations/en/generate.metatag.tag.yml b/web/modules/metatag/console/translations/en/generate.metatag.tag.yml new file mode 100644 index 0000000000000000000000000000000000000000..017c9e9299f5f8815be556b289d304cff3a4ee0a --- /dev/null +++ b/web/modules/metatag/console/translations/en/generate.metatag.tag.yml @@ -0,0 +1,31 @@ +description: Generate a meta tag. +help: The <info>generate:plugin:metatag:tag</info> command helps generate a new meta tag for use with the Metatag module. +welcome: Welcome to the Metatag tag generator +options: + base_class: The base meta tag class to use. + module: common.options.module + name: Meta tag's HTML "name". + label: The user-friendly name for this meta tag. + description: A long explanation of this meta tag. + plugin_id: Internal (machine) name for the meta tag. + class_name: Internal camel-case version of the meta tag's name. + group: The meta tag's group. + weight: The sort order for this meta tag. + type: Type of the data included in this meta tag value. + secure: Whether this meta tag requires URLs be secure. + multiple: Whether this meta tag allows multiple values. + absolute_url: Whether this meta tag requires absolute URLs. +questions: + base_class: Enter the base class to use + module: common.questions.module + name: Enter the meta tag's formal name, e.g. for the Open Graph "Title" tag use "og:title" + label: Enter a user-friendly version of the meta tag's name + description: Enter a longer explanation of what the meta tag is and how to use it + plugin_id: Enter the internal (machine) name for the meta tag plugin + class_name: Enter a camel-case version of the meta tag's name + group: Select the group the meta tag will use + weight: Enter the sort order for the meta tag + type: Which value type does this meta tag allow? + secure: Must this meta tag for URLs be secure? + multiple: Does this meta tag will allow multiple values? + absolute_url: Does this meta tag require absolute URLs to work? diff --git a/web/modules/metatag/metatag.api.php b/web/modules/metatag/metatag.api.php new file mode 100644 index 0000000000000000000000000000000000000000..cd2ad01d86c67603530865e3ede547a26e0cb774 --- /dev/null +++ b/web/modules/metatag/metatag.api.php @@ -0,0 +1,59 @@ +<?php + +/** + * @file + * Document all supported APIs. + */ + +/** + * Provides a ability to integrate alternative routes with metatags. + * + * Return an entity when the given route/route parameters matches a certain + * entity. All meta tags will be rendered on that page. + * + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. + * + * @return \Drupal\Core\Entity\EntityInterface|null + * Return an entity, if the route should use metatags. + */ +function hook_metatag_route_entity(\Drupal\Core\Routing\RouteMatchInterface $route_match) { + if ($route_match->getRouteName() === 'example.test_route') { + if ($node = $route_match->getParameter('node')) { + return $node; + } + } +} + +/** + * Alter the meta tags for pages that are not of content entities. + * + * @param array $metatags + * The special meta tags to be added to the page. + * @param array $context + * The context for the current meta tags being generated. Will contain the + * following: + * 'entity' - The entity being processed; passed by reference. + */ +function hook_metatags_alter(array &$metatags, array &$context) { + // Exclude meta tags on frontpage. + if (\Drupal::service('path.matcher')->isFrontPage()) { + $metatags = NULL; + } +} + +/** + * Alter the meta tags for any page prior to page attachment. + * + * @param array $metatag_attachments + * An array of metatag objects to be attached to the current page. + */ +function hook_metatags_attachments_alter(array &$metatag_attachments) { + if (\Drupal::service('path.matcher')->isFrontPage() && \Drupal::currentUser()->isAnonymous()) { + foreach ($metatag_attachments['#attached']['html_head'] as $id => $attachment) { + if ($attachment[1] == 'title') { + $metatag_attachments['#attached']['html_head'][$id][0]['#attributes']['content'] = 'Front Page Title for Anonymous Users'; + } + } + } +} diff --git a/web/modules/metatag/metatag.info.yml b/web/modules/metatag/metatag.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..37efe692bb58460e9beb98a2ccf4614d4ad42f91 --- /dev/null +++ b/web/modules/metatag/metatag.info.yml @@ -0,0 +1,20 @@ +name: Metatag +type: module +description: Manage meta tags for all entities. +# core: 8.x +package: SEO +configure: entity.metatag_defaults.collection +dependencies: + - drupal:field + - token:token +test_dependencies: + - devel:devel + - redirect:redirect + - restui:restui + - schema_metatag:schema_web_page + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag.install b/web/modules/metatag/metatag.install new file mode 100644 index 0000000000000000000000000000000000000000..2f96a4941fd73760f27f5bed1c4cbc7c1357d284 --- /dev/null +++ b/web/modules/metatag/metatag.install @@ -0,0 +1,376 @@ +<?php + +/** + * @file + * Install, update and uninstall functions for the metatag module. + */ + +/** + * Implements hook_install(). + */ +function metatag_install() { + // Don't display the message during site installation, it looks funny. + if (!drupal_installation_attempted()) { + drupal_set_message(t("To adjust global defaults, go to admin/config/search/metatag. If you need to set meta tags for a specific entity, edit its bundle and add the Metatag field.")); + } +} + +/** + * Implements hook_requirements(). + */ +function metatag_requirements($phase) { + $requirements = []; + + if ($phase == 'runtime') { + // Recommend the Schema.org Metatag module. + if (!\Drupal::moduleHandler()->moduleExists('schema_metatag')) { + $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.', [ + '@module' => 'https://www.drupal.org/project/schema_metatag', + '@jsonld' => 'https://json-ld.org', + '@schema' => 'http://schema.org', + ]), + ]; + } + else { + $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.', [ + '@module' => 'https://www.drupal.org/project/schema_metatag', + ]), + ]; + } + } + + return $requirements; +} + +/** + * Remove tags in field storage that match default or are empty. + */ +function metatag_update_8101() { + // Get all of the field storage entities of type metatag. + $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]); + + // For each of the fields, delete all records that match the defaults. + foreach ($fields as $field) { + // Get the bundle this field is attached to. + $bundle = $field->getTargetBundle(); + + // Get the default value for this field on this bundle. + $field_default_tags_value = $field->getDefaultValueLiteral(); + $field_default_tags_value = $field_default_tags_value[0]['value']; + + // Determine the table and "value" field names. + $field_table = "node__" . $field_name; + $field_value_field = $field_name . "_value"; + + // Delete all records where the field value and default are identical. + \Drupal::database()->delete($field_table) + ->condition('bundle', $bundle, '=') + ->condition($field_value_field, $field_default_tags_value, '=') + ->execute(); + } + } + + return t('Removed all default meta tag records so they can be automatically inherited when the page is loaded.'); +} + +/** + * Remove tags in field storage that match default or are empty. + */ +function metatag_update_8102(&$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. + $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]); + + // For each of the fields, do the mass delete of exact matches but + // store the overridden records in the sandbox to be batch processed. + foreach ($fields as $field) { + // Get the bundle this field is attached to. + $bundle = $field->getTargetBundle(); + + // Get the default value for this field on this bundle. + $field_default_tags_value = $field->getDefaultValueLiteral(); + $field_default_tags_value = $field_default_tags_value[0]['value']; + $field_default_tags = unserialize($field_default_tags_value); + + // Determine the table and "value" field names. + $field_table = "node__" . $field_name; + $field_value_field = $field_name . "_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(); + + // 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]['field_default_tags'] = $field_default_tags; + $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']; + $field_default_tags = $sandbox['fields'][$current_field]['field_default_tags']; + + // Loop through the field(s) and remove any field data that matches the + // field default for that bundle. Because the ability to override a default + // with "nothing" didn't exist prior to this and because any tag that had + // a default of "nothing" would have that also in the field data, we are + // removing those as well. + while ($counter <= $max_per_batch && $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. + $current_tags = unserialize($record->$field_value_field); + $new_tags = []; + foreach ($current_tags as $key => $tag) { + if (!empty($tag) && $field_default_tags[$key] != $tag) { + $new_tags[$key] = $tag; + } + } + + if (empty($new_tags)) { + // All tags were either empty or matched the default so the record can + // be deleted. + \Drupal::database()->delete($field_table) + ->condition('entity_id', $record->entity_id) + ->condition('revision_id', $record->revision_id) + ->condition('langcode', $record->langcode) + ->execute(); + } + else { + // There are some overridden tags so update the record with just those. + $tags_string = serialize($new_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."); + } +} + +/** + * Move field defaults to Metatag Defaults. + */ +function metatag_update_8103() { + $config_installer = \Drupal::service('config.installer'); + $entity_manager = \Drupal::entityTypeManager(); + + // 1. Install cofiguration. + $sync_status = $config_installer->isSyncing(); + if ($sync_status) { + $source_storage = $config_installer->getSourceStorage(); + } + + // Clear plugin manager caches. + \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); + // Install default configuration of the module. + if ($sync_status) { + $config_installer + ->setSyncing(TRUE) + ->setSourceStorage($source_storage); + } + + // Install new configuration for Metatag. + $config_installer->installDefaultConfig('module', 'metatag'); + + // Apply all entity definition changes. + \Drupal::entityDefinitionUpdateManager()->applyUpdates(); + + // 2. Extract Metatag field defaults. + $entity_info = $entity_manager->getDefinitions(); + $tags = []; + + // Get all of the field storage entities of type metatag. + $field_storage_configs = $entity_manager + ->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 = $entity_manager->getStorage('field_config') + ->loadByProperties(['field_name' => $field_name]); + foreach ($fields as $field) { + // Adjust the config id depending on whether these are entity defaults + // or bundle defaults. + $entity_type = $field->getTargetEntityTypeId(); + $bundle = $field->getTargetBundle(); + $metatag_defaults_id = $entity_type; + if ($entity_type != $bundle) { + // This is a bundle override. + $metatag_defaults_id = $entity_type . '__' . $bundle; + } + // Extract field default values. + $field_default_tags_value = $field->getDefaultValueLiteral(); + $field_default_tags_value = unserialize($field_default_tags_value[0]['value']); + $field_default_tags_value = array_filter($field_default_tags_value); + // Don't bother copying empty values. + if (!empty($field_default_tags_value)) { + $tags[$metatag_defaults_id] = $field_default_tags_value; + } + } + } + + // 3. Create Config entities with field default values. + if (!empty($tags)) { + $bundleInfoManager = \Drupal::service('entity_type.bundle.info'); + foreach ($tags as $metatag_defaults_id => $values) { + list($entity_type, $entity_bundle) = explode('__', $metatag_defaults_id); + $entity_label = (string) $entity_info[$entity_type]->get('label'); + $bundle_info = $bundleInfoManager->getBundleInfo($entity_type); + $bundle_label = $bundle_info[$entity_bundle]['label']; + $label = $entity_label . ': ' . $bundle_label; + + $metatags_global_manager = $entity_manager->getStorage('metatag_defaults'); + + $entity = $metatags_global_manager->load($metatag_defaults_id); + if ($entity) { + // These are defaults for an existing config entity, such as User. + $entity->set('tags', $values); + } + else { + // These are bundle overrides. + $entity = $metatags_global_manager->create([ + 'id' => $metatag_defaults_id, + 'label' => $label, + 'tags' => $values, + ]); + } + $entity->save(); + } + return (string) t("@count Metatag field defaults have been converted to using global entity defaults.", ['@count' => count($tags)]); + } + else { + return (string) t("There were Metatag field configurations that needed to be converted."); + } +} + +/** + * Rebuild routes after moving Metatag admin from Structure to Config. + */ +function metatag_update_8104() { + \Drupal::service('router.builder')->setRebuildNeeded(); +} + +/** + * Rebuild routes after renaming. + */ +function metatag_update_8105() { + \Drupal::service('router.builder')->setRebuildNeeded(); +} + +/** + * Add the metatag_defaults config entity to the site. + */ +function metatag_update_8106() { + \Drupal::entityDefinitionUpdateManager()->applyUpdates(); +} + +/** + * Enable the new metatag_open_graph module. + */ +function metatag_update_8107() { + \Drupal::service('module_installer')->install(['metatag_open_graph']); + return (string) t("The new Metatag: Open Graph module has been enabled."); +} diff --git a/web/modules/metatag/metatag.links.action.yml b/web/modules/metatag/metatag.links.action.yml new file mode 100644 index 0000000000000000000000000000000000000000..6ed508f60af894172ba2d678050264b7c8c361e1 --- /dev/null +++ b/web/modules/metatag/metatag.links.action.yml @@ -0,0 +1,5 @@ +entity.metatag_defaults.add_form: + route_name: 'entity.metatag_defaults.add_form' + title: 'Add default meta tags' + appears_on: + - entity.metatag_defaults.collection diff --git a/web/modules/metatag/metatag.links.menu.yml b/web/modules/metatag/metatag.links.menu.yml new file mode 100644 index 0000000000000000000000000000000000000000..f1fef7187313c2207266a794286c45d6a85d625e --- /dev/null +++ b/web/modules/metatag/metatag.links.menu.yml @@ -0,0 +1,11 @@ +# Metatag defaults menu items definition +entity.metatag_defaults.collection: + title: 'Metatag' + route_name: entity.metatag_defaults.collection + description: 'Configure Metatag defaults.' + parent: system.admin_config_search +metatag.settings: + title: 'Settings' + route_name: metatag.settings + description: 'Configure Metatag defaults.' + parent: entity.metatag_defaults.collection diff --git a/web/modules/metatag/metatag.links.task.yml b/web/modules/metatag/metatag.links.task.yml new file mode 100644 index 0000000000000000000000000000000000000000..637e9beb56f6adaa3f38be7642a22dde381573d5 --- /dev/null +++ b/web/modules/metatag/metatag.links.task.yml @@ -0,0 +1,10 @@ +metatag_defaults: + route_name: 'entity.metatag_defaults.collection' + base_route: 'entity.metatag_defaults.collection' + title: 'Metatag defaults' + weight: 0 +metatag.settings: + route_name: 'metatag.settings' + base_route: 'entity.metatag_defaults.collection' + title: 'Settings' + weight: 10 diff --git a/web/modules/metatag/metatag.module b/web/modules/metatag/metatag.module new file mode 100644 index 0000000000000000000000000000000000000000..b9fad84a6df09831476984d7dd6ca35e5cedb1d0 --- /dev/null +++ b/web/modules/metatag/metatag.module @@ -0,0 +1,605 @@ +<?php + +/** + * @file + * Contains metatag.module. + */ + +use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Url; +use Drupal\taxonomy\TermInterface; +use Drupal\Component\Utility\Html; + +/** + * Implements hook_help(). + */ +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 .= '<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 .= '</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>'; + 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>'; + return $output; + } +} + +/** + * 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) { + if ($form_state->getFormObject()->getEntity()->getType() == 'metatag') { + // Hide the cardinality field. + $form['cardinality_container']['#access'] = FALSE; + $form['cardinality_container']['#disabled'] = TRUE; + } +} + +/** + * Implements hook_form_FORM_ID_alter() for 'field_config_edit_form'. + * + * Configuration defaults are handled via a different mechanism, so do not allow + * any values to be saved. + */ +function metatag_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state) { + if ($form_state->getFormObject()->getEntity()->getType() == 'metatag') { + // Hide the required and default value fields. + $form['required']['#access'] = FALSE; + $form['required']['#disabled'] = TRUE; + $form['default_value']['#access'] = FALSE; + $form['default_value']['#disabled'] = TRUE; + + // Step through the default value structure and erase any '#default_value' + // items that are found. + foreach ($form['default_value']['widget'][0] as &$outer) { + if (is_array($outer)) { + foreach ($outer as &$inner) { + if (is_array($inner) && isset($inner['#default_value'])) { + if (is_array($inner['#default_value'])) { + $inner['#default_value'] = []; + } + else { + $inner['#default_value'] = NULL; + } + } + } + } + } + } +} + +/** + * Implements hook_page_attachments(). + * + * Load all meta tags for this page. + */ +function metatag_page_attachments(array &$attachments) { + if (!metatag_is_current_route_supported()) { + return NULL; + } + + $metatag_attachments = &drupal_static('metatag_attachments'); + + if (is_null($metatag_attachments)) { + // Load the meta tags from the route. + $metatag_attachments = metatag_get_tags_from_route(); + } + if (!$metatag_attachments) { + return NULL; + } + + // Trigger hook_metatags_attachments_alter(). + // Allow modules to rendered metatags prior to attaching. + \Drupal::service('module_handler')->alter('metatags_attachments', $metatag_attachments); + + // If any Metatag items were found, append them. + if (!empty($metatag_attachments['#attached']['html_head'])) { + if (empty($attachments['#attached'])) { + $attachments['#attached'] = []; + } + if (empty($attachments['#attached']['html_head'])) { + $attachments['#attached']['html_head'] = []; + } + + $head_links = []; + foreach ($metatag_attachments['#attached']['html_head'] as $item) { + $attachments['#attached']['html_head'][] = $item; + + // Also add a HTTP header "Link:" for canonical URLs and shortlinks. + // See HtmlResponseAttachmentsProcessor::processHtmlHeadLink() for the + // implementation of the functionality in core. + if (in_array($item[1], ['canonical_url', 'shortlink'])) { + $attributes = $item[0]['#attributes']; + + $href = '<' . Html::escape($attributes['href']) . '>'; + unset($attributes['href']); + if ($param = drupal_http_header_attributes($attributes)) { + $href .= ';' . $param; + } + $head_links[] = $href; + } + } + + // If any HTTP Header items were found, add them too. + if (!empty($head_links)) { + $attachments['#attached']['http_header'][] = [ + 'Link', + implode(', ', $head_links), + FALSE, + ]; + } + } +} + +/** + * Implements hook_module_implements_alter(). + */ +function metatag_module_implements_alter(&$implementations, $hook) { + if ($hook == 'page_attachments_alter') { + // Move metatag_page_attachments_alter() to the end of the list. This is so + // the canonical and shortlink tags can be removed that are added by + // taxonomy_page_attachments_alter(). + // @todo Remove once https://www.drupal.org/node/2282029 is fixed. + $group = $implementations['metatag']; + unset($implementations['metatag']); + $implementations['metatag'] = $group; + } +} + +/** + * Implements hook_page_attachments_alter(). + */ +function metatag_page_attachments_alter(array &$attachments) { + $route_match = \Drupal::routeMatch(); + // Can be removed once https://www.drupal.org/node/2282029 is fixed. + if ($route_match->getRouteName() == 'entity.taxonomy_term.canonical' && ($term = $route_match->getParameter('taxonomy_term')) && $term instanceof TermInterface) { + _metatag_remove_duplicate_entity_tags($attachments); + } +} + +/** + * Implements hook_entity_view_alter(). + */ +function metatag_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) { + // If this is a 403 or 404 page then don't output these meta tags. + // @todo Make the default meta tags load properly so this is unnecessary. + if ($display->getOriginalId() == 'node.403.default' || $display->getOriginalId() == 'node.404.default') { + $build['#attached']['html_head_link'] = []; + return; + } + + // Panelized entities still use the original entity's controller, but with + // custom built entities. In those cases hook_entity_view_alter might be + // called too early, where meta links are not yet set. + // @see \Drupal\node\Controller\NodeController::view + if ($display->getThirdPartySetting('panelizer', 'enable', FALSE)) { + $build['#pre_render'][] = '_metatag_panelizer_pre_render'; + return; + } + + _metatag_remove_duplicate_entity_tags($build); +} + +/** + * Pre render callback for entities processed by Panelizer. + * + * @param array $element + * The render array being processed. + * + * @return array + * The filtered render array. + */ +function _metatag_panelizer_pre_render(array $element) { + _metatag_remove_duplicate_entity_tags($element); + return $element; +} + +/** + * Remove duplicate entity tags from a build. + * + * @param array $build + * The build. + */ +function _metatag_remove_duplicate_entity_tags(array &$build) { + // Some entities are built with a link rel="canonical" and/or link + // rel="shortlink" tag attached. + // If metatag provides them, remove the ones built with the entity. + if (isset($build['#attached']['html_head_link'])) { + $metatag_attachments = &drupal_static('metatag_attachments'); + if (is_null($metatag_attachments)) { + // Load the meta tags from the route. + $metatag_attachments = metatag_get_tags_from_route(); + } + + // Check to see if the page currently outputs a canonical and/or shortlink + // tag. + if (isset($metatag_attachments['#attached']['html_head'])) { + 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'])) { + // Remove the link rel="canonical" or link rel="shortlink" tag + // from the entity's build array. + unset($build['#attached']['html_head_link'][$key]); + } + } + } + } + } + } +} + +/** + * Identify whether the current route is supported by the module. + * + * @return bool + * TRUE if the current route is supported. + */ +function metatag_is_current_route_supported() { + // If upgrading, we need to wait for database updates to complete. + $is_ready = \Drupal::service('entity_type.manager') + ->getDefinition('metatag_defaults', FALSE); + if (!$is_ready) { + return FALSE; + } + + // Ignore admin paths. + if (\Drupal::service('router.admin_context')->isAdminRoute()) { + return FALSE; + } + + return TRUE; +} + +/** + * Returns the entity of the current route. + * + * @return Drupal\Core\Entity\EntityInterface + * 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(); + + // 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); + } + + // Look for a rest entity view page, e.g. "node/{nid}?_format=json", etc. + $matches = []; + // Matches e.g. "rest.entity.node.GET.json". + preg_match('/rest\.entity\.(.*)\.(.*)\.(.*)/', $route_name, $matches); + if (!empty($matches[1])) { + $entity_type = $matches[1]; + return $route_match->getParameter($entity_type); + } + + // Look for entity object 'add' pages, e.g. "node/add/{bundle}". + $route_name_matches = []; + preg_match('/(entity\.)?(.*)\.add(_form)?/', $route_name, $route_name_matches); + if (!empty($route_name_matches[2])) { + $entity_type = $route_name_matches[2]; + $definition = Drupal::entityTypeManager()->getDefinition($entity_type, FALSE); + if (!empty($definition)) { + $type = $route_match->getRawParameter($definition->get('bundle_entity_type')); + if (!empty($type)) { + return \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->create([ + $definition->get('entity_keys')['bundle'] => $type, + ]); + } + } + } + + // Look for entity object 'edit' pages, e.g. "node/{entity_id}/edit". + $route_name_matches = []; + preg_match('/entity\.(.*)\.edit_form/', $route_name, $route_name_matches); + if (!empty($route_name_matches[1])) { + $entity_type = $route_name_matches[1]; + $entity_id = $route_match->getRawParameter($entity_type); + + if (!empty($entity_id)) { + return \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->load($entity_id); + } + } + + // Look for entity object 'add content translation' pages, e.g. + // "node/{nid}/translations/add/{source_lang}/{translation_lang}". + $route_name_matches = []; + preg_match('/(entity\.)?(.*)\.content_translation_add/', $route_name, $route_name_matches); + if (!empty($route_name_matches[2])) { + $entity_type = $route_name_matches[2]; + $definition = Drupal::entityTypeManager()->getDefinition($entity_type, FALSE); + if (!empty($definition)) { + $node = $route_match->getParameter($entity_type); + $type = $node->bundle(); + if (!empty($type)) { + return \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->create([ + $definition->get('entity_keys')['bundle'] => $type, + ]); + } + } + } + + // Special handling for the admin user_create page. In this case, there's only + // 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'; + $definition = Drupal::entityTypeManager()->getDefinition($entity_type); + if (!empty($type)) { + return \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->create([ + $definition->get('entity_keys')['bundle'] => $type, + ]); + } + } + + // Trigger hook_metatag_route_entity(). + if ($entities = \Drupal::moduleHandler()->invokeAll('metatag_route_entity', [$route_match])) { + return reset($entities); + } + + return NULL; +} + +/** + * Implements template_preprocess_html(). + */ +function metatag_preprocess_html(&$variables) { + if (!metatag_is_current_route_supported()) { + return NULL; + } + + $attachments = &drupal_static('metatag_attachments'); + if (is_null($attachments)) { + $attachments = metatag_get_tags_from_route(); + } + + if (!$attachments) { + return NULL; + } + + // Load the page title. + if (!empty($attachments['#attached']['html_head'])) { + foreach ($attachments['#attached']['html_head'] as $key => $attachment) { + if (!empty($attachment[1]) && $attachment[1] == 'title') { + // Empty head_title to avoid the site name and slogan to be appended to + // the meta title. + $variables['head_title'] = []; + $variables['head_title']['title'] = html_entity_decode($attachment[0]['#attributes']['content'], ENT_QUOTES); + break; + } + } + } +} + +/** + * Load the meta tags by processing the route parameters. + * + * @return mixed + * Array of meta tags or NULL. + */ +function metatag_get_tags_from_route($entity = NULL) { + $metatag_manager = \Drupal::service('metatag.manager'); + + // First, get defaults. + $metatags = metatag_get_default_tags($entity); + if (!$metatags) { + return NULL; + } + + // Then, set tag overrides for this particular entity. + if (!$entity) { + $entity = metatag_get_route_entity(); + } + + if (!empty($entity) && $entity instanceof ContentEntityInterface) { + // If content entity does not have an ID the page is likely an "Add" page, + // so do not generate meta tags for entity which has not been created yet. + if (!$entity->id()) { + return NULL; + } + + foreach ($metatag_manager->tagsFromEntity($entity) as $tag => $data) { + $metatags[$tag] = $data; + } + } + + // Trigger hook_metatags_alter(). + // Allow modules to override tags or the entity used for token replacements. + $context = [ + 'entity' => &$entity, + ]; + \Drupal::service('module_handler')->alter('metatags', $metatags, $context); + + // If the entity was changed above, use that for generating the meta tags. + if (isset($context['entity'])) { + $entity = $context['entity']; + } + + return $metatag_manager->generateElements($metatags, $entity); +} + +/** + * Returns default tags for the current route. + * + * @return mixed + * Array of tags or NULL; + */ +function metatag_get_default_tags($entity = NULL) { + /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $global_metatag_manager */ + $global_metatag_manager = \Drupal::entityTypeManager()->getStorage('metatag_defaults'); + // First we load global defaults. + $metatags = $global_metatag_manager->load('global'); + if (!$metatags) { + return NULL; + } + + // Check if this is a special page. + $special_metatags = \Drupal::service('metatag.manager')->getSpecialMetatags(); + if (isset($special_metatags)) { + $metatags->overwriteTags($special_metatags->get('tags')); + } + + // Next check if there is this page is an entity that has meta tags. + else { + if (!$entity) { + $entity = metatag_get_route_entity(); + } + + if (!empty($entity) && $entity instanceof ContentEntityInterface) { + $entity_metatags = $global_metatag_manager->load($entity->getEntityTypeId()); + if ($entity_metatags != NULL) { + // Merge with global defaults. + $metatags->overwriteTags($entity_metatags->get('tags')); + } + + // Finally, check if bundle overrides should be added. + $bundle_metatags = $global_metatag_manager->load($entity->getEntityTypeId() . '__' . $entity->bundle()); + if ($bundle_metatags != NULL) { + // Merge with existing defaults. + $metatags->overwriteTags($bundle_metatags->get('tags')); + } + } + } + + return $metatags->get('tags'); +} + +/** + * Implements hook_entity_base_field_info(). + */ +function metatag_entity_base_field_info(EntityTypeInterface $entity_type) { + $fields = []; + $base_table = $entity_type->getBaseTable(); + $canonical_template_exists = $entity_type->hasLinkTemplate('canonical'); + // Certain classes are just not supported. + $original_class = $entity_type->getOriginalClass(); + $classes_to_skip = [ + 'Drupal\comment\Entity\Comment', + ]; + + // If the entity type doesn't have a base table, has no link template then + // there's no point in supporting it. + if (!empty($base_table) && $canonical_template_exists && !in_array($original_class, $classes_to_skip)) { + $fields['metatag'] = BaseFieldDefinition::create('map') + ->setLabel(t('Metatags')) + ->setDescription(t('The meta tags for the entity.')) + ->setClass('\Drupal\metatag\Plugin\Field\MetatagEntityFieldItemList') + ->setComputed(TRUE) + ->setTranslatable(TRUE) + ->setTargetEntityTypeId($entity_type->id()); + } + + return $fields; +} + +/** + * Implements hook_entity_diff_options(). + */ +function metatag_entity_diff_options($entity_type) { + if (metatag_entity_supports_metatags($entity_type)) { + $options = [ + 'metatag' => t('Metatags'), + ]; + return $options; + } +} + +/** + * Implements hook_entity_diff(). + */ +function metatag_entity_diff($old_entity, $new_entity, $context) { + $result = []; + $entity_type = $context['entity_type']; + $options = variable_get('diff_additional_options_' . $entity_type, []); + if (!empty($options['metatag']) && metatag_entity_supports_metatags($entity_type)) { + // Find meta tags that are set on either the new or old entity. + $tags = []; + foreach (['old' => $old_entity, 'new' => $new_entity] as $entity_key => $entity) { + $language = metatag_entity_get_language($entity_type, $entity); + if (isset($entity->metatags[$language])) { + foreach ($entity->metatags[$language] as $key => $value) { + $tags[$key][$entity_key] = $value['value']; + } + } + } + + $init_weight = 100; + foreach ($tags as $key => $values) { + $id = ucwords('Meta ' . $key); + // @todo Find the default values and show these if not set. + $result[$id] = [ + '#name' => $id, + '#old' => [empty($values['old']) ? '' : $values['old']], + '#new' => [empty($values['new']) ? '' : $values['new']], + '#weight' => $init_weight++, + '#settings' => [ + 'show_header' => TRUE, + ], + ]; + } + } + return $result; +} + +/** + * Turn the meta tags for an entity into a human readable structure. + * + * @param object $entity + * The entity object. + * + * @return array + * All of the meta tags in a nested structure. + */ +function metatag_generate_entity_metatags($entity) { + $values = []; + $raw = metatag_get_tags_from_route($entity); + if (!empty($raw['#attached']['html_head'])) { + foreach ($raw['#attached']['html_head'] as $tag) { + $values[$tag[1]] = $tag[0]; + } + } + return $values; +} diff --git a/web/modules/metatag/metatag.permissions.yml b/web/modules/metatag/metatag.permissions.yml new file mode 100644 index 0000000000000000000000000000000000000000..bdff82ed4693d1d2b7632528a6310fa4ca0dc887 --- /dev/null +++ b/web/modules/metatag/metatag.permissions.yml @@ -0,0 +1,4 @@ +'administer meta tags': + title: Administer meta tags + description: Control the main settings pages and modify per-object meta tags. + 'restrict access': TRUE diff --git a/web/modules/metatag/metatag.routing.yml b/web/modules/metatag/metatag.routing.yml new file mode 100644 index 0000000000000000000000000000000000000000..d809e4dbc2818d888dcc4ca402305a5215c3216a --- /dev/null +++ b/web/modules/metatag/metatag.routing.yml @@ -0,0 +1,60 @@ +# MetatagDefaults routing definition +entity.metatag_defaults.collection: + path: '/admin/config/search/metatag' + defaults: + _entity_list: 'metatag_defaults' + _title: 'Metatag' + requirements: + _permission: 'administer meta tags' + options: + _admin_route: TRUE + +entity.metatag_defaults.add_form: + path: '/admin/config/search/metatag/add' + defaults: + _entity_form: 'metatag_defaults.add' + _title: 'Add default meta tags' + requirements: + _permission: 'administer meta tags' + options: + _admin_route: TRUE + +entity.metatag_defaults.edit_form: + path: '/admin/config/search/metatag/{metatag_defaults}' + defaults: + _entity_form: 'metatag_defaults.edit' + _title: 'Edit default meta tags' + requirements: + _permission: 'administer meta tags' + options: + _admin_route: TRUE + +entity.metatag_defaults.delete_form: + path: '/admin/config/search/metatag/{metatag_defaults}/delete' + defaults: + _entity_form: 'metatag_defaults.delete' + _title: 'Delete default meta tags' + requirements: + _permission: 'administer meta tags' + options: + _admin_route: TRUE + +entity.metatag_defaults.revert_form: + path: '/admin/config/search/metatag/{metatag_defaults}/revert' + defaults: + _entity_form: 'metatag_defaults.revert' + _title: 'Revert default meta tags' + requirements: + _permission: 'administer meta tags' + options: + _admin_route: TRUE + +metatag.settings: + path: '/admin/config/search/metatag/settings' + defaults: + _form: '\Drupal\metatag\Form\MetatagSettingsForm' + _title: 'Configure the Metatag module' + requirements: + _permission: 'administer meta tags' + options: + _admin_route: TRUE diff --git a/web/modules/metatag/metatag.services.yml b/web/modules/metatag/metatag.services.yml new file mode 100644 index 0000000000000000000000000000000000000000..c55377f13fa23e4b9c38083bc4604c4e604cf0de --- /dev/null +++ b/web/modules/metatag/metatag.services.yml @@ -0,0 +1,16 @@ +services: + plugin.manager.metatag.tag: + class: Drupal\metatag\MetatagTagPluginManager + parent: default_plugin_manager + + plugin.manager.metatag.group: + class: Drupal\metatag\MetatagGroupPluginManager + parent: default_plugin_manager + + metatag.token: + class: Drupal\metatag\MetatagToken + arguments: ['@token'] + + metatag.manager: + class: Drupal\metatag\MetatagManager + arguments: ['@plugin.manager.metatag.group', '@plugin.manager.metatag.tag', '@metatag.token', '@logger.factory', '@entity_type.manager'] diff --git a/web/modules/metatag/metatag_app_links/config/schema/metatag_app_links.metatag_tag.schema.yml b/web/modules/metatag/metatag_app_links/config/schema/metatag_app_links.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..d8eb413e84effae183707eaa4dd5c886606e92c1 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/config/schema/metatag_app_links.metatag_tag.schema.yml @@ -0,0 +1,76 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.al_android_app_name: + type: label + label: 'Android app name' +metatag.metatag_tag.al_android_class: + type: label + label: 'Android app Activity Class' +metatag.metatag_tag.al_android_package: + type: label + label: 'Android app package ID' +metatag.metatag_tag.al_android_url: + type: label + label: 'Android app URL scheme' +metatag.metatag_tag.al_ios_url: + type: label + label: 'iOS app URL scheme' +metatag.metatag_tag.al_ios_app_store_id: + type: label + label: 'iOS app store ID' +metatag.metatag_tag.al_ios_app_name: + type: label + label: 'iOS app name' +metatag.metatag_tag.al_ipad_url: + type: label + label: 'iPad app URL scheme' +metatag.metatag_tag.al_ipad_app_store_id: + type: label + label: 'iPad app store ID' +metatag.metatag_tag.al_ipad_app_name: + type: label + label: 'iPad app name' +metatag.metatag_tag.al_iphone_url: + type: label + label: 'iPhone app URL scheme' +metatag.metatag_tag.al_iphone_app_store_id: + type: label + label: 'iPhone app store ID' +metatag.metatag_tag.al_iphone_app_name: + type: label + label: 'iPhone app URL scheme' +metatag.metatag_tag.al_windows_app_id: + type: label + label: 'Windows app GUID' +metatag.metatag_tag.al_windows_app_name: + type: label + label: 'Windows app name' +metatag.metatag_tag.al_windows_url: + type: label + label: 'Windows app URL scheme' +metatag.metatag_tag.al_windows_phone_url: + type: label + label: 'Windows Phone app URL scheme' +metatag.metatag_tag.al_windows_phone_app_id: + type: label + label: 'Windows Phone app GUID' +metatag.metatag_tag.al_windows_phone_app_name: + type: label + label: 'Windows Phone app name' +metatag.metatag_tag.al_windows_universal_url: + type: label + label: 'Windows Universal app URL scheme' +metatag.metatag_tag.al_windows_universal_app_id: + type: label + label: 'Windows Universal app GUID' +metatag.metatag_tag.al_windows_universal_app_name: + type: label + label: 'Windows Universal app name' +metatag.metatag_tag.al_web_url: + type: label + label: 'Web URL' +metatag.metatag_tag.al_web_should_fallback: + type: label + label: 'Should fallback' 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 new file mode 100644 index 0000000000000000000000000000000000000000..0c438e82705aa78f9dfd0c5c53e66b95d1302d5f --- /dev/null +++ b/web/modules/metatag/metatag_app_links/metatag_app_links.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: App Links' +type: module +description: Provides support for applinks.org meta tags. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_app_links/metatag_app_links.module b/web/modules/metatag/metatag_app_links/metatag_app_links.module new file mode 100644 index 0000000000000000000000000000000000000000..a350752bc8f14c37ae6113d3f9b7598228bf04f7 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/metatag_app_links.module @@ -0,0 +1,24 @@ +<?php + +/** + * @file + * Contains metatag_app_links.module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_app_links_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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>'; + return $output; + + default: + } +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Group/AppLinks.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Group/AppLinks.php new file mode 100644 index 0000000000000000000000000000000000000000..4f7aad531e527fdd7a1d8fa667f2f15784176e7c --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Group/AppLinks.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * Provides a plugin for the 'App Links' meta tag group. + * + * @MetatagGroup( + * id = "app_links", + * label = @Translation("App Links"), + * description = @Translation("Meta tags used to expose App Links for app deep linking. See <a href="":url"">applinks.org</a> for details and documentation.", arguments = { ":url" = "http://applinks.org"}), + * weight = 0, + * ) + */ +class AppLinks extends GroupBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidAppName.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidAppName.php new file mode 100644 index 0000000000000000000000000000000000000000..6702f129b279eca49292bc470202b8cba8875f10 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidAppName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Android app name meta tag. + * + * @MetatagTag( + * id = "al_android_app_name", + * label = @Translation("Android app name"), + * description = @Translation("The name of the app (suitable for display)."), + * name = "al:android:app_name", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlAndroidAppName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidClass.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidClass.php new file mode 100644 index 0000000000000000000000000000000000000000..341e3267c55fa1a6b6a33077ce4b4d5841110714 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidClass.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Android app Activity Class meta tag. + * + * @MetatagTag( + * id = "al_android_class", + * label = @Translation("Android app Activity Class"), + * description = @Translation("A fully-qualified Activity class name for intent generation."), + * name = "al:android:class", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlAndroidClass extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidPackage.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidPackage.php new file mode 100644 index 0000000000000000000000000000000000000000..ae02d86bbffe618a3837b6ecb221a26a5234f243 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidPackage.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Android app package ID meta tag. + * + * @MetatagTag( + * id = "al_android_package", + * label = @Translation("Android app package ID"), + * description = @Translation("A fully-qualified package name for intent generation. <strong>This attribute is required by the App Links specification.</strong>"), + * name = "al:android:package", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlAndroidPackage extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..bac535c56058dd652b0689f4f744680169ac2740 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlAndroidUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Android app URL scheme meta tag. + * + * @MetatagTag( + * id = "al_android_url", + * label = @Translation("Android app URL scheme"), + * description = @Translation("A custom scheme for the Android app."), + * name = "al:android:url", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlAndroidUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosAppName.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosAppName.php new file mode 100644 index 0000000000000000000000000000000000000000..489d12f069feb700306e30d1596af670150ec609 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosAppName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iOS app name meta tag. + * + * @MetatagTag( + * id = "al_ios_app_name", + * label = @Translation("iOS app name"), + * description = @Translation("The name of the app (suitable for display)"), + * name = "al:ios:app_name", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIosAppName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosAppStoreId.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosAppStoreId.php new file mode 100644 index 0000000000000000000000000000000000000000..03d8318a2d9a7980dab281c893967f56f4fa13d9 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosAppStoreId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iOS app store ID meta tag. + * + * @MetatagTag( + * id = "al_ios_app_store_id", + * label = @Translation("iOS app store ID"), + * description = @Translation("The app ID for the app store."), + * name = "al:ios:app_store_id", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIosAppStoreId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..8795549d64d8ef5018bf12bbca1f9ced14109a74 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIosUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iOS App URL scheme meta tag. + * + * @MetatagTag( + * id = "al_ios_url", + * label = @Translation("iOS app URL scheme"), + * description = @Translation("A custom scheme for the iOS app. <strong>This attribute is required by the app Links specification.</strong>"), + * name = "al:ios:url", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIosUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadAppName.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadAppName.php new file mode 100644 index 0000000000000000000000000000000000000000..e9d2ce522e3e2eb90a47feb2916740b475eac215 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadAppName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iPad app name meta tag. + * + * @MetatagTag( + * id = "al_ipad_app_name", + * label = @Translation("iPad app name"), + * description = @Translation("The name of the app (suitable for display)."), + * name = "al:ipad:app_name", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIpadAppName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadAppStoreId.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadAppStoreId.php new file mode 100644 index 0000000000000000000000000000000000000000..82f54d2d9f10f8e6a8d8d74df988867baa394dd6 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadAppStoreId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iPad app store ID meta tag. + * + * @MetatagTag( + * id = "al_ipad_app_store_id", + * label = @Translation("iPad app store ID"), + * description = @Translation("The app ID for the app store."), + * name = "al:ipad:app_store_id", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIpadAppStoreId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..ae4f0e4ce5d1bc31d86f9a2c4c02a94100999540 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIpadUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iPad App URL scheme meta tag. + * + * @MetatagTag( + * id = "al_ipad_url", + * label = @Translation("iPad app URL scheme"), + * description = @Translation("A custom scheme for the iOS app. <strong>This attribute is required by the app Links specification.</strong>"), + * name = "al:ipad:url", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIpadUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneAppName.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneAppName.php new file mode 100644 index 0000000000000000000000000000000000000000..2538c6a5788381f2fbe980c10c1708fb6cc110e5 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneAppName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iPhone app name meta tag. + * + * @MetatagTag( + * id = "al_iphone_app_name", + * label = @Translation("iPhone app name"), + * description = @Translation("The name of the app (suitable for display)."), + * name = "al:iphone:app_name", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIphoneAppName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneAppStoreId.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneAppStoreId.php new file mode 100644 index 0000000000000000000000000000000000000000..4c714c62beabec421676676bd385a30806255065 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneAppStoreId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iPad app store ID meta tag. + * + * @MetatagTag( + * id = "al_iphone_app_store_id", + * label = @Translation("iPhone app store ID"), + * description = @Translation("The app ID for the app store."), + * name = "al:iphone:app_store_id", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIphoneAppStoreId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..46aa39f081b188a15b305b02bcc879d82abfe83b --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlIphoneUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks iPhone App URL scheme meta tag. + * + * @MetatagTag( + * id = "al_iphone_url", + * label = @Translation("iPhone app URL scheme"), + * description = @Translation("A custom scheme for the iOS app. <strong>This attribute is required by the app Links specification.</strong>"), + * name = "al:iphone:url", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlIphoneUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWebShouldFallback.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWebShouldFallback.php new file mode 100644 index 0000000000000000000000000000000000000000..cee2c4c47ca6ccea3f76ec891d12826ad678be80 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWebShouldFallback.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Web Should Fallback meta tag. + * + * @MetatagTag( + * id = "al_web_should_fallback", + * label = @Translation("Should fallback"), + * description = @Translation("Indicates if the web URL should be used as a fallback; defaults to ""true""."), + * name = "al:web:should_fallback", + * group = "app_links", + * weight = 2, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWebShouldFallback extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWebUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWebUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..cc06fe6cc9e6260fdc6a86aed45fda7a3dfc7704 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWebUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Web URL meta tag. + * + * @MetatagTag( + * id = "al_web_url", + * label = @Translation("Web URL"), + * description = @Translation("The web URL; defaults to the URL for the content that contains this tag."), + * name = "al:web:url", + * group = "app_links", + * weight = 2, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWebUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsAppId.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsAppId.php new file mode 100644 index 0000000000000000000000000000000000000000..fbbe6b0d786bba09bda561186ad1f4a25c2548ac --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsAppId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows app ID meta tag. + * + * @MetatagTag( + * id = "al_windows_app_id", + * label = @Translation("Windows app ID"), + * description = @Translation("The app ID for the app store."), + * name = "al:windows:app_id", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsAppId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsAppName.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsAppName.php new file mode 100644 index 0000000000000000000000000000000000000000..c6bd6760b2f0547d67604830dbb78a6fe66ed671 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsAppName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows app name meta tag. + * + * @MetatagTag( + * id = "al_windows_app_name", + * label = @Translation("Windows app name"), + * description = @Translation("The name of the app (suitable for display)."), + * name = "al:windows:app_name", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsAppName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneAppId.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneAppId.php new file mode 100644 index 0000000000000000000000000000000000000000..dcc04d5886aae7402182184edc04b3a32474b6af --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneAppId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows Phone app ID meta tag. + * + * @MetatagTag( + * id = "al_windows_phone_app_id", + * label = @Translation("Windows Phone app ID"), + * description = @Translation("The app ID for the app store."), + * name = "al:windows_phone:app_id", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsPhoneAppId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneAppName.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneAppName.php new file mode 100644 index 0000000000000000000000000000000000000000..f4254dc0957974824b516e85fe88c9915aaa48c6 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneAppName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows Phone app name meta tag. + * + * @MetatagTag( + * id = "al_windows_phone_app_name", + * label = @Translation("Windows Phone app name"), + * description = @Translation("The name of the app (suitable for display)"), + * name = "al:windows_phone:app_name", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsPhoneAppName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..c49e98631bd5d8f5a42a188d808cb6414c282f09 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsPhoneUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows Phone app URL scheme meta tag. + * + * @MetatagTag( + * id = "al_windows_phone_url", + * label = @Translation("Windows Phone app URL scheme"), + * description = @Translation("A custom scheme for the iOS app. <strong>This attribute is required by the app Links specification.</strong>"), + * name = "al:windows_phone:url", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsPhoneUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalAppId.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalAppId.php new file mode 100644 index 0000000000000000000000000000000000000000..353c400876caabb248de852fd0df7e2d369d4dc9 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalAppId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows Universal app ID meta tag. + * + * @MetatagTag( + * id = "al_windows_universal_app_id", + * label = @Translation("Windows Universal app ID"), + * description = @Translation("The app ID for the app store."), + * name = "al:windows_universal:app_id", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsUniversalAppId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalAppName.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalAppName.php new file mode 100644 index 0000000000000000000000000000000000000000..3275f9e9ba2c1db436125e42d71a71d65b548eed --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalAppName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows Universal app name meta tag. + * + * @MetatagTag( + * id = "al_windows_universal_app_name", + * label = @Translation("Windows Universal app name"), + * description = @Translation("The name of the app (suitable for display)"), + * name = "al:windows_universal:app_name", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsUniversalAppName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..ba66711bc5e0100af988950aa8c489b2b0808e3b --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUniversalUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows Universal app URL scheme meta tag. + * + * @MetatagTag( + * id = "al_windows_universal_url", + * label = @Translation("Windows Universal app URL scheme"), + * description = @Translation("A custom scheme for the iOS app. <strong>This attribute is required by the app Links specification.</strong>"), + * name = "al:windows_universal:url", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsUniversalUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUrl.php b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..3aa22ab399f70540a7127351ade9a49c98efb2b3 --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Plugin/metatag/Tag/AlWindowsUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_app_links\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The AppLinks Windows App URL scheme meta tag. + * + * @MetatagTag( + * id = "al_windows_url", + * label = @Translation("Windows app URL scheme"), + * description = @Translation("A custom scheme for the iOS app. <strong>This attribute is required by the app Links specification.</strong>"), + * name = "al:windows:url", + * group = "app_links", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AlWindowsUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_app_links/src/Tests/MetatagAppLinksTagsTest.php b/web/modules/metatag/metatag_app_links/src/Tests/MetatagAppLinksTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f791a521105bd129f43ed0d54d48a6ad5491927c --- /dev/null +++ b/web/modules/metatag/metatag_app_links/src/Tests/MetatagAppLinksTagsTest.php @@ -0,0 +1,74 @@ +<?php + +namespace Drupal\metatag_app_links\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the App Links tags work correctly. + * + * @group metatag + */ +class MetatagAppLinksTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'al_android_app_name', + 'al_android_class', + 'al_android_package', + 'al_android_url', + 'al_ios_app_name', + 'al_ios_app_store_id', + 'al_ios_url', + 'al_ipad_app_name', + 'al_ipad_app_store_id', + 'al_ipad_url', + 'al_iphone_app_name', + 'al_iphone_app_store_id', + 'al_iphone_url', + 'al_web_should_fallback', + 'al_web_url', + 'al_windows_app_id', + 'al_windows_app_name', + 'al_windows_phone_app_id', + 'al_windows_phone_app_name', + 'al_windows_phone_url', + 'al_windows_universal_app_id', + 'al_windows_universal_app_name', + 'al_windows_universal_url', + 'al_windows_url', + ]; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'property'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_app_links'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + $tag_name = str_replace('al_android_', 'al:android:', $tag_name); + $tag_name = str_replace('al_ios_', 'al:ios:', $tag_name); + $tag_name = str_replace('al_ipad_', 'al:ipad:', $tag_name); + $tag_name = str_replace('al_iphone_', 'al:iphone:', $tag_name); + $tag_name = str_replace('al_web_', 'al:web:', $tag_name); + // Run the Windows subtype replacements first so that the generic Windows + // one can still work. + $tag_name = str_replace('al_windows_phone_', 'al:windows_phone:', $tag_name); + $tag_name = str_replace('al_windows_universal_', 'al:windows_universal:', $tag_name); + $tag_name = str_replace('al_windows_', 'al:windows:', $tag_name); + return $tag_name; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..afda126fbac9d66b966ae58bbc345b95ee300233 --- /dev/null +++ b/web/modules/metatag/metatag_dc/config/schema/metatag_dc.metatag_tag.schema.yml @@ -0,0 +1,49 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.dcterms_contributor: + type: label + label: 'Dublin Core: Contributor' +metatag.metatag_tag.dcterms_coverage: + type: label + label: 'Dublin Core: Coverage' +metatag.metatag_tag.dcterms_creator: + type: label + label: 'Dublin Core: Creator' +metatag.metatag_tag.dcterms_date: + type: label + label: 'Dublin Core: Date' +metatag.metatag_tag.dcterms_description: + type: text + label: 'Dublin Core: Description' +metatag.metatag_tag.dcterms_format: + type: label + label: 'Dublin Core: Format' +metatag.metatag_tag.dcterms_identifier: + type: label + label: 'Dublin Core: Identifier' +metatag.metatag_tag.dcterms_language: + type: label + label: 'Dublin Core: Language' +metatag.metatag_tag.dcterms_publisher: + type: label + label: 'Dublin Core: Publisher' +metatag.metatag_tag.dcterms_relation: + type: label + label: 'Dublin Core: Relation' +metatag.metatag_tag.dcterms_rights: + type: label + label: 'Dublin Core: Rights' +metatag.metatag_tag.dcterms_source: + type: label + label: 'Dublin Core: Source' +metatag.metatag_tag.dcterms_subject: + type: label + label: 'Dublin Core: Subject' +metatag.metatag_tag.dcterms_title: + type: label + label: 'Dublin Core: Title' +metatag.metatag_tag.dcterms_type: + type: label + label: 'Dublin Core: Type' diff --git a/web/modules/metatag/metatag_dc/metatag_dc.info.yml b/web/modules/metatag/metatag_dc/metatag_dc.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..3123b511b6cbcd5aebf0fee3b5e57d1d18dfc797 --- /dev/null +++ b/web/modules/metatag/metatag_dc/metatag_dc.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Dublin Core' +type: module +description: Provides the fifteen <a href="http://dublincore.org/documents/dces/">Dublin Core Metadata Element Set 1.1</a> meta tags from the <a href="http://dublincore.org/">Dublin Core Metadata Institute</a>. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Group/DublinCore.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Group/DublinCore.php new file mode 100644 index 0000000000000000000000000000000000000000..0e0cb562f161c75bb5e25409bf40f82b8e0e9b46 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Group/DublinCore.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * The DublinCore group. + * + * @MetatagGroup( + * id = "dublin_core", + * label = @Translation("Dublin Core"), + * description = @Translation("Provides the fifteen <a href=':docs'>Dublin Core Metadata Element Set 1.1</a> meta tags from the <a href=':link'>Dublin Core Metadata Institute</a>", arguments = { ":docs" = "http://dublincore.org/documents/dces/", ":link" = "http://dublincore.org/"}), + * weight = 4 + * ) + */ +class DublinCore extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Contributor.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Contributor.php new file mode 100644 index 0000000000000000000000000000000000000000..bba68928d5ef6630a6e618d50b0f95f504233446 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Contributor.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Contributor" meta tag. + * + * @MetatagTag( + * id = "dcterms_contributor", + * label = @Translation("Contributor"), + * description = @Translation("An entity responsible for making contributions to the resource. Examples of a Contributor include a person, an organization, or a service. Typically, the name of a Contributor should be used to indicate the entity."), + * name = "dcterms.contributor", + * group = "dublin_core", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Contributor extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Coverage.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Coverage.php new file mode 100644 index 0000000000000000000000000000000000000000..a0302c843d0e4a250cd458814b184c7e2dc6175d --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Coverage.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Coverage" meta tag. + * + * @MetatagTag( + * id = "dcterms_coverage", + * label = @Translation("Coverage"), + * description = @Translation("The spatial or temporal topic of the resource, the spatial applicability of the resource, or the jurisdiction under which the resource is relevant. Spatial topic and spatial applicability may be a named place or a location specified by its geographic coordinates. Temporal topic may be a named period, date, or date range. A jurisdiction may be a named administrative entity or a geographic place to which the resource applies. Recommended best practice is to use a controlled vocabulary such as the Thesaurus of Geographic Names [TGN]. Where appropriate, named places or time periods can be used in preference to numeric identifiers such as sets of coordinates or date ranges."), + * name = "dcterms.coverage", + * group = "dublin_core", + * weight = 14, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Coverage extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Creator.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Creator.php new file mode 100644 index 0000000000000000000000000000000000000000..8aabc6cc680be800a6b34c4b9628ce14607a8e77 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Creator.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Creator" meta tag. + * + * @MetatagTag( + * id = "dcterms_creator", + * label = @Translation("Creator"), + * description = @Translation("An entity primarily responsible for making the resource. Examples of a Creator include a person, an organization, or a service. Typically, the name of a Creator should be used to indicate the entity."), + * name = "dcterms.creator", + * group = "dublin_core", + * weight = 2, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Creator extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Date.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Date.php new file mode 100644 index 0000000000000000000000000000000000000000..f66352a20b997fe95ef7a3557a22fcdaa5598868 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Date.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Date" meta tag. + * + * @MetatagTag( + * id = "dcterms_date", + * label = @Translation("Date"), + * description = @Translation("A point or period of time associated with an event in the lifecycle of the resource. Date may be used to express temporal information at any level of granularity. Recommended best practice is to use an encoding scheme, such as the W3CDTF profile of ISO 8601 [W3CDTF]."), + * name = "dcterms.date", + * group = "dublin_core", + * weight = 7, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Date extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..8ea944f48b3d65bad1b9ce2f149afa92d860a21b --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Description.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Description" meta tag. + * + * @MetatagTag( + * id = "dcterms_description", + * label = @Translation("Description"), + * description = @Translation("An account of the resource. Description may include but is not limited to: an abstract, a table of contents, a graphical representation, or a free-text account of the resource."), + * name = "dcterms.description", + * group = "dublin_core", + * weight = 4, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Description extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Format.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Format.php new file mode 100644 index 0000000000000000000000000000000000000000..cefe34a57467ad4ca00208aa612955d16222a38c --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Format.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Date" meta tag. + * + * @MetatagTag( + * id = "dcterms_format", + * label = @Translation("Format"), + * description = @Translation("The file format, physical medium, or dimensions of the resource. Examples of dimensions include size and duration. Recommended best practice is to use a controlled vocabulary such as the list of Internet Media Types [MIME]."), + * name = "dcterms.format", + * group = "dublin_core", + * weight = 9, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Format extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Identifier.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Identifier.php new file mode 100644 index 0000000000000000000000000000000000000000..ceadeec6b28e13ddd30a51e6720af6eb497e6639 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Identifier.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Identifier" meta tag. + * + * @MetatagTag( + * id = "dcterms_identifier", + * label = @Translation("Identifier"), + * description = @Translation("An unambiguous reference to the resource within a given context. Recommended best practice is to identify the resource by means of a string conforming to a formal identification system."), + * name = "dcterms.identifier", + * group = "dublin_core", + * weight = 10, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Identifier extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Language.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Language.php new file mode 100644 index 0000000000000000000000000000000000000000..58d567713437ad750627f0b38cef57b56c3f9e21 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Language.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Language" meta tag. + * + * @MetatagTag( + * id = "dcterms_language", + * label = @Translation("Language"), + * description = @Translation("A language of the resource. Recommended best practice is to use a controlled vocabulary such as RFC 4646 [RFC4646]."), + * name = "dcterms.language", + * group = "dublin_core", + * weight = 12, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Language extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Publisher.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Publisher.php new file mode 100644 index 0000000000000000000000000000000000000000..410eeb8128d8b13dbaa9f782c8013754296c37cc --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Publisher.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Publisher" meta tag. + * + * @MetatagTag( + * id = "dcterms_publisher", + * label = @Translation("Publisher"), + * description = @Translation("An entity responsible for making the resource available. Examples of a Publisher include a person, an organization, or a service. Typically, the name of a Publisher should be used to indicate the entity."), + * name = "dcterms.publisher", + * group = "dublin_core", + * weight = 5, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Publisher extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Relation.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Relation.php new file mode 100644 index 0000000000000000000000000000000000000000..ea89c4848fafa33f6d8306770310bd035a5dd425 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Relation.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Relation" meta tag. + * + * @MetatagTag( + * id = "dcterms_relation", + * label = @Translation("Relation"), + * description = @Translation("A related resource. Recommended best practice is to identify the related resource by means of a string conforming to a formal identification system."), + * name = "dcterms.relation", + * group = "dublin_core", + * weight = 13, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Relation extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Rights.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Rights.php new file mode 100644 index 0000000000000000000000000000000000000000..a98e9da0010c9695686238d4eaa5bacdb606ae45 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Rights.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Rights" meta tag. + * + * @MetatagTag( + * id = "dcterms_rights", + * label = @Translation("Rights"), + * description = @Translation("Information about rights held in and over the resource. Typically, rights information includes a statement about various property rights associated with the resource, including intellectual property rights."), + * name = "dcterms.rights", + * group = "dublin_core", + * weight = 15, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Rights extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Source.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Source.php new file mode 100644 index 0000000000000000000000000000000000000000..c0700fcfbf90e106425dc6457f85528e07d30a17 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Source.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Source" meta tag. + * + * @MetatagTag( + * id = "dcterms_source", + * label = @Translation("Source"), + * description = @Translation("A related resource from which the described resource is derived. The described resource may be derived from the related resource in whole or in part. Recommended best practice is to identify the related resource by means of a string conforming to a formal identification system."), + * name = "dcterms.source", + * group = "dublin_core", + * weight = 11, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Source extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Subject.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Subject.php new file mode 100644 index 0000000000000000000000000000000000000000..2cdcb9c686f216b5942a4f4d212a5657382d540d --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Subject.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Subject" meta tag. + * + * @MetatagTag( + * id = "dcterms_subject", + * label = @Translation("Subject"), + * description = @Translation("The topic of the resource. Typically, the subject will be represented using keywords, key phrases, or classification codes. Recommended best practice is to use a controlled vocabulary. To describe the spatial or temporal topic of the resource, use the Coverage element."), + * name = "dcterms.subject", + * group = "dublin_core", + * weight = 3, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Subject extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..cfafb4081aa2a16d92426f836e9ec4caeeb8b1d9 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Title.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Title" meta tag. + * + * @MetatagTag( + * id = "dcterms_title", + * label = @Translation("Title"), + * description = @Translation("The name given to the resource."), + * name = "dcterms.title", + * group = "dublin_core", + * weight = 1, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Title extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Type.php b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Type.php new file mode 100644 index 0000000000000000000000000000000000000000..e34846a4c80245d6ca36c1d0dfd04d8ea74bb6fe --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Plugin/metatag/Tag/Type.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Type" meta tag. + * + * @MetatagTag( + * id = "dcterms_type", + * label = @Translation("Type"), + * description = @Translation("The nature or genre of the resource. Recommended best practice is to use a controlled vocabulary such as the DCMI Type Vocabulary [DCMITYPE]. To describe the file format, physical medium, or dimensions of the resource, use the Format element."), + * name = "dcterms.type", + * group = "dublin_core", + * weight = 8, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Type extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc/src/Tests/MetatagDublinCoreTagsTest.php b/web/modules/metatag/metatag_dc/src/Tests/MetatagDublinCoreTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8085e7e8103ef2d08e7c08ea7e494b40b1cb21b2 --- /dev/null +++ b/web/modules/metatag/metatag_dc/src/Tests/MetatagDublinCoreTagsTest.php @@ -0,0 +1,50 @@ +<?php + +namespace Drupal\metatag_dc\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Dublin Core tags work correctly. + * + * @group metatag + */ +class MetatagDublinCoreTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'dcterms_contributor', + 'dcterms_coverage', + 'dcterms_creator', + 'dcterms_date', + 'dcterms_description', + 'dcterms_format', + 'dcterms_identifier', + 'dcterms_language', + 'dcterms_publisher', + 'dcterms_relation', + 'dcterms_rights', + 'dcterms_source', + 'dcterms_subject', + 'dcterms_title', + 'dcterms_type', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_dc'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + return str_replace('_', '.', $tag_name); + } + +} diff --git a/web/modules/metatag/metatag_dc_advanced/config/schema/metatag_dc_advanced.metatag_tag.schema.yml b/web/modules/metatag/metatag_dc_advanced/config/schema/metatag_dc_advanced.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..a9fdc0ca4f21777e702740d1fe520adaa0a33feb --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/config/schema/metatag_dc_advanced.metatag_tag.schema.yml @@ -0,0 +1,124 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.dcterms_abstract: + type: label + label: 'Dublin Core: Abstract' +metatag.metatag_tag.dcterms_access_rights: + type: label + label: 'Dublin Core: Access Rights' +metatag.metatag_tag.dcterms_accrual_method: + type: label + label: 'Dublin Core: Accrual Method' +metatag.metatag_tag.dcterms_accrual_periodicity: + type: label + label: 'Dublin Core: Accrual Periodicity' +metatag.metatag_tag.dcterms_accrual_policy: + type: text + label: 'Dublin Core: Accrual Policy' +metatag.metatag_tag.dcterms_alternative: + type: label + label: 'Dublin Core: Alternative Title' +metatag.metatag_tag.dcterms_audience: + type: label + label: 'Dublin Core: Audience' +metatag.metatag_tag.dcterms_available: + type: label + label: 'Dublin Core: Date Available' +metatag.metatag_tag.dcterms_bibliographic_citation: + type: label + label: 'Dublin Core: Bibliographic Citation' +metatag.metatag_tag.dcterms_conforms_to: + type: label + label: 'Dublin Core: Conforms To' +metatag.metatag_tag.dcterms_created: + type: label + label: 'Dublin Core: Date Created' +metatag.metatag_tag.dcterms_date_accepted: + type: label + label: 'Dublin Core: Date Accepted' +metatag.metatag_tag.dcterms_date_copyrighted: + type: label + label: 'Dublin Core: Date Copyrighted' +metatag.metatag_tag.dcterms_date_submitted: + type: label + label: 'Dublin Core: Date Submitted' +metatag.metatag_tag.dcterms_education_level: + type: label + label: 'Dublin Core: Audience Education Level' +metatag.metatag_tag.dcterms_extent: + type: label + label: 'Dublin Core: Extent' +metatag.metatag_tag.dcterms_has_format: + type: label + label: 'Dublin Core: Has Format' +metatag.metatag_tag.dcterms_has_part: + type: label + label: 'Dublin Core: Has Part' +metatag.metatag_tag.dcterms_has_version: + type: label + label: 'Dublin Core: Has Version' +metatag.metatag_tag.dcterms_instructional_method: + type: label + label: 'Dublin Core: Instructional Method' +metatag.metatag_tag.dcterms_is_format_of: + type: label + label: 'Dublin Core: Is Format Of' +metatag.metatag_tag.dcterms_is_part_of: + type: label + label: 'Dublin Core: Is Part Of' +metatag.metatag_tag.dcterms_is_referenced_by: + type: label + label: 'Dublin Core: Is Referenced By' +metatag.metatag_tag.dcterms_is_replaced_by: + type: label + label: 'Dublin Core: Is Replaced By' +metatag.metatag_tag.dcterms_is_required_by: + type: label + label: 'Dublin Core: Is Required By' +metatag.metatag_tag.dcterms_issued: + type: label + label: 'Dublin Core: Date Issued' +metatag.metatag_tag.dcterms_is_version_of: + type: label + label: 'Dublin Core: Is Version Of' +metatag.metatag_tag.dcterms_license: + type: label + label: 'Dublin Core: License' +metatag.metatag_tag.dcterms_mediator: + type: label + label: 'Dublin Core: Mediator' +metatag.metatag_tag.dcterms_medium: + type: label + label: 'Dublin Core: Medium' +metatag.metatag_tag.dcterms_modified: + type: label + label: 'Dublin Core: Date Modified' +metatag.metatag_tag.dcterms_provenance: + type: label + label: 'Dublin Core: Provenance' +metatag.metatag_tag.dcterms_references: + type: label + label: 'Dublin Core: References' +metatag.metatag_tag.dcterms_replaces: + type: label + label: 'Dublin Core: Replaces' +metatag.metatag_tag.dcterms_requires: + type: label + label: 'Dublin Core: Requires' +metatag.metatag_tag.dcterms_rights_holder: + type: label + label: 'Dublin Core: Rights Holder' +metatag.metatag_tag.dcterms_spatial: + type: label + label: 'Dublin Core: Spatial Coverage' +metatag.metatag_tag.dcterms_table_of_contents: + type: label + label: 'Dublin Core: Table Of Contents' +metatag.metatag_tag.dcterms_temporal: + type: label + label: 'Dublin Core: Temporal Coverage' +metatag.metatag_tag.dcterms_valid: + type: label + label: 'Dublin Core: Date Valid' 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 new file mode 100644 index 0000000000000000000000000000000000000000..e9fc95e9ef7622d7a54bb9322f955a2d4a39355a --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.info.yml @@ -0,0 +1,14 @@ +name: 'Metatag: Dublin Core Advanced' +type: module +description: 'Provides forty additional meta tags from the <a href="http://dublincore.org/">Dublin Core Metadata Institute</a>.' +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + - metatag:metatag_dc + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.module b/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.module new file mode 100644 index 0000000000000000000000000000000000000000..5fbbb5e5ecbe862e537f041b80cab4448133dba7 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/metatag_dc_advanced.module @@ -0,0 +1,24 @@ +<?php + +/** + * @file + * Contains metatag_dc_advanced.module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_dc_advanced_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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="http://dublincore.org/">Dublin Core Metadata Institute</a>.') . '</p>'; + return $output; + + default: + } +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Group/DublinCoreAdvanced.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Group/DublinCoreAdvanced.php new file mode 100644 index 0000000000000000000000000000000000000000..273e29245d432ceddee6c6012e2b370242f27b02 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Group/DublinCoreAdvanced.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * Provides a plugin for the 'Dublin Core Additional Tags' meta tag group. + * + * @MetatagGroup( + * id = "dublin_core_advanced", + * label = @Translation("Dublin Core Additional Tags"), + * description = @Translation("These tags are not part of the Metadata Element Set but may be useful for certain scenarios."), + * weight = 4, + * ) + */ +class DublinCoreAdvanced extends GroupBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AbstractTag.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AbstractTag.php new file mode 100644 index 0000000000000000000000000000000000000000..c1499b8d25334290b8e579e8e47c8b1f967aa63f --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AbstractTag.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "Abstract" meta tag. + * + * @MetatagTag( + * id = "dcterms_abstract", + * label = @Translation("Abstract"), + * description = @Translation("A summary of the resource."), + * name = "dcterms.abstract", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AbstractTag extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccessRights.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccessRights.php new file mode 100644 index 0000000000000000000000000000000000000000..0dde2650d877795a0ea5cdfef6d5815502eb75ac --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccessRights.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "accessRights" meta tag. + * + * @MetatagTag( + * id = "dcterms_access_rights", + * label = @Translation("Access Rights"), + * description = @Translation("Information about who can access the resource or an indication of its security status. Access Rights may include information regarding access or restrictions based on privacy, security, or other policies."), + * name = "dcterms.accessRights", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AccessRights extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualMethod.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualMethod.php new file mode 100644 index 0000000000000000000000000000000000000000..7430431fa14d31780a016418f4631e0972bd6f51 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualMethod.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "accrualMethod" meta tag. + * + * @MetatagTag( + * id = "dcterms_accrual_method", + * label = @Translation("Accrual Method"), + * description = @Translation("The method by which items are added to a collection."), + * name = "dcterms.accrualMethod", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AccrualMethod extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualPeriodicity.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualPeriodicity.php new file mode 100644 index 0000000000000000000000000000000000000000..d56c534cd6d45596ac463181c0e0134329bbf2f1 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualPeriodicity.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "accrualPeriodicity" meta tag. + * + * @MetatagTag( + * id = "dcterms_accrual_periodicity", + * label = @Translation("Accrual Periodicity"), + * description = @Translation("The frequency with which items are added to a collection."), + * name = "dcterms.accrualPeriodicity", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AccrualPeriodicity extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualPolicy.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualPolicy.php new file mode 100644 index 0000000000000000000000000000000000000000..831a4093d11a19f96408092acf53fb5f9b3f9831 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/AccrualPolicy.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "accrualPolicy" meta tag. + * + * @MetatagTag( + * id = "dcterms_accrual_policy", + * label = @Translation("Accrual Policy"), + * description = @Translation("The policy governing the addition of items to a collection."), + * name = "dcterms.accrualPolicy", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AccrualPolicy extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Alternative.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Alternative.php new file mode 100644 index 0000000000000000000000000000000000000000..663484753d0a1458aa0d089d82a0c980c5c0e7ae --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Alternative.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "alternative" meta tag. + * + * @MetatagTag( + * id = "dcterms_alternative", + * label = @Translation("Alternative Title"), + * description = @Translation("An alternative name for the resource. The distinction between titles and alternative titles is application-specific."), + * name = "dcterms.alternative", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Alternative extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Audience.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Audience.php new file mode 100644 index 0000000000000000000000000000000000000000..ad0548b6eabf2f3580438e884825584036ee2be4 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Audience.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "audience" meta tag. + * + * @MetatagTag( + * id = "dcterms_audience", + * label = @Translation("Audience"), + * description = @Translation("A class of entity for whom the resource is intended or useful."), + * name = "dcterms.audience", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Audience extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Available.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Available.php new file mode 100644 index 0000000000000000000000000000000000000000..e71689f2a01709d91d35760b5176ed2664c8e8ea --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Available.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "available" meta tag. + * + * @MetatagTag( + * id = "dcterms_available", + * label = @Translation("Date Available"), + * description = @Translation("Date (often a range) that the resource became or will become available."), + * name = "dcterms.available", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Available extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/BibliographicCitation.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/BibliographicCitation.php new file mode 100644 index 0000000000000000000000000000000000000000..f3be8684726e128613288fe11a7ea7f622f63b6d --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/BibliographicCitation.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "bibliographicCitation" meta tag. + * + * @MetatagTag( + * id = "dcterms_bibliographic_citation", + * label = @Translation("Bibliographic Citation"), + * description = @Translation("A bibliographic reference for the resource. Recommended practice is to include sufficient bibliographic detail to identify the resource as unambiguously as possible."), + * name = "dcterms.bibliographicCitation", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class BibliographicCitation extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/ConformsTo.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/ConformsTo.php new file mode 100644 index 0000000000000000000000000000000000000000..4417c2752eb8c4aae038c6c218e29b82d47558ca --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/ConformsTo.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "conformsTo" meta tag. + * + * @MetatagTag( + * id = "dcterms_conforms_to", + * label = @Translation("Conforms To"), + * description = @Translation("An established standard to which the described resource conforms."), + * name = "dcterms.conformsTo", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ConformsTo extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Created.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Created.php new file mode 100644 index 0000000000000000000000000000000000000000..0f71f775b88ad202863d1dcd63b2268e0dbd14eb --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Created.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "created" meta tag. + * + * @MetatagTag( + * id = "dcterms_created", + * label = @Translation("Date Created"), + * description = @Translation("Date of creation of the resource."), + * name = "dcterms.created", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Created extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateAccepted.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateAccepted.php new file mode 100644 index 0000000000000000000000000000000000000000..6d4b462df9bb1b7e924c902c6ae489863316efbd --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateAccepted.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "dateAccepted" meta tag. + * + * @MetatagTag( + * id = "dcterms_date_accepted", + * label = @Translation("Date Accepted"), + * description = @Translation("Date of acceptance of the resource. Examples of resources to which a Date Accepted may be relevant are a thesis (accepted by a university department) or an article (accepted by a journal)."), + * name = "dcterms.dateAccepted", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class DateAccepted extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateCopyrighted.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateCopyrighted.php new file mode 100644 index 0000000000000000000000000000000000000000..893b31991ff57430dafd7efe794eda9ee2cd837a --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateCopyrighted.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "dateCopyrighted" meta tag. + * + * @MetatagTag( + * id = "dcterms_date_copyrighted", + * label = @Translation("Date Copyrighted"), + * description = @Translation("Date of copyright."), + * name = "dcterms.dateCopyrighted", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class DateCopyrighted extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateSubmitted.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateSubmitted.php new file mode 100644 index 0000000000000000000000000000000000000000..1a302f7b65295334cbd977dde593fda6f370d91b --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/DateSubmitted.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "dateSubmitted" meta tag. + * + * @MetatagTag( + * id = "dcterms_date_submitted", + * label = @Translation("Date Submitted"), + * description = @Translation("Date of submission of the resource. Examples of resources to which a Date Submitted may be relevant are a thesis (submitted to a university department) or an article (submitted to a journal)."), + * name = "dcterms.dateSubmitted", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class DateSubmitted extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/EducationLevel.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/EducationLevel.php new file mode 100644 index 0000000000000000000000000000000000000000..7c5d101cbcdbcb89c11094a14492d2f8ffdc12ed --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/EducationLevel.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "educationLevel" meta tag. + * + * @MetatagTag( + * id = "dcterms_education_level", + * label = @Translation("Audience Education Level"), + * description = @Translation("A class of entity, defined in terms of progression through an educational or training context, for which the described resource is intended."), + * name = "dcterms.educationLevel", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class EducationLevel extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Extent.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Extent.php new file mode 100644 index 0000000000000000000000000000000000000000..41548420109176a708b3a787fc2383b04b6f7cb6 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Extent.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "extent" meta tag. + * + * @MetatagTag( + * id = "dcterms_extent", + * label = @Translation("Extent"), + * description = @Translation("The size or duration of the resource."), + * name = "dcterms.extent", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Extent extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasFormat.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasFormat.php new file mode 100644 index 0000000000000000000000000000000000000000..6c3d14c727bd7997926168b619f76027ef94c90f --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasFormat.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "hasFormat" meta tag. + * + * @MetatagTag( + * id = "dcterms_has_format", + * label = @Translation("Has Format"), + * description = @Translation("A related resource that is substantially the same as the pre-existing described resource, but in another format."), + * name = "dcterms.hasFormat", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class HasFormat extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasPart.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasPart.php new file mode 100644 index 0000000000000000000000000000000000000000..0924a96ca1ce9487c4ce1fed2f24f28aafd77a46 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasPart.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "hasPart" meta tag. + * + * @MetatagTag( + * id = "dcterms_has_part", + * label = @Translation("Has Part"), + * description = @Translation("A related resource that is included either physically or logically in the described resource."), + * name = "dcterms.hasPart", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class HasPart extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasVersion.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasVersion.php new file mode 100644 index 0000000000000000000000000000000000000000..2b1821ed751a8fe8ac0699d138335ce89ec46d9e --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/HasVersion.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "hasVersion" meta tag. + * + * @MetatagTag( + * id = "dcterms_has_version", + * label = @Translation("Has Version"), + * description = @Translation("A related resource that is a version, edition, or adaptation of the described resource."), + * name = "dcterms.hasVersion", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class HasVersion extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/InstructionalMethod.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/InstructionalMethod.php new file mode 100644 index 0000000000000000000000000000000000000000..dbdfa658cfd314f715eb90aebaa15d0d1f5cbf11 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/InstructionalMethod.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "instructionalMethod" meta tag. + * + * @MetatagTag( + * id = "dcterms_instructional_method", + * label = @Translation("Instructional Method"), + * description = @Translation("A process, used to engender knowledge, attitudes and skills, that the described resource is designed to support. Instructional Method will typically include ways of presenting instructional materials or conducting instructional activities, patterns of learner-to-learner and learner-to-instructor interactions, and mechanisms by which group and individual levels of learning are measured. Instructional methods include all aspects of the instruction and learning processes from planning and implementation through evaluation and feedback."), + * name = "dcterms.instructionalMethod", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class InstructionalMethod extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsFormatOf.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsFormatOf.php new file mode 100644 index 0000000000000000000000000000000000000000..426c5dc6a3eb47dbd5117b993d1711e67da4f4f2 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsFormatOf.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "isFormatOf" meta tag. + * + * @MetatagTag( + * id = "dcterms_is_format_of", + * label = @Translation("Is Format Of"), + * description = @Translation("A related resource that is substantially the same as the described resource, but in another format."), + * name = "dcterms.isFormatOf", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class IsFormatOf extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsPartOf.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsPartOf.php new file mode 100644 index 0000000000000000000000000000000000000000..18846c6281fddf29a95bdc848855818c8cb92f36 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsPartOf.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "isPartOf" meta tag. + * + * @MetatagTag( + * id = "dcterms_is_part_of", + * label = @Translation("Is Part Of"), + * description = @Translation("A related resource in which the described resource is physically or logically included."), + * name = "dcterms.isPartOf", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class IsPartOf extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsReferencedBy.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsReferencedBy.php new file mode 100644 index 0000000000000000000000000000000000000000..29b4879c34c3fd29b1caf903a6f566bcb496e00a --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsReferencedBy.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "isReferencedBy" meta tag. + * + * @MetatagTag( + * id = "dcterms_is_referenced_by", + * label = @Translation("Is Referenced By"), + * description = @Translation("A related resource that references, cites, or otherwise points to the described resource."), + * name = "dcterms.isReferencedBy", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class IsReferencedBy extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsReplacedBy.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsReplacedBy.php new file mode 100644 index 0000000000000000000000000000000000000000..c071d2254cfe3425afc871096b696c3f6dda29f2 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsReplacedBy.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "isReplacedBy" meta tag. + * + * @MetatagTag( + * id = "dcterms_is_replaced_by", + * label = @Translation("Is Replaced By"), + * description = @Translation("A related resource that supplants, displaces, or supersedes the described resource."), + * name = "dcterms.isReplacedBy", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class IsReplacedBy extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsRequiredBy.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsRequiredBy.php new file mode 100644 index 0000000000000000000000000000000000000000..5b004f27a427ac36bb2603c9f200aa0fd69a7ad7 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsRequiredBy.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "isRequiredBy" meta tag. + * + * @MetatagTag( + * id = "dcterms_is_required_by", + * label = @Translation("Is Required By"), + * description = @Translation("A related resource that requires the described resource to support its function, delivery, or coherence."), + * name = "dcterms.isRequiredBy", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class IsRequiredBy extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsVersionOf.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsVersionOf.php new file mode 100644 index 0000000000000000000000000000000000000000..deea2d5d1e1567d758ff5581a6a15cc28c4abfba --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/IsVersionOf.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "isVersionOf" meta tag. + * + * @MetatagTag( + * id = "dcterms_is_version_of", + * label = @Translation("Is Version Of"), + * description = @Translation("A related resource of which the described resource is a version, edition, or adaptation. Changes in version imply substantive changes in content rather than differences in format."), + * name = "dcterms.isVersionOf", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class IsVersionOf extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Issued.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Issued.php new file mode 100644 index 0000000000000000000000000000000000000000..0372b23da90941b019f3b2188346a62368a780da --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Issued.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "issued" meta tag. + * + * @MetatagTag( + * id = "dcterms_issued", + * label = @Translation("Date Issued"), + * description = @Translation("Date of formal issuance (e.g., publication) of the resource."), + * name = "dcterms.issued", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Issued extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/License.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/License.php new file mode 100644 index 0000000000000000000000000000000000000000..282920d2f6a17f1d0338c40041aea8f00e5710c0 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/License.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "license" meta tag. + * + * @MetatagTag( + * id = "dcterms_license", + * label = @Translation("License"), + * description = @Translation("A legal document giving official permission to do something with the resource."), + * name = "dcterms.license", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class License extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Mediator.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Mediator.php new file mode 100644 index 0000000000000000000000000000000000000000..a6d239462f92b5d755ef84e48e0ee49399ae49da --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Mediator.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "mediator" meta tag. + * + * @MetatagTag( + * id = "dcterms_mediator", + * label = @Translation("Mediator"), + * description = @Translation("An entity that mediates access to the resource and for whom the resource is intended or useful. In an educational context, a mediator might be a parent, teacher, teaching assistant, or care-giver."), + * name = "dcterms.mediator", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Mediator extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Medium.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Medium.php new file mode 100644 index 0000000000000000000000000000000000000000..2768267fa78b6dd462c6ea0b28554e4786aa90ef --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Medium.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "medium" meta tag. + * + * @MetatagTag( + * id = "dcterms_medium", + * label = @Translation("Medium"), + * description = @Translation("The material or physical carrier of the resource."), + * name = "dcterms.medium", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Medium extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Modified.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Modified.php new file mode 100644 index 0000000000000000000000000000000000000000..4521c4aeee9df76570647359f681cf1f0cfd2743 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Modified.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "modified" meta tag. + * + * @MetatagTag( + * id = "dcterms_modified", + * label = @Translation("Date Modified"), + * description = @Translation("Date on which the resource was changed."), + * name = "dcterms.modified", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Modified extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Provenance.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Provenance.php new file mode 100644 index 0000000000000000000000000000000000000000..a26c9806a9101d928261cfbf64c01d2156bec974 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Provenance.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "provenance" meta tag. + * + * @MetatagTag( + * id = "dcterms_provenance", + * label = @Translation("Provenance"), + * description = @Translation("A statement of any changes in ownership and custody of the resource since its creation that are significant for its authenticity, integrity, and interpretation. The statement may include a description of any changes successive custodians made to the resource."), + * name = "dcterms.provenance", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Provenance extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/References.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/References.php new file mode 100644 index 0000000000000000000000000000000000000000..a5b41ecd8d72e93ab1d680b889780d88f1ca6df3 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/References.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "references" meta tag. + * + * @MetatagTag( + * id = "dcterms_references", + * label = @Translation("References"), + * description = @Translation("A related resource that is referenced, cited, or otherwise pointed to by the described resource."), + * name = "dcterms.references", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class References extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Replaces.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Replaces.php new file mode 100644 index 0000000000000000000000000000000000000000..46d8bf4b1ebd844c1444f5960406c0d30aa0d5cd --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Replaces.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "replaces" meta tag. + * + * @MetatagTag( + * id = "dcterms_replaces", + * label = @Translation("Replaces"), + * description = @Translation("A related resource that is supplanted, displaced, or superseded by the described resource."), + * name = "dcterms.replaces", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Replaces extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Requires.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Requires.php new file mode 100644 index 0000000000000000000000000000000000000000..4bb5966e3582aa5f457a7804fbd029150900652e --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Requires.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "requires" meta tag. + * + * @MetatagTag( + * id = "dcterms_requires", + * label = @Translation("Requires"), + * description = @Translation("A related resource that is required by the described resource to support its function, delivery, or coherence."), + * name = "dcterms.requires", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Requires extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/RightsHolder.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/RightsHolder.php new file mode 100644 index 0000000000000000000000000000000000000000..c7fc7fa81402a4be285ae620f59f695a1898f607 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/RightsHolder.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "rightsHolder" meta tag. + * + * @MetatagTag( + * id = "dcterms_rights_holder", + * label = @Translation("Rights Holder"), + * description = @Translation("A person or organization owning or managing rights over the resource."), + * name = "dcterms.rightsHolder", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class RightsHolder extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Spatial.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Spatial.php new file mode 100644 index 0000000000000000000000000000000000000000..27bd4684452f36459b9979974ab712929e737392 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Spatial.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "spatial" meta tag. + * + * @MetatagTag( + * id = "dcterms_spatial", + * label = @Translation("Spatial Coverage"), + * description = @Translation("Spatial characteristics of the resource."), + * name = "dcterms.spatial", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Spatial extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/TableOfContents.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/TableOfContents.php new file mode 100644 index 0000000000000000000000000000000000000000..28a55041c23bc6a4830e1075c218d3e241c12899 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/TableOfContents.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "tableOfContents" meta tag. + * + * @MetatagTag( + * id = "dcterms_table_of_contents", + * label = @Translation("Table Of Contents"), + * description = @Translation("A list of subunits of the resource."), + * name = "dcterms.tableOfContents", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TableOfContents extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Temporal.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Temporal.php new file mode 100644 index 0000000000000000000000000000000000000000..25be75b60c658e664b03b82a50701772879d672c --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Temporal.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "temporal" meta tag. + * + * @MetatagTag( + * id = "dcterms_temporal", + * label = @Translation("Temporal Coverage"), + * description = @Translation("Temporal characteristics of the resource."), + * name = "dcterms.temporal", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Temporal extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Valid.php b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Valid.php new file mode 100644 index 0000000000000000000000000000000000000000..443f3fb3bdf57ace23cdfa4790ab06d84b40af26 --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Plugin/metatag/Tag/Valid.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Dublin Core "valid" meta tag. + * + * @MetatagTag( + * id = "dcterms_valid", + * label = @Translation("Date Valid"), + * description = @Translation("Date (often a range) of validity of a resource."), + * name = "dcterms.valid", + * group = "dublin_core_advanced", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Valid extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_dc_advanced/src/Tests/MetatagDublinCoreAdvancedTagsTest.php b/web/modules/metatag/metatag_dc_advanced/src/Tests/MetatagDublinCoreAdvancedTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..da19cf0c44e41112489c0a6995adb5ad5252894b --- /dev/null +++ b/web/modules/metatag/metatag_dc_advanced/src/Tests/MetatagDublinCoreAdvancedTagsTest.php @@ -0,0 +1,78 @@ +<?php + +namespace Drupal\metatag_dc_advanced\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Dublin Core Advanced tags work correctly. + * + * @group metatag + */ +class MetatagDublinCoreAdvancedTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'dcterms_abstract', + 'dcterms_access_rights', + 'dcterms_accrual_method', + 'dcterms_accrual_periodicity', + 'dcterms_accrual_policy', + 'dcterms_alternative', + 'dcterms_audience', + 'dcterms_available', + 'dcterms_bibliographic_citation', + 'dcterms_conforms_to', + 'dcterms_created', + 'dcterms_date_accepted', + 'dcterms_date_copyrighted', + 'dcterms_date_submitted', + 'dcterms_education_level', + 'dcterms_extent', + 'dcterms_has_format', + 'dcterms_has_part', + 'dcterms_has_version', + 'dcterms_instructional_method', + 'dcterms_is_format_of', + 'dcterms_is_part_of', + 'dcterms_is_referenced_by', + 'dcterms_is_replaced_by', + 'dcterms_is_required_by', + 'dcterms_issued', + 'dcterms_is_version_of', + 'dcterms_license', + 'dcterms_mediator', + 'dcterms_medium', + 'dcterms_modified', + 'dcterms_provenance', + 'dcterms_references', + 'dcterms_replaces', + 'dcterms_requires', + 'dcterms_rights_holder', + 'dcterms_spatial', + 'dcterms_table_of_contents', + 'dcterms_temporal', + 'dcterms_valid', + ]; + + /** + * {@inheritdoc} + */ + private $testTag = 'meta'; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'property'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_dc_advanced'; + parent::setUp(); + } + +} diff --git a/web/modules/metatag/metatag_facebook/config/schema/metatag_facebook.metatag_tag.schema.yml b/web/modules/metatag/metatag_facebook/config/schema/metatag_facebook.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..17db196941b5152d10ccb8e9a813db6dcb85d911 --- /dev/null +++ b/web/modules/metatag/metatag_facebook/config/schema/metatag_facebook.metatag_tag.schema.yml @@ -0,0 +1,13 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.fb_admins: + type: label + label: 'Facebook Admins' +metatag.metatag_tag.fb_app_id: + type: label + label: 'Facebook App ID' +metatag.metatag_tag.fb_pages: + type: label + label: 'Facebook Pages' diff --git a/web/modules/metatag/metatag_facebook/metatag_facebook.info.yml b/web/modules/metatag/metatag_facebook/metatag_facebook.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..ed308edda68e689c7891114341f9ed811418e4c6 --- /dev/null +++ b/web/modules/metatag/metatag_facebook/metatag_facebook.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Facebook' +type: module +description: A set of meta tags specially for controlling advanced functionality with Facebook. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Group/Facebook.php b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Group/Facebook.php new file mode 100644 index 0000000000000000000000000000000000000000..98e4af39fb838858078b5daf67e3b596f8c20240 --- /dev/null +++ b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Group/Facebook.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\facebook\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * The Facebook group. + * + * @MetatagGroup( + * id = "facebook", + * label = @Translation("facebook"), + * description = @Translation("A set of meta tags specially for controlling advanced functionality with <a href=':fb'>Facebook</a>.", arguments = { ":fb" = "https://www.facebook.com/" }), + * weight = 4 + * ) + */ +class Facebook extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbAdmins.php b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbAdmins.php new file mode 100644 index 0000000000000000000000000000000000000000..0cbf866ed16c7e6628324d874f625d3bdfcf3017 --- /dev/null +++ b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbAdmins.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_facebook\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Facebook "fb:admins" meta tag. + * + * @MetatagTag( + * id = "fb_admins", + * label = @Translation("Facebook Admins"), + * description = @Translation("A comma-separated list of Facebook user IDs of people who are considered administrators or moderators of this page."), + * name = "fb:admins", + * group = "facebook", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class FbAdmins extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbAppId.php b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbAppId.php new file mode 100644 index 0000000000000000000000000000000000000000..c75a68638b5e4dd8100f9b9847b99c48635e1d00 --- /dev/null +++ b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbAppId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_facebook\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Facebook "fb:app_id" meta tag. + * + * @MetatagTag( + * id = "fb_app_id", + * label = @Translation("Facebook Application ID"), + * description = @Translation("A comma-separated list of Facebook Platform Application IDs applicable for this site."), + * name = "fb:app_id", + * group = "facebook", + * weight = 2, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class FbAppId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbPages.php b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbPages.php new file mode 100644 index 0000000000000000000000000000000000000000..e6ab4ca15420ddb9db1edcf8d44eeedccb2bbd0b --- /dev/null +++ b/web/modules/metatag/metatag_facebook/src/Plugin/metatag/Tag/FbPages.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_facebook\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Facebook "fb:pages" meta tag. + * + * @MetatagTag( + * id = "fb_pages", + * label = @Translation("Facebook Pages"), + * description = @Translation("Facebook Instant Articles claim URL token."), + * name = "fb:pages", + * group = "facebook", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class FbPages extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_facebook/src/Tests/MetatagFacebookTagsTest.php b/web/modules/metatag/metatag_facebook/src/Tests/MetatagFacebookTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bd56b65082445797c86ee5331afe0952e6f6ac94 --- /dev/null +++ b/web/modules/metatag/metatag_facebook/src/Tests/MetatagFacebookTagsTest.php @@ -0,0 +1,44 @@ +<?php + +namespace Drupal\metatag_facebook\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Facebook tags work correctly. + * + * @group metatag + */ +class MetatagFacebookTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'fb_admins', + 'fb_app_id', + 'fb_pages', + ]; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'property'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_facebook'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + $tag_name = str_replace('fb_', 'fb:', $tag_name); + return $tag_name; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..e426a0bb63958aa3a3b55e79d38692a1d0a0deff --- /dev/null +++ b/web/modules/metatag/metatag_favicons/config/schema/metatag_favicons.metatag_tag.schema.yml @@ -0,0 +1,70 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.shortcut_icon: + type: label + label: 'Default shortcut icon' +metatag.metatag_tag.mask_ico: + type: label + label: 'Icon: SVG' +metatag.metatag_tag.icon_16x16: + type: label + label: 'Icon: 16px x 16px' +metatag.metatag_tag.icon_32x32: + type: label + label: 'Icon: 32px x 32px' +metatag.metatag_tag.icon_96x96: + type: label + label: 'Icon: 96px x 96px' +metatag.metatag_tag.icon_192x192: + type: label + label: 'Icon: 192px x 192px' +metatag.metatag_tag.apple_touch_icon: + type: label + label: 'Apple touch icon: 60px x 60px' +metatag.metatag_tag.apple_touch_icon_72x72: + type: label + label: 'Apple touch icon: 72px x 72px' +metatag.metatag_tag.apple_touch_icon_76x76: + type: label + label: 'Apple touch icon: 76px x 76px' +metatag.metatag_tag.apple_touch_icon_114x114: + type: label + label: 'Apple touch icon: 114px x 114px' +metatag.metatag_tag.apple_touch_icon_120x120: + type: label + label: 'Apple touch icon: 120px x 120px' +metatag.metatag_tag.apple_touch_icon_144x144: + type: label + label: 'Apple touch icon: 144px x 144px' +metatag.metatag_tag.apple_touch_icon_152x152: + type: label + label: 'Apple touch icon: 152px x 152px' +metatag.metatag_tag.apple_touch_icon_180x180: + type: label + label: 'Apple touch icon: 180px x 180px' +metatag.metatag_tag.apple_touch_icon_precomposed: + type: label + label: 'Apple touch icon (precomposed): 57px x 57px' +metatag.metatag_tag.apple_touch_icon_precomposed_72x72: + type: label + label: 'Apple touch icon (precomposed): 72px x 72px' +metatag.metatag_tag.apple_touch_icon_precomposed_76x76: + type: label + label: 'Apple touch icon (precomposed): 76px x 76px' +metatag.metatag_tag.apple_touch_icon_precomposed_114x114: + type: label + label: 'Apple touch icon (precomposed): 114px x 114px' +metatag.metatag_tag.apple_touch_icon_precomposed_120x120: + type: label + label: 'Apple touch icon (precomposed): 120px x 120px' +metatag.metatag_tag.apple_touch_icon_precomposed_144x144: + type: label + label: 'Apple touch icon (precomposed): 144px x 144px' +metatag.metatag_tag.apple_touch_icon_precomposed_152x152: + type: label + label: 'Apple touch icon (precomposed): 152px x 152px' +metatag.metatag_tag.apple_touch_icon_precomposed_180x180: + type: label + label: 'Apple touch icon (precomposed): 180px x 180px' diff --git a/web/modules/metatag/metatag_favicons/metatag_favicons.info.yml b/web/modules/metatag/metatag_favicons/metatag_favicons.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..af4b6caa61a0b2f01c6b8da04852725a1bfcb40c --- /dev/null +++ b/web/modules/metatag/metatag_favicons/metatag_favicons.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: favicons' +type: module +description: Provides support for many different favicons. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_favicons/metatag_favicons.module b/web/modules/metatag/metatag_favicons/metatag_favicons.module new file mode 100644 index 0000000000000000000000000000000000000000..39a0b19eea182e070995dca73b3bc432767a40d7 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/metatag_favicons.module @@ -0,0 +1,45 @@ +<?php + +/** + * @file + * Custom hook implementations for Metatag Favicons. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_favicons_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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>'; + return $output; + + default: + } +} + +/** + * Implements hook_page_attachments_alter(). + */ +function metatag_favicons_page_attachments_alter(array &$attachments) { + // Check html_head_link on attached tags in head. + if (!isset($attachments['#attached']['html_head_link'])) { + return; + } + + // Remove the default shortcut icon if one was set by Metatag. + foreach ($attachments['#attached']['html_head'] as $element) { + if (isset($element[1]) && $element[1] == 'shortcut_icon') { + foreach ($attachments['#attached']['html_head_link'] as $key => $value) { + if (isset($value[0]['rel']) && $value[0]['rel'] == 'shortcut icon') { + unset($attachments['#attached']['html_head_link'][$key]); + } + } + } + } +} diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Group/Favicons.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Group/Favicons.php new file mode 100644 index 0000000000000000000000000000000000000000..65d340ce09ab04971a50cf45c63540a2c7893679 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Group/Favicons.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * Provides a plugin for the 'Favicons & touch icons' meta tag group. + * + * @MetatagGroup( + * id = "favicons", + * label = @Translation("Favicons & touch icons"), + * description = @Translation("Meta tags for displaying favicons of various sizes and types. All values should be either absolute or relative URLs. No effects are added to the ""precomposed"" icons."), + * weight = 0, + * ) + */ +class Favicons extends GroupBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon.php b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon.php new file mode 100644 index 0000000000000000000000000000000000000000..715c7a3a32b2a879dda42866530db6e93a3c6f0b --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The Favicons "apple-touch-icon" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon", + * label = @Translation("Apple touch icon: 60px x 60px"), + * description = @Translation("A PNG image that is 60px wide by 60px high. Used with the non-Retina iPhone, iPod Touch, and Android 2.1+ devices."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 7, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5c97c57d4811cf8103da8ef8f368a2c15e9ed0e7 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon114x114.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon_114x114" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_114x114", + * label = @Translation("Apple touch icon: 114px x 114px"), + * description = @Translation("A PNG image that is 114px wide by 114px high. Used with iPhone with @2x display running iOS <= 6."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 10, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon114x114 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..ae44e26df708c0d4a3971e580752280502ab03a1 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon120x120.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon_120x120" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_120x120", + * label = @Translation("Apple touch icon: 120px x 120px"), + * description = @Translation("A PNG image that is 120px wide by 120px high. Used with iPhone with @2x display running iOS >= 7."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 11, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon120x120 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..77570fd290115d0ab31d5e1f191a73c31ed445c0 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon144x144.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon_144x144" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_144x144", + * label = @Translation("Apple touch icon: 144px x 144px"), + * description = @Translation("A PNG image that is 144px wide by 144px high. Used with iPad with @2x display running iOS <= 6."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 12, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon144x144 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..a4bc9f497c74ed5f045afc793bc2fff5cf2183ee --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon152x152.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon_152x152" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_152x152", + * label = @Translation("Apple touch icon: 152px x 152px"), + * description = @Translation("A PNG image that is 152px wide by 152px high. Used with iPad with @2x display running iOS >= 7."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 13, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon152x152 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..e1e50f152be4f3932f7666d9a12dfa8db83e071a --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon180x180.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon_180x180" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_180x180", + * label = @Translation("Apple touch icon: 180px x 180px"), + * description = @Translation("A PNG image that is 180px wide by 180px high. Used with iPhone 6 Plus with @3x display."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 14, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon180x180 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..0bcaa83d1939e58ae3affc08e49dc86de64b0562 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon72x72.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "icon_16x16" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_72x72", + * label = @Translation("Apple touch icon: 72px x 72px"), + * description = @Translation("A PNG image that is 72px wide by 72px high. Used with the iPad mini and the first- and second-generation iPad (@1x display) on iOS <= 6."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 8, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon72x72 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..afe12a3abfdaf4611f31098a5a9d3136bf9526c0 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIcon76x76.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon_76x76" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_76x76", + * label = @Translation("Apple touch icon: 76px x 76px"), + * description = @Translation("A PNG image that is 76px wide by 76px high. Used with the iPad mini and the second-generation iPad (@1x display) on iOS >= 7."), + * name = "apple-touch-icon", + * group = "favicons", + * weight = 9, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIcon76x76 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..8b7eaa39e61eedbd75467a683e3609110cb0373a --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The Favicons "apple-touch-icon-precomposed" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed", + * label = @Translation("Apple touch icon (precomposed): 57px x 57px"), + * description = @Translation("A PNG image that is 57px wide by 57px high. Used with the non-Retina iPhone, iPod Touch, and Android 2.1+ devices."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 15, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed extends LinkRelBase { + // 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 new file mode 100644 index 0000000000000000000000000000000000000000..d6ca574772319ac156859cd6fc976e566f35465f --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed114x114.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon-precomposed_114x114" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed_114x114", + * label = @Translation("Apple touch icon (precomposed): 114px x 114px"), + * description = @Translation("A PNG image that is 114px wide by 114px high. Used with iPhone with @2x display running iOS <= 6."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 18, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed114x114 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + return '114x114'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..2ffc607b148d7ebff145bba9fe33d99972bcdb50 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed120x120.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon-precomposed_120x120" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed_120x120", + * label = @Translation("Apple touch icon (precomposed): 120px x 120px"), + * description = @Translation("A PNG image that is 120px wide by 120px high. Used with iPhone with @2x display running iOS >= 7."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 19, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed120x120 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + return '120x120'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..e087a433a4e3ab0e8f6dc3089755f661bba57401 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed144x144.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon-precomposed_144x144" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed_144x144", + * label = @Translation("Apple touch icon (precomposed): 144px x 144px"), + * description = @Translation("A PNG image that is 144px wide by 144px high. Used with iPad with @2x display running iOS <= 6."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 20, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed144x144 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + return '144x144'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..1bd597613c45aec0c15a2c1f0833e33fab701a84 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed152x152.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon-precomposed_152x152" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed_152x152", + * label = @Translation("Apple touch icon (precomposed): 152px x 152px"), + * description = @Translation("A PNG image that is 152px wide by 152px high. Used with iPad with @2x display running iOS >= 7."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 21, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed152x152 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + return '152x152'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..d4ac4c7657e998eb3825a88dbbc81d8b1c105d06 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed180x180.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon-precomposed_180x180" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed_180x180", + * label = @Translation("Apple touch icon (precomposed): 180px x 180px"), + * description = @Translation("A PNG image that is 180px wide by 180px high. Used with iPhone 6 Plus with @3x display."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 22, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed180x180 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + return '180x180'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..ce1fed66b99132c5cc01465382257a78fee404b6 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed72x72.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon-precomposed_72x72" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed_72x72", + * label = @Translation("Apple touch icon (precomposed): 72px x 72px"), + * description = @Translation("A PNG image that is 72px wide by 72px high. Used with the iPad mini and the first- and second-generation iPad (@1x display) on iOS <= 6."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 16, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed72x72 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + return '72x72'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..a735e61f8b891a42a780b92f4a01f2eb3cbf9af8 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/AppleTouchIconPrecomposed76x76.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "apple-touch-icon-precomposed_76x76" meta tag. + * + * @MetatagTag( + * id = "apple_touch_icon_precomposed_76x76", + * label = @Translation("Apple touch icon (precomposed): 76px x 76px"), + * description = @Translation("A PNG image that is 76px wide by 76px high. Used with the iPad mini and the second-generation iPad (@1x display) on iOS >= 7."), + * name = "apple-touch-icon-precomposed", + * group = "favicons", + * weight = 17, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleTouchIconPrecomposed76x76 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + return '76x76'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..a7d4c54dfe53f1a882a3111d02a8af1a080e8020 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon16x16.php @@ -0,0 +1,30 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "icon_16x16" meta tag. + * + * @MetatagTag( + * id = "icon_16x16", + * label = @Translation("Icon: 16px x 16px"), + * description = @Translation("A PNG image that is 16px wide by 16px high."), + * name = "icon", + * group = "favicons", + * weight = 3, + * type = "image", + * secure = FALSE, + * multiple = FALSE, + * sizes = "16x16" + * ) + */ +class Icon16x16 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..81f28923a38714c3ed6dae7969fd39dcebd4da07 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon192x192.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "icon_192x192" meta tag. + * + * @MetatagTag( + * id = "icon_192x192", + * label = @Translation("Icon: 192px x 192px"), + * description = @Translation("A PNG image that is 192px wide by 192px high."), + * name = "icon", + * group = "favicons", + * weight = 6, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Icon192x192 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..e0cc4a00f545fe9bf5e5f63e5f713d7d679158e0 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon32x32.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "icon_32x32" meta tag. + * + * @MetatagTag( + * id = "icon_32x32", + * label = @Translation("Icon: 32px x 32px"), + * description = @Translation("A PNG image that is 32px wide by 32px high."), + * name = "icon", + * group = "favicons", + * weight = 4, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Icon32x32 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..a0a940acb1f19f24fbd96ec55914b499cb6bebf1 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/Icon96x96.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +/** + * The Favicons "icon_96x96" meta tag. + * + * @MetatagTag( + * id = "icon_96x96", + * label = @Translation("Icon: 96px x 96px"), + * description = @Translation("A PNG image that is 96px wide by 96px high."), + * name = "icon", + * group = "favicons", + * weight = 5, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Icon96x96 extends LinkSizesBase { + + /** + * {@inheritdoc} + */ + protected function sizes() { + 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 new file mode 100644 index 0000000000000000000000000000000000000000..d4f0f766da6d32fe8bed7ab6cde4d20ea3469680 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/LinkSizesBase.php @@ -0,0 +1,39 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * This base plugin allows "link rel" tags with a "sizes" attribute. + */ +abstract class LinkSizesBase extends LinkRelBase { + + /** + * {@inheritdoc} + */ + public function output() { + $element = parent::output(); + + if ($element) { + $element['#attributes'] = [ + 'rel' => $this->name(), + 'sizes' => $this->sizes(), + 'href' => $element['#attributes']['href'], + ]; + } + + return $element; + } + + /** + * The dimensions supported by this icon. + * + * @return string + * A string in the format "XxY" for a given width and height. + */ + protected function sizes() { + return ''; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..fc5689ce1d46bd6ef129e0fea998ecd5d7e47fee --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/MaskIcon.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The Favicons "mask-icon" meta tag. + * + * @MetatagTag( + * id = "mask-icon", + * label = @Translation("Icon: SVG"), + * description = @Translation("A grayscale scalable vector graphic (SVG) file."), + * name = "mask-icon", + * group = "favicons", + * weight = 2, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MaskIcon extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..730a34e6aefea9088bae800e7f7243f6ffeeb471 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Plugin/metatag/Tag/ShortcutIcon.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_favicons\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The Favicons "shortcut icon" meta tag. + * + * @MetatagTag( + * id = "shortcut_icon", + * label = @Translation("Default shortcut icon"), + * description = @Translation("The traditional favicon, must be either a GIF, ICO, JPG/JPEG or PNG image."), + * name = "shortcut icon", + * group = "favicons", + * weight = 1, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ShortcutIcon extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_favicons/src/Tests/MetatagFaviconsTagsTest.php b/web/modules/metatag/metatag_favicons/src/Tests/MetatagFaviconsTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..04f588505440e09dfc1ffcbe77cfbd4d29015828 --- /dev/null +++ b/web/modules/metatag/metatag_favicons/src/Tests/MetatagFaviconsTagsTest.php @@ -0,0 +1,240 @@ +<?php + +namespace Drupal\metatag_favicons\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Favicons tags work correctly. + * + * @group metatag + */ +class MetatagFaviconsTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'shortcut_icon', + // 'mask_icon'. + 'icon_16x16', + 'icon_32x32', + 'icon_96x96', + 'icon_192x192', + 'apple_touch_icon', + 'apple_touch_icon_72x72', + 'apple_touch_icon_76x76', + 'apple_touch_icon_114x114', + 'apple_touch_icon_120x120', + 'apple_touch_icon_144x144', + 'apple_touch_icon_152x152', + 'apple_touch_icon_180x180', + 'apple_touch_icon_precomposed', + 'apple_touch_icon_precomposed_72x72', + 'apple_touch_icon_precomposed_76x76', + 'apple_touch_icon_precomposed_114x114', + 'apple_touch_icon_precomposed_120x120', + 'apple_touch_icon_precomposed_144x144', + 'apple_touch_icon_precomposed_152x152', + 'apple_touch_icon_precomposed_180x180', + ]; + + /** + * {@inheritdoc} + */ + private $testTag = 'link'; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'rel'; + + /** + * {@inheritdoc} + */ + private $testValueAttribute = 'href'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_favicons'; + parent::setUp(); + } + + /** + * Implements {tag_name}TestValueAttribute() for 'shortcut icon'. + */ + private function shortcutIconTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'icon_16x16'. + */ + private function icon16x16TestOutputXpath() { + return "//link[@rel='icon' and @sizes='16x16']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'icon_192x192'. + */ + private function icon192x192TestOutputXpath() { + return "//link[@rel='icon' and @sizes='192x192']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'icon_32x32'. + */ + private function icon32x32TestOutputXpath() { + return "//link[@rel='icon' and @sizes='32x32']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'icon_96x96'. + */ + private function icon96x96TestOutputXpath() { + return "//link[@rel='icon' and @sizes='96x96']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_precomposed'. + */ + private function appleTouchIconPrecomposedTestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and not(@sizes)]"; + } + + /** + * Implements {tag_name}TestOutputXpath(). + * + * For 'apple_touch_icon_precomposed_114x114'. + */ + private function appleTouchIconPrecomposed114x114TestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and @sizes='114x114']"; + } + + /** + * Implements {tag_name}TestOutputXpath(). + * + * For 'apple_touch_icon_precomposed_120x120'. + */ + private function appleTouchIconPrecomposed120x120TestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and @sizes='120x120']"; + } + + /** + * Implements {tag_name}TestOutputXpath(). + * + * For 'apple_touch_icon_precomposed_144x144'. + */ + private function appleTouchIconPrecomposed144x144TestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and @sizes='144x144']"; + } + + /** + * Implements {tag_name}TestOutputXpath(). + * + * For 'apple_touch_icon_precomposed_152x152'. + */ + private function appleTouchIconPrecomposed152x152TestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and @sizes='152x152']"; + } + + /** + * Implements {tag_name}TestOutputXpath(). + * + * For 'apple_touch_icon_precomposed_180x180'. + */ + private function appleTouchIconPrecomposed180x180TestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and @sizes='180x180']"; + } + + /** + * Implements {tag_name}TestOutputXpath(). + * + * For 'apple_touch_icon_precomposed_72x72'. + */ + private function appleTouchIconPrecomposed72x72TestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and @sizes='72x72']"; + } + + /** + * Implements {tag_name}TestOutputXpath(). + * + * For 'apple_touch_icon_precomposed_76x76'. + */ + private function appleTouchIconPrecomposed76x76TestOutputXpath() { + return "//link[@rel='apple-touch-icon-precomposed' and @sizes='76x76']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon'. + */ + private function appleTouchIconTestOutputXpath() { + return "//link[@rel='apple-touch-icon' and not(@sizes)]"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_114x114'. + */ + private function appleTouchIcon114x114TestOutputXpath() { + return "//link[@rel='apple-touch-icon' and @sizes='114x114']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_120x120'. + */ + private function appleTouchIcon120x120TestOutputXpath() { + return "//link[@rel='apple-touch-icon' and @sizes='120x120']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_144x144'. + */ + private function appleTouchIcon144x144TestOutputXpath() { + return "//link[@rel='apple-touch-icon' and @sizes='144x144']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_152x152'. + */ + private function appleTouchIcon152x152TestOutputXpath() { + return "//link[@rel='apple-touch-icon' and @sizes='152x152']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_180x180'. + */ + private function appleTouchIcon180x180TestOutputXpath() { + return "//link[@rel='apple-touch-icon' and @sizes='180x180']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_72x72'. + */ + private function appleTouchIcon72x72TestOutputXpath() { + return "//link[@rel='apple-touch-icon' and @sizes='72x72']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'apple_touch_icon_76x76'. + */ + private function appleTouchIcon76x76TestOutputXpath() { + return "//link[@rel='apple-touch-icon' and @sizes='76x76']"; + } + + /** + * Implements {tag_name}TestOutputXpath for 'mask-icon'. + */ + private function maskIconTestTagName() { + return 'mask-icon'; + } + + /** + * Implements {tag_name}TestTagName for 'shortcut icon'. + */ + private function shortcutIconTestTagName() { + return 'shortcut icon'; + } + +} diff --git a/web/modules/metatag/metatag_google_cse/config/schema/metatag_google_cse.metatag_tag.schema.yml b/web/modules/metatag/metatag_google_cse/config/schema/metatag_google_cse.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..823ad974f09ee44316dd288c8e1a3357d2314c6f --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/config/schema/metatag_google_cse.metatag_tag.schema.yml @@ -0,0 +1,19 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.thumbnail: + type: label + label: 'Thumbnail' +metatag.metatag_tag.department: + type: label + label: 'Department' +metatag.metatag_tag.audience: + type: label + label: 'Content audience' +metatag.metatag_tag.doc_status: + type: label + label: 'Document status' +metatag.metatag_tag.google_rating: + type: label + label: 'google_rating' 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 new file mode 100644 index 0000000000000000000000000000000000000000..7ae07312a54c0f0327efbfe8e9eb60ca2250210b --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/metatag_google_cse.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Google Custom Search Engine (CSE)' +type: module +description: Provides support for meta tags used for Google Custom Search Engine. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_google_cse/metatag_google_cse.module b/web/modules/metatag/metatag_google_cse/metatag_google_cse.module new file mode 100644 index 0000000000000000000000000000000000000000..4d1d49eaddb20194fd9c7485ffaca28fafec0756 --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/metatag_google_cse.module @@ -0,0 +1,24 @@ +<?php + +/** + * @file + * Contains metatag_google_cse.module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_google_cse_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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>'; + return $output; + + default: + } +} diff --git a/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Group/GoogleCse.php b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Group/GoogleCse.php new file mode 100644 index 0000000000000000000000000000000000000000..d9fb5dae6320d89d4ebc3f252c114698001916e6 --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Group/GoogleCse.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_google_cse\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * Provides a plugin for the 'Google Custom Search Engine (CSE)' meta tag group. + * + * @MetatagGroup( + * id = "google_cse", + * label = @Translation("Google Custom Search Engine (CSE)"), + * description = @Translation("Meta tags used to control the mobile browser experience. Some of these meta tags have been replaced by newer mobile browsers. These meta tags usually only need to be set globally, rather than per-page."), + * weight = 80, + * ) + */ +class GoogleCse extends GroupBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Audience.php b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Audience.php new file mode 100644 index 0000000000000000000000000000000000000000..c543362f2e26173c19a8909704716a3e5ea15b0e --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Audience.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_cse\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'audience' meta tag. + * + * @MetatagTag( + * id = "audience", + * label = @Translation("Content audience"), + * description = @Translation("The content audience, e.g. ""all""."), + * name = "audience", + * group = "google_cse", + * weight = 0, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Audience extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Department.php b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Department.php new file mode 100644 index 0000000000000000000000000000000000000000..daf3fa2800f7c0010247e60ca1009d108af8c44b --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Department.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_cse\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'department' meta tag. + * + * @MetatagTag( + * id = "department", + * label = @Translation("Department"), + * description = @Translation("Department tag."), + * name = "department", + * group = "google_cse", + * weight = 0, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Department extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/DocStatus.php b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/DocStatus.php new file mode 100644 index 0000000000000000000000000000000000000000..8d59cf81cb2f175fb56e222f3d39443ec388abe0 --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/DocStatus.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_cse\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'doc_status' meta tag. + * + * @MetatagTag( + * id = "doc_status", + * label = @Translation("Document status"), + * description = @Translation("The document status, e.g. ""draft""."), + * name = "doc_status", + * group = "google_cse", + * weight = 0, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class DocStatus extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/GoogleRating.php b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/GoogleRating.php new file mode 100644 index 0000000000000000000000000000000000000000..079d3e661ef63ffb4496fcde2d34888f396c6afd --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/GoogleRating.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_cse\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'google_rating' meta tag. + * + * @MetatagTag( + * id = "google_rating", + * label = @Translation("Content rating"), + * description = @Translation("Works only with numeric values."), + * name = "rating", + * group = "google_cse", + * weight = 0, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class GoogleRating extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Thumbnail.php b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Thumbnail.php new file mode 100644 index 0000000000000000000000000000000000000000..8d4baecc8ef82017afdc5557f567775780181147 --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/src/Plugin/metatag/Tag/Thumbnail.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_cse\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'thumbnail' meta tag. + * + * @MetatagTag( + * id = "thumbnail", + * label = @Translation("Thumbnail"), + * description = @Translation("Use a url of a valid image."), + * name = "thumbnail", + * group = "google_cse", + * weight = 0, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Thumbnail extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_google_cse/src/Tests/MetatagGoogleCSETagsTest.php b/web/modules/metatag/metatag_google_cse/src/Tests/MetatagGoogleCSETagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7544196a799b8444dfafe5fbcfa2e794880ed08e --- /dev/null +++ b/web/modules/metatag/metatag_google_cse/src/Tests/MetatagGoogleCSETagsTest.php @@ -0,0 +1,40 @@ +<?php + +namespace Drupal\metatag_google_cse\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Google CSE tags work correctly. + * + * @group metatag + */ +class MetatagGoogleCSETagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'audience', + 'department', + 'doc_status', + 'google_rating', + 'thumbnail', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_google_cse'; + parent::setUp(); + } + + /** + * Implements {tag_name}TestTagName() for 'google_rating'. + */ + private function googleRatingTestTagName() { + return 'rating'; + } + +} diff --git a/web/modules/metatag/metatag_google_plus/config/schema/metatag_google_plus.metatag_tag.schema.yml b/web/modules/metatag/metatag_google_plus/config/schema/metatag_google_plus.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..8defd7c35127aa0337b68a9fc0842d38f16c4c92 --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/config/schema/metatag_google_plus.metatag_tag.schema.yml @@ -0,0 +1,19 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.google_plus_name: + type: label + label: 'Google Plus: name' +metatag.metatag_tag.google_plus_image: + type: label + label: 'Google Plus: image' +metatag.metatag_tag.google_plus_description: + type: text + label: 'Google Plus: description' +metatag.metatag_tag.google_plus_publisher: + type: label + label: 'Publisher URL' +metatag.metatag_tag.google_plus_author: + type: label + label: 'Author' 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 new file mode 100644 index 0000000000000000000000000000000000000000..6a2dd43f168982869a69370ba8f5c7a8254fa930 --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/metatag_google_plus.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Google Plus' +type: module +description: Provides support for Google's Plus meta tags. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 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 new file mode 100644 index 0000000000000000000000000000000000000000..1744f672d91366eb75519811656773b24d2b6ea5 --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Group/GooglePlus.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_google_plus\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * The GooglePlus group. + * + * @MetatagGroup( + * id = "google_plus", + * label = @Translation("Google Plus"), + * 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 + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..2cbfa3ada5906c5d8c65b331ba26bd92b3fd3373 --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Author.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_plus\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The basic "Author" meta tag. + * + * @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."), + * name = "author", + * group = "google_plus", + * weight = 4, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..9bcb800f243fb49922f890e874d188df04c99e5d --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Description.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_plus\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaItempropBase; + +/** + * The GooglePlus "Description" meta tag. + * + * @MetatagTag( + * id = "google_plus_description", + * label = @Translation("Description"), + * description = @Translation("Content description less than 200 characters."), + * name = "itemprop:description", + * group = "google_plus", + * weight = 2, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..9fb24d70ff428a926f3b24e61264f040320110d9 --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Image.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_plus\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaItempropBase; + +/** + * The GooglePlus 'image' meta tag. + * + * @MetatagTag( + * id = "google_plus_image", + * label = @Translation("Image"), + * description = @Translation("The URL of an image which should represent the content. For best results use an image that is at least 1200 x 630 pixels in size, but at least 600 x 316 pixels is a recommended minimum. Supports PNG, JPEG and GIF formats."), + * name = "itemprop:image", + * group = "google_plus", + * weight = 3, + * type = "image", + * secure = FALSE, + * multiple = TRUE + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..6f68d06ecc385bbee051744c2764ca18bf5dbd8c --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Name.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_plus\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaItempropBase; + +/** + * The GooglePlus 'name' meta tag. + * + * @MetatagTag( + * id = "google_plus_name", + * label = @Translation("Name"), + * description = @Translation("Content title."), + * name = "itemprop:name", + * group = "google_plus", + * weight = 1, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..2e15fd60af1992b18e13c4556830a15cfdfd27b5 --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/src/Plugin/metatag/Tag/Publisher.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_google_plus\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * Provides a plugin for the 'publisher' meta tag. + * + * @MetatagTag( + * id = "google_plus_publisher", + * label = @Translation("Publisher URL"), + * description = @Translation("Used by some search engines to confirm publication of the content on a page. Should be the full URL for the publication's Google+ profile page."), + * name = "publisher", + * group = "google_plus", + * weight = 5, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Publisher extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_google_plus/src/Tests/MetatagGooglePlusTagsTest.php b/web/modules/metatag/metatag_google_plus/src/Tests/MetatagGooglePlusTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..dc8eea5add2d5d05aa0c850cb84782bd7f0fcd89 --- /dev/null +++ b/web/modules/metatag/metatag_google_plus/src/Tests/MetatagGooglePlusTagsTest.php @@ -0,0 +1,77 @@ +<?php + +namespace Drupal\metatag_google_plus\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Google Plus tags work correctly. + * + * @group metatag + */ +class MetatagGooglePlusTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'google_plus_author', + 'google_plus_description', + 'google_plus_image', + 'google_plus_name', + 'google_plus_publisher', + ]; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'itemprop'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_google_plus'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + $tag_name = str_replace('google_plus_', 'itemprop:', $tag_name); + if ($tag_name == 'itemprop:publisher') { + $tag_name = 'publisher'; + } + return $tag_name; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'author'. + */ + private function googlePlusAuthorTestOutputXpath() { + return "//link[@rel='author']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'author'. + */ + private function googlePlusAuthorTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'publisher'. + */ + private function googlePlusPublisherTestOutputXpath() { + return "//link[@rel='publisher']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'publisher'. + */ + private function googlePlusPublisherTestValueAttribute() { + return 'href'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..20ee6303c04c8428dfc4468762a836ff46e92fa3 --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/config/schema/metatag_hreflang.metatag_tag.schema.yml @@ -0,0 +1,7 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.hreflang_xdefault: + type: label + label: 'Default locale (x-default)' diff --git a/web/modules/metatag/metatag_hreflang/metatag_hreflang.info.yml b/web/modules/metatag/metatag_hreflang/metatag_hreflang.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..fde674e1f59dfbaa1f389fad7d95f45726e7c2f2 --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/metatag_hreflang.info.yml @@ -0,0 +1,13 @@ +name: "Metatag: hreflang" +type: module +description: Provides support for the hreflang meta tag with some extra logic to simplify it. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_hreflang/metatag_hreflang.module b/web/modules/metatag/metatag_hreflang/metatag_hreflang.module new file mode 100644 index 0000000000000000000000000000000000000000..81e7792d860b65024a938fcaf1b9440a9bc2d74d --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/metatag_hreflang.module @@ -0,0 +1,24 @@ +<?php + +/** + * @file + * Contains metatag_hreflang.module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_hreflang_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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>'; + return $output; + + default: + } +} diff --git a/web/modules/metatag/metatag_hreflang/src/Plugin/Derivative/HreflangDeriver.php b/web/modules/metatag/metatag_hreflang/src/Plugin/Derivative/HreflangDeriver.php new file mode 100644 index 0000000000000000000000000000000000000000..0eeef79b317abc7fbc346fb3e6b5d85675dd0e53 --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/src/Plugin/Derivative/HreflangDeriver.php @@ -0,0 +1,53 @@ +<?php + +namespace Drupal\metatag_hreflang\Plugin\Derivative; + +use Drupal\Component\Plugin\Derivative\DeriverBase; +use Drupal\Core\Language\Language; +use Drupal\Core\Language\LanguageInterface; + +/** + * Create a new hreflang tag plugin for each enabled language. + */ +class HreflangDeriver extends DeriverBase { + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions($base_plugin_definition) { + // Get a list of all defined languages. + $languages = \Drupal::languageManager() + ->getLanguages(LanguageInterface::STATE_ALL); + + // Now we loop over them and declare the derivatives. + /** @var \Drupal\Core\Language\LanguageInterface $language */ + foreach ($languages as $langcode => $language) { + // Ignore the global values. + if ($langcode == Language::LANGCODE_NOT_SPECIFIED) { + continue; + } + elseif ($langcode == Language::LANGCODE_NOT_APPLICABLE) { + continue; + } + + // The base definition includes the annotations defined in the plugin, + // i.e. HreflangPerLanguage. Each one may be overridden. + $derivative = $base_plugin_definition; + + // Here we fill in any missing keys on the layout annotation. + $derivative['weight']++; + $derivative['id'] = 'hreflang_' . $langcode; + // The 'name' value is used as the value of the 'hreflang' attribute on + // the HTML tag. + $derivative['name'] = $langcode; + $derivative['label'] = t("URL for a version of this page in %langcode", ['%langcode' => $language->getName()]); + $derivative['description'] = ''; + + // Reference derivatives based on their UUID instead of the record ID. + $this->derivatives[$derivative['id']] = $derivative; + } + + return $this->derivatives; + } + +} diff --git a/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Group/Hreflang.php b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Group/Hreflang.php new file mode 100644 index 0000000000000000000000000000000000000000..6d1a25362e17676794aaeb12d8c6c165a462bd10 --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Group/Hreflang.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_hreflang\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * A plugin for the 'Alternative language links (hreflang)' meta tag group. + * + * @MetatagGroup( + * id = "hreflang", + * label = @Translation("Alternative language links (hreflang)"), + * description = @Translation("These meta tags are designed to point visitors to versions of the current page in other languages."), + * weight = 60, + * ) + */ +class Hreflang extends GroupBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangBase.php b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangBase.php new file mode 100644 index 0000000000000000000000000000000000000000..469ca729f1ca88b3b1082faeb716815665ff627b --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangBase.php @@ -0,0 +1,37 @@ +<?php + +namespace Drupal\metatag_hreflang\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * This base plugin allows "link hreflang" tags to be further customized. + */ +abstract class HreflangBase extends LinkRelBase { + + /** + * {@inheritdoc} + */ + public function output() { + $element = parent::output(); + + if ($element) { + // Rewrite the attributes so the hreflang value is before the href value. + $element['#attributes'] = [ + 'rel' => 'alternate', + 'hreflang' => $this->name(), + 'href' => $element['#attributes']['href'], + ]; + } + + return $element; + } + + /** + * {@inheritdoc} + */ + public function name() { + return str_replace('hreflang_', '', parent::name()); + } + +} diff --git a/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangPerLanguage.php b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangPerLanguage.php new file mode 100644 index 0000000000000000000000000000000000000000..958afdeb7dabceaf9d49f673fe30c1e6b95025e0 --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangPerLanguage.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_hreflang\Plugin\metatag\Tag; + +/** + * A new hreflang tag will be made available for each language. + * + * The meta tag's values will be based upon this annotation. + * + * @MetatagTag( + * id = "hreflang_per_language", + * deriver = "Drupal\metatag_hreflang\Plugin\Derivative\HreflangDeriver", + * label = @Translation("Hreflang per language"), + * description = @Translation("This plugin will be cloned from these settings for each enabled language."), + * name = "hreflang_per_language", + * group = "hreflang", + * weight = 1, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class HreflangPerLanguage extends HreflangBase { + // Everything will be inherited. +} diff --git a/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangXDefault.php b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangXDefault.php new file mode 100644 index 0000000000000000000000000000000000000000..5f2ec5b75925b74fedc224ef6794293bac267aa5 --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/src/Plugin/metatag/Tag/HreflangXDefault.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\metatag_hreflang\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'hreflang_xdefault' meta tag. + * + * @MetatagTag( + * id = "hreflang_xdefault", + * label = @Translation("Default locale (x-default)"), + * description = @Translation("This should point to the version of the page that is for the main or primary locale, e.g. the original version of an article that is translated into other languages."), + * name = "hreflang_xdefault", + * group = "hreflang", + * weight = 0, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class HreflangXDefault extends HreflangBase { + + /** + * {@inheritdoc} + */ + public function name() { + return 'x-default'; + } + +} diff --git a/web/modules/metatag/metatag_hreflang/src/Tests/MetatagHreflangTagsTest.php b/web/modules/metatag/metatag_hreflang/src/Tests/MetatagHreflangTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..dc5d2d3b1d651dc1876c991080d7006c2f99297e --- /dev/null +++ b/web/modules/metatag/metatag_hreflang/src/Tests/MetatagHreflangTagsTest.php @@ -0,0 +1,91 @@ +<?php + +namespace Drupal\metatag_hreflang\Tests; + +use Drupal\language\Entity\ConfigurableLanguage; +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag hreflang tags work correctly. + * + * @group metatag + */ +class MetatagHreflangTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'hreflang_xdefault', + 'hreflang_en', + 'hreflang_es', + 'hreflang_fr', + ]; + + /** + * {@inheritdoc} + */ + private $testTag = 'link'; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'alternate'; + + /** + * {@inheritdoc} + */ + private $testValueAttribute = 'href'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + // Need the Language module in order for any of this to work. + parent::$modules[] = 'language'; + // This module. + parent::$modules[] = 'metatag_hreflang'; + parent::setUp(); + + // Enable additional languages. + foreach (['es', 'fr'] as $langcode) { + ConfigurableLanguage::createFromLangcode($langcode)->save(); + } + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + return str_replace('hreflang_', '', $tag_name); + } + + /** + * Implements {tag_name}TestOutputXpath() for 'hreflang_xdefault'. + */ + private function hreflangXdefaultTestOutputXpath() { + return "//link[@hreflang='x-default']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'hreflang_en'. + */ + private function hreflangEnTestOutputXpath() { + return "//link[@hreflang='en']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'hreflang_es'. + */ + private function hreflangEsTestOutputXpath() { + return "//link[@hreflang='es']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'hreflang_fr'. + */ + private function hreflangFrTestOutputXpath() { + return "//link[@hreflang='fr']"; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..6431aaa2b736c2ce3b8ba12419b8dca78a4e6ba9 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/config/schema/metatag_mobile.metatag_tag.schema.yml @@ -0,0 +1,103 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.android_app_link_alternative: + type: label + label: 'Android Mobile: Android App Link Alternative' +metatag.metatag_tag.android_manifest: + type: label + label: 'Android Mobile: Manifest' +metatag.metatag_tag.apple_itunes_app: + type: label + label: 'Apple Mobile: iTunes App' +metatag.metatag_tag.apple_mobile_web_app_capable: + type: label + label: 'Apple Mobile: Web App Capable' +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 + label: 'Apple Mobile: Web App Title' +metatag.metatag_tag.application_name: + type: label + label: 'Application name' +metatag.metatag_tag.cleartype: + type: label + label: 'Mobile: Cleartype' +metatag.metatag_tag.format_detection: + type: label + label: 'Apple Mobile: Format Detection' +metatag.metatag_tag.handheldfriendly: + type: label + label: 'Mobile: Handheld-Friendly' +metatag.metatag_tag.ios_app_link_alternative: + type: label + label: 'Apple Mobile: iOS App Link Alternative' +metatag.metatag_tag.mobileoptimized: + type: label + label: 'Mobile: Mobile Optimized' +metatag.metatag_tag.msapplication_allowDomainApiCalls: + type: label + label: 'MSApplication - Allow domain API calls' +metatag.metatag_tag.msapplication_allowDomainMetaTags: + type: label + label: 'MSApplication - Allow domain meta tags' +metatag.metatag_tag.msapplication_badge: + type: label + label: 'MSApplication - Badge' +metatag.metatag_tag.msapplication_config: + type: label + label: 'MSApplication - Config' +metatag.metatag_tag.msapplication_navbutton_color: + type: label + label: 'MSApplication - Nav button color' +metatag.metatag_tag.msapplication_notification: + type: label + label: 'MSApplication - Notification' +metatag.metatag_tag.msapplication_square150x150logo: + type: label + label: 'MSApplication - Square logo, 150px x 150px' +metatag.metatag_tag.msapplication_square310x310logo: + type: label + label: 'MSApplication - Square logo, 310px x 310px' +metatag.metatag_tag.msapplication_square70x70logo: + type: label + label: 'MSApplication - Square logo, 70px x 70px' +metatag.metatag_tag.msapplication_starturl: + type: label + label: 'MSApplication - Start URL' +metatag.metatag_tag.msapplication_task: + type: label + label: 'MSApplication - Task' +metatag.metatag_tag.msapplication_task_separator: + type: label + label: 'MSApplication - Task separator' +metatag.metatag_tag.msapplication_tilecolor: + type: label + label: 'MSApplication - Tile color' +metatag.metatag_tag.msapplication_tileimage: + type: label + label: 'MSApplication - Tile image' +metatag.metatag_tag.msapplication_tooltip: + type: label + label: 'MSApplication - Tooltip' +metatag.metatag_tag.msapplication_wide310x150logo: + type: label + label: 'MSApplication - Wide logo, 310px x 150px' +metatag.metatag_tag.msapplication_window: + type: label + label: 'MSApplication - Window' +metatag.metatag_tag.theme_color: + type: label + label: 'Mobile: Theme Color' +metatag.metatag_tag.viewport: + type: label + label: 'Mobile: Viewport' +metatag.metatag_tag.web_manifest: + type: label + label: 'Mobile: Web Manifest' +metatag.metatag_tag.x_ua_compatible: + type: label + label: 'X-UA-Compatible' diff --git a/web/modules/metatag/metatag_mobile/metatag_mobile.info.yml b/web/modules/metatag/metatag_mobile/metatag_mobile.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..fb1c833d5cb4d54556fc06057e1702887fdb42b2 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/metatag_mobile.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Mobile & UI Adjustments' +type: module +description: Provides support for meta tags used to control the mobile browser experience. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_mobile/metatag_mobile.module b/web/modules/metatag/metatag_mobile/metatag_mobile.module new file mode 100644 index 0000000000000000000000000000000000000000..dfe0ff94c7ea26bd6ec34444180b865a282b1bf5 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/metatag_mobile.module @@ -0,0 +1,106 @@ +<?php + +/** + * @file + * Contains metatag_mobile.module.. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_mobile_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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>'; + return $output; + + default: + } +} + +/** + * Implements hook_theme(). + */ +function metatag_mobile_theme() { + $info['metatag_mobile_android_app'] = [ + 'render element' => 'element', + ]; + $info['metatag_mobile_ios_app'] = [ + 'render element' => 'element', + ]; + + return $info; +} + +/** + * Implements hook_page_attachments_alter(). + */ +function metatag_mobile_page_attachments_alter(array &$attachments) { + if (isset($attachments['#attached']['html_head'])) { + // A list of core tags that will be replaced, in the format: + // core tag => Metatag-supplied tag + // This assumes that the module's meta tags are output *before* the core + // tags, if this changes then We're Going To Have A Bad Time. + $dupes = [ + 'MobileOptimized' => 'mobileoptimized', + 'HandheldFriendly' => 'handheldfriendly', + 'viewport' => 'viewport', + ]; + + // Keep track of when the Metatag-supplied meta tags are found, so if the + // core tag is also found it can be removed. + $found = []; + + foreach ($dupes as $core_tag => $meta_tag) { + foreach ($attachments['#attached']['html_head'] as $key => $item) { + if (isset($item[1])) { + // The Metatag values are output before core's, so skip the first item + // found so it can be picked up as the dupe; this is important for the + // "viewport" meta tag where both core and Metatag use the same name. + if ($item[1] == $meta_tag && !isset($found[$meta_tag])) { + $found[$meta_tag] = $key; + } + elseif ($item[1] == $core_tag && isset($found[$meta_tag])) { + // @todo This ought to work, but doesn't? + // $attachments['#attached']['html_head'][$key]['#access'] = FALSE; + unset($attachments['#attached']['html_head'][$key]); + } + } + } + } + } +} + +/** + * Theme callback for an Android app link meta tag. + * + * The format is (all on oneline): + * <link rel="alternate" href="android-app://com.example.Example + * /sitesection/sitepage/thispage" /> + */ +function theme_metatag_mobile_android_app($variables) { + // Pass everything through to the normal 'link' tag theme. + $variables['element']['#name'] = 'alternative'; + $variables['element']['#value'] = 'android-app://' . $variables['element']['#value']; + + return theme('metatag_link_rel', $variables); +} + +/** + * Theme callback for an iOS app link meta tag. + * + * The format is: + * <link rel="alternate" href="ios-app://123456/example/hello-screen" /> + */ +function theme_metatag_mobile_ios_app($variables) { + // Pass everything through to the normal 'link' tag theme. + $variables['element']['#name'] = 'alternative'; + $variables['element']['#value'] = 'ios-app://' . $variables['element']['#value']; + + return theme('metatag_link_rel', $variables); +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/AndroidMobile.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/AndroidMobile.php new file mode 100644 index 0000000000000000000000000000000000000000..b1dfca6c87d961bfbed50630cb6c37e7481d7d8c --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/AndroidMobile.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Group; + +/** + * The Android mobile group. + * + * @MetatagGroup( + * id = "android_mobile", + * label = @Translation("Android"), + * description = @Translation("Custom meta tags used by the Android OS, browser, etc."), + * weight = 82 + * ) + */ +class AndroidMobile extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/AppleMobile.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/AppleMobile.php new file mode 100644 index 0000000000000000000000000000000000000000..fa09276f3135496e7c9bdb91a20f01fbdfae28cc --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/AppleMobile.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Group; + +/** + * The Apple mobile group. + * + * @MetatagGroup( + * id = "apple_mobile", + * label = @Translation("Apple & iOS"), + * description = @Translation("Custom meta tags used by Apple's software, iOS, Safari, etc."), + * weight = 81 + * ) + */ +class AppleMobile extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/Mobile.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/Mobile.php new file mode 100644 index 0000000000000000000000000000000000000000..125e59e3595f9237b977099acb6ece8e3a50ed70 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/Mobile.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Group; + +/** + * Provides a plugin for the 'Mobile & UI Adjustments' meta tag group. + * + * @MetatagGroup( + * id = "mobile", + * label = @Translation("Mobile & UI Adjustments"), + * description = @Translation("Meta tags used to control the mobile browser experience. Some of these meta tags have been replaced by newer mobile browsers. These meta tags usually only need to be set globally, rather than per-page."), + * weight = 80 + * ) + */ +class Mobile extends GroupBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/WindowsMobile.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/WindowsMobile.php new file mode 100644 index 0000000000000000000000000000000000000000..f3959c51b1f1f53f2cc3cbdd98352f15b118acea --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Group/WindowsMobile.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Group; + +/** + * The Windows mobile group. + * + * @MetatagGroup( + * id = "windows_mobile", + * label = @Translation("Windows & Windows Mobile"), + * description = @Translation("Custom meta tags used by the Windows and Windows Mobile OSes, IE browser, etc."), + * weight = 83 + * ) + */ +class WindowsMobile extends GroupBase { + // Inherits everything from Base. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..a3729435c283b1ca1b8166e88cdd0c8e5dc74aca --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidAppLinkAlternative.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The Android app link alternative for Android mobile metatag. + * + * @MetatagTag( + * id = "android_app_link_alternative", + * label = @Translation("Android app link alternative"), + * description = @Translation("A custom string for deeplinking to an Android mobile app. Should be in the format 'package_name/host_path', e.g. 'com.example.android/example/hello-screen'. The 'android-app://' prefix will be included automatically."), + * name = "alternate", + * group = "android_mobile", + * weight = 91, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AndroidAppLinkAlternative extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidManifest.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidManifest.php new file mode 100644 index 0000000000000000000000000000000000000000..5710e152f9207ec18b84873d187359a8e255e1cf --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AndroidManifest.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The Android Manifest for Android mobile metatag. + * + * @MetatagTag( + * id = "android_manifest", + * label = @Translation("Manifest"), + * description = @Translation("A URL to a manifest.json file that describes the application. The <a href='https://developer.chrome.com/multidevice/android/installtohomescreen'>JSON-based manifest</a> provides developers with a centralized place to put metadata associated with a web application."), + * name = "manifest", + * group = "android_mobile", + * weight = 92, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AndroidManifest extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleItunesApp.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleItunesApp.php new file mode 100644 index 0000000000000000000000000000000000000000..b7bfdd730d32292292b8aa5b4093fff1d3261dd6 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleItunesApp.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Itunes App for Apple mobile metatag. + * + * @MetatagTag( + * id = "apple_itunes_app", + * label = @Translation("iTunes App details"), + * description = @Translation("This informs iOS devices to display a banner to a specific app. If used, it must provide the 'app-id' value, the 'affiliate-data' and 'app-argument' values are optional."), + * name = "apple-itunes-app", + * group = "apple_mobile", + * weight = 86, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleItunesApp extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppCapable.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppCapable.php new file mode 100644 index 0000000000000000000000000000000000000000..19261845d75be6c2a8eb11db0b4e3bbd11563030 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppCapable.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Web App Capable for Apple mobile metatag. + * + * @MetatagTag( + * id = "apple_mobile_web_app_capable", + * label = @Translation("Web app capable?"), + * description = @Translation("If set to 'yes', the application will run in full-screen mode; the default behavior is to use Safari to display web content."), + * name = "apple-mobile-web-app-capable", + * group = "apple_mobile", + * weight = 87, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleMobileWebAppCapable extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppStatusBarStyle.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppStatusBarStyle.php new file mode 100644 index 0000000000000000000000000000000000000000..0586c2cf00ad0a83c3b607d0721db31fefe5e4e5 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppStatusBarStyle.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Web App status bar style for Apple mobile metatag. + * + * @MetatagTag( + * id = "apple_mobile_web_app_status_bar_style", + * label = @Translation("Status bar color"), + * description = @Translation("Requires the 'Web app capable' meta tag to be set to 'yes'. May be set to 'default', 'black', or 'black-translucent'."), + * name = "apple-mobile-web-app-status-bar-style", + * group = "apple_mobile", + * weight = 88, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleMobileWebAppStatusBarStyle extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppTitle.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppTitle.php new file mode 100644 index 0000000000000000000000000000000000000000..38d4beb69410a06767e894b6819b5e8f65e9cb66 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/AppleMobileWebAppTitle.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Web App title for Apple mobile metatag. + * + * @MetatagTag( + * id = "apple_mobile_web_app_title", + * label = @Translation("Apple Web App Title"), + * description = @Translation("Overrides the long site title when using the Apple Add to Home Screen."), + * name = "apple-mobile-web-app-title", + * group = "apple_mobile", + * weight = 89, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AppleMobileWebAppTitle extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/ApplicationName.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/ApplicationName.php new file mode 100644 index 0000000000000000000000000000000000000000..1a6e40f617e4df934176364b874dd94fc0bae2ea --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/ApplicationName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'application:name' meta tag. + * + * @MetatagTag( + * id = "application_name", + * label = @Translation("Application name"), + * description = @Translation("The default name displayed with the pinned sites tile (or icon). Set the content attribute to the desired name."), + * name = "application-name", + * group = "windows_mobile", + * weight = 94, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ApplicationName extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/Cleartype.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/Cleartype.php new file mode 100644 index 0000000000000000000000000000000000000000..ea9a0da707b253339a3ecc66c72390fc0780725c --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/Cleartype.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaHttpEquivBase; + +/** + * The Cleartype for Mobile metatag. + * + * @MetatagTag( + * id = "cleartype", + * label = @Translation("Cleartype"), + * description = @Translation("A legacy meta tag for older versions of Internet Explorer on Windows, use the value 'on' to enable it; this tag is ignored by all other browsers."), + * name = "cleartype", + * group = "mobile", + * weight = 85, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Cleartype extends MetaHttpEquivBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/FormatDetection.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/FormatDetection.php new file mode 100644 index 0000000000000000000000000000000000000000..73c186fb5fb8bf3ddb93adf21b51dde07eb89e31 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/FormatDetection.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Format Detection for Apple mobile metatag. + * + * @MetatagTag( + * id = "format_detection", + * label = @Translation("Format detection"), + * description = @Translation("If set to 'telephone=no' the page will not be checked for phone numbers, which would be presented."), + * name = "format-detection", + * group = "apple_mobile", + * weight = 90, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class FormatDetection extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/HandheldFriendly.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/HandheldFriendly.php new file mode 100644 index 0000000000000000000000000000000000000000..29d7e693edbf3f1652faeb974eda0d3f5724279b --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/HandheldFriendly.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Handheld Friendly for Mobile metatag. + * + * @MetatagTag( + * id = "handheldfriendly", + * label = @Translation("Handheld-Friendly"), + * description = @Translation("Some older mobile browsers will expect this meta tag to be set to 'true' to indicate that the site has been designed with mobile browsers in mind."), + * name = "HandheldFriendly", + * group = "mobile", + * weight = 83, + * type = "string", + * secure = FALSE, + * multiple = TRUE + * ) + */ +class HandheldFriendly extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..6efa753130ef46e52e994240aad3586d0d59a496 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/IosAppLinkAlternative.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The iOS App link alternative for Apple mobile metatag. + * + * @MetatagTag( + * id = "ios_app_link_alternative", + * label = @Translation("iOS app link alternative"), + * description = @Translation("A custom string for deeplinking to an iOS mobile app. Should be in the format 'itunes_id/scheme/host_path', e.g. 123456/example/hello-screen'. The 'ios-app://' prefix will be included automatically."), + * name = "alternate", + * group = "apple_mobile", + * weight = 91, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class IosAppLinkAlternative extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MobileOptimized.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MobileOptimized.php new file mode 100644 index 0000000000000000000000000000000000000000..22ac9320e53cf8c512d37c00cf4105398b1b7005 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MobileOptimized.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Mobile optimized for Mobile metatag. + * + * @MetatagTag( + * id = "mobileoptimized", + * label = @Translation("Mobile Optimized"), + * description = @Translation("Using the value 'width' tells certain mobile Internet Explorer browsers to display as-is, without being resized. Alternatively a numerical width may be used to indicate the desired page width the page should be rendered in: '240' is the suggested default, '176' for older browsers or '480' for newer devices with high DPI screens."), + * name = "MobileOptimized", + * group = "mobile", + * weight = 82, + * type = "string", + * secure = FALSE, + * multiple = TRUE + * ) + */ +class MobileOptimized extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationAllowDomainApiCalls.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationAllowDomainApiCalls.php new file mode 100644 index 0000000000000000000000000000000000000000..c21eb621bd19097842eabaa63024a6f92ca8154c --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationAllowDomainApiCalls.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:allowDomainApiCalls' meta tag. + * + * @MetatagTag( + * id = "msapplication_allowDomainApiCalls", + * label = @Translation("MSApplication - Allow domain API calls"), + * description = @Translation("Allows tasks to be defined on child domains of the fully qualified domain name associated with the pinned site. Should be either 'true' or 'false'."), + * name = "msapplication-allowDomainApiCalls", + * group = "windows_mobile", + * weight = 95, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationAllowDomainApiCalls extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationAllowDomainMetaTags.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationAllowDomainMetaTags.php new file mode 100644 index 0000000000000000000000000000000000000000..46b77e6440aa7d3a69e2b6331e6bd228fa000784 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationAllowDomainMetaTags.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:allowDomainMetaTags' meta tag. + * + * @MetatagTag( + * id = "msapplication_allowDomainMetaTags", + * label = @Translation("MSApplication - Allow domain meta tags"), + * description = @Translation("Allows tasks to be defined on child domains of the fully qualified domain name associated with the pinned site. Should be either 'true' or 'false'."), + * name = "msapplication-allowDomainMetaTags", + * group = "windows_mobile", + * weight = 96, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationAllowDomainMetaTags extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationBadge.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationBadge.php new file mode 100644 index 0000000000000000000000000000000000000000..d1d61e0a1b2587e4a5225c4c576e3ad579bc1644 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationBadge.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:badge' meta tag. + * + * @MetatagTag( + * id = "msapplication_badge", + * label = @Translation("MSApplication - Badge"), + * description = @Translation("A semi-colon -separated string that must contain the 'polling-uri=' value with the full URL to a <a href='http://go.microsoft.com/fwlink/p/?LinkID=314019'>Badge Schema XML file</a>. May also contain 'frequency=' value set to either 30, 60, 360, 720 or 1440 (default) which specifies (in minutes) how often the URL should be polled."), + * name = "msapplication-badge", + * group = "windows_mobile", + * weight = 97, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationBadge extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationConfig.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationConfig.php new file mode 100644 index 0000000000000000000000000000000000000000..4487b7c7c1645194dc39e1549cbef824cefc611c --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationConfig.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:config' meta tag. + * + * @MetatagTag( + * id = "msapplication_config", + * label = @Translation("MSApplication - Config"), + * description = @Translation("Should contain the full URL to a <a href='https://msdn.microsoft.com/en-us/library/dn320426(v=vs.85).aspx'>Browser configuration schema</a> file that further controls tile customizations."), + * name = "msapplication-config", + * group = "windows_mobile", + * weight = 98, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationConfig extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationNavbuttonColor.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationNavbuttonColor.php new file mode 100644 index 0000000000000000000000000000000000000000..8d116698b9b32a308e624ca5207e9b7fbdebb1ac --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationNavbuttonColor.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:navbutton:color' meta tag. + * + * @MetatagTag( + * id = "msapplication_navbutton_color", + * label = @Translation("MSApplication - Nav button color"), + * description = @Translation("Controls the color of the Back and Forward buttons in the pinned site browser window."), + * name = "msapplication-navbutton-color", + * group = "windows_mobile", + * weight = 99, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationNavbuttonColor extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationNotification.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationNotification.php new file mode 100644 index 0000000000000000000000000000000000000000..aa739140184eed8055b1778c909633560145def4 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationNotification.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:notification' meta tag. + * + * @MetatagTag( + * id = "msapplication_notification", + * label = @Translation("MSApplication - Notification"), + * description = @Translation("A semi-colon -separated string containing 'polling-uri=' (required), 'polling-uri2=', 'polling-uri3=', 'polling-uri4=' and 'polling-uri5=' to indicate the URLs for notifications. May also contain a 'frequency=' value to specify how often (in minutes) the URLs will be polled; limited to 30, 60, 360, 720 or 1440 (default). May also contain the value 'cycle=' to control the notifications cycle."), + * name = "msapplication-notification", + * group = "windows_mobile", + * weight = 100, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationNotification extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare150x150logo.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare150x150logo.php new file mode 100644 index 0000000000000000000000000000000000000000..fbf96e0d312acfaacc5cffe18e331626a9771bc0 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare150x150logo.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:square150x150logo' meta tag. + * + * @MetatagTag( + * id = "msapplication_square150x150logo", + * label = @Translation("MSApplication - Square logo, 150px x 150px"), + * description = @Translation("The URL to a logo file that is 150px by 150px."), + * name = "msapplication-square150x150logo", + * group = "windows_mobile", + * weight = 101, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationSquare150x150logo extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare310x310logo.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare310x310logo.php new file mode 100644 index 0000000000000000000000000000000000000000..3f1b074947d03bf2718563582a0a8d8711e2393b --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare310x310logo.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:square310x310logo' meta tag. + * + * @MetatagTag( + * id = "msapplication_square310x310logo", + * label = @Translation("MSApplication - Square logo, 310px x 310px"), + * description = @Translation("The URL to a logo file that is 310px by 310px."), + * name = "msapplication-square310x310logo", + * group = "windows_mobile", + * weight = 102, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationSquare310x310logo extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare70x70logo.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare70x70logo.php new file mode 100644 index 0000000000000000000000000000000000000000..042d500620b462ff33361e8ead0988bceebaef90 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationSquare70x70logo.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:square70x70logo' meta tag. + * + * @MetatagTag( + * id = "msapplication_square70x70logo", + * label = @Translation("MSApplication - Square logo, 70px x 70px"), + * description = @Translation("The URL to a logo file that is 70px by 70px."), + * name = "msapplication-square70x70logo", + * group = "windows_mobile", + * weight = 103, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationSquare70x70logo extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationStartUrl.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationStartUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..12de1c7c7ade0a788c129353cf6298351b19334b --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationStartUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:starturl' meta tag. + * + * @MetatagTag( + * id = "msapplication_starturl", + * label = @Translation("MSApplication - Start URL"), + * description = @Translation("The URL to the root page of the site."), + * name = "msapplication-starturl", + * group = "windows_mobile", + * weight = 105, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationStartUrl extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTask.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTask.php new file mode 100644 index 0000000000000000000000000000000000000000..6e4e4d864bf509637c6be101940d2b64359f83c3 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTask.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:task' meta tag. + * + * @MetatagTag( + * id = "msapplication_task", + * label = @Translation("MSApplication - Task"), + * description = @Translation("A semi-colon -separated string defining the 'jump' list task. Should contain the 'name=' value to specify the task's name, the 'action-uri=' value to set the URL to load when the jump list is clicked, the 'icon-uri=' value to set the URL to an icon file to be displayed, and 'window-type=' set to either 'tab' (default), 'self' or 'window' to control how the link opens in the browser."), + * name = "msapplication-task", + * group = "windows_mobile", + * weight = 106, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationTask extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..25d502f31a7ee38e5577742df34522830e3a15f5 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTaskSeparator.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:task:separator' meta tag. + * + * @MetatagTag( + * id = "msapplication_task_separator", + * label = @Translation("MSApplication - Task separator"), + * description = @Translation(""), + * name = "msapplication-task-separator", + * group = "windows_mobile", + * weight = 107, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationTaskSeparator extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTilecolor.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTilecolor.php new file mode 100644 index 0000000000000000000000000000000000000000..bf9c33f41758830e5d97b56c59d9f3c89926c7ee --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTilecolor.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:tilecolor' meta tag. + * + * @MetatagTag( + * id = "msapplication_tilecolor", + * label = @Translation("MSApplication - Tile color"), + * description = @Translation("The HTML color to use as the background color for the live tile."), + * name = "msapplication-tilecolor", + * group = "windows_mobile", + * weight = 108, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationTilecolor extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTileimage.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTileimage.php new file mode 100644 index 0000000000000000000000000000000000000000..994c7e2e88a730b7378a40f1db87035055cd4f01 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTileimage.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:tileimage' meta tag. + * + * @MetatagTag( + * id = "msapplication_tileimage", + * label = @Translation("MSApplication - Tile image"), + * description = @Translation("The URL to an image to use as the background for the live tile."), + * name = "msapplication-tileimage", + * group = "windows_mobile", + * weight = 109, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationTileimage extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTooltip.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTooltip.php new file mode 100644 index 0000000000000000000000000000000000000000..7d2df50023069d7ccad1494f4cc73175d68caa49 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationTooltip.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:tooltip' meta tag. + * + * @MetatagTag( + * id = "msapplication_tooltip", + * label = @Translation("MSApplication - Tooltip"), + * description = @Translation("Controls the text shown in the tooltip for the pinned site's shortcut."), + * name = "msapplication-tooltip", + * group = "windows_mobile", + * weight = 110, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationTooltip extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationWide310x150logo.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationWide310x150logo.php new file mode 100644 index 0000000000000000000000000000000000000000..52532398d8ff2052e75c7736deb8839303c90775 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationWide310x150logo.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:wide310x150logo' meta tag. + * + * @MetatagTag( + * id = "msapplication_wide310x150logo", + * label = @Translation("MSApplication - Wide logo, 310px x 150px"), + * description = @Translation("The URL to a logo file that is 310px by 150px."), + * name = "msapplication-wide310x150logo", + * group = "windows_mobile", + * weight = 104, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationWide310x150logo extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationWindow.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationWindow.php new file mode 100644 index 0000000000000000000000000000000000000000..967e2f490654aed093d54e21ac13e0ac157283ee --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/MsapplicationWindow.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'msapplication:window' meta tag. + * + * @MetatagTag( + * id = "msapplication_window", + * label = @Translation("MSApplication - Window"), + * description = @Translation("A semi-colon -separated value that controls the dimensions of the initial window. Should contain the values 'width=' and 'height=' to control the width and height respectively."), + * name = "msapplication-window", + * group = "windows_mobile", + * weight = 111, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MsapplicationWindow extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/ThemeColor.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/ThemeColor.php new file mode 100644 index 0000000000000000000000000000000000000000..07cd4a217852ca78f81f3372e3dc67d44482839a --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/ThemeColor.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Theme color for Mobile metatag. + * + * @MetatagTag( + * id = "theme_color", + * label = @Translation("Theme Color"), + * description = @Translation("A color in hexidecimal format, e.g. '#0000ff' for blue; must include the '#' symbol. Used by some browsers to control the background color of the toolbar, the color used with an icon, etc."), + * name = "theme-color", + * group = "mobile", + * weight = 81, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ThemeColor extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/Viewport.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/Viewport.php new file mode 100644 index 0000000000000000000000000000000000000000..dca933831cc52c381a1babd249f23bd1cad6488d --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/Viewport.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Viewport for Mobile metatag. + * + * @MetatagTag( + * id = "viewport", + * label = @Translation("Viewport"), + * description = @Translation("Used by most contemporary browsers to control the display for mobile browsers. Please read a guide on responsive web design for details of what values to use."), + * name = "viewport", + * group = "mobile", + * weight = 84, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Viewport extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5028cae018c82dede43996560134961790f07365 --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/WebManifest.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\LinkRelBase; + +/** + * The Web Manifest for Progressive Web Apps. + * + * @MetatagTag( + * id = "web_manifest", + * label = @Translation("Web Manifest"), + * description = @Translation("A URL to a manifest.json file that describes the application. The <a href='https://developer.mozilla.org/en-US/docs/Web/Manifest'>JSON-based manifest</a> provides developers with a centralized place to put metadata associated with a web application."), + * name = "manifest", + * group = "mobile", + * weight = 92, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class WebManifest extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/XUaCompatible.php b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/XUaCompatible.php new file mode 100644 index 0000000000000000000000000000000000000000..99c93ee400a0a75cff1bfd2bf92f6e7f016c124f --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Plugin/metatag/Tag/XUaCompatible.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_mobile\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaHttpEquivBase; + +/** + * Provides a plugin for the 'x:ua:compatible' meta tag. + * + * @MetatagTag( + * id = "x_ua_compatible", + * label = @Translation("X-UA-Compatible"), + * description = @Translation("Indicates to IE which rendering engine should be used for the current page."), + * name = "x-ua-compatible", + * group = "windows_mobile", + * weight = 93, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class XUaCompatible extends MetaHttpEquivBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_mobile/src/Tests/MetatagMobileTagsTest.php b/web/modules/metatag/metatag_mobile/src/Tests/MetatagMobileTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..4287449624f4eb5f8c75df9b25b4289cc7f6034b --- /dev/null +++ b/web/modules/metatag/metatag_mobile/src/Tests/MetatagMobileTagsTest.php @@ -0,0 +1,238 @@ +<?php + +namespace Drupal\metatag_mobile\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag mobile tags work correctly. + * + * @group metatag + */ +class MetatagMobileTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'android_app_link_alternative', + 'android_manifest', + 'apple_itunes_app', + 'apple_mobile_web_app_capable', + 'apple_mobile_web_app_status_bar_style', + 'apple_mobile_web_app_title', + 'application_name', + 'cleartype', + 'format_detection', + 'handheldfriendly', + 'ios_app_link_alternative', + 'mobileoptimized', + 'msapplication_allowDomainApiCalls', + 'msapplication_allowDomainMetaTags', + 'msapplication_badge', + 'msapplication_config', + 'msapplication_navbutton_color', + 'msapplication_notification', + 'msapplication_square150x150logo', + 'msapplication_square310x310logo', + 'msapplication_square70x70logo', + 'msapplication_starturl', + 'msapplication_task', + 'msapplication_task_separator', + 'msapplication_tilecolor', + 'msapplication_tileimage', + 'msapplication_tooltip', + 'msapplication_wide310x150logo', + 'msapplication_window', + 'theme_color', + 'viewport', + 'web_manifest', + 'x_ua_compatible', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_mobile'; + parent::setUp(); + } + + /** + * {@inheritdoc} + */ + private function getTestTagName($tag_name) { + // These tags all use dashes instead of underlines. + $tag_name = str_replace('_', '-', $tag_name); + + // Fix a few specific tags. + $tag_name = str_replace('mobileoptimized', 'MobileOptimized', $tag_name); + $tag_name = str_replace('handheldfriendly', 'HandheldFriendly', $tag_name); + + return $tag_name; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'alternate-handheld'. + */ + private function alternateHandheldTestOutputXpath() { + return "//link[@rel='alternate' and @media='handheld']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'alternate-handheld'. + */ + private function alternateHandheldTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'amphtml'. + */ + private function amphtmlTestOutputXpath() { + return "//link[@rel='amphtml']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'amphtml'. + */ + private function amphtmlTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestValue() for 'android_app_link_alternative'. + */ + private function androidAppLinkAlternativeTestValue() { + return 'android-app:' . $this->randomMachineName(); + } + + /** + * Implements {tag_name}TestOutputXpath() for 'android-app-link-alternative'. + */ + private function androidAppLinkAlternativeTestOutputXpath() { + return "//link[@rel='alternate' and starts-with(@href, 'android-app:')]"; + } + + /** + * Implements {tag_name}TestValueAttribute(). + * + * For 'android-app-link-alternative'. + */ + private function androidAppLinkAlternativeTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'android_manifest'. + */ + private function androidManifestTestOutputXpath() { + return "//link[@rel='manifest']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'android_manifest'. + */ + private function androidManifestTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'cleartype'. + */ + private function cleartypeTestNameAttribute() { + return 'http-equiv'; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'handheldfriendly'. + */ + private function handheldfriendlyTestOutputXpath() { + return "//meta[@name='HandheldFriendly']"; + } + + /** + * Implements {tag_name}TestValue() for 'ios_app_link_alternative'. + */ + private function iosAppLinkAlternativeTestValue() { + return 'ios-app:' . $this->randomMachineName(); + } + + /** + * Implements {tag_name}TestOutputXpath() for 'ios_app_link_alternative'. + */ + private function iosAppLinkAlternativeTestOutputXpath() { + return "//link[@rel='alternate' and starts-with(@href, 'ios-app:')]"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'ios_app_link_alternative'. + */ + private function iosAppLinkAlternativeTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'mobileoptimized'. + */ + private function mobileoptimizedTestOutputXpath() { + return "//meta[@name='MobileOptimized']"; + } + + /** + * Implements {tag_name}TestValue() for 'msapplication-square150x150logo'. + */ + private function msapplicationSquare150x150logoTestValue() { + return $this->randomImageUrl(); + } + + /** + * Implements {tag_name}TestValue() for 'msapplication-square310x310logo'. + */ + private function msapplicationSquare310x310logoTestValue() { + return $this->randomImageUrl(); + } + + /** + * Implements {tag_name}TestValue() for 'msapplication-square70x70logo'. + */ + private function msapplicationSquare70x70logoTestValue() { + return $this->randomImageUrl(); + } + + /** + * Implements {tag_name}TestValue() for 'msapplication-tileimage'. + */ + private function msapplicationTileimageTestValue() { + return $this->randomImageUrl(); + } + + /** + * Implements {tag_name}TestValue() for 'msapplication-wide310x150logo'. + */ + private function msapplicationWide310x150logoTestValue() { + return $this->randomImageUrl(); + } + + /** + * Implements {tag_name}TestOutputXpath() for 'web_manifest'. + */ + private function webManifestTestOutputXpath() { + return "//link[@rel='manifest']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'web_manifest'. + */ + private function webManifestTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'x-ua-compatible'. + */ + private function xUaCompatibleTestNameAttribute() { + return 'http-equiv'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..593df480f034c7eb43cfe92adbeb865cad37ada0 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/config/schema/metatag_open_graph.metatag_tag.schema.yml @@ -0,0 +1,133 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.og_country_name: + type: label + label: 'Open Graph: Country name' +metatag.metatag_tag.og_description: + type: text + label: 'Open Graph: Description' +metatag.metatag_tag.og_determiner: + type: label + label: 'Open Graph: Determiner' +metatag.metatag_tag.og_email: + type: label + label: 'Open Graph: Email' +metatag.metatag_tag.og_fax_number: + type: label + label: 'Open Graph: Fax number' +metatag.metatag_tag.og_image: + type: label + label: 'Open Graph: Image' +metatag.metatag_tag.og_image_alt: + type: label + label: 'Open Graph: Image alt' +metatag.metatag_tag.og_image_height: + type: label + label: 'Open Graph: Image height' +metatag.metatag_tag.og_image_secure_url: + type: label + label: 'Open Graph: Image secure URL' +metatag.metatag_tag.og_image_type: + type: label + label: 'Open Graph: Image type' +metatag.metatag_tag.og_image_url: + type: label + label: 'Open Graph: Image URL' +metatag.metatag_tag.og_image_width: + type: label + label: 'Open Graph: Image width' +metatag.metatag_tag.og_latitude: + type: label + label: 'Open Graph: Latitude' +metatag.metatag_tag.og_locale: + type: label + label: 'Open Graph: Locale' +metatag.metatag_tag.og_locale_alternative: + type: label + label: 'Open Graph: Alternative locale' +metatag.metatag_tag.og_locality: + type: label + label: 'Open Graph: Locality' +metatag.metatag_tag.og_longitude: + type: label + label: 'Open Graph: Longitude' +metatag.metatag_tag.og_phone_number: + type: label + label: 'Open Graph: Phone number' +metatag.metatag_tag.og_postal_code: + type: label + label: 'Open Graph: Postal code' +metatag.metatag_tag.og_region: + type: label + label: 'Open Graph: Region' +metatag.metatag_tag.og_see_also: + type: label + label: 'Open Graph: See also' +metatag.metatag_tag.og_site_name: + type: label + label: 'Open Graph: Site name' +metatag.metatag_tag.og_street_address: + type: label + label: 'Open Graph: Street address' +metatag.metatag_tag.og_title: + type: label + label: 'Open Graph: Title' +metatag.metatag_tag.og_type: + type: label + label: 'Open Graph: Type' +metatag.metatag_tag.og_updated_time: + type: label + label: 'Open Graph: Updated time' +metatag.metatag_tag.og_url: + type: label + label: 'Open Graph: URL' +metatag.metatag_tag.og_video: + type: label + label: 'Open Graph: Video URL' +metatag.metatag_tag.og_video_height: + type: label + label: 'Open Graph: Video height' +metatag.metatag_tag.og_video_secure_url: + type: label + label: 'Open Graph: Video Secure URL' +metatag.metatag_tag.og_video_type: + type: label + label: 'Open Graph: Video type' +metatag.metatag_tag.og_video_width: + type: label + label: 'Open Graph: Video width' +metatag.metatag_tag.article_author: + type: label + label: 'Article author' +metatag.metatag_tag.article_expiration_time: + type: label + label: 'Article expiration time' +metatag.metatag_tag.article_modified_time: + type: label + label: 'Article modified time' +metatag.metatag_tag.article_published_time: + type: label + label: 'Article published time' +metatag.metatag_tag.article_publisher: + type: label + label: 'Article publisher' +metatag.metatag_tag.article_section: + type: label + label: 'Article section' +metatag.metatag_tag.article_tag: + type: label + label: 'Article tag(s)' +metatag.metatag_tag.book_author: + type: label + label: 'Book Author' +metatag.metatag_tag.book_isbn: + type: label + label: 'Book ISBN' +metatag.metatag_tag.book_release_date: + type: label + label: 'Book Release Date' +metatag.metatag_tag.book_tag: + type: label + label: 'Book Tags' 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 new file mode 100644 index 0000000000000000000000000000000000000000..7755b893b4fc36a114054e8d4d4fb02f734e8d18 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/metatag_open_graph.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Open Graph' +type: module +description: Provides support for Open Graph Protocol meta tags. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_open_graph/metatag_open_graph.install b/web/modules/metatag/metatag_open_graph/metatag_open_graph.install new file mode 100644 index 0000000000000000000000000000000000000000..28baa7a4e42754ab2f04c1e679244967fb331b5e --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/metatag_open_graph.install @@ -0,0 +1,127 @@ +<?php + +/** + * @file + * Update scripts for the Metatag Open Graph module. + */ + +use Drupal\Core\Entity\ContentEntityBase; +use Drupal\metatag\Entity\MetatagDefaults; + +/** + * Implementations of hook_update_N(). + */ + +/** + * The "article:tags" meta tag was renamed to the correct "article:tag". + */ +function metatag_open_graph_update_8101() { + /* @var $configs Drupal\metatag\Entity\MetatagDefaults */ + $configs = MetatagDefaults::loadMultiple(); + + foreach ($configs as $config) { + $tags = $config->get('tags'); + + if (array_key_exists("article_tags", $tags)) { + $tags['article_tag'] = $tags['article_tags']; + unset($tags['article_tags']); + $config->set("tags", $tags); + $config->save(); + } + } +} + +/** + * The "article_tags" tag config was renamed "article_tag" on content entities. + */ +function metatag_open_graph_update_8102(&$sandbox) { + // Update existing content with reference to old article_tags. + $etm = Drupal::entityTypeManager(); + + if (empty($sandbox)) { + + $field_map = Drupal::getContainer()->get('entity_field.manager')->getFieldMap(); + $sandbox['todo'] = []; + $sandbox['done'] = 0; + $sandbox['max'] = 0; + $sandbox['#finished'] = 0; + + foreach ($field_map as $entity_type => $fields) { + foreach ($fields as $field_name => $field_def) { + if ($field_def['type'] == "metatag") { + // We found a metatag field, so query for all the entities of this + // type that have "article_tags" in the serialized array. + $q = \Drupal::entityQuery($entity_type); + $q->condition($field_name, "article_tags", "CONTAINS"); + $count = $q->count()->execute(); + + if ($count > 0) { + $sandbox['todo'][$entity_type][$field_name] = 0; + $sandbox['max'] += $count; + } + } + } + } + + if ($sandbox['max'] == 0) { + // Nothing to do. + $sandbox['#finished'] = 1; + return; + } + } + + foreach ($sandbox['todo'] as $entity_type => $fields) { + + /* @var $def Drupal\Core\Entity\ContentEntityType */ + $def = Drupal::entityTypeManager()->getDefinition($entity_type); + + // Grab the primary key field for this entity type + // so we can filter and order by it. + $id_col = $def->getKey("id"); + + foreach ($fields as $field_name => $last) { + $q = \Drupal::entityQuery($entity_type); + $q->condition($field_name, "article_tags", "CONTAINS"); + $q->condition($id_col, $last, ">"); + $q->sort($id_col); + $q->pager(20); + $res = $q->execute(); + + if (empty($res)) { + unset($sandbox['todo'][$entity_type][$field_name]); + continue; + } + + $entities = $etm->getStorage($entity_type)->loadMultiple($res); + + foreach ($entities as $entity) { + /* @var $entity ContentEntityBase */ + if ($entity instanceof ContentEntityBase) { + if ($entity->hasField($field_name)) { + /* @var 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); + if (array_key_exists("article_tags", $tags)) { + $tags['article_tag'] = $tags['article_tags']; + unset($tags['article_tags']); + $trans->set($field_name, serialize($tags)); + $trans->save(); + } + } + } + } + } + + // Store the last pk per entity type and field name. + $sandbox['todo'][$entity_type][$field_name] = $entity->id(); + $sandbox['done']++; + $sandbox['#finished'] = $sandbox['done'] / $sandbox['max']; + } + } + } +} diff --git a/web/modules/metatag/metatag_open_graph/metatag_open_graph.module b/web/modules/metatag/metatag_open_graph/metatag_open_graph.module new file mode 100644 index 0000000000000000000000000000000000000000..fa5ffa70749881da3a4ba93837f77c4a3ac9a529 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/metatag_open_graph.module @@ -0,0 +1,38 @@ +<?php + +/** + * @file + * Contains metatag_open_graph.module. + */ + +/** + * Implements template_preprocess_html(). + */ +function metatag_open_graph_preprocess_html(&$variables) { + if (!metatag_is_current_route_supported()) { + return; + } + + // Add XML namespaces if the RDF module is not enabled as it adds these two + // automatically. + if (!isset($variables['html_attributes'])) { + $variables['html_attributes'] = []; + } + $namespaces = []; + if (!\Drupal::moduleHandler()->moduleExists('rdf')) { + $namespaces = [ + 'prefix' => 'og: http://ogp.me/ns#', + ]; + } + + // Namespaces for Google+. + if (isset($variables['itemtype'])) { + $namespaces['itemscope'] = ''; + $namespaces['itemtype'] = "http://schema.org/{$variables['itemtype']}"; + } + + // Append each namespace. + foreach ($namespaces as $namespace => $uri) { + $variables['html_attributes'][$namespace] = $uri; + } +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Group/OpenGraph.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Group/OpenGraph.php new file mode 100644 index 0000000000000000000000000000000000000000..3e5c8ac58e0672cd3074fedc66699854cadfbbba --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Group/OpenGraph.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * The open graph group. + * + * @MetatagGroup( + * id = "open_graph", + * label = @Translation("Open Graph"), + * description = @Translation("The <a href='http://ogp.me/'>Open Graph meta tags</a> are used control how Facebook, Pinterest, LinkedIn and other social networking sites interpret the site's content."), + * weight = 3 + * ) + */ +class OpenGraph extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleAuthor.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleAuthor.php new file mode 100644 index 0000000000000000000000000000000000000000..2318dcba6fbe22b044e3fa286e6a4f3e716808f2 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleAuthor.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Article author" meta tag. + * + * @MetatagTag( + * id = "article_author", + * label = @Translation("Article author"), + * description = @Translation("Links an article to an author's Facebook profile, should be either URLs to the author's profile page or their Facebook profile IDs."), + * name = "article:author", + * group = "open_graph", + * weight = 28, + * type = "label", + * secure = FALSE, + * multiple = TRUE + * ) + */ +class ArticleAuthor extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleExpirationTime.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleExpirationTime.php new file mode 100644 index 0000000000000000000000000000000000000000..bcd22cda036f18f526495e71ddd457a94236e8e6 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleExpirationTime.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Article expiration time" meta tag. + * + * @MetatagTag( + * id = "article_expiration_time", + * label = @Translation("Article expiration date & time"), + * description = @Translation("The date this content will expire, with an optional time value. Needs to be in <a href='http://en.wikipedia.org/wiki/ISO_8601'>ISO 8601</a> format."), + * name = "article:expiration_time", + * group = "open_graph", + * weight = 34, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ArticleExpirationTime extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleModifiedTime.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleModifiedTime.php new file mode 100644 index 0000000000000000000000000000000000000000..92493f954a1590e7db31263d8abf724dae538091 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleModifiedTime.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Article modified time" meta tag. + * + * @MetatagTag( + * id = "article_modified_time", + * label = @Translation("Article modification date & time"), + * description = @Translation("The date this content was last modified, with an optional time value. Needs to be in <a href='http://en.wikipedia.org/wiki/ISO_8601'>ISO 8601</a> format."), + * name = "article:modified_time", + * group = "open_graph", + * weight = 33, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ArticleModifiedTime extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticlePublishedTime.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticlePublishedTime.php new file mode 100644 index 0000000000000000000000000000000000000000..c96cab0b7ae3ffe080f90ab1579b1159e6f6d06c --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticlePublishedTime.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Article published time" meta tag. + * + * @MetatagTag( + * id = "article_published_time", + * label = @Translation("Article publication date & time"), + * description = @Translation("The date this content was published on, with an optional time value. Needs to be in <a href='http://en.wikipedia.org/wiki/ISO_8601'>ISO 8601</a> format."), + * name = "article:published_time", + * group = "open_graph", + * weight = 32, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ArticlePublishedTime extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticlePublisher.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticlePublisher.php new file mode 100644 index 0000000000000000000000000000000000000000..727d856777ceba2eb807f1e73518dd90f26331ac --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticlePublisher.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Article publisher" meta tag. + * + * @MetatagTag( + * id = "article_publisher", + * label = @Translation("Article publisher"), + * description = @Translation("Links an article to a publisher's Facebook page."), + * name = "article:publisher", + * group = "open_graph", + * weight = 29, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ArticlePublisher extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleSection.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleSection.php new file mode 100644 index 0000000000000000000000000000000000000000..627bd3d14aa7c57e0b66505314cf5f3845579087 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleSection.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Article section" meta tag. + * + * @MetatagTag( + * id = "article_section", + * label = @Translation("Article section"), + * description = @Translation("The primary section of this website the content belongs to."), + * name = "article:section", + * group = "open_graph", + * weight = 30, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ArticleSection extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleTag.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleTag.php new file mode 100644 index 0000000000000000000000000000000000000000..699614e5354097cdabbfbf17ac38add8f1be2fb6 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/ArticleTag.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Article tag" meta tag. + * + * @MetatagTag( + * id = "article_tag", + * label = @Translation("Article tag(s)"), + * description = @Translation("Appropriate keywords for this content."), + * name = "article:tag", + * group = "open_graph", + * weight = 31, + * type = "label", + * secure = FALSE, + * multiple = TRUE + * ) + */ +class ArticleTag extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookAuthor.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookAuthor.php new file mode 100644 index 0000000000000000000000000000000000000000..da02560b594eaa41cfb629b000f03ba057602cef --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookAuthor.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Book author" meta tag. + * + * @MetatagTag( + * id = "book_author", + * label = @Translation("Book author"), + * description = @Translation("Links a book to an author's Facebook profile, should be either URLs to the author's profile page or their Facebook profile IDs."), + * name = "book:author", + * group = "open_graph", + * weight = 35, + * type = "label", + * secure = FALSE, + * multiple = TRUE + * ) + */ +class BookAuthor extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookISBN.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookISBN.php new file mode 100644 index 0000000000000000000000000000000000000000..43452583226fea8a3edae4998b036cc81f58a341 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookISBN.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'book:isbn' meta tag. + * + * @MetatagTag( + * id = "book_isbn", + * label = @Translation("ISBN"), + * description = @Translation("The Book's ISBN"), + * name = "book:isbn", + * group = "open_graph", + * weight = 36, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class BookISBN extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookReleaseDate.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookReleaseDate.php new file mode 100644 index 0000000000000000000000000000000000000000..f2ee39db1f9311a1b11c7cab4b716df23de3b320 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookReleaseDate.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'book:release_date' meta tag. + * + * @MetatagTag( + * id = "book_release_date", + * label = @Translation("Release Date"), + * description = @Translation("The date the book was released."), + * name = "book:release_date", + * group = "open_graph", + * weight = 37, + * type = "date", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class BookReleaseDate extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookTag.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookTag.php new file mode 100644 index 0000000000000000000000000000000000000000..0495d299f2d2fe3bd0c365a55943ab2c64a4a971 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/BookTag.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Book tag" meta tag. + * + * @MetatagTag( + * id = "book_tag", + * label = @Translation("Book tag(s)"), + * description = @Translation("Appropriate keywords for this content."), + * name = "book:tag", + * group = "open_graph", + * weight = 38, + * type = "label", + * secure = FALSE, + * multiple = TRUE + * ) + */ +class BookTag extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..de064a0f031deb447d195cf28dd82a77ffda6f0b --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgCountryName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:country_name' meta tag. + * + * @MetatagTag( + * id = "og_country_name", + * label = @Translation("Country name"), + * description = @Translation(""), + * name = "og:country_name", + * group = "open_graph", + * weight = 22, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgCountryName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..8cad733c0c47f1d3983d720af4e11ad9dfaa1243 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDescription.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Description" meta tag. + * + * @MetatagTag( + * id = "og_description", + * label = @Translation("Description"), + * description = @Translation("A one to two sentence description of the content."), + * name = "og:description", + * group = "open_graph", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgDescription extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDeterminer.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDeterminer.php new file mode 100644 index 0000000000000000000000000000000000000000..94b0fe7ddee00b28dbf57ab2fad4be6be997d643 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgDeterminer.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:determiner' meta tag. + * + * @MetatagTag( + * id = "og_determiner", + * label = @Translation("Determiner"), + * description = @Translation("The word that appears before the content's title in a sentence. The default ignores this value, the 'Automatic' value should be sufficient if this is actually needed."), + * name = "og:determiner", + * group = "open_graph", + * weight = 0, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgDeterminer extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..b0d8060cab0a4c61b4479e9b2df9acc936151e0b --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgEmail.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:email' meta tag. + * + * @MetatagTag( + * id = "og_email", + * label = @Translation("Email address"), + * description = @Translation(""), + * name = "og:email", + * group = "open_graph", + * weight = 23, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgEmail extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..42516b2538310ffedf631acb4286e5cdc4f2408a --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgFaxNumber.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:fax_number' meta tag. + * + * @MetatagTag( + * id = "og_fax_number", + * label = @Translation("Fax number"), + * description = @Translation(""), + * name = "og:fax_number", + * group = "open_graph", + * weight = 25, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgFaxNumber extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImage.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImage.php new file mode 100644 index 0000000000000000000000000000000000000000..4402ae5da97cf673b0bcb8f74d315cb78125e75c --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImage.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:image' meta tag. + * + * @MetatagTag( + * id = "og_image", + * label = @Translation("Image"), + * description = @Translation("The URL of an image which should represent the content. The image must be at least 200 x 200 pixels in size; 600 x 316 pixels is a recommended minimum size, and for best results use an image least 1200 x 630 pixels in size. Supports PNG, JPEG and GIF formats. Should not be used if og:image:url is used. Note: if multiple images are added many services (e.g. Facebook) will default to the largest image, not specifically the first one."), + * name = "og:image", + * group = "open_graph", + * weight = 9, + * type = "image", + * secure = FALSE, + * multiple = TRUE, + * absolute_url = TRUE + * ) + */ +class OgImage extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageAlt.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageAlt.php new file mode 100644 index 0000000000000000000000000000000000000000..bc239bd30a2f7f270bd033dd10b49077ff33d1aa --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageAlt.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:image:alt' meta tag. + * + * @MetatagTag( + * id = "og_image_alt", + * label = @Translation("Image 'alt'"), + * description = @Translation("A description of what is in the image, not a caption. If the page specifies an og:image it should specify og:image:alt."), + * name = "og:image:alt", + * group = "open_graph", + * weight = 15, + * type = "string", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = FALSE + * ) + */ +class OgImageAlt extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageHeight.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageHeight.php new file mode 100644 index 0000000000000000000000000000000000000000..6221dc5f69f541cced4630398e9973af6b2c41cb --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageHeight.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:image:height' meta tag. + * + * @MetatagTag( + * id = "og_image_height", + * label = @Translation("Image height"), + * description = @Translation("The height of the above image(s). Note: if both the unsecured and secured images are provided, they should both be the same size."), + * name = "og:image:height", + * group = "open_graph", + * weight = 14, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgImageHeight extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageSecureUrl.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageSecureUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..b0af05e8a8f22dfdee10803246268ef71f9a04d1 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageSecureUrl.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:image:secure_url' meta tag. + * + * @MetatagTag( + * id = "og_image_secure_url", + * label = @Translation("Image Secure URL"), + * description = @Translation("The secure URL (HTTPS) of an image which should represent the content. The image must be at least 50px by 50px and have a maximum aspect ratio of 3:1. Supports PNG, JPEG and GIF formats. All 'http://' URLs will automatically be converted to 'https://'."), + * name = "og:image:secure_url", + * group = "open_graph", + * weight = 11, + * type = "image", + * secure = TRUE, + * multiple = TRUE, + * absolute_url = TRUE + * ) + */ +class OgImageSecureUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageType.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageType.php new file mode 100644 index 0000000000000000000000000000000000000000..ac039318bca278b8bb6506a55113576b3a0ddac4 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageType.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:image:type' meta tag. + * + * @MetatagTag( + * id = "og_image_type", + * label = @Translation("Image type"), + * description = @Translation("The type of image referenced above. Should be either 'image/gif' for a GIF image, 'image/jpeg' for a JPG/JPEG image, or 'image/png' for a PNG image. Note: there should be one value for each image, and having more than there are images may cause problems."), + * name = "og:image:type", + * group = "open_graph", + * weight = 12, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgImageType extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageUrl.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..055d8afad2c2fe70ab1a5eb61ce19e550878a236 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageUrl.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:image:url' meta tag. + * + * @MetatagTag( + * id = "og_image_url", + * label = @Translation("Image URL"), + * description = @Translation("A alternative version of og:image and has exactly the same requirements; only one needs to be used."), + * name = "og:image:url", + * group = "open_graph", + * weight = 10, + * type = "image", + * secure = FALSE, + * multiple = TRUE, + * absolute_url = TRUE + * ) + */ +class OgImageUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageWidth.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageWidth.php new file mode 100644 index 0000000000000000000000000000000000000000..539341bdd14b12d3932c3adb39380ba43c838c50 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgImageWidth.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:image:width' meta tag. + * + * @MetatagTag( + * id = "og_image_width", + * label = @Translation("Image width"), + * description = @Translation("The height of the above image(s). Note: if both the unsecured and secured images are provided, they should both be the same size."), + * name = "og:image:width", + * group = "open_graph", + * weight = 13, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgImageWidth extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..e1db6f070ff287219b70d92f7f29c646514db59c --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLatitude.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:latitude' meta tag. + * + * @MetatagTag( + * id = "og_latitude", + * label = @Translation("Latitude"), + * description = @Translation(""), + * name = "og:latitude", + * group = "open_graph", + * weight = 16, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgLatitude extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocale.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocale.php new file mode 100644 index 0000000000000000000000000000000000000000..9b3905e3cbe40b8fe9990612ba01725b6236a3ce --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocale.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:locale' meta tag. + * + * @MetatagTag( + * id = "og_locale", + * label = @Translation("Locale"), + * description = @Translation("The locale these tags are marked up in, must be in the format language_TERRITORY. Default is 'en_US'."), + * name = "og:locale", + * group = "open_graph", + * weight = 26, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgLocale extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocaleAlternative.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocaleAlternative.php new file mode 100644 index 0000000000000000000000000000000000000000..60270cc6eb12d7c0f37a9025384bbd90558b7843 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocaleAlternative.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:locale:alternate' meta tag. + * + * @MetatagTag( + * id = "og_locale_alternative", + * label = @Translation("Alternative locales"), + * description = @Translation("Other locales this content is available in, must be in the format language_TERRITORY, e.g. 'fr_FR'."), + * name = "og:locale:alternate", + * group = "open_graph", + * weight = 27, + * type = "string", + * secure = FALSE, + * multiple = TRUE + * ) + */ +class OgLocaleAlternative extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..6311367ee2fca00b26f467fadc7c50ad3e4e1eb2 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLocality.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:locality' meta tag. + * + * @MetatagTag( + * id = "og_locality", + * label = @Translation("Locality"), + * description = @Translation(""), + * name = "og:locality", + * group = "open_graph", + * weight = 19, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgLocality extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..a25c59cf40352c9aed2a27b727cfcca5a4eff77f --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgLongitude.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:longitude' meta tag. + * + * @MetatagTag( + * id = "og_longitude", + * label = @Translation("Longitude"), + * description = @Translation(""), + * name = "og:longitude", + * group = "open_graph", + * weight = 16, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgLongitude extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..27f8503c2a3fae804b4f956708f52b1cb9ce55cd --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPhoneNumber.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:phone_number' meta tag. + * + * @MetatagTag( + * id = "og_phone_number", + * label = @Translation("Phone number"), + * description = @Translation(""), + * name = "og:phone_number", + * group = "open_graph", + * weight = 24, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgPhoneNumber extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..3e3f2fe007964cd4f4314d6fb1ac7473be1f1e9c --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgPostalCode.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:postal_code' meta tag. + * + * @MetatagTag( + * id = "og_postal_code", + * label = @Translation("Postal/ZIP code"), + * description = @Translation(""), + * name = "og:postal_code", + * group = "open_graph", + * weight = 21, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgPostalCode extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..7bda64b5bccbcf19dc2bcf839d69f6e02bb322be --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgRegion.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:region' meta tag. + * + * @MetatagTag( + * id = "og_region", + * label = @Translation("Region"), + * description = @Translation(""), + * name = "og:region", + * group = "open_graph", + * weight = 20, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgRegion extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSeeAlso.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSeeAlso.php new file mode 100644 index 0000000000000000000000000000000000000000..235ea1e57dbc8680b62a8da67f296460db7c03e3 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSeeAlso.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:see_also' meta tag. + * + * @MetatagTag( + * id = "og_see_also", + * label = @Translation("See also"), + * description = @Translation("URLs to related content"), + * name = "og:see_also", + * group = "open_graph", + * weight = 16, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgSeeAlso extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..ce1e1fdbd5b3dd9542892c2e434969d92a50284a --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgSiteName.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Site name" meta tag. + * + * @MetatagTag( + * id = "og_site_name", + * label = @Translation("Site name"), + * description = @Translation("A human-readable name for the site, e.g., <em>IMDb</em>."), + * name = "og:site_name", + * group = "open_graph", + * weight = 1, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgSiteName extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..79795a94e8902cb6743af0f479c5ecebff4f4377 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgStreetAddress.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:street_address' meta tag. + * + * @MetatagTag( + * id = "og_street_address", + * label = @Translation("Street address"), + * description = @Translation(""), + * name = "og:street_address", + * group = "open_graph", + * weight = 18, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgStreetAddress extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..8929887bf0d01064ed466fcfbf660b9ca270d6e7 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgTitle.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Title" meta tag. + * + * @MetatagTag( + * id = "og_title", + * label = @Translation("Title"), + * description = @Translation("The title of the content, e.g., <em>The Rock</em>."), + * name = "og:title", + * group = "open_graph", + * weight = 4, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgTitle extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgType.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgType.php new file mode 100644 index 0000000000000000000000000000000000000000..cc2fc11bf4c23bf3019d396250bc05cf5f135c20 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgType.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "Type" meta tag. + * + * @MetatagTag( + * id = "og_type", + * label = @Translation("Content type"), + * description = @Translation("The type of the content, e.g., <em>movie</em>."), + * name = "og:type", + * group = "open_graph", + * weight = 2, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgType extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgUpdatedTime.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgUpdatedTime.php new file mode 100644 index 0000000000000000000000000000000000000000..6dd6e45a7915de2f18e6ad153b718009eb09b3b9 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgUpdatedTime.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:updated_time' meta tag. + * + * @MetatagTag( + * id = "og_updated_time", + * label = @Translation("Content modification date & time"), + * description = @Translation("The date this content was last modified, with an optional time value. Needs to be in <a href='http://en.wikipedia.org/wiki/ISO_8601'>ISO 8601</a> format. Can be the same as the 'Article modification date' tag."), + * name = "og:updated_time", + * group = "open_graph", + * weight = 15, + * type = "date", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgUpdatedTime extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgUrl.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..dd49eedf5d545eb356244b6f8d2557440e6ffc51 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgUrl.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * The Open Graph "URL" meta tag. + * + * @MetatagTag( + * id = "og_url", + * label = @Translation("Page URL"), + * description = @Translation("Preferred page location or URL to help eliminate duplicate content for search engines, e.g., <em>http://www.imdb.com/title/tt0117500/</em>."), + * name = "og:url", + * group = "open_graph", + * weight = 3, + * type = "uri", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class OgUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideo.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideo.php new file mode 100644 index 0000000000000000000000000000000000000000..f688314852b9fd6687f3bc5a830bda46455d5be4 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideo.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:video' meta tag. + * + * @MetatagTag( + * id = "og_video", + * label = @Translation("Video URL"), + * description = @Translation("The URL of an video which should represent the content. For best results use a source that is at least 1200 x 630 pixels in size, but at least 600 x 316 pixels is a recommended minimum. Object types supported include video.episode, video.movie, video.other, and video.tv_show."), + * name = "og:video", + * group = "open_graph", + * weight = 9, + * type = "video", + * secure = FALSE, + * multiple = TRUE, + * absolute_url = TRUE + * ) + */ +class OgVideo extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoHeight.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoHeight.php new file mode 100644 index 0000000000000000000000000000000000000000..d8d0caaca67c3fe24991c2ae397c74ea6837dbed --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoHeight.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:video:height' meta tag. + * + * @MetatagTag( + * id = "og_video_height", + * label = @Translation("Video height"), + * description = @Translation("The height of the above video(s). Note: if both the unsecured and secured videos are provided, they should both be the same size."), + * name = "og:video:height", + * group = "open_graph", + * weight = 14, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgVideoHeight extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoSecureUrl.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoSecureUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..41003ce74e901486250578f96a2b37cdec3c6045 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoSecureUrl.php @@ -0,0 +1,25 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:video:secure_url' meta tag. + * + * @MetatagTag( + * id = "og_video_secure_url", + * label = @Translation("Video Secure URL"), + * description = @Translation("The secure URL (HTTPS) of an video which should represent the content. The video must be at least 50px by 50px and have a maximum aspect ratio of 3:1. Supports PNG, JPEG and GIF formats. All 'http://' URLs will automatically be converted to 'https://'."), + * name = "og:video:secure_url", + * group = "open_graph", + * weight = 11, + * type = "video", + * secure = TRUE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class OgVideoSecureUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoType.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoType.php new file mode 100644 index 0000000000000000000000000000000000000000..10b79382e65a36b549beb5721965aca5af3aaa37 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoType.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:video:type' meta tag. + * + * @MetatagTag( + * id = "og_video_type", + * label = @Translation("Video type"), + * description = @Translation("The type of video referenced above. Should be either video.episode, video.movie, video.other, and video.tv_show. Note: there should be one value for each video, and having more than there are videos may cause problems."), + * name = "og:video:type", + * group = "open_graph", + * weight = 12, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgVideoType extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoWidth.php b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoWidth.php new file mode 100644 index 0000000000000000000000000000000000000000..5ae8a4e87d13904a748995d11a6b4a305801158a --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Plugin/metatag/Tag/OgVideoWidth.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_open_graph\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'og:video:width' meta tag. + * + * @MetatagTag( + * id = "og_video_width", + * label = @Translation("Video width"), + * description = @Translation("The height of the above video(s). Note: if both the unsecured and secured videos are provided, they should both be the same size."), + * name = "og:video:width", + * group = "open_graph", + * weight = 13, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OgVideoWidth extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph/src/Tests/MetatagOpenGraphTagsTest.php b/web/modules/metatag/metatag_open_graph/src/Tests/MetatagOpenGraphTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..af726e8e00d7b077920caf46cf36c33f88b96628 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph/src/Tests/MetatagOpenGraphTagsTest.php @@ -0,0 +1,102 @@ +<?php + +namespace Drupal\metatag_open_graph\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Open Graph tags work correctly. + * + * @group metatag + */ +class MetatagOpenGraphTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'article_author', + 'article_expiration_time', + 'article_modified_time', + 'article_published_time', + 'article_publisher', + 'article_section', + 'article_tag', + 'book_author', + 'book_isbn', + 'book_releasedate', + 'book_tag', + 'og_country_name', + 'og_description', + 'og_determiner', + 'og_email', + 'og_fax_number', + 'og_image', + 'og_image_alt', + 'og_image_height', + 'og_image_secure_url', + 'og_image_type', + 'og_image_url', + 'og_image_width', + 'og_latitude', + 'og_locale', + 'og_locale_alternative', + 'og_locality', + 'og_longitude', + 'og_phone_number', + 'og_postal_code', + 'og_region', + 'og_see_also', + 'og_site_name', + 'og_street_address', + 'og_title', + 'og_type', + 'og_updated_time', + 'og_url', + 'og_video', + 'og_video_height', + 'og_video_secure_url', + 'og_video_type', + 'og_video_width', + ]; + + /** + * {@inheritdoc} + */ + private $testTag = 'meta'; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'property'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_open_graph'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + // Replace the first underline with a colon. + $tag_name = str_replace('og_', 'og:', $tag_name); + $tag_name = str_replace('article_', 'article:', $tag_name); + $tag_name = str_replace('book_', 'book:', $tag_name); + + // Some tags have an additional underline that turns into a colon. + $tag_name = str_replace('og:image_', 'og:image:', $tag_name); + $tag_name = str_replace('og:video_', 'og:video:', $tag_name); + + // Additional fixes. + if ($tag_name == 'og:locale_alternative') { + $tag_name = 'og:locale:alternate'; + } + + return $tag_name; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..68d0e014a78a49c47361693ec306215f673b874a --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/config/schema/metatag_open_graph_products.metatag_tag.schema.yml @@ -0,0 +1,6 @@ +metatag.metatag_tag.og_price_amount: + type: label + label: 'Open Graph Product: Price amount' +metatag.metatag_tag.og_price_currency: + type: label + label: 'Open Graph Product: Price currency' 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 new file mode 100644 index 0000000000000000000000000000000000000000..39090f3ba8fa809ad9d83d4eae69f706864ff451 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.info.yml @@ -0,0 +1,14 @@ +name: 'Metatag: Open Graph Products' +type: module +description: Provides additional Open Graph Protocol meta tags for describing products. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + - metatag:metatag_open_graph + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 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 new file mode 100644 index 0000000000000000000000000000000000000000..e059787b058cc3c562d206dd602d971addabf856 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/metatag_open_graph_products.module @@ -0,0 +1,24 @@ +<?php + +/** + * @file + * Contains metatag_open_graph_products.module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_open_graph_products_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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>'; + return $output; + + default: + } +} diff --git a/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Group/OpenGraphProducts.php b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Group/OpenGraphProducts.php new file mode 100644 index 0000000000000000000000000000000000000000..3a254cb23dba9287dfb65d60ecb541ea51f0ddb2 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Group/OpenGraphProducts.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_open_graph_products\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * Provides a plugin for the 'Open Graph - Products' meta tag group. + * + * @MetatagGroup( + * id = "open_graph_products", + * label = @Translation("Open Graph - Products"), + * description = @Translation("These Open Graph meta tags are for describing products."), + * weight = 0, + * ) + */ +class OpenGraphProducts extends GroupBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductPriceAmount.php b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductPriceAmount.php new file mode 100644 index 0000000000000000000000000000000000000000..0d73285ef1510c8dee2656436047334af5703192 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductPriceAmount.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:price:amount' meta tag. + * + * @MetatagTag( + * id = "product_price_amount", + * label = @Translation("Product price amount"), + * description = @Translation("The price amount of the product."), + * name = "product:price:amount", + * group = "open_graph_products", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ProductPriceAmount 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/ProductPriceCurrency.php b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductPriceCurrency.php new file mode 100644 index 0000000000000000000000000000000000000000..74536ae7fc04dee5bee759b616e46b34b9360d5c --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/src/Plugin/metatag/Tag/ProductPriceCurrency.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:price:currency' meta tag. + * + * @MetatagTag( + * id = "product_price_currency", + * label = @Translation("Product price currency"), + * description = @Translation("The price currency of the product."), + * name = "product:price:currency", + * group = "open_graph_products", + * weight = 2, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ProductPriceCurrency extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_open_graph_products/src/Tests/MetatagOpenGraphProductsTagsTest.php b/web/modules/metatag/metatag_open_graph_products/src/Tests/MetatagOpenGraphProductsTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3af3a2ac611e84b2317c2c185d575951ce48b216 --- /dev/null +++ b/web/modules/metatag/metatag_open_graph_products/src/Tests/MetatagOpenGraphProductsTagsTest.php @@ -0,0 +1,50 @@ +<?php + +namespace Drupal\metatag_open_graph_products\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Open Graph Product tags work correctly. + * + * @group metatag + */ +class MetatagOpenGraphProductsTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'product_price_amount', + 'product_price_currency', + ]; + + /** + * {@inheritdoc} + */ + private $testTag = 'meta'; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'property'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_open_graph_products'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + // Replace the underlines with a colon. + $tag_name = str_replace('_', ':', $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 new file mode 100644 index 0000000000000000000000000000000000000000..c25fa9338cc1f01610ba9cb485739d4d08802650 --- /dev/null +++ b/web/modules/metatag/metatag_page_manager/metatag_page_manager.info.yml @@ -0,0 +1,14 @@ +name: Metatag Page Manager +type: module +description: Provides metatag support for Page Manager variants. +# core: 8.x +package: SEO +dependencies: + - page_manager:page_manager + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_page_manager/metatag_page_manager.module b/web/modules/metatag/metatag_page_manager/metatag_page_manager.module new file mode 100644 index 0000000000000000000000000000000000000000..68e0a5ba85e66ead3d8aa893aeeb831246340900 --- /dev/null +++ b/web/modules/metatag/metatag_page_manager/metatag_page_manager.module @@ -0,0 +1,106 @@ +<?php + +/** + * @file + * Contains metatag_page_manager.module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Form\FormStateInterface; +use Drupal\page_manager\Entity\PageVariant; +use Drupal\metatag\Entity\MetatagDefaults; + +/** + * Implements hook_form_FORM_ID_alter(). + */ +function metatag_page_manager_form_metatag_defaults_add_form_alter(&$form, FormStateInterface $form_state, $form_id) { + $variants_options['Page Variants'] = _metatag_page_manager_get_variants(); + $form['id']['#options'] = array_merge($form['id']['#options'], $variants_options); +} + +/** + * Implements hook_page_attachments(). + */ +function metatag_page_manager_page_attachments(array &$attachments) { + // Fetch entity from request. + $entity = \Drupal::request()->attributes->get('_entity'); + if ($entity) { + + $key = $entity->getEntityType()->id() . '__' . $entity->id(); + // Get default metatags. + $metatag_defaults = metatag_get_default_tags(); + // Load page variant metatags. + $metatag_variant = MetatagDefaults::load($key); + if ($metatag_variant) { + // Overwrite the metatag defaults with the tags of the page variant. + $metatag_defaults = array_merge($metatag_defaults, $metatag_variant->get('tags')); + + // Set the metatag in the static metatag attachments parameter so the + // metatag module wouldn't overwrite them. + $metatag_attachments = &drupal_static('metatag_attachments'); + + $metatag_manager = \Drupal::service('metatag.manager'); + $metatag_attachments = $metatag_manager->generateElements($metatag_defaults, $entity); + + // If any Metatag items were found, append them. + if (!empty($metatag_attachments['#attached']['html_head'])) { + if (empty($attachments['#attached'])) { + $attachments['#attached'] = []; + } + if (empty($attachments['#attached']['html_head'])) { + $attachments['#attached']['html_head'] = []; + } + foreach ($metatag_attachments['#attached']['html_head'] as $item) { + $attachments['#attached']['html_head'][] = $item; + } + } + } + } +} + +/** + * Returns all available page variants. + * + * @return string[] + * A list of page variants keyed by label. + */ +function _metatag_page_manager_get_variants() { + /** @var \Drupal\page_manager\Entity\PageVariant[] $variants */ + $variants = PageVariant::loadMultiple(); + $variant_options = []; + // Load all metatag defaults so we can filter the variants which already have + // a metatag default configured. + $metatag_defaults = MetatagDefaults::loadMultiple(); + foreach ($variants as $key => $variant) { + $id = $variant->getEntityType()->id() . '__' . $key; + if (!isset($metatag_defaults[$id])) { + $label = $variant->getPage()->label() . ' : ' . $variant->label(); + $variant_options[$id] = $label; + } + } + return $variant_options; +} + +/** + * Implements hook_metatag_alter(). + */ +function metatag_page_manager_metatags_alter(array &$metatags, array &$context) { + if (!$context['entity'] instanceof PageVariant) { + return; + } + + $key = $context['entity']->getEntityType()->id() . '__' . $context['entity']->id(); + $metatag_variant = MetatagDefaults::load($key); + if ($metatag_variant) { + $metatags = array_merge($metatags, $metatag_variant->get('tags')); + } +} + +/** + * Implements hook_metatag_route_entity(). + */ +function metatag_page_manager_metatag_route_entity(RouteMatchInterface $route_match) { + if ($variant = $route_match->getParameter('page_manager_page_variant')) { + return $variant; + } +} diff --git a/web/modules/metatag/metatag_page_manager/src/Tests/Functional/MetatagPageManagerTest.php b/web/modules/metatag/metatag_page_manager/src/Tests/Functional/MetatagPageManagerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..14c228966a48cd45c7150fbec88fa245a471cc5d --- /dev/null +++ b/web/modules/metatag/metatag_page_manager/src/Tests/Functional/MetatagPageManagerTest.php @@ -0,0 +1,177 @@ +<?php + +namespace Drupal\metatag_page_manager\Tests\Functional; + +use Drupal\page_manager\Entity\Page; +use Drupal\page_manager\Entity\PageVariant; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\metatag\Functional\MetatagHelperTrait; + +/** + * Confirm the Page Manager integration works. + * + * @group metatag + */ +class MetatagPageManagerTest extends BrowserTestBase { + + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + // This module. + 'metatag_page_manager', + ]; + + /** + * The assert session object. + * + * @var \Drupal\Tests\WebAssert + */ + public $assertSession; + + /** + * {@inheritdoc} + */ + public function setUp() { + // TODO: Change the autogenerated stub. + parent::setUp(); + + $this->assertSession = $this->assertSession(); + + Page::create([ + 'id' => 'metatag_page_manager_test', + 'label' => 'Metatag Page', + 'path' => '/metatag-test', + ])->save(); + PageVariant::create([ + 'id' => 'metatag_page_manager_variant_test', + 'variant' => 'block_display', + 'label' => 'Metatag Variant', + 'page' => 'metatag_page_manager_test', + 'weight' => 10, + ])->save(); + + \Drupal::service("router.builder")->rebuild(); + + // Log in as user 1. + $this->loginUser1(); + } + + /** + * Tests a single variant page. + */ + public function testSingleVariantPage() { + $this->drupalGet('/metatag-test'); + $this->assertSession->statusCodeEquals(200); + + // Confirm what the page title looks like by default. + $this->assertSession->titleEquals('Metatag Page | Drupal'); + + // Create the Metatag object through the UI to check the custom label. + $edit = [ + 'id' => 'page_variant__metatag_page_manager_variant_test', + 'title' => 'My title', + ]; + + $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + $this->assertSession->pageTextContains('Page Variant: Metatag Page: Metatag Variant'); + + // Clear caches to load the right metatags. + drupal_flush_all_caches(); + + $this->drupalGet('/metatag-test'); + $this->assertSession->statusCodeEquals(200); + + // Confirm what the page title is overridden. + $this->assertSession->titleEquals('My title'); + } + + /** + * Tests a single variant page. + */ + public function testMultipleVariantPage() { + // Add a new variant. + $new_variant = PageVariant::create([ + 'id' => 'metatag_page_manager_multiple_variant_test', + 'variant' => 'block_display', + 'label' => 'Metatag Multiple Variant', + 'page' => 'metatag_page_manager_test', + 'weight' => 0, + ]); + $anonymous_selection = [ + 'id' => 'user_role', + 'roles' => [ + 'anonymous' => 'anonymous', + ], + 'negate' => FALSE, + 'context_mapping' => [ + 'user' => 'current_user', + ], + ]; + $new_variant->set('selection_criteria', [$anonymous_selection]); + $new_variant->save(); + + // Clear caches to load the right metatags. + drupal_flush_all_caches(); + + $this->drupalGet('/metatag-test'); + $this->assertSession->statusCodeEquals(200); + + // Confirm what the page title looks like by default. + $this->assertSession->titleEquals('Metatag Page | Drupal'); + + // Create the Metatag object through the UI to check the custom label. + $edit = [ + 'id' => 'page_variant__metatag_page_manager_variant_test', + 'title' => 'My title', + ]; + + $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + $this->assertSession->pageTextContains('Page Variant: Metatag Page: Metatag Variant'); + + // Clear caches to load the right metatags. + drupal_flush_all_caches(); + + $this->drupalGet('/metatag-test'); + $this->assertSession->statusCodeEquals(200); + + // Confirm what the page title is overridden. + $this->assertSession->titleEquals('My title'); + + // Visiting page as anon user, should get the default title. + $this->drupalLogout(); + $this->drupalGet('/metatag-test'); + $this->assertSession->statusCodeEquals(200); + + // Confirm what the page title looks like by default. + $this->assertSession->titleEquals('Metatag Page | Drupal'); + + // Login and add custom metatag for anonymous user variant. + $this->loginUser1(); + // Create the Metatag object through the UI to check the custom label. + $edit = [ + 'id' => 'page_variant__metatag_page_manager_multiple_variant_test', + 'title' => 'My title anonymous', + ]; + + $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + $this->assertSession->pageTextContains('Page Variant: Metatag Page: Metatag Multiple Variant'); + + // Clear caches to load the right metatags. + drupal_flush_all_caches(); + + // Visit page as logged in user and confirm the right title. + $this->drupalGet('/metatag-test'); + $this->assertSession->statusCodeEquals(200); + $this->assertSession->titleEquals('My title'); + + // Visit page as anonymous user and confirm the right title. + $this->drupalLogout(); + $this->drupalGet('/metatag-test'); + $this->assertSession->statusCodeEquals(200); + $this->assertSession->titleEquals('My title anonymous'); + } + +} diff --git a/web/modules/metatag/metatag_pinterest/config/schema/metatag_pinterest.metatag_tag.schema.yml b/web/modules/metatag/metatag_pinterest/config/schema/metatag_pinterest.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..979e744dfd247ef8a5039d9c61c0ca2978eaab97 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/config/schema/metatag_pinterest.metatag_tag.schema.yml @@ -0,0 +1,25 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.pinterest_description: + type: text + label: 'Pinterest: Description' +metatag.metatag_tag.pinterest_id: + type: label + label: 'Pinterest: ID' +metatag.metatag_tag.pinterest_media: + type: label + label: 'Pinterest: Media' +metatag.metatag_tag.pinterest_nohover: + type: label + label: 'Pinterest: No hover' +metatag.metatag_tag.pinterest_nopin: + type: label + label: 'Pinterest: No pin' +metatag.metatag_tag.pinterest_nosearch: + type: label + label: 'Pinterest: No search' +metatag.metatag_tag.pinterest_url: + type: label + label: 'Pinterest: URL' diff --git a/web/modules/metatag/metatag_pinterest/metatag_pinterest.info.yml b/web/modules/metatag/metatag_pinterest/metatag_pinterest.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..8364186799678976aec1a1a5cd14cfea94e762e4 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/metatag_pinterest.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Pinterest' +type: module +description: Provides support for Pinterest's custom meta tags. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Group/Pinterest.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Group/Pinterest.php new file mode 100644 index 0000000000000000000000000000000000000000..975f5c3dd288a74f1213af2bdd023f148222ce55 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Group/Pinterest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * The Pinterest group. + * + * @MetatagGroup( + * id = "pinterest", + * label = @Translation("Pinterest"), + * description = @Translation("A set of meta tags used to control how the site's content is consumed by <a href='https://pinterest.com/'>Pinterest</a>."), + * weight = 4 + * ) + */ +class Pinterest extends GroupBase { + // Inherits everything from Base. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..bd3fe2e6c28a0f34e1d2ed9cd6bda3c971047885 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestDescription.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'pin:description' meta tag. + * + * @MetatagTag( + * id = "pinterest_description", + * label = @Translation("Description"), + * description = @Translation("A one to two sentence description of the content."), + * name = "pin:description", + * group = "pinterest", + * weight = 8, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class PinterestDescription extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestId.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestId.php new file mode 100644 index 0000000000000000000000000000000000000000..346a197a2eec956c6372243ee9d64963748006b2 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestId.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'pin:id' meta tag. + * + * @MetatagTag( + * id = "pinterest_id", + * label = @Translation("Id"), + * description = @Translation("The Canonical Pinterest object to pin."), + * name = "pin:id", + * group = "pinterest", + * weight = 5, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class PinterestId extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestMedia.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestMedia.php new file mode 100644 index 0000000000000000000000000000000000000000..c59e04292a462330454fc95dbc81dbe3c1cf5d10 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestMedia.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'pin:media' meta tag. + * + * @MetatagTag( + * id = "pinterest_media", + * label = @Translation("Media"), + * description = @Translation("The URL of media which should represent the content."), + * name = "pin:media", + * group = "pinterest", + * weight = 6, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class PinterestMedia extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..f725e441aadc84279cec48c418841d2913836c74 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNohover.php @@ -0,0 +1,41 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Pinterest "nohover" meta tag. + * + * @MetatagTag( + * id = "pinterest_nohover", + * label = @Translation("No hover"), + * description = @Translation("Do not show hovering Save or Search buttons, generated by the Pinterest browser extensions."), + * name = "pinterest", + * group = "pinterest", + * weight = 2, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class PinterestNohover extends MetaNameBase { + + /** + * {@inheritdoc} + */ + public function form(array $element = []) { + $form = [ + '#type' => 'checkbox', + '#title' => $this->label(), + '#description' => $this->description(), + '#default_value' => ($this->value === 'nohover') ?: '', + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#element_validate' => [[get_class($this), 'validateTag']], + '#return_value' => 'nohover', + ]; + + return $form; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5e0265340613ec2f2947e649c87f0b4438317d48 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNopin.php @@ -0,0 +1,41 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Pinterest "nopin" meta tag. + * + * @MetatagTag( + * id = "pinterest_nopin", + * label = @Translation("No pin"), + * description = @Translation("Do not pin anything from this page. When selected, this option will take precedence over all options below."), + * name = "pinterest", + * group = "pinterest", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class PinterestNopin extends MetaNameBase { + + /** + * {@inheritdoc} + */ + public function form(array $element = []) { + $form = [ + '#type' => 'checkbox', + '#title' => $this->label(), + '#description' => $this->description(), + '#default_value' => ($this->value === 'nopin') ?: '', + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#element_validate' => [[get_class($this), 'validateTag']], + '#return_value' => 'nopin', + ]; + + return $form; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..9c0c9437ba6dfdc8c346bfe04c15f2f41b87d15a --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestNosearch.php @@ -0,0 +1,41 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Pinterest "nosearch" meta tag. + * + * @MetatagTag( + * id = "pinterest_nosearch", + * label = @Translation("No search"), + * description = @Translation("Do not allow Pinterest visual search to happen from this page."), + * name = "pinterest", + * group = "pinterest", + * weight = 3, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class PinterestNosearch extends MetaNameBase { + + /** + * {@inheritdoc} + */ + public function form(array $element = []) { + $form = [ + '#type' => 'checkbox', + '#title' => $this->label(), + '#description' => $this->description(), + '#default_value' => ($this->value === 'nosearch') ?: '', + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#element_validate' => [[get_class($this), 'validateTag']], + '#return_value' => 'nosearch', + ]; + + return $form; + } + +} diff --git a/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestUrl.php b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..1ca92be5dd1306ede4f2f7d69f2082b4e61a19e8 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Plugin/metatag/Tag/PinterestUrl.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_pinterest\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaPropertyBase; + +/** + * Provides a plugin for the 'pin:url' meta tag. + * + * @MetatagTag( + * id = "pinterest_url", + * label = @Translation("URL"), + * description = @Translation("The URL which should represent the content."), + * name = "pin:url", + * group = "pinterest", + * weight = 7, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class PinterestUrl extends MetaPropertyBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_pinterest/src/Tests/MetatagPinterestTagsTest.php b/web/modules/metatag/metatag_pinterest/src/Tests/MetatagPinterestTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..06d5cbe6db1a18054e664730e78886ea960ae9d1 --- /dev/null +++ b/web/modules/metatag/metatag_pinterest/src/Tests/MetatagPinterestTagsTest.php @@ -0,0 +1,81 @@ +<?php + +namespace Drupal\metatag_pinterest\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Pinterest tags work correctly. + * + * @group metatag + */ +class MetatagPinterestTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'pinterest_description', + 'pinterest_id', + 'pinterest_media', + 'pinterest_nopin', + 'pinterest_nohover', + 'pinterest_nosearch', + 'pinterest_url', + ]; + + /** + * {@inheritdoc} + */ + private $testTag = 'meta'; + + /** + * {@inheritdoc} + */ + private $testNameAttribute = 'property'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_pinterest'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + if ($tag_name == ('pinterest_nopin' || 'pinterest_nohover' || 'pinterest_nosearch')) { + $tag_name = 'pinterest'; + } + else { + // Replace "pinterest_" with "pin:". + $tag_name = str_replace('pinterest_', 'pin:', $tag_name); + } + + return $tag_name; + } + + /** + * Implements {tag_name}TestFieldXpath() for 'pinterest'. + */ + private function pinterestTestFieldXpath() { + return "//input[@name='pinterest[index]' and @type='checkbox']"; + } + + /** + * Implements {tag_name}TestKey() for 'pinterest'. + */ + private function pinterestTestKey() { + return 'pinterest[index]'; + } + + /** + * Implements {tag_name}TestValue() for 'pinterest'. + */ + private function pinterestTestValue() { + return TRUE; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..78ce79f2fa8583daa881cedad274d3db29c169bd --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/config/schema/metatag_twitter_cards.metatag_tag.schema.yml @@ -0,0 +1,112 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.twitter_cards_app_id_googleplay: + type: label + label: 'Twitter Cards: Google Play app ID' +metatag.metatag_tag.twitter_cards_app_id_ipad: + type: label + label: 'Twitter Cards: iPad app ID' +metatag.metatag_tag.twitter_cards_app_id_iphone: + type: label + label: 'Twitter Cards: iPhone app ID' +metatag.metatag_tag.twitter_cards_app_name_googleplay: + type: label + label: 'Twitter Cards: Google Play app name' +metatag.metatag_tag.twitter_cards_app_name_ipad: + type: label + label: 'Twitter Cards: iPad app name' +metatag.metatag_tag.twitter_cards_app_name_iphone: + type: label + label: 'Twitter Cards: iPhone app name' +metatag.metatag_tag.twitter_cards_app_store_country: + type: label + label: 'Twitter Cards: App store country' +metatag.metatag_tag.twitter_cards_app_url_googleplay: + type: label + label: 'Twitter Cards: Google Play app URL schema' +metatag.metatag_tag.twitter_cards_app_url_ipad: + type: label + label: 'Twitter Cards: iPad app URL schema' +metatag.metatag_tag.twitter_cards_app_url_iphone: + type: label + label: 'Twitter Cards: iPhone app URL schema' +metatag.metatag_tag.twitter_cards_creator: + type: label + label: "Twitter Cards: Creator's Twitter account" +metatag.metatag_tag.twitter_cards_creator_id: + type: label + label: "Twitter Cards: Creator's Twitter account ID" +metatag.metatag_tag.twitter_cards_data1: + type: label + label: 'Twitter Cards: Data 1' +metatag.metatag_tag.twitter_cards_data2: + type: label + label: 'Twitter Cards: Data 2' +metatag.metatag_tag.twitter_cards_description: + type: text + label: 'Twitter Cards: Description' +metatag.metatag_tag.twitter_cards_donottrack: + type: label + label: 'Twitter Cards: Do Not Track' +metatag.metatag_tag.twitter_cards_gallery_image0: + type: label + label: 'Twitter Cards: 1st gallery image' +metatag.metatag_tag.twitter_cards_gallery_image1: + type: label + label: 'Twitter Cards: 2nd gallery image' +metatag.metatag_tag.twitter_cards_gallery_image2: + type: label + label: 'Twitter Cards: 3rd gallery image' +metatag.metatag_tag.twitter_cards_gallery_image3: + type: label + label: 'Twitter Cards: 4th gallery image' +metatag.metatag_tag.twitter_cards_image: + type: label + label: 'Twitter Cards: Image URL' +metatag.metatag_tag.twitter_cards_image_height: + type: label + label: 'Twitter Cards: Image height' +metatag.metatag_tag.twitter_cards_image_width: + type: label + label: 'Twitter Cards: Image width' +metatag.metatag_tag.twitter_cards_image_alt: + type: label + label: 'Twitter Cards: Image alternative text' +metatag.metatag_tag.twitter_cards_label1: + type: label + label: 'Twitter Cards: Label 1' +metatag.metatag_tag.twitter_cards_label2: + type: label + label: 'Twitter Cards: Label 2' +metatag.metatag_tag.twitter_cards_page_url: + type: label + label: 'Twitter Cards: Page URL' +metatag.metatag_tag.twitter_cards_player: + type: label + label: 'Twitter Cards: Media player URL' +metatag.metatag_tag.twitter_cards_player_height: + type: label + label: 'Twitter Cards: Media player height' +metatag.metatag_tag.twitter_cards_player_stream: + type: label + label: 'Twitter Cards: MP4 media stream URL' +metatag.metatag_tag.twitter_cards_player_stream_content_type: + type: label + label: 'Twitter Cards: MP4 media straem MIME-type' +metatag.metatag_tag.twitter_cards_player_width: + type: label + label: 'Twitter Cards: Media player width' +metatag.metatag_tag.twitter_cards_site: + type: label + label: "Twitter Cards: Site's Twitter account" +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 + label: 'Twitter Cards: Title' +metatag.metatag_tag.twitter_cards_type: + type: label + label: 'Twitter Cards: Type' 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 new file mode 100644 index 0000000000000000000000000000000000000000..122e885cad39386076ad6b46dae69d2fdcae41a5 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/metatag_twitter_cards.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Twitter Cards' +type: module +description: Provides support for Twitter's Card meta tags. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Group/TwitterCards.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Group/TwitterCards.php new file mode 100644 index 0000000000000000000000000000000000000000..05c064841600dbab87e9814f270ca2a756221d63 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Group/TwitterCards.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * The TwitterCards group. + * + * @MetatagGroup( + * id = "twitter_cards", + * label = @Translation("Twitter Cards"), + * description = @Translation("A set of meta tags specially for controlling the summaries displayed when content is shared on <a href='https://twitter.com/'>Twitter</a>."), + * weight = 4 + * ) + */ +class TwitterCards extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdGooglePlay.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdGooglePlay.php new file mode 100644 index 0000000000000000000000000000000000000000..2bb98f487bb0a6dec70d81ab59dc7ce78510e899 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdGooglePlay.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app id for Google Play metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_id_googleplay", + * label = @Translation("Google Play app ID"), + * description = @Translation("Your app ID in the Google Play Store (i.e. ""com.android.app"")."), + * name = "twitter:app:id:googleplay", + * group = "twitter_cards", + * weight = 307, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppIdGooglePlay extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdIpad.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdIpad.php new file mode 100644 index 0000000000000000000000000000000000000000..fe03147b23438ebffb279ca1f87e26c6f942b31b --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdIpad.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app id for ipad metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_id_ipad", + * label = @Translation("iPad app ID"), + * description = @Translation("String value, should be the numeric representation of your iPad app's ID in the App Store."), + * name = "twitter:app:id:ipad", + * group = "twitter_cards", + * weight = 304, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppIdIpad extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdIphone.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdIphone.php new file mode 100644 index 0000000000000000000000000000000000000000..bb837ad08873af23fc18c3373a1351e732ae1470 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppIdIphone.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app id for iphone metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_id_iphone", + * label = @Translation("iPhone app ID"), + * description = @Translation("String value, should be the numeric representation of your iPhone app's ID in the App Store."), + * name = "twitter:app:id:iphone", + * group = "twitter_cards", + * weight = 302, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppIdIphone extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameGooglePlay.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameGooglePlay.php new file mode 100644 index 0000000000000000000000000000000000000000..91dd63ff25d5f306d2e9e9acfb4a17266af35868 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameGooglePlay.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app name Google Play metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_name_googleplay", + * label = @Translation("Google Play app name"), + * description = @Translation("The name of the app in the Google Play app store."), + * name = "twitter:app:name:googleplay", + * group = "twitter_cards", + * weight = 306, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppNameGooglePlay extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameIpad.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameIpad.php new file mode 100644 index 0000000000000000000000000000000000000000..a16922e0dbadccba45ce5cc596d4797d7ead901d --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameIpad.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app name for ipad metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_name_ipad", + * label = @Translation("iPad app name"), + * description = @Translation("The name of the iPad app."), + * name = "twitter:app:name:ipad", + * group = "twitter_cards", + * weight = 303, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppNameIpad extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameIphone.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameIphone.php new file mode 100644 index 0000000000000000000000000000000000000000..e95fc0e4928d5c798d00971a10d113f803abfb67 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppNameIphone.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app name for iphone metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_name_iphone", + * label = @Translation("iPhone app name"), + * description = @Translation("The name of the iPhone app."), + * name = "twitter:app:name:iphone", + * group = "twitter_cards", + * weight = 301, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppNameIphone extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppStoreCountry.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppStoreCountry.php new file mode 100644 index 0000000000000000000000000000000000000000..daa8db184bb7df42ca5c0f2c9e42d12c3d0b47bf --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppStoreCountry.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app store country code metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_store_country", + * label = @Translation("App store country"), + * description = @Translation("If your application is not available in the US App Store, you must set this value to the two-letter country code for the App Store that contains your application."), + * name = "twitter:app:country", + * group = "twitter_cards", + * weight = 300, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppStoreCountry extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlGooglePlay.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlGooglePlay.php new file mode 100644 index 0000000000000000000000000000000000000000..eee31215550d7673906110dab70844fb880f0778 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlGooglePlay.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app's custom URL scheme for Google Play metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_url_googleplay", + * label = @Translation("Google Play app's custom URL scheme"), + * description = @Translation("The Google Play app's custom URL scheme (must include ""://"" after the scheme name)."), + * name = "twitter:app:url:googleplay", + * group = "twitter_cards", + * weight = 308, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppUrlGooglePlay extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlIpad.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlIpad.php new file mode 100644 index 0000000000000000000000000000000000000000..784d6fd65082139be89eca7b739882b5d4cde328 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlIpad.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app's custom URL scheme for ipad metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_url_ipad", + * label = @Translation("iPad app's custom URL scheme"), + * description = @Translation("The iPad app's custom URL scheme (must include ""://"" after the scheme name)."), + * name = "twitter:app:url:ipad", + * group = "twitter_cards", + * weight = 305, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppUrlIpad extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlIphone.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlIphone.php new file mode 100644 index 0000000000000000000000000000000000000000..ad1987e9550f3468d5773dea81925fcbb7e9ad9e --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsAppUrlIphone.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards app's custom URL scheme for iphone metatag. + * + * @MetatagTag( + * id = "twitter_cards_app_url_iphone", + * label = @Translation("iPhone app's custom URL scheme"), + * description = @Translation("The iPhone app's custom URL scheme (must include ""://"" after the scheme name)."), + * name = "twitter:app:url:iphone", + * group = "twitter_cards", + * weight = 302, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsAppUrlIphone extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsCreator.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsCreator.php new file mode 100644 index 0000000000000000000000000000000000000000..597af1345ae13f6b63b208dccf2c031f71c560b1 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsCreator.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards creator meta tag. + * + * @MetatagTag( + * id = "twitter_cards_creator", + * label = @Translation("Creator's Twitter account"), + * description = @Translation("The @username for the content creator / author for this page, including the @ symbol."), + * name = "twitter:creator", + * group = "twitter_cards", + * weight = 4, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsCreator extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsCreatorId.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsCreatorId.php new file mode 100644 index 0000000000000000000000000000000000000000..28ec9a97880bbe00f2de641873f6f6c0560482c0 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsCreatorId.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards creator id metatag. + * + * @MetatagTag( + * id = "twitter_cards_creator_id", + * label = @Translation("Creator's Twitter account ID"), + * description = @Translation("The numerical Twitter account ID for the content creator / author for this page."), + * name = "twitter:creator:id", + * group = "twitter_cards", + * weight = 4, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsCreatorId extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsData1.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsData1.php new file mode 100644 index 0000000000000000000000000000000000000000..af57e20aef37ab7140f89e984b38fc8f3762bc61 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsData1.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'twitter:data1' meta tag. + * + * @MetatagTag( + * id = "twitter_cards_data1", + * label = @Translation("Data 1"), + * description = @Translation("This field expects a string, and allows you to specify the types of data you want to offer (price, country, etc.)."), + * name = "twitter:data1", + * group = "twitter_cards", + * weight = 501, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsData1 extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsData2.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsData2.php new file mode 100644 index 0000000000000000000000000000000000000000..ff3ff65717d54f3b4b93eae2ce33317271874a1b --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsData2.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'twitter:data2' meta tag. + * + * @MetatagTag( + * id = "twitter_cards_data2", + * label = @Translation("Data 2"), + * description = @Translation("This field expects a string, and allows you to specify the types of data you want to offer (price, country, etc.)."), + * name = "twitter:data2", + * group = "twitter_cards", + * weight = 503, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsData2 extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..eb3cdbb4bc75aa6698ef1d88cdcb9cbf3721702f --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDescription.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards site's description. + * + * @MetatagTag( + * id = "twitter_cards_description", + * label = @Translation("Description"), + * description = @Translation("A description that concisely summarizes the content of the page, as appropriate for presentation within a Tweet. Do not re-use the title text as the description, or use this field to describe the general services provided by the website. The string will be truncated, by Twitter, at the word to 200 characters."), + * name = "twitter:description", + * group = "twitter_cards", + * weight = 2, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsDescription extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDoNotTrack.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDoNotTrack.php new file mode 100644 index 0000000000000000000000000000000000000000..1d30b0d031e2c100873340d2fa4425521e7a98d9 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsDoNotTrack.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards DNT option. + * + * @MetatagTag( + * id = "twitter_cards_donottrack", + * label = @Translation("Do Not Track"), + * description = @Translation("By default Twitter tracks visitors when a tweet is embedded on a page using the official APIs. Setting this to 'on' will <a href=':url'>stop Twitter from tracking visitors</a>.", arguments = { ":url" = "https://dev.twitter.com/web/overview/privacy#what-privacy-options-do-website-publishers-have" }), + * name = "twitter:dnt", + * group = "twitter_cards", + * weight = 5, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsDoNotTrack extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage0.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage0.php new file mode 100644 index 0000000000000000000000000000000000000000..d0545cdebedcde99ad2226f8ce894d978be674f9 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage0.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards gallery image0 metatag. + * + * @MetatagTag( + * id = "twitter_cards_gallery_image0", + * label = @Translation("1st gallery image"), + * description = @Translation("A URL to the image representing the first photo in your gallery. This will be able to extract the URL from an image field."), + * name = "twitter:gallery:image0", + * group = "twitter_cards", + * weight = 200, + * type = "image", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class TwitterCardsGalleryImage0 extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage1.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage1.php new file mode 100644 index 0000000000000000000000000000000000000000..8de3792ed22cd8d6d6c310d81baedf376b02a73e --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage1.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards gallery image1 metatag. + * + * @MetatagTag( + * id = "twitter_cards_gallery_image1", + * label = @Translation("2nd gallery image"), + * description = @Translation("A URL to the image representing the second photo in your gallery. This will be able to extract the URL from an image field."), + * name = "twitter:gallery:image1", + * group = "twitter_cards", + * weight = 201, + * type = "image", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class TwitterCardsGalleryImage1 extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage2.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage2.php new file mode 100644 index 0000000000000000000000000000000000000000..75816ba2f41fd5044c45cca6b50d33b2b457e7bc --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage2.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards gallery image2 metatag. + * + * @MetatagTag( + * id = "twitter_cards_gallery_image2", + * label = @Translation("3rd gallery image"), + * description = @Translation("A URL to the image representing the third photo in your gallery. This will be able to extract the URL from an image field."), + * name = "twitter:gallery:image2", + * group = "twitter_cards", + * weight = 202, + * type = "image", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class TwitterCardsGalleryImage2 extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage3.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage3.php new file mode 100644 index 0000000000000000000000000000000000000000..1c991b88bea85df914ea6e5ca742888632c1814b --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsGalleryImage3.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards gallery image3 metatag. + * + * @MetatagTag( + * id = "twitter_cards_gallery_image3", + * label = @Translation("4th gallery image"), + * description = @Translation("A URL to the image representing the fourth photo in your gallery. This will be able to extract the URL from an image field."), + * name = "twitter:gallery:image3", + * group = "twitter_cards", + * weight = 203, + * type = "image", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class TwitterCardsGalleryImage3 extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImage.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImage.php new file mode 100644 index 0000000000000000000000000000000000000000..4fa71b7034c5bca89ef8ee9ce136572008c17ab4 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImage.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards image metatag. + * + * @MetatagTag( + * id = "twitter_cards_image", + * label = @Translation("Image URL"), + * description = @Translation("The URL to a unique image representing the content of the page. Do not use a generic image such as your website logo, author photo, or other image that spans multiple pages. Images larger than 120x120px will be resized and cropped square based on longest dimension. Images smaller than 60x60px will not be shown. If the 'type' is set to Photo then the image must be at least 280x150px. This will be able to extract the URL from an image field."), + * name = "twitter:image", + * group = "twitter_cards", + * weight = 7, + * type = "image", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class TwitterCardsImage extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageAlt.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageAlt.php new file mode 100644 index 0000000000000000000000000000000000000000..47bb0b2456b35f409f689552e2625979e66fdd68 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageAlt.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards image alternative text metatag. + * + * @MetatagTag( + * id = "twitter_cards_image_alt", + * label = @Translation("Image alternative text"), + * description = @Translation("The alternative text of the image being linked to. Limited to 420 characters."), + * name = "twitter:image:alt", + * group = "twitter_cards", + * weight = 7, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsImageAlt extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageHeight.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageHeight.php new file mode 100644 index 0000000000000000000000000000000000000000..a89a36a1e51611a748db9775085baa2a34580536 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageHeight.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards image height metatag. + * + * @MetatagTag( + * id = "twitter_cards_image_height", + * label = @Translation("Image height"), + * description = @Translation("The height of the image being linked to, in pixels."), + * name = "twitter:image:height", + * group = "twitter_cards", + * weight = 7, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsImageHeight extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageWidth.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageWidth.php new file mode 100644 index 0000000000000000000000000000000000000000..5840f7f72412dcc92069a3ded2848c9d0e66e814 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsImageWidth.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards image width metatag. + * + * @MetatagTag( + * id = "twitter_cards_image_width", + * label = @Translation("Image width"), + * description = @Translation("The width of the image being linked to, in pixels."), + * name = "twitter:image:width", + * group = "twitter_cards", + * weight = 7, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsImageWidth 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 new file mode 100644 index 0000000000000000000000000000000000000000..d6ecaa5bfeeb31f108706736fe0e4b950f1295e2 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel1.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'twitter:label1' meta tag. + * + * @MetatagTag( + * id = "twitter_cards_label1", + * label = @Translation("Label 1"), + * description = @Translation("This field expects a string, and you can specify values for labels such as price, items in stock, sizes, etc."), + * name = "twitter:label1", + * group = "twitter_cards", + * weight = 500, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsLabel1 extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..294345f4139b8f665557aca37776b893895396d7 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsLabel2.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * Provides a plugin for the 'twitter:label2' meta tag. + * + * @MetatagTag( + * id = "twitter_cards_label2", + * label = @Translation("Label 2"), + * description = @Translation("This field expects a string, and you can specify values for labels such as price, items in stock, sizes, etc."), + * name = "twitter:label2", + * group = "twitter_cards", + * weight = 502, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsLabel2 extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPageUrl.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPageUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..d1f53e3adb9ffe1dedb6c93162a6ae8b94758ac5 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPageUrl.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards site's page url metatag. + * + * @MetatagTag( + * id = "twitter_cards_page_url", + * label = @Translation("Page URL"), + * description = @Translation("The permalink / canonical URL of the current page."), + * name = "twitter:url", + * group = "twitter_cards", + * weight = 6, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsPageUrl extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayer.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayer.php new file mode 100644 index 0000000000000000000000000000000000000000..11080d3a02d5d175384a029eb26bf77eb258475e --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayer.php @@ -0,0 +1,24 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards player metatag. + * + * @MetatagTag( + * id = "twitter_cards_player", + * label = @Translation("Media player URL"), + * description = @Translation("The full URL for loading a media player. Required when using a Media player card."), + * name = "twitter:player", + * group = "twitter_cards", + * weight = 400, + * type = "uri", + * secure = FALSE, + * multiple = FALSE, + * absolute_url = TRUE + * ) + */ +class TwitterCardsPlayer extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerHeight.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerHeight.php new file mode 100644 index 0000000000000000000000000000000000000000..aaac427a3302f4d750e3d86a1c3cacf005ec9ae8 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerHeight.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards player height metatag. + * + * @MetatagTag( + * id = "twitter_cards_player_height", + * label = @Translation("Media player height"), + * description = @Translation("The height of the media player iframe, in pixels. Required when using a Media player card."), + * name = "twitter:player:height", + * group = "twitter_cards", + * weight = 402, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsPlayerHeight extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerStream.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerStream.php new file mode 100644 index 0000000000000000000000000000000000000000..0be2723a81748dd13953e6c7219967a5be550cb1 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerStream.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards player stream url metatag. + * + * @MetatagTag( + * id = "twitter_cards_player_stream", + * label = @Translation("MP4 media stream URL"), + * description = @Translation("The full URL for an MP4 video (h.264) or audio (AAC) stream, takes precidence over the other media player field."), + * name = "twitter:player:stream", + * group = "twitter_cards", + * weight = 403, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsPlayerStream extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerStreamContentType.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerStreamContentType.php new file mode 100644 index 0000000000000000000000000000000000000000..558c7aab256a6619251374d7dba1df3445ae1797 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerStreamContentType.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards player stream content-type metatag. + * + * @MetatagTag( + * id = "twitter_cards_player_stream_content_type", + * label = @Translation("MP4 media stream MIME-type"), + * description = @Translation("The MIME type for the media contained in the stream URL, as defined by <a href=':url'>RFC 4337</a>.", arguments = { ":url" = "http://tools.ietf.org/rfc/rfc4337.txt" }), + * name = "twitter:player:stream:content_type", + * group = "twitter_cards", + * weight = 404, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsPlayerStreamContentType extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerWidth.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerWidth.php new file mode 100644 index 0000000000000000000000000000000000000000..ec0895203d7dd40943d426dac054a731de4208cb --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsPlayerWidth.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards player width metatag. + * + * @MetatagTag( + * id = "twitter_cards_player_width", + * label = @Translation("Media player width"), + * description = @Translation("The width of the media player iframe, in pixels. Required when using a Media player card."), + * name = "twitter:player:width", + * group = "twitter_cards", + * weight = 401, + * type = "integer", + * secure = FALSE, + * multiple = FALSE + * ); + */ +class TwitterCardsPlayerWidth extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsSite.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsSite.php new file mode 100644 index 0000000000000000000000000000000000000000..94ed630bf0134e9c4e519eae86124cf768dbcfe1 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsSite.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards site's account metatag. + * + * @MetatagTag( + * id = "twitter_cards_site", + * label = @Translation("Site's Twitter account"), + * description = @Translation("The @username for the website, which will be displayed in the Card's footer; must include the @ symbol."), + * name = "twitter:site", + * group = "twitter_cards", + * weight = 2, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsSite extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsSiteId.php b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsSiteId.php new file mode 100644 index 0000000000000000000000000000000000000000..cae9faf06e8ef5c395948a898c42368b0133e62b --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsSiteId.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards site's id metatag. + * + * @MetatagTag( + * id = "twitter_cards_site_id", + * label = @Translation("Site's Twitter account ID"), + * description = @Translation("The numerical Twitter account ID for the website, which will be displayed in the Card's footer."), + * name = "twitter:site:id", + * group = "twitter_cards", + * weight = 3, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsSiteId 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 new file mode 100644 index 0000000000000000000000000000000000000000..268dfa4bd8fc4548d841374e537ee1cb38759e37 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsTitle.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards title metatag. + * + * @MetatagTag( + * id = "twitter_cards_title", + * label = @Translation("Title"), + * description = @Translation("The page's title, which should be concise; it will be truncated at 70 characters by Twitter. This field is required unless this the 'type' field is set to 'photo'."), + * name = "twitter:title", + * group = "twitter_cards", + * weight = 2, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..9ae322f50e2e511430d22445461f5ed9ec4ccf45 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Plugin/metatag/Tag/TwitterCardsType.php @@ -0,0 +1,51 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * The Twitter Cards Type-tag. + * + * @MetatagTag( + * id = "twitter_cards_type", + * label = @Translation("Twitter card type"), + * description = @Translation("Notes:<ul><li>no other fields are required for a Summary card</li><li>Photo card requires the 'image' field</li><li>Media player card requires the 'title', 'description', 'media player URL', 'media player width', 'media player height' and 'image' fields,</li><li>Summary Card with Large Image card requires the 'Summary' field and the 'image' field,</li><li>Gallery Card requires all the 'Gallery Image' fields,</li><li>App Card requires the 'iPhone app ID' field, the 'iPad app ID' field and the 'Google Play app ID' field,</li><li>Product Card requires the 'description' field, the 'image' field, the 'Label 1' field, the 'Data 1' field, the 'Label 2' field and the 'Data 2' field.</li></ul>"), + * name = "twitter:card", + * group = "twitter_cards", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class TwitterCardsType extends MetaNameBase { + + /** + * {@inheritdoc} + */ + public function form(array $element = []) { + $form = [ + '#type' => 'select', + '#title' => $this->label(), + '#description' => $this->description(), + '#options' => [ + 'summary' => t('Summary Card'), + 'summary_large_image' => t('Summary Card with large image'), + 'photo' => t('Photo Card'), + 'gallery' => t('Gallery Card'), + 'app' => t('App Card'), + 'player' => t('Player Card'), + 'product' => t('Product Card'), + ], + '#empty_option' => t('- None -'), + '#empty_value' => '', + '#default_value' => $this->value(), + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#element_validate' => [[get_class($this), 'validateTag']], + ]; + + return $form; + } + +} diff --git a/web/modules/metatag/metatag_twitter_cards/src/Tests/MetatagTwitterCardsTagsTest.php b/web/modules/metatag/metatag_twitter_cards/src/Tests/MetatagTwitterCardsTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b718d0156e94fed671bc47953edc7713b431c1e0 --- /dev/null +++ b/web/modules/metatag/metatag_twitter_cards/src/Tests/MetatagTwitterCardsTagsTest.php @@ -0,0 +1,106 @@ +<?php + +namespace Drupal\metatag_twitter_cards\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Twitter Cards tags work correctly. + * + * @group metatag + */ +class MetatagTwitterCardsTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'twitter_cards_app_id_googleplay', + 'twitter_cards_app_id_ipad', + 'twitter_cards_app_id_iphone', + 'twitter_cards_app_name_googleplay', + 'twitter_cards_app_name_ipad', + 'twitter_cards_app_name_iphone', + 'twitter_cards_app_store_country', + 'twitter_cards_app_url_googleplay', + 'twitter_cards_app_url_ipad', + 'twitter_cards_app_url_iphone', + 'twitter_cards_creator', + 'twitter_cards_creator_id', + 'twitter_cards_data1', + 'twitter_cards_data2', + 'twitter_cards_description', + 'twitter_cards_donottrack', + 'twitter_cards_gallery_image0', + 'twitter_cards_gallery_image1', + 'twitter_cards_gallery_image2', + 'twitter_cards_gallery_image3', + 'twitter_cards_image', + 'twitter_cards_image_alt', + 'twitter_cards_image_height', + 'twitter_cards_image_width', + 'twitter_cards_label1', + 'twitter_cards_label2', + 'twitter_cards_page_url', + 'twitter_cards_player', + 'twitter_cards_player_height', + 'twitter_cards_player_stream', + 'twitter_cards_player_stream_content_type', + 'twitter_cards_player_width', + 'twitter_cards_site', + 'twitter_cards_site_id', + 'twitter_cards_title', + 'twitter_cards_type', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_twitter_cards'; + parent::setUp(); + } + + /** + * Twitter meta tags (almost) all have colons instead of underlines. + * + * They also don't have "cards" in their name. + */ + private function getTestTagName($tag_name) { + $tag_name = str_replace('twitter_cards', 'twitter', $tag_name); + $tag_name = str_replace('_', ':', $tag_name); + + if ($tag_name == 'twitter:app:store:country') { + $tag_name = 'twitter:app:country'; + } + elseif ($tag_name == 'twitter:page:url') { + $tag_name = 'twitter:url'; + } + elseif ($tag_name == 'twitter:player:stream:content:type') { + $tag_name = 'twitter:player:stream:content_type'; + } + elseif ($tag_name == 'twitter:type') { + $tag_name = 'twitter:card'; + } + elseif ($tag_name == 'twitter:donottrack') { + $tag_name = 'twitter:dnt'; + } + + return $tag_name; + } + + /** + * Implements {tag_name}TestFieldXpath() for 'twitter_cards_type'. + */ + private function twitterCardsTypeTestFieldXpath() { + return "//select[@name='twitter_cards_type']"; + } + + /** + * Implements {tag_name}TestValue() for 'twitter_cards_type'. + */ + private function twitterCardsTypeTestValue() { + return 'summary_large_image'; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..29aafb283a5c59b98977ae5bbb792f9fe759e6e9 --- /dev/null +++ b/web/modules/metatag/metatag_verification/config/schema/metatag_verification.metatag_tag.schema.yml @@ -0,0 +1,28 @@ +# The 'type' should be "label" for short meta tags and "text" for ones which +# could get longer, especially ones which use a textarea field instead of a +# textfield. + +metatag.metatag_tag.alexa: + type: label + label: 'Site validation: Alexa' +metatag.metatag_tag.baidu: + type: label + label: 'Site validation: Baidu' +metatag.metatag_tag.bing: + type: label + label: 'Site validation: Bing' +metatag.metatag_tag.google: + type: label + label: 'Site validation: Google' +metatag.metatag_tag.norton_safe_web: + type: label + label: 'Site validation: Norton Safe Web' +metatag.metatag_tag.pinterest: + type: label + label: 'Site validation: Pinterest' +metatag.metatag_tag.yahoo: + type: label + label: 'Site validation: Yahoo' +metatag.metatag_tag.yandex: + type: label + label: 'Site validation: Yandex' diff --git a/web/modules/metatag/metatag_verification/metatag_verification.info.yml b/web/modules/metatag/metatag_verification/metatag_verification.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..336c45f089ce858aa256607d37626fdc05aa3542 --- /dev/null +++ b/web/modules/metatag/metatag_verification/metatag_verification.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag: Verification' +type: module +description: Verifies ownership of a site for search engines and other services. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Group/SiteVerification.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Group/SiteVerification.php new file mode 100644 index 0000000000000000000000000000000000000000..4be81b2af1947617878f3352caa5200e22ada526 --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Group/SiteVerification.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag_verification\Plugin\metatag\Group; + +use Drupal\metatag\Plugin\metatag\Group\GroupBase; + +/** + * The Site Verification group. + * + * @MetatagGroup( + * id = "site_verification", + * label = @Translation("Site verification"), + * description = @Translation("These meta tags are used to confirm site ownership for search engines and other services."), + * weight = 10 + * ) + */ +class SiteVerification extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Baidu.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Baidu.php new file mode 100644 index 0000000000000000000000000000000000000000..ac41a8957a4f8bd1475dc7347a42537af5ee6da8 --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Baidu.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 'baidu-site-verification' meta tag. + * + * @MetatagTag( + * id = "baidu", + * label = @Translation("Baidu"), + * description = @Translation("A string provided by <a href=':baidu'>Baidu</a>.", arguments = { ":baidu" = "http://www.baidu.com/" }), + * name = "baidu-site-verification", + * group = "site_verification", + * weight = 2, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Baidu extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Bing.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Bing.php new file mode 100644 index 0000000000000000000000000000000000000000..9679777de78a6b831d74ffd5d9006532e278853a --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Bing.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 'msvalidate.01' meta tag. + * + * @MetatagTag( + * id = "bing", + * label = @Translation("Bing"), + * description = @Translation("A string provided by <a href=':bing'>Bing</a>, full details are available from the <a href=':verify_url'>Bing online help</a>.", arguments = { ":bing" = "http://www.bing.com/", ":verify_url" = "http://www.bing.com/webmaster/help/how-to-verify-ownership-of-your-site-afcfefc6" }), + * name = "msvalidate.01", + * group = "site_verification", + * weight = 3, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Bing extends MetaNameBase { +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..e502a785fc73c1242e3aa694922c567938ea408b --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Google.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 'google-site-verification' meta tag. + * + * @MetatagTag( + * id = "google", + * label = @Translation("Google"), + * 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", + * weight = 4, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Google extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/NortonSafeWeb.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/NortonSafeWeb.php new file mode 100644 index 0000000000000000000000000000000000000000..94e086a34a94a4fcb623c04f1c51e21cd99b3a3c --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/NortonSafeWeb.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 'norton-safeweb-site-verification' meta tag. + * + * @MetatagTag( + * id = "norton_safe_web", + * label = @Translation("Norton Safe Web"), + * description = @Translation("A string provided by <a href=':norton'>Norton Safe Web</a>, full details are available from the <a href=':verify_url'>Norton Safe Web online help</a>.", arguments = { ":norton" = "https://safeweb.norton.com/", ":verify_url" = "https://safeweb.norton.com/help/site_owners" }), + * name = "norton-safeweb-site-verification", + * group = "site_verification", + * weight = 5, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class NortonSafeWeb extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Pinterest.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Pinterest.php new file mode 100644 index 0000000000000000000000000000000000000000..4c6512f79c15ef14a2478fda230258c32ce49644 --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Pinterest.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 'p:domain_verify' meta tag. + * + * @MetatagTag( + * id = "pinterest", + * label = @Translation("Pinterest"), + * description = @Translation("A string provided by <a href=':pinterest'>Pinterest</a>, full details are available from the <a href=':verify_url'>Pinterest online help</a>.", arguments = { ":pinterest" = "https://www.pinterest.com/", ":verify_url" = "https://help.pinterest.com/en/articles/verify-your-website" }), + * name = "p:domain_verify", + * group = "site_verification", + * weight = 6, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Pinterest extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Yandex.php b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Yandex.php new file mode 100644 index 0000000000000000000000000000000000000000..23c0504285ef977f5ca32253f85c4e0ff173fd79 --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Plugin/metatag/Tag/Yandex.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 'yandex-verification' meta tag. + * + * @MetatagTag( + * id = "yandex", + * label = @Translation("Yandex"), + * description = @Translation("A string provided by <a href=':yandex'>Yandex</a>, full details are available from the <a href=':verify_url'>Yandex online help</a>.", arguments = { ":yandex" = "http://www.yandex.com/", ":verify_url" = "http://api.yandex.com/webmaster/doc/dg/reference/hosts-type.xml" }), + * name = "yandex-verification", + * group = "site_verification", + * weight = 8, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Yandex extends MetaNameBase { +} diff --git a/web/modules/metatag/metatag_verification/src/Tests/MetatagVerificationTagsTest.php b/web/modules/metatag/metatag_verification/src/Tests/MetatagVerificationTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..940ede99df7cbbca884cb05e8d754e618ae83b27 --- /dev/null +++ b/web/modules/metatag/metatag_verification/src/Tests/MetatagVerificationTagsTest.php @@ -0,0 +1,60 @@ +<?php + +namespace Drupal\metatag_verification\Tests; + +use Drupal\metatag\Tests\MetatagTagsTestBase; + +/** + * Tests that each of the Metatag Verification tags work correctly. + * + * @group metatag + */ +class MetatagVerificationTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'baidu', + 'bing', + 'google', + 'norton_safe_web', + 'pinterest', + 'yandex', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::$modules[] = 'metatag_verification'; + parent::setUp(); + } + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + if ($tag_name == 'baidu') { + $tag_name = 'baidu-site-verification'; + } + elseif ($tag_name == 'bing') { + $tag_name = 'msvalidate.01'; + } + elseif ($tag_name == 'google') { + $tag_name = 'google-site-verification'; + } + elseif ($tag_name == 'norton_safe_web') { + $tag_name = 'norton-safeweb-site-verification'; + } + elseif ($tag_name == 'pinterest') { + $tag_name = 'p:domain_verify'; + } + elseif ($tag_name == 'yandex') { + $tag_name = 'yandex-verification'; + } + + return $tag_name; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..b98db8cadcf5d8f17aa640ba2a895d3e078044af --- /dev/null +++ b/web/modules/metatag/metatag_views/config/schema/metatag_views.views.schema.yml @@ -0,0 +1,8 @@ +views.display_extender.metatag_display_extender: + type: views_display_extender + mapping: + metatags: + type: sequence + label: 'Metatags' + sequence: + type: metatag.metatag_tag.[%key] diff --git a/web/modules/metatag/metatag_views/metatag_views.info.yml b/web/modules/metatag/metatag_views/metatag_views.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..db451743ccd3580800464df41958bee268de8715 --- /dev/null +++ b/web/modules/metatag/metatag_views/metatag_views.info.yml @@ -0,0 +1,14 @@ +name: 'Metatag: Views' +type: module +description: Provides views integration for metatags. +# core: 8.x +package: SEO +dependencies: + - metatag:metatag + - drupal:views + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/metatag_views/metatag_views.install b/web/modules/metatag/metatag_views/metatag_views.install new file mode 100644 index 0000000000000000000000000000000000000000..f743437240dcfe0d4647364cfc609b9108532fb0 --- /dev/null +++ b/web/modules/metatag/metatag_views/metatag_views.install @@ -0,0 +1,45 @@ +<?php + +/** + * @file + * Various install/uninstall hooks for the Metatag Views module. + */ + +/** + * Implements hook_install(). + */ +function metatag_views_install() { + // Enable metatag_display_extender plugin. + $config = \Drupal::service('config.factory')->getEditable('views.settings'); + $display_extenders = $config->get('display_extenders') ?: []; + $display_extenders[] = 'metatag_display_extender'; + $config->set('display_extenders', $display_extenders); + $config->save(); +} + +/** + * Implements hook_uninstall(). + */ +function metatag_views_uninstall() { + // Disable metatag_display_extender plugin. + $config = \Drupal::service('config.factory')->getEditable('views.settings'); + $display_extenders = $config->get('display_extenders') ?: []; + + $key = array_search('metatag_display_extender', $display_extenders); + if ($key !== FALSE) { + unset($display_extenders[$key]); + $config->set('display_extenders', $display_extenders); + $config->save(); + } +} + +/** + * Implementations of hook_update_N(). + */ + +/** + * 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."); +} diff --git a/web/modules/metatag/metatag_views/metatag_views.module b/web/modules/metatag/metatag_views/metatag_views.module new file mode 100644 index 0000000000000000000000000000000000000000..02b9e9cd88282a856b9e5f690777e3bc636131f7 --- /dev/null +++ b/web/modules/metatag/metatag_views/metatag_views.module @@ -0,0 +1,76 @@ +<?php + +/** + * @file + * Contains hook implementations for the metatag_views module. + */ + +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\views\ViewEntityInterface; +use Drupal\views\ViewExecutable; +use Drupal\views\Views; + +/** + * Gets the meta tags of a specific view, if set. + * + * @param mixed $view + * The view id, view config entity or view executable. + * @param string $display_id + * The display id. If empty uses the preselected display if $view is a + * ViewExecutable, otherwise the default display. + * + * @return array|null + * The meta tags if set, null otherwise. + */ +function metatag_get_view_tags($view, $display_id = NULL) { + if (empty($view)) { + return; + } + if ($view instanceof ViewEntityInterface) { + $view = $view->getExecutable(); + } + elseif (is_string($view)) { + $view = Views::getView($view); + } + if (!$view instanceof ViewExecutable) { + return; + } + $view->setDisplay($display_id); + + // And get the list of extenders for this display. + $extenders = $view->getDisplay()->getExtenders(); + if (!isset($extenders['metatag_display_extender'])) { + // If the id of the plugin is not in the list then something is wrong. + return; + } + + // Retrieve the metatag settings from the extender. + return $extenders['metatag_display_extender']->getMetatags(); +} + +/** + * Implements hook_metatags_alter(). + */ +function metatag_views_metatags_alter(array &$metatags, array &$context) { + if (!$context['entity'] instanceof ViewEntityInterface) { + return; + } + + $view = $context['entity']->getExecutable(); + // If display_id is not available, will default to Master display. + $display_id = \Drupal::routeMatch()->getParameter('display_id'); + if ($tags = metatag_get_view_tags($view, $display_id)) { + // Apply view overrides. + $metatags = array_merge($metatags, $tags); + } +} + +/** + * Implements hook_metatag_route_entity(). + */ +function metatag_views_metatag_route_entity(RouteMatchInterface $route_match) { + if ($view_id = $route_match->getParameter('view_id')) { + $entity = \Drupal::entityTypeManager()->getStorage('view')->load($view_id); + return $entity; + } +} diff --git a/web/modules/metatag/metatag_views/src/Controller/MetatagViewsController.php b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsController.php new file mode 100644 index 0000000000000000000000000000000000000000..2ddf0b824e43183c81ac437f8174479f9f31dc20 --- /dev/null +++ b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsController.php @@ -0,0 +1,246 @@ +<?php + +namespace Drupal\metatag_views\Controller; + +use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Url; +use Drupal\metatag\MetatagManagerInterface; +use Drupal\views\Views; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Class MetatagViewsController. + * + * @package Drupal\metatag_views\Controller + */ +class MetatagViewsController extends ControllerBase { + + /** + * The Views storage interface. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $viewStorage; + + /** + * The Metatag manager interface. + * + * @var \Drupal\metatag\MetatagManagerInterface + */ + protected $metatagManager; + + /** + * Associative array of labels. + * + * @var array + */ + protected $viewLabels; + + /** + * {@inheritdoc} + */ + public function __construct(EntityStorageInterface $viewStorage, MetatagManagerInterface $metatagManager) { + $this->viewStorage = $viewStorage; + $this->metatagManager = $metatagManager; + + // Generate the labels for views and displays. + $this->labels = $this->getViewsAndDisplaysLabels(); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity_type.manager')->getStorage('view'), + $container->get('metatag.manager') + ); + } + + /** + * Get meta tags for all of the views / displays that have them set. + * + * @return array + * List of tags grouped by view and display. + */ + public static function getTaggedViews() { + $tagged_views = []; + foreach (Views::getEnabledViews() as $view_id => $view) { + $displays = $view->get('display'); + foreach (array_keys($displays) as $display_id) { + if ($tags = metatag_get_view_tags($view_id, $display_id)) { + $tagged_views[$view_id][$display_id] = $tags; + } + } + } + return $tagged_views; + } + + /** + * Generates the renderable array for views meta tags UI. + * + * @return array + * The list of details. + */ + public function listViews() { + $elements = []; + + $elements['header'] = [ + '#markup' => '<p>' . $this->t("To view a list of displays with meta tags set up, click on a view name. To view a summary of meta tags configuration for a particular display, click on the display name. If you need to set meta tags for a specific view, choose Add views meta tags. Reverting the meta tags removes the specific configuration and falls back to defaults.") . '</p>', + ]; + + // Iterate over the values and build the whole UI. + // 1. Top level is a collapsible fieldset with a view name (details) + // 2. Inside each fieldset we have 2 columns -> Display and Operations. + // Display contains point 3. + // Operations contain edit and revert. + // 3. In each display there is a table that has 2 columns: tag name and tag + // value. + $tagged_views = $this->getTaggedViews(); + foreach ($tagged_views as $view_id => $displays) { + $elements[$view_id] = [ + '#type' => 'details', + '#title' => $this->t($this->viewLabels[$view_id]['#label']), + 'details' => $this->buildViewDetails($view_id, $displays), + ]; + } + + return $elements; + } + + /** + * Builds the second "level" of the UI table with display fieldset and ops. + * + * @param string $view_id + * The view display to use. + * @param array $displays + * The displays to process. + * + * @return array + * Render array. + */ + protected function buildViewDetails($view_id, array $displays) { + $element = [ + '#type' => 'table', + '#collapsible' => TRUE, + '#header' => [ + $this->t('Display'), + $this->t('Operations'), + ], + ]; + + foreach ($displays as $display_id => $metatags) { + $metatags = array_filter($metatags); + + $element[$display_id]['details'] = [ + '#type' => 'details', + '#title' => $this->viewLabels[$view_id][$display_id], + ]; + + $params = [ + 'view_id' => $view_id, + 'display_id' => $display_id, + ]; + + // Generate the operations. + $element[$display_id]['ops'] = [ + '#type' => 'operations', + '#links' => [ + 'edit' => [ + 'title' => $this->t('Edit'), + 'url' => Url::fromRoute('metatag_views.metatags.edit', $params), + ], + 'translate' => [ + 'title' => $this->t('Translate'), + 'url' => Url::fromRoute('metatag_views.metatags.translate_overview', $params), + ], + 'revert' => [ + 'title' => $this->t('Revert'), + 'url' => Url::fromRoute('metatag_views.metatags.revert', $params), + ], + ], + ]; + + // Build the rows for each of the metatag types. + $element[$display_id]['details']['table'] = $this->buildDisplayDetailsTable($metatags); + } + + return $element; + } + + /** + * Build the table with metatag values summary. + * + * @param array $tags + * The tags to process. + * + * @return array + * The tag structure in a display element. + */ + protected function buildDisplayDetailsTable(array $tags) { + $element = [ + '#type' => 'table', + ]; + + $i = 0; + foreach ($tags as $tag_name => $tag_value) { + // This is for the case where we have a subarray. + $tag_value = $this->prepareTagValue($tag_value); + if (!$tag_value) { + continue; + } + + $element[$i]['tag_name'] = [ + '#type' => 'markup', + '#markup' => $tag_name, + ]; + + $element[$i]['tag_value'] = [ + '#type' => 'markup', + '#markup' => $tag_value, + ]; + $i++; + } + + return $element; + } + + /** + * Massage the tag value. + * + * @param string $value + * The meta tag to output. + * + * @return string + * An imploded string for meta tags that are nested, ex. robots. + */ + protected function prepareTagValue($value) { + if (is_array($value)) { + $value = implode(', ', array_filter($value)); + } + + return $value; + } + + /** + * Gets label values for the views and their displays. + */ + protected function getViewsAndDisplaysLabels() { + /** @var \Drupal\views\ViewEntityInterface[] $views */ + $views = $this->viewStorage->loadByProperties(['status' => 1]); + + $labels = []; + + foreach ($views as $view_id => $view) { + $displays = $view->get('display'); + $labels[$view_id]['#label'] = $view->label(); + foreach (array_keys($displays) as $display_id) { + $labels[$view_id][$display_id] = $displays[$display_id]['display_title']; + } + } + + $this->viewLabels = $labels; + } + +} diff --git a/web/modules/metatag/metatag_views/src/Controller/MetatagViewsTranslationController.php b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsTranslationController.php new file mode 100644 index 0000000000000000000000000000000000000000..eec9afc6e61072a604853b84ca3bcbde7c20e28c --- /dev/null +++ b/web/modules/metatag/metatag_views/src/Controller/MetatagViewsTranslationController.php @@ -0,0 +1,151 @@ +<?php + +namespace Drupal\metatag_views\Controller; + +use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Url; +use Drupal\metatag\MetatagManagerInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Translate Views meta tags. + */ +class MetatagViewsTranslationController extends ControllerBase { + + /** + * The View storage interface. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $viewStorage; + + /** + * The Metatag manager. + * + * @var \Drupal\metatag\MetatagManagerInterface + */ + protected $metatagManager; + + /** + * The language manager. + * + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + + /** + * {@inheritdoc} + */ + public function __construct(EntityStorageInterface $viewStorage, MetatagManagerInterface $metatagManager, LanguageManagerInterface $languageManager) { + $this->viewStorage = $viewStorage; + $this->metatagManager = $metatagManager; + $this->languageManager = $languageManager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity_type.manager')->getStorage('view'), + $container->get('metatag.manager'), + $container->get('language_manager') + ); + } + + /** + * Language translations overview page for a views. + * + * @return array + * Page render array. + */ + public function itemPage() { + $view_id = \Drupal::request()->get('view_id'); + $display_id = \Drupal::request()->get('display_id'); + + $view = $this->viewStorage->load($view_id); + $original_langcode = $view->language()->getId(); + + $config_name = $view->getConfigDependencyName(); + $config_path = 'display.' . $display_id . '.display_options.display_extenders.metatag_display_extender.metatags'; + + $configuration = \Drupal::service('config.factory')->get($config_name); + $config_source = $configuration->getOriginal($config_path, FALSE); + + $page['languages'] = [ + '#type' => 'table', + '#header' => [$this->t('Language'), $this->t('Operations')], + ]; + + $languages = $this->languageManager->getLanguages(); + foreach ($languages as $language) { + $langcode = $language->getId(); + $language_name = $language->getName(); + $operations = []; + + // Prepare the language name and the operations depending on whether this + // is the original language or not. + if ($langcode == $original_langcode) { + $language_name = '<strong>' . $this->t('@language (original)', [ + '@language' => $language_name, + ]) . '</strong>'; + + // Default language can only be edited, no add/delete. + $operations['edit'] = [ + 'title' => $this->t('Edit'), + 'url' => Url::fromRoute('metatag_views.metatags.edit', [ + 'view_id' => $view_id, + 'display_id' => $display_id, + ]), + ]; + } + else { + // Get the metatag translation for this language. + $config_translation = $this->languageManager + ->getLanguageConfigOverride($langcode, $config_name) + ->get($config_path); + + // If no translation exists for this language, link to add one. + if (!$config_translation || $config_translation == $config_source) { + $operations['add'] = [ + 'title' => $this->t('Add'), + 'url' => Url::fromRoute('metatag_views.metatags.translate', [ + 'view_id' => $view_id, + 'display_id' => $display_id, + 'langcode' => $langcode, + ]), + ]; + } + else { + // Otherwise, link to edit the existing translation. + $operations['edit'] = [ + 'title' => $this->t('Edit'), + 'url' => Url::fromRoute('metatag_views.metatags.translate', [ + 'view_id' => $view_id, + 'display_id' => $display_id, + 'langcode' => $langcode, + ]), + ]; + // @todo Operations delete. + } + } + + $page['languages'][$langcode]['language'] = [ + '#markup' => $language_name, + ]; + + $page['languages'][$langcode]['operations'] = [ + '#type' => 'operations', + '#links' => $operations, + // Even if the mapper contains multiple language codes, the source + // configuration can still be edited. + // '#access' => ($langcode == $original_langcode) || $operations_access, + ]; + } + + return $page; + } + +} diff --git a/web/modules/metatag/metatag_views/src/Form/MetatagViewsAddForm.php b/web/modules/metatag/metatag_views/src/Form/MetatagViewsAddForm.php new file mode 100644 index 0000000000000000000000000000000000000000..476293df95b34836d24122b0a0723a83a2fb7afb --- /dev/null +++ b/web/modules/metatag/metatag_views/src/Form/MetatagViewsAddForm.php @@ -0,0 +1,49 @@ +<?php + +namespace Drupal\metatag_views\Form; + +use Drupal\Core\Form\FormStateInterface; +use Drupal\metatag_views\Controller\MetatagViewsController; +use Drupal\views\Views; + +/** + * Class MetatagViewsAddForm. + * + * @package Drupal\metatag_views\Form + */ +class MetatagViewsAddForm extends MetatagViewsEditForm { + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'metatag_views_add_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $form = parent::buildForm($form, $form_state); + + // Add a view select to the edit form. + $views = Views::getViewsAsOptions(FALSE, 'enabled', NULL, TRUE, TRUE); + // Get only the views that do not have the meta tags set yet. + $in_use = MetatagViewsController::getTaggedViews(); + foreach ($in_use as $view_id => $displays) { + foreach (array_keys($displays) as $display_id) { + unset($views[$view_id][$view_id . ':' . $display_id]); + } + } + $views = array_filter($views); + + // Need to create that AFTER the $form['metatags'] as the whole form + // is passed to the $metatagManager->form() which causes duplicated field. + $form['view']['#type'] = 'select'; + $form['view']['#options'] = $views; + $form['view']['#empty_option'] = $this->t('- Select a view -'); + + return $form; + } + +} diff --git a/web/modules/metatag/metatag_views/src/Form/MetatagViewsEditForm.php b/web/modules/metatag/metatag_views/src/Form/MetatagViewsEditForm.php new file mode 100644 index 0000000000000000000000000000000000000000..0e395e8426cb850b8b1f418b000f2161a18d4053 --- /dev/null +++ b/web/modules/metatag/metatag_views/src/Form/MetatagViewsEditForm.php @@ -0,0 +1,194 @@ +<?php + +namespace Drupal\metatag_views\Form; + +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Form\FormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\metatag\MetatagManagerInterface; +use Drupal\metatag_views\MetatagViewsValuesCleanerTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Class MetatagViewsEditForm. + * + * @package Drupal\metatag_views\Form + */ +class MetatagViewsEditForm extends FormBase { + + use MetatagViewsValuesCleanerTrait; + + /** + * Drupal\metatag\MetatagManager definition. + * + * @var \Drupal\metatag\MetatagManager + */ + protected $metatagManager; + + /** + * The Views manager. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $viewsManager; + + /** + * Array of display settings from ViewEntityInterface::getDisplay(). + * + * @var array + */ + protected $display; + + /** + * View entity object. + * + * @var \Drupal\views\ViewEntityInterface + */ + protected $view; + + /** + * {@inheritdoc} + */ + public function __construct(MetatagManagerInterface $metatag_manager, EntityTypeManagerInterface $entity_manager) { + $this->metatagManager = $metatag_manager; + $this->viewsManager = $entity_manager->getStorage('view'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('metatag.manager'), + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'metatag_views_edit_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + // Get the parameters from request. + $view_id = \Drupal::request()->get('view_id'); + $display_id = \Drupal::request()->get('display_id'); + + // Get meta tags from the view entity. + $metatags = []; + if ($view_id && $display_id) { + $metatags = metatag_get_view_tags($view_id, $display_id); + } + + $form['metatags'] = $this->metatagManager->form($metatags, $form, ['view']); + $form['metatags']['#title'] = $this->t('Metatags'); + $form['metatags']['#type'] = 'fieldset'; + + // Need to create that AFTER the $form['metatags'] as the whole form is + // passed to the $metatagManager->form() which causes duplicated field. + $form['view'] = [ + '#type' => 'value', + '#title' => $this->t('View'), + '#weight' => -100, + '#default_value' => $view_id . ':' . $display_id, + '#required' => TRUE, + ]; + + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Submit'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function form(array $values, array $element, array $token_types = [], array $included_groups = NULL, array $included_tags = NULL) { + // Add the outer fieldset. + $element += [ + '#type' => 'details', + ]; + + $element += $this->tokenService->tokenBrowser($token_types); + + $groups_and_tags = $this->sortedGroupsWithTags(); + + $first = TRUE; + foreach ($groups_and_tags as $group_id => $group) { + // Only act on groups that have tags and are in the list of included + // groups (unless that list is null). + if (isset($group['tags']) && (is_null($included_groups) || in_array($group_id, $included_groups))) { + // Create the fieldset. + $element[$group_id]['#type'] = 'details'; + $element[$group_id]['#title'] = $group['label']; + $element[$group_id]['#description'] = $group['description']; + $element[$group_id]['#open'] = $first; + $first = FALSE; + + foreach ($group['tags'] as $tag_id => $tag) { + // 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. + $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->setValue($tag_value); + + // Create the bit of form for this tag. + $element[$group_id][$tag_id] = $tag->form($element); + } + } + } + } + + return $element; + } + + /** + * {@inheritdoc} + */ + 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); + + $metatags = $form_state->getValues(); + unset($metatags['view']); + $metatags = $this->clearMetatagViewsDisallowedValues($metatags); + + /** @var \Drupal\views\ViewEntityInterface $view */ + $view = $this->viewsManager->load($view_id); + + // Store the meta tags on the view. + $config_name = $view->getConfigDependencyName(); + $config_path = 'display.' . $display_id . '.display_options.display_extenders.metatag_display_extender.metatags'; + + // Set configuration values based on form submission. This always edits the + // original language. + $configuration = $this->configFactory()->getEditable($config_name); + if (empty($this->removeEmptyTags($metatags))) { + $configuration->clear($config_path); + } + else { + $configuration->set($config_path, $metatags); + } + $configuration->save(); + + // Redirect back to the views list. + $form_state->setRedirect('metatag_views.metatags.list'); + + drupal_set_message($this->t('Metatags for @view : @display have been saved.', [ + '@view' => $view->label(), + '@display' => $view->getDisplay($display_id)['display_title'], + ])); + } + +} diff --git a/web/modules/metatag/metatag_views/src/Form/MetatagViewsRevertForm.php b/web/modules/metatag/metatag_views/src/Form/MetatagViewsRevertForm.php new file mode 100644 index 0000000000000000000000000000000000000000..1bd585929dabab5ad5d2430a0cbf1f8c9725df3f --- /dev/null +++ b/web/modules/metatag/metatag_views/src/Form/MetatagViewsRevertForm.php @@ -0,0 +1,132 @@ +<?php + +namespace Drupal\metatag_views\Form; + +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Form\ConfirmFormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Url; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Defines a form for reverting views metatags. + */ +class MetatagViewsRevertForm extends ConfirmFormBase { + + /** + * Entity manager for views entities. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $viewsManager; + + /** + * The view entity to revert meta tags on. + * + * @var \Drupal\views\ViewEntityInterface + */ + protected $view; + + /** + * The view's display id. + * + * @var string + */ + protected $displayId; + + /** + * {@inheritdoc} + */ + public function __construct(EntityTypeManagerInterface $entity_manager) { + $this->viewsManager = $entity_manager->getStorage('view'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'metatag_views_revert_form'; + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return $this->t('Do you want to revert meta tags for @view_name : @display_name?', [ + '@view_name' => $this->view->label(), + '@display_name' => $this->view->getDisplay($this->displayId)['display_title'], + ]); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl() { + return new Url('metatag_views.metatags.list'); + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->t('You are about to revert the custom meta tags for the %display_name display on the %view_name view. This action cannot be undone.', [ + '%view_name' => $this->view->label(), + '%display_name' => $this->view->getDisplay($this->displayId)['display_title'], + ]); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Revert'); + } + + /** + * {@inheritdoc} + */ + public function getCancelText() { + return $this->t('Cancel'); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state, $view_id = NULL, $display_id = NUL) { + $this->view = $this->viewsManager->load($view_id); + $this->displayId = $display_id; + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Removed meta tags from the view. + $config_name = $this->view->getConfigDependencyName(); + $config_path = 'display.' . $this->displayId . '.display_options.display_extenders.metatag_display_extender.metatags'; + + $this->configFactory()->getEditable($config_name) + ->clear($config_path) + ->save(); + + // Redirect back to the views list. + $form_state->setRedirect('metatag_views.metatags.list'); + + drupal_set_message($this->t('Reverted meta tags for @view_name : @display_name', [ + '@view_name' => $this->view->label(), + '@display_name' => $this->view->getDisplay($this->displayId)['display_title'], + ])); + } + +} diff --git a/web/modules/metatag/metatag_views/src/Form/MetatagViewsTranslationForm.php b/web/modules/metatag/metatag_views/src/Form/MetatagViewsTranslationForm.php new file mode 100644 index 0000000000000000000000000000000000000000..88875c0a6e9230dd4a5761a8d21c5bce1a9bef53 --- /dev/null +++ b/web/modules/metatag/metatag_views/src/Form/MetatagViewsTranslationForm.php @@ -0,0 +1,269 @@ +<?php + +namespace Drupal\metatag_views\Form; + +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Form\FormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\metatag\MetatagManagerInterface; +use Drupal\metatag\MetatagTagPluginManager; +use Drupal\metatag\MetatagToken; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\language\ConfigurableLanguageManagerInterface; +use Drupal\metatag_views\MetatagViewsValuesCleanerTrait; + +/** + * Class MetatagViewsEditForm. + * + * @package Drupal\metatag_views\Form + */ +class MetatagViewsTranslationForm extends FormBase { + + use MetatagViewsValuesCleanerTrait; + + /** + * Drupal\metatag\MetatagManager definition. + * + * @var \Drupal\metatag\MetatagManager + */ + protected $metatagManager; + + /** + * The language manager. + * + * @var \Drupal\language\ConfigurableLanguageManagerInterface + */ + protected $languageManager; + + /** + * The Views manager. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $viewsManager; + + /** + * The Metatag token service. + * + * @var \Drupal\metatag\MetatagToken + */ + protected $tokenService; + + /** + * The Metatag tag plugin manager. + * + * @var \Drupal\metatag\MetatagTagPluginManager + */ + protected $tagPluginManager; + + /** + * The View entity object. + * + * @var \Drupal\views\ViewEntityInterface + */ + protected $view; + + /** + * View ID. + * + * @var string + */ + protected $viewId; + + /** + * View display ID. + * + * @var string + */ + protected $displayId = 'default'; + + /** + * The language of the translation. + * + * @var \Drupal\Core\Language\LanguageInterface + */ + protected $language; + + /** + * The language of the translation source. + * + * @var \Drupal\Core\Language\LanguageInterface + */ + protected $sourceLanguage; + + /** + * An array of base language data. + * + * @var array + */ + protected $baseData = []; + + /** + * {@inheritdoc} + */ + public function __construct(MetatagManagerInterface $metatag_manager, EntityTypeManagerInterface $entity_manager, MetatagToken $token, MetatagTagPluginManager $tagPluginManager, ConfigurableLanguageManagerInterface $language_manager) { + $this->metatagManager = $metatag_manager; + $this->viewsManager = $entity_manager->getStorage('view'); + $this->tokenService = $token; + $this->tagPluginManager = $tagPluginManager; + $this->languageManager = $language_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('metatag.manager'), + $container->get('entity_type.manager'), + $container->get('metatag.token'), + $container->get('plugin.manager.metatag.tag'), + $container->get('language_manager') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'metatag_views_translate_form'; + } + + /** + * Gets the translated values while storing a copy of the original values. + */ + protected function prepareValues() { + $config_name = $this->view->getConfigDependencyName(); + $config_path = 'display.' . $this->displayId . '.display_options.display_extenders.metatag_display_extender.metatags'; + + $configuration = \Drupal::service('config.factory')->get($config_name); + $this->baseData = $configuration->getOriginal($config_path, FALSE); + + // Set the translation target language on the configuration factory. + $original_language = $this->languageManager->getConfigOverrideLanguage(); + $this->languageManager->setConfigOverrideLanguage($this->language); + + // Read in translated values. + $configuration = \Drupal::service('config.factory')->get($config_name); + $translated_values = $configuration->get($config_path); + + // Set the configuration language back. + $this->languageManager->setConfigOverrideLanguage($original_language); + + return $translated_values; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + // Get the parameters from request. + $this->viewId = \Drupal::request()->get('view_id'); + $this->displayId = \Drupal::request()->get('display_id'); + $langcode = \Drupal::request()->get('langcode'); + + $this->view = $this->viewsManager->load($this->viewId); + $this->language = $this->languageManager->getLanguage($langcode); + $this->sourceLanguage = $this->view->language(); + + // Get meta tags from the view entity. + $form['#tree'] = TRUE; + $form['#attached']['library'][] = 'config_translation/drupal.config_translation.admin'; + + $form['#title'] = $this->t('Edit @language translation for %view: %display metatags', [ + '%view' => $this->view->label(), + '%display' => $this->view->getDisplay($this->displayId)['display_title'], + '@language' => $this->language->getName(), + ]); + + $form['metatags'] = $this->form($form, $this->prepareValues()); + $form['metatags']['#title'] = t('Metatags'); + $form['metatags']['#type'] = 'fieldset'; + + $form['submit'] = [ + '#type' => 'submit', + '#value' => t('Submit'), + ]; + + return $form; + } + + /** + * Add the translation form element for meta tags available in the source. + */ + public function form(array $element, array $translated_values) { + $translated_values = $this->clearMetatagViewsDisallowedValues($translated_values); + // Only offer form elements for tags present in the source language. + $source_values = $this->removeEmptyTags($this->baseData); + + // Add the outer fieldset. + $element += [ + '#type' => 'details', + ]; + $element += $this->tokenService->tokenBrowser(['view']); + + foreach ($source_values as $tag_id => $value) { + $tag = $this->tagPluginManager->createInstance($tag_id); + $tag->setValue($translated_values[$tag_id]); + + $form_element = $tag->form($element); + $element[$tag_id] = [ + '#theme' => 'config_translation_manage_form_element', + 'source' => [ + '#type' => 'item', + '#title' => $form_element['#title'], + '#markup' => $value, + ], + 'translation' => $form_element, + ]; + } + + return $element; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Get the values of metatags. + $values = $form_state->getValue('metatags'); + $translated_values = array_combine(array_keys($values), array_column($values, 'translation')); + + $config_name = $this->view->getConfigDependencyName(); + $config_path = 'display.' . $this->displayId . '.display_options.display_extenders.metatag_display_extender.metatags'; + + // Set configuration values based on form submission and source values. + $base_config = $this->configFactory()->getEditable($config_name); + $config_translation = $this->languageManager->getLanguageConfigOverride($this->language->getId(), $config_name); + + // Save the configuration values, if they are different from the source + // values in the base configuration. Otherwise remove the override. + $source_values = $this->removeEmptyTags($base_config->get($config_path)); + if ($source_values !== $translated_values) { + $config_translation->set($config_path, $translated_values); + } + else { + $config_translation->clear($config_path); + } + + // If no overrides, delete language specific configuration file. + $saved_config = $config_translation->get(); + if (empty($saved_config)) { + $config_translation->delete(); + } + else { + $config_translation->save(); + } + + // Redirect back to the views list. + $form_state->setRedirect('metatag_views.metatags.translate_overview', [ + 'view_id' => $this->viewId, + 'display_id' => $this->displayId, + ]); + + drupal_set_message($this->t('Successfully updated @language translation.', [ + '@language' => $this->language->getName(), + ])); + } + +} diff --git a/web/modules/metatag/metatag_views/src/MetatagViewsValuesCleanerTrait.php b/web/modules/metatag/metatag_views/src/MetatagViewsValuesCleanerTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..a13f8a2bd5c163ecbf4f08589d2edb390e02a3e6 --- /dev/null +++ b/web/modules/metatag/metatag_views/src/MetatagViewsValuesCleanerTrait.php @@ -0,0 +1,44 @@ +<?php + +namespace Drupal\metatag_views; + +/** + * Collection of helper methods when handling raw tag values. + */ +trait MetatagViewsValuesCleanerTrait { + + /** + * Clears the metatag form state values from illegal elements. + * + * @param array $metatags + * Array of values to submit. + * + * @return array + * Filtered metatag array. + */ + public function clearMetatagViewsDisallowedValues(array $metatags) { + // Get all legal tags. + $tags = $this->metatagManager->sortedTags(); + + // Return only common elements. + $metatags = array_intersect_key($metatags, $tags); + + return $metatags; + } + + /** + * Removes tags that are empty. + */ + public function removeEmptyTags($metatags) { + $metatags = array_filter($metatags, function ($value) { + if (is_array($value)) { + return count(array_filter($value)) > 0; + } + else { + return $value !== ''; + } + }); + return $metatags; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..c31a4e825bcca6442b901c9d5b192b9628344ec1 --- /dev/null +++ b/web/modules/metatag/metatag_views/src/Plugin/views/display_extender/MetatagDisplayExtender.php @@ -0,0 +1,187 @@ +<?php + +namespace Drupal\metatag_views\Plugin\views\display_extender; + +use Drupal\Core\Form\FormStateInterface; +use Drupal\metatag\MetatagManagerInterface; +use Drupal\metatag\MetatagTagPluginManager; +use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Metatag display extender plugin. + * + * @ingroup views_display_extender_plugins + * + * @ViewsDisplayExtender( + * id = "metatag_display_extender", + * title = @Translation("Metatag display extender"), + * help = @Translation("Metatag settings for this view."), + * no_ui = FALSE + * ) + */ +class MetatagDisplayExtender extends DisplayExtenderPluginBase { + + /** + * The metatag manager. + * + * @var \Drupal\metatag\MetatagManagerInterface + */ + protected $metatagManager; + + /** + * The plugin manager for metatag tags. + * + * @var \Drupal\metatag\MetatagTagPluginManager + */ + protected $metatagTagManager; + + /** + * Constructs the plugin. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\metatag\MetatagTagPluginManager $metatag_plugin_manager + * The plugin manager for metatag tags. + * @param \Drupal\metatag\MetatagManagerInterface $metatag_manager + * The metatag manager. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, MetatagTagPluginManager $metatag_plugin_manager, MetatagManagerInterface $metatag_manager) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + $this->metatagTagManager = $metatag_plugin_manager; + $this->metatagManager = $metatag_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.metatag.tag'), + $container->get('metatag.manager') + ); + } + + /** + * Provide a form to edit options for this plugin. + */ + public function buildOptionsForm(&$form, FormStateInterface $form_state) { + + if ($form_state->get('section') == 'metatags') { + $form['#title'] .= t('The meta tags for this display'); + $metatags = $this->getMetatags(); + + // Build/inject the Metatag form. + $form['metatags'] = $this->metatagManager->form($metatags, $form, ['view']); + } + } + + /** + * Validate the options form. + */ + public function validateOptionsForm(&$form, FormStateInterface $form_state) { + } + + /** + * Handle any special handling on the validate form. + */ + public function submitOptionsForm(&$form, FormStateInterface $form_state) { + if ($form_state->get('section') == 'metatags') { + // Process submitted metatag values and remove empty tags. + $tag_values = []; + $metatags = $form_state->cleanValues()->getValues(); + 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. + $tag = $this->metatagTagManager->createInstance($tag_id); + $tag->setValue($tag_value); + if (!empty($tag->value())) { + $tag_values[$tag_id] = $tag->value(); + } + } + $this->options['metatags'] = $tag_values; + } + } + + /** + * Set up any variables on the view prior to execution. + */ + public function preExecute() { + } + + /** + * Inject anything into the query that the display_extender handler needs. + */ + public function query() { + } + + /** + * Provide the default summary for options in the views UI. + * + * This output is returned as an array. + */ + public function optionsSummary(&$categories, &$options) { + $categories['metatags'] = [ + 'title' => t('Meta tags'), + 'column' => 'second', + ]; + $options['metatags'] = [ + 'category' => 'metatags', + 'title' => t('Meta tags'), + 'value' => $this->hasMetatags() ? t('Overridden') : t('Using defaults'), + ]; + } + + /** + * Lists defaultable sections and items contained in each section. + */ + public function defaultableSections(&$sections, $section = NULL) { + } + + /** + * Identify whether or not the current display has custom meta tags defined. + * + * @return bool + * Whether or not the view has overridden metatags. + */ + protected function hasMetatags() { + $metatags = $this->getMetatags(); + return !empty($metatags); + + } + + /** + * Get the Metatag configuration for this display. + * + * @return array + * The meta tag values. + */ + public function getMetatags() { + $metatags = []; + + if (!empty($this->options['metatags'])) { + $metatags = $this->options['metatags']; + } + + return $metatags; + } + + /** + * Sets the meta tags for the given view. + * + * @param array $metatags + * Metatag arrays as suitable for storage. + */ + public function setMetatags(array $metatags) { + $this->options['metatags'] = $metatags; + } + +} diff --git a/web/modules/metatag/metatag_views/templates/config_translation_manage_form_element.html.twig b/web/modules/metatag/metatag_views/templates/config_translation_manage_form_element.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..4c1459be8530622b73e1a6b736da1e29f626d38d --- /dev/null +++ b/web/modules/metatag/metatag_views/templates/config_translation_manage_form_element.html.twig @@ -0,0 +1,23 @@ +{# +/** + * @file + * Default theme implementation for a form element in config_translation. + * + * Available variables: + * - element: Array that represents the element shown in the form. + * - source: The source of the translation. + * - translation: The translation for the target language. + * + * @see template_preprocess() + * + * @ingroup themeable + */ +#} +<div class="translation-set clearfix"> + <div class="layout-column layout-column--half translation-set__source"> + {{ element.source }} + </div> + <div class="layout-column layout-column--half translation-set__translated"> + {{ element.translation }} + </div> +</div> diff --git a/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsBasicsTest.php b/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsBasicsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3aa3e80aac8cc1d24ca5141626c42f81bc888977 --- /dev/null +++ b/web/modules/metatag/metatag_views/tests/src/Functional/MetatagViewsBasicsTest.php @@ -0,0 +1,141 @@ +<?php + +namespace Drupal\Tests\metatag_views\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Confirm the defaults functionality works. + * + * @group panelizer + */ +class MetatagViewsBasicsTest extends BrowserTestBase { + + // Contains helper methods. + use \Drupal\Tests\metatag\Functional\MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public 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 function setUp() { + parent::setUp(); + + // Enable the Bartik theme and make it the default. + $theme = 'bartik'; + \Drupal::service('theme_installer')->install([$theme]); + \Drupal::service('theme_handler')->setDefault($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, + ]); + } + + /** + * Confirm the site isn't broken. + */ + public function testSiteStillWorks() { + // Load the front page. + $this->drupalGet('<front>'); + $this->assertResponse(200); + + // With nothing else configured the front page just has a login form. + $this->assertText('Enter your Drupal username.'); + + // Log in as user 1. + $this->loginUser1(); + + // Load the main Views admin page. + $this->drupalGet('/admin/structure/views'); + $this->assertResponse(200); + + // Enable the Archive view. This should be the first such link while the + // gallery is the second. + $this->clickLink('Enable', 0); + + // Confirm the archive page works. + $this->drupalGet('/archive'); + $this->assertResponse(200); + + // Confirm what the page title looks like by default. + $this->assertTitle('Monthly archive | Drupal'); + + // Load the Arcive view. + $this->drupalGet('/admin/structure/views/view/archive'); + $this->assertResponse(200); + + // Confirm that the Metatag options are present. + $this->assertText('Meta tags:'); + + // Confirm that the page is currently using defaults. + $this->assertText('Using defaults'); + + // Open the 'page' configuration. + $this->clickLink('Page'); + + // Confirm that no changes have been made yet. + $this->assertNoText('Overridden'); + + // Open the settings dialog. + $this->clickLink('Using defaults'); + + // Confirm the settings opened and it has some basic fields. + $this->assertText('Configure the meta tags below.'); + $this->assertFieldByName('title'); + $this->assertFieldByName('description'); + $this->assertFieldByName('op'); + $edit = [ + 'title' => 'Metatag title', + 'description' => 'Metatag description.', + ]; + $this->drupalPostForm(NULL, $edit, 'Apply'); + + // Confirm the Metatag settings are now overridden. + $this->assertText('Overridden'); + + // @todo Confirm there's now a "save" button. + // Save the changes. + $edit = []; + $this->drupalPostForm(NULL, $edit, 'Save'); + + // @todo Confirm the page saved. + // Load the archives page again. + $this->drupalGet('/archive'); + $this->assertResponse(200); + + // Confirm what the page title looks like now. + $this->assertTitle('Metatag title'); + + // Load the Metatag admin page to confirm it still works. + $this->drupalGet('admin/config/search/metatag'); + $this->assertResponse(200); + $this->assertText('Add default meta tags'); + } + +} diff --git a/web/modules/metatag/src/Annotation/MetatagGroup.php b/web/modules/metatag/src/Annotation/MetatagGroup.php new file mode 100644 index 0000000000000000000000000000000000000000..873cdb078f7e90a05db258a9ca7def8796891ef8 --- /dev/null +++ b/web/modules/metatag/src/Annotation/MetatagGroup.php @@ -0,0 +1,44 @@ +<?php + +namespace Drupal\metatag\Annotation; + +use Drupal\Component\Annotation\Plugin; + +/** + * Defines a MetatagGroup annotation object. + * + * @Annotation + */ +class MetatagGroup extends Plugin { + + /** + * The group's internal ID, in machine name format. + * + * @var string + */ + public $id; + + /** + * The name of the group. + * + * @var \Drupal\Core\Annotation\Translation + * + * @ingroup plugin_translatable + */ + public $label; + + /** + * Description of the group. + * + * @var string + */ + public $description; + + /** + * Weight of the group. + * + * @var int + */ + public $weight; + +} diff --git a/web/modules/metatag/src/Annotation/MetatagTag.php b/web/modules/metatag/src/Annotation/MetatagTag.php new file mode 100644 index 0000000000000000000000000000000000000000..948c101f7882bb3a59361ac4d1978fb498018a5a --- /dev/null +++ b/web/modules/metatag/src/Annotation/MetatagTag.php @@ -0,0 +1,90 @@ +<?php + +namespace Drupal\metatag\Annotation; + +use Drupal\Component\Annotation\Plugin; + +/** + * Defines a MetatagTag annotation object. + * + * @Annotation + */ +class MetatagTag extends Plugin { + + /** + * The meta tag plugin's internal ID, in machine name format. + * + * @var string + */ + public $id; + + /** + * The display label/name of the meta tag plugin. + * + * @var \Drupal\Core\Annotation\Translation + * + * @ingroup plugin_translatable + */ + public $label; + + /** + * A longer explanation of what the field is for. + * + * @var \Drupal\Core\Annotation\Translation + * + * @ingroup plugin_translatable + */ + public $description; + + /** + * Proper name of the actual meta tag itself. + * + * @var string + */ + public $name; + + /** + * The group this meta tag fits in, corresponds to a MetatagGroup plugin. + * + * @var string + */ + public $group; + + /** + * Weight of the tag. + * + * @var int + */ + public $weight; + + /** + * Type of the meta tag. + * + * Should be either 'date', 'image', 'integer', 'label', 'string' or 'uri'. + * + * @var string + */ + public $type; + + /** + * True if URL must use HTTPS. + * + * @var bool + */ + protected $secure; + + /** + * True if more than one is allowed. + * + * @var bool + */ + public $multiple; + + /** + * True if the URL value(s) must be absolute. + * + * @var bool + */ + protected $absoluteUrl; + +} diff --git a/web/modules/metatag/src/Command/GenerateGroupCommand.php b/web/modules/metatag/src/Command/GenerateGroupCommand.php new file mode 100644 index 0000000000000000000000000000000000000000..af11ec50a916cec161f8c2948528859c3908ad67 --- /dev/null +++ b/web/modules/metatag/src/Command/GenerateGroupCommand.php @@ -0,0 +1,197 @@ +<?php + +namespace Drupal\metatag\Command; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Command\Command; +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; + +/** + * Class GenerateGroupCommand. + * + * Generate a Metatag group plugin. + * + * @package Drupal\metatag + */ +class GenerateGroupCommand extends Command { + + use CommandTrait; + use ModuleTrait; + use FormTrait; + 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; + + /** + * 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. + */ + public function __construct( + MetatagGroupGenerator $generator, + Manager $extensionManager, + ChainQueue $chainQueue + ) { + $this->generator = $generator; + $this->extensionManager = $extensionManager; + $this->chainQueue = $chainQueue; + + 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', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.common.options.base_class')) + ->addOption('module', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.common.options.module')) + ->addOption('label', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.group.options.label')) + ->addOption('description', '', InputOption::VALUE_OPTIONAL, + $this->trans('commands.generate.metatag.group.options.description')) + ->addOption('plugin-id', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.group.options.plugin_id')) + ->addOption('class-name', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.group.options.class_name')) + ->addOption('weight', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.group.options.weight')); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) { + $io = new DrupalStyle($input, $output); + + // @see Drupal\Console\Command\ConfirmationTrait::confirmGeneration + if (!$this->confirmGeneration($io)) { + return 1; + } + + $base_class = $input->getOption('base_class'); + $module = $input->getOption('module'); + $label = $input->getOption('label'); + $description = $input->getOption('description'); + $plugin_id = $input->getOption('plugin-id'); + $class_name = $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) { + $io = new DrupalStyle($input, $output); + + // --base_class option. + // @todo Turn this into a choice() option. + $base_class = $input->getOption('base_class'); + if (empty($base_class)) { + $base_class = $io->ask( + $this->trans('commands.generate.metatag.group.questions.base_class'), + 'GroupBase' + ); + } + $input->setOption('base_class', $base_class); + + // --module option. + $module = $input->getOption('module'); + if (empty($module)) { + // @see Drupal\AppConsole\Command\Helper\ModuleTrait::moduleQuestion + $module = $this->moduleQuestion($io); + } + $input->setOption('module', $module); + + // --label option. + $label = $input->getOption('label'); + if (empty($label)) { + $label = $io->ask( + $this->trans('commands.generate.metatag.group.questions.label') + ); + } + $input->setOption('label', $label); + + // --description option. + $description = $input->getOption('description'); + if (empty($description)) { + $description = $io->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 = $io->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 (empty($class_name)) { + $class_name = $io->ask( + $this->trans('commands.generate.metatag.group.questions.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 = $io->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 new file mode 100644 index 0000000000000000000000000000000000000000..f5a829aed71f212b7d63b46cd409be04e5cd5204 --- /dev/null +++ b/web/modules/metatag/src/Command/GenerateTagCommand.php @@ -0,0 +1,367 @@ +<?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\MetatagManager; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Class GenerateTagCommand. + * + * Generate a Metatag tag plugin. + * + * @package Drupal\metatag + */ +class GenerateTagCommand extends Command { + + use CommandTrait; + use ModuleTrait; + use FormTrait; + use ConfirmationTrait; + + /** + * The Metatag manager. + * + * @var \Drupal\metatag\MetatagManager + */ + 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; + + /** + * The GenerateTagCommand constructor. + * + * @param \Drupal\metatag\MetatagManager $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. + */ + public function __construct( + MetatagManager $metatagManager, + MetatagTagGenerator $generator, + Manager $extensionManager, + StringConverter $stringConverter, + ChainQueue $chainQueue + ) { + $this->metatagManager = $metatagManager; + $this->generator = $generator; + $this->extensionManager = $extensionManager; + $this->stringConverter = $stringConverter; + $this->chainQueue = $chainQueue; + + 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', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.common.options.base_class')) + ->addOption('module', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.common.options.module')) + ->addOption('name', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.name')) + ->addOption('label', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.label')) + ->addOption('description', '', InputOption::VALUE_OPTIONAL, + $this->trans('commands.generate.metatag.tag.options.description')) + ->addOption('plugin-id', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.plugin_id')) + ->addOption('class-name', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.class_name')) + ->addOption('group', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.group')) + ->addOption('weight', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.weight')) + ->addOption('type', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.type')) + ->addOption('secure', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.secure')) + ->addOption('multiple', '', InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.metatag.tag.options.multiple')); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) { + $io = new DrupalStyle($input, $output); + + // @see Drupal\Console\Command\ConfirmationTrait::confirmGeneration + if (!$this->confirmGeneration($io)) { + return 1; + } + + $base_class = $input->getOption('base_class'); + $module = $input->getOption('module'); + $name = $input->getOption('name'); + $label = $input->getOption('label'); + $description = $input->getOption('description'); + $plugin_id = $input->getOption('plugin-id'); + $class_name = $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) { + + $io = new DrupalStyle($input, $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 = $io->ask( + $this->trans('commands.generate.metatag.tag.questions.base_class'), + 'MetaNameBase' + ); + } + $input->setOption('base_class', $base_class); + + // --module option. + $module = $input->getOption('module'); + if (empty($module)) { + // @see Drupal\AppConsole\Command\Helper\ModuleTrait::moduleQuestion + $module = $this->moduleQuestion($io); + } + $input->setOption('module', $module); + + // --name option. + // @todo Add validation. + $name = $input->getOption('name'); + if (empty($name)) { + $name = $io->ask( + $this->trans('commands.generate.metatag.tag.questions.name') + ); + } + $input->setOption('name', $name); + + // --label option. + $label = $input->getOption('label'); + if (empty($label)) { + $label = $io->ask( + $this->trans('commands.generate.metatag.tag.questions.label'), + $name + ); + } + $input->setOption('label', $label); + + // --description option. + $description = $input->getOption('description'); + if (empty($description)) { + $description = $io->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 = $io->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 (empty($class_name)) { + $class_name = $this->nameToClassName($name); + $class_name = $io->ask( + $this->trans('commands.generate.metatag.tag.questions.class_name'), + $class_name + ); + } + $input->setOption('class-name', $class_name); + + // --group option. + $group = $input->getOption('group'); + if (empty($group)) { + $groups = $this->getGroups(); + $group = $io->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 = $io->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 = $io->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 = $io->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 = $io->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()); + } + + /** + * Confirm that a requested group exists. + * + * @param string $group + * A group's machine name. + * + * @return string + * The group's name, if available, otherwise an empty string. + */ + private function validateGroupExist($group) { + $groups = $this->getGroups(); + if (isset($groups[$group])) { + return $group; + } + return ''; + } + +} diff --git a/web/modules/metatag/src/Entity/MetatagDefaults.php b/web/modules/metatag/src/Entity/MetatagDefaults.php new file mode 100644 index 0000000000000000000000000000000000000000..da9a8efbbdf4093f2fa10a6ad413bde5e9bee7a2 --- /dev/null +++ b/web/modules/metatag/src/Entity/MetatagDefaults.php @@ -0,0 +1,146 @@ +<?php + +namespace Drupal\metatag\Entity; + +use Drupal\Core\Config\Entity\ConfigEntityBase; +use Drupal\Core\Config\Entity\ConfigEntityInterface; +use Drupal\Core\Config\FileStorage; +use Drupal\Core\Config\InstallStorage; +use Drupal\Core\Config\StorageInterface; +use Drupal\metatag\MetatagDefaultsInterface; + +/** + * Defines the Metatag defaults entity. + * + * @ConfigEntityType( + * id = "metatag_defaults", + * label = @Translation("Metatag defaults"), + * handlers = { + * "list_builder" = "Drupal\metatag\MetatagDefaultsListBuilder", + * "form" = { + * "add" = "Drupal\metatag\Form\MetatagDefaultsForm", + * "edit" = "Drupal\metatag\Form\MetatagDefaultsForm", + * "delete" = "Drupal\metatag\Form\MetatagDefaultsDeleteForm", + * "revert" = "Drupal\metatag\Form\MetatagDefaultsRevertForm" + * } + * }, + * config_prefix = "metatag_defaults", + * admin_permission = "administer meta tags", + * entity_keys = { + * "id" = "id", + * "label" = "label" + * }, + * links = { + * "edit-form" = "/admin/config/search/metatag/{metatag_defaults}/edit", + * "delete-form" = "/admin/config/search/metatag/{metatag_defaults}/delete", + * "revert-form" = "/admin/config/search/metatag/{metatag_defaults}/revert", + * "collection" = "/admin/config/search/metatag" + * } + * ) + */ +class MetatagDefaults extends ConfigEntityBase implements MetatagDefaultsInterface { + + /** + * The Metatag defaults ID. + * + * @var string + */ + protected $id; + + /** + * The Metatag defaults label. + * + * @var string + */ + protected $label; + + /** + * The default tag values. + * + * @var array + */ + protected $tags = []; + + /** + * Returns TRUE if a tag exists. + * + * @param string $tag_id + * The identifier of the tag. + * + * @return bool + * TRUE if the tag exists. + */ + public function hasTag($tag_id) { + return array_key_exists($tag_id, $this->tags); + } + + /** + * Returns the value of a tag. + * + * @param string $tag_id + * The identifier of the tag. + * + * @return array|null + * Array containing the tag values or NULL if not found. + */ + public function getTag($tag_id) { + if (!$this->hasTag($tag_id)) { + return NULL; + } + return $this->tags[$tag_id]; + } + + /** + * Reverts an entity to its default values. + */ + public function revert() { + $default_install_path = drupal_get_path('module', '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) { + $this->set('tags', $default_config_data['tags']); + $this->save(); + } + } + + /** + * Overwrite the current tags with new values. + */ + public function overwriteTags(array $new_tags = []) { + if (!empty($new_tags)) { + // Get the existing tags. + $combined_tags = $this->get('tags'); + + // Loop over the new tags, adding them to the existing tags. + foreach ($new_tags as $tag_name => $data) { + $combined_tags[$tag_name] = $data; + } + + // Save the combination of the existing tags + the new tags. + $this->set('tags', $combined_tags); + } + } + + /** + * {@inheritdoc} + */ + public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b) { + // Put always Global in 1st place and front page later if available. + if ($a->id() == 'global') { + return -1; + } + elseif ($b->id() == 'global') { + return 1; + } + elseif ($a->id() == 'front') { + return -1; + } + elseif ($b->id() == 'front') { + return 1; + } + + // Use the default sort function. + return parent::sort($a, $b); + } + +} diff --git a/web/modules/metatag/src/Form/MetatagDefaultsDeleteForm.php b/web/modules/metatag/src/Form/MetatagDefaultsDeleteForm.php new file mode 100644 index 0000000000000000000000000000000000000000..1bc150d52c94b9902d9ec2f8688bbcd7cc1dd675 --- /dev/null +++ b/web/modules/metatag/src/Form/MetatagDefaultsDeleteForm.php @@ -0,0 +1,52 @@ +<?php + +namespace Drupal\metatag\Form; + +use Drupal\Core\Entity\EntityConfirmFormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Url; + +/** + * Builds the form to delete Metatag defaults entities. + */ +class MetatagDefaultsDeleteForm extends EntityConfirmFormBase { + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return $this->t('Are you sure you want to delete %name?', ['%name' => $this->entity->label()]); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl() { + return new Url('entity.metatag_defaults.collection'); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $this->entity->delete(); + + drupal_set_message( + $this->t('Deleted @label defaults.', + [ + '@label' => $this->entity->label(), + ] + ) + ); + + $form_state->setRedirectUrl($this->getCancelUrl()); + } + +} diff --git a/web/modules/metatag/src/Form/MetatagDefaultsForm.php b/web/modules/metatag/src/Form/MetatagDefaultsForm.php new file mode 100644 index 0000000000000000000000000000000000000000..ee2997237e034ef6bf4efd5d20a221451a3a466d --- /dev/null +++ b/web/modules/metatag/src/Form/MetatagDefaultsForm.php @@ -0,0 +1,319 @@ +<?php + +namespace Drupal\metatag\Form; + +use Drupal\Core\Entity\ContentEntityType; +use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Form\FormStateInterface; +use Drupal\metatag\MetatagManager; +use Drupal\page_manager\Entity\PageVariant; + +/** + * Class MetatagDefaultsForm. + * + * @package Drupal\metatag\Form + */ +class MetatagDefaultsForm extends EntityForm { + + /** + * {@inheritdoc} + */ + public function form(array $form, FormStateInterface $form_state) { + $form = parent::form($form, $form_state); + $metatag_defaults = $this->entity; + $metatag_manager = \Drupal::service('metatag.manager'); + + $form['#ajax_wrapper_id'] = 'metatag-defaults-form-ajax-wrapper'; + $ajax = [ + 'wrapper' => $form['#ajax_wrapper_id'], + 'callback' => '::rebuildForm', + ]; + $form['#prefix'] = '<div id="' . $form['#ajax_wrapper_id'] . '">'; + $form['#suffix'] = '</div>'; + + $default_type = NULL; + if (!empty($metatag_defaults)) { + $default_type = $metatag_defaults->getOriginalId(); + } + else { + $form_state->set('default_type', $default_type); + } + + $token_types = empty($default_type) ? [] : [explode('__', $default_type)[0]]; + + // Add the token browser at the top. + $form += \Drupal::service('metatag.token')->tokenBrowser($token_types); + + // If this is a new Metatag defaults, then list available bundles. + if ($metatag_defaults->isNew()) { + $options = $this->getAvailableBundles(); + $form['id'] = [ + '#type' => 'select', + '#title' => $this->t('Type'), + '#description' => $this->t('Select the type of default meta tags you would like to add.'), + '#options' => $options, + '#required' => TRUE, + '#default_value' => $default_type, + '#ajax' => $ajax + [ + 'trigger_as' => [ + 'name' => 'select_id_submit', + ], + ], + ]; + $form['select_id_submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Submit'), + '#name' => 'select_id_submit', + '#ajax' => $ajax, + '#attributes' => [ + 'class' => ['js-hide'], + ], + ]; + $values = []; + } + else { + $values = $metatag_defaults->get('tags'); + } + + // Retrieve configuration settings. + $settings = $this->config('metatag.settings'); + $entity_type_groups = $settings->get('entity_type_groups'); + + // Find the current entity type and bundle. + $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; + + // 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 = $metatag_manager->form($values, $form, [$entity_type], $groups); + } + // Otherwise, display all groups. + else { + $form = $metatag_manager->form($values, $form); + } + + return $form; + } + + /** + * Ajax form submit handler that will return the whole rebuilt form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return array + * The form structure. + */ + public function rebuildForm(array &$form, FormStateInterface $form_state) { + return $form; + } + + /** + * {@inheritdoc} + */ + protected function actions(array $form, FormStateInterface $form_state) { + $actions = parent::actions($form, $form_state); + if (isset($actions['delete'])) { + $actions['delete']['#access'] = $actions['delete']['#access'] && !in_array($this->entity->id(), MetatagManager::protectedDefaults()); + } + return $actions; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + if ($form_state->getTriggeringElement()['#name'] == 'select_id_submit') { + $form_state->set('default_type', $form_state->getValue('id')); + $form_state->setRebuild(); + } + else { + parent::submitForm($form, $form_state); + } + } + + /** + * {@inheritdoc} + */ + public function save(array $form, FormStateInterface $form_state) { + $metatag_defaults = $this->entity; + + // Set the label on new defaults. + if ($metatag_defaults->isNew()) { + $metatag_defaults_id = $form_state->getValue('id'); + + $type_parts = explode('__', $metatag_defaults_id); + $entity_type = $type_parts[0]; + $entity_bundle = isset($type_parts[1]) ? $type_parts[1] : NULL; + + // Get the entity label. + $entity_manager = \Drupal::service('entity_type.manager'); + $entity_info = $entity_manager->getDefinitions(); + $entity_label = (string) $entity_info[$entity_type]->get('label'); + + if (!is_null($entity_bundle)) { + // Get the bundle label. + $bundle_manager = \Drupal::service('entity_type.bundle.info'); + $bundle_info = $bundle_manager->getBundleInfo($entity_type); + if ($entity_type === 'page_variant') { + // Check if page manager is enabled and try to load the page variant + // so the label of the variant can be used. + $moduleHandler = \Drupal::service('module_handler'); + if ($moduleHandler->moduleExists('metatag_page_manager')) { + $page_variant = PageVariant::load($entity_bundle); + $page = $page_variant->getPage(); + if ($page_variant) { + $entity_label .= ': ' . $page->label() . ': ' . $page_variant->label(); + } + } + } + else { + $entity_label .= ': ' . $bundle_info[$entity_bundle]['label']; + } + } + + // Set the label to the config entity. + $this->entity->set('label', $entity_label); + } + + // Set tags within the Metatag entity. + $tag_manager = \Drupal::service('plugin.manager.metatag.tag'); + $tags = $tag_manager->getDefinitions(); + $tag_values = []; + foreach ($tags as $tag_id => $tag_definition) { + if ($form_state->hasValue($tag_id)) { + // Some plugins need to process form input before storing it. Hence, we + // set it and then get it. + $tag = $tag_manager->createInstance($tag_id); + $tag->setValue($form_state->getValue($tag_id)); + if (!empty($tag->value())) { + $tag_values[$tag_id] = $tag->value(); + } + } + } + $metatag_defaults->set('tags', $tag_values); + $status = $metatag_defaults->save(); + + switch ($status) { + case SAVED_NEW: + drupal_set_message($this->t('Created the %label Metatag defaults.', [ + '%label' => $metatag_defaults->label(), + ])); + break; + + default: + drupal_set_message($this->t('Saved the %label Metatag defaults.', [ + '%label' => $metatag_defaults->label(), + ])); + } + + $form_state->setRedirectUrl($metatag_defaults->toUrl('collection')); + } + + /** + * Returns an array of available bundles to override. + * + * @return array + * A list of available bundles as $id => $label. + */ + protected function getAvailableBundles() { + $options = []; + $entity_types = static::getSupportedEntityTypes(); + /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager */ + $entity_manager = \Drupal::service('entity_type.manager'); + /** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info */ + $bundle_info = \Drupal::service('entity_type.bundle.info'); + $metatags_defaults_manager = $entity_manager->getStorage('metatag_defaults'); + foreach ($entity_types as $entity_type => $entity_label) { + if (empty($metatags_defaults_manager->load($entity_type))) { + $options[$entity_label][$entity_type] = "$entity_label (Default)"; + } + + $bundles = $bundle_info->getBundleInfo($entity_type); + foreach ($bundles as $bundle_id => $bundle_metadata) { + $metatag_defaults_id = $entity_type . '__' . $bundle_id; + + if (empty($metatags_defaults_manager->load($metatag_defaults_id))) { + $options[$entity_label][$metatag_defaults_id] = $bundle_metadata['label']; + } + } + } + return $options; + } + + /** + * Returns a list of supported entity types. + * + * @return array + * A list of available entity types as $machine_name => $label. + */ + public static function getSupportedEntityTypes() { + $entity_types = []; + + /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager */ + $entity_manager = \Drupal::service('entity_type.manager'); + + // A list of entity types that are not supported. + $unsupported_types = [ + // Custom blocks. + 'block_content', + // Comments. + 'comment', + // Contact messages are the messages submitted on individual contact forms + // so obviously shouldn't get meta tags. + 'contact_message', + // Menu items. + 'menu_link_content', + // Shortcut items. + 'shortcut', + ]; + + // Make a list of supported content types. + foreach ($entity_manager->getDefinitions() as $entity_name => $definition) { + // Skip some entity types that we don't want to support. + if (in_array($entity_name, $unsupported_types)) { + continue; + } + + // Identify supported entities. + if ($definition instanceof ContentEntityType) { + // Only work with entity types that have a list of links, i.e. publicly + // viewable. + $links = $definition->get('links'); + if (!empty($links)) { + $entity_types[$entity_name] = static::getEntityTypeLabel($definition); + } + } + } + + return $entity_types; + } + + /** + * Returns the text label for the entity type specified. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entityType + * The entity type to process. + * + * @return string + * A label. + */ + public static function getEntityTypeLabel(EntityTypeInterface $entityType) { + $label = $entityType->getLabel(); + + if (is_a($label, 'Drupal\Core\StringTranslation\TranslatableMarkup')) { + /** @var \Drupal\Core\StringTranslation\TranslatableMarkup $label */ + $label = $label->render(); + } + + return $label; + } + +} diff --git a/web/modules/metatag/src/Form/MetatagDefaultsRevertForm.php b/web/modules/metatag/src/Form/MetatagDefaultsRevertForm.php new file mode 100644 index 0000000000000000000000000000000000000000..5d224117dee8f97e28b777bb0626dcc045976a98 --- /dev/null +++ b/web/modules/metatag/src/Form/MetatagDefaultsRevertForm.php @@ -0,0 +1,52 @@ +<?php + +namespace Drupal\metatag\Form; + +use Drupal\Core\Entity\EntityConfirmFormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Url; + +/** + * Builds the form to revert Metatag defaults entities. + */ +class MetatagDefaultsRevertForm extends EntityConfirmFormBase { + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return $this->t('Are you sure you want to revert %name to its default values?', ['%name' => $this->entity->label()]); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl() { + return new Url('entity.metatag_defaults.collection'); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Revert'); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $this->entity->revert(); + + drupal_set_message( + $this->t('Reverted @label defaults.', + [ + '@label' => $this->entity->label(), + ] + ) + ); + + $form_state->setRedirectUrl($this->getCancelUrl()); + } + +} diff --git a/web/modules/metatag/src/Form/MetatagSettingsForm.php b/web/modules/metatag/src/Form/MetatagSettingsForm.php new file mode 100644 index 0000000000000000000000000000000000000000..a77e2460326c0c324fb39d75ed2a7e6dd6f28f3c --- /dev/null +++ b/web/modules/metatag/src/Form/MetatagSettingsForm.php @@ -0,0 +1,104 @@ +<?php + +namespace Drupal\metatag\Form; + +use Drupal\Core\Form\ConfigFormBase; +use Drupal\Core\Form\FormStateInterface; + +/** + * Defines the configuration export form. + */ +class MetatagSettingsForm extends ConfigFormBase { + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'metatag_admin_settings'; + } + + /** + * {@inheritdoc} + */ + protected function getEditableConfigNames() { + return ['metatag.settings']; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $settings = $this->config('metatag.settings')->get('entity_type_groups'); + + $form['entity_type_groups'] = [ + '#type' => 'details', + '#open' => TRUE, + '#title' => $this->t('Entity type / Group Mapping'), + '#description' => $this->t('Identify which metatag groups should be available on which entity type / bundle combination. Unselected groups will not appear on the configuration form for that entity type, reducing the size of the form and increasing performance. If no groups are selected for a type, all groups will appear.'), + '#tree' => TRUE, + ]; + + $metatag_manager = \Drupal::service('metatag.manager'); + $bundle_manager = \Drupal::service('entity_type.bundle.info'); + $metatag_groups = $metatag_manager->sortedGroups(); + $entity_types = MetatagDefaultsForm::getSupportedEntityTypes(); + foreach ($entity_types as $entity_type => $entity_label) { + $bundles = $bundle_manager->getBundleInfo($entity_type); + foreach ($bundles as $bundle_id => $bundle_info) { + // Create an option list for each bundle. + $options = []; + foreach ($metatag_groups as $group_name => $group_info) { + $options[$group_name] = $group_info['label']; + } + // Format a collapsible fieldset for each group for easier readability. + $form['entity_type_groups'][$entity_type][$bundle_id] = [ + '#type' => 'details', + '#title' => $entity_label . ': ' . $bundle_info['label'], + ]; + $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] : [], + ]; + } + } + + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $settings = $this->config('metatag.settings'); + $value = $form_state->getValue('entity_type_groups'); + $value = static::arrayFilterRecursive($value); + // Remove the extra layer created by collapsible fieldsets. + foreach ($value as $entity_type => $bundle) { + foreach ($bundle as $bundle_id => $groups) { + $value[$entity_type][$bundle_id] = $groups[0]; + } + } + $settings->set('entity_type_groups', $value)->save(); + parent::submitForm($form, $form_state); + } + + /** + * Recursively filter results. + * + * @param array $input + * The array to filter. + * + * @return array + * The filtered array. + */ + public static function arrayFilterRecursive(array $input) { + foreach ($input as &$value) { + if (is_array($value)) { + $value = static::arrayFilterRecursive($value); + } + } + return array_filter($input); + } + +} diff --git a/web/modules/metatag/src/Generator/MetatagGroupGenerator.php b/web/modules/metatag/src/Generator/MetatagGroupGenerator.php new file mode 100644 index 0000000000000000000000000000000000000000..9b737e30239f5c3747ba1ec7de89f22455e06682 --- /dev/null +++ b/web/modules/metatag/src/Generator/MetatagGroupGenerator.php @@ -0,0 +1,80 @@ +<?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 new file mode 100644 index 0000000000000000000000000000000000000000..ba089b64a285b5898a1f6c6b2b53d5002a5d7a79 --- /dev/null +++ b/web/modules/metatag/src/Generator/MetatagTagGenerator.php @@ -0,0 +1,102 @@ +<?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/MetatagDefaultsInterface.php b/web/modules/metatag/src/MetatagDefaultsInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..36b2bd80d946930c1f9547c81c191742189f657c --- /dev/null +++ b/web/modules/metatag/src/MetatagDefaultsInterface.php @@ -0,0 +1,12 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Core\Config\Entity\ConfigEntityInterface; + +/** + * Provides an interface for defining Metatag defaults entities. + */ +interface MetatagDefaultsInterface extends ConfigEntityInterface { + // Add get/set methods for your configuration properties here. +} diff --git a/web/modules/metatag/src/MetatagDefaultsListBuilder.php b/web/modules/metatag/src/MetatagDefaultsListBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..0b4945009cf1504169edceb86e0509cbb8cbe870 --- /dev/null +++ b/web/modules/metatag/src/MetatagDefaultsListBuilder.php @@ -0,0 +1,141 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Core\Config\Entity\ConfigEntityListBuilder; +use Drupal\Core\Entity\EntityInterface; + +/** + * Provides a listing of Metatag defaults entities. + */ +class MetatagDefaultsListBuilder extends ConfigEntityListBuilder { + + /** + * {@inheritdoc} + */ + protected function getEntityIds() { + $query = $this->getStorage()->getQuery() + ->condition('id', 'global', '<>'); + + // Only add the pager if a limit is specified. + if ($this->limit) { + $query->pager($this->limit); + } + + $entity_ids = $query->execute(); + + // Load global entity always. + return $entity_ids + $this->getParentIds($entity_ids); + } + + /** + * Gets the parent entity ids for the list of entities to load. + * + * @param array $entity_ids + * The metatag entity ids. + * + * @return array + * The list of parents to load + */ + protected function getParentIds(array $entity_ids) { + $parents = ['global' => 'global']; + foreach ($entity_ids as $entity_id) { + if (strpos($entity_id, '__') !== FALSE) { + $entity_id_array = explode('__', $entity_id); + $parent = reset($entity_id_array); + $parents[$parent] = $parent; + } + } + $parents_query = $this->getStorage()->getQuery() + ->condition('id', $parents, 'IN'); + return $parents_query->execute(); + } + + /** + * {@inheritdoc} + */ + public function buildHeader() { + $header['label'] = $this->t('Type'); + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + $row['label'] = $this->getLabelAndConfig($entity); + return $row + parent::buildRow($entity); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + $operations = parent::getOperations($entity); + + // Global and entity defaults can be reverted but not deleted. + if (in_array($entity->id(), MetatagManager::protectedDefaults())) { + unset($operations['delete']); + $operations['revert'] = [ + 'title' => t('Revert'), + 'weight' => $operations['edit']['weight'] + 1, + 'url' => $entity->toUrl('revert-form'), + ]; + } + + return $operations; + } + + /** + * Renders the Metatag defaults label plus its configuration. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The Metatag defaults entity. + * + * @return array + * Render array for a table cell. + */ + public function getLabelAndConfig(EntityInterface $entity) { + $output = '<div>'; + $prefix = ''; + $inherits = ''; + if ($entity->id() != 'global') { + $prefix = '<div class="indentation"></div>'; + $inherits .= 'Global'; + } + if (strpos($entity->id(), '__') !== FALSE) { + $prefix .= '<div class="indentation"></div>'; + list($entity_label, $bundle_label) = explode(': ', $entity->get('label')); + $inherits .= ', ' . $entity_label; + } + + if (!empty($inherits)) { + $output .= '<div><p>' . t('Inherits meta tags from: @inherits', [ + '@inherits' => $inherits, + ]) . '</p></div>'; + } + $tags = $entity->get('tags'); + if (count($tags)) { + $output .= '<table> +<tbody>'; + foreach ($tags as $tag_id => $tag_value) { + $output .= '<tr><td>' . $tag_id . ':</td><td>' . $tag_value . '</td></tr>'; + } + $output .= '</tbody></table>'; + } + + $output .= '</div></div>'; + + return [ + 'data' => [ + '#type' => 'details', + '#prefix' => $prefix, + '#title' => $entity->label(), + 'config' => [ + '#markup' => $output, + ], + ], + ]; + } + +} diff --git a/web/modules/metatag/src/MetatagGroupPluginManager.php b/web/modules/metatag/src/MetatagGroupPluginManager.php new file mode 100644 index 0000000000000000000000000000000000000000..b019ca9eb3fa553c40852a04582792c59bc0bec8 --- /dev/null +++ b/web/modules/metatag/src/MetatagGroupPluginManager.php @@ -0,0 +1,30 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Plugin\DefaultPluginManager; + +/** + * A Plugin to manage your meta tag group. + */ +class MetatagGroupPluginManager extends DefaultPluginManager { + + /** + * {@inheritdoc} + */ + public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { + $subdir = 'Plugin/metatag/Group'; + + // The name of the annotation class that contains the plugin definition. + $plugin_definition_annotation_name = 'Drupal\metatag\Annotation\MetatagGroup'; + + parent::__construct($subdir, $namespaces, $module_handler, NULL, $plugin_definition_annotation_name); + + $this->alterInfo('metatag_groups'); + + $this->setCacheBackend($cache_backend, 'metatag_groups'); + } + +} diff --git a/web/modules/metatag/src/MetatagManager.php b/web/modules/metatag/src/MetatagManager.php new file mode 100644 index 0000000000000000000000000000000000000000..57c4ca281d92288cd59cf74a4b4416aacd3a5ba6 --- /dev/null +++ b/web/modules/metatag/src/MetatagManager.php @@ -0,0 +1,578 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Component\Render\PlainTextOutput; +use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Logger\LoggerChannelFactoryInterface; +use Drupal\views\ViewEntityInterface; + +/** + * Class MetatagManager. + * + * @package Drupal\metatag + */ +class MetatagManager implements MetatagManagerInterface { + + /** + * The group plugin manager. + * + * @var \Drupal\metatag\MetatagGroupPluginManager + */ + protected $groupPluginManager; + + /** + * The tag plugin manager. + * + * @var \Drupal\metatag\MetatagTagPluginManager + */ + protected $tagPluginManager; + + /** + * The Metatag defaults. + * + * @var array + */ + protected $metatagDefaults; + + /** + * The Metatag token. + * + * @var \Drupal\metatag\MetatagToken + */ + protected $tokenService; + + /** + * The Metatag logging channel. + * + * @var \Drupal\Core\Logger\LoggerChannelInterface + */ + protected $logger; + + /** + * Constructor for MetatagManager. + * + * @param \Drupal\metatag\MetatagGroupPluginManager $groupPluginManager + * The MetatagGroupPluginManager object. + * @param \Drupal\metatag\MetatagTagPluginManager $tagPluginManager + * The MetatagTagPluginMÏ€anager 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. + */ + public function __construct(MetatagGroupPluginManager $groupPluginManager, + MetatagTagPluginManager $tagPluginManager, + MetatagToken $token, + LoggerChannelFactoryInterface $channelFactory, + EntityTypeManagerInterface $entityTypeManager) { + $this->groupPluginManager = $groupPluginManager; + $this->tagPluginManager = $tagPluginManager; + $this->tokenService = $token; + $this->logger = $channelFactory->get('metatag'); + $this->metatagDefaults = $entityTypeManager->getStorage('metatag_defaults'); + } + + /** + * Returns the list of protected defaults. + * + * @return array + * Th protected defaults. + */ + public static function protectedDefaults() { + return [ + 'global', + '403', + '404', + 'node', + 'front', + 'taxonomy_term', + 'user', + ]; + } + + /** + * {@inheritdoc} + */ + public function tagsFromEntity(ContentEntityInterface $entity) { + $tags = []; + + $fields = $this->getFields($entity); + + /* @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); + } + + return $tags; + } + + /** + * {@inheritdoc} + */ + public function tagsFromEntityWithDefaults(ContentEntityInterface $entity) { + return $this->tagsFromEntity($entity) + $this->defaultTagsFromEntity($entity); + } + + /** + * {@inheritdoc} + */ + public function defaultTagsFromEntity(ContentEntityInterface $entity) { + /** @var \Drupal\metatag\Entity\MetatagDefaults $metatags */ + $metatags = $this->metatagDefaults->load('global'); + if (!$metatags) { + return NULL; + } + // Add/overwrite with tags set on the entity type. + $entity_type_tags = $this->metatagDefaults->load($entity->getEntityTypeId()); + if (!is_null($entity_type_tags)) { + $metatags->overwriteTags($entity_type_tags->get('tags')); + } + // Add/overwrite with tags set on the entity bundle. + $bundle_metatags = $this->metatagDefaults->load($entity->getEntityTypeId() . '__' . $entity->bundle()); + if (!is_null($bundle_metatags)) { + $metatags->overwriteTags($bundle_metatags->get('tags')); + } + return $metatags->get('tags'); + } + + /** + * Gets the group plugin definitions. + * + * @return array + * Group definitions. + */ + protected function groupDefinitions() { + return $this->groupPluginManager->getDefinitions(); + } + + /** + * Gets the tag plugin definitions. + * + * @return array + * Tag definitions + */ + protected function tagDefinitions() { + return $this->tagPluginManager->getDefinitions(); + } + + /** + * {@inheritdoc} + */ + public function sortedGroups() { + $metatag_groups = $this->groupDefinitions(); + + // Pull the data from the definitions into a new array. + $groups = []; + 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]['weight'] = $group_info['weight']; + } + + // Create the 'sort by' array. + $sort_by = []; + foreach ($groups as $group) { + $sort_by[] = $group['weight']; + } + + // Sort the groups by weight. + array_multisort($sort_by, SORT_ASC, $groups); + + return $groups; + } + + /** + * {@inheritdoc} + */ + public function sortedTags() { + $metatag_tags = $this->tagDefinitions(); + + // Pull the data from the definitions into a new array. + $tags = []; + foreach ($metatag_tags as $tag_name => $tag_info) { + $tags[$tag_name]['id'] = $tag_info['id']; + $tags[$tag_name]['label'] = $tag_info['label']->render(); + $tags[$tag_name]['group'] = $tag_info['group']; + $tags[$tag_name]['weight'] = $tag_info['weight']; + } + + // Create the 'sort by' array. + $sort_by = []; + foreach ($tags as $key => $tag) { + $sort_by['group'][$key] = $tag['group']; + $sort_by['weight'][$key] = $tag['weight']; + } + + // Sort the tags by weight. + array_multisort($sort_by['group'], SORT_ASC, $sort_by['weight'], SORT_ASC, $tags); + + return $tags; + } + + /** + * {@inheritdoc} + */ + public function sortedGroupsWithTags() { + $groups = $this->sortedGroups(); + $tags = $this->sortedTags(); + + foreach ($tags as $tag_name => $tag) { + $tag_group = $tag['group']; + + 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]); + $tag['group'] = 'basic'; + $tag_group = 'basic'; + } + + $groups[$tag_group]['tags'][$tag_name] = $tag; + } + + return $groups; + } + + /** + * {@inheritdoc} + */ + public function form(array $values, array $element, array $token_types = [], array $included_groups = NULL, array $included_tags = NULL) { + // Add the outer fieldset. + $element += [ + '#type' => 'details', + ]; + + $element += $this->tokenService->tokenBrowser($token_types); + + $groups_and_tags = $this->sortedGroupsWithTags(); + + foreach ($groups_and_tags as $group_name => $group) { + // Only act on groups that have tags and are in the list of included + // groups (unless that list is null). + if (isset($group['tags']) && (is_null($included_groups) || in_array($group_name, $included_groups) || in_array($group['id'], $included_groups))) { + // Create the fieldset. + $element[$group_name]['#type'] = 'details'; + $element[$group_name]['#title'] = $group['label']; + $element[$group_name]['#description'] = $group['description']; + $element[$group_name]['#open'] = FALSE; + + foreach ($group['tags'] as $tag_name => $tag) { + // Only act on tags in the included tags list, unless that is null. + if (is_null($included_tags) || in_array($tag_name, $included_tags) || in_array($tag['id'], $included_tags)) { + // Make an instance of the tag. + $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->setValue($tag_value); + + // Open any groups that have non-empty values. + if (!empty($tag_value)) { + $element[$group_name]['#open'] = TRUE; + } + + // Create the bit of form for this tag. + $element[$group_name][$tag_name] = $tag->form($element); + } + } + } + } + + return $element; + } + + /** + * Returns a list of the Metatag fields on an entity. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The entity to examine. + * + * @return array + * The fields from the entity which are Metatag fields. + */ + protected function getFields(ContentEntityInterface $entity) { + $field_list = []; + + if ($entity instanceof ContentEntityInterface) { + // Get a list of the metatag field types. + $field_types = $this->fieldTypes(); + + // Get a list of the field definitions on this entity. + $definitions = $entity->getFieldDefinitions(); + + // Iterate through all the fields looking for ones in our list. + foreach ($definitions as $field_name => $definition) { + // Get the field type, ie: metatag. + $field_type = $definition->getType(); + + // Check the field type against our list of fields. + if (isset($field_type) && in_array($field_type, $field_types)) { + $field_list[$field_name] = $definition; + } + } + } + + return $field_list; + } + + /** + * Returns a list of the meta tags with values from a field. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The ContentEntityInterface object. + * @param string $field_name + * The name of the field to work on. + * + * @return array + * Array of field tags. + */ + protected function getFieldTags(ContentEntityInterface $entity, $field_name) { + $tags = []; + foreach ($entity->{$field_name} as $item) { + // 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); + } + } + + return $tags; + } + + /** + * Returns default meta tags for an entity. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The entity to work on. + * + * @return array + * The default meta tags appropriate for this entity. + */ + public function getDefaultMetatags(ContentEntityInterface $entity = NULL) { + // Get general global metatags. + $metatags = $this->getGlobalMetatags(); + // If that is empty something went wrong. + if (!$metatags) { + return; + } + + // Check if this is a special page. + $special_metatags = $this->getSpecialMetatags(); + + // Merge with all globals defaults. + if ($special_metatags) { + $metatags->set('tags', array_merge($metatags->get('tags'), $special_metatags->get('tags'))); + } + + // Next check if there is this page is an entity that has meta tags. + // @todo Think about using other defaults, e.g. views. Maybe use plugins? + else { + if (is_null($entity)) { + $entity = metatag_get_route_entity(); + } + + if (!empty($entity)) { + // Get default meta tags for a given entity. + $entity_defaults = $this->getEntityDefaultMetatags($entity); + if ($entity_defaults != NULL) { + $metatags->set('tags', array_merge($metatags->get('tags'), $entity_defaults)); + } + } + } + + return $metatags->get('tags'); + } + + /** + * Returns global meta tags. + * + * @return array + * The global meta tags. + */ + public function getGlobalMetatags() { + return $this->metatagDefaults->load('global'); + } + + /** + * Returns special meta tags. + * + * @return array + * The defaults for this page, if it's a special page. + */ + public function getSpecialMetatags() { + $metatags = NULL; + + if (\Drupal::service('path.matcher')->isFrontPage()) { + $metatags = $this->metatagDefaults->load('front'); + } + elseif (\Drupal::service('current_route_match')->getRouteName() == 'system.403') { + $metatags = $this->metatagDefaults->load('403'); + } + elseif (\Drupal::service('current_route_match')->getRouteName() == 'system.404') { + $metatags = $this->metatagDefaults->load('404'); + } + + return $metatags; + } + + /** + * Returns default meta tags for an entity. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The entity to work with. + * + * @return array + * The appropriate default meta tags. + */ + public function getEntityDefaultMetatags(ContentEntityInterface $entity) { + $entity_metatags = $this->metatagDefaults->load($entity->getEntityTypeId()); + $metatags = []; + if ($entity_metatags != NULL) { + // Merge with global defaults. + $metatags = array_merge($metatags, $entity_metatags->get('tags')); + } + + // Finally, check if we should apply bundle overrides. + $bundle_metatags = $this->metatagDefaults->load($entity->getEntityTypeId() . '__' . $entity->bundle()); + if ($bundle_metatags != NULL) { + // Merge with existing defaults. + $metatags = array_merge($metatags, $bundle_metatags->get('tags')); + } + + return $metatags; + } + + /** + * 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) { + $elements = []; + $tags = $this->generateRawElements($tags, $entity); + + foreach ($tags as $name => $tag) { + if (!empty($tag)) { + $elements['#attached']['html_head'][] = [ + $tag, + $name, + ]; + } + } + + return $elements; + } + + /** + * 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. + * + * @return array + * Render array with tag elements. + */ + public function generateRawElements(array $tags, $entity = NULL) { + // Ignore the update.php path. + $request = \Drupal::request(); + if ($request->getBaseUrl() == '/update.php') { + return []; + } + + $rawTags = []; + + $metatag_tags = $this->tagPluginManager->getDefinitions(); + + // Order the elements by weight first, as some systems like Facebook care. + uksort($tags, function ($tag_name_a, $tag_name_b) use ($metatag_tags) { + $weight_a = isset($metatag_tags[$tag_name_a]['weight']) ? $metatag_tags[$tag_name_a]['weight'] : 0; + $weight_b = isset($metatag_tags[$tag_name_b]['weight']) ? $metatag_tags[$tag_name_b]['weight'] : 0; + + return ($weight_a < $weight_b) ? -1 : 1; + }); + + // Each element of the $values array is a tag with the tag plugin name as + // the key. + foreach ($tags as $tag_name => $value) { + // Check to ensure there is a matching plugin. + if (isset($metatag_tags[$tag_name])) { + // Get an instance of the plugin. + $tag = $this->tagPluginManager->createInstance($tag_name); + + // Render any tokens in the value. + $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. + // @todo Can we move this into metatag_views somehow? + $token_replacements = ['view' => $entity->getExecutable()]; + } + elseif ($entity instanceof ContentEntityInterface) { + $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(); + + $processed_value = PlainTextOutput::renderFromHtml(htmlspecialchars_decode($this->tokenService->replace($tag->value(), $token_replacements, ['langcode' => $langcode]))); + + // Now store the value with processed tokens back into the plugin. + $tag->setValue($processed_value); + + // Have the tag generate the output based on the value we gave it. + $output = $tag->output(); + + if (!empty($output)) { + $output = $tag->multiple() ? $output : [$output]; + + // Backwards compatibility for modules which don't support this logic. + if (isset($output['#tag'])) { + $output = [$output]; + } + + foreach ($output as $index => $element) { + // Add index to tag name as suffix to avoid having same key. + $index_tag_name = $tag->multiple() ? $tag_name . '_' . $index : $tag_name; + $rawTags[$index_tag_name] = $element; + } + } + } + } + + return $rawTags; + } + + /** + * Returns a list of fields handled by Metatag. + * + * @return array + * A list of supported field types. + */ + protected function fieldTypes() { + // @todo Either get this dynamically from field plugins or forget it and + // just hardcode metatag where this is called. + return ['metatag']; + } + +} diff --git a/web/modules/metatag/src/MetatagManagerInterface.php b/web/modules/metatag/src/MetatagManagerInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..0cc060cbc35fdd5a1e84133473eda2d148a7b8fb --- /dev/null +++ b/web/modules/metatag/src/MetatagManagerInterface.php @@ -0,0 +1,98 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Core\Entity\ContentEntityInterface; + +/** + * Class MetatagManager. + * + * @package Drupal\metatag + */ +interface MetatagManagerInterface { + + /** + * Extracts all tags of a given entity. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The content entity to extract meta tags from. + * + * @return array + * Array of metatags. + */ + public function tagsFromEntity(ContentEntityInterface $entity); + + /** + * Extracts all tags of a given entity. + * + * And combines them with sitewide, per-entity-type, and per-bundle defaults. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The content entity to extract meta tags from. + * + * @return array + * Array of metatags. + */ + public function tagsFromEntityWithDefaults(ContentEntityInterface $entity); + + /** + * Extracts all appropriate default tags for an entity. + * + * From sitewide, per-entity-type, and per-bundle defaults. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The content entity for which to calculate defaults. + * + * @return array + * Array of metatags. + */ + public function defaultTagsFromEntity(ContentEntityInterface $entity); + + /** + * Returns an array of group plugin information sorted by weight. + * + * @return array + * Array of groups, sorted by weight. + */ + public function sortedGroups(); + + /** + * Returns an array of tag plugin information sorted by group then weight. + * + * @return array + * Array of tags, sorted by weight. + */ + public function sortedTags(); + + /** + * Returns a weighted array of groups containing their weighted tags. + * + * @return array + * Array of sorted tags, in groups. + */ + public function sortedGroupsWithTags(); + + /** + * Builds the form element for a Metatag field. + * + * If a list of either groups or tags are passed in, those will be used to + * limit the groups/tags on the form. If nothing is passed in, all groups + * and tags will be used. + * + * @param array $values + * Existing values. + * @param array $element + * Existing element. + * @param array $token_types + * Token types to return in the tree. + * @param array $included_groups + * Available group plugins. + * @param array $included_tags + * Available tag plugins. + * + * @return array + * Render array for metatag form. + */ + public function form(array $values, array $element, array $token_types = [], array $included_groups = NULL, array $included_tags = NULL); + +} diff --git a/web/modules/metatag/src/MetatagServiceProvider.php b/web/modules/metatag/src/MetatagServiceProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..811485a407bb83c2b362e6e975935e1f9fda387c --- /dev/null +++ b/web/modules/metatag/src/MetatagServiceProvider.php @@ -0,0 +1,40 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\DependencyInjection\ServiceProviderBase; +use Drupal\metatag\Normalizer\FieldItemNormalizer; +use Drupal\metatag\Normalizer\MetatagHalNormalizer; +use Drupal\metatag\Normalizer\MetatagNormalizer; +use Symfony\Component\DependencyInjection\Definition; + +/** + * Service Provider for Metatag. + */ +class MetatagServiceProvider extends ServiceProviderBase { + + /** + * {@inheritdoc} + */ + public function alter(ContainerBuilder $container) { + $modules = $container->getParameter('container.modules'); + if (isset($modules['serialization'])) { + // Serialization module is enabled, add our metatag normalizers. + // Priority of the metatag normalizer must be higher than other + // general-purpose typed data and field item normalizers. + $metatag = new Definition(MetatagNormalizer::class); + $metatag->addTag('normalizer', ['priority' => 30]); + $container->setDefinition('metatag.normalizer.metatag', $metatag); + + $metatag_hal = new Definition(MetatagHalNormalizer::class); + $metatag_hal->addTag('normalizer', ['priority' => 31]); + $container->setDefinition('metatag.normalizer.metatag.hal', $metatag_hal); + + $metatag_field = new Definition(FieldItemNormalizer::class); + $metatag_field->addTag('normalizer', ['priority' => 30]); + $container->setDefinition('metatag.normalizer.metatag_field', $metatag_field); + } + } + +} diff --git a/web/modules/metatag/src/MetatagTagPluginManager.php b/web/modules/metatag/src/MetatagTagPluginManager.php new file mode 100644 index 0000000000000000000000000000000000000000..06562fed2450748cff77a986974113bdbf7efb7f --- /dev/null +++ b/web/modules/metatag/src/MetatagTagPluginManager.php @@ -0,0 +1,30 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Plugin\DefaultPluginManager; + +/** + * A Plugin to manage your meta tag type. + */ +class MetatagTagPluginManager extends DefaultPluginManager { + + /** + * {@inheritdoc} + */ + public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { + $subdir = 'Plugin/metatag/Tag'; + + // The name of the annotation class that contains the plugin definition. + $plugin_definition_annotation_name = 'Drupal\metatag\Annotation\MetatagTag'; + + parent::__construct($subdir, $namespaces, $module_handler, NULL, $plugin_definition_annotation_name); + + $this->alterInfo('metatag_tags'); + + $this->setCacheBackend($cache_backend, 'metatag_tags'); + } + +} diff --git a/web/modules/metatag/src/MetatagToken.php b/web/modules/metatag/src/MetatagToken.php new file mode 100644 index 0000000000000000000000000000000000000000..e240fc01994145541b5b80372fb7dbb70a9d1b08 --- /dev/null +++ b/web/modules/metatag/src/MetatagToken.php @@ -0,0 +1,95 @@ +<?php + +namespace Drupal\metatag; + +use Drupal\Core\Utility\Token; +use Drupal\Core\Render\BubbleableMetadata; + +/** + * Token handling service. Uses core token service or contributed Token. + */ +class MetatagToken { + + /** + * Token service. + * + * @var \Drupal\Core\Utility\Token + */ + protected $token; + + /** + * Constructs a new MetatagToken object. + * + * @param \Drupal\Core\Utility\Token $token + * Token service. + */ + public function __construct(Token $token) { + $this->token = $token; + } + + /** + * Wrapper for the Token module's string parsing. + * + * @param string $string + * The string to parse. + * @param array $data + * Arguments for token->replace(). + * @param array $options + * Any additional options necessary. + * @param \Drupal\Core\Render\BubbleableMetadata|null $bubbleable_metadata + * (optional) An object to which static::generate() and the hooks and + * functions that it invokes will add their required bubbleable metadata. + * + * @return mixed|string + * The processed string. + */ + public function replace($string, array $data = [], array $options = [], BubbleableMetadata $bubbleable_metadata = NULL) { + // Set default requirements for metatag unless options specify otherwise. + $options = $options + [ + 'clear' => TRUE, + ]; + + $replaced = $this->token->replace($string, $data, $options, $bubbleable_metadata); + + // Ensure that there are no double-slash sequences due to empty token + // values. + $replaced = preg_replace('/(?<!:)(?<!)\/+\//', '/', $replaced); + + return $replaced; + } + + /** + * Gatekeeper function to direct to either the core or contributed Token. + * + * @param array $token_types + * The token types to filter the tokens list by. Defaults to an empty array. + * + * @return array + * If token module is installed, a popup browser plus a help text. If not + * only the help text. + */ + public function tokenBrowser(array $token_types = []) { + $form = []; + + $form['intro_text'] = [ + '#markup' => '<p>' . t('<strong>Configure the meta tags below.</strong><br /> To view a summary of the individual meta tags and the pattern for a specific configuration, click on its name below. Use tokens to avoid redundant meta data and search engine penalization. For example, a \'keyword\' value of "example" will be shown on all content using this configuration, whereas using the [node:field_keywords] automatically inserts the "keywords" values from the current entity (node, term, etc).') . '</p>', + ]; + + // Normalize taxonomy tokens. + if (!empty($token_types)) { + $token_types = array_map(function ($value) { + return stripos($value, 'taxonomy_') === 0 ? substr($value, strlen('taxonomy_')) : $value; + }, (array) $token_types); + } + + $form['tokens'] = [ + '#theme' => 'token_tree_link', + '#token_types' => $token_types, + '#global_types' => TRUE, + '#show_nested' => FALSE, + ]; + + return $form; + } + +} diff --git a/web/modules/metatag/src/Normalizer/FieldItemNormalizer.php b/web/modules/metatag/src/Normalizer/FieldItemNormalizer.php new file mode 100644 index 0000000000000000000000000000000000000000..c567750fe648e7e182c2ffc72bd591d5d7a14c08 --- /dev/null +++ b/web/modules/metatag/src/Normalizer/FieldItemNormalizer.php @@ -0,0 +1,28 @@ +<?php + +namespace Drupal\metatag\Normalizer; + +use Drupal\serialization\Normalizer\NormalizerBase; + +/** + * Converts the Metatag field item object structure to METATAG array structure. + */ +class FieldItemNormalizer extends NormalizerBase { + + /** + * {@inheritdoc} + */ + protected $supportedInterfaceOrClass = 'Drupal\metatag\Plugin\Field\FieldType\MetatagFieldItem'; + + /** + * {@inheritdoc} + */ + public function normalize($field_item, $format = NULL, array $context = []) { + $values = $field_item->getValue(); + + $normalized['value'] = unserialize($values['value']); + + return $normalized; + } + +} diff --git a/web/modules/metatag/src/Normalizer/MetatagHalNormalizer.php b/web/modules/metatag/src/Normalizer/MetatagHalNormalizer.php new file mode 100644 index 0000000000000000000000000000000000000000..03c26361cd8a9890e3c345b0521718d8f7621128 --- /dev/null +++ b/web/modules/metatag/src/Normalizer/MetatagHalNormalizer.php @@ -0,0 +1,28 @@ +<?php + +namespace Drupal\metatag\Normalizer; + +/** + * Converts the Metatag field item object structure to Metatag array structure. + */ +class MetatagHalNormalizer extends MetatagNormalizer { + + /** + * {@inheritdoc} + */ + protected $format = ['hal_json']; + + /** + * {@inheritdoc} + */ + public function normalize($field_item, $format = NULL, array $context = []) { + $normalized = parent::normalize($field_item, $format, $context); + + // Mock the field array similar to the other fields. + // @see Drupal\hal\Normalizer\FieldItemNormalizer + return [ + 'metatag' => [$normalized], + ]; + } + +} diff --git a/web/modules/metatag/src/Normalizer/MetatagNormalizer.php b/web/modules/metatag/src/Normalizer/MetatagNormalizer.php new file mode 100644 index 0000000000000000000000000000000000000000..32837dcd68897f70671666db91559c1a0cd6f666 --- /dev/null +++ b/web/modules/metatag/src/Normalizer/MetatagNormalizer.php @@ -0,0 +1,53 @@ +<?php + +namespace Drupal\metatag\Normalizer; + +use Drupal\serialization\Normalizer\NormalizerBase; + +/** + * Normalizes metatag into the viewed entity. + */ +class MetatagNormalizer extends NormalizerBase { + + /** + * {@inheritdoc} + */ + protected $supportedInterfaceOrClass = 'Drupal\metatag\Plugin\Field\MetatagEntityFieldItemList'; + + /** + * {@inheritdoc} + */ + public function normalize($field_item, $format = NULL, array $context = []) { + // @see metatag_get_tags_from_route() + $entity = $field_item->getEntity(); + + $tags = metatag_get_tags_from_route($entity); + + $normalized['value'] = []; + if (isset($tags['#attached']['html_head'])) { + foreach ($tags['#attached']['html_head'] as $tag) { + // @todo Work out a proper, long-term fix for this. + if (isset($tag[0]['#attributes']['content'])) { + $normalized['value'][$tag[1]] = $tag[0]['#attributes']['content']; + } + elseif (isset($tag[0]['#attributes']['href'])) { + $normalized['value'][$tag[1]] = $tag[0]['#attributes']['href']; + } + } + } + + if (isset($context['langcode'])) { + $normalized['lang'] = $context['langcode']; + } + + return $normalized; + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = NULL) { + return FALSE; + } + +} diff --git a/web/modules/metatag/src/Plugin/DataType/Metatag.php b/web/modules/metatag/src/Plugin/DataType/Metatag.php new file mode 100644 index 0000000000000000000000000000000000000000..75717996772c42be9a5264ec8fed9036727f03b6 --- /dev/null +++ b/web/modules/metatag/src/Plugin/DataType/Metatag.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\metatag\Plugin\DataType; + +use Drupal\Core\TypedData\Plugin\DataType\StringData; + +/** + * The metatag data type. + * + * The plain value of a metatag is a serialized object represented as a string. + * + * @DataType( + * id = "metatag", + * label = @Translation("Metatag") + * ) + */ +class Metatag extends StringData implements MetatagInterface { + +} diff --git a/web/modules/metatag/src/Plugin/DataType/MetatagInterface.php b/web/modules/metatag/src/Plugin/DataType/MetatagInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..5d41d282461cea1f709859a6ef0efda4a17a427a --- /dev/null +++ b/web/modules/metatag/src/Plugin/DataType/MetatagInterface.php @@ -0,0 +1,14 @@ +<?php + +namespace Drupal\metatag\Plugin\DataType; + +use Drupal\Core\TypedData\PrimitiveInterface; + +/** + * The metatag data type. + * + * The plain value of a metatag is a serialized object represented as a string. + */ +interface MetatagInterface extends PrimitiveInterface { + +} diff --git a/web/modules/metatag/src/Plugin/Field/FieldFormatter/MetatagEmptyFormatter.php b/web/modules/metatag/src/Plugin/Field/FieldFormatter/MetatagEmptyFormatter.php new file mode 100644 index 0000000000000000000000000000000000000000..06b6877d38118681b743beca95f6ff6e0c93ab87 --- /dev/null +++ b/web/modules/metatag/src/Plugin/Field/FieldFormatter/MetatagEmptyFormatter.php @@ -0,0 +1,30 @@ +<?php + +namespace Drupal\metatag\Plugin\Field\FieldFormatter; + +use Drupal\Core\Field\FormatterBase; +use Drupal\Core\Field\FieldItemListInterface; + +/** + * Plugin implementation of the 'metatag_empty_formatter' formatter. + * + * @FieldFormatter( + * id = "metatag_empty_formatter", + * module = "metatag", + * label = @Translation("Empty formatter"), + * field_types = { + * "metatag" + * } + * ) + */ +class MetatagEmptyFormatter extends FormatterBase { + + /** + * {@inheritdoc} + */ + public function viewElements(FieldItemListInterface $items, $langcode) { + // Does not actually output anything. + return []; + } + +} diff --git a/web/modules/metatag/src/Plugin/Field/FieldType/MetatagFieldItem.php b/web/modules/metatag/src/Plugin/Field/FieldType/MetatagFieldItem.php new file mode 100644 index 0000000000000000000000000000000000000000..1a6726a8040839f0dcc17790bef36581b7bc6ccc --- /dev/null +++ b/web/modules/metatag/src/Plugin/Field/FieldType/MetatagFieldItem.php @@ -0,0 +1,88 @@ +<?php + +namespace Drupal\metatag\Plugin\Field\FieldType; + +use Drupal\Core\Field\FieldItemBase; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; + +/** + * Plugin implementation of the 'metatag' field type. + * + * @FieldType( + * id = "metatag", + * label = @Translation("Meta tags"), + * description = @Translation("This field stores code meta tags."), + * default_widget = "metatag_firehose", + * default_formatter = "metatag_empty_formatter" + * ) + */ +class MetatagFieldItem extends FieldItemBase { + + /** + * {@inheritdoc} + */ + public static function schema(FieldStorageDefinitionInterface $field_definition) { + return [ + 'columns' => [ + 'value' => [ + 'type' => 'text', + 'size' => 'big', + 'not null' => FALSE, + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { + $properties['value'] = DataDefinition::create('metatag') + ->setLabel(t('Metatag')) + ->setRequired(TRUE); + + return $properties; + } + + /** + * {@inheritdoc} + */ + public function isEmpty() { + $value = $this->get('value')->getValue(); + return $value === NULL || $value === '' || $value === serialize([]); + } + + /** + * {@inheritdoc} + */ + public function preSave() { + parent::preSave(); + + // Merge field defaults on top of global ones. + $default_tags = metatag_get_default_tags(); + + // Get the value about to be saved. + $current_value = $this->value; + // Only unserialize if still serialized string. + if (is_string($current_value)) { + $current_tags = unserialize($current_value); + } + else { + $current_tags = $current_value; + } + + // Only include values that differ from the default. + // @todo When site defaults are added, account for those. + $tags_to_save = []; + foreach ($current_tags as $tag_id => $tag_value) { + if (!isset($default_tags[$tag_id]) || ($tag_value != $default_tags[$tag_id])) { + $tags_to_save[$tag_id] = $tag_value; + } + } + + // 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 new file mode 100644 index 0000000000000000000000000000000000000000..6797f59ae6a4d181ba79120144ce89d5a2ee5d45 --- /dev/null +++ b/web/modules/metatag/src/Plugin/Field/FieldWidget/MetatagFirehose.php @@ -0,0 +1,129 @@ +<?php + +namespace Drupal\metatag\Plugin\Field\FieldWidget; + +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\metatag\MetatagManager; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Advanced widget for metatag field. + * + * @FieldWidget( + * id = "metatag_firehose", + * label = @Translation("Advanced meta tags form"), + * field_types = { + * "metatag" + * } + * ) + */ +class MetatagFirehose extends WidgetBase implements ContainerFactoryPluginInterface { + + /** + * Instance of MetatagManager service. + * + * @var \Drupal\metatag\MetatagManager + */ + protected $metatagManager; + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $plugin_id, + $plugin_definition, + $configuration['field_definition'], + $configuration['settings'], + $configuration['third_party_settings'], + $container->get('metatag.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, MetatagManager $manager) { + parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings); + $this->metatagManager = $manager; + } + + /** + * {@inheritdoc} + */ + public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { + $item = $items[$delta]; + $default_tags = metatag_get_default_tags(); + + // Retrieve the values for each metatag from the serialized array. + $values = []; + if (!empty($item->value)) { + $values = unserialize($item->value); + } + + // Populate fields which have not been overridden in the entity. + if (!empty($default_tags)) { + foreach ($default_tags as $tag_id => $tag_value) { + if (!isset($values[$tag_id]) && !empty($tag_value)) { + $values[$tag_id] = $tag_value; + } + } + } + + // Retrieve configuration settings. + $settings = \Drupal::config('metatag.settings'); + $entity_type_groups = $settings->get('entity_type_groups'); + + // Find the current entity type and bundle. + $entity_type = $item->getEntity()->getentityTypeId(); + $entity_bundle = $item->getEntity()->bundle(); + + // 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)) { + $element = $this->metatagManager->form($values, $element, [$entity_type], $groups); + } + // Otherwise, display all groups. + else { + $element = $this->metatagManager->form($values, $element, [$entity_type]); + } + + // Put the form element into the form's "advanced" group. + $element['#group'] = 'advanced'; + + return $element; + } + + /** + * {@inheritdoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { + // Flatten the values array to remove the groups and then serialize all the + // meta tags into one value for storage. + $tag_manager = \Drupal::service('plugin.manager.metatag.tag'); + foreach ($values as &$value) { + $flattened_value = []; + foreach ($value as $group) { + // Exclude the "original delta" value. + if (is_array($group)) { + foreach ($group as $tag_id => $tag_value) { + $tag = $tag_manager->createInstance($tag_id); + $tag->setValue($tag_value); + if (!empty($tag->value())) { + $flattened_value[$tag_id] = $tag->value(); + } + } + } + } + $value = serialize($flattened_value); + } + + return $values; + } + +} diff --git a/web/modules/metatag/src/Plugin/Field/MetatagEntityFieldItemList.php b/web/modules/metatag/src/Plugin/Field/MetatagEntityFieldItemList.php new file mode 100644 index 0000000000000000000000000000000000000000..69c11265edd0c5311c294de6a7f24dd064eac9b2 --- /dev/null +++ b/web/modules/metatag/src/Plugin/Field/MetatagEntityFieldItemList.php @@ -0,0 +1,11 @@ +<?php + +namespace Drupal\metatag\Plugin\Field; + +use Drupal\Core\Field\FieldItemList; + +/** + * Defines a metatag list class for better normalization targeting. + */ +class MetatagEntityFieldItemList extends FieldItemList { +} diff --git a/web/modules/metatag/src/Plugin/GraphQL/Scalars/MetatagScalar.php b/web/modules/metatag/src/Plugin/GraphQL/Scalars/MetatagScalar.php new file mode 100644 index 0000000000000000000000000000000000000000..105ef536689f72c4bc5e90f66b72f23ed314e794 --- /dev/null +++ b/web/modules/metatag/src/Plugin/GraphQL/Scalars/MetatagScalar.php @@ -0,0 +1,20 @@ +<?php + +namespace Drupal\metatag\Plugin\GraphQL\Scalars; + +use Drupal\graphql\Plugin\GraphQL\Scalars\Internal\StringScalar; + +/** + * Metatag module dummy type. + * + * Metatag module defines a custom data type that essentially is a string, but + * not called "string", which causes the GraphQL type system chokes. + * + * @GraphQLScalar( + * id = "metatag", + * name = "metatag", + * type = "string" + * ) + */ +class MetatagScalar extends StringScalar { +} diff --git a/web/modules/metatag/src/Plugin/metatag/Group/Advanced.php b/web/modules/metatag/src/Plugin/metatag/Group/Advanced.php new file mode 100644 index 0000000000000000000000000000000000000000..ab76679f5294e8c07f5e6364990aa4496058dde1 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Group/Advanced.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Group; + +/** + * The advanced group. + * + * @MetatagGroup( + * id = "advanced", + * label = @Translation("Advanced"), + * description = @Translation("Meta tags that might not be needed by many sites."), + * weight = 2 + * ) + */ +class Advanced extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Group/Basic.php b/web/modules/metatag/src/Plugin/metatag/Group/Basic.php new file mode 100644 index 0000000000000000000000000000000000000000..26705acf7acc592318fd885b56c063031e5e6f65 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Group/Basic.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Group; + +/** + * The basic group. + * + * @MetatagGroup( + * id = "basic", + * label = @Translation("Basic tags"), + * description = @Translation("Simple meta tags."), + * weight = 1 + * ) + */ +class Basic extends GroupBase { + // Inherits everything from Base. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Group/GroupBase.php b/web/modules/metatag/src/Plugin/metatag/Group/GroupBase.php new file mode 100644 index 0000000000000000000000000000000000000000..0c2770ce8d168b72b243a8c86c80930a36789304 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Group/GroupBase.php @@ -0,0 +1,88 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Group; + +use Drupal\Component\Plugin\PluginBase; + +/** + * Each group will extend this base. + */ +abstract class GroupBase extends PluginBase { + + /** + * Machine name of the meta tag group plugin. + * + * @var string + */ + protected $id; + + /** + * The name of the group. + * + * @var \Drupal\Core\Annotation\Translation + * + * @ingroup plugin_translatable + */ + protected $label; + + /** + * Description of the group. + * + * @var string + */ + protected $description; + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, array $plugin_definition) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + // Set the properties from the annotation. + // @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']; + } + + /** + * Get this group's internal ID. + * + * @return string + * This group's ID. + */ + public function id() { + return $this->id; + } + + /** + * Get this group's human-friendly name. + * + * @return string + * This group's human-friendly name. + */ + public function label() { + return $this->label; + } + + /** + * This group object's description. + * + * @return string + * This group's ID. + */ + public function description() { + return $this->description; + } + + /** + * Whether or not this group is being used. + * + * @return bool + * Whether this group has been enabled. + */ + public function isActive() { + return TRUE; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/AbstractTag.php b/web/modules/metatag/src/Plugin/metatag/Tag/AbstractTag.php new file mode 100644 index 0000000000000000000000000000000000000000..d8786110ece26b6d2496266584496827ad4fc482 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/AbstractTag.php @@ -0,0 +1,38 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Abstract" meta tag. + * + * @MetatagTag( + * id = "abstract", + * label = @Translation("Abstract"), + * description = @Translation("A brief and concise summary of the page's content, preferably 150 characters or less. Where as the description meta tag may be used by search engines to display a snippet about the page in search results, the abstract tag may be used to archive a summary about the page. This meta tag is <em>no longer</em> supported by major search engines."), + * name = "abstract", + * group = "basic", + * weight = 3, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class AbstractTag extends MetaNameBase { + + /** + * Generate a form element for this meta tag. + */ + public function form(array $element = []) { + $form = [ + '#type' => 'textarea', + '#title' => $this->label(), + '#default_value' => $this->value(), + '#row' => 2, + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#description' => $this->description(), + '#element_validate' => [[get_class($this), 'validateTag']], + ]; + return $form; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/CanonicalUrl.php b/web/modules/metatag/src/Plugin/metatag/Tag/CanonicalUrl.php new file mode 100644 index 0000000000000000000000000000000000000000..9b2f85a25100ac6440c516c9c43c36dbb295d67f --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/CanonicalUrl.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'canonical' meta tag. + * + * @MetatagTag( + * id = "canonical_url", + * label = @Translation("Canonical URL"), + * description = @Translation("A link to the preferred page location or URL of the content of this page, to help eliminate duplicate content penalties from search engines."), + * name = "canonical", + * group = "advanced", + * weight = 1, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class CanonicalUrl extends LinkRelBase { + // 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 new file mode 100644 index 0000000000000000000000000000000000000000..dfc0942e20a0b713c76a2102bdfcf73527a19018 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/ContentLanguage.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The advanced "Content Language" meta tag. + * + * @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."), + * name = "content-language", + * group = "advanced", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..7616d77fd2830e35a604c0dbeacb63cfda762d2c --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Description.php @@ -0,0 +1,38 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Description" meta tag. + * + * @MetatagTag( + * id = "description", + * label = @Translation("Description"), + * description = @Translation("A brief and concise summary of the page's content, preferably 320 characters or less. The description meta tag may be used by search engines to display a snippet about the page in search results."), + * name = "description", + * group = "basic", + * weight = 2, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Description extends MetaNameBase { + + /** + * Generate a form element for this meta tag. + */ + public function form(array $element = []) { + $form = [ + '#type' => 'textarea', + '#title' => $this->label(), + '#default_value' => $this->value(), + '#row' => 2, + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#description' => $this->description(), + '#element_validate' => [[get_class($this), 'validateTag']], + ]; + return $form; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Generator.php b/web/modules/metatag/src/Plugin/metatag/Tag/Generator.php new file mode 100644 index 0000000000000000000000000000000000000000..23f19bba47c6b9c6179b12bbd213151b4cb52d2f --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Generator.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Generator" meta tag. + * + * @MetatagTag( + * id = "generator", + * label = @Translation("Generator"), + * description = @Translation("Describes the name and version number of the software or publishing tool used to create the page."), + * name = "generator", + * group = "advanced", + * weight = 4, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Generator extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/GeoPlacename.php b/web/modules/metatag/src/Plugin/metatag/Tag/GeoPlacename.php new file mode 100644 index 0000000000000000000000000000000000000000..c8c3a7f8d0f2e7497ad783cd515f36d2a90ae3a9 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/GeoPlacename.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'geo.placename' meta tag. + * + * @MetatagTag( + * id = "geo_placename", + * label = @Translation("Geographical place name"), + * description = @Translation("A location's formal name."), + * name = "geo.placename", + * group = "advanced", + * weight = 0, + * type = "label", + * secure = 0, + * multiple = FALSE + * ) + */ +class GeoPlacename extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/GeoPosition.php b/web/modules/metatag/src/Plugin/metatag/Tag/GeoPosition.php new file mode 100644 index 0000000000000000000000000000000000000000..c50d7c6b220603576ec5afa4392ea17da60cc8c4 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/GeoPosition.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'geo.position' meta tag. + * + * @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>."), + * name = "geo.position", + * group = "advanced", + * weight = 0, + * type = "label", + * secure = 0, + * multiple = FALSE + * ) + */ +class GeoPosition extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/GeoRegion.php b/web/modules/metatag/src/Plugin/metatag/Tag/GeoRegion.php new file mode 100644 index 0000000000000000000000000000000000000000..b939e462f5e1e17dbcb77e26827f7d5bb6f6696a --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/GeoRegion.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'geo.region' meta tag. + * + * @MetatagTag( + * id = "geo_region", + * label = @Translation("Geographical region"), + * description = @Translation("A location's two-letter international country code, with an optional two-letter region, e.g. 'US-NH' for New Hampshire in the USA."), + * name = "geo.region", + * group = "advanced", + * weight = 0, + * type = "label", + * secure = 0, + * multiple = FALSE + * ) + */ +class GeoRegion extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Google.php b/web/modules/metatag/src/Plugin/metatag/Tag/Google.php new file mode 100644 index 0000000000000000000000000000000000000000..0f81d955dc421eac0371651418302b5f89d32329 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Google.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'google' meta tag. + * + * @MetatagTag( + * id = "google", + * label = @Translation("Google"), + * description = @Translation("This meta tag communicates with Google. There are currently two directives supported: 'nositelinkssearchbox' to not to show the sitelinks search box, and 'notranslate' to ask Google not to offer a translation of the page. Both options may be added, just separate them with a comma. See <a href='https://support.google.com/webmasters/answer/79812?hl=en'>meta tags that Google understands</a> for further details."), + * name = "google", + * group = "advanced", + * weight = 5, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Google extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Icbm.php b/web/modules/metatag/src/Plugin/metatag/Tag/Icbm.php new file mode 100644 index 0000000000000000000000000000000000000000..078d2c7a968a27aa3697964b72e130b3df673a7b --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Icbm.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'icbm' meta tag. + * + * @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>."), + * name = "icbm", + * group = "advanced", + * weight = 0, + * type = "label", + * secure = 0, + * multiple = FALSE + * ) + */ +class Icbm extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/ImageSrc.php b/web/modules/metatag/src/Plugin/metatag/Tag/ImageSrc.php new file mode 100644 index 0000000000000000000000000000000000000000..6c9fe3eaafe1aeb6e8aea7e4d4ee61858fd243a7 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/ImageSrc.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The advanced "Image" meta tag. + * + * @MetatagTag( + * id = "image_src", + * label = @Translation("Image"), + * description = @Translation("An image associated with this page, for use as a thumbnail in social networks and other services."), + * name = "image_src", + * group = "advanced", + * weight = 4, + * type = "image", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ImageSrc extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Keywords.php b/web/modules/metatag/src/Plugin/metatag/Tag/Keywords.php new file mode 100644 index 0000000000000000000000000000000000000000..fd59665d1504f87fefa9b26a1e57ddf02391873e --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Keywords.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Keywords" meta tag. + * + * @MetatagTag( + * id = "keywords", + * label = @Translation("Keywords"), + * description = @Translation("A comma-separated list of keywords about the page. This meta tag is <em>no longer</em> supported by most search engines."), + * name = "keywords", + * group = "basic", + * weight = 4, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Keywords extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/LinkRelBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/LinkRelBase.php new file mode 100644 index 0000000000000000000000000000000000000000..449ce2fb4991cfe45d6bff2834323c277cc69a16 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/LinkRelBase.php @@ -0,0 +1,27 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * This base plugin allows "link rel" tags to be further customized. + */ +abstract class LinkRelBase extends MetaNameBase { + + /** + * {@inheritdoc} + */ + 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']); + } + + return $element; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaHttpEquivBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaHttpEquivBase.php new file mode 100644 index 0000000000000000000000000000000000000000..607d6bf75ee9b0fae1c39f54d18c190295950874 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaHttpEquivBase.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * This base plugin allows "http-equiv"-style meta tags to be customized. + * + * Used with e.g. the content language meta tag. + */ +abstract class MetaHttpEquivBase extends MetaNameBase { + + /** + * {@inheritdoc} + */ + protected $nameAttribute = 'http-equiv'; + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaItempropBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaItempropBase.php new file mode 100644 index 0000000000000000000000000000000000000000..802e247fae2223e55e09ecd52b5e66b21d114122 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaItempropBase.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * This base plugin allows "itemprop"-style meta tags be customized. + * + * Used with e.g. the Google Plus tags. + */ +abstract class MetaItempropBase extends MetaNameBase { + + /** + * {@inheritdoc} + */ + protected $nameAttribute = 'itemprop'; + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaNameBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaNameBase.php new file mode 100644 index 0000000000000000000000000000000000000000..9212571ef2f17a72784f639114a21ca0165919cb --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaNameBase.php @@ -0,0 +1,413 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +use Drupal\Component\Plugin\PluginBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; + +/** + * Each meta tag will extend this base. + */ +abstract class MetaNameBase extends PluginBase { + + use StringTranslationTrait; + + /** + * Machine name of the meta tag plugin. + * + * @var string + */ + protected $id; + + /** + * Official metatag name. + * + * @var string + */ + protected $name; + + /** + * The title of the plugin. + * + * @var \Drupal\Core\Annotation\Translation + * + * @ingroup plugin_translatable + */ + protected $label; + + /** + * A longer explanation of what the field is for. + * + * @var \Drupal\Core\Annotation\Translation + * + * @ingroup plugin_translatable + */ + protected $description; + + /** + * The category this meta tag fits in. + * + * @var string + */ + protected $group; + + /** + * Type of the value being stored. + * + * @var string + */ + protected $type; + + /** + * True if URL must use HTTPS. + * + * @var bool + */ + protected $secure; + + /** + * True if more than one is allowed. + * + * @var bool + */ + protected $multiple; + + /** + * True if the URL value(s) must be absolute. + * + * @var bool + */ + protected $absoluteUrl; + + /** + * Retrieves the currently active request object. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + + /** + * The value of the metatag in this instance. + * + * @var mixed + */ + protected $value; + + /** + * The attribute this tag uses for the name. + * + * @var string + */ + protected $nameAttribute = 'name'; + + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, array $plugin_definition) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + // Set the properties from the annotation. + // @todo Should we have setProperty() methods for each of these? + $this->id = $plugin_definition['id']; + $this->name = $plugin_definition['name']; + $this->label = $plugin_definition['label']; + $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->absoluteUrl = !empty($plugin_definition['absolute_url']); + $this->request = \Drupal::request(); + } + + /** + * Obtain the meta tag's internal ID. + * + * @return string + * This meta tag's internal ID. + */ + public function id() { + return $this->id; + } + + /** + * This meta tag's label. + * + * @return string + * The label. + */ + public function label() { + return $this->label; + } + + /** + * The meta tag's description. + * + * @return bool + * This meta tag's description. + */ + public function description() { + return $this->description; + } + + /** + * The meta tag's machine name. + * + * @return string + * This meta tag's machine name. + */ + public function name() { + return $this->name; + } + + /** + * The meta tag group this meta tag belongs to. + * + * @return string + * The meta tag's group name. + */ + public function group() { + return $this->group; + } + + /** + * This meta tag's form field's weight. + * + * @return int|float + * The form API weight for this. May be any number supported by Form API. + */ + public function weight() { + return $this->weight; + } + + /** + * Obtain this meta tag's type. + * + * @return string + * This meta tag's type. + */ + public function type() { + return $this->type; + } + + /** + * 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 secure() { + return $this->secure; + } + + /** + * Whether or not this meta tag supports multiple values. + * + * @return bool + * Whether or not this meta tag supports multiple values. + */ + public function multiple() { + return $this->multiple; + } + + /** + * Whether or not this meta tag must output required absolute URLs. + * + * @return bool + * Whether or not this meta tag must output required absolute URLs. + */ + public function requiresAbsoluteUrl() { + return $this->absoluteUrl; + } + + /** + * Whether or not this meta tag is active. + * + * @return bool + * Whether this meta tag has been enabled. + */ + public function isActive() { + return TRUE; + } + + /** + * Generate a form element for this meta tag. + * + * @param array $element + * The existing form element to attach to. + * + * @return array + * The completed form element. + */ + public function form(array $element = []) { + $form = [ + '#type' => 'textfield', + '#title' => $this->label(), + '#default_value' => $this->value(), + '#maxlength' => 255, + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#description' => $this->description(), + '#element_validate' => [[get_class($this), 'validateTag']], + ]; + + // Optional handling for items that allow multiple values. + if (!empty($this->multiple)) { + $form['#description'] .= ' ' . $this->t('Multiple values may be used, separated by a comma. Note: Tokens that return multiple values will be handled automatically.'); + } + + // Optional handling for images. + if ((!empty($this->type())) && ($this->type() === 'image')) { + $form['#description'] .= ' ' . $this->t('This will be able to extract the URL from an image field.'); + } + + if (!empty($this->absolute_url)) { + $form['#description'] .= ' ' . $this->t('Any relative or protocol-relative URLs will be converted to absolute URLs.'); + } + + // Optional handling for secure paths. + if (!empty($this->secure)) { + $form['#description'] .= ' ' . $this->t('Any links containing http:// will be converted to https://'); + } + + return $form; + } + + /** + * Obtain the current meta tag's raw value. + * + * @return string + * The current raw meta tag value. + */ + public function value() { + return $this->value; + } + + /** + * Assign the current meta tag a value. + * + * @param string $value + * The value to assign this meta tag. + */ + public function setValue($value) { + $this->value = $value; + } + + /** + * Make the string presentable. + * + * @param string $value + * The raw string to process. + * + * @return string + * The meta tag value after processing. + */ + private function tidy($value) { + return trim($value); + } + + /** + * Generate the HTML tag output for a meta tag. + * + * @return array|string + * A render array or an empty string. + */ + public function output() { + if (empty($this->value)) { + // If there is no value, we don't want a tag output. + return $this->multiple() ? [] : ''; + } + + // Parse out the image URL, if needed. + $value = $this->parseImageUrl(); + $values = $this->multiple() ? explode(',', $value) : [$value]; + $elements = []; + foreach ($values as $value) { + $value = $this->tidy($value); + if ($this->requiresAbsoluteUrl()) { + // Relative URL. + if (parse_url($value, PHP_URL_HOST) == NULL) { + $value = $this->request->getSchemeAndHttpHost() . $value; + } + // Protocol-relative URL. + elseif (substr($value, 0, 2) === '//') { + $value = $this->request->getScheme() . ':' . $value; + } + } + + // If tag must be secure, convert all http:// to https://. + if ($this->secure() && strpos($value, 'http://') !== FALSE) { + $value = str_replace('http://', 'https://', $value); + } + + $elements[] = [ + '#tag' => 'meta', + '#attributes' => [ + $this->nameAttribute => $this->name, + 'content' => $value, + ], + ]; + } + + return $this->multiple() ? $elements : reset($elements); + } + + /** + * Validates the metatag data. + * + * @param array $element + * The form element to process. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + */ + public static function validateTag(array &$element, FormStateInterface $form_state) { + // @todo If there is some common validation, put it here. Otherwise, make + // it abstract? + } + + /** + * Extract any image URLs that might be found in a meta tag. + * + * @return string + * A comma separated list of any image URLs found in the meta tag's value, + * or the original string if no images were identified. + */ + protected function parseImageUrl() { + $value = $this->value(); + + // If this contains embedded image tags, extract the image URLs. + if ($this->type() === 'image') { + // If image tag src is relative (starts with /), convert to an absolute + // link; ignore protocol-relative URLs. + global $base_root; + if (strpos($value, '<img src="/') !== FALSE && strpos($value, '<img src="//') === FALSE) { + $value = str_replace('<img src="/', '<img src="' . $base_root . '/', $value); + } + + if ($this->multiple()) { + // Split the string into an array, remove empty items. + $values = array_filter(explode(',', $value)); + } + else { + $values = [$value]; + } + + // Check through the value(s) to see if there are any image tags. + foreach ($values as $key => $val) { + $matches = []; + preg_match('/src="([^"]*)"/', $val, $matches); + if (!empty($matches[1])) { + $values[$key] = $matches[1]; + } + } + $value = implode(',', $values); + + // Remove any HTML tags that might remain. + $value = strip_tags($value); + } + + return $value; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/MetaPropertyBase.php b/web/modules/metatag/src/Plugin/metatag/Tag/MetaPropertyBase.php new file mode 100644 index 0000000000000000000000000000000000000000..c242d23cf15a1bc1476e2c3b87986f2ed0837ab3 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/MetaPropertyBase.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * This base plugin allows "property"-style meta tags tobe customized. + * + * Used with e.g. the Open Graph tags. + */ +abstract class MetaPropertyBase extends MetaNameBase { + + /** + * {@inheritdoc} + */ + protected $nameAttribute = 'property'; + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/NewsKeywords.php b/web/modules/metatag/src/Plugin/metatag/Tag/NewsKeywords.php new file mode 100644 index 0000000000000000000000000000000000000000..081debd6ea5427e9200b43108c40cc29169176f4 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/NewsKeywords.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "NewsKeywords" meta tag. + * + * @MetatagTag( + * id = "news_keywords", + * label = @Translation("News Keywords"), + * description = @Translation("A comma-separated list of keywords about the page. This meta tag is used as an indicator in <a href=':google_news'>Google News</a>.", arguments = { ":google_news" = "https://support.google.com/news/publisher/bin/answer.py?hl=en&answer=68297" }), + * name = "news_keywords", + * group = "advanced", + * weight = 2, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class NewsKeywords extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/OriginalSource.php b/web/modules/metatag/src/Plugin/metatag/Tag/OriginalSource.php new file mode 100644 index 0000000000000000000000000000000000000000..aa3cd820f9d1ba39ad887dbf3cfb8977ef80a613 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/OriginalSource.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The advanced "Original Source" meta tag. + * + * @MetatagTag( + * id = "original_source", + * label = @Translation("Original source"), + * description = @Translation("Used to indicate the URL that broke the story, and can link to either an internal URL or an external source. If the full URL is not known it is acceptable to use a partial URL or just the domain name."), + * name = "original-source", + * group = "advanced", + * weight = 4, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class OriginalSource 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 new file mode 100644 index 0000000000000000000000000000000000000000..c4be7ab1fc201ee21d30ab84ed3b72f806b0faac --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Referrer.php @@ -0,0 +1,47 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Referrer policy" meta tag. + * + * @MetatagTag( + * id = "referrer", + * label = @Translation("Referrer policy"), + * description = @Translation("Indicate to search engines and other page scrapers whether or not links should be followed. See <a href='http://w3c.github.io/webappsec/specs/referrer-policy/'>the W3C specifications</a> for further details."), + * name = "referrer", + * group = "advanced", + * weight = 5, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Referrer extends MetaNameBase { + + /** + * {@inheritdoc} + */ + public function form(array $element = []) { + $form = [ + '#type' => 'select', + '#title' => $this->label(), + '#description' => $this->description(), + '#options' => [ + 'no-referrer' => t('No Referrer'), + 'origin' => t('Origin'), + 'no-referrer-when-downgrade' => t('No Referrer When Downgrade'), + 'origin-when-cross-origin' => t('Origin When Cross-Origin'), + 'unsafe-url' => t('Unsafe URL'), + ], + '#empty_option' => t('- None -'), + '#empty_value' => '', + '#default_value' => $this->value(), + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#element_validate' => [[get_class($this), 'validateTag']], + ]; + + return $form; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Rights.php b/web/modules/metatag/src/Plugin/metatag/Tag/Rights.php new file mode 100644 index 0000000000000000000000000000000000000000..df692eed36b90557d86920416517371ee5eac1cd --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Rights.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Rights" meta tag. + * + * @MetatagTag( + * id = "rights", + * label = @Translation("Rights"), + * description = @Translation("Details about intellectual property, such as copyright or trademarks; does not automatically protect the site's content or intellectual property."), + * name = "rights", + * group = "advanced", + * weight = 5, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Rights extends MetaNameBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Robots.php b/web/modules/metatag/src/Plugin/metatag/Tag/Robots.php new file mode 100644 index 0000000000000000000000000000000000000000..363fbbcbf1e5ffb8f6456218222860d5c6f443cd --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Robots.php @@ -0,0 +1,73 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Robots" meta tag. + * + * @MetatagTag( + * id = "robots", + * label = @Translation("Robots"), + * description = @Translation("Provides search engines with specific directions for what to do when this page is indexed."), + * name = "robots", + * group = "advanced", + * weight = 1, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Robots extends MetaNameBase { + + /** + * Sets the value of this tag. + * + * @param string|array $value + * The value to set to this tag. + * It can be an array if it comes from a form submission or from field + * defaults, in which case + * we transform it to a comma-separated string. + */ + public function setValue($value) { + if (is_array($value)) { + $value = array_filter($value); + $value = implode(', ', array_keys($value)); + } + $this->value = $value; + } + + /** + * {@inheritdoc} + */ + public function form(array $element = []) { + // Prepare the default value as it is stored as a string. + $default_value = []; + if (!empty($this->value)) { + $default_value = explode(', ', $this->value); + } + + $form = [ + '#type' => 'checkboxes', + '#title' => $this->label(), + '#description' => $this->description(), + '#options' => [ + 'index' => t('Allow search engines to index this page (assumed).'), + 'follow' => t('Allow search engines to follow links on this page (assumed).'), + 'noindex' => t('Prevents search engines from indexing this page.'), + 'nofollow' => t('Prevents search engines from following links on this page.'), + 'noarchive' => t('Prevents cached copies of this page from appearing in search results.'), + 'nosnippet' => t('Prevents descriptions from appearing in search results, and prevents page caching.'), + 'noodp' => t('Blocks the <a href=":opendirectory">Open Directory Project</a> description from appearing in search results.', [':opendirectory' => 'http://www.dmoz.org/']), + 'noydir' => t('Prevents Yahoo! from listing this page in the <a href=":ydir">Yahoo! Directory</a>.', [':ydir' => 'http://dir.yahoo.com/']), + 'noimageindex' => t('Prevent search engines from indexing images on this page.'), + 'notranslate' => t('Prevent search engines from offering to translate this page in search results.'), + ], + '#default_value' => $default_value, + '#required' => isset($element['#required']) ? $element['#required'] : FALSE, + '#element_validate' => [[get_class($this), 'validateTag']], + ]; + + return $form; + } + +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/SetCookie.php b/web/modules/metatag/src/Plugin/metatag/Tag/SetCookie.php new file mode 100644 index 0000000000000000000000000000000000000000..f72c763189c29980619e9254492681c15d0f8011 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/SetCookie.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'set-cookie' meta tag. + * + * @MetatagTag( + * id = "set_cookie", + * label = @Translation("Set cookie"), + * description = @Translation("<a href='https://www.metatags.org/meta_http_equiv_set_cookie'>Sets a cookie</a> on the visitor's browser. Can be in either NAME=VALUE format, or a more verbose format including the path and expiration date; see the link for full details on the syntax."), + * name = "set-cookie", + * group = "advanced", + * weight = 5, + * type = "string", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class SetCookie extends MetaHttpEquivBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/ShortLink.php b/web/modules/metatag/src/Plugin/metatag/Tag/ShortLink.php new file mode 100644 index 0000000000000000000000000000000000000000..9df80e5b9e49302f4f0c98acda9716ed0c5295b0 --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/ShortLink.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * Provides a plugin for the 'shortlink' meta tag. + * + * @MetatagTag( + * id = "shortlink", + * label = @Translation("Shortlink URL"), + * description = @Translation("A brief URL, often created by a URL shortening service."), + * name = "shortlink", + * group = "advanced", + * weight = 1, + * type = "uri", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class ShortLink extends LinkRelBase { + // Nothing here yet. Just a placeholder class for a plugin. +} diff --git a/web/modules/metatag/src/Plugin/metatag/Tag/Standout.php b/web/modules/metatag/src/Plugin/metatag/Tag/Standout.php new file mode 100644 index 0000000000000000000000000000000000000000..131f0a4c71a250e5c416e85ae8828aa64ac495eb --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Standout.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The basic "Standout" meta tag. + * + * @MetatagTag( + * id = "standout", + * label = @Translation("Standout"), + * description = @Translation("Highlight standout journalism on the web, especially for breaking news; used as an indicator in <a href=':google_news'>Google News</a>. Warning: Don't abuse it, to be used a maximum of 7 times per calendar week!", arguments = { ":google_news" = "https://support.google.com/news/publisher/bin/answer.py?hl=en&answer=68297" }), + * name = "standout", + * group = "advanced", + * weight = 3, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +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 new file mode 100644 index 0000000000000000000000000000000000000000..4cdbe54b646d33024decba0ed2484e556e9edfef --- /dev/null +++ b/web/modules/metatag/src/Plugin/metatag/Tag/Title.php @@ -0,0 +1,43 @@ +<?php + +namespace Drupal\metatag\Plugin\metatag\Tag; + +/** + * The standard page title. + * + * @MetatagTag( + * id = "title", + * label = @Translation("Page title"), + * description = @Translation("The text to display in the title bar of a visitor's web browser when they view this page. This meta tag may also be used as the title of the page when a visitor bookmarks or favorites this page, or as the page title in a search engine result. It is common to append '[site:name]' to the end of this, so the site's name is automatically added. It is recommended that the title is no greater than 55 - 65 characters long, including spaces."), + * name = "title", + * group = "basic", + * weight = -1, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class Title extends MetaNameBase { + + /** + * Override the output of this tag so it's an actual TITLE tag. + * + * @todo Override the existing title tag X-) + */ + // 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; + // } + +} diff --git a/web/modules/metatag/src/Tests/MetatagAdminTest.php b/web/modules/metatag/src/Tests/MetatagAdminTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3072b62e0a15df27deec1f8d3aae7ca83335a5df --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagAdminTest.php @@ -0,0 +1,497 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\metatag\MetatagManager; +use Drupal\metatag\Entity\MetatagDefaults; +use Drupal\simpletest\WebTestBase; +use Drupal\Tests\metatag\Functional\MetatagHelperTrait; + +/** + * Tests the Metatag administration. + * + * @group metatag + */ +class MetatagAdminTest extends WebTestBase { + + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'node', + 'field_ui', + 'test_page_test', + 'token', + 'metatag', + + // @see testAvailableConfigEntities + 'block', + 'block_content', + 'comment', + 'contact', + 'menu_link_content', + 'menu_ui', + 'shortcut', + 'taxonomy', + 'entity_test', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Use the test page as the front page. + $this->config('system.site')->set('page.front', '/test-page')->save(); + + // Create Basic page and Article node types. + if ($this->profile != 'standard') { + $this->drupalCreateContentType([ + 'type' => 'page', + 'name' => 'Basic page', + 'display_submitted' => FALSE, + ]); + $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']); + } + } + + /** + * Tests the interface to manage metatag defaults. + */ + public function testDefaults() { + // Save the default title to test the Revert operation at the end. + $metatag_defaults = \Drupal::config('metatag.metatag_defaults.global'); + $default_title = $metatag_defaults->get('tags')['title']; + + // Initiate session with a user who can manage metatags. + $permissions = ['administer site configuration', 'administer meta tags']; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Check that the user can see the list of metatag defaults. + $this->drupalGet('admin/config/search/metatag'); + $this->assertResponse(200); + + // Check that the Global defaults were created. + $this->assertLinkByHref('admin/config/search/metatag/global', 0, t('Global defaults were created on installation.')); + + // Check that Global and entity defaults can't be deleted. + $this->assertNoLinkByHref('admin/config/search/metatag/global/delete', 0, t("Global defaults can't be deleted")); + $this->assertNoLinkByHref('admin/config/search/metatag/node/delete', 0, t("Entity defaults can't be deleted")); + + // Check that the module defaults were injected into the Global config + // entity. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $this->assertFieldById('edit-title', $metatag_defaults->get('title'), t('Metatag defaults were injected into the Global configuration entity.')); + + // Update the Global defaults and test them. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $values = [ + 'title' => 'Test title', + 'description' => 'Test description', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + $this->drupalGet('hit-a-404'); + $this->assertResponse(404); + foreach ($values as $metatag => $value) { + $this->assertRaw($value, t('Updated metatag @tag was found in the HEAD section of the page.', ['@tag' => $metatag])); + } + + // Check that tokens are processed. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $values = [ + 'title' => '[site:name] | Test title', + 'description' => '[site:name] | Test description', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + drupal_flush_all_caches(); + $this->drupalGet('hit-a-404'); + $this->assertResponse(404); + foreach ($values as $metatag => $value) { + $processed_value = \Drupal::token()->replace($value); + $this->assertRaw($processed_value, t('Processed token for metatag @tag was found in the HEAD section of the page.', ['@tag' => $metatag])); + } + + // Test the Robots plugin. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $robots_values = ['index', 'follow', 'noydir']; + $values = []; + foreach ($robots_values as $value) { + $values['robots[' . $value . ']'] = TRUE; + } + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + drupal_flush_all_caches(); + + // Trigger a 404 request. + $this->drupalGet('hit-a-404'); + $this->assertResponse(404); + $robots_value = implode(', ', $robots_values); + $this->assertRaw($robots_value, t('Robots metatag has the expected values.')); + + // Test reverting global configuration to its defaults. + $this->drupalGet('admin/config/search/metatag/global/revert'); + $this->assertResponse(200); + $this->drupalPostForm(NULL, [], 'Revert'); + $this->assertText('Reverted Global defaults.'); + $this->assertText($default_title, 'Global title was reverted to its default value.'); + + $this->drupalLogout(); + } + + /** + * Confirm the available entity types show on the add-default page. + */ + public function testAvailableConfigEntities() { + // Initiate session with a user who can manage metatags. + $permissions = [ + 'administer site configuration', + 'administer meta tags', + ]; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Load the default-add page. + $this->drupalGet('admin/config/search/metatag/add'); + $this->assertResponse(200); + + // Confirm the 'type' field exists. + $this->assertFieldByName('id'); + + // Compile a list of entities from the list. + $xpath = $this->xpath("//select[@name='id']"); + $this->verbose('<pre>' . print_r($xpath, TRUE) . '</pre>'); + $types = []; + foreach ($xpath[0]->children() as $item) { + if (!empty($item->option)) { + $data = (array) $item->option; + $types[$data['@attributes']['value']] = $data[0]; + } + } + $this->verbose('<pre>' . print_r($types, TRUE) . '</pre>'); + + // Check through the values that are in the 'select' list, make sure that + // unwanted items are not present. + $this->assertFalse(isset($types['block_content']), 'Custom block entities are not supported.'); + $this->assertFalse(isset($types['comment']), 'Comment entities are not supported.'); + $this->assertFalse(isset($types['menu_link_content']), 'Menu link entities are not supported.'); + $this->assertFalse(isset($types['shortcut']), 'Shortcut entities are not supported.'); + $this->assertTrue(isset($types['node__page']), 'Nodes are supported.'); + $this->assertTrue(isset($types['user__user']), 'Users are supported.'); + $this->assertTrue(isset($types['entity_test']), 'Test entities are supported.'); + } + + /** + * Tests special pages. + */ + public function testSpecialPages() { + // Initiate session with a user who can manage metatags. + $permissions = ['administer site configuration', 'administer meta tags']; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Adjust the front page and test it. + $this->drupalGet('admin/config/search/metatag/front'); + $this->assertResponse(200); + $values = [ + 'description' => 'Front page description', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Front page Metatag defaults.'); + $this->drupalGet('<front>'); + $this->assertResponse(200); + $this->assertRaw($values['description'], t('Front page defaults are used at the front page.')); + + // Adjust the 403 page and test it. + $this->drupalGet('admin/config/search/metatag/403'); + $this->assertResponse(200); + $values = [ + 'description' => '403 page description.', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the 403 access denied Metatag defaults.'); + $this->drupalLogout(); + $this->drupalGet('admin/config/search/metatag'); + $this->assertResponse(403); + $this->assertRaw($values['description'], t('403 page defaults are used at 403 pages.')); + + // Adjust the 404 page and test it. + $this->drupalLogin($account); + $this->drupalGet('admin/config/search/metatag/404'); + $this->assertResponse(200); + $values = [ + 'description' => '404 page description.', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the 404 page not found Metatag defaults.'); + $this->drupalGet('foo'); + $this->assertResponse(404); + $this->assertRaw($values['description'], t('404 page defaults are used at 404 pages.')); + $this->drupalLogout(); + } + + /** + * Tests entity and bundle overrides. + */ + public function testOverrides() { + // Initiate session with a user who can manage metatags. + $permissions = [ + 'administer site configuration', + 'administer meta tags', + 'access content', + 'create article content', + 'administer nodes', + 'create article content', + 'create page content', + ]; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Update the Metatag Node defaults. + $this->drupalGet('admin/config/search/metatag/node'); + $this->assertResponse(200); + $values = [ + 'title' => 'Test title for a node.', + 'description' => 'Test description for a node.', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Content Metatag defaults.'); + + // Create a test node. + $node = $this->drupalCreateNode([ + 'title' => t('Hello, world!'), + 'type' => 'article', + ]); + + // Check that the new values are found in the response. + $this->drupalGet('node/' . $node->id()); + $this->assertResponse(200); + foreach ($values as $metatag => $value) { + $this->assertRaw($value, t('Node metatag @tag overrides Global defaults.', ['@tag' => $metatag])); + } + + // Check that when the node defaults don't define a metatag, the Global one + // is used. + // First unset node defaults. + $this->drupalGet('admin/config/search/metatag/node'); + $this->assertResponse(200); + $values = [ + 'title' => '', + 'description' => '', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Content Metatag defaults.'); + + // Then, set global ones. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $values = [ + 'title' => 'Global title', + 'description' => 'Global description', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + + // Next, test that global defaults are rendered since node ones are empty. + // We are creating a new node as doing a get on the previous one would + // return cached results. + // @todo BookTest.php resets the cache of a single node, which is way more + // performant than creating a node for every set of assertions. + // @see BookTest::testDelete() + $node = $this->drupalCreateNode([ + 'title' => t('Hello, world!'), + 'type' => 'article', + ]); + $this->drupalGet('node/' . $node->id()); + $this->assertResponse(200); + foreach ($values as $metatag => $value) { + $this->assertRaw($value, t('Found global @tag tag as Node does not set it.', ['@tag' => $metatag])); + } + + // Now create article overrides and then test them. + $this->drupalGet('admin/config/search/metatag/add'); + $this->assertResponse(200); + $values = [ + 'id' => 'node__article', + 'title' => 'Article title override', + 'description' => 'Article description override', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText(strip_tags(t('Created the %label Metatag defaults.', ['%label' => 'Content: Article']))); + + // Confirm the fields load properly on the node/add/article page. + $node = $this->drupalCreateNode([ + 'title' => t('Hello, world!'), + 'type' => 'article', + ]); + $this->drupalGet('node/' . $node->id()); + $this->assertResponse(200); + unset($values['id']); + foreach ($values as $metatag => $value) { + $this->assertRaw($value, t('Found bundle override for tag @tag.', ['@tag' => $metatag])); + } + + // Test deleting the article defaults. + $this->drupalGet('admin/config/search/metatag/node__article/delete'); + $this->assertResponse(200); + $this->drupalPostForm(NULL, [], 'Delete'); + $this->assertText(t('Deleted @label defaults.', ['@label' => 'Content: Article'])); + } + + /** + * Test that the entity default values load on the entity form. + * + * And that they can then be overridden correctly. + */ + public function testEntityDefaultInheritence() { + // Initiate session with a user who can manage meta tags and content type + // fields. + $permissions = [ + 'administer site configuration', + 'administer meta tags', + 'access content', + 'administer node fields', + 'create article content', + 'administer nodes', + 'create article content', + 'create page content', + ]; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Add a Metatag field to the Article content type. + $this->drupalGet('admin/structure/types/manage/article/fields/add-field'); + $this->assertResponse(200); + $edit = [ + 'new_storage_type' => 'metatag', + 'label' => 'Meta tags', + 'field_name' => 'meta_tags', + ]; + $this->drupalPostForm(NULL, $edit, t('Save and continue')); + $this->drupalPostForm(NULL, [], t('Save field settings')); + $this->assertText(strip_tags(t('Updated field %label field settings.', ['%label' => 'Meta tags']))); + $this->drupalPostForm(NULL, [], t('Save settings')); + $this->assertText(strip_tags(t('Saved %label configuration.', ['%label' => 'Meta tags']))); + + // Try creating an article, confirm the fields are present. This should be + // the node default values that are shown. + $this->drupalGet('node/add/article'); + $this->assertResponse(200); + $this->assertFieldByName('field_meta_tags[0][basic][title]', '[node:title] | [site:name]'); + $this->assertFieldByName('field_meta_tags[0][basic][description]', '[node:summary]'); + + // Customize the Article content type defaults. + $this->drupalGet('admin/config/search/metatag/add'); + $this->assertResponse(200); + $values = [ + 'id' => 'node__article', + 'title' => 'Article title override', + 'description' => 'Article description override', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText(strip_tags(t('Created the %label Metatag defaults.', ['%label' => 'Content: Article']))); + + // Try creating an article, this time with the overridden defaults. + $this->drupalGet('node/add/article'); + $this->assertResponse(200); + $this->assertFieldByName('field_meta_tags[0][basic][title]', 'Article title override'); + $this->assertFieldByName('field_meta_tags[0][basic][description]', 'Article description override'); + } + + /** + * Test that protected Metatag defaults cannot be deleted. + */ + public function testDefaultProtected() { + // Initiate session with a user who can manage metatags. + $permissions = ['administer site configuration', 'administer meta tags']; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Add default metatag for Articles. + $edit = [ + 'id' => 'node__article', + ]; + $this->drupalPostForm('/admin/config/search/metatag/add', $edit, 'Save'); + + // Check that protected defaults contains "Revert" link instead of "Delete". + foreach (MetatagManager::protectedDefaults() as $protected) { + $this->assertLinkByHref('/admin/config/search/metatag/' . $protected); + $this->assertLinkByHref('/admin/config/search/metatag/' . $protected . '/revert'); + $this->assertNoLinkByHref('/admin/config/search/metatag/' . $protected . '/delete'); + } + + // Confirm that non protected defaults can be deleted. + $this->assertLinkByHref('/admin/config/search/metatag/node__article'); + $this->assertNoLinkByHref('/admin/config/search/metatag/node__article/revert'); + $this->assertLinkByHref('/admin/config/search/metatag/node__article/delete'); + + // Visit each protected default page to confirm "Delete" button is hidden. + foreach (MetatagManager::protectedDefaults() as $protected) { + $this->drupalGet('/admin/config/search/metatag/' . $protected); + $this->assertNoLink('Delete'); + } + + // Confirm that non protected defaults can be deleted. + $this->drupalGet('/admin/config/search/metatag/node__article'); + $this->assertLink('Delete'); + } + + /** + * Test that metatag list page pager works as expected. + */ + public function testListPager() { + $this->loginUser1(); + + $this->drupalGet('admin/config/search/metatag'); + $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'); + + // Create 50 vocabularies and generate metatag defaults for all of them. + for ($i = 0; $i < 50; $i++) { + $vocabulary = $this->createVocabulary(); + MetatagDefaults::create([ + 'id' => 'taxonomy_term__' . $vocabulary->id(), + 'label' => 'Taxonomy term: ' . $vocabulary->label(), + ])->save(); + } + + // Reload the page. + $this->drupalGet('admin/config/search/metatag'); + $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'); + // User entity not visible because it has been pushed to the next page. + $this->assertNoLinkByHref('/admin/config/search/metatag/user'); + $this->clickLinkPartialName('Next'); + + // Go to next page and confirm that parents are loaded and user us present. + $this->assertLinkByHref('/admin/config/search/metatag/global'); + $this->assertLinkByHref('/admin/config/search/metatag/taxonomy_term'); + // Main links not visible in the 2nd page. + $this->assertNoLinkByHref('/admin/config/search/metatag/front'); + $this->assertNoLinkByHref('/admin/config/search/metatag/403'); + $this->assertNoLinkByHref('/admin/config/search/metatag/404'); + $this->assertNoLinkByHref('/admin/config/search/metatag/node'); + // User is present because was pushed to page 2. + $this->assertLinkByHref('/admin/config/search/metatag/user'); + + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagConfigTranslationTest.php b/web/modules/metatag/src/Tests/MetatagConfigTranslationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f5c45180be402b5341043d63e77212fcb6af9ee1 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagConfigTranslationTest.php @@ -0,0 +1,160 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Ensures that the Metatag config translations work correctly. + * + * @group metatag + */ +class MetatagConfigTranslationTest extends WebTestBase { + + /** + * Profile to use. + * + * @var string + */ + protected $profile = 'testing'; + + /** + * Admin user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $adminUser; + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + 'metatag', + 'language', + 'config_translation', + ]; + + /** + * Permissions to grant admin user. + * + * @var array + */ + protected $permissions = [ + // From Metatag. + 'administer meta tags', + + // From system module, in order to access the /admin pages. + 'access administration pages', + + // From language module. + 'administer languages', + + // From config_translations module. + 'translate configuration', + ]; + + /** + * Sets the test up. + */ + protected function setUp() { + parent::setUp(); + $this->adminUser = $this->drupalCreateUser($this->permissions); + $this->drupalLogin($this->adminUser); + + // Enable the French language. + $this->drupalGet('admin/config/regional/language/add'); + $this->assertResponse(200); + $edit = [ + 'predefined_langcode' => 'fr', + ]; + $this->drupalPostForm(NULL, $edit, t('Add language')); + $this->assertRaw(t( + 'The language %language has been created and can now be used.', + ['%language' => t('French')] + )); + } + + /** + * Confirm the config defaults show on the translations page. + */ + public function testConfigTranslationsExist() { + // Ensure the config shows on the admin form. + $this->drupalGet('admin/config/regional/config-translation'); + $this->assertResponse(200); + $this->assertText(t('Metatag defaults')); + + // Load the main metatag_defaults config translation page. + $this->drupalGet('admin/config/regional/config-translation/metatag_defaults'); + $this->assertResponse(200); + // @todo Update this to confirm the H1 is loaded. + $this->assertRaw(t('Metatag defaults')); + + // Load all of the Metatag defaults. + $defaults = \Drupal::configFactory()->listAll('metatag.metatag_defaults'); + + /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */ + $config_manager = \Drupal::service('config.manager'); + + // Confirm each of the configs is available on the translation form. + foreach ($defaults as $config_name) { + if ($config_entity = $config_manager->loadConfigEntityByName($config_name)) { + $this->assertText($config_entity->label()); + } + } + + // Confirm that each config translation page can be loaded. + foreach ($defaults as $config_name) { + if ($config_entity = $config_manager->loadConfigEntityByName($config_name)) { + $this->drupalGet('admin/config/search/metatag/' . $config_entity->id() . '/translate'); + $this->assertResponse(200); + } + else { + $this->error('Unable to load a Metatag default config: ' . $config_name); + } + } + } + + /** + * Confirm the global configs are translatable page. + */ + public function testConfigTranslations() { + // Add something to the Global config. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $edit = [ + 'title' => 'Test title', + 'description' => 'Test description', + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->assertResponse(200); + $this->assertText(t('Saved the Global Metatag defaults.')); + + // Confirm the config has languages available to translate into. + $this->drupalGet('admin/config/search/metatag/global/translate'); + $this->assertResponse(200); + + // Load the translation form. + $this->drupalGet('admin/config/search/metatag/global/translate/fr/add'); + $this->assertResponse(200); + + // Confirm the meta tag fields are shown on the form. Confirm the fields and + // values separately to make it easier to pinpoint where the problem is if + // one should fail. + $this->assertFieldByName('translation[config_names][metatag.metatag_defaults.global][tags][title]'); + $this->assertFieldByName('translation[config_names][metatag.metatag_defaults.global][tags][title]', $edit['title']); + $this->assertFieldByName('translation[config_names][metatag.metatag_defaults.global][tags][description]'); + $this->assertFieldByName('translation[config_names][metatag.metatag_defaults.global][tags][description]', $edit['description']); + + // Confirm the form can be saved correctly. + $edit = [ + '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, t('Save translation')); + $this->assertResponse(200); + $this->assertText(t('Successfully saved French translation')); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagCustomRouteTest.php b/web/modules/metatag/src/Tests/MetatagCustomRouteTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b22350c8e4c20ce95f9e16edf6881c66ac6b54e3 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagCustomRouteTest.php @@ -0,0 +1,57 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\entity_test\Entity\EntityTest; +use Drupal\metatag\Entity\MetatagDefaults; +use Drupal\simpletest\WebTestBase; + +/** + * Tests custom route integration. + * + * @group metatag + * + * @see hook_metatag_route_entity() + */ +class MetatagCustomRouteTest extends WebTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'node', + // Dependencies. + 'token', + // Metatag itself. + 'metatag', + // This module will be used to load a static page which will inherit the + // global defaults, without loading values from other configs. + 'metatag_test_custom_route', + 'entity_test', + ]; + + /** + * Run tests on the custom route. + */ + public function testCustomRoute() { + $entity_test = EntityTest::create([ + 'name' => 'test name', + 'type' => 'entity_test', + ]); + $entity_test->save(); + + MetatagDefaults::create([ + 'id' => 'entity_test__entity_test', + 'tags' => [ + 'keywords' => 'test', + ], + ])->save(); + + $this->drupalGet('metatag_test_custom_route/' . $entity_test->id()); + $this->assertResponse(200); + $xpath = $this->xpath("//meta[@name='keywords']"); + $this->assertEqual(count($xpath), 1); + $this->assertEqual((string) $xpath[0]->attributes()['content'], 'test'); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagFieldNodeTest.php b/web/modules/metatag/src/Tests/MetatagFieldNodeTest.php new file mode 100644 index 0000000000000000000000000000000000000000..e56c7f0bb43a250333bba62ce562d6b4b2eed238 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagFieldNodeTest.php @@ -0,0 +1,89 @@ +<?php + +namespace Drupal\metatag\Tests; + +/** + * Ensures that the Metatag field works correctly on nodes. + * + * @group metatag + */ +class MetatagFieldNodeTest extends MetatagFieldTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Needed for token handling. + 'token', + + // Needed for the field UI testing. + 'field_ui', + + // Needed to verify that nothing is broken for unsupported entities. + 'contact', + + // The base module. + 'metatag', + + // Some extra custom logic for testing Metatag. + 'metatag_test_tag', + + // Manages the entity type that is being tested. + 'node', + ]; + + /** + * {@inheritdoc} + */ + protected $entityPerms = [ + // From Field UI. + 'administer node fields', + + // From Node. + 'access content', + 'administer content types', + 'administer nodes', + 'bypass node access', + 'create page content', + 'edit any page content', + 'edit own page content', + ]; + + /** + * {@inheritdoc} + */ + protected $entityType = 'node'; + + /** + * {@inheritdoc} + */ + protected $entityLabel = 'Content'; + + /** + * {@inheritdoc} + */ + protected $entityBundle = 'page'; + + /** + * {@inheritdoc} + */ + protected $entityAddPath = 'node/add'; + + /** + * {@inheritdoc} + */ + protected $entityFieldAdminPath = 'admin/structure/types/manage/page/fields'; + + /** + * {@inheritdoc} + */ + 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/src/Tests/MetatagFieldTermTest.php b/web/modules/metatag/src/Tests/MetatagFieldTermTest.php new file mode 100644 index 0000000000000000000000000000000000000000..36bcbde645cbfdce118e2deb68718edd232b1887 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagFieldTermTest.php @@ -0,0 +1,99 @@ +<?php + +namespace Drupal\metatag\Tests; + +/** + * Ensures that the Metatag field works correctly on taxonomy terms. + * + * @group metatag + */ +class MetatagFieldTermTest extends MetatagFieldTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Needed for token handling. + 'token', + + // Needed for the field UI testing. + 'field_ui', + + // Needed to verify that nothing is broken for unsupported entities. + 'contact', + + // The base module. + 'metatag', + + // Some extra custom logic for testing Metatag. + 'metatag_test_tag', + + // Manages the entity type that is being tested. + 'taxonomy', + ]; + + /** + * {@inheritdoc} + */ + protected $entityPerms = [ + // From Field UI. + 'administer taxonomy_term fields', + + // From Taxonomy. + 'administer taxonomy', + 'edit terms in tags', + 'delete terms in tags', + ]; + + /** + * {@inheritdoc} + */ + protected $entityType = 'taxonomy_term'; + + /** + * {@inheritdoc} + */ + protected $entityLabel = 'Taxonomy term'; + + /** + * {@inheritdoc} + */ + protected $entityBundle = 'entity_test'; + + /** + * {@inheritdoc} + */ + protected $entityAddPath = 'admin/structure/taxonomy/manage/tags/add'; + + /** + * {@inheritdoc} + */ + protected $entityFieldAdminPath = 'admin/structure/taxonomy/manage/tags/overview/fields'; + + /** + * {@inheritdoc} + */ + protected $entityTitleField = 'name'; + + /** + * {@inheritdoc} + */ + protected function setUpEntityType() { + $new_perms = [ + // From Taxonomy. + 'administer taxonomy', + ]; + $all_perms = array_merge($this->basePerms, $new_perms); + $this->adminUser = $this->drupalCreateUser($all_perms); + $this->drupalLogin($this->adminUser); + $this->drupalGet('admin/structure/taxonomy/add'); + $this->assertResponse(200); + $edit = [ + 'name' => 'Tags', + 'vid' => 'tags', + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->drupalLogout(); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagFieldTestBase.php b/web/modules/metatag/src/Tests/MetatagFieldTestBase.php new file mode 100644 index 0000000000000000000000000000000000000000..47d1de01d077e1c568619eca0dd5febac3ad60af --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagFieldTestBase.php @@ -0,0 +1,503 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\Core\Cache\Cache; +use Drupal\simpletest\WebTestBase; + +/** + * Base class for ensuring that the Metatag field works correctly. + */ +abstract class MetatagFieldTestBase extends WebTestBase { + + /** + * Profile to use. + * + * @var string + */ + protected $profile = 'testing'; + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + // Needed for token handling. + 'token', + + // Needed for the field UI testing. + 'field_ui', + + // Needed to verify that nothing is broken for unsupported entities. + 'contact', + + // The base module. + 'metatag', + + // Some extra custom logic for testing Metatag. + 'metatag_test_tag', + + // Manages the entity type that is being tested. + 'entity_test', + ]; + + /** + * Admin user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $adminUser; + + /** + * Basic permissions that all of the entity tests will need. + * + * @var array + */ + protected $basePerms = [ + 'access administration pages', + 'administer meta tags', + ]; + + /** + * Additional permissions needed for this entity type. + * + * @var array + */ + protected $entityPerms = []; + + /** + * The entity type that is being tested. + * + * @var string + */ + protected $entityType = ''; + + /** + * The formal name for this entity type. + * + * @var string + */ + protected $entityLabel = ''; + + /** + * The entity bundle that is being tested. + * + * @var string + */ + protected $entityBundle = ''; + + /** + * The path to add an object for this entity type. + * + * @var string + */ + protected $entityAddPath = ''; + + /** + * The path to access the field admin for this entity bundle. + * + * @var string + */ + protected $entityFieldAdminPath = ''; + + /** + * Whether or not this entity type supports default meta tag values. + * + * @var bool + */ + protected $entitySupportsDefaults = TRUE; + + /** + * The label used on the entity form for the 'save' action. + * + * @var string + */ + protected $entitySaveButtonLabel = 'Save'; + + /** + * The name of the primary title or name field for this entity. + * + * @var string + */ + protected $entityTitleField = 'title'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Any additional configuration that's neede for this entity type. + $this->setUpEntityType(); + + // Merge the base permissions with the custom ones for the entity type and + // create a user with these permissions. + $all_perms = array_merge($this->basePerms, $this->entityPerms); + $this->adminUser = $this->drupalCreateUser($all_perms); + $this->drupalGet('/user/login'); + $this->assertResponse(200); + $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. + */ + 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 []; + } + + /** + * Add a Metatag field to this entity type. + */ + protected function addField() { + // Add a metatag field to the entity type test_entity. + $this->drupalGet($this->entityFieldAdminPath . '/add-field'); + $this->assertResponse(200); + $edit = [ + 'label' => 'Metatag', + 'field_name' => 'metatag', + 'new_storage_type' => 'metatag', + ]; + $this->drupalPostForm(NULL, $edit, t('Save and continue')); + $this->drupalPostForm(NULL, [], t('Save field settings')); + + // Clear all settings. + $this->container->get('entity.manager')->clearCachedFieldDefinitions(); + } + + /** + * Confirm that the global default values work correctly. + * + * Specifically when there are no entity or bundle defaults available. + */ + public function testGlobalDefaultsInheritance() { + // First we set global defaults. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $global_values = [ + 'metatag_test_tag' => 'Global description', + ]; + $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + + // Add the field to this entity type. + $this->addField(); + + // Now when we create an entity, global defaults are used to fill the form + // fields. + $this->drupalGet($this->entityAddPath); + $this->assertResponse(200); + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag'], t('The metatag_test_tag field has the global default as the field default does not define it.')); + } + + /** + * Confirm that the entity default values work correctly. + */ + public function testEntityDefaultsInheritance() { + // This test doesn't make sense if the entity doesn't support defaults. + if (!$this->entitySupportsDefaults) { + return; + } + + // Set a global default. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $global_values = [ + 'metatag_test_tag' => 'Global description', + ]; + $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->assertText(strip_tags(t('Saved the %label Metatag defaults.', ['%label' => t('Global')]))); + + // Set an entity default. + $this->drupalGet('admin/config/search/metatag/' . $this->entityType); + $this->assertResponse(200); + $entity_values = [ + 'metatag_test_tag' => 'Entity description', + ]; + $this->drupalPostForm(NULL, $entity_values, 'Save'); + $this->assertText(strip_tags(t('Saved the %label Metatag defaults.', ['%label' => t($this->entityLabel)]))); + + // Add the field to this entity type. + $this->addField(); + + // Load the entity form for this entity type. + $this->drupalGet($this->entityAddPath); + $this->assertResponse(200); + $this->assertNoText('Fatal error'); + + // Allow the fields to be customized if needed. + $title = 'Barfoo'; + $edit = $this->entityDefaultValues(); + if (empty($edit)) { + $edit = [ + $this->entityTitleField . '[0][value]' => $title, + ]; + } + + // If this entity type supports defaults then verify the global default is + // not present but that the entity default *is* present. + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $entity_values['metatag_test_tag']); + $this->assertNoFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); + } + + /** + * Confirm that the default values for an entity bundle work. + * + * When there is no field for overriding the defaults. + * + * @todo + */ + public function testBundleDefaultsInheritance() { + } + + /** + * Confirm a field can be added to the entity bundle. + */ + public function testFieldCanBeAdded() { + $this->drupalGet($this->entityFieldAdminPath . '/add-field'); + $this->assertResponse(200); + $this->assertRaw('<option value="metatag">' . t('Meta tags') . '</option>'); + } + + /** + * Confirm a field can be added to the entity bundle. + */ + public function testEntityFieldsAvailable() { + // Add a field to the entity type. + $this->addField(); + + // Load the entity's form. + $this->drupalGet($this->entityAddPath); + $this->assertResponse(200); + $this->assertNoText('Fatal error'); + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]'); + } + + /** + * Confirm that the default values load correctly for an entity created. + * + * Before the custom field is added. + */ + public function testEntityFieldValuesOldEntity() { + // Set a global default. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $global_values = [ + 'metatag_test_tag' => 'Global description', + ]; + $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->assertText(strip_tags(t('Saved the %label Metatag defaults.', ['%label' => t('Global')]))); + + // Set an entity default if it's supported by the entity type. + if ($this->entitySupportsDefaults) { + $this->drupalGet('admin/config/search/metatag/' . $this->entityType); + $this->assertResponse(200); + $entity_values = [ + 'metatag_test_tag' => 'Entity description', + ]; + $this->drupalPostForm(NULL, $entity_values, 'Save'); + $this->assertText(strip_tags(t('Saved the %label Metatag defaults.', ['%label' => t($this->entityLabel)]))); + } + + // Load the entity form for this entity type. + $title = 'Barfoo'; + $this->drupalGet($this->entityAddPath); + $this->assertResponse(200); + $this->assertNoText('Fatal error'); + + // Allow the fields to be customized if needed. + $edit = $this->entityDefaultValues(); + if (empty($edit)) { + $edit = [ + $this->entityTitleField . '[0][value]' => $title, + ]; + } + + // Create a new entity object. + $this->drupalPostForm(NULL, $edit, t($this->entitySaveButtonLabel)); + $entities = \Drupal::entityTypeManager() + ->getStorage($this->entityType) + ->loadByProperties([$this->entityTitleField => $title]); + $this->assertEqual(1, count($entities), 'Entity was saved'); + $entity = reset($entities); + + // @todo Confirm the values output correctly. + // Add a field to the entity type. + $this->addField(); + + // Open the 'edit' form for the entity. + $this->drupalGet($entity->toUrl('edit-form')); + $this->assertResponse(200); + + // If this entity type supports defaults then verify the global default is + // not present but that the entity default *is* present. + if ($this->entitySupportsDefaults) { + $this->assertNoFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $entity_values['metatag_test_tag']); + } + else { + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); + } + + // @todo Confirm the values output correctly. + } + + /** + * Confirm that the default values load correctly. + * + * For an entity created after the custom field is added. + */ + public function testEntityFieldValuesNewEntity() { + // Set a global default. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $global_values = [ + 'metatag_test_tag' => 'Global description', + ]; + $this->drupalPostForm(NULL, $global_values, 'Save'); + $this->assertText(strip_tags(t('Saved the %label Metatag defaults.', ['%label' => t('Global')]))); + + // Set an entity default if it's supported by the entity type. + if ($this->entitySupportsDefaults) { + $this->drupalGet('admin/config/search/metatag/' . $this->entityType); + $this->assertResponse(200); + $entity_values = [ + 'metatag_test_tag' => 'Entity description', + ]; + $this->drupalPostForm(NULL, $entity_values, 'Save'); + $this->assertText(strip_tags(t('Saved the %label Metatag defaults.', ['%label' => t($this->entityLabel)]))); + } + + // Add a field to the entity type. + $this->addField(); + + // Load the entity form for this entity type. + $title = 'Barfoo'; + $this->drupalGet($this->entityAddPath); + $this->assertResponse(200); + $this->assertNoText('Fatal error'); + + // If this entity type supports defaults then verify the global default is + // not present but that the entity default *is* present. + if ($this->entitySupportsDefaults) { + $this->assertNoFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $entity_values['metatag_test_tag']); + } + else { + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); + } + + // Allow the fields to be customized if needed. + $edit = $this->entityDefaultValues(); + if (empty($edit)) { + $edit = [ + $this->entityTitleField . '[0][value]' => $title, + ]; + } + + // Create a new entity object. + $this->drupalPostForm(NULL, $edit, t($this->entitySaveButtonLabel)); + $entities = \Drupal::entityTypeManager() + ->getStorage($this->entityType) + ->loadByProperties([$this->entityTitleField => $title]); + $this->assertEqual(1, count($entities), 'Entity was saved'); + $entity = reset($entities); + + // @todo Confirm the values output correctly. + // Open the 'edit' form for the entity. + $this->drupalGet($entity->toUrl('edit-form')); + $this->assertResponse(200); + + // If this entity type supports defaults then verify the global default is + // not present but that the entity default *is* present. + if ($this->entitySupportsDefaults) { + $this->assertNoFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $entity_values['metatag_test_tag']); + } + else { + $this->assertFieldByName('field_metatag[0][basic][metatag_test_tag]', $global_values['metatag_test_tag']); + } + + // @todo Confirm the values output correctly. + } + + /** + * Tests adding and editing values on a given entity type. + * + * @todo Finish this. + */ + public function tofixTestEntityField() { + // Add a field to the entity type. + $this->addField(); + + // Create a test entity. + $this->drupalGet($this->entityAddPath); + $this->assertResponse(200); + $this->assertNoText('Fatal error'); + $edit = $this->entityDefaultValues($title) + [ + 'field_metatag[0][basic][metatag_test_tag]' => 'Kilimanjaro', + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $entities = \Drupal::entityTypeManager() + ->getStorage('entity_test') + ->loadByProperties([$this->entityTitleField => 'Barfoo']); + $this->assertEqual(1, count($entities), 'Entity was saved'); + $entity = reset($entities); + + // Make sure tags that have a field value but no default value still show + // up. + $this->drupalGet($entity->toUrl()); + $this->assertResponse(200); + $elements = $this->cssSelect('meta[name=metatag_test_tag]'); + $this->assertTrue(count($elements) === 1, 'Found keywords metatag_test_tag from defaults'); + $this->assertEqual((string) $elements[0]['content'], 'Kilimanjaro', 'Field value for metatag_test_tag found when no default set.'); + + // @todo This should not be required, but meta tags does not invalidate + // cache upon setting globals. + Cache::invalidateTags(['entity_test:' . $entity->id()]); + + // Update the Global defaults and test them. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $values = [ + 'metatag_test_tag' => 'Purple monkey dishwasher', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + $this->drupalGet($entity->toUrl()); + $this->assertResponse(200); + $elements = $this->cssSelect('meta[name=metatag_test_tag]'); + $this->assertTrue(count($elements) === 1, 'Found test metatag from defaults'); + $this->verbose('<pre>' . print_r($elements, TRUE) . '</pre>'); + $this->assertEqual((string) $elements[0]['content'], $values['metatag_test_tag']); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagFieldTestTest.php b/web/modules/metatag/src/Tests/MetatagFieldTestTest.php new file mode 100644 index 0000000000000000000000000000000000000000..95f7da176d17558d2cc35d950ada5fe7a2d93435 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagFieldTestTest.php @@ -0,0 +1,83 @@ +<?php + +namespace Drupal\metatag\Tests; + +/** + * Ensure that the Metatag field works correctly for the test entity. + * + * @group metatag + */ +class MetatagFieldTestTest extends MetatagFieldTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Needed for token handling. + 'token', + + // Needed for the field UI testing. + 'field_ui', + + // Needed to verify that nothing is broken for unsupported entities. + 'contact', + + // The base module. + 'metatag', + + // Some extra custom logic for testing Metatag. + 'metatag_test_tag', + + // Manages the entity type that is being tested. + 'entity_test', + ]; + + /** + * {@inheritdoc} + */ + protected $entityPerms = [ + 'view test entity', + 'administer entity_test fields', + 'administer entity_test content', + ]; + + /** + * {@inheritdoc} + */ + protected $entityType = 'entity_test'; + + /** + * {@inheritdoc} + */ + protected $entityLabel = 'Test entity'; + + /** + * {@inheritdoc} + */ + protected $entityBundle = 'entity_test'; + + /** + * {@inheritdoc} + */ + protected $entityAddPath = 'entity_test/add'; + + /** + * {@inheritdoc} + */ + protected $entityFieldAdminPath = 'entity_test/structure/entity_test/fields'; + + /** + * Whether or not the entity type supports defaults. + * + * @var bool + * + * @todo Fix this. + */ + protected $entitySupportsDefaults = FALSE; + + /** + * {@inheritdoc} + */ + protected $entityTitleField = 'name'; + +} diff --git a/web/modules/metatag/src/Tests/MetatagFieldUserTest.php b/web/modules/metatag/src/Tests/MetatagFieldUserTest.php new file mode 100644 index 0000000000000000000000000000000000000000..723401414606279371eb5dd2cdbe41ea299ecdb3 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagFieldUserTest.php @@ -0,0 +1,109 @@ +<?php + +namespace Drupal\metatag\Tests; + +/** + * Ensures that the Metatag field works correctly on users. + * + * @group metatag + */ +class MetatagFieldUserTest extends MetatagFieldTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Needed for token handling. + 'token', + + // Needed for the field UI testing. + 'field_ui', + + // Needed to verify that nothing is broken for unsupported entities. + 'contact', + + // The base module. + 'metatag', + + // Some extra custom logic for testing Metatag. + 'metatag_test_tag', + + // Manages the entity type that is being tested. + 'user', + ]; + + /** + * {@inheritdoc} + */ + protected $entityPerms = [ + // From Field UI. + 'administer user fields', + + // From User. + 'administer account settings', + 'administer users', + ]; + + /** + * {@inheritdoc} + */ + protected $entityType = 'user'; + + /** + * {@inheritdoc} + */ + protected $entityLabel = 'User'; + + /** + * {@inheritdoc} + */ + protected $entityBundle = 'user'; + + /** + * {@inheritdoc} + */ + protected $entityAddPath = 'admin/people/create'; + + /** + * {@inheritdoc} + */ + protected $entityFieldAdminPath = 'admin/config/people/accounts/fields'; + + /** + * {@inheritdoc} + */ + protected $entityTitleField = 'name'; + + /** + * {@inheritdoc} + */ + protected $entitySaveButtonLabel = 'Create new account'; + + /** + * {@inheritdoc} + */ + protected function entityDefaultValues($title = 'Barfoo') { + $password = $this->randomString(16); + return [ + 'mail' => 'test' . $this->adminUser->getEmail(), + 'name' => $title, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ]; + } + + /** + * Confirm the metatag field can be shown on a user registration page. + * + * @todo + */ + public function testFieldsOnUserRegistrationForm() {} + + /** + * Confirm the metatag field can be shown on a normal user's own edit form. + * + * @todo + */ + public function testFieldsOnUserEditForm() {} + +} diff --git a/web/modules/metatag/src/Tests/MetatagForumTest.php b/web/modules/metatag/src/Tests/MetatagForumTest.php new file mode 100644 index 0000000000000000000000000000000000000000..662cfc9421323297d4bcf540fcec80315052aa49 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagForumTest.php @@ -0,0 +1,78 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Ensures that meta tags are rendering correctly on forum pages. + * + * @group metatag + */ +class MetatagForumTest extends WebTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'token', + 'metatag', + 'node', + 'system', + 'forum', + ]; + + /** + * Administrator user for tests. + * + * @var \Drupal\user\UserInterface + */ + protected $adminUser; + + /** + * Setup basic environment. + */ + protected function setUp() { + parent::setUp(); + + $admin_permissions = [ + 'administer nodes', + 'bypass node access', + 'administer meta tags', + 'administer site configuration', + 'access content', + ]; + + // Create and login user. + $this->adminUser = $this->drupalCreateUser($admin_permissions); + $this->drupalLogin($this->adminUser); + + // Create content type. + $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(); + } + + /** + * Verify that a forum post can be loaded when Metatag is enabled. + */ + public function testForumPost() { + $this->drupalGet('node/add/forum'); + $this->assertResponse(200); + $edit = [ + 'title[0][value]' => 'Testing forums', + 'taxonomy_forums' => 1, + 'body[0][value]' => 'Just testing.', + ]; + $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + $this->drupalPostForm(NULL, $edit, $save_label); + $this->assertResponse(200); + $this->assertText(t('@type @title has been created.', ['@type' => t('Forum topic'), '@title' => 'Testing forums'])); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagFrontpageTest.php b/web/modules/metatag/src/Tests/MetatagFrontpageTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a360432c9b44b180aa07e0c7edd5d5500facde1d --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagFrontpageTest.php @@ -0,0 +1,172 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Ensures that meta tags are rendering correctly on home page. + * + * @group metatag + */ +class MetatagFrontpageTest extends WebTestBase { + + // Use the helper functions from the Functional trait. This is pretty safe but + // remember to rewrite all of these WebTestBase tests using BrowserTestBase + // before the next millenium. + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'token', + 'metatag', + 'node', + 'system', + 'test_page_test', + ]; + + /** + * The path to a node that is created for testing. + * + * @var string + */ + protected $nodeId; + + /** + * Setup basic environment. + */ + protected function setUp() { + parent::setUp(); + + // Login user 1. + $this->loginUser1(); + + // Create content type. + $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(); + } + + /** + * The front page config is enabled, its meta tags should be used. + */ + public function testFrontPageMetatagsEnabledConfig() { + // Add something to the front page config. + $this->drupalGet('admin/config/search/metatag/front'); + $this->assertResponse(200); + $edit = [ + 'title' => 'Test title', + 'description' => 'Test description', + 'keywords' => 'testing,keywords', + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->assertResponse(200); + $this->assertText(t('Saved the Front page Metatag defaults.')); + + // Testing front page metatags. + $this->drupalGet('<front>'); + foreach ($edit as $metatag => $metatag_value) { + $xpath = $this->xpath("//meta[@name='" . $metatag . "']"); + $this->assertEqual(count($xpath), 1, 'Exactly one ' . $metatag . ' meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, $metatag_value); + } + + $node_path = '/node/' . $this->nodeId; + // Testing front page metatags. + $this->drupalGet($node_path); + foreach ($edit as $metatag => $metatag_value) { + $xpath = $this->xpath("//meta[@name='" . $metatag . "']"); + $this->assertEqual(count($xpath), 1, 'Exactly one ' . $metatag . ' meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, $metatag_value); + } + + // Change the front page to a valid custom route. + $site_edit = [ + 'site_frontpage' => '/test-page', + ]; + $this->drupalGet('admin/config/system/site-information'); + $this->assertResponse(200); + $this->drupalPostForm(NULL, $site_edit, t('Save configuration')); + $this->assertText(t('The configuration options have been saved.'), 'The front page path has been saved.'); + return; + + // @todo Finish this? + $this->drupalGet('test-page'); + $this->assertResponse(200); + foreach ($edit as $metatag => $metatag_value) { + $xpath = $this->xpath("//meta[@name='" . $metatag . "']"); + $this->assertEqual(count($xpath), 1, 'Exactly one ' . $metatag . ' meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, $metatag_value); + } + } + + /** + * Test front page meta tags when front page config is disabled. + */ + public function testFrontPageMetatagDisabledConfig() { + // Disable front page metatag, enable node metatag & check. + $this->drupalGet('admin/config/search/metatag/front/delete'); + $this->assertResponse(200); + $this->drupalPostForm(NULL, [], t('Delete')); + $this->assertResponse(200); + $this->assertText(t('Deleted Front page defaults.')); + + // Update the Metatag Node defaults. + $this->drupalGet('admin/config/search/metatag/node'); + $this->assertResponse(200); + $edit = [ + 'title' => 'Test title for a node.', + 'description' => 'Test description for a node.', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $this->assertText('Saved the Content Metatag defaults.'); + $this->drupalGet('<front>'); + foreach ($edit as $metatag => $metatag_value) { + $xpath = $this->xpath("//meta[@name='" . $metatag . "']"); + $this->assertEqual(count($xpath), 1, 'Exactly one ' . $metatag . ' meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, $metatag_value); + } + + // Change the front page to a valid path. + $this->drupalGet('admin/config/system/site-information'); + $this->assertResponse(200); + $edit = [ + 'site_frontpage' => '/test-page', + ]; + $this->drupalPostForm(NULL, $edit, t('Save configuration')); + $this->assertText(t('The configuration options have been saved.'), 'The front page path has been saved.'); + + // Front page is custom route. + // Update the Metatag Node global. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $edit = [ + 'title' => 'Test title.', + 'description' => 'Test description.', + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + + // Test Metatags. + $this->drupalGet('test-page'); + $this->assertResponse(200); + foreach ($edit as $metatag => $metatag_value) { + $xpath = $this->xpath("//meta[@name='" . $metatag . "']"); + $this->assertEqual(count($xpath), 1, 'Exactly one ' . $metatag . ' meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, $metatag_value); + } + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagHelperTrait.php b/web/modules/metatag/src/Tests/MetatagHelperTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..fc9538abf1693f9a432d02e9409a7cbcc35337f6 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagHelperTrait.php @@ -0,0 +1,159 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\Component\Render\FormattableMarkup; +use Drupal\Component\Utility\Html; +use Drupal\taxonomy\Entity\Term; +use Drupal\taxonomy\Entity\Vocabulary; +use Drupal\user\Entity\User; + +/** + * A copy of Drupal\Tests\metatag\Functional\MetatagHelperTrait. + * + * @todo Remove once the other tests are converted over. + */ +trait MetatagHelperTrait { + + /** + * Log in as user 1. + */ + protected function loginUser1() { + // Load user 1. + /* @var \Drupal\user\Entity\User $account */ + $account = User::load(1); + + // Reset the password. + $password = 'foo'; + $account->setPassword($password)->save(); + + // Support old and new tests. + $account->passRaw = $password; + $account->pass_raw = $password; + + // 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); + } + + /** + * Create a content type and a node. + * + * @param string $title + * A title for the node that will be returned. + * @param string $body + * The text to use as the body. + * + * @return \Drupal\node\NodeInterface + * A fully formatted node object. + */ + private function createContentTypeNode($title = 'Title test', $body = 'Body test') { + $content_type = 'metatag_test'; + $args = [ + 'type' => $content_type, + 'label' => 'Test content type', + ]; + $this->createContentType($args); + + $args = [ + 'body' => [ + [ + 'value' => $body, + 'format' => filter_default_format(), + ], + ], + 'title' => $title, + 'type' => $content_type, + ]; + + return $this->createNode($args); + } + + /** + * Create a vocabulary. + * + * @param array $values + * Items passed to the vocabulary. If the 'vid' item is not present it will + * be automatically generated. If the 'name' item is not present the 'vid' + * will be used. + * + * @return \Drupal\taxonomy\Entity\Vocabulary + * A fully formatted vocabulary object. + */ + private function createVocabulary(array $values = []) { + // Find a non-existent random type name. + if (!isset($values['vid'])) { + do { + $id = strtolower($this->randomMachineName(8)); + } while (Vocabulary::load($id)); + } + else { + $id = $values['vid']; + } + $values += [ + 'vid' => $id, + 'name' => $id, + ]; + $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 { + $this->assertEqual($status, SAVED_NEW, (new FormattableMarkup('Created vocabulary %type.', ['%type' => $vocab->id()]))->__toString()); + } + + return $vocab; + } + + /** + * Create a taxonomy term. + * + * @param array $values + * Items passed to the term. Requires the 'vid' element. + * + * @return Drupal\taxonomy\Entity\Term + * A fully formatted term object. + */ + private function createTerm(array $values = []) { + // Populate defaults array. + $values += [ + 'description' => [ + [ + 'value' => $this->randomMachineName(32), + 'format' => filter_default_format(), + ], + ], + 'name' => $this->randomMachineName(8), + ]; + $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 { + $this->assertEqual($status, SAVED_NEW, (new FormattableMarkup('Created term %name.', ['%name' => $term->label()]))->__toString()); + } + + return $term; + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagNodeTranslationTest.php b/web/modules/metatag/src/Tests/MetatagNodeTranslationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..669726a342d3d34165b9c0257476997fd57d4468 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagNodeTranslationTest.php @@ -0,0 +1,210 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\language\Entity\ConfigurableLanguage; +use Drupal\simpletest\WebTestBase; + +/** + * Ensures that meta tag values are translated correctly on nodes. + * + * @group metatag + */ +class MetatagNodeTranslationTest extends WebTestBase { + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + 'content_translation', + 'field_ui', + 'metatag', + 'node', + ]; + + /** + * The default language code to use in this test. + * + * @var array + */ + protected $defaultLangcode = 'fr'; + + /** + * Languages to enable. + * + * @var array + */ + protected $additionalLangcodes = ['es']; + + /** + * Administrator user for tests. + * + * @var \Drupal\user\UserInterface + */ + protected $adminUser; + + /** + * Setup basic environment. + */ + protected function setUp() { + parent::setUp(); + + $admin_permissions = [ + 'administer content types', + 'administer content translation', + 'administer languages', + 'administer nodes', + 'administer node fields', + 'bypass node access', + 'create content translations', + 'delete content translations', + 'translate any entity', + 'update content translations', + ]; + + // Create and login user. + $this->adminUser = $this->drupalCreateUser($admin_permissions); + + // Add languages. + foreach ($this->additionalLangcodes as $langcode) { + ConfigurableLanguage::createFromLangcode($langcode)->save(); + } + } + + /** + * Tests the metatag value translations. + */ + public function testMetatagValueTranslation() { + if (floatval(\Drupal::VERSION) <= 8.3) { + $save_label = t('Save and publish'); + $save_label_i18n = t('Save and keep published (this translation)'); + } + else { + $save_label = t('Save'); + $save_label_i18n = t('Save (this translation)'); + } + + // Set up a content type. + $name = $this->randomMachineName() . ' ' . $this->randomMachineName(); + $this->drupalLogin($this->adminUser); + $this->drupalCreateContentType(['type' => 'metatag_node', 'name' => $name]); + + // Add a metatag field to the content type. + $this->drupalGet('admin/structure/types'); + $this->assertResponse(200); + $this->drupalGet('admin/structure/types/manage/metatag_node'); + $this->assertResponse(200); + $edit = [ + 'language_configuration[language_alterable]' => TRUE, + 'language_configuration[content_translation]' => TRUE, + ]; + $this->drupalPostForm(NULL, $edit, t('Save content type')); + $this->assertResponse(200); + + $this->drupalGet('admin/structure/types/manage/metatag_node/fields/add-field'); + $this->assertResponse(200); + $edit = [ + 'label' => 'Meta tags', + 'field_name' => 'meta_tags', + 'new_storage_type' => 'metatag', + ]; + $this->drupalPostForm(NULL, $edit, t('Save and continue')); + $this->assertResponse(200); + $this->drupalPostForm(NULL, [], t('Save field settings')); + $this->assertResponse(200); + $edit = [ + 'translatable' => TRUE, + ]; + $this->drupalPostForm(NULL, $edit, t('Save settings')); + $this->assertResponse(200); + $this->drupalGet('admin/structure/types/manage/metatag_node/fields/node.metatag_node.field_meta_tags'); + $this->assertResponse(200); + + // Set up a node without explicit metatag description. This causes the + // global default to be used, which contains a token (node:summary). The + // token value should be correctly translated. + + // Load the node form. + $this->drupalGet('node/add/metatag_node'); + $this->assertResponse(200); + + // Check the default values are correct. + $this->assertFieldByName('field_meta_tags[0][basic][title]', '[node:title] | [site:name]', 'Default title token is present.'); + $this->assertFieldByName('field_meta_tags[0][basic][description]', '[node:summary]', 'Default description token is present.'); + + // Create a node. + $edit = [ + 'title[0][value]' => 'Node Français', + 'body[0][value]' => 'French summary.', + ]; + $this->drupalPostForm(NULL, $edit, $save_label); + $this->assertResponse(200); + + $xpath = $this->xpath("//meta[@name='description']"); + $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, 'French summary.'); + + $this->drupalGet('node/1/translations/add/en/es'); + $this->assertResponse(200); + // Check the default values are there. + $this->assertFieldByName('field_meta_tags[0][basic][title]', '[node:title] | [site:name]', 'Default title token is present.'); + $this->assertFieldByName('field_meta_tags[0][basic][description]', '[node:summary]', 'Default description token is present.'); + + $edit = [ + 'title[0][value]' => 'Node Español', + 'body[0][value]' => 'Spanish summary.', + ]; + $this->drupalPostForm(NULL, $edit, $save_label_i18n); + $this->assertResponse(200); + + $this->drupalGet('es/node/1'); + $this->assertResponse(200); + $xpath = $this->xpath("//meta[@name='description']"); + $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, 'Spanish summary.'); + $this->assertNotEqual($value, 'French summary.'); + + $this->drupalGet('node/1/edit'); + $this->assertResponse(200); + // Check the default values are there. + $this->assertFieldByName('field_meta_tags[0][basic][title]', '[node:title] | [site:name]', 'Default title token is present.'); + $this->assertFieldByName('field_meta_tags[0][basic][description]', '[node:summary]', 'Default description token is present.'); + + // Set explicit values on the description metatag instead using the + // defaults. + $this->drupalGet('node/1/edit'); + $this->assertResponse(200); + $edit = [ + 'field_meta_tags[0][basic][description]' => 'Overridden French description.', + ]; + $this->drupalPostForm(NULL, $edit, $save_label_i18n); + $this->assertResponse(200); + + $xpath = $this->xpath("//meta[@name='description']"); + $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, 'Overridden French description.'); + $this->assertNotEqual($value, 'Spanish summary.'); + $this->assertNotEqual($value, 'French summary.'); + + $this->drupalGet('es/node/1/edit'); + $this->assertResponse(200); + $edit = [ + 'field_meta_tags[0][basic][description]' => 'Overridden Spanish description.', + ]; + $this->drupalPostForm(NULL, $edit, $save_label_i18n); + $this->assertResponse(200); + + $xpath = $this->xpath("//meta[@name='description']"); + $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.'); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, 'Overridden Spanish description.'); + $this->assertNotEqual($value, 'Spanish summary.'); + $this->assertNotEqual($value, 'French summary.'); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagStringTest.php b/web/modules/metatag/src/Tests/MetatagStringTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ac5c7d578b2dcdd08846a57a5b8f9c099bbd6daf --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagStringTest.php @@ -0,0 +1,319 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Ensures that the Metatag field works correctly. + * + * @group metatag + */ +class MetatagStringTest extends WebTestBase { + + /** + * Admin user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $adminUser; + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + 'token', + 'node', + 'field_ui', + 'metatag', + ]; + + /** + * Permissions to grant admin user. + * + * @var array + */ + protected $permissions = [ + 'administer node fields', + 'administer content types', + 'access administration pages', + 'administer meta tags', + 'administer nodes', + 'bypass node access', + 'administer meta tags', + 'administer site configuration', + 'access content', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->adminUser = $this->drupalCreateUser($this->permissions); + $this->drupalLogin($this->adminUser); + + $this->drupalCreateContentType(['type' => 'page', 'display_submitted' => FALSE]); + + // Add a Metatag field to the content type. + $this->drupalGet('admin/structure/types'); + $this->assertResponse(200); + $this->drupalGet('admin/structure/types/manage/page/fields/add-field'); + $this->assertResponse(200); + $edit = [ + 'label' => 'Metatag', + 'field_name' => 'metatag_field', + 'new_storage_type' => 'metatag', + ]; + $this->drupalPostForm(NULL, $edit, t('Save and continue')); + $this->drupalPostForm(NULL, [], t('Save field settings')); + $this->container->get('entity.manager')->clearCachedFieldDefinitions(); + } + + /** + * Tests that a meta tag with single quote is not double escaped. + */ + public function testSingleQuote() { + $this->checkString("bla'bleblu"); + } + + /** + * Tests that a meta tag with a double quote is not double escaped. + */ + public function testDoubleQuote() { + $this->checkString('bla"bleblu'); + } + + /** + * Tests that a meta tag with an ampersand is not double escaped. + */ + public function testAmpersand() { + $this->checkString("blable&blu"); + } + + /** + * Tests that specific strings are not double escaped. + */ + public function checkString($string) { + $this->checkConfig($string); + $this->checkNode($string); + $this->checkEncodedField($string); + } + + /** + * Tests that a specific config string is not double encoded. + */ + public function checkConfig($string) { + // The original strings. + $title_original = 'Title: ' . $string; + $desc_original = 'Description: ' . $string; + + // The strings after they're encoded, but quotes will not be encoded. + $title_encoded = htmlentities($title_original, ENT_QUOTES); + $desc_encoded = htmlentities($desc_original, ENT_QUOTES); + + // The strings double-encoded, to make sure the tags aren't broken. + $title_encodeded = htmlentities($title_encoded, ENT_QUOTES); + $desc_encodeded = htmlentities($desc_encoded, ENT_QUOTES); + + // Update the Global defaults and test them. + $this->drupalGet('admin/config/search/metatag/front'); + $this->assertResponse(200); + $edit = [ + 'title' => $title_original, + 'description' => $desc_original, + ]; + $this->drupalPostForm(NULL, $edit, 'Save'); + $this->assertResponse(200); + + $metatag_defaults = \Drupal::config('metatag.metatag_defaults.front'); + $default_title = $metatag_defaults->get('tags')['title']; + $default_description = $metatag_defaults->get('tags')['description']; + + // Make sure the title tag is stored correctly. + $this->assertEqual($title_original, $default_title, 'The title tag was stored in its original format.'); + $this->assertNotEqual($title_encoded, $default_title, 'The title tag was not stored in an encoded format.'); + $this->assertNotEqual($title_encodeded, $default_title, 'The title tag was not stored in a double-encoded format.'); + + // Make sure the description tag is stored correctly. + $this->assertEqual($desc_original, $default_description, 'The description tag was stored in its original format.'); + $this->assertNotEqual($desc_encoded, $default_description, 'The description tag was not stored in an encoded format.'); + $this->assertNotEqual($desc_encodeded, $default_description, 'The description tag was not stored in a double-encoded format.'); + + // Set up a node without explicit metatag description. This causes the + // global default to be used, which contains a token (node:summary). The + // token value should be correctly translated. + + // Create a node. + $this->drupalGet('node/add/page'); + $this->assertResponse(200); + $edit = [ + 'title[0][value]' => $title_original, + 'body[0][value]' => $desc_original, + ]; + $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + $this->drupalPostForm(NULL, $edit, $save_label); + + $this->config('system.site')->set('page.front', '/node/1')->save(); + + // Load the front page. + $this->drupalGet('<front>'); + $this->assertResponse(200); + + // Again, with xpath the HTML entities will be parsed automagically. + $xpath_title = (string) current($this->xpath("//title")); + $this->assertEqual($xpath_title, $title_original); + $this->assertNotEqual($xpath_title, $title_encoded); + $this->assertNotEqual($xpath_title, $title_encodeded); + + // 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. + $this->assertRaw('<title>' . $title_encoded . '</title>', 'Confirmed the node title tag is available in its encoded format.'); + $this->assertNoRaw('<title>' . $title_original . '</title>', 'Confirmed the node title tag is not available in its original format.'); + $this->assertNoRaw('<title>' . $title_encodeded . '</title>', 'Confirmed the node title tag is not double-double-encoded?'); + + // Again, with xpath the HTML entities will be parsed automagically. + $xpath = $this->xpath("//meta[@name='description']"); + $this->assertEqual($xpath[0]['content'], $desc_original); + $this->assertNotEqual($xpath[0]['content'], $desc_encoded); + $this->assertNotEqual($xpath[0]['content'], $desc_encodeded); + } + + /** + * Tests that a specific node string is not double escaped. + */ + public function checkNode($string) { + $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + + // The original strings. + $title_original = 'Title: ' . $string; + $desc_original = 'Description: ' . $string; + + // The strings after they're encoded, but quotes will not be encoded. + $title_encoded = htmlentities($title_original, ENT_QUOTES); + $desc_encoded = htmlentities($desc_original, ENT_QUOTES); + + // The strings double-encoded, to make sure the tags aren't broken. + $title_encodeded = htmlentities($title_encoded, ENT_QUOTES); + $desc_encodeded = htmlentities($desc_encoded, ENT_QUOTES); + + // Update the Global defaults and test them. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $edit = [ + 'title' => $title_original, + 'description' => $desc_original, + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->assertResponse(200); + + // Set up a node without explicit metatag description. This causes the + // global default to be used, which contains a token (node:summary). The + // token value should be correctly translated. + + // Create a node. + $this->drupalGet('node/add/page'); + $this->assertResponse(200); + $edit = [ + 'title[0][value]' => $title_original, + 'body[0][value]' => $desc_original, + ]; + $this->drupalPostForm(NULL, $edit, $save_label); + $this->assertResponse(200); + + // Load the node page. + $this->drupalGet('node/1'); + $this->assertResponse(200); + + // Again, with xpath the HTML entities will be parsed automagically. + $xpath_title = (string) current($this->xpath("//title")); + $this->assertEqual($xpath_title, $title_original); + $this->assertNotEqual($xpath_title, $title_encoded); + $this->assertNotEqual($xpath_title, $title_encodeded); + + // 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. + $this->assertRaw('<title>' . $title_encoded . '</title>', 'Confirmed the node title tag is encoded.'); + // Again, with xpath the HTML entities will be parsed automagically. + $xpath = $this->xpath("//meta[@name='description']"); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, $desc_original); + $this->assertNotEqual($value, $desc_encoded); + $this->assertNotEqual($value, $desc_encodeded); + + // Normal meta tags should be encoded properly. + $this->assertRaw('"' . $desc_encoded . '"', 'Confirmed the node "description" meta tag string was encoded properly.'); + // Normal meta tags with HTML entities should be displayed in their original + // format. + $this->assertNoRaw('"' . $desc_original . '"', 'Confirmed the node "description" meta tag string does not show in its original form.'); + // Normal meta tags should not be double-encoded. + $this->assertNoRaw('"' . $desc_encodeded . '"', 'Confirmed the node "description" meta tag string was not double-encoded.'); + } + + /** + * Tests that fields with encoded HTML entities will not be double-encoded. + */ + public function checkEncodedField($string) { + $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + + // The original strings. + $title_original = 'Title: ' . $string; + $desc_original = 'Description: ' . $string; + + // The strings after they're encoded, but quotes will not be encoded. + $desc_encoded = htmlentities($desc_original, ENT_QUOTES); + + // The strings double-encoded, to make sure the tags aren't broken. + $desc_encodeded = htmlentities($desc_encoded, ENT_QUOTES); + + // Update the Global defaults and test them. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $edit = [ + 'title' => $title_original, + 'description' => $desc_original, + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->assertResponse(200); + + // Set up a node without explicit metatag description. This causes the + // global default to be used, which contains a token (node:summary). The + // token value should be correctly translated. + + // Create a node. + $this->drupalGet('node/add/page'); + $this->assertResponse(200); + $edit = [ + 'title[0][value]' => $title_original, + 'body[0][value]' => $desc_original, + ]; + $this->drupalPostForm(NULL, $edit, $save_label); + $this->assertResponse(200); + + // Load the node page. + $this->drupalGet('node/1'); + $this->assertResponse(200); + + // With xpath the HTML entities will be parsed automagically. + $xpath = $this->xpath("//meta[@name='description']"); + $value = (string) $xpath[0]['content']; + $this->assertEqual($value, $desc_original); + $this->assertNotEqual($value, $desc_encoded); + $this->assertNotEqual($value, $desc_encodeded); + + // Normal meta tags should be encoded properly. + $this->assertRaw('"' . $desc_encoded . '"', 'Confirmed the node "description" meta tag string was encoded properly.'); + + // Normal meta tags with HTML entities should be displayed in their original + // format. + $this->assertNoRaw('"' . $desc_original . '"', 'Confirmed the node "description" meta tag string does not show in its original form.'); + + // Normal meta tags should not be double-encoded. + $this->assertNoRaw('"' . $desc_encodeded . '"', 'Confirmed the node "description" meta tag string was not double-encoded.'); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagTagTypesTest.php b/web/modules/metatag/src/Tests/MetatagTagTypesTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c1404835bdc18c912fb507184aabde3620178ecb --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagTagTypesTest.php @@ -0,0 +1,188 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Verify that different meta tag API options are supported. + * + * @group metatag + */ +class MetatagTagTypesTest extends WebTestBase { + + /** + * Profile to use. + * + * @var string + */ + protected $profile = 'testing'; + + /** + * Admin user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $adminUser; + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + // Needed for token handling. + 'token', + + // Needed for the field UI testing. + 'field_ui', + + // Needed for the basic entity testing. + 'entity_test', + + // Needed to verify that nothing is broken for unsupported entities. + 'contact', + + // The base module. + 'metatag', + + // Some extra custom logic for testing Metatag. + 'metatag_test_tag', + + // Needed for testSecureTagOption(). + 'metatag_open_graph', + ]; + + /** + * Permissions to grant admin user. + * + * @var array + */ + protected $permissions = [ + 'access administration pages', + 'view test entity', + 'administer entity_test fields', + 'administer entity_test content', + 'administer meta tags', + ]; + + /** + * Sets the test up. + */ + protected function setUp() { + parent::setUp(); + $this->adminUser = $this->drupalCreateUser($this->permissions); + $this->drupalLogin($this->adminUser); + + // Add a metatag field to the entity type test_entity. + $this->drupalGet('entity_test/structure/entity_test/fields/add-field'); + $this->assertResponse(200); + $edit = [ + 'label' => 'Metatag', + 'field_name' => 'metatag', + 'new_storage_type' => 'metatag', + ]; + $this->drupalPostForm(NULL, $edit, t('Save and continue')); + $this->drupalPostForm(NULL, [], t('Save field settings')); + $this->container->get('entity.manager')->clearCachedFieldDefinitions(); + } + + /** + * Tests whether HTML is correctly removed from metatags. + * + * Tests three values in meta tags -- one without any HTML; one with raw html; + * and one with escaped HTML. To pass all HTML including escaped should be + * removed. + */ + public function testHtmlIsRemoved() { + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $values = [ + 'abstract' => 'No HTML here', + 'description' => '<html><body><p class="test">Surrounded by raw HTML</p></body></html>', + 'keywords' => '<html><body><p class="test">Surrounded by escaped HTML</p></body></html>', + ]; + + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + drupal_flush_all_caches(); + $this->drupalGet('hit-a-404'); + $this->assertResponse(404); + + $this->assertRaw('<meta name="abstract" content="No HTML here" />', t('Test with no HTML content')); + $this->assertRaw('<meta name="description" content="Surrounded by raw HTML" />', t('Test with raw HTML content')); + $this->assertRaw('<meta name="keywords" content="Surrounded by escaped HTML" />', t('Test with escaped HTML content')); + } + + /** + * Tests the 'secure' meta tag attribute. + * + * Tests insecure values in og:image:secure_url (a tag with secure attribute + * set to TRUE) and in og:image (a tag with secure attribute set to FALSE). To + * To pass og:image_secure should be changed to https:// and og:image + * unchanged. + */ + public function testSecureTagOption() { + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $values = [ + 'og_image' => 'http://blahblahblah.com/insecure.jpg', + 'og_image_secure_url' => 'http://blahblahblah.com/secure.jpg', + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + drupal_flush_all_caches(); + $this->drupalGet(''); + $this->assertResponse(200); + + $this->assertRaw('<meta property="og:image" content="http://blahblahblah.com/insecure.jpg" />', t('Test og:image with regular http:// link')); + $this->assertRaw('<meta property="og:image:secure_url" content="https://blahblahblah.com/secure.jpg" />', t('Test og:image:secure_url updated regular http:// link to https://')); + } + + /** + * Check the contact form. + * + * @todo Move this somewhere else. + */ + public function testContactForm() { + // Test a route where the entity for that route does not implement + // ContentEntityInterface. + $controller = \Drupal::entityTypeManager()->getStorage('contact_form'); + $controller->create([ + 'id' => 'test_contact_form', + ])->save(); + $account = $this->drupalCreateUser(['access site-wide contact form']); + $this->drupalLogin($account); + $this->drupalGet('contact/test_contact_form'); + $this->assertResponse(200); + } + + /** + * Check URL handling. + * + * @todo Finish. + */ + public function todoTestUrl() { + // $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + // // Tests meta tags with URLs work. + // $this->drupalGet($this->entity_add_path); + // $this->assertResponse(200); + // $edit = [ + // 'name[0][value]' => 'UrlTags', + // 'user_id[0][target_id]' => 'foo (' . $this->adminUser->id() . ')', + // 'field_metatag[0][advanced][original_source]' => 'http://example.com/foo.html', + // ]; + // $this->drupalPostForm(NULL, $edit, $save_label); + // $entities = entity_load_multiple_by_properties('entity_test', [ + // 'name' => 'UrlTags', + // ]); + // $this->assertEqual(1, count($entities), 'Entity was saved'); + // $entity = reset($entities); + // $this->drupalGet($this->entity_base_path . '/' . $entity->id()); + // $this->assertResponse(200); + // $elements = $this->cssSelect("meta[name='original-source']"); + // $this->assertTrue(count($elements) === 1, 'Found original source metatag from defaults'); + // $this->assertEqual((string) $elements[0]['content'], $edit['field_metatag[0][advanced][original_source]']); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagTagsTest.php b/web/modules/metatag/src/Tests/MetatagTagsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5cdb3a5012cf9329778334c64819275f943988d2 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagTagsTest.php @@ -0,0 +1,184 @@ +<?php + +namespace Drupal\metatag\Tests; + +/** + * Tests that each of the Metatag base tags work correctly. + * + * @group metatag + */ +class MetatagTagsTest extends MetatagTagsTestBase { + + /** + * {@inheritdoc} + */ + private $tags = [ + 'abstract', + 'canonical_url', + 'content_language', + 'description', + 'generator', + 'geo_placename', + 'geo_position', + 'geo_region', + 'google', + 'icbm', + 'image_src', + 'keywords', + 'news_keywords', + 'original_source', + 'referrer', + 'rights', + 'robots', + 'set_cookie', + 'shortlink', + 'standout', + 'title', + ]; + + /** + * Each of these meta tags has a different tag name vs its internal name. + */ + private function getTestTagName($tag_name) { + if ($tag_name == 'geo_placename') { + $tag_name = 'geo.placename'; + } + elseif ($tag_name == 'geo_position') { + $tag_name = 'geo.position'; + } + elseif ($tag_name == 'geo_region') { + $tag_name = 'geo.region'; + } + elseif ($tag_name == 'content_language') { + $tag_name = 'content-language'; + } + elseif ($tag_name == 'original_source') { + $tag_name = 'original-source'; + } + elseif ($tag_name == 'set_cookie') { + $tag_name = 'set-cookie'; + } + + return $tag_name; + } + + /** + * Implements {tag_name}TestFieldXpath() for 'abstract'. + */ + private function abstractTestFieldXpath() { + return "//textarea[@name='abstract']"; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'author'. + */ + private function authorTestOutputXpath() { + return "//link[@rel='author']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'author'. + */ + private function authorTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'canonical_url'. + */ + private function canonicalUrlTestOutputXpath() { + return "//link[@rel='canonical']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'canonical_url'. + */ + private function canonicalUrlTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'content_language'. + */ + private function contentLanguageTestNameAttribute() { + return 'http-equiv'; + } + + /** + * Implements {tag_name}TestNameAttribute() for 'set_cookie'. + */ + private function setCookieTestNameAttribute() { + return 'http-equiv'; + } + + /** + * Implements {tag_name}TestFieldXpath() for 'description'. + */ + private function descriptionTestFieldXpath() { + return "//textarea[@name='description']"; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'image_src'. + */ + private function imageSrcTestOutputXpath() { + return "//link[@rel='image_src']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'image_src'. + */ + private function imageSrcTestValueAttribute() { + return 'href'; + } + + /** + * Implements {tag_name}TestFieldXpath() for 'referrer'. + */ + private function referrerTestFieldXpath() { + return "//select[@name='referrer']"; + } + + /** + * Implements {tag_name}TestFieldXpath() for 'robots'. + */ + private function robotsTestFieldXpath() { + return "//input[@name='robots[index]' and @type='checkbox']"; + } + + /** + * Implements {tag_name}TestValue() for 'referrer'. + */ + private function referrerTestValue() { + return 'origin'; + } + + /** + * Implements {tag_name}TestValue() for 'robots'. + */ + private function robotsTestKey() { + return 'robots[index]'; + } + + /** + * Implements {tag_name}TestValue() for 'robots'. + */ + private function robotsTestValue() { + return TRUE; + } + + /** + * Implements {tag_name}TestOutputXpath() for 'shortlink'. + */ + private function shortlinkTestOutputXpath() { + return "//link[@rel='shortlink']"; + } + + /** + * Implements {tag_name}TestValueAttribute() for 'shortlink'. + */ + private function shortlinkTestValueAttribute() { + return 'href'; + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagTagsTestBase.php b/web/modules/metatag/src/Tests/MetatagTagsTestBase.php new file mode 100644 index 0000000000000000000000000000000000000000..88fc3129b8a9616db07a446a0ddc8c28d3325f12 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagTagsTestBase.php @@ -0,0 +1,328 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\Component\Render\FormattableMarkup; +use Drupal\simpletest\WebTestBase; +use Symfony\Component\DependencyInjection\Container; + +/** + * Base class to test all of the meta tags that are in a specific module. + */ +abstract class MetatagTagsTestBase extends WebTestBase { + + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + // This is needed for the 'access content' permission. + 'node', + + // Dependencies. + 'token', + + // Metatag itself. + 'metatag', + + // This module will be used to load a static page which will inherit the + // global defaults, without loading values from other configs. + 'metatag_test_custom_route', + ]; + + /** + * All of the meta tags defined by this module which will be tested. + * + * @var array + */ + private $tags = []; + + /** + * The tag to look for when testing the output. + * + * @var string + */ + private $testTag = 'meta'; + + /** + * {@inheritdoc} + * + * @var string + */ + private $testNameAttribute = 'name'; + + /** + * The attribute to look for when testing the output. + * + * @var string + */ + private $testValueAttribute = 'content'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Use the test page as the front page. + $this->config('system.site')->set('page.front', '/test-page')->save(); + + // Initiate session with a user who can manage meta tags and access content. + $permissions = [ + 'administer site configuration', + 'administer meta tags', + 'access content', + ]; + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + } + + /** + * Tests that this module's tags are available. + */ + public function testTagsArePresent() { + // Load the global config. + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + + // Confirm the various meta tags are available. + foreach ($this->tags as $tag) { + // Look for a custom method named "{$tagname}TestFieldXpath", if found + // use that method to get the xpath definition for this meta tag, + // otherwise it defaults to just looking for a text input field. + $method = $this->getMethodFromTagCallback($tag, 'test_field_xpath'); + if (method_exists($this, $method)) { + $xpath = $this->$method(); + } + else { + $xpath = "//input[@name='{$tag}' and @type='text']"; + } + + $this->assertFieldByXPath($xpath, NULL, new FormattableMarkup('Found the @tag meta tag field.', ['@tag' => $tag])); + } + + $this->drupalLogout(); + } + + /** + * Confirm that each tag can be saved and that the output is correct. + */ + public function testTagsInputOutput() { + // Create a content type to test with. + $this->createContentType(['type' => 'page']); + $this->drupalCreateNode([ + 'title' => t('Hello, world!'), + 'type' => 'page', + ]); + + // Test a non-entity path and an entity path. The non-entity path inherits + // the global meta tags, the entity path inherits from its entity config. + $paths = [ + [ + 'admin/config/search/metatag/global', + 'metatag_test_custom_route', + 'Saved the Global Metatag defaults.', + ], + [ + 'admin/config/search/metatag/node', + 'node/1', + 'Saved the Content Metatag defaults', + ], + ]; + + foreach ($paths as $item) { + list($path1, $path2, $save_message) = $item; + + // Load the global config. + $this->drupalGet($path1); + $this->assertResponse(200); + + // Update the Global defaults and test them. + $all_values = $values = []; + foreach ($this->tags as $tag_name) { + // Look for a custom method named "{$tagname}TestKey", if found use + // that method to get the test string for this meta tag, otherwise it + // defaults to the meta tag's name. + $method = $this->getMethodFromTagCallback($tag_name, 'TestKey'); + if (method_exists($this, $method)) { + $test_key = $this->$method(); + } + else { + $test_key = $tag_name; + } + + // Look for a custom method named "{$tagname}TestValue", if found use + // that method to get the test string for this meta tag, otherwise it + // defaults to just generating a random string. + $method = $this->getMethodFromTagCallback($tag_name, 'TestValue'); + if (method_exists($this, $method)) { + $test_value = $this->$method(); + } + else { + // Generate a random string. Generating two words of 8 characters each + // with simple machine name -style strings. + $test_value = $this->randomMachineName() . ' ' . $this->randomMachineName(); + } + + $values[$test_key] = $test_value; + $all_values[$tag_name] = $test_value; + } + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText($save_message); + + // Load the test page. + $this->drupalGet($path2); + $this->assertResponse(200); + + // Look for the values. + foreach ($this->tags as $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: + // <$testTag $testNameAttribute=$tag_name $testValueAttribute=$value /> + $method = $this->getMethodFromTagCallback($tag_name, 'TestOutputXpath'); + if (method_exists($this, $method)) { + $xpath_string = $this->$method(); + } + else { + // Look for a custom method named "{$tag_name}TestTag", if + // found use that method to get the xpath definition for this meta + // tag, otherwise it defaults to $this->testTag. + $method = $this->getMethodFromTagCallback($tag_name, 'TestTag'); + if (method_exists($this, $method)) { + $xpath_tag = $this->$method(); + } + else { + $xpath_tag = $this->testTag; + } + + // Look for a custom method named "{$tag_name}TestNameAttribute", + // if found use that method to get the xpath definition for this meta + // tag, otherwise it defaults to $this->testNameAttribute. + $method = $this->getMethodFromTagCallback($tag_name, 'TestNameAttribute'); + if (method_exists($this, $method)) { + $xpath_name_attribute = $this->$method(); + } + else { + $xpath_name_attribute = $this->testNameAttribute; + } + + // Look for a custom method named "{$tag_name}TestTagName", if + // found use that method to get the xpath definition for this meta + // tag, otherwise it defaults to $tag_name. + $method = $this->getMethodFromTagCallback($tag_name, 'TestTagName'); + if (method_exists($this, $method)) { + $xpath_name_tag = $this->$method(); + } + else { + $xpath_name_tag = $this->getTestTagName($tag_name); + } + + // Compile the xpath. + $xpath_string = "//{$xpath_tag}[@{$xpath_name_attribute}='{$xpath_name_tag}']"; + } + + // Look for a custom method named "{$tag_name}TestValueAttribute", if + // found use that method to get the xpath definition for this meta tag, + // otherwise it defaults to $this->testValueAttribute. + $method = $this->getMethodFromTagCallback($tag_name, 'TestValueAttribute'); + if (method_exists($this, $method)) { + $xpath_value_attribute = $this->$method(); + } + else { + $xpath_value_attribute = $this->testValueAttribute; + } + + // Extract the meta tag from the HTML. + $xpath = $this->xpath($xpath_string); + $this->assertEqual(count($xpath), 1, new FormattableMarkup('One @name tag found.', ['@name' => $tag_name])); + if (count($xpath) !== 1) { + $this->verbose($xpath, $tag_name . ': ' . $xpath_string); + } + + // Run various tests on the output variables. + // Most meta tags have an attribute, but some don't. + if (!empty($xpath_value_attribute)) { + $this->assertTrue($xpath_value_attribute); + $this->assertTrue(isset($xpath[0][$xpath_value_attribute])); + // Help with debugging. + if (!isset($xpath[0][$xpath_value_attribute])) { + $this->verbose($xpath, $tag_name . ': ' . $xpath_string); + } + else { + if ((string) $xpath[0][$xpath_value_attribute] != $all_values[$tag_name]) { + $this->verbose($xpath, $tag_name . ': ' . $xpath_string); + } + $this->assertTrue($xpath[0][$xpath_value_attribute]); + $this->assertEqual($xpath[0][$xpath_value_attribute], $all_values[$tag_name], "The meta tag was found with the expected value."); + } + } + else { + $this->verbose($xpath, $tag_name . ': ' . $xpath_string); + $this->assertTrue((string) $xpath[0]); + $this->assertEqual((string) $xpath[0], $all_values[$tag_name], "The meta tag was found with the expected value."); + } + } + } + + $this->drupalLogout(); + } + + /** + * Convert a tag's internal name to the string which is actually used in HTML. + * + * The meta tag internal name will be machine names, i.e. only contain a-z, + * A-Z, 0-9 and the underline character. Meta tag names will actually contain + * any possible character. + * + * @param string $tag_name + * The tag name to be converted. + * + * @return string + * The converted tag name. + */ + private function getTestTagName($tag_name) { + return $tag_name; + } + + /** + * Generate a random value for testing meta tag fields. + * + * As a reasonable default, this will generating two words of 8 characters + * each with simple machine name -style strings. + * + * @return string + * A normal string. + */ + private function getTestTagValue() { + return $this->randomMachineName() . ' ' . $this->randomMachineName(); + } + + /** + * Generate a URL for an image. + * + * @return string + * An absolute URL to a non-existent image. + */ + private function randomImageUrl() { + return 'http://www.example.com/images/' . $this->randomMachineName() . '.png'; + } + + /** + * Convert a tag name with a callback to a lowerCamelCase method name. + * + * @param string $tag_name + * The meta tag name. + * @param string $callback + * The callback that is to be used. + * + * @return string + * The tag name and callback concatenated together and converted to + * lowerCamelCase. + */ + private function getMethodFromTagCallback($tag_name, $callback) { + return lcfirst(Container::camelize($tag_name . '_' . $callback)); + } + +} diff --git a/web/modules/metatag/src/Tests/MetatagXssTest.php b/web/modules/metatag/src/Tests/MetatagXssTest.php new file mode 100644 index 0000000000000000000000000000000000000000..da5a3e6d8dee2a51872e73b4ec90241785f57ee3 --- /dev/null +++ b/web/modules/metatag/src/Tests/MetatagXssTest.php @@ -0,0 +1,213 @@ +<?php + +namespace Drupal\metatag\Tests; + +use Drupal\simpletest\WebTestBase; + +/** + * Ensures that meta tags do not allow xss vulnerabilities. + * + * @group metatag + */ +class MetatagXssTest extends WebTestBase { + + /** + * String that causes an alert when page titles aren't filtered for xss. + * + * @var string + */ + private $xssTitleString = '<script>alert("xss");</script>'; + + /** + * String that causes an alert when meta tags aren't filtered for xss. + * + * @var string + */ + private $xssString = '"><script>alert("xss");</script><meta "'; + + /** + * Rendered xss tag that has escaped attribute to avoid xss injection. + * + * @var string + */ + private $escapedXssTag = '<meta name="abstract" content="">alert("xss");" />'; + + /** + * String that causes an alert when meta tags aren't filtered for xss. + * + * "Image" meta tags are processed differently to others, so this checks for a + * different string. + * + * @var string + */ + private $xssImageString = '"><script>alert("image xss");</script><meta "'; + + /** + * Rendered xss tag that has escaped attribute to avoid xss injection. + * + * @var string + */ + private $escapedXssImageTag = '<link rel="image_src" href="">alert("image xss");" />'; + + /** + * Administrator user for tests. + * + * @var \Drupal\user\UserInterface + */ + protected $adminUser; + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'node', + 'views', + 'system', + 'field', + 'field_ui', + 'token', + 'metatag', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Create a user that can manage content types and create content. + $admin_permissions = [ + 'administer content types', + 'administer nodes', + 'bypass node access', + 'administer meta tags', + 'administer site configuration', + 'access content', + 'administer content types', + 'administer nodes', + 'administer node fields', + ]; + + // Create and login a with the admin-ish permissions user. + $this->adminUser = $this->drupalCreateUser($admin_permissions); + $this->drupalLogin($this->adminUser); + + // Set up a 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'); + $this->assertResponse(200); + $edit = [ + 'label' => 'Metatag', + 'field_name' => 'metatag_field', + 'new_storage_type' => 'metatag', + ]; + $this->drupalPostForm(NULL, $edit, t('Save and continue')); + $this->drupalPostForm(NULL, [], t('Save field settings')); + } + + /** + * Verify XSS injected in global config is not rendered. + */ + public function testXssMetatagConfig() { + $this->drupalGet('admin/config/search/metatag/global'); + $this->assertResponse(200); + $values = [ + 'title' => $this->xssTitleString, + 'abstract' => $this->xssString, + 'image_src' => $this->xssImageString, + ]; + $this->drupalPostForm(NULL, $values, 'Save'); + $this->assertText('Saved the Global Metatag defaults.'); + $this->rebuildAll(); + + // Load the Views-based front page. + $this->drupalGet('node'); + $this->assertResponse(200); + $this->assertText(t('No front page content has been created yet.')); + + // Check for the title tag, which will have the HTML tags removed and then + // be lightly HTML encoded. + $this->assertEscaped(strip_tags($this->xssTitleString)); + $this->assertNoRaw($this->xssTitleString); + + // Check for the basic meta tag. + $this->assertRaw($this->escapedXssTag); + $this->assertNoRaw($this->xssString); + + // Check for the image meta tag. + $this->assertRaw($this->escapedXssImageTag); + $this->assertNoRaw($this->xssImageString); + } + + /** + * Verify XSS injected in the entity metatag override field is not rendered. + */ + public function testXssEntityOverride() { + $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + + $this->drupalGet('node/add/metatag_node'); + $this->assertResponse(200); + $edit = [ + 'title[0][value]' => $this->randomString(32), + 'field_metatag_field[0][basic][title]' => $this->xssTitleString, + 'field_metatag_field[0][basic][abstract]' => $this->xssString, + 'field_metatag_field[0][advanced][image_src]' => $this->xssImageString, + ]; + $this->drupalPostForm(NULL, $edit, $save_label); + + // Check for the title tag, which will have the HTML tags removed and then + // be lightly HTML encoded. + $this->assertEscaped(strip_tags($this->xssTitleString)); + $this->assertNoRaw($this->xssTitleString); + + // Check for the basic meta tag. + $this->assertRaw($this->escapedXssTag); + $this->assertNoRaw($this->xssString); + + // Check for the image meta tag. + $this->assertRaw($this->escapedXssImageTag); + $this->assertNoRaw($this->xssImageString); + } + + /** + * Verify XSS injected in the entity titles are not rendered. + */ + public function testXssEntityTitle() { + $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + + $this->drupalGet('node/add/metatag_node'); + $this->assertResponse(200); + $edit = [ + 'title[0][value]' => $this->xssTitleString, + 'body[0][value]' => $this->randomString() . ' ' . $this->randomString(), + ]; + $this->drupalPostForm(NULL, $edit, $save_label); + + // Check for the title tag, which will have the HTML tags removed and then + // be lightly HTML encoded. + $this->assertEscaped(strip_tags($this->xssTitleString)); + $this->assertNoRaw($this->xssTitleString); + } + + /** + * Verify XSS injected in the entity fields are not rendered. + */ + public function testXssEntityBody() { + $save_label = (floatval(\Drupal::VERSION) <= 8.3) ? t('Save and publish') : t('Save'); + + $this->drupalGet('node/add/metatag_node'); + $this->assertResponse(200); + $edit = [ + 'title[0][value]' => $this->randomString(), + 'body[0][value]' => $this->xssTitleString, + ]; + $this->drupalPostForm(NULL, $edit, $save_label); + + // Check the body text. + // $this->assertNoTitle($this->xssTitleString); + $this->assertNoRaw($this->xssTitleString); + } + +} diff --git a/web/modules/metatag/src/Tests/WithRedirect.php b/web/modules/metatag/src/Tests/WithRedirect.php new file mode 100644 index 0000000000000000000000000000000000000000..72c0833c6eb79d39c68d3bffbef5e1e80f3ea969 --- /dev/null +++ b/web/modules/metatag/src/Tests/WithRedirect.php @@ -0,0 +1,37 @@ +<?php + +namespace Drupal\metatag\Tests; + +/** + * Tests the Metatag administration when Redirect is installed. + * + * @group metatag + */ +class WithRedirect extends MetatagAdminTest { + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'node', + 'field_ui', + 'test_page_test', + 'token', + 'metatag', + + // @see testAvailableConfigEntities + 'block', + 'block_content', + 'comment', + 'contact', + 'menu_link_content', + 'menu_ui', + 'shortcut', + 'taxonomy', + 'entity_test', + + // The whole point of this test. + 'redirect', + ]; + +} diff --git a/web/modules/metatag/templates/generator.php.twig b/web/modules/metatag/templates/generator.php.twig new file mode 100644 index 0000000000000000000000000000000000000000..4c9857c678500ee8b0e92427db81500938188b22 --- /dev/null +++ b/web/modules/metatag/templates/generator.php.twig @@ -0,0 +1,9 @@ +{% 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 new file mode 100644 index 0000000000000000000000000000000000000000..1d1bbc34de1c3eaec64d77da3dbf4dd60fcc5424 --- /dev/null +++ b/web/modules/metatag/templates/group.php.twig @@ -0,0 +1,25 @@ +{% 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 new file mode 100644 index 0000000000000000000000000000000000000000..d5e23275976f0966d630d8e45388ddfc3655e157 --- /dev/null +++ b/web/modules/metatag/templates/metatag_tag.schema.yml.twig @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..f990b4be6fce5cdea92afa2e270fabb65951afed --- /dev/null +++ b/web/modules/metatag/templates/tag.php.twig @@ -0,0 +1,30 @@ +{% 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/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 new file mode 100644 index 0000000000000000000000000000000000000000..dad9f064ab412b50eec5fd836f1980b07fdb9808 --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.info.yml @@ -0,0 +1,13 @@ +name: "Metatag: Test Custom Route" +type: module +description: Support module for testing handling of a custom route that only inherits the global configuration. +# core: 8.x +package: Testing +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 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 new file mode 100644 index 0000000000000000000000000000000000000000..3c6ed8a85a5a8e578a8f50f99ab22ee0c0c7fbc5 --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.module @@ -0,0 +1,35 @@ +<?php + +/** + * @file + * Contains metatag_test_custom_route.module.. + */ + +use Drupal\Core\Routing\RouteMatchInterface; + +/** + * Implements hook_help(). + */ +function metatag_test_custom_route_help($route_name, RouteMatchInterface $route_match) { + switch ($route_name) { + // 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>'; + return $output; + + default: + } +} + +/** + * Implements hook_metatag_route_entity(). + */ +function metatag_test_custom_route_metatag_route_entity(RouteMatchInterface $route_match) { + if ($route_match->getRouteName() === 'metatag_test_custom_route.entity_route') { + if ($entity_test = $route_match->getParameter('entity_test')) { + return $entity_test; + } + } +} diff --git a/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.routing.yml b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.routing.yml new file mode 100644 index 0000000000000000000000000000000000000000..1e1a5d41ad0794bf6bf5bf7772ed8935baf26c67 --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_custom_route/metatag_test_custom_route.routing.yml @@ -0,0 +1,15 @@ +metatag_test_custom_route.test: + path: '/metatag_test_custom_route' + defaults: + _title: 'Metatag Test' + _controller: '\Drupal\metatag_test_custom_route\Controller\MetatagTestCustomRouteController::test' + requirements: + _permission: 'access content' + + +metatag_test_custom_route.entity_route: + path: '/metatag_test_custom_route/{entity_test}' + defaults: + _entity_view: 'entity_test.full' + requirements: + _permission: 'access content' diff --git a/web/modules/metatag/tests/modules/metatag_test_custom_route/src/Controller/MetatagTestCustomRouteController.php b/web/modules/metatag/tests/modules/metatag_test_custom_route/src/Controller/MetatagTestCustomRouteController.php new file mode 100644 index 0000000000000000000000000000000000000000..24a537cd1cc9303f64f1cc9ac5348b6f8b6d71c9 --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_custom_route/src/Controller/MetatagTestCustomRouteController.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_test_custom_route\Controller; + +use Drupal\Core\Controller\ControllerBase; + +/** + * Testing routes for Metatag tests. + */ +class MetatagTestCustomRouteController extends ControllerBase { + + /** + * Constructs a page for integration testing. + */ + public function test() { + $render = [ + '#markup' => $this->t('<p>Hello world!</p>'), + ]; + + return $render; + } + +} diff --git a/web/modules/metatag/tests/modules/metatag_test_tag/config/schema/metatag_test_tag.metatag_tag.schema.yml b/web/modules/metatag/tests/modules/metatag_test_tag/config/schema/metatag_test_tag.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..f401affa92a6558b648142aa6238f26a3a00003d --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_tag/config/schema/metatag_test_tag.metatag_tag.schema.yml @@ -0,0 +1,3 @@ +metatag.metatag_tag.metatag_test_tag: + type: label + label: 'Metatag Test' 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 new file mode 100644 index 0000000000000000000000000000000000000000..04a5a51c8f2618d74ad6eba08689e27f783bb7c4 --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.info.yml @@ -0,0 +1,13 @@ +name: 'Metatag Tests: Tag' +type: module +description: 'Support module for testing handling of a custom meta tag.' +# core: 8.x +package: Testing +dependencies: + - metatag:metatag + +# Information added by Drupal.org packaging script on 2018-08-31 +version: '8.x-1.7' +core: '8.x' +project: 'metatag' +datestamp: 1535726412 diff --git a/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.metatag_tag.schema.yml b/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.metatag_tag.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..4055732069734b77f76699cfdb811be7b8ccf953 --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.metatag_tag.schema.yml @@ -0,0 +1,3 @@ +metatag.metatag_tag.metatag_test_tag: + type: label + label: 'Metatag test' diff --git a/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.module b/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.module new file mode 100644 index 0000000000000000000000000000000000000000..65808d44f6f1e24d5720172d1ed74e0f8b73f0cd --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_tag/metatag_test_tag.module @@ -0,0 +1,6 @@ +<?php + +/** + * @file + * Primary hook implementations for the Metatag Test Tag module. + */ diff --git a/web/modules/metatag/tests/modules/metatag_test_tag/src/Plugin/metatag/Tag/MetatagTestTag.php b/web/modules/metatag/tests/modules/metatag_test_tag/src/Plugin/metatag/Tag/MetatagTestTag.php new file mode 100644 index 0000000000000000000000000000000000000000..eb420def2b34e7fcd59c1dbd9c7b0c8da4dcd4a9 --- /dev/null +++ b/web/modules/metatag/tests/modules/metatag_test_tag/src/Plugin/metatag/Tag/MetatagTestTag.php @@ -0,0 +1,23 @@ +<?php + +namespace Drupal\metatag_test_tag\Plugin\metatag\Tag; + +use Drupal\metatag\Plugin\metatag\Tag\MetaNameBase; + +/** + * A metatag tag for testing. + * + * @MetatagTag( + * id = "metatag_test_tag", + * label = @Translation("Metatag Test"), + * description = @Translation("A metatag tag for testing."), + * name = "metatag_test_tag", + * group = "basic", + * weight = 3, + * type = "label", + * secure = FALSE, + * multiple = FALSE + * ) + */ +class MetatagTestTag extends MetaNameBase { +} diff --git a/web/modules/metatag/tests/src/Functional/DefaultTags.php b/web/modules/metatag/tests/src/Functional/DefaultTags.php new file mode 100644 index 0000000000000000000000000000000000000000..8bd2b958cc3a6a50bfed790a5dce49ae8886ad58 --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/DefaultTags.php @@ -0,0 +1,156 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Verify that the configured defaults load as intended. + * + * @group metatag + */ +class DefaultTags extends BrowserTestBase { + + // Contains helper methods. + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Modules for core functionality. + 'node', + 'taxonomy', + 'user', + + // Need this so that the /node page exists. + 'views', + + // Contrib dependencies. + 'token', + + // This module. + 'metatag', + + // Use the custom route to verify the site works. + 'metatag_test_custom_route', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Set the front page to the main /node page, so that the front page is not + // just the login page. + \Drupal::configFactory() + ->getEditable('system.site') + ->set('page.front', '/node') + ->save(TRUE); + } + + /** + * Test the default values for the front page. + */ + public function testFrontpage() { + $this->drupalGet('<front>'); + $this->assertResponse(200); + $xpath = $this->xpath("//link[@rel='canonical']"); + $this_page_url = $this->buildUrl('<front>'); + $this->assertEqual((string) $xpath[0]->getAttribute('href'), $this_page_url); + } + + /** + * Test the default values for a custom route. + */ + public function testCustomRoute() { + $this->drupalGet('metatag_test_custom_route'); + $this->assertResponse(200); + $this->assertText('Hello world!'); + + // Check the meta tags. + $xpath = $this->xpath("//link[@rel='canonical']"); + $this_page_url = $this->buildUrl('/metatag_test_custom_route'); + $this->assertEqual((string) $xpath[0]->getAttribute('href'), $this_page_url); + } + + /** + * Test the default values for a Node entity. + */ + public function testNode() { + $node = $this->createContentTypeNode(); + $this_page_url = $node->toUrl('canonical', ['absolute' => TRUE])->toString(); + + // Load the node's entity page. + $this->drupalGet($this_page_url); + $this->assertResponse(200); + + // Check the meta tags. + $xpath = $this->xpath("//link[@rel='canonical']"); + $this->assertEqual((string) $xpath[0]->getAttribute('href'), $this_page_url); + } + + /** + * Test the default values for a Term entity. + */ + public function testTerm() { + $vocab = $this->createVocabulary(); + $term = $this->createTerm(['vid' => $vocab->id()]); + $this_page_url = $term->toUrl('canonical', ['absolute' => TRUE])->toString(); + $this->drupalGet($this_page_url); + $this->assertResponse(200); + + // Check the meta tags. + $xpath = $this->xpath("//link[@rel='canonical']"); + $this->assertEqual((string) $xpath[0]->getAttribute('href'), $this_page_url); + } + + /** + * Test the default values for a User entity. + */ + public function testUser() { + $this->loginUser1(); + $account = \Drupal::currentUser()->getAccount(); + $this_page_url = $account->toUrl('canonical', ['absolute' => TRUE])->toString(); + + // Load the user's entity page. + $this->drupalGet($this_page_url); + $this->assertResponse(200); + + // Check the meta tags. + $xpath = $this->xpath("//link[@rel='canonical']"); + $this->assertEqual((string) $xpath[0]->getAttribute('href'), $this_page_url); + $this->drupalLogout(); + } + + /** + * Test the default values for the user login page, etc. + */ + public function testUserLoginPages() { + $front_url = $this->buildUrl('<front>', ['absolute' => TRUE]);; + + // A list of paths to examine. + $routes = [ + '/user/login', + '/user/register', + '/user/password', + ]; + + foreach ($routes as $route) { + // Identify the path to load. + $this_page_url = $this->buildUrl($route, ['absolute' => TRUE]); + $this->assertTrue(!empty($this_page_url)); + + // Load the path. + $this->drupalGet($this_page_url); + $this->assertResponse(200); + + // Check the meta tags. + $xpath = $this->xpath("//link[@rel='canonical']"); + $this->assertNotEqual((string) $xpath[0]->getAttribute('href'), $front_url); + $this->assertEqual((string) $xpath[0]->getAttribute('href'), $this_page_url); + } + } + +} diff --git a/web/modules/metatag/tests/src/Functional/EnsureDevelWebProfilerWorks.php b/web/modules/metatag/tests/src/Functional/EnsureDevelWebProfilerWorks.php new file mode 100644 index 0000000000000000000000000000000000000000..654f1bff7b798fe33fd413be9c459e82246daf84 --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/EnsureDevelWebProfilerWorks.php @@ -0,0 +1,36 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +/** + * Verify that enabling WebProfiler don't cause the site to blow up. + * + * @group metatag + */ +class EnsureDevelWebProfilerWorks extends EnsureDevelWorks { + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Modules for core functionality. + 'node', + 'field', + 'field_ui', + 'user', + + // Contrib dependencies. + 'token', + + // This module. + 'metatag', + + // Use the custom route to verify the site works. + 'metatag_test_custom_route', + + // The modules to test. + 'devel', + 'webprofiler', + ]; + +} diff --git a/web/modules/metatag/tests/src/Functional/EnsureDevelWorks.php b/web/modules/metatag/tests/src/Functional/EnsureDevelWorks.php new file mode 100644 index 0000000000000000000000000000000000000000..fa392f2681ce57a8515f9b78d0565bacffe649eb --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/EnsureDevelWorks.php @@ -0,0 +1,58 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Verify that enabling Devel don't cause the site to blow up. + * + * @group metatag + */ +class EnsureDevelWorks extends BrowserTestBase { + + // Contains helper methods. + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Modules for core functionality. + 'node', + 'field', + 'field_ui', + 'user', + + // Contrib dependencies. + 'token', + + // This module. + 'metatag', + + // Use the custom route to verify the site works. + 'metatag_test_custom_route', + + // The modules to test. + 'devel', + ]; + + /** + * Load the custom route, make sure something is output. + */ + public function testCustomRoute() { + $this->drupalGet('metatag_test_custom_route'); + $this->assertResponse(200); + $this->assertText('Hello world!'); + } + + /** + * Make sure that the system still works when some example content exists. + */ + public function testNode() { + $node = $this->createContentTypeNode(); + $this->drupalGet($node->toUrl()); + $this->assertResponse(200); + } + +} diff --git a/web/modules/metatag/tests/src/Functional/MetatagHelperTrait.php b/web/modules/metatag/tests/src/Functional/MetatagHelperTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..659b5ef63e8235a50a90295dcc8ef81c9b3a7c7f --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/MetatagHelperTrait.php @@ -0,0 +1,157 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\Component\Render\FormattableMarkup; +use Drupal\Component\Utility\Html; +use Drupal\taxonomy\Entity\Term; +use Drupal\taxonomy\Entity\Vocabulary; +use Drupal\user\Entity\User; + +/** + * Misc helper functions for the automated tests. + */ +trait MetatagHelperTrait { + + /** + * Log in as user 1. + */ + protected function loginUser1() { + // Load user 1. + /* @var \Drupal\user\Entity\User $account */ + $account = User::load(1); + + // Reset the password. + $password = 'foo'; + $account->setPassword($password)->save(); + + // Support old and new tests. + $account->passRaw = $password; + $account->pass_raw = $password; + + // 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); + } + + /** + * Create a content type and a node. + * + * @param string $title + * A title for the node that will be returned. + * @param string $body + * The text to use as the body. + * + * @return \Drupal\node\NodeInterface + * A fully formatted node object. + */ + private function createContentTypeNode($title = 'Title test', $body = 'Body test') { + $content_type = 'metatag_test'; + $args = [ + 'type' => $content_type, + 'label' => 'Test content type', + ]; + $this->createContentType($args); + + $args = [ + 'body' => [ + [ + 'value' => $body, + 'format' => filter_default_format(), + ], + ], + 'title' => $title, + 'type' => $content_type, + ]; + + return $this->createNode($args); + } + + /** + * Create a vocabulary. + * + * @param array $values + * Items passed to the vocabulary. If the 'vid' item is not present it will + * be automatically generated. If the 'name' item is not present the 'vid' + * will be used. + * + * @return \Drupal\taxonomy\Entity\Vocabulary + * A fully formatted vocabulary object. + */ + private function createVocabulary(array $values = []) { + // Find a non-existent random type name. + if (!isset($values['vid'])) { + do { + $id = strtolower($this->randomMachineName(8)); + } while (Vocabulary::load($id)); + } + else { + $id = $values['vid']; + } + $values += [ + 'vid' => $id, + 'name' => $id, + ]; + $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 { + $this->assertEqual($status, SAVED_NEW, (new FormattableMarkup('Created vocabulary %type.', ['%type' => $vocab->id()]))->__toString()); + } + + return $vocab; + } + + /** + * Create a taxonomy term. + * + * @param array $values + * Items passed to the term. Requires the 'vid' element. + * + * @return Drupal\taxonomy\Entity\Term + * A fully formatted term object. + */ + private function createTerm(array $values = []) { + // Populate defaults array. + $values += [ + 'description' => [ + [ + 'value' => $this->randomMachineName(32), + 'format' => filter_default_format(), + ], + ], + 'name' => $this->randomMachineName(8), + ]; + $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 { + $this->assertEqual($status, SAVED_NEW, (new FormattableMarkup('Created term %name.', ['%name' => $term->label()]))->__toString()); + } + + return $term; + } + +} diff --git a/web/modules/metatag/tests/src/Functional/NodeJsonOutput.php b/web/modules/metatag/tests/src/Functional/NodeJsonOutput.php new file mode 100644 index 0000000000000000000000000000000000000000..44681192f1fa577b3ba74b870a92115f43375b75 --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/NodeJsonOutput.php @@ -0,0 +1,135 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\Core\Cache\Cache; +use Drupal\rest\RestResourceConfigInterface; +use Drupal\Tests\BrowserTestBase; + +/** + * Verify that the JSON output from core works as intended. + * + * @group metatag + */ +class NodeJsonOutput extends BrowserTestBase { + + // Contains helper methods. + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Modules for core functionality. + 'node', + 'field', + 'field_ui', + 'user', + + // Contrib dependencies. + 'token', + + // This module. + 'metatag', + + // The modules to test. + 'serialization', + 'hal', + 'rest', + + // Need this to make the configuration sane. + 'restui', + ]; + + /** + * Create an entity, view its JSON output, confirm Metatag data exists. + */ + public function testNode() { + $this->provisionResource(); + + /* @var\Drupal\node\NodeInterface $node */ + $node = $this->createContentTypeNode('Test JSON output', 'Testing JSON output for a content type'); + $url = $node->toUrl(); + + // Load the node's page. + $this->drupalGet($url); + $this->assertResponse(200); + + // Load the JSON output. + $url->setOption('query', ['_format' => 'json']); + $response = $this->drupalGet($url); + $this->assertResponse(200); + + // Decode the JSON output. + $response = $this->getRawContent(); + $this->assertTrue(!empty($response)); + $json = json_decode($response); + $this->verbose($json, 'JSON output'); + $this->assertTrue(!empty($json)); + + // Confirm the JSON object's values. + $this->assertTrue(isset($json->nid)); + if (isset($json->nid)) { + $this->assertTrue($json->nid[0]->value == $node->id()); + } + $this->assertTrue(isset($json->metatag)); + if (isset($json->metatag)) { + $this->assertTrue($json->metatag->value->title == $node->label() . ' | Drupal'); + // @todo Test other meta tags. + } + } + + /** + * Provisions the REST resource under test. + * + * @param string $entity_type + * The entity type to be enabled; defaults to 'node'. + * @param array $formats + * The allowed formats for this resource; defaults to ['json']. + * @param array $authentication + * The allowed authentication providers for this resource; defaults to + * ['basic_auth']. + */ + protected function provisionResource($entity_type = 'node', array $formats = [], array $authentication = []) { + $this->resourceConfigStorage = $this->container + ->get('entity_type.manager') + ->getStorage('rest_resource_config'); + + // Defaults. + if (empty($formats)) { + $formats[] = 'json'; + } + if (empty($authentication)) { + $authentication[] = 'basic_auth'; + } + + $this->resourceConfigStorage->create([ + 'id' => 'entity.' . $entity_type, + 'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY, + 'configuration' => [ + 'methods' => ['GET', 'POST', 'PATCH', 'DELETE'], + 'formats' => $formats, + 'authentication' => $authentication, + ], + 'status' => TRUE, + ])->save(); + + // Ensure that the cache tags invalidator has its internal values reset. + // Otherwise the http_response cache tag invalidation won't work. + // Clear the tag cache. + \Drupal::service('cache_tags.invalidator')->resetChecksums(); + foreach (Cache::getBins() as $backend) { + if (is_callable([$backend, 'reset'])) { + $backend->reset(); + } + } + $this->container->get('config.factory')->reset(); + $this->container->get('state')->resetCache(); + + // Tests using this base class may trigger route rebuilds due to changes to + // RestResourceConfig entities or 'rest.settings'. Ensure the test generates + // routes using an up-to-date router. + \Drupal::service('router.builder')->rebuildIfNeeded(); + } + +} diff --git a/web/modules/metatag/tests/src/Functional/NodeTranslation.php b/web/modules/metatag/tests/src/Functional/NodeTranslation.php new file mode 100644 index 0000000000000000000000000000000000000000..91b444379be19b5197ef64ae76aad05e26a38183 --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/NodeTranslation.php @@ -0,0 +1,76 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Verify that node translation form works. + * + * @group metatag + */ +class NodeTranslation extends BrowserTestBase { + + // Contains helper methods. + use MetatagHelperTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + // Modules for core functionality. + 'language', + 'node', + 'field_ui', + 'user', + + // Contrib dependencies. + 'token', + + // This module. + 'metatag', + + // The extra module(s) to test. + 'content_translation', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + // Login. + $this->loginUser1(); + + // Add language. + $this->drupalGet('/admin/config/regional/language/add'); + $this->assertResponse(200); + $edit = [ + 'predefined_langcode' => 'hu', + ]; + $this->drupalPostForm(NULL, $edit, 'Add language'); + + // Set up a content type. + $this->drupalCreateContentType(['type' => 'article']); + $this->drupalGet('/admin/structure/types/manage/article'); + $this->assertResponse(200); + $edit = [ + 'language_configuration[content_translation]' => TRUE, + ]; + $this->drupalPostForm(NULL, $edit, 'Save content type'); + } + + /** + * Load the custom route, make sure something is output. + */ + public function testContentTranslationForm() { + $this->drupalGet('/admin/config/regional/content-language'); + $this->assertResponse(200); + $this->assertText('Content language'); + $this->drupalPostForm(NULL, [], 'Save configuration'); + $this->assertResponse(200); + $this->assertText('Settings successfully updated.'); + } + +} diff --git a/web/modules/metatag/tests/src/Functional/RemoveCoreMetaTags.php b/web/modules/metatag/tests/src/Functional/RemoveCoreMetaTags.php new file mode 100644 index 0000000000000000000000000000000000000000..489b007ba16f760d2ae67aa416869dad4e761d8f --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/RemoveCoreMetaTags.php @@ -0,0 +1,60 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\taxonomy\Entity\Term; +use Drupal\taxonomy\Entity\Vocabulary; +use Drupal\Tests\BrowserTestBase; + +/** + * Ensures that meta tags output by core are removed if we are overriding them. + * + * @group metatag + */ +class RemoveCoreMetaTags extends BrowserTestBase { + + // Contains helper methods. + use MetatagHelperTrait; + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + 'token', + 'metatag', + 'taxonomy', + ]; + + /** + * Tests core tags are removed on taxonomy term pages. + */ + public function testTaxonomyPage() { + $this->loginUser1(); + + // Set up a vocabulary. + $vocabulary = Vocabulary::create([ + 'vid' => 'metatag_vocab', + 'name' => $this->randomString(), + ]); + $vocabulary->save(); + $term = Term::create([ + 'vid' => $vocabulary->id(), + 'name' => $this->randomString(), + ]); + $term->save(); + + // Set up meta tags for taxonomy. + $edit = [ + 'canonical_url' => '[current-page:url:unaliased]', + ]; + $this->drupalPostForm('admin/config/search/metatag/taxonomy_term', $edit, 'Save'); + + // Ensure there is only 1 canonical metatag. + $this->drupalGet('taxonomy/term/' . $term->id()); + $xpath = $this->xpath("//link[@rel='canonical']"); + $this->assertEquals(1, count($xpath), 'Exactly one canonical rel meta tag found.'); + } + +} diff --git a/web/modules/metatag/tests/src/Functional/SchemaMetatagTest.php b/web/modules/metatag/tests/src/Functional/SchemaMetatagTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bc4330c6db940de1a1d25ded496fd97b5315c77f --- /dev/null +++ b/web/modules/metatag/tests/src/Functional/SchemaMetatagTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\metatag\Functional; + +use Drupal\Tests\schema_web_page\Functional\SchemaWebPageTest; + +/** + * Wrapper to trigger one of the Schema.org Metatag module's tests. + * + * This will help avoid making changes to Metatag that trigger problems for + * separate submodules. + * + * @see https://www.drupal.org/project/metatag/issues/2994979 + * + * @group metatag + */ +class SchemaMetatagTest extends SchemaWebPageTest { + // Just run the tests as-is. +} diff --git a/web/modules/metatag/tests/src/Kernel/MetatagManagerTest.php b/web/modules/metatag/tests/src/Kernel/MetatagManagerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f086bef4616d958e3f1d26bd02f83f47aea411a0 --- /dev/null +++ b/web/modules/metatag/tests/src/Kernel/MetatagManagerTest.php @@ -0,0 +1,136 @@ +<?php + +namespace Drupal\Tests\metatag\Kernel; + +use Drupal\KernelTests\KernelTestBase; + +/** + * Test the Metatag Manager class. + * + * @group metatag + */ +class MetatagManagerTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'metatag', + 'metatag_open_graph', + ]; + + /** + * Test the order of the meta tags as they are output. + */ + public function testMetatagOrder() { + /** @var \Drupal\metatag\MetatagManager $metatag_manager */ + $metatag_manager = \Drupal::service('metatag.manager'); + + $tags = $metatag_manager->generateElements([ + 'og_image_width' => 100, + 'og_image_height' => 100, + 'og_image_url' => 'http://www.example.com/example/foo.png', + ]); + + $expected = [ + '#attached' => [ + 'html_head' => [ + [ + [ + '#tag' => 'meta', + '#attributes' => [ + 'property' => 'og:image:url', + 'content' => 'http://www.example.com/example/foo.png', + ], + ], + 'og_image_url_0', + ], + [ + [ + '#tag' => 'meta', + '#attributes' => [ + 'property' => 'og:image:width', + 'content' => 100, + ], + ], + 'og_image_width', + ], + [ + [ + '#tag' => 'meta', + '#attributes' => [ + 'property' => 'og:image:height', + 'content' => 100, + ], + ], + 'og_image_height', + ], + ], + ], + ]; + $this->assertEquals($expected, $tags); + } + + /** + * Tests metatags with multiple values return multiple metatags. + */ + public function testMetatagMultiple() { + /** @var \Drupal\metatag\MetatagManager $metatag_manager */ + $metatag_manager = \Drupal::service('metatag.manager'); + + $tags = $metatag_manager->generateElements([ + 'og_image_width' => 100, + 'og_image_height' => 100, + 'og_image_url' => 'http://www.example.com/example/foo.png, http://www.example.com/example/foo2.png', + ]); + + $expected = [ + '#attached' => [ + 'html_head' => [ + [ + [ + '#tag' => 'meta', + '#attributes' => [ + 'property' => 'og:image:url', + 'content' => 'http://www.example.com/example/foo.png', + ], + ], + 'og_image_url_0', + ], + [ + [ + '#tag' => 'meta', + '#attributes' => [ + 'property' => 'og:image:url', + 'content' => 'http://www.example.com/example/foo2.png', + ], + ], + 'og_image_url_1', + ], + [ + [ + '#tag' => 'meta', + '#attributes' => [ + 'property' => 'og:image:width', + 'content' => 100, + ], + ], + 'og_image_width', + ], + [ + [ + '#tag' => 'meta', + '#attributes' => [ + 'property' => 'og:image:height', + 'content' => 100, + ], + ], + 'og_image_height', + ], + ], + ], + ]; + $this->assertEquals($expected, $tags); + } + +}