diff --git a/profiles/wcm_base/CHANGELOG.txt b/profiles/wcm_base/CHANGELOG.txt
index f08ff2de6ced92cd5a25b65182c1fe27884492de..61e8e0378e5fdd93362523ad74f4db47bf08d3e9 100644
--- a/profiles/wcm_base/CHANGELOG.txt
+++ b/profiles/wcm_base/CHANGELOG.txt
@@ -1,8 +1,15 @@
+WCM Base 7.x-1.x, 2017-03-21
+----------------------------
+- WCM Base: Added WCM Metatags module.
+- WCM User Config: Changed "OSU" to "Ohio State" on login template.
+- WCM User Profile: Fixed permissions check for user profiles.
+
 WCM Base 7.x-1.x, 2017-03-14
 ----------------------------
 - WCM Omega: Added a second menu style option.
 - WCM User Profile: Made first and last name fields optional.
 - WCM Workbench: Fixed unpublished content missing from All Recent Content page.
+- OCIO Book: Added context to display book navigation.
 - OCIO Main Menu: Added context to support new menu style option for WCM Omega theme.
 - OCIO News: Added Kicker, Byline, Sidebar, Learn More fields.
 - OCIO Web Form: Hid node revision option instead of all publishing options.
diff --git a/profiles/wcm_base/build-wcm_base-dev.make b/profiles/wcm_base/build-wcm_base-dev.make
index 6ec3cd0e8a7944e3aae39a15e9662eecfc118aa0..67dcdd555628a905fca704a7b6878075962cc58a 100644
--- a/profiles/wcm_base/build-wcm_base-dev.make
+++ b/profiles/wcm_base/build-wcm_base-dev.make
@@ -25,6 +25,7 @@ projects[ocio_main_menu][options][working-copy] = TRUE
 projects[ocio_media][options][working-copy] = TRUE
 projects[ocio_news][options][working-copy] = TRUE
 projects[ocio_omega_settings][options][working-copy] = TRUE
+projects[wcm_metatags][options][working-copy] = TRUE
 projects[wcm_panels_settings][options][working-copy] = TRUE
 projects[wcm_permissions][options][working-copy] = TRUE
 projects[wcm_search][options][working-copy] = TRUE
diff --git a/profiles/wcm_base/libraries/colorbox/README.md b/profiles/wcm_base/libraries/colorbox/README.md
index 298507619f1382befd474168084f8f6baec53c8e..ae91e29ddffe224dea8640ccdcd060b21f4ca0ed 100644
--- a/profiles/wcm_base/libraries/colorbox/README.md
+++ b/profiles/wcm_base/libraries/colorbox/README.md
@@ -438,7 +438,7 @@ Files Changed: jquery.colorbox.js/jquery.colorbox-min.js
 
 * Added 'innerWidth' and 'innerHeight' options to allow people to easily set the size dimensions for Colorbox, without having to anticipate the size of the borders and buttons.
 * Renamed 'scrollbars' option to 'scrolling' to be in keeping with the existing HTML attribute. The option now also applies to iframes.
-* Bug fix: In Safari, positioning occassionally incorrect when using '100%' dimensions.
+* Bug fix: In Safari, positioning occasionally incorrect when using '100%' dimensions.
 * Bug fix: In IE6, the background overlay is briefly not full size when first viewing.
 * Bug fix: In Firefox, opening Colorbox causes a split second shift with a small minority of webpage layouts.
 * Simplified code in a few areas.
diff --git a/profiles/wcm_base/libraries/colorbox/jquery.colorbox.js b/profiles/wcm_base/libraries/colorbox/jquery.colorbox.js
index 12dd1b2b69e79c76d85317054726288d1340cf6f..a4e2d15650fb286d5ea6036c43299436df7608d0 100644
--- a/profiles/wcm_base/libraries/colorbox/jquery.colorbox.js
+++ b/profiles/wcm_base/libraries/colorbox/jquery.colorbox.js
@@ -155,7 +155,7 @@
 	$prev,
 	$close,
 	$groupControls,
-	$events = $('<a/>'), // $({}) would be prefered, but there is an issue with jQuery 1.4.2
+	$events = $('<a/>'), // $({}) would be preferred, but there is an issue with jQuery 1.4.2
 
 	// Variables for cached values or use across multiple functions
 	settings,
@@ -982,7 +982,7 @@
 					return;
 				}
 
-				// A small pause because some browsers will occassionaly report a
+				// A small pause because some browsers will occasionally report a
 				// img.width and img.height of zero immediately after the img.onload fires
 				setTimeout(function(){
 					var percent;
diff --git a/profiles/wcm_base/modules/contrib/metatag/.codeclimate.yml b/profiles/wcm_base/modules/contrib/metatag/.codeclimate.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e8b0bd077e5c241bb3886d7ef423511101bb0a9f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/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/profiles/wcm_base/modules/contrib/metatag/.csslintrc b/profiles/wcm_base/modules/contrib/metatag/.csslintrc
new file mode 100644
index 0000000000000000000000000000000000000000..aacba956e5bbede1c195ce554fcad3e200b24ff8
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/.csslintrc
@@ -0,0 +1,2 @@
+--exclude-exts=.min.css
+--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
diff --git a/profiles/wcm_base/modules/contrib/metatag/.eslintignore b/profiles/wcm_base/modules/contrib/metatag/.eslintignore
new file mode 100644
index 0000000000000000000000000000000000000000..96212a3593bac8c93f624b77185a8d11018efd96
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/.eslintignore
@@ -0,0 +1 @@
+**/*{.,-}min.js
diff --git a/profiles/wcm_base/modules/contrib/metatag/.eslintrc b/profiles/wcm_base/modules/contrib/metatag/.eslintrc
new file mode 100644
index 0000000000000000000000000000000000000000..9faa37508e533c82089e0485dd9e9907370a309d
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/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/profiles/wcm_base/modules/contrib/metatag/CHANGELOG.txt b/profiles/wcm_base/modules/contrib/metatag/CHANGELOG.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ad38e6370bb51f9af99a6e4fe3819ab55368c8a2
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/CHANGELOG.txt
@@ -0,0 +1,1081 @@
+Metatag 7.x-1.21, 2017-02-15
+----------------------------
+#2844504 by DamienMcKenna: Add project names to all dependencies.
+By DamienMcKenna: Backported some minor text changes from the D8 branch.
+#2821713 by WidgetsBurritos: Don't output the mask-icon 'color' attribute if
+  it's empty.
+By DamienMcKenna, Michelle: Minor updates to README.txt.
+#2852260 by DamienMcKenna: Output caching wasn't fully disabled for the front
+  page or non-entity pages that used the global defaults.
+#2852737 by DamienMcKenna: Added CodeClimate config files.
+By DamienMcKenna, klausi: Information disclosure issue under certain
+  circumstances.
+
+
+Metatag 7.x-1.20, 2017-01-18
+----------------------------
+#2840500 by DamienMcKenna: Bring back compatibility with Workbench Moderation
+  v1.
+#2841064 by klausi, DamienMcKenna: Fix sandbox-based update scripts so they
+  don't run into infinite loops.
+
+
+Metatag 7.x-1.19, 2017-01-01
+----------------------------
+#2832427 by dmitry.kazberovich, e2thex, DamienMcKenna: Allow the metatag cache
+  expiration time to be modified.
+#2780025 by DamienMcKenna: Backported output tests from D8. Also fixes the
+  output of the shortcut icon, ios-app, android-app, author, publisher, and made
+  the Google CSE thumbnail tag an 'image'. Left some others to be fixed later.
+#2832476 by czigor; Added the 'product.group' and 'place' og:type options.
+#2835614 by drumm: metatag_metatags_load_multiple() doesn't need to sort the
+  results.
+By DamienMcKenna: Noted in the metatag_google_plus info file and README.txt that
+  it includes the Author and Publisher meta tags.
+By DamienMcKenna: Tweaked the favicons module description.
+By DamienMcKenna: Updated main tests to match the latest coding standards.
+By DamienMcKenna: Minor updates to various Google CSE labels.
+By DamienMcKenna: A string in metatag_opengraph_products wasn't using an
+  argument that was being passed to it.
+By DamienMcKenna: Minor adjustment to metatag_mobile strings.
+By DamienMcKenna: Updated submodule tests to match the latest coding standards.
+#2838198 by DamienMcKenna, Mixologic: Test dependency changes to workaround
+  changes in the DrupalCI platform.
+#2831073 by dxvargas, DamienMcKenna: Remove old workarounds due to Workbench
+  Moderation 3.x API changes, warn if older version installed.
+
+
+Metatag 7.x-1.18, 2016-11-30
+----------------------------
+#2761817 by DamienMcKenna: Fixed metatag_update_replace_config() so it isn't
+  hardcoded to only work with og:video.
+#2759843 by DamienMcKenna: Removed the Alexa verification tag.
+#2759855 by DamienMcKenna: Removed the Yahoo verification tag.
+By DamienMcKenna: Clear Metatag's caches after deleting or renaming a meta tag.
+#2763499 by DamienMcKenna: Don't use entity_load() when saving Metatag data,
+  it can cause anomolies.
+#2750705 by jalpesh, susannecoates: Updated description of the Google Play app
+  ID meta tag.
+#2771603 by FeyP: Fixed incorrect argument name to metatag_metatag_save().
+#2745177 by DamienMcKenna: Tests to confirm each meta tag can be filled in and
+  added to the global settings.
+#2773839 by DamienMcKenna: Remove 'metatag_ui' from the {system} table.
+#2773465 by DamienMcKenna: Because Page Title is now fully deprecated, promote
+  converting its settings and uninstalling it.
+#1944862 by FeyP, DamienMcKenna: Allow control over which meta tags and
+  languages are reverted on the Bulk Revert page.
+#2766315 by recrit, DamienMcKenna: metatag_entity_type_enable() would
+  incorrectly change settings in certain circumstances.
+#2774859 by DamienMcKenna: Refactored main tests to not use the submodules by
+  default.
+#2678896 by nmalinoski: Fixed redundant t() calls to fix double translation.
+#2787189 by DamienMcKenna: Added some tests to confirm that the different node
+  preview options don't interfere with saving meta tag values.
+By DamienMcKenna: Added a Known Issue for problems with Entity Token.
+#2790967 by DamienMcKenna: Added tests for taxonomy term config translations
+  using i18n.
+#2795255 by lazysoundsystem: 'disabled' was misspelled.
+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 Author meta tag to GooglePlus submodule.
+#1343914 by DamienMcKenna: Moved Publisher meta tag to GooglePlus submodule.
+#2784879 by sorinb, DamienMcKenna: Change metatag_update_7108 to use a sandbox.
+#2791963 by ttkaminski, DamienMcKenna: Don't change protocol-relative URLs in
+  image values.
+#2797069 by Internet, DamienMcKenna: Corrected the URL to Wikipedia's ICBM page.
+#2799317 by mdooley: Use a static date example for the Expires meta tag's
+  description to avoid flooding the {locales_source} table.
+#2800479 by DamienMcKenna, david.gil: Avoid showing errors if Search API is not
+  installed.
+By DamienMcKenna: Slight reordering of the main info file.
+#2663208 by DamienMcKenna, geertvd: Don't load meta tags on the /user/me page,
+  avoid problems when the Me module is installed.
+#2813429 by DamienMcKenna: Added tests for metatag_mobile.
+#2813427 by DamienMcKenna: Added support for the amphtml link tag.
+#2811735 by Stevel, DamienMcKenna: Added dependencies to all tests so that tests
+  will only be listed if those dependencies are also available.
+By stimalsina: Minor improvements to the amphtml meta tag's description.
+#2823367 by DamienMcKenna: Fixed tests after internal API change in Media.
+#2826023 by renatog, DamienMcKenna, gfcamilo: Coding standards fixes for
+  metatag.module.
+#2831030 by prince_zyxware: Fixed some minor coding standard bugs, spacing
+ issues.
+#2759461 by DamienMcKenna: hreflang=x-default is no longer removed when another
+  hreflang meta tag has the same URL, instead the other tag is removed as it
+  was supposed to be. Added a new [node:url-original] token for showing the
+  URL for the source node for translations; updated the default value for
+  the hreflang=x-default meta tag to use the new token instead of
+  [node:source:url]. Updates to many tests to allow these changes.
+#2532588 by cebasqueira, renatog, DamienMcKenna: Added new meta tags for Google
+  CSE.
+#2796701 by DrupalDano, DamienMcKenna: Some XSS tests for meta tag handling.
+#2831073 by DamienMcKenna: Added Workbench Moderation as a test dependency, for
+  future use.
+#2831822 by DamienMcKenna: Added support for the handheld mobile alternate link
+  tag, supported by Google.
+
+
+Metatag 7.x-1.17, 2016-06-30
+----------------------------
+#2748627 by jalpesh: Corrected twitter:app:id:googleplay description.
+#2752319 by DamienMcKenna: Fixed output of the mask-icon meta tag.
+#2752319 by DamienMcKenna: Added the mask-icon 'color' attribute, the new 'url'
+  option for meta tag definitions, and tests for the mask-icon meta tag.
+#2754263 by DamienMcKenna: Meta tags with multiple values should still be
+  returned as a string from metatag_get_value().
+#1953080 by DamienMcKenna: Don't output language/locale meta tags if they are
+  equal to LANGUAGE_NONE/"und".
+#2659906 by DamienMcKenna: Rewrote update 7040 to use less memory and work
+  better.
+#2720723 by IRuslan: Allow config instance names to be changed.
+#2669592 by DamienMcKenna: Fix for possible problem with removal of meta tags
+  that Metatag is already outputting.
+#2162397 by DamienMckenna: Added test dependency for Profile2.
+#2162397 by roderick, DamienMckenna, hideaway: Fixed loading multiple entities
+  on the same path when at least one of them is not enabled for use with
+  Metatag and gets in the way of the one which is enabled.
+
+
+Metatag 7.x-1.16, 2016-06-03
+----------------------------
+#2742063 by jalpesh, DamienMcKenna: Fix syntax error in verification module.
+#2742123 by DamienMcKenna: Added test for all submodules to ensure they could be
+  enabled.
+
+
+Metatag 7.x-1.15, 2016-06-03
+----------------------------
+#2700217 by DamienMcKenna: Added Media module as a test dependency.
+#2700217 by DamienMcKenna: Automatically filter out Media embed codes from meta
+  tags when the Media WYSIWYG module is installed.
+#2709985 by alzz: Added fb:pages meta tag for Facebook Instant Pages.
+#2703081 by DylanUnderwood: Added apple-mobile-web-app-title meta tag.
+#2704805 by jcnventura: Fixed the hreflang meta tag.
+#2678004 by alvar0hurtad0: Improvements to the API documentation.
+By DamienMcKenna: Corrected some messages in metatag_update_7104.
+By DamienMcKenna: Incorrect indenting in metatag_favicons.metatag.inc.
+#2687309 by das-peter, skein, DamienMcKenna, k_zoltan: Fixed output translations
+  so it's actually disabled when it's turned off.
+#2712815 by Chalk, DamienMcKenna: Rewrote update scripts that rename meta tags
+  to use two new shared functions, and always use a sandbox for it.
+#2720463 by DamienMcKenna: Rename the icon_any favicon to mask-icon.
+#2276855 by ben.kyriakou: Properly handle the 'disabled' state when featurized
+  configs are reverted.
+#2687309 by das-peter, DamienMcKenna: Submodules shouldn't update translations
+  during page load.
+#2725251 by DamienMcKenna, Jim.M: Added validation tags for Alexa, Baidu, Norton
+  Safe Web and Yahoo.
+#2725741 by DamienMcKenna: Ensure the Locale module is enabled before running db
+  queries against the {locales_source} table.
+By DamienMcKenna: Updated the docblock comment for metatag_metatags_save().
+#2728919 by DYdave: Workaround for CTools bug that causes the Views popup to be
+  tiny.
+#2728933 by DYdave, DamienMcKenna: Trigger hook_metatag_token_types() from
+  metatag_metatags_form() instead of metatag_field_attach_form() so it works
+  with all submodules too.
+#2710377 by DamienMcKenna: Updated the message for og:image:url to make it
+  clear it might be better to not use it.
+#2539388 by DamienMcKenna: All image meta tags will be output with absolute URLs
+  and spaces will be replaced with '%20'.
+#2692877 by stefan.r, DamienMcKenna, Drunkey Monkey: Search API integration.
+#2720221 by dnmurray: Allow sanitizing of values through token_replace(); for
+  advanced usage only, may lead to other issues.
+#2497043 by marcelovani, uzlov: Allow Metatag:Context configs to be sorted by a
+  'weight' value.
+
+
+Metatag 7.x-1.14, 2016-04-02
+----------------------------
+By DamienMcKenna: Corrected return code from update 7107.
+#2664624 by DamienMcKenna: Added a space in front of the Google Plus schemaorg
+  variable to avoid HTML validation errors because of the lack of space.
+#2658902 by DamienMcKenna, swentel: Renamed the 'Add a Metatag default' link to
+  match the D8 wording.
+#2665206 by DamienMcKenna: Don't add an index in 7029 if it already exists.
+#2670842 by Ambient.Impact: Fixed permissions in the Importer submodule.
+#2613598 by DamienMcKenna: Removed the Contributor Covenant, replaced it with a
+  link to https://www.drupal.org/dcoc.
+#2692933 by doostinharrell, DamienMcKenna: $metatags variable in
+  metatag_field_attach_form() may not be an array in certain circumstances.
+#2658808 by tommik: Rewrote query in update 7040 so it works better.
+#2688963 by DamienMcKenna: Added a note about the Yoast SEO module.
+#2687847 by DamienMcKenna: Added a note about the Parse.ly module.
+#2696445 by Simon Georges: Added the twitter:image:alt meta tag.
+#2678896 by Dave Reid: Fixed double-encoding of form fields.
+#2667214 by DamienMcKenna: Improved tests for string encoding.
+#2667214 by joelstein, DamienMcKenna: Decode HTML entities prior to rendering
+  meta tags.
+
+
+Metatag 7.x-1.13, 2016-03-04
+----------------------------
+#2662952 by DamienMcKenna: Fixed logic on hook_requirements for checking the
+  version of Token that is installed.
+
+
+Metatag 7.x-1.12, 2016-03-04
+----------------------------
+#2644742 by kev5873, DamienMcKenna: Variable scoping issue with Metatag:Panels
+  could lead to incorrect meta tag output.
+#2309017 by DamienMcKenna, rodrigoaguilera: Tidied up the install file a little.
+#2658808 by DamienMcKenna: Improved query to skip update 7040 if it isn't
+  needed.
+#2658262 by Devin Carlson, DamienMcKenna: Fixed hook_metatag_config_delete(),
+  this time with tests.
+#2661378 by DamienMcKenna: No longer require Token v7.x-1.6, just highly
+  recommend it.
+#2661408 by DamienMcKenna: Removed the status message when core is up-to-date.
+#2661412 by DamienMcKenna: Improve hook_requirements check for Entity
+  Translation.
+#2661434 by DamienMcKenna: Removed the status message about alt_hreflang.
+#2652120 by DamienMcKenna: Fixes for old config translations that weren't
+  fixed with previous updates.
+
+
+Metatag 7.x-1.11, 2016-01-26
+----------------------------
+#2568499 by DamienMcKenna, DD 85: Removed an errant space.
+#2655582 by DamienMcKenna, MihaiMiculescu: Fixed automatic image parsing.
+By DamienMcKenna: Minor changes to the README.txt file.
+#2655614 by DamienMcKenna: Added tests for image handling.
+#2655662 by DamienMcKenna: Fixed handling of output translation on pages with
+  really long paths.
+
+
+Metatag 7.x-1.10, 2016-01-22
+----------------------------
+#2654838 by Plazik, DamienMcKenna: Disabling output caching lead to Undefined
+  Variable errors.
+#2654638 by DamienMcKenna, noah, marleythedog: Allow updates 7104 and 7105 to
+  run if Locale is not enabled.
+#2654530 by DamienMcKenna, Adenn, deja711: Twitter Cards update 7100 and
+  OpenGraph update 7103 cannot run until Metatag update 7100 has finished.
+
+
+Metatag 7.x-1.9, 2016-01-21
+---------------------------
+#2652772 by DamienMcKenna: Fix update 7101 and rerun it to correct translation
+  data.
+#2651812 by DamienMcKenna: Added an option to disable the i18n integration.
+#2420489 by Les Lim, DamienMcKenna: New caching process for entities.
+#2652260 by DamienMcKenna: Remove the revision_id from translation string IDs.
+#2509246 by DamienMcKenna, zniki.ru: Remove meta tags added by core, with option
+  to leave them as-is.
+#2652294 by DamienMcKenna: Incorrect string context was being used for meta tag
+  output translation.
+#2653434 by DamienMcKenna, reinchek: Fixed metatag_metatags_load().
+#2653446 by DamienMcKenna: Wrong variable name passed to
+  metatag_config_delete().
+#1858540 by DamienMcKenna, friera: Added the pragma, cache-control and expires
+  meta tags.
+
+
+Metatag 7.x-1.8, 2016-01-14
+---------------------------
+#2546636 by DamienMcKenna: Fixes to the custom Panels pane for editing tags.
+#2113501 by DamienMcKenna: Shortened i18n translation context to just
+  "metatag:METATAGNAME" to make translations easier.
+#2552829 by DamienMcKenna: Move the basic meta tags to a group.
+#2552827 by DamienMcKenna: Group meta tag tokens so they're less confusing.
+#2552849 by DamienMcKenna: Meta tag tokens for user entities.
+#1986032 by DamienMcKenna, izus, yang_yi_cn, Placinta, maijs, Tharna, stijndmd:
+  Improved i18n compatibility for the Views, Panels and Context submodules.
+#2518690 by manikaprasanth: Added support for editing Commerce product entities.
+#2550001 by DamienMcKenna: Renamed twitter:image:src back to twitter:image. LOL.
+#2559359 by labboy0276: Errors if the Views integration can't find the expected
+  display object.
+#2560649 by DamienMcKenna: Added optional second-stage translation for meta tag
+  output.
+#2556741 by DamienMcKenna: Fixed robots handling on Nodewords importer; moved
+  Nodewords importer into a separate file to keep the Importer module more
+  general.
+#1809652 by DamienMcKenna: Added a new [current-page:pager] token for inserting
+  a pager into meta tags.
+#1809652 by DamienMcKenna: Update default node title to insert the pager.
+#2518690 by DamienMcKenna: Improvements to Commerce Product handling.
+#2568499 by DamienMcKenna: Added new Apple-specific meta tags to the Mobile
+  submodule.
+#2568463 by DamienMcKenna: Added the android-app deeplink meta tag.
+#2569093 by DamienMcKenna: Added the ios-app deeplink meta tag.
+#2568955 by DamienMcKenna: Don't output meta tags that only contain a pager.
+#2556741 by DamienMcKenna: BatchAPI call wasn't updated after the Nodewords
+  importer file was renamed.
+#2514916 by DamienMcKenna: Split up the tests file, moved them into the tests
+  directory, added new tests for node revisions.
+#2567621 by hass: Allow the custom pager to be translated using the i18n
+  Variable module.
+#2572371 by Dave Reid: Remove support for comments.
+#2572291 by Dave Reid: Always display config items in the correct order - global
+  items first, then sorted alphabetically.
+#2567677 by Perignon, DamienMcKenna: og:video meta tag renamed.
+#2556741 by DamienMcKenna: Follow-up to fix imported robots meta tags.
+#2556741 by DamienMcKenna: Updated the final commit message to show the correct
+  count.
+#2498213 by makangus: Added the Android manifest meta tag.
+#2573869 by DamienMcKenna: Fixed variable bug in update 7040.
+#2579871 by DamienMcKenna: Added more test dependencies.
+#2579201 by lesonunique, DamienMcKenna: Missing 'secure' option on
+  og:audio:secure_url.
+#2580623 by marcvangend: Incorrect check for admin_language.
+#2580523 by DamienMcKenna: Add a note to hook_requirements if hreflang module
+  is not installed and there are multiple locales enabled on the site.
+#2587369 by DamienMcKenna: Added two placeholder files for storing tests for the
+  Views integration.
+#2587371 by DamienMcKenna: Added two placeholder files for storing tests for the
+  Panels integration.
+#2376857 by DamienMcKenna: Work around entity definitions that don't have a
+  'bundles' attribute.
+#2455777 by DamienMcKenna: Don't try to save any {metatag} records if the entity
+  or bundle is not supported.
+#2597301 by DamienMcKenna: New submodule for handling the hreflang meta tag.
+#2603058 by FluxSauce: Fixed problem loading migrate.inc file if Migrate is not
+  enabled.
+#1957358 by pjonckiere, DamienMcKenna: Add tests to ensure that the meta tag
+  string encoding works correctly.
+By DamienMcKenna: Some commit messages were in the wrong place.
+#2603458 by Frando: Fixed update 7018 for sites using Entity Translation, and
+  re-run it.
+#1355788 by DamienMcKenna: Allow use of 'public://' file scheme for images.
+#2550001 by Dave Reid: Blank out metatag_update_7024() and metatag_update_7030()
+  because the 'twitter:image:src' meta tag was renamed back to 'twitter:image'
+  so these updates don't need to ever run.
+#1957358 by DamienMcKenna: Added tests to confirm that HTML entities work
+  correctly in the page title.
+#2619438 by DamienMcKenna: Improve documentation on the mobile subtheme.
+#2597301 by DamienMcKenna: Only use the new locale-URL tokens when translations
+  modules are enabled.
+#2180031 by DamienMcKenna: Fixed double-encoding of tokens.
+#2635144 by DamienMcKenna: Added the apple-itunes-app meta tag.
+#1904542 by DamienMcKenna: Added a bunch of Windows and IE -focused meta tags.
+#2636132 by SpaghettiBolognese: Inconsistency in submodule naming.
+#2637026 by matthewordie, DamienMcKenna: Mention in the og:image meta tag how
+  Facebook will handle multiple images (It defaults to the largest one).
+#2564483 by DamienMcKenna, drupov, mas0h, das-peter, pwiniacki, sylus, webflo,
+  Gábor Hojtsy, pjonckiere, k_zoltan: Fixed i18n integration for core module and
+  all submodules; added over 1,000 new test assertions in major expansion of the
+  test suite.
+#2644156 by DamienMcKenna: Default value of image_src meta tag for user entity
+  was set incorrectly.
+#2639170 by anthonyleach: Use the correct hooks to add the RDF namespaces.
+#2628558 by marcelovani: Renamed the bundled Context definitions to avoid
+  conflicts.
+By DamienMcKenna: Fixed an accidental removal of the Token v1.6 requirement.
+#2622662 by rollsd: Adjusted logic to fix problem with entity types that only
+  have one bundle.
+#2648804 by DamienMcKenna: Removed some unfinished code from
+  metatag_metatags_delete_multiple().
+#2587725 by DamienMcKenna: Fixed display of meta tag labels in localized entity
+  & config forms.
+#2389929 by michee.lengronne, scor, DamienMcKenna, sint: Fixed Google+ HTML
+  head declaration so it validates, but a change to the site's html.tpl.php is
+  now required.
+#2184857 by DamienMcKenna, mikeytown2: Expanded metatag_metatags_load() to allow
+  meta tags to be loaded by revision ID.
+#1838554 by dimchich, jcnventura, Bao Truong, marcelovani, DamienMcKenna: Allow
+  entity tokens to be properly used on entity pages via Metatag:Context i.e.
+  'by path'.
+#2361343 by marcelovani: Allow by-path definitions to override the page title of
+  all pages.
+#2493689 by DamienMcKenna: Removed two arguments from metatag_metatags_save()
+  that weren't actually being used.
+#2613598 by DamienMcKenna: Added a copy of the Contributor Covenant in the
+  CODE_OF_CONDUCT.txt file.
+#2335015 by DamienMcKenna: Remove og:type 'blog'.
+#2649816 by DamienMcKenna: Added a copy of the GPL 2.0 license to the
+  repository.
+#2338211 by DamienMcKenna: Only output the first item of a token for image meta
+  tags that only support one value.
+
+
+Metatag 7.x-1.7, 2015-07-24
+---------------------------
+#2537738 by deepak_zyxware: Incorrect path to fb_social settings page.
+#2535178 by DamienMcKenna: 'multiple' option on Viewport causes problems with
+  the meta tag's intended values.
+#2524460 by DamienMcKenna, adriancotter, gbirch, jrb: Remove custom wrangling
+  for Views-based custom entity displays, added new hook to allow other modules
+  to customize as needed (hook_metatag_views_post_render_get_entity).
+#2199533 by Adrian Richardson, DamienMcKenna, mairi: Don't reload entities when
+  processing tokens, it causes problems with content workflows.
+#2513892 by DamienMcKenna: Tests for user objects.
+#1658970 by DamienMcKenna, stefan.r, subhojit777, HyperGlide, jenlampton: Drush
+  script to convert data from the Page Title module.
+
+
+Metatag 7.x-1.6, 2015-06-30
+---------------------------
+#2503089 by DamienMcKenna: Added support for the "any" favicon, used for SVG
+  files in Safari 9.
+#2499865 by DamienMcKenna: Improvements to entity selection, all sites will now
+  automatically start off supporting news, terms and users.
+#2503097 by DamienMcKenna: Added the theme-color meta tag.
+#2503089 by jdanthinne, DamienMcKenna: Improved wording of the SVG favicon
+  description.
+#2499737 by DamienMcKenna: Moved the Dublin Core Additional Tags meta tags into
+  a new submodule, metatag_dc_advanced.
+#2499739 by DamienMcKenna: Moved the Open Graph Products meta tags into a new
+  submodule, metatag_opengraph_products.
+#2498173 by DamienMcKenna: Clarified the touch icon meta tags available by
+  adding separate primary vs precomposed tags.
+#2499739 by DamienMcKenna: Follow-up to fix a missing variable.
+#2507025 by DamienMcKenna: Fixed Panels/Panelizer support for entities after
+  changes in 1.5.
+#2505051 by DamienMcKenna: Automatically check for image URLs in image meta
+  tags; added a new 'image' attribute to meta tag specifications.
+#2504561 by hanoii: Remove unused metatag_load_entity_from_path() function and
+  corresponding hook.
+#2222711 by hanoii, DamienMcKenna, andyg5000: Fixed Views support for entities
+  after API changes in 1.5.
+#2467587 by DamienMcKenna: Clear the Metatag cache when a node's state is
+  changed via Workbench Moderation.
+#2449425 by DamienMcKenna: Only process string values for token replacement.
+#2265453 by zd123, DamienMcKenna: CTools keyword substitution for Panels
+  integration.
+#2512284 by DamienMcKenna: Missing token browser link on main Metatag fieldset.
+#2513890 by DamienMcKenna: Added tests for taxonomy term integration.
+#1404270 by JStanton, DamienMcKenna: Added the Refresh meta tag.
+#2384673 by etroid, DamienMcKenna: Added the shortcut icon meta tag.
+#2514852 by rrfegade: Spelling mistakes in README.txt files.
+#2514878 by DamienMcKenna: Ignore admin pages on Views/CTools-driven entity
+  pages.
+#2514812 by david_garcia: Fix Views integration for ECK entities.
+#2514572 by DamienMcKenna: Don't check if records exist when deleting them,
+  just run the deletion query.
+
+
+Metatag 7.x-1.5, 2015-05-29
+---------------------------
+#2442183 by DamienMcKenna, jwilson: Mention the Image URL Formatter module in
+  the README.txt file.
+#2451231 by DamienMcKenna: Fixed the Devel:Generate integration.
+By DamienMcKenna: Rearranged og:type select_or_other integration code to be
+  after the og:type tag definition.
+By DamienMcKenna: Removed duplicate description for video:writer meta tag.
+By DamienMcKenna: Standardized structure of all theme functions.
+#2452985 by DamienMcKenna: Added 39 additional Dublin Core meta tags.
+By DamienMcKenna: Removed duplicate dcterms.rights tag.
+By DamienMcKenna: Updated new 'date' dcterms tags to use 'date' generator.
+#2460791 by DamienMcKenna: Allow the page region used to trigger output to be
+  changed; see the advanced settings page for details.
+#2462117 by DamienMcKenna: Allow the included default configurations to be
+  disabled.
+#2454499 by Dmitriy.trt: metatag_config_is_enabled() returned FALSE for empty
+  config, when checked with defaults.
+#2407477 by greggles: Provide support for Twitter app tags without having to use
+  an "app" type.
+By DamienMcKenna: Fixed a small mistake in output of metatag_update_7011().
+#2429091 by deviantintegral, DamienMcKenna: Add support for applinks.org tags.
+#2417155 by dobe: Feeds import fails because of placement of entity_type.
+By DamienMcKenna: Minor text improvements per D8 branch.
+By DamienMcKenna: Clarified compatibility with Workbench Moderation.
+#2473459 by DamienMcKenna: Updated all links to d.o.
+#2479325 by DamienMcKenna: Require Token 1.6.
+#1491562 by jonathan_hunt, knalstaaf: Add instructions to README.txt explaining
+  how to configure meta tags for entity bundles.
+#2449425 by DamienMcKenna: Refactored select_or_other usage, API addition.
+#2487179 by DamienMcKenna: Allow longer cache IDs to reduce conflicts.
+#2473107 by DamienMcKenna: Added a warning about having more og:image:type
+  values than there are og:image values, it can lead to Facebook validation
+  errors.
+#2474427 by DamienMcKenna: Added an advanced option to disable the output cache.
+#2432517 by undertext, DamienMcKenna: Check all CTools contexts, not just the
+  first one.
+#2449425 by DamienMcKenna: Follow-up for select_or_other bug.
+#2415983 by ciss, DamienMcKenna: Core elements not removed when no metatag
+  substitute provided.
+#2490846 by DamienMcKenna: Using [metatag] tokens failed if the value was empty.
+#2466629 by DamienMcKenna, rupertj: Ensure entity is an object before checking
+  its language code.
+#2081717 by DamienMcKenna: Added Admin Menu item for flush the Metatag caches.
+By DamienMcKenna: Noted that the 'shortlink' meta tag replaces 'shorturl'.
+#2493711 by akoe, DamienMcKenna: Added geo.position, geo.placename, geo.region
+  and icbm meta tags.
+#2493395 by das-peter: Google+ itemtype meta tag malformatted.
+#1915926 by DamienMcKenna: Allow multiple fb:admins values.
+#2494271 by DamienMcKenna: og:street_address, og:postal_code, og:country_name
+  are incorrect.
+#1498762 by DamienMcKenna: Added the Rating meta tag.
+#2451271 by DamienMcKenna: Added the Referrer meta tag.
+#1285946 by DamienMcKenna: Added metatag_mobile submodule with a few mobile
+  -related meta tags.
+#2475147 by MatthewHager, DamienMcKenna: Fixed Feeds integration after its API
+  changed.
+#2070821 by DamienMcKenna, pounard: Major re-architecture to how supported
+  entities are handled.
+#2495877 by DamienMcKenna: Added a Context global config instance.
+#2495875 by DamienMcKenna: Added a Panels global config instance.
+#1281138 by jantoine, DamienMcKenna, drupalninja99, stuart.crouch, subhojit777,
+  KarlShea: Metatag:Importer submodule for importing data from Nodewords (D6).
+#2376921 by DamienMcKenna: Trigger an entity cache clear when meta tags are
+  saved or deleted.
+#2496487 by DamienMcKenna: The function is called entity_get_info(), not
+  entity_info().
+#2103321 by mistermoper, DamienMcKenna: Added 24 more Open Graph meta tags for
+  managing product information.
+#2085747 by DamienMcKenna: Added twelve favicon varieties to a new submodule,
+  Metatag: Favicons.
+By DamienMcKenna: Removed message from metatag_opengraph_install() warning about
+  compatibility with the RDF module, which is no longer applicable.
+#2408211 by infinet, MatthewHager: Context substitution added to Metatag: Panels
+  output.
+#2156653 by mitsuroseba, undertext, asgorobets, DamienMcKenna: Added a custom
+  pane for adding the meta tags fieldset to a node form customized via Panels.
+#2496487 by DamienMcKenna: Follow-up on previous commit, remove unneeded
+  function_exists() call.
+
+
+Metatag 7.x-1.5-beta1, 2015-02-02
+---------------------------------
+#2362639 by DamienMcKenna: Improved defaults for Google+ meta tags.
+#2318985 by DamienMcKenna: Indicate that Open Graph tags are used on Pinterest.
+#2362639 by DamienMcKenna: Added itemtype default values for Google+ meta tags.
+#2358137 by DamienMcKenna: Added a submodule for managing site verification
+  meta tags, the first of which is for Google.
+#2358131 by DamienMcKenna: Support for the Pinterest verification meta tag.
+#1848338 by larowlan, DamienMcKenna: Added more tests, especially one for
+  checking the editorial process on a node.
+#2362893 by ipo4ka704: Don't assume the first Panels context is an object.
+#2363591 by DamienMcKenna: Added a default for the 'image' meta tag on user
+  entity pages.
+#1967856 by duozersk: Fixed a minor mistake in the previous commit.
+#2370943 by Simon George: Removed redundant comment.
+#2373189 by nmillin: Added support for the Bing verification code.
+#2358139 by nmillin: Added support for the Yandex verification code.
+#2378127 by DamienMcKenna: Support for rel="alternate" hreflang="x" link tag.
+#2376915 by jenlampton, DamienMcKenna: Added the og:image:url meta tag.
+#1978708 by DamienMcKenna, scor: Updated warning about compatibility with the
+  RDF module in Drupal core before 7.33.
+#2385265 by mikemiles86: Correctly flatten Metatag form fieldsets in Context
+  integration.
+#2370439 by potop, DamienMcKenna: Work around hook_entity_load() problems by
+  loading entity info in metatag_entity_supports_metatags() on demand.
+#1868460 by preshetin: Added the rel=prev and rel=next meta tags.
+#2388339 by das-peter: Fix select_or_other integration for Metatag:GooglePlus,
+  add the missing element_validator.
+#2391975 by Spleshka: Support scenarios where the entity is possibly blank or
+  has no entity_id assigned yet, e.g. Profile2 pages.
+#2400241 by greggles: Typo in description of robots-notranslate option.
+#2400529 by greggles: Add support for OG product price:amount, price:currency.
+#2411607 by liberatr, DamienMcKenna: README.txt note about using the
+  field_multiple_types module to control how many items are output.
+#2415025 by DamienMcKenna: l() in metatag_metatag_info() creates recursion bug.
+#2411477 by betz, DamienMcKenna: $form[#entity] doesn't work for all entities.
+#2411549 by maijs: Language is lost during migration.
+#2198669 by D2ev: Using metatag tokens can easily cause an infinite loop.
+#2411477 by DamienMcKenna, betz: Follow-up to last change.
+
+
+Metatag 7.x-1.4, 2014-10-09
+---------------------------
+#2353079 by DamienMcKenna: Fixed Views integration, for real this time.
+#2344877 by DamienMcKenna: Fixed Panels integration, for real this time.
+
+
+Metatag 7.x-1.3, 2014-10-07
+---------------------------
+#2350967 by das-peter, DamienMcKenna: Fatal error occurred loading any View that
+  did not have meta tags assigned.
+#2344877 by DamienMcKenna, Mau Palantír, libelle2000: Fixed Panels integration.
+By DamienMcKenna: metatag_metatags_load()'s documentation was incorrect.
+#2347193 by DamienMcKenna: Updated Feeds integration to be compatible with the
+  new data structures in 1.0, and revision_id problems.
+
+
+Metatag 7.x-1.2, 2014-10-04
+---------------------------
+#2343909 by DamienMcKenna: Unable to update meta tags on nodes that didn't
+  contain translations.
+#2185791 by DamienMcKenna: Improved logic for deciding which meta tag values
+  to use for the current language; new advanced option allows loading of the
+  entity's default language's values if nothing else matches.
+#2346159 by DamienMcKenna: Fixed tag dependencies, which were broken in 1.0.
+#2346153 by DamienMcKenna: Added Twitter app 'name' tags, misc improvements to
+  Twitter Cards code.
+#2185791 by DamienMcKenna: Changed the no-values-to-load entity language default
+  logic so that the default language values will be loaded unless disabled.
+#1304038 by DamienMcKenna: Indicate in the README.txt how to disable output for
+  the three meta tags output by Drupal core by default.
+#2350129 by DamienMcKenna: Added a Drush command for clearing Metatag's caches.
+#2341795 by DamienMcKenna: Updated Metatag:Views to be compatible with the new
+  form data structure in 1.0.
+#2292043 by eric.chenchao, DamienMcKenna: Added Google+ 'itemprop' meta tags.
+#2341795 by DamienMcKenna: Fixed Views previews.
+#2289139 by maijs, DamienMcKenna: Allow each Views display to have different
+  meta tag values.
+
+
+Metatag 7.x-1.1, 2014-09-18
+---------------------------
+#2340639 by agoradesign: Additional check needed in hook_requirements to avoid
+  breaking installation profiles.
+#2340337 by DamienMcKenna: Config system updated for the new language-based
+  data handling.
+#2330823 by DamienMcKenna: REVERT: Remove the deprecated G+ Author meta tag.
+
+
+Metatag 7.x-1.0, 2014-09-17
+---------------------------
+#2319389 by DamienMcKenna: Additional Open Graph meta tags, for videos.
+#2169575 by gvorbeck: Workbench Moderation v2 doesn't need any hackery, so
+  removed the message in hook_requirements().
+#2140189 by ttkaminski, DamienMcKenna: Added an index to {metatag} table for the
+  'type' and 'revision_id' fields.
+#1391554 by DamienMcKenna: Handle scenarios where the legacy "metatags" module
+  had been installed.
+#2325459 by DamienMcKenna: Used JSHint to correct some minor JS bugs.
+#2326197 by Dave Reid: metatag_generate_entity_metatags() cache can be bypassed.
+By DamienMcKenna: Updated the og:image size guidelines.
+By DamienMcKenna: Remove the redundant metatag_taxonomy_term_view_alter().
+By DamienMcKenna: Support Twitter Cards fieldset in Metatag:Context.
+#1778286 by alberto56: Removed the deprecated metatag_ui module.
+#2331677 by othermachines: Updates 7025 and 7027 attempted to update the wrong
+  tables.
+#2330823 by othermachines: Remove the deprecated G+ Author meta tag.
+#2186155 by DamienMcKenna, grahamC, JeroenT: Resolved problems when saving an
+  entity directly rather than via entity form.
+By DamienMcKenna: Corrected the namespace prefix for OG video meta tags.
+#2186155 by DamienMcKenna: Follow-up to fix a number of scenarios.
+
+
+
+Metatag 7.x-1.0-rc2, 2014-08-05
+-------------------------------
+#1904266 by mvwensen, DamienMcKenna: Added the dcterms.modified meta tag.
+#2202031 by DamienMcKenna: Don't double-encode output, handle &nbsp; specially.
+#2026343 by DamienMcKenna, skruf, valkum, wxman: Added many more Open Graph meta
+  tags.
+#2164919 by DamienMcKenna: Added an Advanced Settings page.
+#2241083 by DamienMcKenna: API structure for definiting field dependencies;
+  currently limited to hiding/showing fields, can be expanded later with
+  validation logic. Initial implementation for some Open Graph and Twitter Cards
+  meta tags.
+#2307523 by leewillis77, DamienMcKenna: Additional arguments for two
+  drupal_alter hooks.
+#2241083 by rooby: Refactored meta tag output generation using a new function,
+  metatag_generate_entity_metatags(), allowing for the tags to be independently
+  obtained for a given entity.
+#2262159 by DamienMcKenna: Bumped core requirement to 7.28, removed the
+  [node:summary] fix that's no longer needed.
+#2306449 by DamienMcKenna: Not having the Transliteration or Imagecache Token
+  modules installed no longer reports an error in hook_requirements().
+#1328562 by andremolnar, Greg Boggs, DamienMcKenna: Improved form descriptions.
+#1918706 by theunraveler, DamienMcKenna, Zekvyrin, JeroenT: [current-page:title]
+  didn't work correctly on Panels pages.
+#2153977 by paolomainardi, DamienMcKenna: Fix for translations of base entity
+  type configuration when there is no bundle configuration.
+#2572891 by DamienMcKenna: Removed most 'fine tuning' items from the README.txt
+  file, added notes again about using Imagecache_Token to improve images.
+
+
+Metatag 7.x-1.0-rc1, 2014-07-12
+-------------------------------
+By DamienMcKenna: Small improvement to the comment on update 7007.
+#2196393 by generalconsensus, aprohl5: Typo in hook_install().
+#2237507 by SebCorbin: Only delete all records when editing one entity revision.
+#2056739 by B-Prod: Incorrect language handling when displaying entity pages
+  using Panels.
+#2205675 by Romlam, greggles: Typo in variable name caused data to not load.
+#2265447 by opdavies: Ignore comment entities, conflict with comment_fragment.
+#2271685 by adee147: Typos in metatag_metatags_cache_clear().
+#2271811 by DamienMcKenna: Replaced theme_metatag_opengraph() with
+  theme_metatag_property().
+#1282636 by DamienMcKenna: Support meta tags that allow multiple values; first
+  supported tags are og:image and og:image:secure_url.
+#2273459 by DamienMcKenna: Improved Twitter Cards default values.
+#2273241 by DamienMcKenna: Use the new hook_metatag_bundled_config_alter() to
+  load settings from submodules.
+#2273493 by DamienMcKenna: Improved Dublin Core default values.
+#2274921 by DamienMcKenna: Token browser link missing on settings pages.
+#2277787 by eugene.ilyin: Missing translations in metatag_context.
+By DamienMcKenna: Removed duplicate 'devel_generate' setting for 'image_src'.
+#2282903 by DamienMcKenna: Special handling for meta tags that need to output a
+  secure URL, replace 'http://' with 'https://'.
+#2281833 by DamienMcKenna: Ensure multi-item values are output in a consistent
+  order.
+#2275323 by drastik: Provide link to settings page in Metatag:Context module.
+#1284810 by DamienMcKenna: Really recommend installing Imagecache Token.
+#1809356 by DamienMcKenna: Sort all meta tags.
+#2276361 by DamienMcKenna: Move Facebook meta tags into a separate submodule.
+#2185943 by fizk: Remove warnings about Exclude Node Title.
+#2266595 by hefox: Change watchdog() message to a warning not critical, to avoid
+  problems with Jenkins.
+#2193195 by 75th Trombone: Corrected a variable usage in README.txt.
+#1338612 by Lasac, DamienMcKenna: Added the content-language meta tag.
+#2291993 by DamienMcKenna: Duplicate fb meta tags causes lots of errors.
+#2285787 by SebCorbin: Entity Translation problems with revisions.
+#2025425 by moonray, David_Rothstein, hefox, DamienMcKenna: Cache improvement
+  to separate entity vs page language.
+#2186241 by nnevill.io1, DamienMcKenna: Revisions support for Panels.
+#2051407 by cha0s, DamienMcKenna: Language support for token integration.
+#2183203 by mikeytown2, juampy, DamienMcKenna: Improved queries in
+  metatag_metatags_load_multiple().
+#2227377 by DamienMcKenna: taxonomy_vocabulary_load() caused problems when
+  executed during hook_entity_info_alter().
+#1995564 by DamienMcKenna, willieseabrook: Added a warning about a possible
+  conflict with the Admin Language module.
+#2298337 by DamienMcKenna: Added an API option to indicate one meta tag replaces
+  another; updated API docs accordingly.
+#2267501 by DamienMcKenna: Renamed the 'twitter:image' meta tag to the correct
+  'twitter:image:src'.
+#2121437 by DamienMcKenna: Renamed the 'copyright' meta tag to the correct
+  'rights' tag.
+#2177455 by DamienMcKenna: Avoid errors when updating from older releases due
+  to missing revision_id field.
+#2178411 by DamienMcKenna, kporras07: Language not assigned correctly on CTools
+  -based pages.
+
+
+Metatag 7.x-1.0-beta9, 2014-01-18
+---------------------------------
+#2174363 by DamienMcKenna: Changed update 7018 to avoid attempting to create
+  duplicate records when updating; instead should there be a collision the
+  record with revision_id 0 will be deleted.
+#2176351 by DamienMcKenna: 403 and 404 error pages will use the global default
+  for the page title instead of copying the homepage's.
+#2175843 by DamienMcKenna: It was possible to get to update 7016 without the
+  revision_id field existing, so make sure it exists.
+#2081787 by attila.fekete: Don't let Metatag:Views overwrite the frontpage meta
+  tag config, matching how Metatag:Panels works.
+#2176375 by DamienMcKenna: Added note to README.txt about the Textimage module's
+  compatibility with Metatag.
+#2170771 by DamienMcKenna: Added support for the og:image:secure_url meta tag.
+
+
+Metatag 7.x-1.0-beta8, 2014-01-15
+---------------------------------
+#1995284 by DamienMcKenna: Replace $_SERVER['REQUEST_URI'] with request_uri().
+By DamienMcKenna: Updated the README.txt's Credits section to match the project
+  page.
+#1978708 by DamienMcKenna: Added a note to the README.txt, hook_install and
+  hook_requirements to mention that RDF can cause validation errors for the
+  Open Graph meta tag output.
+#1977640 by dsdeiz: Fixed a comment typo.
+#1978730 by DamienMcKenna: Added an installation note to read the README.txt
+  file.
+#1978568 by DamienMcKenna: Strip line breaks in all tag output.
+#1961354 by DamienMcKenna, thesame: Optionally provide additional permissions
+  so that access to modify each meta tag can be controlled individually, see
+  README.txt for more details.
+#1933678 by DamienMcKenna: Default Context configurations for the user login and
+  registration pages.
+#1816856 by DamienMcKenna: Default Context configuration for the main forum
+  page.
+#1292612 by DamienMcKenna: Default Context configuration for the main blog
+  page.
+#1988346 by DamienMcKenna: Form permissions were being overridden thus making
+  the Metatag fieldset visible when it shouldn't have been.
+#1994352 by AmbikaFR: Two strings were not translatable.
+#1970064 by Jorrit: Metatag:Panels did not load the data correctly.
+#1994634 by DamienMcKenna: DrupalTextMetaTag::getValue fails if
+  $options['instance'] element doesn't exist.
+#1994630 by DamienMcKenna: Cleanup/filter all meta tag output.
+By DamienMcKenna: Moved hook_requirements to the top of metatag.install.
+#1982164 by DamienMcKenna: Added hook_requirements note to ensure that Entity
+  Translation is up-to-date.
+#2020565 by DamienMcKenna: Save the correct language value on initial entity
+  creation.
+#1876034 by DamienMcKenna: Updated a comment to indicate that there was a
+  problem with Metatag itself when saving records via node_save(), not
+  Workbench Moderation after all.
+#2024277 by greggles, DamienMcKenna: Don't output a meta tag if the string is
+  blank, but still allow "0" to be output when needed.
+#1999936 by DamienMcKenna: Fixed poor logic for checking if a valid language
+  was available in metatag_metatags_values().
+#2024277 by DamienMcKenna: Follow-up to fix all meta tag output.
+#1498764 by nick_schuch, DamienMcKenna: Added the Revisit-After meta tag.
+#1671846 by benys, DamienMcKenna: Expose meta tags as tokens.
+#1830952 by DYdave, DamienMcKenna: Allow token types and patterns to be altered.
+#1859136 by plopesc, DamienMcKenna: Properly update meta tag records.
+#2045855 by czigor: Fix translation of meta tag info labels.
+#1572474 by PieIsGood, Dan Reinders, DamienMcKenna: Entity revision support.
+#2051401 by cha0s: Remove errant dpm() left in from earlier testing.
+#2037677 by adnasa, DamienMcKenna, tsvenson: UX improvement for the token popup.
+#1985932 by kolier: Correct the taxonomy term token on Panels pages.
+#2033723 by som30ind, DamienMcKenna: Fixed occasional error saving array values,
+  e.g. the ROBOTS tag.
+#1959830 by DamienMcKenna: Added a note to README.txt about Node Form Panes.
+#2061511 by amanire: Verify view display 'path' option exists before using it.
+#1776836 by kobee, DamienMcKenna: Added the Standout meta tag.
+#2095397 by DamienMcKenna: Allow method to skip skipping metatag_entity_view().
+#2095501 by DamienMcKenna: Logic mistake in metatag_metatags_delete_multiple()
+  meant records were never deleted.
+#2072087 by brunascle: Twitter Cards changed to use correct 'name' attribute.
+#2086037 by greggles: Only show schema warning messages to appropriate people.
+#1311050 by pasive, DamienMcKenna: Added the og:locale meta tag.
+#2082539 by DamienMcKenna, hswong3i: {metatag}.revision_id cannot be null.
+#2082539 by DamienMcKenna: Follow-up to make all revision_id values numeric.
+#1848338 by DamienMcKenna: Added a list of test scenarios that need to be added.
+#2152043 by DamienMcKenna: Devel Generate integration via Metatag:Devel
+  submodule.
+#2152043 by DamienMcKenna: Expanded Devel Generate integration to cover almost
+  all included meta tags.
+#1572474 by DamienMcKenna, HyperGlide, jyee, Kristen Pol, sylus: Fixes for
+  revisions support.
+#1876042 by DamienMcKenna: Rename variables to use $entity_id instead of $id
+  in metatag.admin.inc, $entity_type instead of $type in metatag.migrate.inc.
+#2157689/#2088299 by travelertt, iMiksu, DamienMcKenna: JS error broke
+  CKEditor, etc.
+#2168343 by DamienMcKenna: Clear EntityCache bins.
+#2062379 by DamienMcKenna: Restructured caching.
+#2168939 by DamienMcKenna: Don't skip batch processing on updates ran via Drush.
+#2169547 by DamienMcKenna: Clarification on Workbench Moderation support.
+#2090557 by Kristen Pol, DamienMcKenna: Don't cache tags on 403/404 error pages.
+#1848622 by DamienMcKenna: Translation helper for 'bar'.
+#1967856 by duozersk: Support for the noimageindex and notranslate robots tag
+  options.
+#2140463 by zhuber: Small misspelling in a comment.
+#1963678 by DC_Marc, gnuget, Albert Volkman: Additional Twitter Card meta tags.
+#2170363 by juampy: Incorrect data handling in DrupalDefaultMetaTag.
+#1286270 by DamienMcKenna: Provide options for disabling meta tags on specific
+  entity types or entity bundles, see README.txt for details.
+#2071649 by eelkeblok, DamienMcKenna: Verify the entity still exists when
+  loading meta tag data in metatag_ctools_render_alter() and
+  metatag_views_post_render().
+#2126157 by hefox: metatag_entity_has_metatags() returns TRUE for disabled
+  entities, not FALSE.
+#2001178 by jantoine, DamienMcKenna: Verify the language exists before saving.
+#1864306 by hefox: Export the 'disabled' state via Features, thus allowing
+  disabled configurations to be exported too.
+#2172883 by Kristen Pol, DamienMcKenna: Only use Workbench Moderation functions
+  on nodes.
+#1975552 by pivica, DamienMcKenna: Fixed errors when changing {metatag} table's
+  primary keys.
+#1864306 by DamienMcKenna: Follow-on to only export the $config->disabled
+  setting if it exists.
+#2173271 by deetergp: Spelling and grammar fixes for README.txt.
+#2172433 by fabsor, DamienMcKenna: Ensure that update 7015 runs early enough to
+  avoid data corruption or errors during other updates.
+#2156261 by plopesc, DamienMcKenna: Allow meta tags for 403/404 error pages to
+  be configured, along with some reasonable defaults; removed previous option to
+  control caching on these pages, the meta tags are now always cached.
+#2173863 by DamienMcKenna: Don't load meta tags on admin pages, provide setting
+  to override this.
+#2174363 by DamienMcKenna: Don't attempt to create revision records in update
+  7018 if one already exists.
+
+
+Metatag 7.x-1.0-beta7, 2013-04-22
+---------------------------------
+#1970946 by laura s: Twitter Cards no longer requires SSL.
+#1971406 by alextataurov, DamienMcKenna: Correct check to see if i18n is
+  installed.
+#1955898 by DamienMcKenna: Clicking 'cancel' when editing a per-path
+  configuration would cause the config to be deleted.
+#1955894 by plopesc: It wasn't possible to remove values from the
+  Metatag:Context editor.
+#1972038 by DamienMcKenna: Context admin page didn't display the '<front>' path
+  correctly.
+#1970064 by DamienMcKenna: Metatag:Context did not load the data correctly.
+#1970518 by John Morahan: Incorrect syntax in metatag.info.
+#1972932 by chrisjlee: Typo in hook_requirements.
+By DamienMcKenna: Removed trailing space in some files.
+#1951118 by DamienMcKenna: Display a runtime hook_requirements error message if
+  the old metatag.entity_translation.inc file is still present.
+By DamienMcKenna: Removed some tabs that snook in.
+#1973254 by plopesc: Added functional tests for Metatag:Context.
+#1284756 by dsdeiz: Add instructions to metatag.migrate.inc explaining how to
+  use the Migrate integration.
+#1954106 by DamienMcKenna: Simplified the project's name to just 'Metatag'.
+#1974870 by DamienMcKenna: Moved all modules to the 'SEO' package.
+
+
+Metatag 7.x-1.0-beta6, 2013-04-14
+---------------------------------
+#1961448 by DamienMcKenna: Disable the fb:app_id field if fb_social is present.
+#1282620 by idflood, evanbarter, mgifford, Lukas von Blarer, Peacog, zterry95,
+  DamienMcKenna: Configuration translation through integration with the i18n
+  module.
+#1498740 by devuo: Merged Diogo's metatag_panels module.
+#1804356 by Dave Reid: Merged Dave's metatag_views module.
+#1909224 by DamienMcKenna: Fixed sloppy code in metatag_metatags_form_submit().
+#1969428 by DamienMcKenna: Changed the DC 'property' attribute to 'name'.
+#1284756 by dsdeiz: Update Migrate integration for compatibility with v2.5,
+  support additional entity types.
+#1953724 by DamienMcKenna, joshf, wiifm, twistor: PostgreSQL compatibility for
+  recent updates.
+#1295524 by DamienMcKenna: Temporary fix for the [node:summary] token not
+  working.
+#1952190 by DamienMcKenna: Only run queries involving taxonomy data if the
+  Taxonomy module is enabled.
+
+
+Metatag 7.x-1.0-beta5, 2013-03-23
+---------------------------------
+#1844638 by DamienMcKenna: Updated help messages around update 7004, when ran
+  via Drush it will no longer used Batch API.
+#1844764 by Devin Carlson, DamienMcKenna: Fix arg placeholders in t() calls.
+#1846516 by Staratel: Incorrect arguments for watchdog().
+#1846516 by DamienMcKenna: Further incorrect arguments for watchdog().
+#1844638 by DamienMcKenna: Correctly used drupal_is_cli() instead of just
+  php_sapi_name().
+#1846978 by edulterado: Corrected the theme function name used with the
+  Twitter Cards submodule.
+#1307804 by juampy: Support for Select_or_Other for use with the OpenGraph
+  'type' field.
+#1854522 by DamienMcKenna: Redundant return statements in the MetaTag classes.
+#1852600 by DamienMcKenna: Only use the first page argument in the Views and
+  Panels preprocessors if it is numerical.
+#1850014 by plopesc: Not all contexts that may be shown on the admin page will
+  have a path condition defined.
+#1846080 by DamienMcKenna: Only support entities that have the 'metatags'
+  option specifically enabled.
+#1857116 by DamienMcKenna: Purge {metatag} records for a few known unsupported
+  entities that old versions would have saved.
+#1857116 by DamienMcKenna: Don't purge 'file' {metatag} records until #1857334
+  is decided.
+#1857360 by DamienMcKenna: Purge {metatag} records for nodes, taxonomy terms
+  and users that were purged but where the APIs of older versions failed to
+  remove them.
+#1857116 by DamienMcKenna: Purge {metatag} records for Profile2.
+#1852600 by helmo: Typo in Views integration function.
+#1852022 by DamienMcKenna: Don't export the {metatag_config}.cid field.
+#1862570 by DamienMcKenna: Purge any empty values that may have been added by
+  very early releases.
+#1862570 by DamienMcKenna: Follow-up to correctly handle the serialized empty
+  array.
+#1864340 by cdoyle, DamienMcKenna: Incorrect output for certain Twitter Card
+  tags.
+#1865170 by DamienMcKenna: Fix metatag_requirements() return array when the
+  Page Title module is also installed.
+#1722564 by DamienMcKenna: Provide a hook_requirements() message and README.txt
+  note about a possible conflict with the Exclude Node Title module.
+#1284756 by damiankloip, sylus, alanburke, lancee: Migrate module integration.
+#1865228 by greggles, DamienMcKenna: Added the rel=author link meta tag.
+#1866122 by DamienMcKenna: Added the twitter:site:id and twitter:creator:id
+  meta tags.
+#1866980 by makangus: Corrected metatag_features_revert().
+#1862818 by DYdave, DamienMcKenna: Added documentation for
+  hook_metatag_config_default().
+#1778534 by DamienMcKenna: Added the original-source meta tag.
+#1886170 by DamienMcKenna: Typo in the API docs regarding enabling metatag
+  support in custom entities.
+#1871020 by DamienMcKenna: Compatibility problem with Workbench_Moderation.
+#1773926 by Dave Reid: Fixed token validation fails on config edit if the
+  instance context is not an entity type.
+#1814736 by plach, Dave Reid: metatag_page_build() did not check if the
+  global:frontpage metatag configuration is disabled.
+#1871852: Fixed metatag_update_7005() did not check if the watchdog table
+  exists.
+#1891082 by bago, Dave Reid: Fixed metatag_config_instance_label() failed to
+  recurse properly.
+#1915284: Fixed metatag_html_head_alter() stopped removing duplicate tags too
+  soon. Fixed duplicate canonical links when global redirect is enabled.
+#1845326 by DamienMcKenna, Peacog: Resolved language handling problems to
+  correctly identify the langcode to properly work with or without
+  Entity_Translation.
+#1876042 by DamienMcKenna: Rename variables to use $entity_id instead of $id
+  and $entity_type instead of $type.
+#1859136 by splatio, DamienMcKenna, multpix: Feeds integration - allow meta tag
+  fields to be the target for data imported using the Feeds module.
+#1880302 by olli, DamienMcKenna: Resolve problems with Features integration.
+#1923030 by krlucas, DamienMcKenna: Only run metatag_entity_update() on
+  supported entities.
+#1844638 by DamienMcKenna, mikeytown2: Remove unnecessary duplicate {metatag}
+  records, fix language values for all entities.
+#1935084 by DamienMcKenna: Remove unnecessary items from metatag_hook_info()
+  that was causing problems with PHP 5.4.
+#1791720 by kbasarab: Added the news_keywords meta tag.
+#1934492 by juampy, DamienMcKenna: Added a page for reverting meta tags for
+  specific entity or bundle.
+#1386320: Note a known issue of using custom template files that do not output
+  the $page['content'] variable.
+#1917902 by DamienMcKenna: Ensure strings returned from token replacement of
+  text fields ([node:summary]) is passed through the appropriate text filters.
+#1919070 by DamienMcKenna: Fix any records that may have been corrupted by e.g.
+  #1871020.
+#1861656 by DamienMcKenna, torrance123: Optionally load the global meta tags on
+  all pages, enabled by default.
+#1871798 by mstrelan: Clear the Context plugin cache when metatag_context is
+  enabled so that the new plugin becomes available.
+#1932192 by DamienMcKenna: Only run metatag_entity_view() once per page view.
+#1900434 by Dustin Currie, j0rd, DamienMcKenna: Added several new OpenGraph meta
+  tags, including ones for videos, location and contact information.
+#1883118 by DamienMcKenna: Improve the help message on Metatag:Context's Path
+  field as neither relative nor absolute URLs will work.
+#1945114 by SergO, DamienMcKenna: A query from #1919070 was missing the
+  preproccess wrapper around the table name.
+#1908586 by DamienMcKenna: Added a line to README.txt explaining how to
+  customize the tokens used to generate the meta tags.
+#1350610 by DamienMcKenna: metatag_update_7001 needed to drop the primary key
+  before customizing it.
+#1859136 by DamienMcKenna: Fixed scenarios when updating an entity there are two
+  copies of the data submitted, e.g. Feeds integration.
+#1308790 by DamienMcKenna: Documented that [current-user] tokens should not be
+  used.
+#1318294 by DamienMcKenna: Documented how to use Imagecache Token to resize
+  images that are being used as tokens for meta tags.
+#1871534 by DamienMcKenna: Documented how some browser plugins can make the page
+  title appear to be wrapped with doublequotes though the output doesn't
+  actually show them.
+
+
+Metatag 7.x-1.0-beta4, 2012-11-17
+---------------------------------
+#1842764 by DamienMcKenna: Work around problems in metatag_entity_load()
+  stemming from an outdated database schema, leave a message suggesting the
+  site admin run the database updates.
+#1842868 by DamienMcKenna: Changed metatag_update_7003 to automatically assign
+  the correct language per entity, added update_7004 to fix records updated in
+  beta3, fixed the language selection for loading meta tags so sites without
+  translation functionality continue to work correctly.
+#1842868 by DamienMcKenna: Changed update 7003 again so it *only* adds the new
+  field, changed update 7004 so it will update all records using Batch API.
+#1843676 by DamienMcKenna: Changed the hook_requirements message to an INFO
+  message if Page_Title is also installed, will freak people out less.
+
+
+Metatag 7.x-1.0-beta3, 2012-11-16
+---------------------------------
+#1688286 by colan, DamienMcKenna: Support for Entity Translation.
+#1835030 by DamienMcKenna: Documentation and hook_requirements note re Drupal
+  core v7.17.
+#1840402 by DamienMcKenna, paperdhc: Corrected use of array_pop().
+#1841404 by mh86: Don't attempt to load meta tags for unsupported entities, and
+  don't support configuration-only entities.
+#1841564 by peximo: Correctly identify the content language being used on the
+  homepage.
+#1841774 by DamienMcKenna: Provide a warning via hook_requirements if the Page
+  Title module is also enabled, due to the possibilities of complications and
+  unexpected results.
+#1363476 by DamienMcKenna: Workaround to trigger metatag_entity_view() if the
+  current CTools (Panels, Panelizer, etc) page is an entity display page.
+#1842052 by DamienMcKenna: Don't process unsupported entities being displayed
+  via Views.
+#1664322 by nico059, kerasai, miechiel, idflood, DamienMcKenna, alexweber:
+  Twitter Cards meta tags.
+#1842198 by DamienMcKenna: Move the 'advanced' fieldset under the others.
+#1840236 by weri, Marty2081: Only revert the requested feature, not all
+  features.
+
+
+Metatag 7.x-1.0-beta2, 2012-10-30
+---------------------------------
+#1817580 by DamienMcKenna: Removed code that was enabling debug mode on all
+  Contexts.
+#1818240 by DamienMcKenna: Added $instance value to the drupal_alter() call in
+  metatag_metatags_view().
+#1817984 by DamienMcKenna, alexweber: Documented
+  hook_metatag_metatags_view_alter().
+#1818252 by DamienMcKenna: There was no caching on the front page's meta tags.
+#1818516 by DamienMcKenna: Incorrect variable check in metatag_page_build().
+#1818762 by DamienMcKenna: Updated hook_hook_info().
+#1466292 by DamienMcKenna: Listed hooks in metatag.api.php and everywhere the
+  hooks are triggered there's a comment to say what the hook is.
+#1818984 by DamienMcKenna: Add the $instance value to metatag_context's
+  triggering of hook_metatag_metatags_view.
+#1819000 by DamienMcKenna: Don't load default meta tags if no active contexts
+  define meta tags.
+#1819448 by DamienMcKenna: Error on admin page if any meta tags were disabled.
+#1818958 by DamienMcKenna: The $cid_parts array should contain all relevant
+  entity variables.
+#1820362 by DamienMcKenna: $cid_parts should use base_path() instead of '/'.
+#1820374 by DamienMcKenna: Front page $cid_parts did not include the full URL.
+#1822726 by DamienMcKenna: Ensure the CTools exportables system is loaded.
+#1818300 by eugene.ilyin, DamienMcKenna: Improved Features integration.
+#1151936 by DamienMcKenna, maximpodorov: Workaround to trigger
+  metatag_entity_view() if the current Views page is an entity display page.
+
+
+Metatag 7.x-1.0-beta1, 2012-10-19
+---------------------------------
+First mostly-stable release.
diff --git a/profiles/wcm_base/modules/contrib/metatag/CODE_OF_CONDUCT.txt b/profiles/wcm_base/modules/contrib/metatag/CODE_OF_CONDUCT.txt
new file mode 100644
index 0000000000000000000000000000000000000000..587ba66b7c38a2ecd3cbd53ac09e43e4445807a2
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/CODE_OF_CONDUCT.txt
@@ -0,0 +1,3 @@
+Contributor Code of Conduct
+---------------------------
+See: https://www.drupal.org/dcoc
diff --git a/profiles/wcm_base/modules/contrib/metatag/LICENSE.txt b/profiles/wcm_base/modules/contrib/metatag/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/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/profiles/wcm_base/modules/contrib/metatag/README.txt b/profiles/wcm_base/modules/contrib/metatag/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9312b3bdbd27177c599ac53371a38f7673a72fa5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/README.txt
@@ -0,0 +1,406 @@
+Metatag
+-------
+This module allows you to automatically provide structured metadata, aka "meta
+tags", about your website and web pages.
+
+In the context of search engine optimization, providing an extensive set of
+meta tags may help improve your site's & pages' ranking, thus may aid with
+achieving a more prominent display of your content within search engine
+results. Additionally, using meta tags can help control the summary content
+that is used within social networks when visitors link to your site,
+particularly the Open Graph submodule for use with Facebook, Pinterest,
+LinkedIn, etc (see below).
+
+This version of the module only works with Drupal 7.28 and newer.
+
+For additional information, see the online documentation:
+  https://www.drupal.org/docs/7/modules/metatag
+
+
+Features
+--------------------------------------------------------------------------------
+The primary features include:
+
+* The current supported basic meta tags are ABSTRACT, DESCRIPTION, CANONICAL,
+  GENERATOR, GEO.PLACENAME, GEO.POSITION, GEO.REGION, ICBM IMAGE_SRC, KEYWORDS,
+  PUBLISHER, REFRESH, REVISIT-AFTER, RIGHTS, ROBOTS, SHORTLINK, and the page's
+  TITLE tag.
+
+* Multi-lingual support using the Entity Translation module.
+
+* Translation support using the Internationalization (i18n) module of the global
+  configurations, the values for all three submodules (Metatag:Context,
+  Metatag:Panels, Metatag:Views), and the final meta tags being output.
+
+* Full support for entity revisions and workflows based upon revision editing,
+  including compatibility with the Revisioning and Workbench Moderation modules.
+
+* Automatically extracts URLs from image fields, no need for extra modules.
+
+* A custom pager string may be added to meta tags by inserting the token
+  [current-page:pager] into e.g. page titles, description tags, etc. The
+  replacement string may be customized from the settings page.
+
+* Per-path control over meta tags using the "Metatag: Context" submodule
+  (requires the Context module).
+
+* Integration with the Views module allowing meta tags to be controlled for
+  individual Views pages, with each display in the view able to have different
+  meta tags, by using the "Metatag: Views" submodule.
+
+* Integration with the Panels module allowing meta tags to be controlled for
+  individual Panels pages, by using the "Metatag: Panels" submodule.
+
+* The fifteen Dublin Core Basic Element Set 1.1 meta tags may be added by
+  enabling the "Metatag: Dublin Core" submodule.
+
+* Forty additional Dublin Core meta tags may be added by enabling the "Metatag:
+  Dublin Core Advanced" submodule.
+
+* The Open Graph Protocol meta tags, as used by Facebook, Pinterest, LinkedIn
+  and other sites, may be added by enabling the "Metatag: Open Graph" submodule.
+
+* Twenty six additional Open Graph Protocol meta tags are provided for
+  describing products in the "Metatag: Open Graph Products" 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 App Links meta tags may be added by enabling the Metatag: App Links
+  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.
+
+* Support for meta tags specific to Google Custom Search Appliance are available
+  in the "Metatag: Google Custom Search Engine (CSE)" submodule.
+
+* A variety of favicon sizes and styles can be added to the global configuration
+  using the Metatag: Favicons submodule.
+
+* An API allowing for additional meta tags to be added, beyond what is provided
+  by this module - see metatag.api.php for full details.
+
+* Support for the Migrate module for migrating data from another system - see
+  metatag.migrate.inc for full details.
+
+* Support for the Feeds module for importing data from external data sources or
+  file uploads.
+
+* Support for the Search API module for indexing of keywords.
+
+* Integrates with Devel_Generate, part of the Devel module, to automatically
+  generate meta tags for generated nodes, via the Metatag:Devel submodule.
+
+* Integrates with Workbench Moderation (v1) allowing meta tags on nodes to be
+  managed through the workflow process; this custom support is not needed in
+  Workbench Moderation v3 so the extra logic is automatically ignored.
+
+* The Transliteration module (see below) is highly recommended when using image
+  meta tags, e.g. og:image, to ensure that filenames are HTML-safe.
+
+* Adds an extra item to the "Flush all caches" menu for the Admin Menu module,
+  allowing for a quick way to clear the Metatag module's custom caches.
+
+* A custom pane, called "Node form meta tags", is available for adding the meta
+  tags fieldset when the node_edit page is customized using Panels; the
+  Metatag: Panels submodule does not need to be enabled in order for this to
+  work.
+
+* Several advanced options may be controlled via the Settings page.
+
+* An import script is provided in the Metatag:Importer submodule for D6 sites
+  that used Nodewords and need to migrate the data.
+
+* If the Media module (v2) is installed, the Media WYSIWYG submodule will be
+  used to automatically filter out Media's embed codes.
+
+
+Configuration
+--------------------------------------------------------------------------------
+ 1. On the People Permissions administration page ("Administer >> People
+    >> Permissions") you need to assign:
+
+    - The "Administer meta tags" permission to the roles that are allowed to
+      access the meta tags admin pages to control the site defaults.
+
+    - The "Edit meta tags" permission to the roles that are allowed to change
+      meta tags on each individual page (node, term, etc).
+
+ 2. The main administrative page controls the site-wide defaults, both global
+    settings and defaults per entity (node, term, etc), in addition to those
+    assigned specifically for the front page:
+      admin/config/search/metatags
+
+ 3. The list of supported entity types (nodes, taxonomy terms, etc) and bundles
+    (content types, vocabularies, etc) may be controlled from the Settings page:
+      admin/config/search/metatags/settings
+
+ 4. In order to provide a specific configuration per entity bundle (content
+    type, vocabulary, etc), click "Add default meta tags".
+
+ 5. Each supported entity object (nodes, terms, users) will have a set of meta
+    tag fields available for customization on their respective edit page, these
+    will inherit their values from the defaults assigned in #2 above. Any
+    values that are not overridden per object will automatically update should
+    the defaults be updated.
+
+ 6. As the meta tags are output using Tokens, it may be necessary to customize
+    the token display for the site's entities (content types, vocabularies,
+    etc). To do this go to e.g., admin/structure/types/manage/article/display,
+    in the "Custom Display Settings" section ensure that "Tokens" is checked
+    (save the form if necessary), then to customize the tokens go to:
+    admin/structure/types/manage/article/display/token
+
+
+Internationalization with the Translation (core) and Entity Translation modules
+--------------------------------------------------------------------------------
+The module works with the core Translation module, allowing the meta tags for a
+specific entity (node, term, etc) to be tied to a specific language. It also
+supports the Entity Translation module, which may work better thank the basic
+Translation module depending upon the site's desired functionality. This
+integration means that content creators can customize an entity's meta tags for
+each language supported on the site, and that the correct meta tags should
+always be displayed for each locale.
+
+
+Internationalization with the i18n modules
+--------------------------------------------------------------------------------
+Using the String Translation (i18n_string) submodule of the Internationalization
+(i18n) module package it is possible to translate meta tags:
+
+* All default configurations (admin/config/search/metatag) are translatable.
+  When a configuration is created or updated it will pass the values to the
+  i18n_string system. Additionally it is possible to bulk update them via the
+  string translation page (admin/config/regional/translate/i18n_string).
+
+* Meta tags for all submodules (Metatag:Context, Metatag:Panels, Metatag:Views)
+  are translatable. Similar to the default configurations, these meta tags are
+  made available when they are created and/or update, and may also be bulk
+  updated.
+
+* Meta tags from entities (nodes, terms, etc) are not directly translatable.
+
+* The final output meta tags are passed through the translation system when the
+  page is being loaded. It is not possible to use the strings bulk updater to
+  spool all pages on the site, to do so it would be necessary to spool the page
+  using a separate script or tool.
+
+Additionally, certain variables are available for translation using the Variable
+Translation submodule of the i18n package:
+
+* metatag_pager_string - The custom pager string.
+
+
+Internationalization with the Smartling module
+--------------------------------------------------------------------------------
+The Smartling translation service may be used with the Metatag module provide an
+improved UX around the meta tag translation process. In order to do this, the
+Smartling Interface Translation (smartling_interface_translation) module must
+be enabled.
+
+For further details see the module's project page:
+  https://www.drupal.org/project/smartling
+
+
+Search API integration
+--------------------------------------------------------------------------------
+Entity meta tag values can be made searchable using the Search API module
+(https://www.drupal.org/project/search_api).
+
+ 1. Select "Meta tags" under "Data alterations" in the filters for the
+    index:
+      admin/config/search/search_api/index/INDEX NAME/workflow
+ 2. Meta tag fields will now appear under "Fields" and can be enabled there:
+      admin/config/search/search_api/index/INDEX NAME/fields
+
+
+Fine tuning & suggestions
+--------------------------------------------------------------------------------
+* There are many options available on the settings page to control how Metatag
+  works:
+    admin/config/search/metatags/settings
+
+* It is possible to "disable" the meta tags provided by Drupal core, i.e.
+  "generator", "canonical URL" and "shortlink", though it may not be completely
+  obvious. Metatag takes over the display of these tags, thus any changes made
+  to them in Metatag will supercede Drupal's normal output. To hide a tag, all
+  that is necessary is to clear the default value for that tag, e.g. on the
+  global settings for nodes, which will result in the tag not being output for
+  those pages.
+
+* When using Features to export Metatag configurations, it is suggested to
+  override all of the default configurations and then disable the default
+  configurations via the advanced settings page; doing so will avoid potential
+  conflicts of the same configurations being loaded by both the Metatag module
+  and the new Features-based modules.
+
+* Using fields to automatically fill in values for image meta tags is the
+  recommended way of inserting images - the module will automatically extract
+  the URL from the value. However, by default this forces social networks,
+  search engines and certain browsers to download the original version of the
+  image, which could be multiple megabytes. The alternative is to use the
+  Imagecache_Token module to instead load meta tags via a specific image style.
+  As an example, in order to load an image from a node field named
+  "field_meta_tag_image" using the "seo_thumbnail" style, the following token
+  would be used:
+    [node:field_meta_tag_image:seo_thumbnail:uri]
+  or
+    [node:field_meta_tag_image:seo_thumbnail]
+  (They give the same results)
+  Additionally, dimensions of the image may be obtained from the following:
+    [node:field_meta_tag_image:seo_thumbnail:width]
+    [node:field_meta_tag_image:seo_thumbnail:height]
+
+
+Developers
+--------------------------------------------------------------------------------
+Full API documentation is available in metatag.api.php.
+
+It is not necessary to control Metatag via the entity API, any entity that has
+view modes defined and is not a configuration entity is automatically suitable
+for use.
+
+The meta tags for a given entity object (node, etc) can be obtained as follows:
+  $metatags = metatags_get_entity_metatags($entity_id, $entity_type, $langcode);
+The result will be a nested array of meta tag structures ready for either output
+via drupal_render(), or examining to identify the actual text values.
+
+
+Troubleshooting / known issues
+--------------------------------------------------------------------------------
+* When using custom page template files, e.g., page--front.tpl.php, it is
+  important to ensure that the following code is present in the template file:
+    <?php render($page['content']); ?>
+  or
+    <?php render($page['content']['metatags']); ?>
+  Without one of these being present the meta tags will not be displayed.
+* An alternative method to fixing the missing-tags problem is to change the page
+  region used to output the meta tags. The region used may be controlled from
+  the settings page, it is recommended to test different options to identify the
+  one that works best for a specific site.
+* Versions of Drupal older than v7.17 were missing necessary functionality for
+  taxonomy term pages to work correctly.
+* Using Metatag with values assigned for the page title and the Page Title
+  module simultaneously can cause conflicts and unexpected results. It is
+  strongly recommended to convert the Page Title settings to Metatag and just
+  uninstall Page Title entirely. See https://www.drupal.org/node/2774833 for
+  further details.
+* When customizing the meta tags for user pages, it is strongly recommended to
+  not use the [current-user] tokens, these pertain to the person *viewing* the
+  page and not e.g., the person who authored a page.
+* Certain browser plugins, e.g., on Chrome, can cause the page title to be
+  displayed with additional double quotes, e.g., instead of:
+    <title>The page title | My cool site</title>
+  it will show:
+    <title>"The page title | My cool site"</title>
+  The solution is to remove the browser plugin - the page's actual output is not
+  affected, it is just a problem in the browser.
+* Drupal core versions before v7.33 had a bug which caused validation problems
+  in the Open Graph output if the RDF module was also enabled. The solution is
+  to update to core v7.33 or newer.
+* If the Administration Language (admin_language) module is installed, it is
+  recommended to disable the "Force language neutral aliases" setting on the
+  Admin Language settings page, i.e. set the "admin_language_force_neutral"
+  variable to FALSE. Failing to do so can lead to data loss in Metatag.
+* If Entity Token is installed (a dependency for Rules, Commerce and others) it
+  is possible that the token browser may not work correctly and may either
+  timeout or give an error instead of a browsable list of tokens. This is a
+  limitation of the token browser.
+
+
+Related modules
+--------------------------------------------------------------------------------
+Some modules are available that extend Metatag with additional or complimentary
+functionality:
+
+* Transliteration
+  https://drupal.org/project/transliteration
+  Tidies up filenames for uploaded files, e.g. it can remove commas from
+  filenames that could otherwise break certain meta tags.
+
+* Imagecache Token
+  https://www.drupal.org/project/imagecache_token
+  Use tokens to load images via image styles, rather than forcing meta tags to
+  use the original image.
+
+* Alternative hreflang
+  https://www.drupal.org/project/hreflang
+  An alternative to the Metatag:hreflang module. Automatically outputs
+  <link rel="alternate" hreflang="x" href="http://" /> meta tags on every page
+  for each language/locale available on the site. Also does not provide any way
+  of overriding the values or setting the x-default value.
+
+* Domain Meta Tags
+  https://drupal.org/project/domain_meta
+  Integrates with the Domain Access module, so each site of a multi-domain
+  install can separately control their meta tags.
+
+* Select or Other
+  https://drupal.org/project/select_or_other
+  Enhances the user experience of the metatag_google_plus and metatag_opengraph
+  submodules by allowing the creation of custom itemtype and og:types values.
+
+* Node Form Panes
+  https://drupal.org/project/node_form_panes
+  Create custom node-edit forms and control the location of the Metatag fields.
+
+* Textimage
+  https://drupal.org/project/textimage
+  Supports using Textimage's custom tokens in meta tag fields.
+
+* Field Multiple Limit
+  https://drupal.org/project/field_multiple_limit
+  Allows control over how many items are output in a multi-item field, useful
+  with meta tags that only allow for one item but which are assigned from fields
+  which accept multiple items, e.g. og:audio and og:video.
+
+* 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.
+
+* Parse.ly Publishing Analytics
+  https://www.drupal.org/project/parsely
+  Automatically generates meta tags for the Parse.ly service.
+
+
+Credits / contact
+--------------------------------------------------------------------------------
+Currently maintained by Damien McKenna [1] and Dave Reid [2]; all initial
+development was by Dave Reid.
+
+Ongoing development is sponsored by Mediacurrent [3] and Lullabot [4]. All
+initial development was sponsored by Acquia [5] and Palantir.net [6].
+
+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/u/damienmckenna
+2: https://www.drupal.org/u/dave-reid
+3: https://www.mediacurrent.com/
+4: https://www.lullabot.com/
+5: https://www.acquia.com/
+6: https://www.palantir.net/
diff --git a/profiles/wcm_base/modules/contrib/metatag/arrow-down.png b/profiles/wcm_base/modules/contrib/metatag/arrow-down.png
new file mode 100644
index 0000000000000000000000000000000000000000..dbd52a3b50ecd2251bd426fcba48afc1a2a9d7e6
Binary files /dev/null and b/profiles/wcm_base/modules/contrib/metatag/arrow-down.png differ
diff --git a/profiles/wcm_base/modules/contrib/metatag/arrow-right.png b/profiles/wcm_base/modules/contrib/metatag/arrow-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..e14dbaed5a9378006c4696f6169ece2492e2a88a
Binary files /dev/null and b/profiles/wcm_base/modules/contrib/metatag/arrow-right.png differ
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.admin.css b/profiles/wcm_base/modules/contrib/metatag/metatag.admin.css
new file mode 100644
index 0000000000000000000000000000000000000000..3b463f6f3cfbaf30ea19f89c1cb841e40dec6508
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.admin.css
@@ -0,0 +1,88 @@
+div.metatag-config-label {
+  padding-left: 20px;
+}
+
+div.metatag-config-label > a {
+  font-weight: bold;
+}
+
+.metatag-config-label.collapsed {
+  background-image: url('arrow-right.png');
+  background-repeat: no-repeat;
+  background-position: center left;
+}
+
+.metatag-config-label.expanded {
+  background-image: url('arrow-down.png');
+  background-repeat: no-repeat;
+  background-position: center left;
+}
+
+table.metatag-config-overview > tbody > tr > td:first-child {
+  width: 60%;
+}
+
+table.metatag-config-overview > tbody > tr > td {
+  vertical-align: top;
+}
+
+table.metatag-config-overview tbody div.indent {
+  margin-left: 20px;
+}
+
+table.metatag-config-overview tr.disabled > td:first-child a {
+  color: #999;
+}
+
+div.metatag-config-details {
+  color: #666;
+  margin-left: 20px;
+}
+
+div.metatag-config-details p {
+  margin: 0.75em 0;
+}
+
+div.metatag-config-details div.inheritance {
+  font-style: italic;
+}
+
+div.metatag-config-details table.metatag-value-summary {
+  border: none;
+  width: auto;
+  margin: 0.75em 0;
+}
+
+div.metatag-config-details table.metatag-value-summary td {
+  padding: 0 0.5em 0 0;
+  color: #666;
+}
+
+div.metatag-config-details table.metatag-value-summary tr,
+div.metatag-config-details table.metatag-value-summary tr td:last-child {
+  background-color: transparent;
+  border: none;
+}
+
+div.metatag-config-details table.metatag-value-summary tr td:first-child {
+  font-weight: bold;
+  padding-right: 2em;
+}
+
+/*div.metatag-config-details ul {
+  margin-left: 2em;
+}
+
+div.metatag-config-details ul li {
+  line-height: 105%;
+}
+
+div.metatag-config-details > p {
+  margin: 0.25em 0;
+}*/
+
+
+/* For the advanced settings page */
+.metatag-bundle-checkbox {
+  margin-left: 2em;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.admin.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.admin.inc
new file mode 100644
index 0000000000000000000000000000000000000000..649861d6cd03f94a8e06229849b3b6800d0908f7
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.admin.inc
@@ -0,0 +1,792 @@
+<?php
+
+/**
+ * @file
+ * Administration page callbacks for the metatag module.
+ */
+
+function _metatag_config_overview_indent($text, $instance) {
+  $parents = metatag_config_get_parent_instances($instance);
+  array_shift($parents);
+
+  // Add indentation to the leading cell.
+  if (!empty($parents)) {
+    $prefix = array_fill(0, count($parents), '<div class="indent">');
+    $suffix = array_fill(0, count($parents), '</div>');
+    $text = implode('', $prefix) . $text . implode('', $suffix);
+  }
+
+  return $text;
+}
+
+function metatag_config_overview() {
+  ctools_include('export');
+
+  $metatags = metatag_get_info('tags');
+
+  $configs = ctools_export_crud_load_all('metatag_config');
+  uksort($configs, '_metatag_config_instance_sort');
+
+  $rows = array();
+  foreach ($configs as $config) {
+    $row = array();
+
+    // Style disabled configurations differently.
+    if (!empty($config->disabled)) {
+      $row['class'][] = 'disabled';
+    }
+
+    $details = '<div class="metatag-config-label collapsed"><a href="#" class="toggle-details">' . check_plain(metatag_config_instance_label($config->instance)) . '</a></div>';
+    $details .= '<div class="metatag-config-details js-hide">';
+
+    $inherits = array();
+    $parents = metatag_config_get_parent_instances($config->instance);
+    array_shift($parents);
+    foreach (array_reverse($parents) as $parent) {
+      if (!isset($configs[$parent])) {
+        $rows[$parent] = array(
+          _metatag_config_overview_indent('<div class="metatag-config-label">' . check_plain(metatag_config_instance_label($parent)) . '</div>', $parent),
+          '',
+        );
+      }
+      else {
+        $inherits[$parent] = metatag_config_instance_label($parent);
+        if (!empty($configs[$parent]->disabled)) {
+          $inherits[$parent] .= ' ' . t('(disabled)');
+        }
+      }
+    }
+
+    // Show how this config inherits from its parents.
+    if (!empty($inherits)) {
+      $details .= '<div class="inheritance"><p>' . t('Inherits meta tags from: @parents', array('@parents' => implode(', ', $inherits))) . '</p></div>';
+    }
+
+    // Add a summary of the configuration's defaults.
+    $summary = array();
+    foreach ($config->config as $metatag => $data) {
+      // Skip meta tags that were disabled.
+      if (empty($metatags[$metatag])) {
+        continue;
+      }
+      $summary[] = array(
+        check_plain($metatags[$metatag]['label']) . ':',
+        check_plain(metatag_get_value($metatag, $data, array('raw' => TRUE))),
+      );
+    }
+    if (!empty($summary)) {
+      $details .= theme('table', array(
+        'rows' => $summary,
+        'attributes' => array('class' => array('metatag-value-summary')),
+      ));
+    }
+    else {
+      $details .= '<p class="warning">No overridden default meta tags</p>';
+      $row['class'][] = 'warning';
+    }
+
+    // Close the details div
+    $details .= '</div>';
+
+    // Add indentation to the leading cell based on how many parents the config has.
+    $details = _metatag_config_overview_indent($details, $config->instance);
+
+    $row['data']['details'] = $details;
+
+    $operations = array();
+    if (metatag_config_access('disable', $config)) {
+      $operations['edit'] = array(
+        'title' => ($config->export_type & EXPORT_IN_DATABASE) ? t('Edit') : t('Override'),
+        'href' => 'admin/config/search/metatags/config/' . $config->instance,
+      );
+    }
+    if (metatag_config_access('enable', $config)) {
+      $operations['enable'] = array(
+        'title' => t('Enable'),
+        'href' => 'admin/config/search/metatags/config/' . $config->instance . '/enable',
+        'query' => array(
+          'token' => drupal_get_token('enable-' . $config->instance),
+        ) + drupal_get_destination(),
+      );
+    }
+    if (metatag_config_access('disable', $config)) {
+      $operations['disable'] = array(
+        'title' => t('Disable'),
+        'href' => 'admin/config/search/metatags/config/' . $config->instance . '/disable',
+        'query' => array(
+          'token' => drupal_get_token('disable-' . $config->instance),
+        ) + drupal_get_destination(),
+      );
+    }
+    if (metatag_config_access('revert', $config)) {
+      $operations['revert'] = array(
+        'title' => t('Revert'),
+        'href' => 'admin/config/search/metatags/config/' . $config->instance . '/revert',
+      );
+    }
+    if (metatag_config_access('delete', $config)) {
+      $operations['delete'] = array(
+        'title' => t('Delete'),
+        'href' => 'admin/config/search/metatags/config/' . $config->instance . '/delete',
+      );
+    }
+    $operations['export'] = array(
+      'title' => t('Export'),
+      'href' => 'admin/config/search/metatags/config/' . $config->instance . '/export',
+    );
+    if (module_exists('i18n_string') && !variable_get('metatag_i18n_disabled', FALSE)) {
+      $operations['translate'] = array(
+        'title' => t('Translate'),
+        'href' => 'admin/config/search/metatags/config/' . $config->instance . '/translate',
+      );
+    }
+    $row['data']['operations'] = array(
+      'data' => array(
+        '#theme' => 'links',
+        '#links' => $operations,
+        '#attributes' => array('class' => array('links', 'inline')),
+      ),
+    );
+
+    $rows[$config->instance] = $row;
+  }
+
+  $build['config_table'] = array(
+    '#theme' => 'table',
+    '#header' => array(
+      'type' => t('Type'),
+      'operations' => t('Operations'),
+    ),
+    '#rows' => $rows,
+    '#empty' => t('No meta tag defaults available yet.'),
+    '#attributes' => array(
+      'class' => array('metatag-config-overview'),
+    ),
+    '#attached' => array(
+      'js' => array(
+        drupal_get_path('module', 'metatag') . '/metatag.admin.js',
+      ),
+      'css' => array(
+        drupal_get_path('module', 'metatag') . '/metatag.admin.css',
+      ),
+    ),
+    '#suffix' => '<p>' . t('Any items marked "Unknown" are configurations in the system for entity types or bundles which have been disabled via the API or the <a href="@url">Settings page</a>; they will not be used.', array('@url' => url('admin/config/search/metatags/settings'))) . '</p>',
+  );
+
+  return $build;
+}
+
+/**
+ * Build an FAPI #options array for the instance select field.
+ */
+function _metatag_config_instance_get_available_options() {
+  $options = array();
+  $instances = metatag_config_instance_info();
+
+  foreach ($instances as $instance => $instance_info) {
+    if (metatag_config_load($instance)) {
+      continue;
+    }
+    $parents = metatag_config_get_parent_instances($instance, FALSE);
+    array_shift($parents);
+    if (!empty($parents)) {
+      $parent = reset($parents);
+      $parent_label = isset($instances[$parent]['label']) ? $instances[$parent]['label'] : t('Unknown');
+      if (!isset($options[$parent_label])) {
+        $options[$parent_label] = array();
+        if (!metatag_config_load($parent)) {
+          $options[$parent_label][$parent] = t('All');
+        }
+      }
+      $options[$parent_label][$instance] = $instance_info['label'];
+      unset($options[$parent]);
+    }
+    else {
+      $options[$instance] = $instance_info['label'];
+    }
+  }
+
+  return $options;
+}
+
+function metatag_config_add_form($form, &$form_state) {
+  $form['instance'] = array(
+    '#type' => 'select',
+    '#title' => t('Type'),
+    '#description' => t('Select the type of default meta tags you would like to add.'),
+    '#options' => _metatag_config_instance_get_available_options(),
+    '#required' => TRUE,
+  );
+  $form['config'] = array(
+    '#type' => 'value',
+    '#value' => array(),
+  );
+
+  $form['actions']['#type'] = 'actions';
+  $form['actions']['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add and configure'),
+  );
+  $form['actions']['cancel'] = array(
+    '#type' => 'link',
+    '#title' => t('Cancel'),
+    '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags',
+  );
+
+  return $form;
+}
+
+function metatag_config_add_form_submit($form, &$form_state) {
+  form_state_values_clean($form_state);
+  $config = (object) $form_state['values'];
+  metatag_config_save($config);
+  $form_state['redirect'] = 'admin/config/search/metatags/config/' . $config->instance;
+}
+
+function metatag_config_edit_form($form, &$form_state, $config) {
+  $form['cid'] = array(
+    '#type' => 'value',
+    '#value' => !empty($config->cid) ? $config->cid : NULL,
+  );
+  $form['instance'] = array(
+    '#type' => 'value',
+    '#value' => $config->instance,
+  );
+
+  $contexts = explode(':', $config->instance);
+  $options['context'] = $contexts[0];
+  if ($contexts[0] != 'global') {
+    // The context part of the instance may not map to an entity type, so allow
+    // the token_get_entity_mapping() function to fallback to the provided type.
+    if ($token_type = token_get_entity_mapping('entity', $contexts[0], TRUE)) {
+      $options['token types'] = array($token_type);
+    }
+    else {
+      $options['token types'] = array($contexts[0]);
+    }
+    // Trigger hook_metatag_token_types_alter().
+    // Allow the defined tokens to be modified.
+    drupal_alter('metatag_token_types', $options);
+  }
+
+  // Ensure that this configuration is properly compared to its parent 'default'
+  // configuration values.
+  if (count($contexts) > 1) {
+    // If the config is something like 'node:article' or 'taxonomy_term:tags'
+    // then the parent default config is 'node' or 'taxonomy_term'.
+    $default_instance = $contexts;
+    array_pop($default_instance);
+    $default_instance = implode(':', $default_instance);
+    $options['defaults'] = metatag_config_load_with_defaults($default_instance);
+  }
+  elseif ($contexts[0] != 'global') {
+    // If the config is something like 'node' or 'taxonomy_term' then the
+    // parent default config is 'global'.
+    $options['defaults'] = metatag_config_load_with_defaults('global');
+  }
+  else {
+    // If the config is 'global' than there are no parent defaults.
+    $options['defaults'] = array();
+  }
+
+  metatag_metatags_form($form, $config->instance, $config->config, $options);
+  $form['metatags']['#type'] = 'container';
+
+  $form['actions']['#type'] = 'actions';
+  $form['actions']['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  $form['actions']['cancel'] = array(
+    '#type' => 'link',
+    '#title' => t('Cancel'),
+    '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags',
+  );
+
+  $form['#submit'][] = 'metatag_config_edit_form_submit';
+  return $form;
+}
+
+function metatag_config_edit_form_submit($form, &$form_state) {
+  // Build the configuration object and save it.
+  form_state_values_clean($form_state);
+  $config = (object) $form_state['values'];
+  // @todo Consider renaming the config field from 'config' to 'metatags'
+  $config->config = $config->metatags[LANGUAGE_NONE];
+  unset($config->metatags);
+  metatag_config_save($config);
+
+  $label = metatag_config_instance_label($config->instance);
+  drupal_set_message(t('The meta tag defaults for @label have been saved.', array('@label' => $label)));
+
+  $form_state['redirect'] = 'admin/config/search/metatags';
+}
+
+function metatag_config_enable($config) {
+  if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'enable-' . $config->instance)) {
+    return MENU_ACCESS_DENIED;
+  }
+
+  ctools_export_crud_enable('metatag_config', $config);
+
+  $label = metatag_config_instance_label($config->instance);
+  drupal_set_message(t('The meta tag defaults for @label have been enabled.', array('@label' => $label)));
+  drupal_goto();
+}
+
+function metatag_config_disable($config) {
+  if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'disable-' . $config->instance)) {
+    return MENU_ACCESS_DENIED;
+  }
+
+  ctools_export_crud_disable('metatag_config', $config);
+
+  $label = metatag_config_instance_label($config->instance);
+  drupal_set_message(t('The meta tag defaults for @label have been disabled.', array('@label' => $label)));
+  drupal_goto();
+}
+
+function metatag_config_delete_form($form, &$form_state, $config) {
+  $form['cid'] = array('#type' => 'value', '#value' => $config->cid);
+  $form['instance'] = array('#type' => 'value', '#value' => $config->instance);
+
+  $label = metatag_config_instance_label($config->instance);
+  $delete = metatag_config_access('delete', $config);
+  $title = $delete ? t('Are you sure you want to delete the meta tag defaults for @label?', array('@label' => $label)) : t('Are you sure you want to revert the meta tag defaults for @label?', array('@label' => $label));
+
+  return confirm_form(
+    $form,
+    $title,
+    'admin/config/search/metatags',
+    t('This action cannot be undone.')
+  );
+}
+
+function metatag_config_delete_form_submit($form, &$form_state) {
+  $config = metatag_config_load($form_state['values']['instance']);
+  metatag_config_delete($config);
+
+  $label = metatag_config_instance_label($config->instance);
+  $delete = metatag_config_access('delete', $config);
+  $title = $delete ? t('The meta tag defaults for @label have been deleted.', array('@label' => $label)) : t('The meta tag defaults for @label have been reverted.', array('@label' => $label));
+  drupal_set_message($title);
+
+  $form_state['redirect'] = 'admin/config/search/metatags';
+}
+
+function metatag_config_export_form($config) {
+  ctools_include('export');
+  return drupal_get_form('ctools_export_form', ctools_export_crud_export('metatag_config', $config), t('Export'));
+}
+
+/**
+ * Form constructor to revert nodes to their default metatags.
+ *
+ * @see metatag_bulk_revert_form_submit()
+ * @ingroup forms
+ */
+function metatag_bulk_revert_form() {
+  // Get the list of entity:bundle options
+  $options = array();
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    foreach (array_keys($entity_info['bundles']) as $bundle) {
+      if (metatag_entity_supports_metatags($entity_type, $bundle)) {
+        $options[$entity_type . ':' . $bundle] = $entity_info['label'] . ': ' . $entity_info['bundles'][$bundle]['label'];
+      }
+    }
+  }
+
+  $form['update'] = array(
+    '#type' => 'checkboxes',
+    '#required' => TRUE,
+    '#title' => t('Select the entities to revert'),
+    '#options' => $options,
+    '#default_value' => array(),
+    '#description' => t('All meta tags will be removed for all content of the selected entities.'),
+  );
+
+  $metatags = metatag_get_info();
+  $options = array();
+  foreach ($metatags['tags'] as $tag_name => $tag) {
+    $options[$tag_name] = t('@group_label: @tag_label', array(
+      '@group_label' => $metatags['groups'][$tag['group']]['label'],
+      '@tag_label' => $tag['label'],
+    ));
+  }
+
+  if (count($options) > 0) {
+    $form['tags'] = array(
+      '#type' => 'checkboxes',
+      '#required' => FALSE,
+      '#title' => t('Select the tags to revert'),
+      '#description' => t('If you select any tags, only those tags will be reverted.'),
+      '#options' => $options,
+    );
+  }
+
+  $languages = language_list();
+  $options = array(
+    LANGUAGE_NONE => t('Language neutral'),
+  );
+  foreach ($languages as $language) {
+    $options[$language->language] = $language->name;
+  }
+
+  $form['languages'] = array(
+    '#type' => 'checkboxes',
+    '#required' => FALSE,
+    '#title' => t('Select the languages to revert'),
+    '#description' => t('If you select any languages, only tags for those languages will be reverted.'),
+    '#options' => $options,
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Revert'),
+  );
+
+  return $form;
+}
+
+/**
+ * Form submit handler for metatag reset bulk revert form.
+ *
+ * @see metatag_batch_revert_form()
+ * @see metatag_bulk_revert_batch_finished()
+ */
+function metatag_bulk_revert_form_submit($form, &$form_state) {
+  $batch = array(
+    'title' => t('Bulk updating metatags'),
+    'operations' => array(),
+    'finished' => 'metatag_bulk_revert_batch_finished',
+    'file' => drupal_get_path('module', 'metatag') . '/metatag.admin.inc',
+  );
+
+  $tags = isset($form_state['values']['tags']) ? array_filter($form_state['values']['tags']) : array();
+  $languages = isset($form_state['values']['languages']) ? array_filter($form_state['values']['languages']) : array();
+
+  // Set a batch operation per entity:bundle.
+  foreach (array_filter($form_state['values']['update']) as $option) {
+    list($entity_type, $bundle) = explode(':', $option);
+    $batch['operations'][] = array('metatag_bulk_revert_batch_operation', array($entity_type, $bundle, $tags, $languages));
+  }
+
+  batch_set($batch);
+}
+
+/**
+ * Batch callback: delete custom metatags for selected bundles.
+ */
+function metatag_bulk_revert_batch_operation($entity_type, $bundle, $tags, $languages, &$context) {
+  if (!isset($context['sandbox']['current'])) {
+    $context['sandbox']['count'] = 0;
+    $context['sandbox']['current'] = 0;
+  }
+
+  // Query the selected entity table.
+  $entity_info = entity_get_info($entity_type);
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', $entity_type)
+    ->propertyCondition($entity_info['entity keys']['id'], $context['sandbox']['current'], '>')
+    ->propertyOrderBy($entity_info['entity keys']['id']);
+  if ($entity_type != 'user') {
+    /**
+     * Entities which do not define a bundle such as User fail returning no results.
+     * @see https://www.drupal.org/node/1054168#comment-5266208
+     */
+    $query->entityCondition('bundle', $bundle);
+  }
+  // Get the total amount of entities to process.
+  if (!isset($context['sandbox']['total'])) {
+    $context['sandbox']['total'] = $query->count()->execute();
+    $query->count = FALSE;
+
+    // If there are no bundles to revert, stop immediately.
+    if (!$context['sandbox']['total']) {
+      $context['finished'] = 1;
+      return;
+    }
+  }
+
+  // Process 25 entities per iteration.
+  $query->range(0, 25);
+  $result = $query->execute();
+  $entity_ids = !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
+  foreach ($entity_ids as $entity_id) {
+    $metatags = metatag_metatags_load($entity_type, $entity_id);
+    if (!empty($metatags)) {
+      $reset = FALSE;
+      if (empty($tags)) {
+        // All tags should be reset, so we just delete any records from the db.
+        $query = db_delete('metatag')
+          ->condition('entity_type', $entity_type)
+          ->condition('entity_id', $entity_id);
+        if (!empty($languages)) {
+          $query->condition('language', $languages, 'IN');
+        }
+        $query->execute();
+        metatag_metatags_cache_clear($entity_type, $entity_id);
+        $reset = TRUE;
+      }
+      else {
+        // Iterate over tags and unset those, that we want to reset.
+        $needs_reset = FALSE;
+        foreach ($metatags as $metatags_language => $metatags_tags) {
+          if (empty($languages) || in_array($metatags_language, $languages)) {
+            foreach ($metatags_tags as $metatags_tag => $metatags_value) {
+              if (in_array($metatags_tag, $tags)) {
+                unset($metatags[$metatags_language][$metatags_tag]);
+                $needs_reset = TRUE;
+              }
+            }
+          }
+        }
+        // Save modified metatags.
+        if ($needs_reset) {
+          // We don't have a revision id, so we'll get the active one.
+          // Unfortunately, the only way of getting the active revision ID is to
+          // first load the entity, and then extract the ID. This is a bit
+          // performance intensive, but it seems to be the only way of doing it.
+          $entities = entity_load($entity_type, array($entity_id));
+          if (!empty($entities[$entity_id])) {
+            // We only care about the revision_id.
+            list(, $revision_id, ) = entity_extract_ids($entity_type, $entities[$entity_id]);
+          }
+          metatag_metatags_save($entity_type, $entity_id, $revision_id, $metatags, $bundle);
+          $reset = TRUE;
+        }
+      }
+      if ($reset) {
+        $context['results'][] = t('Reverted metatags for @bundle with id @id.', array(
+          '@bundle' => $entity_type . ': ' . $bundle,
+          '@id' => $entity_id,
+        ));
+      }
+    }
+  }
+
+  $context['sandbox']['count'] += count($entity_ids);
+  $context['sandbox']['current'] = max($entity_ids);
+
+  if ($context['sandbox']['count'] != $context['sandbox']['total']) {
+    $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
+  }
+}
+
+/**
+ * Batch finished callback.
+ */
+function metatag_bulk_revert_batch_finished($success, $results, $operations) {
+  if ($success) {
+    if (!count($results)) {
+      drupal_set_message(t('No metatags were reverted.'));
+    }
+    else {
+      $message = theme('item_list', array('items' => $results));
+      drupal_set_message($message);
+    }
+  }
+  else {
+    $error_operation = reset($operations);
+    drupal_set_message(t('An error occurred while processing @operation with arguments : @args',
+      array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE))));
+  }
+}
+
+/**
+ * Misc settings page.
+ */
+function metatag_admin_settings_form() {
+  $form = array();
+
+  $form['#attached'] = array(
+    'js' => array(
+      drupal_get_path('module', 'metatag') . '/metatag.admin.js',
+    ),
+    'css' => array(
+      drupal_get_path('module', 'metatag') . '/metatag.admin.css',
+    ),
+  );
+
+  $form['entities'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Master controls for all entities'),
+    '#description' => t('By enabling and disabling items here, it is possible to control which entities (e.g. nodes, taxonomy terms) and bundles (e.g. content types, vocabularies) will have the meta tag form available on their respective edit pages. If an entity type is disabled it also disables it for <em>all</em> of that entity type\'s bundles.<br />Technical note: Entity types must not be configuration entities and must have view modes in order to be compatible.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    // Only show entities that are capable of using meta tags.
+    if (metatag_entity_type_is_suitable($entity_type, $entity_info)) {
+      $entity_enabled = metatag_entity_supports_metatags($entity_type);
+      $form['entities']['metatag_enable_' . $entity_type] = array(
+        '#type' => 'checkbox',
+        '#title' => t($entity_info['label']),
+        '#default_value' => $entity_enabled,
+        // '#description' => t('Enable meta tags for all pages of this entity type.'),
+      );
+
+      // Some entities, e.g. User, (core) File, have a single bundle with the
+      // same name as the entity, so only show the bundles list if there is
+      // more than one of them and the bundle's name isn't the same as the
+      // entity type's.
+      if (!empty($entity_info['bundles'])) {
+        foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+          if (count($entity_info['bundles']) > 1 || $entity_type != $bundle_name) {
+            // If the entity type was disabled, automatically enable the bundle.
+            // This will have the effect that if the entity type is enabled in
+            // the form then all of the bundles will then also be enabled. This
+            // is safe to do because in the rest of the module the bundle will
+            // be ignored if the entity is disabled.
+            $form['entities']['metatag_enable_' . $entity_type . '__' . $bundle_name] = array(
+              '#type' => 'checkbox',
+              '#title' => t($bundle_info['label']),
+              '#default_value' => !$entity_enabled || metatag_entity_supports_metatags($entity_type, $bundle_name),
+              '#attributes' => array(
+                // Add some theming that'll indent this bundle.
+                'class' => array('metatag-bundle-checkbox'),
+              ),
+              '#states' => array(
+                'visible' => array(
+                  ':input[name="metatag_enable_' . $entity_type . '"]' => array('checked' => TRUE),
+                ),
+              ),
+            );
+          }
+        }
+      }
+    }
+  }
+
+  $form['additional'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Additional settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  $form['additional']['metatag_pager_string'] = array(
+    '#title' => t('Custom pager string'),
+    '#type' => 'textfield',
+    '#description' => t('When the current page includes a pager, e.g. the URL contains "?page=42", the [current-page:pager] token may be added to a meta tag to differentiate between two pages that would otherwise have the same meta tags. The value "PAGER" (must be in uppercase) will be replaced by the actual page count. Note: the pager will only output if the page number is 2 or above and the string "page=NUMBER" is in the URL.<br />For best use, it may be worthwhile to add the [current-page:pager] to the page title to the left of the site name, to the start of description tags, etc.'),
+    '#default_value' => variable_get('metatag_pager_string', 'Page PAGER | '),
+  );
+
+  $form['i18n'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Internationalization options'),
+    '#description' => t('Additional options are available when using the <a href="@url">Internationalization module</a>.', array('@url' => 'https://www.drupal.org/project/i18n')),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  $form['i18n']['metatag_i18n_disabled'] = array(
+    '#title' => t('Disable i18n integration'),
+    '#type' => 'checkbox',
+    '#description' => t('If the i18n_string module is enabled but the site does not need to translate Metatag strings, the integration may be disabled to avoid a large volume of records being added to the translation system.'),
+    '#default_value' => variable_get('metatag_i18n_disabled', FALSE),
+    '#disabled' => !module_exists('i18n_string'),
+  );
+
+  $form['i18n']['metatag_i18n_translate_output'] = array(
+    '#title' => t('Translate output'),
+    '#type' => 'checkbox',
+    '#description' => t('Optionally translate the final page output.'),
+    '#default_value' => variable_get('metatag_i18n_translate_output', FALSE),
+    '#disabled' => !module_exists('i18n_string'),
+  );
+
+  $form['i18n']['metatag_i18n_enable_watchdog'] = array(
+    '#title' => t('Enable logging of translations to Watchdog'),
+    '#type' => 'checkbox',
+    '#description' => t('Optionally log to Watchdog any changes that happen.'),
+    '#default_value' => variable_get('metatag_i18n_enable_watchdog', FALSE),
+    '#disabled' => !module_exists('i18n_string'),
+  );
+
+  $form['advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  $form['advanced']['metatag_load_all_pages'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Output meta tags even if only global settings apply'),
+    '#description' => t('By default Metatag will load the global default values for all pages that do not have meta tags assigned via the normal entity display or via Metatag Context. This may be disabled so that meta tags will only be output on pages that specifically have meta tags configured for them.'),
+    '#default_value' => variable_get('metatag_load_all_pages', TRUE),
+  );
+
+  $form['advanced']['metatag_tag_admin_pages'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Output meta tags on admin pages'),
+    '#description' => t('By default meta tags will not be output on admin pages, but it may be beneficial for some sites to do so.'),
+    '#default_value' => variable_get('metatag_tag_admin_pages', FALSE),
+  );
+
+  $form['advanced']['metatag_extended_permissions'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Advanced permissions'),
+    '#description' => t('Optionally add a permission for each individual meta tag. This provides tremendous flexibility for the editorial process, at the expense of making the permissions configuration more tedious.'),
+    '#default_value' => variable_get('metatag_extended_permissions', FALSE),
+  );
+
+  $form['advanced']['metatag_entity_no_lang_default'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Don't load entity's default language values if no languages match"),
+    '#description' => t("On a site with multiple languages it is possible for an entity to not have meta tag values assigned for the language of the current page. By default the meta tags for an entity's default language value will be used in this scenario, with the canonical URL pointing to the URL. This option may be disabled, i.e. to only load meta tags for languages that specifically have them assigned, otherwise using defaults."),
+    '#default_value' => variable_get('metatag_entity_no_lang_default', FALSE),
+  );
+
+  $form['advanced']['metatag_load_defaults'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Load the module's default configurations"),
+    '#description' => t("Control whether the module's default configuration is used. This will not affect configurations exported via Features."),
+    '#default_value' => variable_get('metatag_load_defaults', TRUE),
+  );
+
+  $form['advanced']['metatag_cache_output'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Cache meta tag output'),
+    '#description' => t('Enabling this will cause all meta tag output to be cached for each page, which may aid with site performance in some circumstances. Should not be used if there are paths which include user-specific meta tags for the <em>current user</em>, they may lead to information about the user being accidentally leaked; this problem does not affect the "user/[uid]" pages. It may also cause the {cache_metatag} cache table to grow to be extremely large in certain circumstances.'),
+    '#default_value' => variable_get('metatag_cache_output', FALSE),
+  );
+
+  $form['advanced']['metatag_leave_core_tags'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Leave core's meta tags as-is"),
+    '#description' => t("Drupal core outputs a number of meta tags itself: canonical, shortlink, and generator. Metatag can be used to replace these with custom values. Should Metatag not have values for these meta tags, core's tags will normally be removed. Enabling this option will leave those meta tags on the page, even if Metatag is not replacing them."),
+    '#default_value' => variable_get('metatag_leave_core_tags', FALSE),
+  );
+
+  $form['advanced']['metatag_page_region'] = array(
+    '#type' => 'select',
+    '#title' => t("Page region to use"),
+    '#description' => t("By default Metatag uses the 'Content' region to trigger output of the meta tags. Some themes do not have this region, so it can be necessary to pick another."),
+    '#options' => system_region_list(variable_get('theme_default', 'bartik')),
+    '#default_value' => variable_get('metatag_page_region', 'content'),
+  );
+
+  $form['advanced']['metatag_token_sanitize'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Sanitize content during token replacement'),
+    '#description' => t('If checked, will ensure that metatag value output is encoded and text filters are processed.'),
+    '#default_value' => variable_get('metatag_token_sanitize', FALSE),
+  );
+
+  // Extra submission logic.
+  $form['#submit'][] = 'metatag_admin_settings_form_submit';
+
+  return system_settings_form($form);
+}
+
+/**
+ * Form API submission callback for metatag_admin_settings_form().
+ */
+function metatag_admin_settings_form_submit() {
+  cache_clear_all('entity_info:', 'cache', TRUE);
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  drupal_set_message(t('The Metatag cache has been cleared, so all meta tags can be reloaded.'));
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.admin.js b/profiles/wcm_base/modules/contrib/metatag/metatag.admin.js
new file mode 100644
index 0000000000000000000000000000000000000000..64e6778f4810599642007b6b7c3d7f31aa3fc2aa
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.admin.js
@@ -0,0 +1,48 @@
+/**
+ * @file
+ * Custom admin-side JS for the Metatag module.
+ */
+
+(function ($) {
+  'use strict';
+
+Drupal.behaviors.metatagUIConfigListing = {
+  attach: function (context) {
+    // Hidden elements to be visible if JavaScript is enabled.
+    $('.js-show').show();
+
+    // Make the leaf arrow clickable.
+    $('.metatag-config-label').hover(function(){
+      $(this).css({'cursor': 'pointer'});
+    })
+    .click(function(){
+      $(this).find('a.toggle-details', context).trigger('click');
+    });
+
+    // Show or hide the summary
+    $('table.metatag-config-overview a.toggle-details', context).click(function(event) {
+      $(this).parent('div').siblings('div.metatag-config-details').each(function() {
+        if ($(this).hasClass('js-hide')) {
+          $(this).slideDown('slow').removeClass('js-hide');
+        }
+        else {
+          $(this).slideUp('slow').addClass('js-hide');
+        }
+      });
+
+      // Change the expanded or collapsed state of the instance label.
+      if ($(this).parent('div').hasClass('collapsed')) {
+        $(this).parent('div').removeClass('collapsed').addClass('expanded');
+      }
+      else {
+        $(this).parent('div').removeClass('expanded').addClass('collapsed');
+      }
+
+      // This event may be triggered by a parent element click - so we don't
+      // want the click to bubble up otherwise we get recursive click events.
+      event.stopPropagation();
+    });
+  }
+};
+
+})(jQuery);
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.api.php b/profiles/wcm_base/modules/contrib/metatag/metatag.api.php
new file mode 100644
index 0000000000000000000000000000000000000000..f356140fcad35269c2f8477b2fb7ad6918b66e79
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.api.php
@@ -0,0 +1,454 @@
+<?php
+/**
+ * @file
+ * API documentation for the Metatag module.
+ */
+
+/**
+ * Provides a default configuration for Metatag intances.
+ *
+ * This hook allows modules to provide their own Metatag instances which can
+ * either be used as-is or as a "starter" for users to build from.
+ *
+ * This hook should be placed in MODULENAME.metatag.inc and it will be auto-
+ * loaded. MODULENAME.metatag.inc *must* be in the same directory as the
+ * .module file which *must* also contain an implementation of
+ * hook_ctools_plugin_api, preferably with the same code as found in
+ * metatag_ctools_plugin_api().
+ *
+ * The $config->disabled boolean attribute indicates whether the Metatag
+ * instance should be enabled (FALSE) or disabled (TRUE) by default.
+ *
+ * @return array
+ *   An associative array containing the structures of Metatag instances, as
+ *   generated from the Export tab, keyed by the Metatag config name.
+ *
+ * @see metatag_metatag_config_default()
+ * @see metatag_ctools_plugin_api()
+ */
+function hook_metatag_config_default() {
+  $configs = array();
+
+  $config = new stdClass();
+  $config->instance = 'config1';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => '[current-page:title] | [site:name]'),
+    'generator' => array('value' => 'Drupal 7 (http://drupal.org)'),
+    'canonical' => array('value' => '[current-page:url:absolute]'),
+    'shortlink' => array('value' => '[current-page:url:unaliased]'),
+  );
+  $configs[$config->instance] = $config;
+
+  $config = new stdClass();
+  $config->instance = 'config2';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => '[user:name] | [site:name]'),
+  );
+  $configs[$config->instance] = $config;
+
+  return $configs;
+}
+
+/**
+ * Allow the exported configurations to be changed prior to being cached.
+ */
+function hook_metatag_config_default_alter(&$config) {
+}
+
+/**
+ * Internal hook for adding further configuration values in bundled submodules.
+ *
+ * The defaults provided by the main Metatag module need to be extended by the
+ * bundled submodules before they are presented to other modules for altering
+ * via hook_metatag_config_default_alter(), in case differences in module
+ * weights and loading priorities cause the submodules' settings to run after
+ * those of any custom modules.
+ *
+ * @see hook_metatag_config_default()
+ * @see hook_metatag_config_default_alter()
+ */
+function hook_metatag_bundled_config_alter(&$config) {
+}
+
+/**
+ * Allow modules to act upon the record insertion.
+ */
+function hook_metatag_config_instance_info() {
+  return array();
+}
+
+/**
+ * Alter record insertion provided by modules with the previous hook.
+ *
+ * @see hook_metatag_config_instance_info()
+ */
+function hook_metatag_config_instance_info_alter(&$info) {
+}
+
+/**
+ * Allow the Metatag config instance name to be changed.
+ *
+ * By default, Metatag module define config instance per entity bundle, making
+ * it impossible to store set of meta tags based on other criteria. Combining
+ * this hook with hook_metatag_config_instance_info_alter() it is possible to
+ * alter the logic of how instances are named based on any custom criteria.
+ *
+ * @param string $instance
+ *   The name of the instance generated by default.
+ * @param object $entity
+ *   The entity object to generate the Metatag instance name for.
+ * @param string $entity_type
+ *   The entity type of the entity.
+ * @param string $bundle
+ *   The bundle of the entity.
+ */
+function hook_metatag_get_entity_metatags_instance_alter(&$instance, $entity, $entity_type, $bundle) {
+  if ($entity_type == 'user') {
+    // Split config instances based on user roles.
+    foreach (array_reverse(user_roles(), TRUE) as $rid => $role) {
+      if ($rid == DRUPAL_AUTHENTICATED_RID) {
+        continue;
+      }
+
+      if (isset($entity->roles[$rid])) {
+        $instance = 'user:' . $role;
+        break;
+      }
+    }
+  }
+}
+
+/**
+ * Never triggered?
+ *
+ * @todo Confirm whether this still exists.
+ */
+function hook_metatag_config_load() {
+}
+
+/**
+ * Never triggered?
+ *
+ * @todo Confirm whether this still exists.
+ */
+function hook_metatag_config_load_presave() {
+}
+
+/**
+ * Allow a Metatag configuration to be modified prior to being saved.
+ *
+ * @param object $config
+ *   The configuration object that is about to be saved.
+ */
+function hook_metatag_config_presave($config) {
+}
+
+/**
+ * Triggered when a Metatag configuration is created.
+ *
+ * @param object $config
+ *   The configuration object that was created.
+ */
+function hook_metatag_config_insert($config) {
+}
+
+/**
+ * Triggered when a Metatag configuration is updated.
+ *
+ * @param object $config
+ *   The configuration object that was modified.
+ */
+function hook_metatag_config_update($config) {
+}
+
+/**
+ * Triggered when a Metatag configuration is removed.
+ *
+ * @param object $config
+ *   The name of the configuration object that was removed.
+ */
+function hook_metatag_config_delete($config) {
+}
+
+/**
+ * Definition of the meta tags and groups.
+ *
+ * @return array
+ *   A nested array of 'tags' and 'groups', each keyed off the machine name for
+ *   their respective structure type, with the following values:
+ *   Tags:
+ *     'label' - The name for this meta tag.
+ *     'description' - An explanation of what this meta tag is used for and what
+ *       values are permissible.
+ *     'class' - The class name that controls this meta tag.
+ *     'weight' - Used to sort the meta tags during output.
+ *     'group' - The machine name of a group this meta tag will be contained
+ *       within.
+ *     'context' - Optionally control the type of configuration the meta tag
+ *       will be available from. Possible values are:
+ *       [empty] - All meta tags apply to all possible objects, by default.
+ *       'global' - This will make it only show in the global meta tag
+ *         configuration form.
+ *       [entity type] - Makes the meta tag only show for specific entity types.
+ *     'header' - Optionally output the meta tag as an HTTP header value.
+ *     'element' - Optional attributes for rendering the meta tag. Should
+ *       contain the following:
+ *       '#theme' - The theming function used to render the meta tag.
+ *     'replaces' - An optional array of meta tags that this meta tag replaces.
+ *       Used to indicate that these deprecated meta tags will be replaced by
+ *       this newer one, their values will be used, upon the next object save
+ *       the deprecated tag will be entirely replaced by the new meta tag. While
+ *       one meta tag can replace several others, only one of the possible
+ *       values will be used, the others will be silently purged upon the next
+ *       configuration/object save.
+ *     'multiple' - If set to TRUE the output will be comma-separated and output
+ *       as multiple tags.
+ *     'image' - If set to TRUE some additional effort will be added to attempt
+ *       extracting image URLs from the value. Currently limited to matching
+ *       the default output of core image theming, i.e. the following string:
+ *         src="[URL]" width=
+ *     'url' - If set to TRUE, relative paths will be converted to absolute.
+ *     'is_language' - If set to TRUE, will not allow the Drupal default
+ *       language value "und" to be output.
+ *     'select_or_other' - If set to TRUE, form[#type] is set to 'select' and
+ *       the "select_or_other" module is available, that module will be used to
+ *       provide a text field to manually insert another option.
+ *     'form' - Optional items to be passed directly to the form; uses standard
+ *       Form API values.
+ *     'devel_generate' - Optional values to be passed to the Devel Generate
+ *       submodule. Should be an array containing one of the following values:
+ *       'type' - One of the following:
+ *         'canonical' - The token for the absolute URL for the current page.
+ *         'email' - An email address randomly generated at the site's hostname.
+ *         'float' - A random floating point number between 0.0 and 999.999.
+ *         'image' - A randomly generated image.
+ *         'integer' - A random integer between 0 and 999.
+ *         'phone' - A phone number in the format 999-999-9999.
+ *         'select' - A value randomly selected from the available form options.
+ *         'text' - Random text string.
+ *         'twitter' - A Twitter username.
+ *         'url' - A randomly generated URL on this site.
+ *       'maxlength' - The maximum length / number of iterations of this value,
+ *         defaults to 10.
+ *     'dependencies' - Optional nested array of values to indicate other meta
+ *       tags that must be present in order for this meta tag to be visible. See
+ *       The Open Graph and Twitter Cards submodules for example usage. Each
+ *       dependency must contain the following elements:
+ *       'dependency' - The name of the meta tag that is required.
+ *       'attribute' - The name of the other meta tag that is to be checked,
+ *         most meta tags use "value" as the attribute name.
+ *       'condition' - The state condition to be checked against, e.g. "filled"
+ *         to check text values, "checked" for a checkbox, "value" to compare
+ *         the raw selection; see https://api.drupal.org/drupal_process_states
+ *         for more details.
+ *       'value' - The field value to check the 'condition' against. see
+ *         https://api.drupal.org/drupal_process_states for further details.
+ *   Groups:
+ *     'label' - The name for this group.
+ *     'description' - A detailed explanation of these meta tags.
+ *     'form' - Additional items to be passed directly to the form.
+ *   Note: 'label', 'description', and any text strings passed in 'form', should
+ *   be translated.
+ *
+ * @see metatag_metatag_info()
+ */
+function hook_metatag_info() {
+  return array();
+}
+
+/**
+ * Alter record insertion provided by modules with the previous hook.
+ *
+ * @see hook_metatag_info()
+ */
+function hook_metatag_info_alter(&$info) {
+}
+
+/**
+ * Alter metatags before being cached.
+ *
+ * This hook is invoked prior to the meta tags for a given page are cached.
+ *
+ * @param array $output
+ *   All of the meta tags to be output for this page in their raw format. This
+ *   is a heavily nested array.
+ * @param string $instance
+ *   An identifier for the current page's page type, typically a combination
+ *   of the entity name and bundle name, e.g. "node:story".
+ * @param array $options
+ *   All of the options used to generate the meta tags.
+ */
+function hook_metatag_metatags_view_alter(&$output, $instance, $options) {
+  if (isset($output['description']['#attached']['drupal_add_html_head'][0][0]['#value'])) {
+    $output['description']['#attached']['drupal_add_html_head'][0][0]['#value'] = 'O rly?';
+  }
+}
+
+/**
+ * Allow other modules to customize the data to generate the cache ID.
+ */
+function hook_metatag_page_cache_cid_parts_alter(&$cid_parts) {
+}
+
+/**
+ * Allow other modules to alter the meta tags prior to saving.
+ */
+function hook_metatag_presave(&$metatags, $entity_type, $entity_id, $revision_id, $langcode) {
+}
+
+/**
+ * Allows modules to alter the defined list of tokens available
+ * for metatag patterns replacements.
+ *
+ * By default only context (for example: global, node, etc...)
+ * related tokens are made available to metatag patterns replacements.
+ * This hook allows other modules to extend the default declared tokens.
+ *
+ * @param array $options
+ *   (optional) An array of options including the following keys and values:
+ *   - token types: An array of token types to be passed to theme_token_tree().
+ *   - context: An identifier for the configuration instance type, typically
+ *     an entity name or object name, e.g. node, views, taxonomy_term.
+ *
+ * @see metatag_config_edit_form()
+ * @see metatag_field_attach_form()
+ */
+function hook_metatag_token_types_alter(&$options) {
+  // Watchout: $options['token types'] might be empty.
+  if (!isset($options['token types'])) {
+    $options['token types'] = array();
+  }
+
+  if ($options['context'] == 'config1') {
+    $options['token types'] += array('token_type1', 'token_type2');
+  }
+  elseif ($options['context'] == 'config2') {
+    $options['token types'] += array('token_type3', 'token_type4');
+  }
+}
+
+/**
+ * Allows modules to alter defined token patterns and values before replacement.
+ *
+ * The metatag module defines default token patterns replacements depending on
+ * the different configuration instances (contexts, such as global, node, ...).
+ * This hook provides an opportunity for other modules to alter the patterns or
+ * the values for replacements, before tokens are replaced (token_replace).
+ *
+ * See facetapi and facetapi_bonus modules for an example of implementation.
+ *
+ * @param string $pattern
+ *   A string potentially containing replaceable tokens. The pattern could also
+ *   be altered by reference, allowing modules to implement further logic, such
+ *   as tokens lists or masks/filters.
+ * @param array $types
+ *   Corresponds to the 'token data' property of the $options object.
+ *   (optional) An array of keyed objects. For simple replacement scenarios
+ *   'node', 'user', and others are common keys, with an accompanying node or
+ *   user object being the value. Some token types, like 'site', do not require
+ *   any explicit information from $data and can be replaced even if it is
+ *   empty.
+ * @param string $tag_name
+ *   The name of the meta tag being altered.
+ *
+ * @see DrupalTextMetaTag::getValue()
+ */
+function hook_metatag_pattern_alter(&$pattern, &$types, $tag_name) {
+  if (strpos($pattern, 'token_type1') !== FALSE) {
+    $types['token_type1'] = "data to be used in hook_tokens for replacement";
+  }
+  if (strpos($pattern, 'token_type2') !== FALSE) {
+    // Load something or do some operations.
+    $types['token_type2'] = array("Then fill in the array with the right data");
+    // $pattern could also be altered, for example, strip off [token_type3].
+    $pattern = str_replace('[token_type3]', '', $pattern);
+  }
+}
+
+/**
+ * Allow modules to override whether entity types are enabled for use.
+ *
+ * By default the system only support entities that are not configuration
+ * entities, have multiple view modes (excluding those created by the ical,
+ * diff and token modules), are fieldable, and are not one of the following:
+ * - field_collection_item (from the Field Collection module)
+ * - paragraphs_item (from the Paragraphs module)
+ *
+ * @param bool $suitable
+ *   Whether or not the entity type is enabled for use with Metatag.
+ * @param string $entity_type
+ *   The machine name of the entity type.
+ * @param array $entity_info
+ *   The full specifications for this entity type, as returned by
+ *   entity_get_info().
+ */
+function hook_metatag_entity_type_is_supported_alter(&$suitable, $entity_type, $entity_info) {
+  // Enable Metatag support for a custom entity that might otherwise be
+  // ignored, e.g. it doesn't allow fields.
+  if ($entity_type == 'my_entity') {
+    $suitable = TRUE;
+  }
+}
+
+/**
+ * Identify the entity type provided by a specific view.
+ *
+ * When a view is used to display a page it can be difficult to identify what
+ * entity type is being managed. Use this hook to inform Metatag what type of
+ * entity is being displayed.
+ *
+ * @param object $view
+ *   The view object being displayed.
+ *
+ * @return string|NULL
+ *   Should return a string indicating an entity type that will be paired with
+ *   the views' first argument ($view->args[0]) to load that entity.
+ */
+function hook_metatag_views_post_render_get_entity($view) {
+  $display = $view->display[$view->current_display];
+  if ($display->display_options['path'] == 'coolpage/%') {
+    return 'my_entity';
+  }
+}
+
+/**
+ * Allow the context string being passed to i18n_string to be changed before it
+ * is used.
+ *
+ * If the string is set to an empty value it will cause this meta tag to not
+ * be translated.
+ *
+ * @param string $context
+ *   The context string being passed into i18n_string. Will usually be in the
+ *   format "[category]:[path-identifier]", e.g. "[node:123]", "[page:contact]",
+ *   etc.
+ * @param string $tag_name
+ *   The name of the meta tag being translated.
+ */
+function hook_metatag_i18n_context_alter(&$context, $tag_name) {
+  // Don't bother translating the canonical URL.
+  if ($tag_name == 'canonical') {
+    $context = '';
+  }
+}
+
+/**
+ * Allow modules to overide the expiration of metatag caches.
+ *
+ * By default Metatag caches everything as CACHE_PERMANENT, this alter allows to
+ * change that.
+ *
+ * @param $expire
+ *   The expire value to change.
+ * @param $cid
+ *   The cid about to be cached.
+ * @param $data
+ *   The data to be cached.
+ */
+function hook_metatag_cache_set_expire_alter(&$expire, $cid, $data) {
+  $expire = CACHE_TEMPORARY;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.drush.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..950e560710240cd9e1a120fe95c3aa15b3238f91
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.drush.inc
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @file
+ * Drush integration for Metatag.
+ */
+
+/**
+ * Implements hook_drush_cache_clear().
+ */
+function metatag_drush_cache_clear(&$types) {
+  if (function_exists('module_exists') && module_exists('metatag')) {
+    $types['metatag'] = 'drush_metatag_cache_clear_token_info';
+  }
+}
+
+/**
+ * Clear caches internal to Metatag module.
+ */
+function drush_metatag_cache_clear_token_info() {
+  metatag_config_cache_clear();
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.features.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.features.inc
new file mode 100644
index 0000000000000000000000000000000000000000..244fecc3769eb099740e635d36017ad2e9a10ad0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.features.inc
@@ -0,0 +1,97 @@
+<?php
+/**
+ * @file
+ * Features integration for the Metatag module.
+ */
+
+/**
+ * Implements hook_features_export().
+ */
+function metatag_features_export($data, &$export, $module_name = '', $type = 'metatag') {
+  $pipe = array();
+
+  foreach ($data as $name) {
+    if (metatag_config_load($name)) {
+      $export['features'][$type][$name] = $name;
+    }
+  }
+
+  $export['dependencies']['metatag'] = 'metatag';
+
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function metatag_features_export_render($module_name, $data, $export = NULL) {
+  $code = array();
+  $code[] = '  $config = array();';
+  $code[] = '';
+
+  foreach ($data as $key => $name) {
+    if (is_object($name)) {
+      $name = $name->instance;
+    }
+    if ($config = metatag_config_load($name)) {
+      $export = new stdClass();
+      $export->instance = $config->instance;
+      if (isset($config->disabled)) {
+        $export->disabled = $config->disabled;
+      }
+      $export->config = $config->config;
+      $export = features_var_export($export, '  ');
+      $key = features_var_export($name);
+      $code[] = "  // Exported Metatag config instance: {$name}.";
+      $code[] = "  \$config[{$key}] = {$export};";
+      $code[] = "";
+    }
+  }
+  $code[] = '  return $config;';
+  $code = implode("\n", $code);
+  return array('metatag_export_default' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function metatag_features_revert($module) {
+  if ($feature_conf = features_get_default('metatag', $module)) {
+    foreach (array_keys($feature_conf) as $config) {
+      if ($conf = metatag_config_load($config)) {
+        db_delete('metatag_config')->condition('instance', $config)->execute();
+      }
+      unset($feature_conf[$config]['cid']);
+      $object = new stdClass();
+      $object->cid = NULL;
+      $object->instance = $config;
+      $object->config = $feature_conf[$config]['config'];
+      metatag_config_save($object);
+
+      if (!empty($feature_conf[$config]['disabled'])) {
+        ctools_export_crud_disable('metatag_config', $config);
+      }
+      else {
+        ctools_export_crud_enable('metatag_config', $config);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function metatag_features_export_options() {
+  $instances = metatag_config_instance_info();
+  foreach ($instances as $key => $instance) {
+    $options[$key] = $key;
+  };
+  return $options;
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function metatag_features_rebuild($module) {
+  metatag_features_revert($module);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.feeds.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.feeds.inc
new file mode 100644
index 0000000000000000000000000000000000000000..d45d639e2f1674ea9dddc31bf9ccaca01a902524
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.feeds.inc
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @file
+ * Feeds mapping implementation for the Metatag module.
+ */
+
+/**
+ * Implements hook_feeds_processor_targets_alter().
+ */
+function metatag_feeds_processor_targets_alter(&$targets, $entity_type, $bundle) {
+  if (metatag_entity_supports_metatags($entity_type)) {
+    $info = metatag_get_info();
+    foreach ($info['tags'] as $name => $tag) {
+      $targets['meta_' . $name] = array(
+        'name' => t('Meta tag: !label', array('!label' => $tag['label'])),
+        'callback' => 'metatag_feeds_set_target',
+        'description' => $tag['description'],
+      );
+    }
+  }
+}
+
+/**
+ * Callback function to set value of a metatag tag.
+ */
+function metatag_feeds_set_target($source, $entity, $target, $values) {
+  // Don't do anything if we weren't given any data.
+  if (empty($values)) {
+    return;
+  }
+
+  // The Feed API was changed so that the $values are passed as an array rather
+  // than a single value. For backwards compatibility, support both.
+  if (!is_array($values)) {
+    $values = array($values);
+  }
+
+  // Strip the prefix that was added above.
+  $name = str_replace('meta_', '', $target);
+
+  // Identify the type of entity being imported.
+  $entity_type = $entity->feeds_item->entity_type;
+
+  // Check for any existing data that may not have been loaded already.
+  if (!isset($entity->metatags) && !empty($entity->feeds_item->entity_id) && is_numeric($entity->feeds_item->entity_id)) {
+    $entity->metatags = array();
+    $entity_id = $entity->feeds_item->entity_id;
+
+    // Load the existing entity.
+    $stored_entities = entity_load($entity_type, array($entity_id));
+    if (!empty($stored_entities)) {
+      $stored_entity = reset($stored_entities);
+      if (!empty($stored_entity)) {
+        // Only load meta tags for the current revision.
+        list(, $revision_id) = entity_extract_ids($entity_type, $stored_entity);
+
+        // This function returns all values for all revisions.
+        $metatags = metatag_metatags_load($entity_type, $entity_id, $revision_id);
+        if (!empty($metatags)) {
+          if (!empty($metatags[$revision_id])) {
+            // Just copy all meta tags for all languages.
+            $entity->metatags = $metatags[$revision_id];
+          }
+        }
+      }
+    }
+  }
+
+  // Assign the value.
+  $langcode = metatag_entity_get_language($entity_type, $entity);
+  $entity->metatags[$langcode][$name]['value'] = $values[0];
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.i18n.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.i18n.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ab264871b51b20d84e5011ffd94349e8d3e15ceb
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.i18n.inc
@@ -0,0 +1,147 @@
+<?php
+/**
+ * @file
+ * Internationalization (i18n) hooks.
+ */
+
+/**
+ * Implements hook_i18n_string_info().
+ */
+function metatag_i18n_string_info() {
+  // Text groups.
+  $groups['metatag'] = array(
+    'title' => t('Metatag'),
+    'description' => t('Configurable meta tags.'),
+
+    // This group does not have strings with text formats.
+    'format' => FALSE,
+
+    // This group can list all strings.
+    // @todo What does this actually do?
+    'list' => TRUE,
+  );
+  return $groups;
+}
+
+/**
+ * Implements hook_i18n_object_info().
+ */
+function metatag_i18n_object_info() {
+  // Compile all of the tags to add to the translation stack.
+  $meta_tag_info = metatag_get_info();
+  $groups = $meta_tag_info['groups'];
+  $config_properties = $output_properties = array();
+  foreach ($meta_tag_info['tags'] as $tag_name => $tag_info) {
+    // Ignore certain field types that aren't translatable, mostly fields that
+    // list predetermined options in various forms.
+    if (!empty($tag_info['class']) && $tag_info['class'] == 'DrupalListMetaTag') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#type']) && $tag_info['form']['#type'] == 'select') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#options'])) {
+      continue;
+    }
+
+    // Build a suitable structure for this meta tag.
+    if (!empty($tag_info['group']) && !empty($groups[$tag_info['group']]['label'])) {
+      $group_label = $groups[$tag_info['group']]['label'] . ': ';
+    }
+    elseif (!empty($tag_info['group'])) {
+      $group_label = $tag_info['group'] . ': ';
+    }
+    else {
+      $group_label = '';
+    }
+
+    // Configuration items.
+    $config_properties[$tag_name] = array(
+      'title' => $group_label . $tag_info['label'],
+      'field' => "config.{$tag_name}.value",
+    );
+
+    // Output items.
+    $output_properties[$tag_name] = array(
+      'title' => $group_label . ': ' . $tag_info['label'],
+      'field' => "data.{$tag_name}.value",
+    );
+  }
+
+  // The main Metatag configuration items.
+  $info['metatag_config'] = array(
+    'title' => t('Metatag configuration'),
+    // Callback to load all config objects.
+    'list callback' => 'metatag_i18n_list_metatag_config',
+    // The object load callback.
+    'load callback' => 'metatag_config_load',
+    // @todo Custom i18n object overrides.
+    // 'class' => 'metatag_i18n_metatag',
+    // @todo Is this needed? What does it do?
+    // 'translation set' => TRUE,
+
+    // The object key field.
+    'key' => 'instance',
+    // Placeholders for automatic paths. This connects the 'key' to strings in
+    // the paths listed below.
+    'placeholders' => array(
+      '%instance' => 'instance',
+    ),
+    // To produce edit links automatically.
+    'edit path' => 'admin/config/search/metatags/config/%instance',
+    // Auto-generate a 'translate' tab.
+    'translate tab' => 'admin/config/search/metatags/config/%instance/translate',
+
+    // Properties for string translation.
+    'string translation' => array(
+      // The textgroup, type and (below) name will be concatenated into a single
+      // string as the {locales_source} context.
+      'textgroup' => 'metatag',
+      'type' => 'metatag_config',
+      // Table where the object is stored, to automate string lists.
+      'table' => 'metatag_config',
+      // Translatable properties of these objects.
+      'properties' => $config_properties,
+      // The path to translate individual strings.
+      'translate path' => 'admin/config/search/metatags/config/%instance/translate/%i18n_language',
+    ),
+  );
+
+  // The final meta tags being output on the page.
+  if (variable_get('metatag_i18n_translate_output', FALSE)) {
+    $info['output'] = array(
+      'title' => t('Metatag final tag output'),
+
+      // Properties for string translation.
+      'string translation' => array(
+        // The textgroup, type and (below) name will be concatenated into a
+        // single string as the {locales_source} context.
+        'textgroup' => 'metatag',
+        'type' => 'output',
+        // Translatable properties of these objects.
+        'properties' => $output_properties,
+      ),
+    );
+  }
+
+  return $info;
+}
+
+/**
+ * List callback for {metatag_config} strings.
+ */
+function metatag_i18n_list_metatag_config() {
+  ctools_include('export');
+  $configs = ctools_export_crud_load_all('metatag_config');
+
+  if (!empty($configs)) {
+    // Unserialize the config array.
+    foreach ($configs as &$config) {
+      if (is_string($config->config)) {
+        $config->config = unserialize($config->config);
+      }
+    }
+  }
+
+  return $configs;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..09bef4edc3be30e72170e7eecaa429e0763faeea
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.inc
@@ -0,0 +1,536 @@
+<?php
+/**
+ * @file
+ * Metatag primary classes.
+ */
+
+interface DrupalMetaTagInterface {
+
+  /**
+   * Constructor
+   *
+   * @param array $info
+   *   The information about the meta tag from metatag_get_info().
+   */
+  function __construct(array $info, array $data = array());
+
+  function getForm();
+
+  //function validateForm();
+
+  //function processForm();
+
+  function getValue();
+
+  function getWeight();
+
+  function getElement();
+
+  function tidyValue($value);
+
+  function convertUrlToAbsolute($url);
+
+}
+
+class DrupalDefaultMetaTag implements DrupalMetaTagInterface {
+
+  protected $info;
+  protected $data = array('value' => '');
+  protected $weight = 0;
+
+  function __construct(array $info, array $data = NULL) {
+    $this->info = $info;
+    if (isset($data)) {
+      $this->data = $data;
+    }
+  }
+
+  /**
+   * Calculate the weight of this meta tag.
+   *
+   * @return integer
+   */
+  public function getWeight() {
+    static $counter = 0;
+
+    // If no weight value is found, stack this meta tag at the end.
+    $weight = 100;
+    if (!empty($this->info['weight'])) {
+      $weight = $this->info['weight'];
+    }
+
+    return $weight + ($counter++ * 0.1);
+  }
+
+  /**
+   * Build the form for this meta tag.
+   *
+   * @return array
+   *   A standard FormAPI array.
+   */
+  public function getForm(array $options = array()) {
+    return array();
+  }
+
+  /**
+   * Get the string value of this meta tag.
+   *
+   * @return string
+   *   The value of this meta tag.
+   */
+  public function getValue(array $options = array()) {
+    $value = $this->tidyValue($this->data['value']);
+
+    // Translate the final output string prior to output. Use the
+    // 'output' i18n_string object type, and pass along the meta tag's
+    // options as the context so it can be handled appropriately.
+    $value = metatag_translate_metatag($value, $this->info['name'], $options, NULL, TRUE);
+
+    return $value;
+  }
+
+  /**
+   * Get the HTML tag for this meta tag.
+   *
+   * @return array
+   *   A render array for this meta tag.
+   */
+  public function getElement(array $options = array()) {
+    $value = $this->getValue($options);
+    if (strlen($value) === 0) {
+      return array();
+    }
+
+    // The stack of elements that will be output.
+    $elements = array();
+
+    // Dynamically add each option to this setting.
+    $base_element = isset($this->info['element']) ? $this->info['element'] : array();
+
+    // Single item.
+    if (empty($this->info['multiple'])) {
+      $values = array($value);
+    }
+
+    // Multiple items.
+    else {
+      $values = array_filter(explode(',', $value));
+    }
+
+    // Loop over each item.
+    if (!empty($values)) {
+      foreach ($values as $ctr => $value) {
+        $value = trim($value);
+
+        // Some meta tags must be output as secure URLs.
+        if (!empty($this->info['secure'])) {
+          $value = str_replace('http://', 'https://', $value);
+        }
+
+        // Combine the base configuration for this meta tag with the value.
+        $element = $base_element + array(
+          '#theme' => 'metatag',
+          '#tag' => 'meta',
+          '#id' => 'metatag_' . $this->info['name'] . '_' . $ctr,
+          '#name' => $this->info['name'],
+          '#value' => $value,
+          '#weight' => $this->getWeight(),
+        );
+
+        // Add header information if desired.
+        if (!empty($this->info['header'])) {
+          $element['#attached']['drupal_add_http_header'][] = array($this->info['header'], $value);
+        }
+
+        $elements[] = array($element, $element['#id']);
+      }
+    }
+
+    if (!empty($elements)) {
+      return array(
+        '#attached' => array('drupal_add_html_head' => $elements),
+      );
+    }
+  }
+
+  /**
+   * Remove unwanted formatting from a meta tag.
+   *
+   * @param $value string
+   *   The meta tag value to be tidied up.
+   *
+   * @return string
+   *   The meta tag value after it has been tidied up.
+   */
+  public function tidyValue($value) {
+    // Check for Media strings from the WYSIWYG submodule.
+    if (module_exists('media_wysiwyg') && strpos($value, '[[{') !== FALSE) {
+      // In https://www.drupal.org/node/2129273 media_wysiwyg_filter() was
+      // changed to require several additional arguments.
+      $langcode = language_default('language');
+      $value = media_wysiwyg_filter($value, NULL, NULL, $langcode, NULL, NULL);
+    }
+
+    // Specifically replace encoded spaces, because some WYSIWYG editors are
+    // silly. Do this before decoding the other HTML entities so that the output
+    // doesn't end up with a bunch of a-circumflex characters.
+    $value = str_replace('&nbsp;', ' ', $value);
+
+    // Decode HTML entities.
+    $value = decode_entities($value);
+
+    // Remove any HTML code that might have been included.
+    $value = strip_tags($value);
+
+    // Strip errant whitespace.
+    $value = str_replace(array("\r\n", "\n", "\r", "\t"), ' ', $value);
+    $value = str_replace('  ', ' ', $value);
+    $value = str_replace('  ', ' ', $value);
+    $value = trim($value);
+
+    return $value;
+  }
+
+  /**
+   * Make sure a given URL is absolute.
+   *
+   * @param string $url
+   *   The URL to convert to an absolute URL.
+   *
+   * @return string
+   *   The argument converted to an absolute URL.
+   */
+  function convertUrlToAbsolute($url) {
+    // Convert paths relative to the hostname, that start with a slash, to
+    // ones that are relative to the Drupal root path; ignore protocol-relative
+    // URLs.
+    if (strpos($url, base_path()) === 0 && strpos($url, '//') !== 0) {
+      // Logic:
+      // * Get the length of the base_path(), 
+      // * Get a portion of the image's path starting from the position equal
+      //   to the base_path()'s length; this will result in a path relative
+      //   to the Drupal installation's base directory.
+      $len = strlen(base_path());
+      $url = substr($url, $len);
+    }
+
+    // Pass everything else through file_create_url(). The alternative is to
+    // use url() but it would insert '?q=' into the path.
+    return file_create_url($url);
+  }
+
+}
+
+/**
+ * Text-based meta tag controller.
+ */
+class DrupalTextMetaTag extends DrupalDefaultMetaTag {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getForm(array $options = array()) {
+    $options += array(
+      'token types' => array(),
+    );
+
+    $form['value'] = isset($this->info['form']) ? $this->info['form'] : array();
+
+    $form['value'] += array(
+      '#type' => 'textfield',
+      '#title' => $this->info['label'],
+      '#description' => !empty($this->info['description']) ? $this->info['description'] : '',
+      '#default_value' => isset($this->data['value']) ? $this->data['value'] : '',
+      '#element_validate' => array('token_element_validate'),
+      '#token_types' => $options['token types'],
+      '#maxlength' => 1024,
+    );
+
+    // Optional handling for items that allow multiple values.
+    if (!empty($this->info['multiple'])) {
+      $form['value']['#description'] .= ' ' . 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->info['image'])) {
+      $form['value']['#description'] .= ' ' . t('This will be able to extract the URL from an image field.');
+    }
+
+    // Optional handling for languages.
+    if (!empty($this->info['is_language'])) {
+      $form['value']['#description'] .= ' ' . t('This will not be displayed if it is set to the "Language neutral" (i.e. "und").');
+    }
+
+    // Optional support for select_or_other.
+    if ($form['value']['#type'] == 'select' && !empty($this->info['select_or_other']) && module_exists('select_or_other')) {
+      $form['value']['#type'] = 'select_or_other';
+      $form['value']['#other'] = t('Other (please type a value)');
+      $form['value']['#multiple'] = FALSE;
+      $form['value']['#other_unknown_defaults'] = 'other';
+      $form['value']['#other_delimiter'] = FALSE;
+      $form['value']['#theme'] = 'select_or_other';
+      $form['value']['#select_type'] = 'select';
+      $form['value']['#element_validate'] = array('select_or_other_element_validate');
+    }
+
+    // Support for dependencies, using Form API's #states system.
+    // @see metatag.api.php.
+    // @see https://api.drupal.org/drupal_process_states
+    if (!empty($this->info['dependencies'])) {
+      foreach ($this->info['dependencies'] as $specs) {
+        $form['value']['#states']['visible'][':input[name*="[' . $specs['dependency'] . '][' . $specs['attribute'] . ']"]'] = array(
+          $specs['condition'] => $specs['value'],
+        );
+      }
+    }
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue(array $options = array()) {
+    $options += array(
+      'instance' => '',
+      'token data' => array(),
+      // Remove any remaining token after the string is parsed.
+      'clear' => TRUE,
+      'sanitize' => variable_get('metatag_token_sanitize', FALSE),
+      'raw' => FALSE,
+    );
+
+    $value = $this->data['value'];
+
+    if (empty($options['raw'])) {
+      // Give other modules the opportunity to use hook_metatag_pattern_alter()
+      // to modify defined token patterns and values before replacement.
+      drupal_alter('metatag_pattern', $value, $options['token data'], $this->info['name']);
+      $value = token_replace($value, $options['token data'], $options);
+    }
+
+    // Special handling for language meta tags.
+    if (!empty($this->info['is_language'])) {
+      // If the meta tag value equals LANGUAGE_NONE, i.e. "und", then don't
+      // output it.
+      if (is_string($value) && $value == LANGUAGE_NONE) {
+        $value = '';
+      }
+    }
+
+    // Special handling for images and other URLs.
+    if (!empty($this->info['image']) || !empty($this->info['url'])) {
+      // Support multiple items, whether it's needed or not. Also remove the
+      // empty values.
+      $values = array_filter(explode(',', $value));
+
+      // If this meta tag does *not* allow multiple items, only keep the first
+      // one.
+      if (empty($this->info['multiple']) && !empty($values[0])) {
+        $values = array($values[0]);
+      }
+
+      foreach ($values as $key => &$image_value) {
+        // Remove any unwanted whitespace around the value.
+        $image_value = trim($image_value);
+
+        // If this contains embedded image tags, extract the image URLs.
+        if (!empty($this->info['image']) && strip_tags($image_value) != $image_value) {
+          $matches = array();
+          preg_match('/src="([^"]*)"/', $image_value, $matches);
+          if (!empty($matches[1])) {
+            $image_value = $matches[1];
+          }
+        }
+
+        // Convert the URL to an absolute URL.
+        $image_value = $this->convertUrlToAbsolute($image_value);
+
+        // Replace spaces the URL encoded entity to avoid validation problems.
+        $image_value = str_replace(' ', '%20', $image_value);
+      }
+
+      // Combine the multiple values into a single string.
+      $value = implode(',', $values);
+    }
+
+    $value = $this->tidyValue($value);
+
+    // Translate the final output string prior to output. Use the
+    // 'output' i18n_string object type, and pass along the meta tag's
+    // options as the context so it can be handled appropriately.
+    $value = metatag_translate_metatag($value, $this->info['name'], $options, NULL, TRUE);
+
+    return $value;
+  }
+
+}
+
+/**
+ * Link type meta tag controller.
+ */
+class DrupalLinkMetaTag extends DrupalTextMetaTag {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getElement(array $options = array()) {
+    $element = isset($this->info['element']) ? $this->info['element'] : array();
+
+    $value = $this->getValue($options);
+    if (strlen($value) === 0) {
+      return array();
+    }
+
+    $element += array(
+      '#theme' => 'metatag_link_rel',
+      '#tag' => 'link',
+      '#id' => 'metatag_' . $this->info['name'],
+      '#name' => $this->info['name'],
+      '#value' => $value,
+      '#weight' => $this->getWeight(),
+    );
+
+    if (!isset($this->info['header']) || !empty($this->info['header'])) {
+      // Also send the generator in the HTTP header.
+      // @todo This does not support 'rev' or alternate link headers.
+      $element['#attached']['drupal_add_http_header'][] = array('Link', '<' . $value . '>;' . drupal_http_header_attributes(array('rel' => $element['#name'])), TRUE);
+    }
+
+    return array(
+      '#attached' => array('drupal_add_html_head' => array(array($element, $element['#id']))),
+    );
+  }
+
+}
+
+/**
+ * Title meta tag controller.
+ *
+ * This extends DrupalTextMetaTag as we need to alter variables in
+ * template_preprocess_html() rather output a normal meta tag.
+ */
+class DrupalTitleMetaTag extends DrupalTextMetaTag {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getElement(array $options = array()) {
+    $element = array();
+    if ($value = $this->getValue($options)) {
+      $element['#attached']['metatag_set_preprocess_variable'][] = array('html', 'head_title', $value);
+      $element['#attached']['metatag_set_preprocess_variable'][] = array('html', 'head_array', array('title' => $value));
+    }
+    return $element;
+  }
+
+}
+
+/**
+ * Multiple value meta tag controller.
+ */
+class DrupalListMetaTag extends DrupalDefaultMetaTag {
+
+  /**
+   * {@inheritdoc}
+   */
+  function __construct(array $info, array $data = NULL) {
+    // Ensure that the $data['value] argument is an array.
+    if (empty($data['value'])) {
+      $data['value'] = array();
+    }
+    $data['value'] = (array) $data['value'];
+
+    parent::__construct($info, $data);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getForm(array $options = array()) {
+    $form['value'] = isset($this->info['form']) ? $this->info['form'] : array();
+
+    $form['value'] += array(
+      '#type' => 'checkboxes',
+      '#title' => $this->info['label'],
+      '#description' => !empty($this->info['description']) ? $this->info['description'] : '',
+      '#default_value' => isset($this->data['value']) ? $this->data['value'] : array(),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue(array $options = array()) {
+    $values = array_keys(array_filter($this->data['value']));
+    sort($values);
+    $value = implode(', ', $values);
+    $value = $this->tidyValue($value);
+
+    // Translate the final output string prior to output. Use the
+    // 'output' i18n_string object type, and pass along the meta tag's
+    // options as the context so it can be handled appropriately.
+    $value = metatag_translate_metatag($value, $this->info['name'], $options, NULL, TRUE);
+
+    return $value;
+  }
+
+}
+
+/**
+ * Date interval meta tag controller.
+ */
+class DrupalDateIntervalMetaTag extends DrupalDefaultMetaTag {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getForm(array $options = array()) {
+    $form['value'] = array(
+      '#type' => 'textfield',
+      '#title' => t('!title interval', array('!title' => $this->info['label'])),
+      '#default_value' => isset($this->data['value']) ? $this->data['value'] : '',
+      '#element_validate' => array('element_validate_integer_positive'),
+      '#maxlength' => 4,
+      '#description' => isset($this->info['description']) ? $this->info['description'] : '',
+    );
+    $form['period'] = array(
+      '#type' => 'select',
+      '#title' => t('!title interval type', array('!title' => $this->info['label'])),
+      '#default_value' => isset($this->data['period']) ? $this->data['period'] : '',
+      '#options' => array(
+        '' => t('- none -'),
+        'day' => t('Day(s)'),
+        'week' => t('Week(s)'),
+        'month' => t('Month(s)'),
+        'year' => t('Year(s)'),
+      ),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue(array $options = array()) {
+    $value = '';
+    if (!empty($this->data['value'])) {
+      $interval = intval($this->data['value']);
+      if (!empty($interval) && !empty($this->data['period'])) {
+        $period = $this->data['period'];
+        $value = format_plural($interval, '@count ' . $period, '@count ' . $period . 's');
+      }
+    }
+
+    // Translate the final output string prior to output. Use the
+    // 'output' i18n_string object type, and pass along the meta tag's
+    // options as the context so it can be handled appropriately.
+    $value = metatag_translate_metatag($value, $this->info['name'], $options, NULL, TRUE);
+
+    return $value;
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.info b/profiles/wcm_base/modules/contrib/metatag/metatag.info
new file mode 100644
index 0000000000000000000000000000000000000000..bf1da27ff06d599a03921e0e52328f9feba0c5af
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.info
@@ -0,0 +1,113 @@
+name = Metatag
+description = "Adds support and an API to implement meta tags."
+package = SEO
+core = 7.x
+
+; This requires Drupal 7.28 or newer as it fixes the [node:summary] token that
+; was previously broken.
+dependencies[] = drupal:system (>= 7.28)
+
+; CTools is required.
+dependencies[] = ctools:ctools
+
+; Requires Token; v7.x-1.6 is highly recommended due to bugs with certain tags
+; when using older versions.
+dependencies[] = token:token
+
+configure = admin/config/search/metatags
+
+; The main classes.
+files[] = metatag.inc
+
+; Defines the basic meta tags.
+files[] = metatag.migrate.inc
+
+; Search API integration.
+files[] = metatag.search_api.inc
+
+
+; Tests.
+files[] = tests/metatag.helper.test
+
+; Basic configuration handling.
+files[] = tests/metatag.unit.test
+
+; Basic tag testing.
+files[] = tests/metatag.tags_helper.test
+files[] = tests/metatag.tags.test
+
+; Core entities.
+files[] = tests/metatag.node.test
+files[] = tests/metatag.term.test
+files[] = tests/metatag.user.test
+
+; Handling of core's default meta tags.
+files[] = tests/metatag.core_tag_removal.test
+
+; The custom Bulk Revert functionality.
+files[] = tests/metatag.bulk_revert.test
+
+; String handling.
+files[] = tests/metatag.string_handling.test
+files[] = tests/metatag.string_handling_with_i18n.test
+
+; XSS testing.
+files[] = tests/metatag.xss.test
+
+; Output caching.
+files[] = tests/metatag.output_caching.test
+
+; Images need specia attention.
+test_dependencies[] = devel:devel
+test_dependencies[] = imagecache_token:imagecache_token
+files[] = tests/metatag.image.test
+
+; Internationalization & translation.
+test_dependencies[] = entity_translation:entity_translation
+test_dependencies[] = i18n:i18n
+files[] = tests/metatag.locale.test
+files[] = tests/metatag.node.with_i18n.test
+files[] = tests/metatag.term.with_i18n.test
+files[] = tests/metatag.with_i18n_output.test
+files[] = tests/metatag.with_i18n_disabled.test
+files[] = tests/metatag.with_i18n_config.test
+
+; Basic integration with Me.
+test_dependencies[] = me:me
+files[] = tests/metatag.with_me.test
+
+; Basic integration with Media.
+test_dependencies[] = file_entity:file_entity
+test_dependencies[] = media:media (>= 2.0, < 3.0)
+files[] = tests/metatag.with_media.test
+
+; Basic integration with Panels.
+test_dependencies[] = panels:panels
+files[] = tests/metatag.with_panels.test
+
+; Basic integration with Profile2.
+test_dependencies[] = profile2:profile2
+files[] = tests/metatag.with_profile2.test
+
+; Basic integration with Search API.
+test_dependencies[] = entity:entity
+test_dependencies[] = search_api:search_api
+files[] = tests/metatag.with_search_api.test
+
+; Integration with Workbench Moderation.
+test_dependencies[] = workbench_moderation:workbench_moderation
+files[] = tests/metatag.with_workbench_moderation.test
+
+; Basic integration with Views.
+test_dependencies[] = views:views
+files[] = tests/metatag.with_views.test
+
+; Other test dependencies.
+test_dependencies[] = context:context
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.install b/profiles/wcm_base/modules/contrib/metatag/metatag.install
new file mode 100644
index 0000000000000000000000000000000000000000..7e969d2fdff864d9cb65fd22354b435c76e22d10
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.install
@@ -0,0 +1,2585 @@
+<?php
+/**
+ * @file
+ * Install, update, and uninstall functions for the metatag module.
+ */
+
+/**
+ * Implements hook_requirements().
+ */
+function metatag_requirements($phase) {
+  $requirements = array();
+  // Ensure translations don't break during installation.
+  $t = get_t();
+
+  if ($phase == 'install') {
+    // Handle scenarios where the site had the legacy "metatags" module
+    // installed but then had Metatag installed on top of it.
+    if (function_exists('db_table_exists') && function_exists('db_field_exists') && function_exists('db_query') && Database::isActiveConnection()) {
+      // Check if the primary table already exists.
+      if (db_table_exists('metatag')) {
+        // Check to see if all of the fields exist in the table. If one of the
+        // fields does not exist, proceed with the fix.
+        $fields = array(
+          'entity_type',
+          'entity_id',
+          'revision_id',
+          'language',
+          'data',
+        );
+        foreach ($fields as $field) {
+          // This field doesn't exist, so determine what to do.
+          if (!db_field_exists('metatag', $field)) {
+            // The table contains data, so rename it.
+            if (db_query("SELECT COUNT(*) FROM {metatag}")->fetchField() > 0) {
+              db_query("RENAME TABLE {metatag} TO {metatag}_legacy");
+              $message = 'An out-of-date version of the {metatag} table was discovered. As the table contained data it was renamed with a suffix of "_legacy". This will not prevent installation from continuing, but will need to be dealt with later. See <a href="https://www.drupal.org/node/1391554">https://www.drupal.org/node/1391554</a> for further details.';
+            }
+            // The table is empty, so delete it.
+            else {
+              db_query("DROP TABLE {metatag}");
+              $message = 'An out-of-date version of the {metatag} table was discovered. As the table was empty it was simply removed so that it could be recreated in the correct format. Installation may now proceed. See <a href="https://www.drupal.org/node/1391554">https://www.drupal.org/node/1391554</a> for further details.';
+            }
+            $requirements['metatag'] = array(
+              'severity' => REQUIREMENT_WARNING,
+              'title' => 'Metatag',
+              'value' => $t('Legacy data discovered.'),
+              'description' => $t($message),
+            );
+            drupal_set_message($t($message), 'warning');
+            break;
+          }
+        }
+      }
+    }
+  }
+  elseif ($phase == 'runtime') {
+    // Complete data dump of all installed modules, used later.
+    $module_data = system_rebuild_module_data();
+
+    // Work out the release of D7 that is currently running.
+    list($major, $minor) = explode('.', VERSION);
+    // Strip off any suffixes on the version string, e.g. "17-dev".
+    if (strpos('-', $minor)) {
+      list($minor, $suffix) = explode('-', $minor);
+    }
+
+    // Releases of Drupal older than 7.28 did not have entity_language(), which
+    // is now required, and had a broken [node:summary] token.
+    if ($minor < 28) {
+      $requirements['metatag'] = array(
+        'severity' => REQUIREMENT_WARNING,
+        'title' => 'Metatag',
+        'value' => $t('Upgrade Drupal core to v7.28 or newer'),
+        'description' => $t("This older version of Drupal core is missing functionality necessary for the module's multilingual support and contains a broken [node:summary] token, it must be upgraded to version 7.28 or newer."),
+      );
+    }
+
+    // Add a note if Page Title is also installed.
+    if (module_exists('page_title')) {
+      $requirements['metatag_page_title'] = array(
+        'severity' => REQUIREMENT_WARNING,
+        'title' => 'Metatag',
+        'value' => $t('Page Title module should be removed'),
+        'description' => $t('The Metatag module is able to customize page titles, so running the Page Title module simultaneously can lead to complications. Please follow the instructions to <a href="@page">convert the Page Title settings</a> and uninstall the module.', array('@page' => 'https://www.drupal.org/node/2774833')),
+      );
+    }
+
+    // Add a note if the deprecated metatag.entity_translation.inc file still
+    // exists.
+    $filename = 'metatag.entity_translation.inc';
+    if (file_exists(dirname(__FILE__) . '/' . $filename)) {
+      $requirements['metatag_deprecated_et_file'] = array(
+        'severity' => REQUIREMENT_ERROR,
+        'title' => 'Metatag',
+        'value' => $t('Unwanted :filename file found', array(':filename' => $filename)),
+        'description' => $t("The :filename file was removed in v7.x-1.0-beta5 but it still exists in the site's Metatag module's directory and will cause problems. This file needs to be removed. The file's path in the Drupal directory structure is:<br /><code>!short_path</code><br />The file's full path is:<br /><code>!full_path</code>", array(':filename' => $filename, '!short_path' => drupal_get_path('module', 'metatag') . '/' . $filename, '!full_path' => dirname(__FILE__) . $filename)),
+      );
+    }
+
+    // Check that Entity_Translation is current.
+    if (module_exists('entity_translation')
+      && !empty($module_data['entity_translation'])
+      && !empty($module_data['entity_translation']->schema_version)
+      && $module_data['entity_translation']->schema_version < 7004) {
+      $requirements['metatag_et_version'] = array(
+        'severity' => REQUIREMENT_ERROR,
+        'title' => 'Metatag',
+        'value' => $t('<a href="@url">Entity_Translation</a> is out of date and requires updating', array('@url' => 'https://www.drupal.org/project/entity_translation')),
+        'description' => $t('The Entity_Translation module is out of date and needs to be updated in order to be compatible with Metatag.'),
+      );
+    }
+
+    // It's recommended to install the Transliteration module to clean up file
+    // paths for use with image meta tags.
+    if (!module_exists('transliteration')) {
+      $requirements['metatag_transliteration'] = array(
+        'severity' => REQUIREMENT_INFO,
+        'title' => 'Metatag',
+        'value' => $t('The Transliteration module is recommended.'),
+        'description' => $t("It is recommended to install the <a href=\"@url\">Transliteration module</a> to clean up filenames of uploaded files that may be used with image meta tags.", array('@url' => 'https://drupal.org/project/transliteration')),
+      );
+    }
+
+    // It's recommended to install the Imagecache Token module to make image
+    // tokens easier to do.
+    if (!module_exists('imagecache_token')) {
+      $requirements['metatag_imagecache_token'] = array(
+        'severity' => REQUIREMENT_INFO,
+        'title' => 'Metatag',
+        'value' => $t('The Imagecache Token module is recommended.'),
+        'description' => $t("It is recommended to install the <a href=\"@url\">Imagecache Token module</a> to make it easier to control image meta tags, e.g. og:image. See the Metatag module's README.txt for details.", array('@url' => 'https://drupal.org/project/imagecache_token')),
+      );
+    }
+
+    // The Admin Language module can cause problems.
+    if (module_exists('admin_language') && variable_get('admin_language_force_neutral', 0)) {
+      $requirements['metatag_admin_language'] = array(
+        'severity' => REQUIREMENT_WARNING,
+        'title' => 'Metatag',
+        'value' => $t('Conflict with Admin Language module.'),
+        'description' => $t("Using the \"@option\" with Metatag can lead to data loss, so it is recommended to <a href=\"@url\">disable that option</a>.", array('@option' => t('Force language neutral aliases'), '@url' => url('admin/config/regional/language/admin_language'))),
+      );
+    }
+
+    // Token v7.x-1.6 is *highly* recommended.
+    $token_module = $module_data['token'];
+    // If the version string is not present then it means the module is running
+    // from git, which means it can't be compared against. Alternatively, look
+    // for the test file, which was the last commit of the 1.6 release.
+    if (!empty($token_module->info['version'])
+      || empty($token_module->info['files'])) {
+      // If there's no test file then this is older than v1.6.
+      if (empty($token_module->info['files'])) {
+        $minor = 5;
+      }
+      // Otherwise check the version string.
+      else {
+        // Versions are in the format 7.x-1.y, so split the string up to find
+        // the 'y' portion.
+        $version = explode('-', $token_module->info['version']);
+        if (isset($version[1])) {
+          list($major, $minor) = explode('.', $version[1]);
+          // Strip off any suffixes on the version string, e.g. "17-dev".
+          if (strpos('-', $minor)) {
+            list($minor, $suffix) = explode('-', $minor);
+          }
+        }
+        // If the version string couldn't be extracted correctly, assume that
+        // an incorrect version is installed.
+        else {
+          $minor = 0;
+        }
+      }
+      // If v1.6 is not installed, give a warning.
+      if ($minor < 6) {
+        $requirements['metatag_token_version'] = array(
+          'severity' => REQUIREMENT_WARNING,
+          'title' => 'Metatag',
+          'value' => $t('Token module is out of date.'),
+          'description' => $t('It is highly recommended to install <a href="https://www.drupal.org/project/token">Token module</a> v7.x-1.6 or newer, otherwise there may be problems using certain meta tags.'),
+        );
+      }
+    }
+
+    // If Workbench Moderation is installed, show a message if it is out of
+    // date.
+    if (module_exists('workbench_moderation')) {
+      $wm_module = $module_data['workbench_moderation'];
+      // If the version string is not present then it means the module is
+      // running from git, which means it can't be compared against.
+      if (!empty($wm_module->info['version'])) {
+        // Versions are in the format 7.x-1.y, so split the string up to find
+        // the 'y' portion.
+        $version = explode('-', $wm_module->info['version']);
+        if (isset($version[1])) {
+          list($major, $minor) = explode('.', $version[1]);
+        }
+        // If the version string couldn't be extracted correctly, assume that
+        // an incorrect version is installed.
+        else {
+          $major = 0;
+        }
+      }
+      // If v3.x is not installed, give a message.
+      if ($major < 3) {
+        $requirements['metatag_wm_version'] = array(
+          'severity' => REQUIREMENT_INFO,
+          'title' => 'Metatag',
+          'value' => $t('Workbench Moderation module is out of date.'),
+          'description' => $t('It is recommended to use <a href="https://www.drupal.org/project/workbench_moderation">Workbench Moderation module</a> v7.x-3.0 or newer.'),
+        );
+      }
+    }
+  }
+
+  return $requirements;
+}
+
+/**
+ * Implements hook_schema().
+ */
+function metatag_schema() {
+  $schema['metatag_config'] = array(
+    'description' => 'Storage of meta tag configuration and defaults.',
+    'export' => array(
+      'key' => 'instance',
+      'key name' => 'Instance',
+      'primary key' => 'cid',
+      'identifier' => 'config',
+      'default hook' => 'metatag_config_default',
+      'api' => array(
+        'owner' => 'metatag',
+        'api' => 'metatag',
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+      'cache defaults' => TRUE,
+      'default cache bin' => 'cache_metatag',
+    ),
+    'fields' => array(
+      'cid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The primary identifier for a metatag configuration set.',
+        'no export' => TRUE,
+      ),
+      'instance' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The machine-name of the configuration, typically entity-type:bundle.',
+      ),
+      'config' => array(
+        'type' => 'blob',
+        'size' => 'big',
+        'not null' => TRUE,
+        'serialize' => TRUE,
+        'description' => 'Serialized data containing the meta tag configuration.',
+        'translatable' => TRUE,
+      ),
+    ),
+    'primary key' => array('cid'),
+    'unique keys' => array(
+      'instance' => array('instance'),
+    ),
+  );
+
+  $schema['metatag'] = array(
+    'fields' => array(
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The entity type this data is attached to.',
+      ),
+      'entity_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The entity id this data is attached to.',
+      ),
+      'revision_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The revision_id for the entity object this data is attached to.',
+      ),
+      'language' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The language of the tag.',
+      ),
+      'data' => array(
+        'type' => 'blob',
+        'size' => 'big',
+        'not null' => TRUE,
+        'serialize' => TRUE,
+      ),
+    ),
+    'indexes' => array(
+      'type_revision' => array(
+        'entity_type',
+        'revision_id',
+      ),
+    ),
+    'primary key' => array(
+      'entity_type',
+      'entity_id',
+      'revision_id',
+      'language',
+    ),
+  );
+
+  $schema['cache_metatag'] = drupal_get_schema_unprocessed('system', 'cache');
+  $schema['cache_metatag']['description'] = 'Cache table for the generated meta tag output.';
+
+  return $schema;
+}
+
+/**
+ * Implements hook_install().
+ */
+function metatag_install() {
+  drupal_set_message(t("Thank you for installing the Metatag module. It is recommended to read the module's <a href=\"!url\" title=\"Read the Metatag module's documentation\">README.txt</a> file as there are some known issues that may affect this site.", array('!url' => url(drupal_get_path('module', 'metatag') . '/README.txt'))));
+
+  // Always enable the node, taxonomy term and user entities.
+  foreach (array('node', 'taxonomy_term', 'user') as $entity_type) {
+    // Enable the main entity type.
+    $variable_name = 'metatag_enable_' . $entity_type;
+    variable_set($variable_name, TRUE);
+
+    // Update each entity bundle too.
+    $entity_info = entity_get_info($entity_type);
+    if (!empty($entity_info['bundles'])) {
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+        $variable_name = 'metatag_enable_' . $entity_type . '__' . $bundle_name;
+        variable_set($variable_name, TRUE);
+      }
+    }
+  }
+
+  // Possibly enable other entities, if they're specifically requested.
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    // Skip the three entity types that were already enabled.
+    if (in_array($entity_type, array('node', 'taxonomy_term', 'user'))) {
+      continue;
+    }
+
+    $variable_name = 'metatag_enable_' . $entity_type;
+
+    // Configuration entities are skipped.
+    if (isset($entity_info['configuration']) && $entity_info['configuration'] == TRUE) {
+      continue;
+    }
+
+    // Entities must have bundles.
+    if (empty($entity_info['bundles'])) {
+      continue;
+    }
+
+    // Entities must be fieldable.
+    elseif (empty($entity_info['fieldable'])) {
+      continue;
+    }
+
+    // Ignore some view modes that are automatically added by certain modules.
+    unset($entity_info['view modes']['ical']);
+    unset($entity_info['view modes']['diff_standard']);
+    unset($entity_info['view modes']['token']);
+
+    // Entities without view modes are skipped.
+    if (empty($entity_info['view modes'])) {
+      continue;
+    }
+
+    // At this point, disable the entity by default.
+    $entity_enabled = FALSE;
+
+    // Anything that was specifically enabled via hook_entity_info() from older
+    // versions will be enabled if not configured already.
+    if (!empty($entity_info['metatag']) || !empty($entity_info['metatags'])) {
+      $entity_enabled = variable_get($variable_name, 'monkey');
+      if ($entity_enabled === 'monkey') {
+        $entity_enabled = TRUE;
+      }
+    }
+
+    variable_set($variable_name, $entity_enabled);
+
+    // Loop through the bundles, but only if the entity is enabled.
+    if ($entity_enabled) {
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+        $variable_name = 'metatag_enable_' . $entity_type . '__' . $bundle_name;
+
+        // If it wasn't specifically disabled before, enable it.
+        $bundle_enabled = variable_get($variable_name, 'monkey');
+        if ($bundle_name != FALSE) {
+          variable_set($variable_name, TRUE);
+        }
+      }
+    }
+  }
+
+  drupal_set_message(t('It may be worth verifying on the <a href="@url">Settings page</a> which types of content on the site should allow meta tags.', array('@url' => url('admin/config/search/metatags/settings'))));
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function metatag_uninstall() {
+  // This variable is created via hook_enable.
+  variable_del('metatag_schema_installed');
+  // Used to control whether 403/404 pages are cached.
+  variable_del('metatag_cache_error_pages');
+  // Used to make meta tags display on admin pages.
+  variable_del('metatag_tag_admin_pages');
+
+  // Temp variables, just in case they weren't removed already.
+  variable_del('metatag_skip_update_7017');
+
+  // Used to note that the schema for the main {metatag} table were sufficiently
+  // updated.
+  variable_del('metatag_has_revision_id');
+
+  // Used to force an entity's default language values to be used if nothing
+  // else matched.
+  variable_del('metatag_entity_no_lang_default');
+
+  // Controls which page region is used to trigger output of the meta tags.
+  variable_del('metatag_page_region');
+
+  // Optionally disable the default configurations.
+  variable_del('metatag_load_defaults');
+
+  // Optionally disables the output cache.
+  variable_del('metatag_cache_output');
+
+  // Customizable pager string.
+  variable_del('metatag_pager_string');
+
+  // Optionally enable translations of final output.
+  variable_del('metatag_i18n_translate_output');
+
+  // Optionally enable the automatic watchdog logging of i18n strings.
+  variable_del('metatag_i18n_enable_watchdog');
+
+  // Optionally disable the i18n integration.
+  variable_del('metatag_i18n_disabled');
+
+  // Optionally output core's meta tags.
+  variable_del('metatag_leave_core_tags');
+
+  // Optionally enable individual permissions for each meta tag.
+  variable_del('metatag_extended_permissions');
+
+  // Optionally load meta tags on admin pages.
+  variable_del('metatag_load_all_pages');
+
+  // Sanitize token replacement output.
+  variable_del('metatag_token_sanitize');
+
+  // Remove all possible 'enable' variables.
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    variable_del('metatag_enable_' . $entity_type);
+    if (!empty($entity_info['bundles'])) {
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+        variable_del('metatag_enable_' . $entity_type . '__' . $bundle_name);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_enable().
+ */
+function metatag_enable() {
+  variable_set('metatag_schema_installed', TRUE);
+}
+
+/**
+ * Replace one meta tag's with another in the entity records.
+ *
+ * @param array $sandbox
+ *   A Batch API sandbox, passed by reference.
+ * @param string $old_tag
+ *   The meta tag that is to be replaced.
+ * @param string $new_tag
+ *   The meta tag that replaces the old one.
+ */
+function metatag_update_replace_entity_tag(&$sandbox, $old_tag, $new_tag) {
+  if (!isset($sandbox['progress'])) {
+    // Count of all {metatag} records that contained an entry for the old meta
+    // tag.
+    $records_count = db_select('metatag', 'm')
+      ->condition('m.data', '%' . db_like('"' . $old_tag . '"') . '%', 'LIKE')
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+
+    if (empty($records_count)) {
+      return t('No Metatag entity records needed to have the "@tag" meta tag renamed.', array('@tag' => $old_tag));
+    }
+
+    $sandbox['max'] = $records_count;
+    $sandbox['progress'] = 0;
+  }
+
+  // Count of rows that will be processed per iteration.
+  $limit = 100;
+
+  // Fetches a part of records.
+  $records = db_select('metatag', 'm')
+    ->fields('m', array())
+    ->condition('m.data', '%' . db_like('"' . $old_tag . '"') . '%', 'LIKE')
+    ->range(0, $limit)
+    ->execute();
+
+  $count = 0;
+  $keys = array('entity_type', 'entity_id', 'revision_id', 'language');
+
+  // Loop over the values and correct them.
+  foreach ($records as $record) {
+    $record->data = unserialize($record->data);
+
+    if (isset($record->data[$old_tag])) {
+      $record->data[$new_tag] = $record->data[$old_tag];
+      unset($record->data[$old_tag]);
+      drupal_write_record('metatag', $record, $keys);
+
+      // Clear the cache for the entity this belongs to.
+      entity_get_controller($record->entity_type)->resetCache(array($record->entity_id));
+    }
+
+    $count++;
+  }
+
+  if (!empty($count)) {
+    $sandbox['progress'] += $count;
+    // In some cases the query yields results that cannot be fixed and we would
+    // run into an infinite loop. Stop immediately if we processed all records.
+    if ($sandbox['progress'] >= $sandbox['max']) {
+      $sandbox['#finished'] = TRUE;
+    }
+    else {
+      $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+    }
+  }
+  else {
+    $sandbox['#finished'] = TRUE;
+    return t('Converted the "@old_tag" meta tag for @count entity records to "@new_tag" meta tag.', array('@old_tag' => $old_tag, '@new_tag' => $new_tag, '@count' => $sandbox['progress']));
+  }
+}
+
+/**
+ * Replace one meta tag's value in the entity records.
+ *
+ * @param array $sandbox
+ *   A Batch API sandbox, passed by reference.
+ * @param string $meta_tag
+ *   The meta tag that needs its value replaced.
+ * @param string $old_value
+ *   The meta tag value that is to be replaced.
+ * @param string $new_value
+ *   The meta tag value that replaces the old one.
+ */
+function metatag_update_replace_entity_value(&$sandbox, $meta_tag, $old_value, $new_value) {
+  // The condition used for both queries.
+  $db_and = db_and();
+  $db_and->condition('m.data', '%' . db_like('"' . $meta_tag . '"') . '%', 'LIKE');
+  $db_and->condition('m.data', '%' . db_like('"' . $old_value . '"') . '%', 'LIKE');
+
+  if (!isset($sandbox['progress'])) {
+    // Count of all {metatag} records that contained an entry for the old meta
+    // tag value
+    $records_count = db_select('metatag', 'm')
+      ->condition($db_and)
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+
+    if (empty($records_count)) {
+      return t('No Metatag entity records needed to have the "@tag" meta tag "@old_value" value replaced.', array('@tag' => $meta_tag, '@old_value' => $old_value));
+    }
+
+    $sandbox['max'] = $records_count;
+    $sandbox['progress'] = 0;
+
+    // Keep track of the number of replaced values separately.
+    $sandbox['count'] = 0;
+  }
+
+  // Count of rows that will be processed per iteration.
+  $limit = 100;
+
+  // Fetches a part of records.
+  $records = db_select('metatag', 'm')
+    ->fields('m', array())
+    ->condition($db_and)
+    ->range(0, $limit)
+    ->execute();
+
+  $count = 0;
+  $keys = array('entity_type', 'entity_id', 'revision_id', 'language');
+
+  // Loop over the values and correct them.
+  foreach ($records as $record) {
+    $record->data = unserialize($record->data);
+
+    if (isset($record->data[$meta_tag])) {
+      $record->data[$meta_tag]['value'] = str_replace($old_value, $new_value, $record->data[$meta_tag]['value']);
+      drupal_write_record('metatag', $record, $keys);
+
+      // Clear the cache for the entity this belongs to.
+      entity_get_controller($record->entity_type)->resetCache(array($record->entity_id));
+
+      $sandbox['count']++;
+    }
+
+    $sandbox['progress']++;
+  }
+
+  if (!empty($count)) {
+    // In some cases the query yields results that cannot be fixed and we would
+    // run into an infinite loop. Stop immediately if we processed all records.
+    if ($sandbox['progress'] >= $sandbox['max']) {
+      $sandbox['#finished'] = TRUE;
+    }
+    else {
+      $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+    }
+  }
+  else {
+    $sandbox['#finished'] = TRUE;
+    return t('Replaced the value of @count entity records for the "@meta_tag" meta tag.', array('@meta_tag' => $meta_tag, '@count' => $sandbox['count']));
+  }
+}
+
+/**
+ * Replace one meta tag with another in the configs.
+ *
+ * @param string $old_tag
+ *   The meta tag that is to be replaced.
+ * @param string $new_tag
+ *   The meta tag that replaces the old one.
+ */
+function metatag_update_replace_config_tag($old_tag, $new_tag) {
+  // Find all {metatag_config} records that contained an entry for the old meta
+  // tag.
+  $records = db_select('metatag_config', 'm')
+    ->fields('m', array('cid', 'config'))
+    ->condition('m.config', '%' . db_like('"' . $old_tag . '"') . '%', 'LIKE')
+    ->execute();
+  // This message will be returned if nothing needed to be updated.
+  $none_message = t('No Metatag configuration records needed to have the "@tag" meta tag fixed. That said, there may be other configurations elsewhere that do need updating.', array('@tag' => $old_tag));
+
+  // Loop over the values and correct them.
+  if ($records->rowCount() == 0) {
+    $message = $none_message;
+  }
+  else {
+    $keys = array('cid');
+
+    // Loop over the values and correct them.
+    $counter = 0;
+    foreach ($records as $record) {
+      $record->config = unserialize($record->config);
+      if (isset($record->config[$old_tag])) {
+        $record->config[$new_tag] = $record->config[$old_tag];
+        unset($record->config[$old_tag]);
+        drupal_write_record('metatag_config', $record, $keys);
+        $counter++;
+      }
+    }
+    if ($counter == 0) {
+      $message = $none_message;
+    }
+    else {
+      $message = t('Converted the "@old_tag" meta tag for @count configurations to the new "@new_tag" meta tag.', array('@old_tag' => $old_tag, '@new_tag' => $new_tag, '@count' => $counter));
+    }
+  }
+
+  // Clear all Metatag caches.
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  drupal_static_reset('metatag_config_load_with_defaults');
+  drupal_static_reset('metatag_entity_supports_metatags');
+  drupal_static_reset('metatag_config_instance_info');
+  drupal_static_reset('metatag_get_info');
+  ctools_include('export');
+  ctools_export_load_object_reset('metatag_config');
+
+  return $message;
+}
+
+/**
+ * Replace one meta tag with another in the configs.
+ *
+ * @param string $meta_tag
+ *   The meta tag that needs its value replaced.
+ * @param string $old_value
+ *   The meta tag value that is to be replaced.
+ * @param string $new_value
+ *   The meta tag value that replaces the old one.
+ */
+function metatag_update_replace_config_value($meta_tag, $old_value, $new_value) {
+  // Find all {metatag_config} records that contained an entry for the old meta
+  // tag.
+  $db_and = db_and();
+  $db_and->condition('m.config', '%' . db_like('"' . $meta_tag . '"') . '%', 'LIKE');
+  $db_and->condition('m.config', '%' . db_like('"' . $old_value . '"') . '%', 'LIKE');
+  $records = db_select('metatag_config', 'm')
+    ->fields('m', array('cid', 'config'))
+    ->condition($db_and)
+    ->execute();
+  // This message will be returned if nothing needed to be updated.
+  $none_message = t('No Metatag configuration records needed to have the "@tag" meta tag values updated. That said, there may be other configurations elsewhere that do need updating.', array('@tag' => $meta_tag));
+
+  // Loop over the values and correct them.
+  if ($records->rowCount() == 0) {
+    $message = $none_message;
+  }
+  else {
+    $keys = array('cid');
+
+    // Loop over the values and correct them.
+    $counter = 0;
+    foreach ($records as $record) {
+      $record->config = unserialize($record->config);
+      if (isset($record->config[$meta_tag])) {
+        $record->config[$meta_tag]['value'] = str_replace($old_value, $new_value, $record->config[$meta_tag]['value']);
+        drupal_write_record('metatag_config', $record, $keys);
+        $counter++;
+      }
+    }
+    if ($counter == 0) {
+      $message = $none_message;
+    }
+    else {
+      $message = t('Replaced the value of @count entity records for the "@meta_tag" meta tag.', array('@meta_tag' => $meta_tag, '@count' => $counter));
+    }
+  }
+
+  // Clear all Metatag caches.
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  drupal_static_reset('metatag_config_load_with_defaults');
+  drupal_static_reset('metatag_entity_supports_metatags');
+  drupal_static_reset('metatag_config_instance_info');
+  drupal_static_reset('metatag_get_info');
+  ctools_include('export');
+  ctools_export_load_object_reset('metatag_config');
+
+  return $message;
+}
+
+/**
+ * Remove a specific meta tag from all configs.
+ *
+ * @param string $$tag_name
+ *   The meta tag that is to be removed.
+ */
+function metatag_update_delete_config($tag_name) {
+  // Find all {metatag_config} records that contained an entry for the meta tag.
+  $records = db_select('metatag_config', 'm')
+    ->fields('m', array('cid', 'config'))
+    ->condition('m.config', '%' . db_like('"' . $tag_name . '"') . '%', 'LIKE')
+    ->execute();
+  // This message will be returned if nothing needed to be updated.
+  $none_message = t('No Metatag configuration records needed to have the "@tag" meta tag removed.', array('@tag' => $tag_name));
+
+  // Loop over the values and correct them.
+  if ($records->rowCount() == 0) {
+    drupal_set_message($none_message);
+  }
+  else {
+    // Loop over the values and correct them.
+    $counter = 0;
+    foreach ($records as $record) {
+      $record->config = unserialize($record->config);
+      if (isset($record->config[$tag_name])) {
+        unset($record->config[$tag_name]);
+        drupal_write_record('metatag_config', $record, array('cid'));
+        $counter++;
+      }
+    }
+    if ($counter == 0) {
+      drupal_set_message($none_message);
+    }
+    else {
+      drupal_set_message(t('Removed the "@tag" meta tag for @count configurations.', array('@tag' => $tag_name, '@count' => $counter)));
+    }
+  }
+
+  // Clear all Metatag caches.
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  drupal_static_reset('metatag_config_load_with_defaults');
+  drupal_static_reset('metatag_entity_supports_metatags');
+  drupal_static_reset('metatag_config_instance_info');
+  drupal_static_reset('metatag_get_info');
+  ctools_include('export');
+  ctools_export_load_object_reset('metatag_config');
+}
+
+/**
+ * Disable the deprecated metatag_ui module, which has been merged into metatag.
+ */
+function metatag_update_7000() {
+  if (module_exists('metatag_ui')) {
+    module_disable(array('metatag_ui'), FALSE);
+    drupal_uninstall_modules(array('metatag_ui'), FALSE);
+  }
+}
+
+/**
+ * Fix the "{metatag_config}.cid column cannot be NULL" error.
+ */
+function metatag_update_7001() {
+  $table_name = 'metatag_config';
+  $field_name = 'cid';
+  $field_spec = array(
+    'type' => 'serial',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'description' => 'The primary identifier for a metatag configuration set.',
+  );
+  $keys = array('primary key' => array($field_name));
+
+  // Before making any changes, drop the existing primary key.
+  // Let's add a temporary unique key for cid so MySQL will let it go.
+  // Hint taken from https://drupal.org/node/2064305#comment-7753197.
+  db_add_unique_key($table_name, 'temp_key', array($field_name, 'instance'));
+
+  // Unforunately there is no API way to check if a primary key exists, so if
+  // it doesn't exist the db_drop_primary_key() call will fail.
+  try {
+    db_drop_primary_key($table_name);
+  }
+  catch (Exception $e) {
+    drupal_set_message('Caught an exception: ', $e->getMessage());
+  }
+
+  // Rejig the field, and turn on the primary key again.
+  db_change_field($table_name, $field_name, $field_name, $field_spec, $keys);
+
+  // Finally, remove the temporary unique key because it's no longer useful.
+  db_drop_unique_key($table_name, 'temp_key');
+}
+
+/**
+ * Disable the deprecated metatag_ui module which has been merged into metatag,
+ * again.
+ */
+function metatag_update_7002() {
+  if (module_exists('metatag_ui')) {
+    module_disable(array('metatag_ui'), FALSE);
+    drupal_uninstall_modules(array('metatag_ui'), FALSE);
+    drupal_set_message(t('The deprecated Metatag UI module has been disabled.'));
+  }
+}
+
+/**
+ * Add the {metatag}.language field.
+ */
+function metatag_update_7003() {
+  // Set the target table and field name.
+  $table_name = 'metatag';
+  $field_name = 'language';
+
+  // Don't add the new field if it already exists.
+  if (!db_field_exists($table_name, $field_name)) {
+    // Describe the new field.
+    $field_spec = array(
+      'type' => 'varchar',
+      'length' => 32,
+      'not null' => TRUE,
+      'default' => '',
+      'description' => 'The language of the tag',
+    );
+
+    // Add it and update the primary key.
+    db_add_field($table_name, $field_name, $field_spec);
+    db_drop_primary_key($table_name);
+    db_add_primary_key($table_name, array('entity_type', 'entity_id', 'language'));
+  }
+}
+
+/**
+ * Replaced by updates 7009, 7010, 7011, 7012 and 7013.
+ */
+function metatag_update_7004() {
+  // Do nothing.
+}
+
+/**
+ * Removing wrong metatag watchdog entries that break the admin/reports/dblog
+ * page.
+ */
+function metatag_update_7005() {
+  if (db_table_exists('watchdog')) {
+    db_delete('watchdog')
+      ->condition('type', 'metatag')
+      ->condition('variables', serialize('info'))
+      ->execute();
+  }
+}
+
+/**
+ * Remove {metatag} records that were added by old versions of the module for
+ * entities that don't actually support Metatag. A more complete version of
+ * this will be added later on after it's (hopefully) guaranteed that all
+ * modules have updated to the correct API usage.
+ */
+function metatag_update_7006() {
+  $entity_types = array(
+    // Core.
+    'comment',
+    'menu_link',
+    'taxonomy_vocabulary',
+    // Some contrib entities.
+    'mailchimp_list',
+    'profile2',
+    'profile2_type',
+    'redirect',
+    'rules_config',
+    'wysiwyg_profile',
+  );
+  foreach ($entity_types as $entity_type) {
+    $num_deleted = db_delete('metatag')
+      ->condition('entity_type', $entity_type)
+      ->execute();
+    if ($num_deleted > 0) {
+      drupal_set_message(t('Removed @count meta tag record(s) for the @type entity type, it does not support meta tags.', array('@count' => $num_deleted, '@type' => $entity_type)));
+    }
+  }
+}
+
+/**
+ * Remove {metatag} records for nodes, users and taxonomy terms that have been
+ * deleted; older versions of Metatag may have failed to purge these.
+ */
+function metatag_update_7007() {
+  $nodes = db_query("SELECT m.entity_id
+    FROM {metatag} m
+    LEFT OUTER JOIN {node} n
+      ON m.entity_id=n.nid
+    WHERE m.entity_type='node'
+      AND n.nid IS NULL")
+    ->fetchCol();
+  if (count($nodes) > 0) {
+    $deleted = db_delete('metatag')
+      ->condition('entity_type', 'node')
+      ->condition('entity_id', $nodes)
+      ->execute();
+    if ($deleted > 0) {
+      drupal_set_message(t('Removed @count meta tag record(s) for nodes that had been purged.', array('@count' => $deleted)));
+    }
+    else {
+      drupal_set_message(t('There were no meta tag records to purge for removed nodes. This is a good thing :)'));
+    }
+  }
+
+  $users = db_query("SELECT m.entity_id
+    FROM {metatag} m
+    LEFT OUTER JOIN {users} u
+      ON m.entity_id=u.uid
+    WHERE m.entity_type='user'
+      AND u.uid IS NULL")
+    ->fetchCol();
+  if (count($users) > 0) {
+    $deleted = db_delete('metatag')
+      ->condition('entity_type', 'user')
+      ->condition('entity_id', $users)
+      ->execute();
+    if ($deleted > 0) {
+      drupal_set_message(t('Removed @count meta tag record(s) for users that had been purged.', array('@count' => $deleted)));
+    }
+    else {
+      drupal_set_message(t('There were no meta tag records to purge for removed users. This is a good thing :)'));
+    }
+  }
+
+  // Only run this if the Taxonomy module is enabled.
+  if (module_exists('taxonomy')) {
+    $terms = db_query("SELECT m.entity_id
+      FROM {metatag} m
+      LEFT OUTER JOIN {taxonomy_term_data} t
+        ON m.entity_id=t.tid
+      WHERE m.entity_type='taxonomy_term'
+        AND t.tid IS NULL")
+      ->fetchCol();
+    if (count($terms) > 0) {
+      $deleted = db_delete('metatag')
+        ->condition('entity_type', 'taxonomy_term')
+        ->condition('entity_id', $terms)
+        ->execute();
+      if ($deleted > 0) {
+        drupal_set_message(t('Removed @count meta tag record(s) for taxonomy terms that had been purged.', array('@count' => $deleted)));
+      }
+      else {
+        drupal_set_message(t('There were no meta tag records to purge for removed taxonomy terms. This is a good thing :)'));
+      }
+    }
+  }
+}
+
+/**
+ * Remove any empty records that may be hanging around from old releases.
+ */
+function metatag_update_7008() {
+  $conditions = db_or()
+    ->isNull('data')
+    ->condition('data', '')
+    ->condition('data', serialize(array()));
+  $deleted = db_delete("metatag")
+    ->condition($conditions)
+    ->execute();
+  if ($deleted > 0) {
+    drupal_set_message(t('Purged @count empty meta tag record(s).', array('@count' => $deleted)));
+  }
+}
+
+/**
+ * Fix {metatag} records for taxonomy terms.
+ */
+function metatag_update_7009() {
+  if (module_exists('taxonomy')) {
+    // Fix the {metatag} table first.
+    metatag_update_7015();
+
+    // Remove duplicates.
+    _metatag_remove_dupes('taxonomy_term');
+  }
+
+  // The taxonomy term entity doesn't support a 'language' option, so reset it
+  // to LANGUAGE_NONE.
+  $result = db_query("UPDATE {metatag} SET language = :language WHERE entity_type='taxonomy_term'", array(':language' => LANGUAGE_NONE));
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Fixed language values for @count taxonomy terms.', array('@count' => $result->rowCount())));
+  }
+}
+
+/**
+ * Fix {metatag} records for users.
+ */
+function metatag_update_7010() {
+  // Fix the {metatag} table first.
+  metatag_update_7015();
+
+  // Remove duplicates.
+  _metatag_remove_dupes('user');
+
+  // Update User values.
+  $result = db_query("UPDATE {metatag} SET language = :language WHERE entity_type='user'", array(':language' => LANGUAGE_NONE));
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Fixed language values for @count user records.', array('@count' => $result->rowCount())));
+  }
+}
+
+/**
+ * Fix {metatag} records for nodes.
+ */
+function metatag_update_7011(&$sandbox) {
+  // Fix the {metatag} table first.
+  metatag_update_7015();
+
+  // Only proceed if Entity_Translation is not enabled as it allows each node
+  // record to have multiple languages available.
+  if (module_exists('entity_translation')) {
+    drupal_set_message(t("Entity Translation is enabled, so node meta tags will not be updated, to avoid accidental dataloss."));
+    return;
+  }
+
+  // Process records by groups of 10 (arbitrary value).
+  // When a group is processed, the batch update engine determines whether it
+  // should continue processing in the same request or provide progress
+  // feedback to the user and wait for the next request.
+  $limit = 10;
+  // When ran through Drush it's Ok to process a larger number of objects at a
+  // time.
+  if (drupal_is_cli()) {
+    $limit = 100;
+  }
+
+  // Use the sandbox at your convenience to store the information needed
+  // to track progression between successive calls to the function.
+  if (!isset($sandbox['progress'])) {
+    // The count of records visited so far.
+    $sandbox['progress'] = 0;
+
+    // Remove duplicates.
+    _metatag_remove_dupes('node');
+
+    // Update Node values.
+    $nodes = db_query("SELECT n.nid, n.language FROM {node} n INNER JOIN {metatag} m ON n.nid = m.entity_id WHERE m.entity_type = 'node' AND n.language != m.language ORDER BY nid");
+    $sandbox['records'] = array();
+    foreach ($nodes as $record) {
+      $sandbox['records'][] = $record;
+    }
+
+    // If there's no data, don't bother with the extra work.
+    if (empty($sandbox['records'])) {
+      watchdog('metatag', 'Update 7011: No nodes need the Metatag language values fixed.', array(), WATCHDOG_INFO);
+      if (drupal_is_cli()) {
+        drupal_set_message(t('Update 7011: No nodes need the Metatag language values fixed.'));
+      }
+      return t('No nodes need the Metatag language values fixed.');
+    }
+
+    // Total records that must be visited.
+    $sandbox['max'] = count($sandbox['records']);
+
+    // A place to store messages during the run.
+    $sandbox['messages'] = array();
+
+    // An initial record of the number of records to be updated.
+    watchdog('metatag', 'Update 7011: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7011: !count records to update.', array('!count' => $sandbox['max'])));
+    }
+
+    // Last record processed.
+    $sandbox['current_record'] = -1;
+
+    // Because a lot of other processing happens on the first iteration, just do
+    // one.
+    $limit = 1;
+  }
+
+  // Set default values.
+  for ($ctr = 0; $ctr < $limit; $ctr++) {
+    $sandbox['current_record']++;
+    if (empty($sandbox['records'][$sandbox['current_record']])) {
+      break;
+    }
+
+    // Shortcuts for later.
+    $langcode = $sandbox['records'][$sandbox['current_record']]->language;
+    $nid = $sandbox['records'][$sandbox['current_record']]->nid;
+
+    db_update('metatag')
+      ->fields(array('language' => $langcode))
+      ->condition('entity_type', 'node')
+      ->condition('entity_id', $nid)
+      ->execute();
+
+    // Update our progress information.
+    $sandbox['progress']++;
+  }
+
+  // Set the "finished" status, to tell batch engine whether this function
+  // needs to run again. If you set a float, this will indicate the progress of
+  // the batch so the progress bar will update.
+  if ($sandbox['progress'] >= $sandbox['max']) {
+    $sandbox['#finished'] = TRUE;
+  }
+  else {
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
+
+  if ($sandbox['#finished']) {
+    // Clear all caches so the fixed data will be reloaded.
+    cache_clear_all('*', 'cache_metatag', TRUE);
+
+    // A final log of the number of records that were converted.
+    watchdog('metatag', 'Update 7011: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7011: !count records were updated.', array('!count' => $sandbox['progress'])));
+    }
+
+    // hook_update_N() may optionally return a string which will be displayed
+    // to the user.
+    return t('Fixed the Metatag language values for @count nodes.', array('@count' => $sandbox['progress']));
+  }
+}
+
+/**
+ * Remove duplicate {metatag} records for non-core entities.
+ */
+function metatag_update_7012() {
+  // Fix the {metatag} table first.
+  metatag_update_7015();
+
+  if (module_exists('entity_translation')) {
+    drupal_set_message(t("Entity Translation is enabled, duplicate meta tags will not be removed for custom entities, to avoid accidental dataloss."));
+    return;
+  }
+
+  $records = db_select('metatag', 'm')
+    ->fields('m', array('entity_type'))
+    ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN')
+    ->orderBy('m.entity_type', 'ASC')
+    ->orderBy('m.entity_id', 'ASC')
+    ->distinct()
+    ->execute();
+
+  $entity_types = array();
+  foreach ($records as $record) {
+    $entity_types[] = $record->entity_type;
+    // Remove duplicates.
+    _metatag_remove_dupes($record->entity_type);
+  }
+
+  if (empty($entity_types)) {
+    drupal_set_message(t('There were no other records to fix.'));
+  }
+}
+
+/**
+ * Fix the {metatag} language value for all non-core entity records. This might
+ * take a while, depending on how much data needs to be converted.
+ */
+function metatag_update_7013(&$sandbox) {
+  // Fix the {metatag} table first.
+  metatag_update_7015();
+
+  if (module_exists('entity_translation')) {
+    drupal_set_message(t("Entity Translation is enabled, meta tags will not be updated for custom entities, to avoid accidental dataloss."));
+    return;
+  }
+
+  // Use the sandbox at your convenience to store the information needed
+  // to track progression between successive calls to the function.
+  if (!isset($sandbox['progress'])) {
+    // The count of records visited so far.
+    $sandbox['progress'] = 0;
+
+    // Because the {metatag} table uses multiple primary keys, there's no easy
+    // way to do this, so we're going to cache all record keys and manually
+    // step through them.
+    $records = db_select('metatag', 'm')
+      ->fields('m', array('entity_type', 'entity_id'))
+      ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN')
+      ->orderBy('m.entity_type', 'ASC')
+      ->orderBy('m.entity_id', 'ASC')
+      ->execute();
+    $sandbox['records'] = array();
+    foreach ($records as $record) {
+      $sandbox['records'][] = $record;
+    }
+
+    // If there's no data, don't bother with the extra work.
+    if (empty($sandbox['records'])) {
+      watchdog('metatag', 'Update 7013: No meta tag records need updating.', array(), WATCHDOG_INFO);
+      if (drupal_is_cli()) {
+        drupal_set_message(t('Update 7013: No meta tag records need updating.'));
+      }
+      return t('No meta tag records need updating.');
+    }
+
+    // Total records that must be visited.
+    $sandbox['max'] = count($sandbox['records']);
+
+    // A place to store messages during the run.
+    $sandbox['messages'] = array();
+
+    // An initial record of the number of records to be updated.
+    watchdog('metatag', 'Update 7013: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7013: !count records to update.', array('!count' => $sandbox['max'])));
+    }
+
+    // Last record processed.
+    $sandbox['current_record'] = -1;
+  }
+
+  // Process records by groups of 10 (arbitrary value).
+  // When a group is processed, the batch update engine determines whether it
+  // should continue processing in the same request or provide progress
+  // feedback to the user and wait for the next request.
+  $limit = 10;
+  // When ran through Drush it's Ok to process a larger number of objects at a
+  // time.
+  if (drupal_is_cli()) {
+    $limit = 100;
+  }
+
+  // Set default values.
+  for ($ctr = 0; $ctr < $limit; $ctr++) {
+    $sandbox['current_record']++;
+    if (empty($sandbox['records'][$sandbox['current_record']])) {
+      break;
+    }
+
+    // Shortcuts for later.
+    $entity_type = $sandbox['records'][$sandbox['current_record']]->entity_type;
+    $entity_id = $sandbox['records'][$sandbox['current_record']]->entity_id;
+
+    // Load the entity.
+    $entities = entity_load($entity_type, array($entity_id));
+    if (!empty($entities)) {
+      $entity = array_pop($entities);
+
+      // Make sure that the entity has a language set.
+      if (!empty($entity)) {
+        // If there's a (non-empty) language value, use it.
+        $new_language = entity_language($entity_type, $entity);
+        if (empty($new_language)) {
+          $new_language = LANGUAGE_NONE;
+        }
+        // Update the 'language' value.
+        db_update('metatag')
+          ->fields(array('language' => $new_language))
+          ->condition('entity_type', $entity_type)
+          ->condition('entity_id', $entity_id)
+          ->execute();
+      }
+    }
+
+    // Update our progress information.
+    $sandbox['progress']++;
+  }
+
+  // Set the "finished" status, to tell batch engine whether this function
+  // needs to run again. If you set a float, this will indicate the progress of
+  // the batch so the progress bar will update.
+  if ($sandbox['progress'] >= $sandbox['max']) {
+    $sandbox['#finished'] = TRUE;
+  }
+  else {
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
+
+  if ($sandbox['#finished']) {
+    // Clear all caches so the fixed data will be reloaded.
+    cache_clear_all('*', 'cache_metatag', TRUE);
+
+    // A final log of the number of records that were converted.
+    watchdog('metatag', 'Update 7013: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7013: !count records were updated.', array('!count' => $sandbox['progress'])));
+    }
+
+    // hook_update_N() may optionally return a string which will be displayed
+    // to the user.
+    return t('!count records were updated in total.', array('!count' => $sandbox['progress']));
+  }
+}
+
+/**
+ * Remove duplicate records for a given entity.
+ *
+ * It should be OK to run this without doing a separate batch process as there
+ * shouldn't be many records that have this problem. Hopefully.
+ *
+ * @param $entity_type
+ *   The name of an entity type to check for.
+ */
+function _metatag_remove_dupes($entity_type) {
+  $purge_count = 0;
+
+  // First step: fix the records. There should not be multiple records for the
+  // same entity_id with different languages.
+  $dupe_records = db_query("SELECT m.entity_id, count(m.language) AS the_count
+    FROM {metatag} m
+    WHERE
+      m.entity_type = :type
+    GROUP BY m.entity_id
+    HAVING count(m.language) > 1", array(':type' => $entity_type));
+
+  if (!empty($dupe_records)) {
+    foreach ($dupe_records as $record) {
+      $entity_id = $record->entity_id;
+      $langs = db_query("SELECT m.entity_id, m.language, m.data FROM {metatag} m WHERE m.entity_type = :type AND m.entity_id = :id", array(':type' => $entity_type, ':id' => $entity_id))->fetchAll();
+
+      // Work out which language record to remove. Will need to store this as
+      // an array incase there are multiple records to purge.
+      $langs_to_remove = array();
+
+      // Check for duplicate records.
+      // Outer loop starts from the beginning.
+      for ($outer = 0; $outer < count($langs); $outer++) {
+        // This record may have been removed already.
+        if (isset($langs[$outer])) {
+          // Inner loop starts from the end.
+          for ($inner = count($langs) - 1; $inner > 0; $inner--) {
+            // Work out if the outer loop's data is the same as the inner
+            // loop's.
+            if (isset($langs[$inner]) && $langs[$outer]->data == $langs[$inner]->data) {
+              // Remove the second record.
+              $langs_to_remove[] = $langs[$inner]->language;
+              unset($langs[$inner]);
+            }
+          }
+        }
+      }
+
+      // Only one record left.
+      if (count($langs) == 1) {
+        // This is how it should be, this record is fine.
+      }
+      // More than one record, work out which one to keep.
+      elseif (count($langs) > 1) {
+        // Work out the entity's language.
+        $entity = entity_load($entity_type, $entity_id);
+        $entity_language = entity_language($entity_type, $entity);
+        if (empty($language)) {
+          $entity_language = LANGUAGE_NONE;
+        }
+
+        // Work out if the entity's language record exists.
+        $lang_pos = NULL;
+        foreach ($langs as $key => $record) {
+          if ($record->language == $entity_language) {
+            $lang_pos = $key;
+            break;
+          }
+        }
+        // If the language record exists, delete the others.
+        if (isset($lang_pos)) {
+          foreach ($langs as $key => $record) {
+            if ($record->language != $entity_language) {
+              $langs_to_remove[] = $record->language;
+            }
+          }
+        }
+        // Otherwise look for a record for the site's default language.
+        else {
+          foreach ($langs as $key => $record) {
+            if ($record->language == $GLOBALS['language']->language) {
+              $lang_pos = $key;
+              break;
+            }
+          }
+          if (isset($lang_pos)) {
+            foreach ($langs as $key => $record) {
+              if ($record->language != $GLOBALS['language']->language) {
+                $langs_to_remove[] = $record->language;
+              }
+            }
+          }
+          // Finally check for LANGUAGE_NONE.
+          else {
+            foreach ($langs as $key => $record) {
+              if ($record->language == LANGUAGE_NONE) {
+                $lang_pos = $key;
+                break;
+              }
+            }
+            if (isset($lang_pos)) {
+              foreach ($langs as $key => $record) {
+                if ($record->language != LANGUAGE_NONE) {
+                  $langs_to_remove[] = $record->language;
+                }
+              }
+            }
+          }
+        }
+      }
+
+      // Purge the redundant records.
+      if (!empty($langs_to_remove)) {
+        $purge_count += db_delete('metatag')
+          ->condition('entity_type', $entity_type)
+          ->condition('entity_id', $entity_id)
+          ->condition('language', $langs_to_remove)
+          ->execute();
+      }
+    }
+  }
+
+  if (empty($purge_count)) {
+    drupal_set_message(t('No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type)));
+    watchdog('metatag', 'No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type));
+  }
+  else {
+    drupal_set_message(t('Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type)));
+    watchdog('metatag', 'Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type));
+    return;
+  }
+}
+
+/**
+ * Fix {metatag} records that may have been corrupted by #1871020.
+ */
+function metatag_update_7014() {
+  $records = db_query("SELECT *
+  FROM {metatag} m
+  WHERE
+       m.data LIKE :nolang
+    OR m.data LIKE :lang
+    OR m.data LIKE :und",
+    array(
+      ':nolang' => 'a:1:{s:0:"";a:%:{s:%;a:%:{%;}}}',
+      ':lang' => 'a:1:{s:2:"__";a:%:{s:%;a:%:{%;}}}',
+      ':und' => 'a:1:{s:3:"___";a:%:{s:%;a:%:{%;}}}',
+    ));
+
+  // Nothing to fix.
+  if ($records->rowCount() == 0) {
+    drupal_set_message(t('No corrupt records to fix, this is good news :-)'));
+  }
+
+  // Fix the faulty records.
+  else {
+    foreach ($records as $record) {
+      // Extract the data and get the first element of the array, this should be
+      // valid data.
+      $record->data = reset(unserialize($record->data));
+
+      // Update the record.
+      drupal_write_record('metatag', $record, array('entity_type', 'entity_id', 'language'));
+    }
+    drupal_set_message(t('Fixed @count corrupt meta tag record(s).', array('@count' => $records->rowCount())));
+  }
+}
+
+/**
+ * Add the revision_id from the entity into metatag schema, adjust the primary
+ * keys accordingly.
+ */
+function metatag_update_7015() {
+  if (!db_field_exists('metatag', 'revision_id')) {
+    // Leave a note for metatag_metatags_load_multiple() that the revision_id
+    // field has been added.
+    variable_set('metatag_has_revision_id', TRUE);
+
+    // Tell update 7017 that it isn't needed.
+    variable_set('metatag_skip_update_7017', TRUE);
+
+    // Add the new field.
+    db_add_field('metatag', 'revision_id', array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The revision_id for the entity object this data is attached to.',
+      ));
+
+    // Remove the existing primary key. This may take some work so it can be
+    // database agnostic, i.e. some databases will not like it.
+    db_drop_primary_key('metatag');
+
+    // Add the new primary key.
+    db_add_primary_key('metatag', array('entity_type', 'entity_id', 'revision_id', 'language'));
+
+    drupal_set_message(t('Added the {metatag}.revision_id field.'));
+  }
+  else {
+    drupal_set_message(t('The {metatag}.revision_id field has already been added, nothing to do.'));
+  }
+}
+
+/**
+ * Update the revision ID to fix the NULL values, help avoid problems with
+ * update 7017.
+ */
+function metatag_update_7016() {
+  // It's possible that 7015 was not executed if the site had been updated to
+  // an early dev release, so make sure the revision_id field exists.
+  metatag_update_7015();
+
+  // Run the update.
+  db_query("UPDATE {metatag} SET revision_id = 0 WHERE revision_id IS NULL");
+}
+
+/**
+ * The {metatag}.revision_id field is required.
+ */
+function metatag_update_7017() {
+  if (!variable_get('metatag_skip_update_7017', FALSE)) {
+    // Let's add a temporary unique key so MySQL will let it go.
+    db_add_unique_key('metatag', 'temp_key', array('entity_type', 'entity_id', 'revision_id', 'language'));
+
+    // Now remove the PK before changing a field from serial.
+    db_drop_primary_key('metatag');
+
+    // Change the field.
+    db_change_field('metatag', 'revision_id', 'revision_id', array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+      'description' => 'The revision_id for the entity object this data is attached to.',
+    ));
+
+    // Manually re-add the PK.
+    db_add_primary_key('metatag', array('entity_type', 'entity_id', 'revision_id', 'language'));
+
+    // Finally, remove the temporary unique key because it's no longer useful.
+    db_drop_unique_key('metatag', 'temp_key');
+
+    drupal_set_message(t('Fixed the {metatag}.revision_id field.'));
+  }
+  else {
+    drupal_set_message(t("Didn't need to fix the {metatag}.revision_id field; please disperse, nothing to see here."));
+  }
+
+  // Delete the temporary variable.
+  variable_del('metatag_skip_update_7017');
+}
+
+/**
+ * Update the revision ID for each record. This may take some time. Should any
+ * nodes be discovered with a meta tag record for both revision_id 0 and the
+ * correct revision_id, the "0" value will be deleted; if this is not the
+ * desired result the {metatag} table must be manually pruned to have the
+ * correct records prior to letting this update run.
+ */
+function metatag_update_7018(&$sandbox) {
+  // Process records in small groups.
+  // When a group is processed, the batch update engine determines whether it
+  // should continue processing in the same request or provide progress
+  // feedback to the user and wait for the next request.
+  $limit = 10;
+  // When ran through Drush it's Ok to process a larger number of objects at a
+  // time.
+  if (drupal_is_cli()) {
+    $limit = 100;
+  }
+
+  // Use the sandbox at your convenience to store the information needed
+  // to track progression between successive calls to the function.
+  if (!isset($sandbox['progress'])) {
+    // The count of records visited so far.
+    $sandbox['progress'] = 0;
+
+    // Get a list of all records affected.
+    $sandbox['records'] = db_query("SELECT entity_type, entity_id, language
+      FROM {metatag}
+      WHERE revision_id = 0")
+      ->fetchAll();
+
+    // If there's no data, don't bother with the extra work.
+    if (empty($sandbox['records'])) {
+      watchdog('metatag', 'Update 7018: No {metatag} records needed to have the revision_id value fixed.', array(), WATCHDOG_INFO);
+      if (drupal_is_cli()) {
+        drupal_set_message(t('Update 7018: No {metatag} records needed to have the revision_id value fixed.'));
+      }
+      return t('No {metatag} records needed to have the revision_id value fixed.');
+    }
+
+    // Total records that must be visited.
+    $sandbox['max'] = count($sandbox['records']);
+
+    // A place to store messages during the run.
+    $sandbox['messages'] = array();
+
+    // An initial record of the number of records to be updated.
+    watchdog('metatag', 'Update 7018: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7018: !count records to update.', array('!count' => $sandbox['max'])));
+    }
+
+    // Last record processed.
+    $sandbox['current_record'] = -1;
+
+    // Because a lot of other processing happens on the first iteration, just do
+    // one.
+    $limit = 1;
+  }
+
+  // Work out which entities support languages and revisions.
+  $has_language = array();
+  $has_revisions = array();
+  foreach (entity_get_info() as $entity_type => $info) {
+    $has_language[$entity_type] = FALSE;
+    $has_revisions[$entity_type] = FALSE;
+    if (!empty($info['entity keys']['language'])) {
+      $has_language[$entity_type] = $info['entity keys']['language'];
+    }
+    if (!empty($info['entity keys']['revision'])) {
+      $has_revisions[$entity_type] = $info['entity keys']['revision'];
+    }
+  }
+
+  // Set default values.
+  for ($ctr = 0; $ctr < $limit; $ctr++) {
+    $sandbox['current_record']++;
+    if (empty($sandbox['records'][$sandbox['current_record']])) {
+      break;
+    }
+
+    // Shortcuts for later.
+    $entity_type = $sandbox['records'][$sandbox['current_record']]->entity_type;
+    $entity_id = $sandbox['records'][$sandbox['current_record']]->entity_id;
+    // Make sure to load the correct language record.
+    $language = $sandbox['records'][$sandbox['current_record']]->language;
+    $conditions = array();
+    // Some entities don't include a language value.
+    if (!empty($has_language[$entity_type])) {
+      $conditions['language'] = $language;
+    }
+    $records = entity_load($entity_type, array($entity_id), $conditions);
+
+    // Try to fallback to default language if no record was found. This may
+    // happen when using entity_translation as the parent entity table only
+    // contains one record.
+    if (!empty($conditions) && empty($records)) {
+      $records = entity_load($entity_type, array($entity_id));
+    }
+
+    // Fix this record.
+    if (!empty($records)) {
+      $entity = reset($records);
+
+      // Speed up the handling of entities that don't support revisions.
+      $revision_id = 0;
+      if (!empty($has_revisions[$entity_type])) {
+        list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+        $revision_id = intval($revision_id);
+      }
+
+      // Don't bother updating records if the revision_id is 0.
+      if (!empty($revision_id)) {
+        $exists = db_query("SELECT entity_id
+            FROM {metatag}
+            WHERE entity_type = :entity_type
+            AND entity_id = :entity_id
+            AND revision_id = :revision_id
+            AND language = :language",
+          array(
+            ':entity_type' => $entity_type,
+            ':entity_id' => $entity_id,
+            ':revision_id' => $revision_id,
+            ':language' => $language,
+          ))->fetchObject();
+        // There isn't already a record for the revision_id, so update the
+        // metatag record.
+        if (!$exists) {
+          db_update('metatag')
+            ->fields(array('revision_id' => $revision_id))
+            ->condition('entity_type', $entity_type)
+            ->condition('entity_id', $entity_id)
+            ->condition('revision_id', 0)
+            ->condition('language', $language)
+            ->execute();
+        }
+        // The record exists, so delete the old one under the grounds that the
+        // one with a revision_id is newer.
+        // Disclaimer: this is completely arbitrary, without providing a UI to
+        // let the site maintainer/builder choose which of the two records to
+        // keep, we're stuck with a bad scenario. Thankfully this should not
+        // happen very often and would only affect sites that were running a
+        // dev release. Also, sorry :(
+        else {
+          db_delete('metatag')
+            ->condition('entity_type', $entity_type)
+            ->condition('entity_id', $entity_id)
+            ->condition('revision_id', 0)
+            ->condition('language', $language)
+            ->execute();
+        }
+
+        // Nodes can have multiple revisions, so create new {metatag} records
+        // for each of the other revisions.
+        if ($entity_type == 'node') {
+          $revisions = node_revision_list($entity);
+          if (count($revisions) > 1) {
+            $metatags = db_query("SELECT data
+                FROM {metatag}
+                WHERE entity_type = :entity_type
+                AND entity_id = :entity_id
+                AND language = :language",
+              array(
+                ':entity_type' => $entity_type,
+                ':entity_id' => $entity_id,
+                ':language' => $language,
+              ));
+            if (!empty($metatags) && isset($metatags->data) && !empty($metatags->data)) {
+              foreach ($revisions as $vid => $revision) {
+                // Only one record per nid/vid/langcode, thank you.
+                if ($vid != $revision_id) {
+                  // Check that there isn't already a record for this revision.
+                  $exists = db_query("SELECT entity_id
+                      FROM {metatag}
+                      WHERE entity_type = :entity_type
+                      AND entity_id = :entity_id
+                      AND revision_id = :revision_id
+                      AND language = :language",
+                    array(
+                      ':entity_type' => $entity_type,
+                      ':entity_id' => $entity_id,
+                      ':revision_id' => $vid,
+                      ':language' => $language,
+                    ))->fetchObject();
+                  if (!$exists) {
+                    $node = node_load($entity_id, $vid);
+                    $record = new StdClass();
+                    $record->entity_type = $entity_type;
+                    $record->entity_id = $entity_id;
+                    $record->revision_id = $vid;
+                    $record->language = $language;
+                    $record->data = $metatags->data;
+                    drupal_write_record('metatag', $record);
+                  }
+                }
+              }
+            }
+          }
+        }
+
+        // Other entity types.
+        else {
+          drupal_set_message(t('Metatag records for @type objects have not been checked for revisions.', array('@type' => $entity_type)), 'status', FALSE);
+        }
+      }
+    }
+
+    // Update our progress information.
+    $sandbox['progress']++;
+  }
+
+  // Set the "finished" status, to tell batch engine whether this function
+  // needs to run again. If you set a float, this will indicate the progress of
+  // the batch so the progress bar will update.
+  if ($sandbox['progress'] >= $sandbox['max']) {
+    $sandbox['#finished'] = TRUE;
+  }
+  else {
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
+
+  if ($sandbox['#finished']) {
+    // Clear all caches so the fixed data will be reloaded.
+    cache_clear_all('*', 'cache_metatag', TRUE);
+
+    // A final log of the number of records that were converted.
+    watchdog('metatag', 'Update 7018: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7018: !count records were updated.', array('!count' => $sandbox['progress'])));
+    }
+
+    // hook_update_N() may optionally return a string which will be displayed
+    // to the user.
+    return t('Fixed the revision_id values for !count {metatag} records.', array('!count' => $sandbox['progress']));
+  }
+}
+
+/**
+ * Clear the entity_cache bins.
+ */
+function metatag_update_7019() {
+  if (module_exists('entitycache')) {
+    foreach (drupal_get_schema() as $table_name => $spec) {
+      if (strpos($table_name, 'cache_entity_') === 0) {
+        cache_clear_all('*', $table_name, TRUE);
+        drupal_set_message(t("Cleared the @table cache bin", array('@table' => $table_name)));
+      }
+    }
+  }
+  else {
+    drupal_set_message(t("The EntityCache module is not installed, nothing to do."));
+  }
+}
+
+/**
+ * Clear the Metatag cache.
+ */
+function metatag_update_7020() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
+
+/**
+ * Clear the existing Metatag cache so all unwanted 403/404 paths can be
+ * purged.
+ */
+function metatag_update_7021() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
+
+/**
+ * A minor bit of tidy-up after update 7015.
+ */
+function metatag_update_7022() {
+  variable_del('metatag_skip_update_7015');
+}
+
+/**
+ * Clear the Metatag cache because $cid_parts was changed.
+ */
+function metatag_update_7023() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
+
+/**
+ * No-op update. Renaming twitter:image to twitter:image:src no longer needed.
+ */
+function metatag_update_7024() {
+  // Do nothing.
+}
+
+/**
+ * Replaced by update 7030.
+ */
+function metatag_update_7025() {
+  // Do nothing.
+}
+
+/**
+ * Rename the 'copyright' meta tag to 'rights', part 1.
+ */
+function metatag_update_7026(&$sandbox) {
+  $old_tag = 'copyright';
+  $new_tag = 'rights';
+  return metatag_update_replace_entity_tag($sandbox, $old_tag, $new_tag);
+}
+
+/**
+ * Replaced by update 7031.
+ */
+function metatag_update_7027() {
+  // Do nothing.
+}
+
+/**
+ * Clear the menu cache so the new Settings page will be picked up.
+ */
+function metatag_update_7028() {
+  variable_set('menu_rebuild_needed', TRUE);
+}
+
+/**
+ * Add an index to the {metatag} table to speed up some queries.
+ */
+function metatag_update_7029() {
+  if (!db_index_exists('metatag', 'type_revision')) {
+    db_add_index('metatag', 'type_revision', array('entity_type', 'revision_id'));
+    return t('Added an index to the main Metatag table that will hopefully improve performance a little.');
+  }
+  else {
+    return t('Did not add the index, it already existed.');
+  }
+}
+
+/**
+ * No-op update. Renaming twitter:image to twitter:image:src no longer needed.
+ */
+function metatag_update_7030() {
+  // Do nothing.
+}
+
+/**
+ * Rename the 'copyright' meta tag to 'rights', part 2.
+ */
+function metatag_update_7031() {
+  $old_tag = 'copyright';
+  $new_tag = 'rights';
+  return metatag_update_replace_config_tag($old_tag, $new_tag);
+}
+
+/**
+ * Clear the Metatag cache.
+ */
+function metatag_update_7032() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
+
+/**
+ * These originally removed the 'author' meta tag, but it was subsequently
+ * decided that this was not the correct approach, that the meta tag should not
+ * be removed after all.
+ *
+ * @see https://www.drupal.org/node/2330823
+ */
+function metatag_update_7033() {
+}
+function metatag_update_7034() {
+}
+function metatag_update_7035() {
+}
+
+/**
+ * Update variables to indicate which entities should be supported.
+ */
+function metatag_update_7036() {
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    $variable_name = 'metatag_enable_' . $entity_type;
+
+    // Configuration entities are skipped.
+    if (isset($entity_info['configuration']) && $entity_info['configuration'] == TRUE) {
+      continue;
+    }
+
+    // Entities without view modes are skipped.
+    elseif (empty($entity_info['view modes'])) {
+      continue;
+    }
+
+    // Basic core entities or "normal" entities that have been enabled via the
+    // API.
+    elseif (in_array($entity_type, array('node', 'taxonomy_term', 'user')) ||
+      !empty($entity_info['metatag']) || !empty($entity_info['metatags'])) {
+      // Check if the entity type has been enabled or disabled previously; if
+      // the variable equals a junk value then it was not previously set,
+      // therefore we'll set a default.
+      if (variable_get($variable_name, 'monkey') == 'monkey') {
+        // By default these entity types are enabled.
+        variable_set($variable_name, TRUE);
+        // Check each entity bundle.
+        if (!empty($entity_info['bundles'])) {
+          foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+            $variable_name = 'metatag_enable_' . $entity_type . '__' . $bundle_name;
+            // Check if the bundle has been enabled or disabled previously; if
+            // the variable equals a junk value then it was not previously set,
+            // therefore we'll set a default.
+            if (variable_get($variable_name, 'monkey') == 'monkey') {
+              if (!empty($bundle_info['metatag']) || !empty($bundle_info['metatags'])) {
+                variable_set($variable_name, TRUE);
+              }
+              else {
+                variable_set($variable_name, FALSE);
+              }
+            }
+            // This variable was set before.
+            else {
+              // Do nothing.
+            }
+          }
+        }
+      }
+      // This variable was set before.
+      else {
+        // Do nothing.
+      }
+    }
+
+    // Disable this entity type.
+    else {
+      variable_set($variable_name, FALSE);
+    }
+  }
+
+  // Clear the caches.
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  drupal_static_reset('metatag_config_load_with_defaults');
+  drupal_static_reset('metatag_entity_supports_metatags');
+  ctools_include('export');
+  ctools_export_load_object_reset('metatag_config');
+
+  drupal_set_message(t('The way that Metatag tracks which entity types are compatible has changed. Please review the <a href="@url">Settings page</a> to ensure that all of the entity types are enabled correctly.', array('@url' => 'admin/config/search/metatags/settings')));
+}
+
+/**
+ * Clear the menu cache so the renamed Settings page will be picked up.
+ */
+function metatag_update_7037() {
+  variable_set('menu_rebuild_needed', TRUE);
+}
+
+/**
+ * Manually enable all content types, vocabularies and the user entity to help
+ * resolve issues from 1.5's architecture change.
+ */
+function metatag_update_7038() {
+  foreach (array('node', 'taxonomy_term', 'user') as $entity_type) {
+    // Enable the main entity type.
+    $variable_name = 'metatag_enable_' . $entity_type;
+    variable_set($variable_name, TRUE);
+
+    // Update each entity bundle too.
+    $entity_info = entity_get_info($entity_type);
+    if (!empty($entity_info['bundles'])) {
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+        $variable_name = 'metatag_enable_' . $entity_type . '__' . $bundle_name;
+        variable_set($variable_name, TRUE);
+      }
+    }
+  }
+}
+
+/**
+ * Reload some meta tag caches.
+ */
+function metatag_update_7039() {
+  foreach (language_list() as $langcode => $language) {
+    cache_clear_all('info:' . $langcode, 'cache_metatag');
+  }
+}
+
+/**
+ * Fix robots meta tags that might have been broken when they were imported
+ * from Nodewords.
+ */
+function metatag_update_7040(&$sandbox) {
+  // Process records by groups of 10 (arbitrary value).
+  // When a group is processed, the batch update engine determines whether it
+  // should continue processing in the same request or provide progress
+  // feedback to the user and wait for the next request.
+  $limit = 10;
+  // When ran through Drush it's Ok to process a larger number of objects at a
+  // time.
+  if (drupal_is_cli()) {
+    $limit = 100;
+  }
+
+  // Use the sandbox at your convenience to store the information needed
+  // to track progression between successive calls to the function.
+  if (!isset($sandbox['progress'])) {
+    // The count of records visited so far.
+    $sandbox['progress'] = 0;
+
+    // Get a count of {metatag} records that have a robots meta tag definition
+    // that is not in the correct format.
+    $records = db_select('metatag', 'm')
+      ->fields('m')
+      ->condition('m.data', '%:6:"robots";%', 'LIKE')
+      ->condition('m.data', '%:6:"robots";a:1:{s:5:"value";%', 'NOT LIKE')
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+
+    // If there's no data, don't bother with the extra work.
+    if (empty($records)) {
+      watchdog('metatag', 'Update 7040: No robots meta tags need to be fixed.', array(), WATCHDOG_INFO);
+      if (drupal_is_cli()) {
+        drupal_set_message(t('Update 7040: No robots meta tags need to be fixed.'));
+      }
+      return t('No robots meta tags need to be fixed.');
+    }
+
+    // Total records that must be visited.
+    $sandbox['max'] = $records;
+
+    // A place to store messages during the run.
+    $sandbox['messages'] = array();
+
+    // An initial record of the number of records to be updated.
+    watchdog('metatag', 'Update 7040: !count records to examine.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7040: !count records to examine.', array('!count' => $sandbox['max'])));
+    }
+
+    // Log how many records are fixed.
+    $sandbox['fixed'] = 0;
+
+    // Because a lot of other processing happens on the first iteration, just do
+    // ten.
+    $limit = 10;
+  }
+
+  // Get a list of records that need to be fixed.
+  $records = db_select('metatag', 'm')
+    ->fields('m')
+    ->condition('m.data', '%:6:"robots";%', 'LIKE')
+    ->condition('m.data', '%:6:"robots";a:1:{s:5:"value";%', 'NOT LIKE')
+    ->range(0, $limit)
+    ->execute();
+
+  // Set default values.
+  foreach ($records as $record) {
+    // Extract the record.
+    $record->data = unserialize($record->data);
+
+    // See if the record needs to be fixed.
+    if (!empty($record->data['robots']) && empty($record->data['robots']['value'])) {
+      // Fix the record.
+      $robots = $record->data['robots'];
+      $record->data['robots'] = array(
+        'value' => $robots,
+      );
+
+      // Update the database.
+      db_update('metatag')
+        ->fields(array('data' => serialize($record->data)))
+        ->condition('entity_type', $record->entity_type)
+        ->condition('entity_id', $record->entity_id)
+        ->condition('revision_id', $record->revision_id)
+        ->condition('language', $record->language)
+        ->execute();
+
+      // Clear the cache for this entity.
+      entity_get_controller($record->entity_type)->resetCache(array($record->entity_id));
+
+      // Update our progress information.
+      $sandbox['fixed']++;
+    }
+
+    // Update our progress information.
+    $sandbox['progress']++;
+  }
+
+  // Set the "finished" status, to tell batch engine whether this function
+  // needs to run again. If you set a float, this will indicate the progress of
+  // the batch so the progress bar will update.
+  if ($sandbox['progress'] >= $sandbox['max']) {
+    $sandbox['#finished'] = TRUE;
+  }
+  else {
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
+
+  // Only display a status message if process finished.
+  if ($sandbox['#finished'] === TRUE) {
+    // Clear all caches so the fixed data will be reloaded.
+    cache_clear_all('*', 'cache_metatag', TRUE);
+
+    // A final log of the number of records that were converted.
+    watchdog('metatag', 'Update 7040: !count records were fixed.', array('!count' => $sandbox['fixed']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7040: !count records were fixed.', array('!count' => $sandbox['fixed'])));
+    }
+
+    // hook_update_N() may optionally return a string which will be displayed
+    // to the user.
+    return t('Fixed the Metatag robots values for @count nodes.', array('@count' => $sandbox['fixed']));
+  }
+}
+
+/**
+ * Rerun update 7018 that was fixed to run correctly when using Entity
+ * Translation. This may take some time.
+ */
+function metatag_update_7041(&$sandbox) {
+  metatag_update_7018($sandbox);
+}
+
+/**
+ * Delete a deprecated variable and clear all Metatag caches.
+ */
+function metatag_update_7100() {
+  variable_del('metatag_translate_final_values');
+
+  // Clear all caches so that i18n support can be activated, if necessary.
+  cache_clear_all('*', 'cache_metatag', TRUE);
+}
+
+/**
+ * Update i18n strings for all meta tags to use the new format.
+ */
+function metatag_update_7101() {
+  if (!module_exists('locale') || !db_table_exists('locales_source')) {
+    return t('No translations to fix as the locale system is not enabled.');
+  }
+
+  // Loop through each entity type. Not going to bother filtering this list,
+  // it'll only be a difference of a few entities anyway and the queries
+  // should be fairly quick.
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    // Entities must have bundles.
+    if (empty($entity_info['bundles'])) {
+      $entity_info['bundles'] = array(
+        $entity_type => $entity_type,
+      );
+    }
+    foreach ($entity_info['bundles'] as $bundle_type => $bundle_info) {
+      // Update {locales_source}, replace 'metatag:ENTITYTYPE:BUNDLE:tag' with
+      // 'metatag:metatag_config:ENTITYTYPE:BUNDLE:tag'.
+      db_query("UPDATE {locales_source}
+        SET location = REPLACE(location, 'metatag:{$entity_type}:{$bundle_type}:', 'metatag:metatag_config:{$entity_type}:{$bundle_type}:'),
+          context = REPLACE(context, '{$entity_type}:{$bundle_type}:', 'metatag_config:{$entity_type}:{$bundle_type}:')
+        WHERE textgroup = 'metatag'
+          AND location LIKE 'metatag:{$entity_type}:{$bundle_type}:%'");
+
+      // Update {locales_source}, replace 'metatag:ENTITYTYPE:tag' with
+      // 'metatag:metatag_config:ENTITYTYPE:tag'.
+      db_query("UPDATE {locales_source}
+        SET location = REPLACE(location, 'metatag:{$entity_type}:', 'metatag:metatag_config:{$entity_type}:'),
+          context = REPLACE(context, '{$entity_type}:', 'metatag_config:{$entity_type}:')
+        WHERE textgroup = 'metatag'
+          AND location LIKE 'metatag:{$entity_type}:%'");
+    }
+  }
+  // Update {locales_source}, replace 'metatag:metatag:' with
+  // 'metatag:output:'.
+  db_query("UPDATE {locales_source}
+    SET location = REPLACE(location, 'metatag:metatag:', 'metatag:output:'),
+      context = REPLACE(context, 'metatag:', 'output:')
+    WHERE textgroup = 'metatag'
+      AND location LIKE 'metatag:metatag:%'");
+}
+
+/**
+ * Re-run update 7101.
+ */
+function metatag_update_7102() {
+  metatag_update_7101();
+}
+
+/**
+ * Clear all metatag caches so the new entity caching structure takes over.
+ */
+function metatag_update_7103() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+}
+
+/**
+ * Remove the entity revision ID from the translation strings.
+ */
+function metatag_update_7104(&$sandbox) {
+  // Verify that locales are being used in the first place.
+  if (!module_exists('locale') || !db_table_exists('locales_source')) {
+    return t('Metatag: No translations to fix as the locale system is not enabled.');
+  }
+
+  // No need to do anything if output translation is disabled.
+  if (!variable_get('metatag_i18n_translate_output', FALSE)) {
+    return t('Metatag: Output translation is disabled, so no need to update anything.');
+  }
+
+  // Process records by groups of 10 (arbitrary value).
+  // When a group is processed, the batch update engine determines whether it
+  // should continue processing in the same request or provide progress
+  // feedback to the user and wait for the next request.
+  $limit = 10;
+  // When ran through Drush it's Ok to process a larger number of objects at a
+  // time.
+  if (drupal_is_cli()) {
+    $limit = 100;
+  }
+
+  // Use the sandbox at your convenience to store the information needed
+  // to track progression between successive calls to the function.
+  if (!isset($sandbox['progress'])) {
+    // The count of records visited so far.
+    $sandbox['progress'] = 0;
+
+    // Total records that must be visited.
+    $sandbox['max'] = db_query("SELECT COUNT(lid)
+      FROM {locales_source}
+      WHERE textgroup = 'metatag'
+      AND context LIKE 'output:%:%:%:%'")->fetchField();
+
+    // If there's no data, don't bother with the extra work.
+    if (empty($sandbox['max'])) {
+      watchdog('metatag', 'Update 7104: No nodes need the translation entity string fixed.', array(), WATCHDOG_INFO);
+      if (drupal_is_cli()) {
+        drupal_set_message(t('Update 7104: No nodes need the translation entity string fixed.'));
+      }
+      return t('No nodes need the Metatag language values fixed.');
+    }
+
+    // A place to store messages during the run.
+    $sandbox['messages'] = array();
+
+    // An initial record of the number of records to be updated.
+    watchdog('metatag', 'Update 7104: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7104: !count records to update.', array('!count' => $sandbox['max'])));
+    }
+  }
+
+  // Get a batch of records that need to be fixed.
+  $records = db_query_range("SELECT lid, location, context
+    FROM {locales_source}
+    WHERE textgroup = 'metatag'
+    AND context LIKE 'output:%:%:%:%'", 0, $limit);
+
+  // Update each of the records.
+  foreach ($records as $record) {
+    $old_location = '/metatag:output:([^:]*):([^:]*):([^:]*):([^:]*)/';
+    $new_location = 'metatag:output:$1:$2:$4';
+    $location = preg_replace($old_location, $new_location, $record->location);
+    $old_context = '/output:([^:]*):([^:]*):([^:]*):([^:]*)/';
+    $new_context = 'output:$1:$2:$4';
+    $context = preg_replace($old_context, $new_context, $record->context);
+    drupal_set_message($location);
+    drupal_set_message($context);
+    db_update('locales_source')
+      ->fields(array(
+        'location' => $location,
+        'context' => $context,
+      ))
+      ->condition('lid', $record->lid)
+      ->execute();
+
+    // Update our progress information.
+    $sandbox['progress']++;
+  }
+
+  // Set the "finished" status, to tell batch engine whether this function
+  // needs to run again. If you set a float, this will indicate the progress of
+  // the batch so the progress bar will update.
+  if ($sandbox['progress'] >= $sandbox['max']) {
+    $sandbox['#finished'] = TRUE;
+  }
+  else {
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
+
+  if ($sandbox['#finished']) {
+    // Clear all caches so the fixed data will be reloaded.
+    cache_clear_all('*', 'cache_metatag', TRUE);
+
+    // hook_update_N() may optionally return a string which will be displayed
+    // to the user.
+    return t('Fixed the Metatag language values for @count nodes.', array('@count' => $sandbox['progress']));
+  }
+}
+
+/**
+ * Fix the output translation strings.
+ */
+function metatag_update_7105() {
+  if (!module_exists('locale') || !db_table_exists('locales_source')) {
+    return t('No translations to fix as the locale system is not enabled.');
+  }
+
+  db_query("UPDATE {locales_source}
+    SET location = REPLACE(location, 'metatag:metatag:', 'metatag:output:'),
+      context = REPLACE(context, 'metatag:', 'output:')
+    WHERE textgroup = 'metatag'
+    AND location LIKE 'metatag:metatag:%'");
+
+  return t('Fixed the Metatag output strings.');
+}
+
+
+/**
+ * The output translation strings were renamed to something shorter, so rerun
+ * update 7105.
+ */
+function metatag_update_7106() {
+  return metatag_update_7105();
+}
+
+/**
+ * Fix the global config translation strings.
+ */
+function metatag_update_7107() {
+  if (!module_exists('locale') || !db_table_exists('locales_source')) {
+    return t('No translations to fix as the locale system is not enabled.');
+  }
+
+  db_query("UPDATE {locales_source}
+    SET location = REPLACE(location, 'metatag:global:', 'metatag:metatag_config:global:'),
+      context = REPLACE(context, 'global:', 'metatag_config:global:')
+    WHERE textgroup = 'metatag'
+    AND location LIKE 'metatag:global:%'");
+
+  return t('Fixed the Metatag global config string translations.');
+}
+
+/**
+ * Delete output translations if it's disabled.
+ */
+function metatag_update_7108(&$sandbox) {
+  if (!module_exists('locale') || !db_table_exists('locales_source')) {
+    return t('No translations to fix as the locale system is not enabled.');
+  }
+
+  // If the output-translation option is enabled then don't delete anything.
+  if (variable_get('metatag_i18n_translate_output', FALSE)) {
+    return t("Metatag: Not deleting output translations because that option is enabled.");
+  }
+
+  $limit = 100;
+
+  // When ran through Drush it's Ok to process a larger number of objects at a
+  // time.
+  if (drupal_is_cli()) {
+    $limit = 500;
+  }
+
+  // Use the sandbox at your convenience to store the information needed to
+  // track progression between successive calls to the function.
+  if (!isset($sandbox['progress'])) {
+    // The count of records visited so far.
+    $sandbox['progress'] = 0;
+
+    $sandbox['max'] = db_query("SELECT COUNT(lid)
+      FROM {locales_source}
+      WHERE textgroup = 'metatag'
+      AND context LIKE 'output:%'")->fetchField();
+
+    // If there's no data, don't bother with the extra work.
+    if (empty($sandbox['max'])) {
+      watchdog('metatag', 'Update 7108: No nodes need the translation entity string fixed.', array(), WATCHDOG_INFO);
+      if (drupal_is_cli()) {
+        drupal_set_message(t('Update 7108: No nodes need the translation entity string fixed.'));
+      }
+      return t('No nodes need the Metatag language values fixed.');
+    }
+
+    // A place to store messages during the run.
+    $sandbox['messages'] = array();
+
+    // An initial record of the number of records to be updated.
+    watchdog('metatag', 'Update 7108: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7108: !count records to update.', array('!count' => $sandbox['max'])));
+    }
+  }
+
+  // Get a batch of records that need to be fixed.
+  $records = db_query_range("SELECT lid
+    FROM {locales_source}
+    WHERE textgroup = 'metatag'
+    AND context LIKE 'output:%'", 0, $limit);
+
+  $lids = $records->fetchCol();
+  $count = count($lids);
+  // Delete records in the tables in reverse order, so that if the query fails
+  // and has to be reran it'll still find records. But it should be ok.
+  if (db_table_exists('i18n_string')) {
+    db_delete('i18n_string')
+      ->condition('lid', $lids, 'IN')
+      ->execute();
+  }
+  db_delete('locales_target')
+    ->condition('lid', $lids, 'IN')
+    ->execute();
+  db_delete('locales_source')
+    ->condition('lid', $lids, 'IN')
+    ->execute();
+
+  $sandbox['progress'] = $sandbox['progress'] + $count;
+
+  // Set the "finished" status, to tell batch engine whether this function
+  // needs to run again. If you set a float, this will indicate the progress of
+  // the batch so the progress bar will update.
+  if ($sandbox['progress'] >= $sandbox['max']) {
+    $sandbox['#finished'] = TRUE;
+  }
+  else {
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
+
+  if ($sandbox['#finished']) {
+    // Clear all caches so the fixed data will be reloaded.
+    cache_clear_all('*', 'cache_metatag', TRUE);
+
+    // hook_update_N() may optionally return a string which will be displayed
+    // to the user.
+    return t('Deleted output translation if disabled for  @count items.', array('@count' => $sandbox['progress']));
+  }
+}
+
+/**
+ * Rename the 'icon_any' meta tag to 'mask-icon' in the entity records.
+ */
+function metatag_update_7109(&$sandbox) {
+  module_load_include('install', 'metatag');
+  $old_tag = 'icon_any';
+  $new_tag = 'mask-icon';
+  return metatag_update_replace_entity_tag($sandbox, $old_tag, $new_tag);
+}
+
+/**
+ * Rename the 'icon_any' meta tag to 'mask-icon' in the configs.
+ */
+function metatag_update_7110() {
+  module_load_include('install', 'metatag');
+  $old_tag = 'icon_any';
+  $new_tag = 'mask-icon';
+  return metatag_update_replace_config_tag($old_tag, $new_tag);
+}
+
+/**
+ * Remove the "metatag_ui" record from the {system} table.
+ */
+function metatag_update_7111() {
+  db_delete('system')
+    ->condition('name', 'metatag_ui')
+    ->execute();
+}
+
+/**
+ * The Publisher meta tag is now part of the Google Plus submodule.
+ */
+function metatag_update_7112() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  drupal_set_message(t('The Publisher meta tag is now part of the Google Plus submodule.'));
+}
+
+/**
+ * Clear all metatag output caches if output caching is disabled.
+ */
+function metatag_update_7113() {
+  if (variable_get('metatag_cache_output', TRUE) == FALSE) {
+    cache_clear_all('output:', 'cache_metatag', TRUE);
+  }
+}
+
+/**
+ * Disable output caching.
+ */
+function metatag_update_7114() {
+  variable_del('metatag_cache_output');
+}
+
+/**
+ * Clear all metatag output caches, it will be rebuild if needed.
+ */
+function metatag_update_7115() {
+  cache_clear_all('output:', 'cache_metatag', TRUE);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bea0bf7cd91c5db2b33b9bf4332b8fbb82fc9944
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.metatag.inc
@@ -0,0 +1,463 @@
+<?php
+
+/**
+ * Implements hook_metatag_config_default().
+ */
+function metatag_metatag_config_default() {
+  // Optionally skip loading the defaults.
+  if (!variable_get('metatag_load_defaults', TRUE)) {
+    return;
+  }
+
+  $configs = array();
+
+  $config = new stdClass();
+  $config->instance = 'global';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => '[current-page:title] | [current-page:pager][site:name]'),
+    'generator' => array('value' => 'Drupal 7 (http://drupal.org)'),
+    'canonical' => array('value' => '[current-page:url:absolute]'),
+    'shortlink' => array('value' => '[current-page:url:unaliased]'),
+  );
+  $configs[$config->instance] = $config;
+
+  $config = new stdClass();
+  $config->instance = 'global:frontpage';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => variable_get('site_slogan') ? '[site:name] | [current-page:pager][site:slogan]' : '[site:name] | [current-page:pager]'),
+    'canonical' => array('value' => '[site:url]'),
+    'shortlink' => array('value' => '[site:url]'),
+  );
+  $configs[$config->instance] = $config;
+
+  $config = new stdClass();
+  $config->instance = 'global:403';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'canonical' => array('value' => '[site:url]'),
+    'shortlink' => array('value' => '[site:url]'),
+  );
+  $configs[$config->instance] = $config;
+
+  $config = new stdClass();
+  $config->instance = 'global:404';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'canonical' => array('value' => '[site:url]'),
+    'shortlink' => array('value' => '[site:url]'),
+  );
+  $configs[$config->instance] = $config;
+
+  $config = new stdClass();
+  $config->instance = 'node';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => '[node:title] | [current-page:pager][site:name]'),
+    'description' => array('value' => '[node:summary]'),
+  );
+  $configs[$config->instance] = $config;
+
+  if (module_exists('taxonomy')) {
+    $config = new stdClass();
+    $config->instance = 'taxonomy_term';
+    $config->api_version = 1;
+    $config->disabled = FALSE;
+    $config->config = array(
+      'title' => array('value' => '[term:name] | [current-page:pager][site:name]'),
+      'description' => array('value' => '[term:description]'),
+    );
+    $configs[$config->instance] = $config;
+  }
+
+  $config = new stdClass();
+  $config->instance = 'user';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => '[user:name] | [site:name]'),
+  );
+  if (variable_get('user_pictures')) {
+    $config->config['image_src'] = array('value' => '[user:picture:url]');
+  }
+  $configs[$config->instance] = $config;
+
+  // Before returning these, allow the bundled submodules to override them, thus
+  // extending the "real" defaults before they can then be altered by other
+  // modules.
+  // See hook_metatag_bundled_config_alter() in the API documentation.
+  drupal_alter('metatag_bundled_config', $configs);
+
+  return $configs;
+}
+
+/**
+ * Implements hook_metatag_config_instance_info().
+ */
+function metatag_metatag_config_instance_info() {
+  $info['global']           = array('label' => t('Global'));
+  $info['global:frontpage'] = array('label' => t('Front page'));
+  $info['global:403']       = array('label' => t('403 access denied'));
+  $info['global:404']       = array('label' => t('404 page not found'));
+
+  // Add instance information for entities.
+  $entity_types = entity_get_info();
+  foreach ($entity_types as $entity_type => $entity_info) {
+    if (metatag_entity_supports_metatags($entity_type)) {
+      $info[$entity_type] = array('label' => $entity_info['label']);
+      foreach ($entity_info['bundles'] as $bundle => $bundle_info) {
+        if (count($entity_info['bundles'] == 1) && $bundle == $entity_type) {
+          // Skip default bundles (entities that do not really have bundles).
+          continue;
+        }
+        if (metatag_entity_supports_metatags($entity_type, $bundle)) {
+          $info[$entity_type . ':' . $bundle] = array('label' => $bundle_info['label']);
+        }
+      }
+    }
+  }
+
+  return $info;
+}
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_metatag_info() {
+  $info['groups']['basic'] = array(
+    'label' => t('Basic tags'),
+    'form' => array(
+      '#weight' => 1,
+      '#collapsed' => FALSE,
+    ),
+  );
+  $info['groups']['advanced'] = array(
+    'label' => t('Advanced tags'),
+    'form' => array(
+      '#weight' => 2,
+    ),
+  );
+
+  // "Simple" meta tags go first.
+  $weight = 0;
+
+  $info['tags']['title'] = array(
+    'label' => t('Page title'),
+    'description' => t("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."),
+    'class' => 'DrupalTitleMetaTag',
+    'group' => 'basic',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['description'] = array(
+    'label' => t('Description'),
+    'description' => t("A brief and concise summary of the page's content, preferably 150 characters or less. The description meta tag may be used by search engines to display a snippet about the page in search results."),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'basic',
+    'weight' => ++$weight,
+    'form' => array(
+      '#type' => 'textarea',
+      '#rows' => 2,
+      '#wysiwyg' => FALSE,
+    ),
+  );
+
+  $info['tags']['abstract'] = array(
+    'label' => t('Abstract'),
+    'description' => t("A brief and concise summary of the page's content, preferably 150 characters or less. The abstract meta tag may be used by search engines for archiving purposes."),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'basic',
+    'weight' => ++$weight,
+    'form' => array(
+      '#type' => 'textarea',
+      '#rows' => 2,
+      '#wysiwyg' => FALSE,
+    ),
+  );
+
+  $info['tags']['keywords'] = array(
+    'label' => t('Keywords'),
+    'description' => t("A comma-separated list of keywords about the page. This meta tag is <em>not</em> supported by most search engines anymore."),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'basic',
+    'weight' => ++$weight,
+  );
+
+  // More advanced meta tags.
+  $info['tags']['robots'] = array(
+    'label' => t('Robots'),
+    'description' => t("Provides search engines with specific directions for what to do when this page is indexed."),
+    'class' => 'DrupalListMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'form' => array(
+      '#options' => array(
+        '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.', array('!opendirectory' => 'http://www.dmoz.org/')),
+        'noydir' => t('Prevents Yahoo! from listing this page in the <a href="@ydir">Yahoo! Directory</a>.', array('@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.'),
+      ),
+    ),
+  );
+
+  $info['tags']['news_keywords'] = array(
+    'label' => t('Google News Keywords'),
+    'description' => t('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>.', array('@google_news' => 'http://support.google.com/news/publisher/bin/answer.py?hl=en&answer=68297')),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['standout'] = array(
+    'label' => t('Google Standout'),
+    'description' => t("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!", array('@google_news' => 'https://support.google.com/news/publisher/answer/191283?hl=en&ref_topic=2484650')),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['rating'] = array(
+    'label' => t('Content rating'),
+    'description' => t('Used to indicate the intended audience for the content.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'select_or_other' => TRUE,
+    'form' => array(
+      '#type' => 'select',
+      '#options' => array(
+        'general' => t('General'),
+        'mature' => t("Mature"),
+        'restricted' => t("Restricted"),
+        '14 years' => t("14 years or Older"),
+        'safe for kids' => t("Safe for kids"),
+      ),
+      '#empty_option' => t('- None -'),
+    ),
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['referrer'] = array(
+    'label' => t('Referrer policy'),
+    'description' => t('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.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'select_or_other' => TRUE,
+    'form' => array(
+      '#type' => 'select',
+      '#options' => array(
+        '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 -'),
+    ),
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['generator'] = array(
+    'label' => t('Generator'),
+    'description' => t("Describes the name and version number of the software or publishing tool used to create the page."),
+    'class' => 'DrupalTextMetaTag',
+    'header' => 'X-Generator',
+    'context' => array('global'),
+    'group' => 'advanced',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['rights'] = array(
+    'label' => t('Rights'),
+    'description' => t("Details about intellectual property, such as copyright or trademarks; does not automatically protect the site's content or intellectual property."),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'replaces' => array(
+      'copyright',
+    ),
+  );
+
+  $info['tags']['image_src'] = array(
+    'label' => t('Image'),
+    'description' => t("An image associated with this page, for use as a thumbnail in social networks and other services."),
+    'class' => 'DrupalLinkMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'image' => TRUE,
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  );
+
+  $info['tags']['canonical'] = array(
+    'label' => t('Canonical URL'),
+    'description' => t("Preferred page location or URL to help eliminate duplicate content for search engines."),
+    'class' => 'DrupalLinkMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'canonical',
+    ),
+  );
+
+  $info['tags']['shortlink'] = array(
+    'label' => t('Shortlink URL'),
+    'description' => t('A brief URL, often created by a URL shortening service.'),
+    'class' => 'DrupalLinkMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'replaces' => array(
+      'shorturl',
+    ),
+    'devel_generate' => array(
+      'type' => 'shortlink',
+    ),
+  );
+
+  $info['tags']['original-source'] = array(
+    'label' => t('Original Source'),
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'description' => t("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."),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  );
+
+  $info['tags']['prev'] = array(
+    'label' => t('Previous page URL'),
+    'description' => t('Used for paginated content. Meet Google recommendations to <a href="@google_pagination">indicate paginated content</a> by providing URL with rel="prev" link.', array('@google_pagination' => 'https://support.google.com/webmasters/answer/1663744')),
+    'class' => 'DrupalLinkMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  );
+
+  $info['tags']['next'] = array(
+    'label' => t('Next page URL'),
+    'description' => t('Used for paginated content. Meet Google recommendations to <a href="@google_pagination">indicate paginated content</a> by providing URL with rel="next" link.', array('@google_pagination' => 'https://support.google.com/webmasters/answer/1663744')),
+    'class' => 'DrupalLinkMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  );
+
+  $info['tags']['content-language'] = array(
+    'label' => t('Content language'),
+    'description' => t("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."),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'is_language' => TRUE,
+    'element' => array(
+      '#theme' => 'metatag_http_equiv',
+    ),
+  );
+
+  $info['tags']['geo.position'] = array(
+    'label' => t('Geo position'),
+    'description' => t('Geo-spatial information in "latitude;longitude" format, e.g. "50.167958;-97.133185"; <a href="http://en.wikipedia.org/wiki/Geotagging#HTML_pages">see Wikipedia for details</a>.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['geo.placename'] = array(
+    'label' => t('Geo place name'),
+    'description' => t("A location's formal name."),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['geo.region'] = array(
+    'label' => t('Geo region'),
+    'description' => t("A location's two-letter international country code, with an optional two-letter region, e.g. \"US-NH\" for New Hampshire in the USA."),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['icbm'] = array(
+    'label' => t('ICBM'),
+    'description' => t('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>.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+  );
+
+  $info['tags']['refresh'] = array(
+    'label' => t('Refresh'),
+    'description' => t('The number of seconds to wait before refreshing the page. May also force redirect to another page using the format "5; url=http://example.com/", which would be triggered after five seconds.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_http_equiv',
+    ),
+  );
+
+  $info['tags']['revisit-after'] = array(
+    'label' => t('Revisit After'),
+    'description' => t('Tell search engines when to index the page again. Very few search engines support this tag, it is more useful to use an <a href="@xmlsitemap">XML Sitemap</a> file.', array('@xmlsitemap' => 'https://www.drupal.org/project/xmlsitemap')),
+    'class' => 'DrupalDateIntervalMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  );
+
+  $info['tags']['pragma'] = array(
+    'label' => t('Pragma'),
+    'description' => t('Used to control whether a browser caches a specific page locally. Little used today. Should be used in conjunction with the Cache-Control meta tag.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_http_equiv',
+    ),
+  );
+
+  $info['tags']['cache-control'] = array(
+    'label' => t('Cache-Control'),
+    'description' => t('Used to control whether a browser caches a specific page locally. Little used today. Should be used in conjunction with the Pragma meta tag.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'advanced',
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_http_equiv',
+    ),
+  );
+
+  $info['tags']['expires'] = array(
+    'label' => t('Expires'),
+    'description' => t("Control when the browser's internal cache of the current page should expire. The date must to be an <a href=\"@rfc\">RFC-1123</a>-compliant date string that is represented in Greenwich Mean Time (GMT), e.g. 'Thu, 01 Sep 2016 00:12:56 GMT'. Set to '0' to stop the page being cached entirely.", array('@rfc' => 'http://www.csgnetwork.com/timerfc1123calc.html')),
+    'class' => 'DrupalTextMetaTag',
+    'weight' => ++$weight,
+    'group' => 'advanced',
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  );
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.migrate.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.migrate.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a9876cbb9157a8b65edeba122a8f138a40e064a3
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.migrate.inc
@@ -0,0 +1,128 @@
+<?php
+/**
+ * @file
+ * Metatag support for Migrate.
+ */
+
+if (!class_exists('MigrateDestinationHandler')) {
+  return;
+}
+
+/**
+ * Basic usage of the Migrate integration.
+ *
+ * This example assumes the custom module's name is "example_migrate".
+ *
+ * example_migrate.inc:
+ *
+ * class MetatagTestMigration extends DynamicMigration {
+ *
+ *   public function __construct() {
+ *     parent::__construct();
+ *
+ *     $this->description = t('Migrate test.');
+ *
+ *     $this->map = new MigrateSQLMap(
+ *       $this->machineName,
+ *       array(
+ *         'id' => array(
+ *           'type' => 'varchar',
+ *           'not null' => TRUE,
+ *           'length' => 254,
+ *           'description' => 'ID of record.',
+ *         ),
+ *       ),
+ *       MigrateDestinationNode::getKeySchema()
+ *     );
+ *
+ *     $this->source = new MigrateSourceCSV(
+ *       drupal_get_path('module', 'example_migrate') . '/sample.csv',
+ *       array(),
+ *       array('header_rows' => TRUE)
+ *     );
+ *
+ *     $this->destination = new MigrateDestinationNode('article');
+ *
+ *     $this->addFieldMapping('metatag_description', 'description');
+ *     $this->addFieldMapping('metatag_keywords', 'keywords');
+ *   }
+ * }
+ *
+ * example_migrate.migrate.inc:
+ *
+ * /**
+ *  * Implements hook_migrate_api().
+ *  * /
+ * function example_migrate_migrate_api() {
+ *   $api = array(
+ *     'api' => 2,
+ *     'migrations' => array(
+ *       'MetatagTest' => array('class_name' => 'MetatagTestMigration'),
+ *     ),
+ *   );
+ *
+ *   return $api;
+ * }
+ */
+
+/**
+ * Implements hook_migrate_api().
+ */
+function metatag_migrate_api() {
+  $api = array(
+    'api' => 2,
+    'destination handlers' => array(
+      'MigrateMetatagHandler',
+    ),
+  );
+
+  return $api;
+}
+
+/**
+ * Metatag destination handler.
+ */
+class MigrateMetatagHandler extends MigrateDestinationHandler {
+
+  /**
+   * Identify a list of supported entity types.
+   */
+  public function __construct() {
+    $entity_types = metatag_entity_supports_metatags();
+    $entity_types = array_filter($entity_types);
+    $entity_types = array_keys($entity_types);
+
+    $this->registerTypes($entity_types);
+  }
+
+  /**
+   * Implements MigrateDestinationHandler::fields().
+   */
+  public function fields() {
+    $fields = array();
+    $elements = metatag_get_info();
+
+    foreach ($elements['tags'] as $value) {
+      $metatag_field = 'metatag_' . $value['name'];
+      $fields[$metatag_field] = $value['description'];
+    }
+
+    return $fields;
+  }
+
+  /**
+   * Implements MigrateDestinationHandler::prepare().
+   */
+  public function prepare($entity, stdClass $row) {
+    $elements = metatag_get_info();
+
+    foreach ($elements['tags'] as $value) {
+      $metatag_field = 'metatag_' . $value['name'];
+      if (isset($entity->$metatag_field)) {
+        $language = isset($entity->language) ? $entity->language : LANGUAGE_NONE;
+        $entity->metatags[$language][$value['name']]['value'] = $entity->$metatag_field;
+        unset($entity->$metatag_field);
+      }
+    }
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.module b/profiles/wcm_base/modules/contrib/metatag/metatag.module
new file mode 100644
index 0000000000000000000000000000000000000000..a44128327f11015c3c07be463761092e7a777a00
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.module
@@ -0,0 +1,3140 @@
+<?php
+
+/**
+ * @file
+ * Primary hook implementations for Metatag.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function metatag_help($path, $arg) {
+  if ($path == 'admin/config/search/metatags') {
+    return '<p>' . t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.') . '</p>';
+  }
+  elseif ($path == 'admin/help#metatag') {
+    return '<p>' . t('The Metatag module provides a options to let each page have customized meta data added to the "meta" tags in the HEAD section of the document.') . '</p>';
+  }
+  elseif ($path == 'admin/config/search/metatags/bulk-revert') {
+    return '<p>' . t('This form <strong>will wipe out</strong> all custom meta tags for the selected entities, reverting them to the default configuration assigned at the <a href="@url">Defaults tab</a>. For example, if the meta tags are changed for an article they will be removed if the "Node: Article" checkbox is selected.', array('@url' => url('admin/config/search/metatags'))) . '</p>';
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_theme() {
+  $info['metatag'] = array(
+    'render element' => 'element',
+    'file' => 'metatag.theme.inc',
+  );
+  $info['metatag_http_equiv'] = array(
+    'render element' => 'element',
+    'file' => 'metatag.theme.inc',
+  );
+  $info['metatag_link_rel'] = array(
+    'render element' => 'element',
+    'file' => 'metatag.theme.inc',
+  );
+  $info['metatag_link_rev'] = array(
+    'render element' => 'element',
+    'file' => 'metatag.theme.inc',
+  );
+  $info['metatag_property'] = array(
+    'render element' => 'element',
+    'file' => 'metatag.theme.inc',
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function metatag_ctools_plugin_directory($owner, $plugin_type) {
+  if ($owner == 'ctools' && $plugin_type == 'content_types') {
+    return "plugins/$plugin_type";
+  }
+}
+
+/**
+ * Implements hook_hook_info().
+ */
+function metatag_hook_info() {
+  $hooks = array(
+    'metatag_config_default',
+    'metatag_config_default_alter',
+    'metatag_config_delete',
+    'metatag_config_insert',
+    'metatag_config_instance_info',
+    'metatag_config_instance_info_alter',
+    'metatag_config_load',
+    'metatag_config_load_presave',
+    'metatag_config_update',
+    'metatag_info',
+    'metatag_info_alter',
+  );
+
+  return array_fill_keys($hooks, array('group' => 'metatag'));
+}
+
+/**
+ * Implements hook_permission().
+ */
+function metatag_permission() {
+  $permissions['administer meta tags'] = array(
+    'title' => t('Administer meta tags'),
+    'restrict access' => TRUE,
+    'description' => t('Control the main settings pages and modify per-object meta tags.'),
+  );
+  $permissions['edit meta tags'] = array(
+    'title' => t('Edit meta tags'),
+    'description' => t('Modify meta tags on individual entity records (nodes, terms, users, etc).'),
+  );
+
+  // Optional extended edit permissions.
+  if (variable_get('metatag_extended_permissions', FALSE)) {
+    $permissions['edit meta tags']['description'] .= '<br />' . t('<em>Extended Permissions</em> has been enabled. Roles have the :admin permission will see all meta tags on edit forms, otherwise the permissions below will control which meta tags are available and are needed in addition to <em>Edit meta tags</em>.', array(':admin' => t('Administer meta tags')));
+    $metatags = metatag_get_info();
+    foreach ($metatags['tags'] as $metatag_name => $metatag) {
+      $permissions['edit meta tag: ' . $metatag_name] = array(
+        'title' => t('Extended permission: Edit :tag meta tag', array(':tag' => $metatag['label'])),
+        'description' => t('Customize the :tag meta tag on individual forms.', array(':tag' => $metatag['label'])),
+      );
+    }
+  }
+
+  return $permissions;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function metatag_menu() {
+  $items['admin/config/search/metatags'] = array(
+    'title' => 'Metatag',
+    'description' => 'Configure Metatag defaults.',
+    'page callback' => 'metatag_config_overview',
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag.admin.inc',
+  );
+  $items['admin/config/search/metatags/config'] = array(
+    'title' => 'Defaults',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/config/search/metatags/config/add'] = array(
+    'title' => 'Add default meta tags',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_config_add_form'),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag.admin.inc',
+    'type' => MENU_LOCAL_ACTION,
+  );
+  $items['admin/config/search/metatags/config/%metatag_config'] = array(
+    'title callback' => 'metatag_config_title',
+    'title arguments' => array(5),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_config_edit_form', 5),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag.admin.inc',
+  );
+  $items['admin/config/search/metatags/config/%metatag_config/edit'] = array(
+    'title' => 'Edit',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/config/search/metatags/config/%metatag_config/enable'] = array(
+    'title' => 'Enable',
+    'page callback' => 'metatag_config_enable',
+    'page arguments' => array(5),
+    'access callback' => 'metatag_config_access',
+    'access arguments' => array('enable', 5),
+    'file' => 'metatag.admin.inc',
+  );
+  $items['admin/config/search/metatags/config/%metatag_config/disable'] = array(
+    'title' => 'Disable',
+    'page callback' => 'metatag_config_disable',
+    'page arguments' => array(5),
+    'access callback' => 'metatag_config_access',
+    'access arguments' => array('disable', 5),
+    'file' => 'metatag.admin.inc',
+  );
+  $items['admin/config/search/metatags/config/%metatag_config/revert'] = array(
+    'title' => 'Revert',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_config_delete_form', 5),
+    'access callback' => 'metatag_config_access',
+    'access arguments' => array('revert', 5),
+    'file' => 'metatag.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['admin/config/search/metatags/config/%metatag_config/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_config_delete_form', 5),
+    'access callback' => 'metatag_config_access',
+    'access arguments' => array('delete', 5),
+    'file' => 'metatag.admin.inc',
+  );
+  $items['admin/config/search/metatags/config/%metatag_config/export'] = array(
+    'title' => 'Export',
+    'page callback' => 'metatag_config_export_form',
+    'page arguments' => array(5),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 10,
+  );
+  $items['admin/config/search/metatags/settings'] = array(
+    'title' => 'Settings',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_admin_settings_form'),
+    'access arguments' => array('administer meta tags'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 30,
+    'file' => 'metatag.admin.inc',
+  );
+  $items['admin/config/search/metatags/bulk-revert'] = array(
+    'title' => 'Bulk revert',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_bulk_revert_form'),
+    'access arguments' => array('administer meta tags'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 40,
+    'file' => 'metatag.admin.inc',
+  );
+
+  // Optional integration with the i18n_string module for translating the
+  // configurations. Note: this should also check for 'metatag_i18n_disabled'
+  // but doing so would require rebuilding the menu cache every time the Metatag
+  // settings page was saved, which may not be advised. Instead the links to
+  // these pages on the config pages *do* check the variable, which is close
+  // enough.
+  if (module_exists('i18n_string')) {
+    $items['admin/config/search/metatags/config/%metatag_config/translate'] = array(
+      'title' => 'Translate',
+      'access arguments' => array('administer meta tags'),
+      'page callback' => 'i18n_string_object_translate_page',
+      'page arguments' => array('metatag_config', 5),
+      'type' => MENU_LOCAL_TASK,
+    );
+    $items['admin/config/search/metatags/config/%metatag_config/translate/%i18n_language'] = array(
+      'title' => 'Translate',
+      'access arguments' => array('administer meta tags'),
+      'page callback' => 'i18n_string_object_translate_page',
+      'page arguments' => array('metatag_config', 5, 7),
+      'type' => MENU_CALLBACK,
+    );
+  }
+
+  return $items;
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function metatag_flush_caches() {
+  return array('cache_metatag');
+}
+
+/**
+ * Load a metatag configuration record with all the defaults merged in.
+ *
+ * For example, given the configuration instance 'node:article', this function
+ * will load the configuration records for 'node:article', then 'node', and
+ * then finally 'global', with each attempt using an array merge.
+ *
+ * The levels of defaults is arranged by splitting the $instance variable by
+ * the colon character, and always using a 'global' instance at the end.
+ */
+function metatag_config_load_with_defaults($instance, $include_global = TRUE) {
+  $defaults = &drupal_static(__FUNCTION__, array());
+
+  // Use the current page's locale.
+  $langcode = $GLOBALS['language_content']->language;
+
+  // Statically cache defaults since they can include multiple levels.
+  $cid = "config:{$instance}:{$langcode}" . ($include_global ? ':withglobal' : ':withoutglobal');
+
+  if (!isset($defaults[$cid])) {
+    if ($cache = metatag_cache_get($cid)) {
+      $defaults[$cid] = $cache->data;
+    }
+    else {
+      $defaults[$cid] = array();
+      $instances = metatag_config_get_parent_instances($instance, $include_global);
+      $configs = metatag_config_load_multiple($instances);
+      foreach ($instances as $key) {
+        // Ignore disabled configurations.
+        if (!isset($configs[$key]) || !empty($configs[$key]->disabled)) {
+          continue;
+        }
+
+        // Add config to the defaults array.
+        if (!empty($configs[$key]->config)) {
+          $defaults[$cid] += $configs[$key]->config;
+        }
+      }
+
+      metatag_cache_set($cid, $defaults[$cid]);
+    }
+  }
+
+  return $defaults[$cid];
+}
+
+/**
+ * Load a metatag configuration record.
+ */
+function metatag_config_load($instance) {
+  $results = metatag_config_load_multiple(array($instance));
+  return !empty($results[$instance]) ? $results[$instance] : FALSE;
+}
+
+/**
+ * Load multiple metatag configuration records.
+ */
+function metatag_config_load_multiple(array $instances) {
+  // Load the data.
+  ctools_include('export');
+  $configs = ctools_export_load_object('metatag_config', 'names', $instances);
+
+  // "Fix" any records that might be using old values. Ideally these will be
+  // permanently fixed by being re-saved or re-exported.
+  foreach (metatag_config_get_replacements() as $old_tag => $new_tag) {
+    foreach ($configs as $instance => $config) {
+      if (isset($config->config[$old_tag])) {
+        $config->config[$new_tag] = $config->config[$old_tag];
+        unset($config->config[$old_tag]);
+      }
+    }
+  }
+
+  // Translate the configuration.
+  if (module_exists('i18n_string') && !variable_get('metatag_i18n_disabled', FALSE)) {
+    $options = array();
+
+    // By default disable the watchdog logging of translation messages.
+    $options['watchdog'] = variable_get('metatag_i18n_enable_watchdog', FALSE);
+
+    foreach ($configs as $instance => &$config) {
+      foreach ($config->config as $tag => &$value) {
+        if (isset($value['value']) && is_string($value['value'])) {
+          $value['value'] = i18n_string_translate(array(
+            'metatag',
+            'metatag_config',
+            $instance,
+            $tag,
+          ),
+          $value['value'],
+          $options);
+        }
+      }
+    }
+  }
+
+  return $configs;
+}
+
+/**
+ * Identify the meta tags that have been deprecated and replaced by others.
+ */
+function metatag_config_get_replacements() {
+  $replacements = &drupal_static(__FUNCTION__);
+
+  if (!isset($replacements)) {
+    $replacements = array();
+
+    foreach (metatag_get_info('tags') as $tag_name => $tag_info) {
+      if (!empty($tag_info['replaces'])) {
+        if (!is_array($tag_info['replaces'])) {
+          $tag_info['replaces'] = array($tag_info['replaces']);
+        }
+        foreach ($tag_info['replaces'] as $replaces) {
+          $replacements[$replaces] = $tag_name;
+        }
+      }
+    }
+  }
+
+  return $replacements;
+}
+
+/**
+ * Save a metatag configuration record to the database.
+ */
+function metatag_config_save($config) {
+  $config->is_new = empty($config->cid);
+
+  // Allow modules to alter the configuration before it is saved using
+  // hook_metatag_config_presave().
+  module_invoke_all('metatag_config_presave', $config);
+
+  if ($config->is_new) {
+    drupal_write_record('metatag_config', $config);
+
+    // Allow modules to act upon the record insertion using
+    // hook_metatag_config_insert().
+    module_invoke_all('metatag_config_insert', $config);
+  }
+  else {
+    drupal_write_record('metatag_config', $config, array('cid'));
+
+    // Allow modules to act upon the record update using
+    // hook_metatag_config_insert().
+    module_invoke_all('metatag_config_update', $config);
+  }
+
+  unset($config->is_new);
+
+  // Clear any caches.
+  metatag_config_cache_clear();
+}
+
+/**
+ * Delete a metatag configuration record.
+ */
+function metatag_config_delete($config) {
+  db_delete('metatag_config')
+    ->condition('instance', $config->instance)
+    ->execute();
+
+  // Allow modules to act upon the record deletion using
+  // hook_metatag_config_delete().
+  module_invoke_all('metatag_config_delete', $config);
+
+  // Clear any caches.
+  metatag_config_cache_clear();
+}
+
+/**
+ * Clear the metatag configuration cache.
+ */
+function metatag_config_cache_clear() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  drupal_static_reset('metatag_config_load_with_defaults');
+  drupal_static_reset('metatag_entity_supports_metatags');
+  drupal_static_reset('metatag_config_instance_info');
+  drupal_static_reset('metatag_get_info');
+  ctools_include('export');
+  ctools_export_load_object_reset('metatag_config');
+}
+
+/**
+ * Load an entity's tags.
+ *
+ * @param string $entity_type
+ *   The entity type to load.
+ * @param int $entity_id
+ *   The ID of the entity to load.
+ * @param mixed $revision_id
+ *   Optional revision ID to load instead of the entity ID.
+ *
+ * @return array
+ *   An array of tag data keyed by language for the entity's current active
+ *   revision.
+ */
+function metatag_metatags_load($entity_type, $entity_id, $revision_id = NULL) {
+  // A specific revision ID was not requested, so get the active revision ID.
+  if (is_null($revision_id)) {
+    // Unfortunately, the only way of getting the active revision ID is to
+    // first load the entity, and then extract the ID. This is a bit
+    // performance intensive, but it seems to be the only way of doing it.
+    $entities = entity_load($entity_type, array($entity_id));
+    if (!empty($entities[$entity_id])) {
+      // We only care about the revision_id.
+      list(, $revision_id,) = entity_extract_ids($entity_type, $entities[$entity_id]);
+    }
+  }
+
+  // This returns an array nested by the entity ID, the revision ID and the
+  // langcode.
+  $metatags = metatag_metatags_load_multiple($entity_type, array($entity_id), array($revision_id));
+
+  // Look for records for the requested revision ID.
+  if (isset($metatags[$entity_id][$revision_id])) {
+    return $metatags[$entity_id][$revision_id];
+  }
+
+  // Getting to this point means that no meta tags were identified earlier, so
+  // return an empty array.
+  return array();
+}
+
+/**
+ * Load tags for multiple entities.
+ *
+ * @param string $entity_type
+ *   The entity type to load.
+ * @param array $entity_ids
+ *   The list of entity IDs.
+ * @param array $revision_ids
+ *   Optional revision ID to load instead of the entity ID.
+ *
+ * @return array
+ *   An array of tag data, keyed by entity ID, revision ID and language.
+ */
+function metatag_metatags_load_multiple($entity_type, array $entity_ids, array $revision_ids = array()) {
+  // Double check entity IDs are all numeric.
+  $entity_ids = array_filter($entity_ids, 'is_numeric');
+  if (empty($entity_ids)) {
+    return array();
+  }
+
+  // Ensure that the revision IDs are all numeric too.
+  $revision_ids = array_filter($revision_ids, 'is_numeric');
+
+  // Verify that there aren't any empty values copied in from
+  // metatag_metatags_load(). Note: a zero indicates that the entity record does
+  // not support revisions, so this is ok to do.
+  $revision_ids = array_filter($revision_ids);
+
+  // Also need to check if the metatag table exists since this condition could
+  // fire before the table has been installed yet.
+  if (!variable_get('metatag_schema_installed', FALSE)) {
+    if (db_table_exists('metatag')) {
+      variable_set('metatag_schema_installed', TRUE);
+    }
+    else {
+      watchdog('metatag', 'The system tried to load metatag data before the schema was fully loaded.', array(), WATCHDOG_WARNING);
+      return array();
+    }
+  }
+
+  // Verify that the metatag.revision_id field has been added to the {metatag}
+  // table schema.
+  if (!variable_get('metatag_has_revision_id', FALSE)) {
+    if (db_field_exists('metatag', 'revision_id')) {
+      variable_set('metatag_has_revision_id', TRUE);
+    }
+    else {
+      watchdog('metatag', 'The database updates need to be ran.', array(), WATCHDOG_WARNING);
+      return array();
+    }
+  }
+
+  // Get all translations of tag data for this entity.
+  $query = db_select('metatag', 'm')
+    ->fields('m', array('entity_id', 'revision_id', 'language', 'data'))
+    ->condition('m.entity_type', $entity_type);
+  // Filter by revision_ids if they are available. If not, filter by entity_ids.
+  if (!empty($revision_ids)) {
+    $query->condition('m.revision_id', $revision_ids, 'IN');
+  }
+  else {
+    $query->condition('m.entity_id', $entity_ids, 'IN');
+  }
+  $result = $query->execute();
+
+  // Marshal it into an array keyed by entity ID. Each value is an array of
+  // translations keyed by language code.
+  $metatags = array();
+  while ($record = $result->fetchObject()) {
+    $data = unserialize($record->data);
+
+    // "Fix" any records that might be using old values. Ideally these will be
+    // permanently fixed by being re-saved or re-exported.
+    foreach (metatag_config_get_replacements() as $old_tag => $new_tag) {
+      if (isset($data[$old_tag])) {
+        $data[$new_tag] = $data[$old_tag];
+        unset($data[$old_tag]);
+      }
+    }
+
+    $metatags[$record->entity_id][$record->revision_id][$record->language] = $data;
+  }
+
+  return $metatags;
+}
+
+/**
+ * Save an entity's tags.
+ *
+ * @param string $entity_type
+ *   The entity type to load.
+ * @param int $entity_id
+ *   The entity's primary ID.
+ * @param int $revision_id
+ *   The entity's revision ID.
+ * @param array $metatags
+ *   All of the tag information, keyed by the language code. Most meta tags use
+ *   the 'value' element, so the structure should look like:
+ *   array(
+ *     LANGUAGE_NONE => array(
+ *       'title' => array(
+ *         'value' => "This node's title!",
+ *       ),
+ *       'og:title' => array(
+ *         'value' => "This node's title for Open Graph!",
+ *       ),
+ *       'og:image' => array(
+ *         'value' => "[node:field_thumbnail]",
+ *       ),
+ *     ),
+ *   );.
+ * @param string|null $bundle
+ *   The bundle of the entity that is being saved. Optional.
+ */
+function metatag_metatags_save($entity_type, $entity_id, $revision_id, $metatags, $bundle = NULL) {
+  // Check that $entity_id is numeric because of Entity API and string IDs.
+  if (!is_numeric($entity_id)) {
+    return;
+  }
+
+  // Don't do anything if the entity type is not supported.
+  if (!metatag_entity_supports_metatags($entity_type)) {
+    return;
+  }
+
+  // Verify the entity bundle is supported, if not available just check the
+  // entity type.
+  if (!empty($bundle)) {
+    if (!metatag_entity_supports_metatags($entity_type, $bundle)) {
+      return;
+    }
+  }
+  else {
+    if (!metatag_entity_supports_metatags($entity_type)) {
+      return;
+    }
+  }
+
+  // The revision_id must be a numeric value; some entities use NULL for the
+  // revision so change that to a zero.
+  if (is_null($revision_id)) {
+    $revision_id = 0;
+  }
+
+  // Handle scenarios where the metatags are completely empty, this will have
+  // the effect of erasing the meta tags for those this entity.
+  if (empty($metatags)) {
+    $metatags = array();
+    // Add an empty array record for each language.
+    $languages = db_query("SELECT language
+        FROM {metatag}
+        WHERE (entity_type = :type)
+        AND (entity_id = :id)
+        AND (revision_id = :revision)",
+      array(
+        ':type'     => $entity_type,
+        ':id'       => $entity_id,
+        ':revision' => $revision_id,
+      ))->fetchCol();
+    foreach ($languages as $oldlang) {
+      $metatags[$oldlang] = array();
+    }
+  }
+
+  // Update each of the per-language metatag configurations in turn.
+  foreach ($metatags as $langcode => $new_metatags) {
+    // Allow other modules to alter the meta tags prior to saving using
+    // hook_metatag_presave().
+    foreach (module_implements('metatag_presave') as $module) {
+      $function = "{$module}_metatag_presave";
+      $function($new_metatags, $entity_type, $entity_id, $revision_id, $langcode);
+    }
+
+    // If the data array is empty, there is no data to actually save, so just
+    // delete the record from the database.
+    if (empty($new_metatags)) {
+      db_delete('metatag')
+        ->condition('entity_type', $entity_type)
+        ->condition('entity_id', $entity_id)
+        ->condition('revision_id', $revision_id)
+        ->condition('language', $langcode)
+        ->execute();
+    }
+    // Otherwise save the data for this entity.
+    else {
+      db_merge('metatag')
+        ->key(array(
+          'entity_type' => $entity_type,
+          'entity_id' => $entity_id,
+          'language' => $langcode,
+          'revision_id' => $revision_id,
+        ))
+        ->fields(array(
+          'data' => serialize($new_metatags),
+        ))
+        ->execute();
+    }
+  }
+
+  // Clear cached data.
+  metatag_metatags_cache_clear($entity_type, $entity_id);
+
+  // Clear the entity cache.
+  entity_get_controller($entity_type)->resetCache(array($entity_id));
+}
+
+/**
+ * Delete an entity's tags.
+ *
+ * @param string $entity_type
+ *   The entity type.
+ * @param int $entity_id
+ *   The entity's ID.
+ * @param int $revision_id
+ *   The entity's VID.
+ * @param string $langcode
+ *   The language ID of the entry to delete. If left blank, all language
+ *   entries for this entity will be deleted.
+ */
+function metatag_metatags_delete($entity_type, $entity_id, $revision_id = NULL, $langcode = NULL) {
+  $revision_ids = array();
+  if (!empty($revision_id)) {
+    $revision_ids[] = $revision_id;
+  }
+  return metatag_metatags_delete_multiple($entity_type, array($entity_id), $revision_ids, $langcode);
+}
+
+/**
+ * Delete multiple entities' tags.
+ *
+ * @param string $entity_type
+ *   The entity type.
+ * @param array $entity_ids
+ *   The list of IDs.
+ * @param array $revision_ids
+ *   An optional list of revision IDs; if omitted all revisions will be deleted.
+ * @param string $langcode
+ *   The language ID of the entities to delete. If left blank, all language
+ *   entries for the enities will be deleted.
+ *
+ * @return bool
+ *   If any problems were encountered will return FALSE, otherwise TRUE.
+ */
+function metatag_metatags_delete_multiple($entity_type, array $entity_ids, array $revision_ids = array(), $langcode = NULL) {
+  // Double check entity IDs and revision IDs are numeric.
+  $entity_ids = array_filter($entity_ids, 'is_numeric');
+  $revision_ids = array_filter($revision_ids, 'is_numeric');
+
+  if (!empty($entity_ids) || !empty($revision_ids)) {
+    $transaction = db_transaction();
+    try {
+      // Let other modules know about the records being deleted using
+      // hook_metatag_metatags_delete().
+      module_invoke_all('metatag_metatags_delete', $entity_type, $entity_ids, $revision_ids, $langcode);
+
+      // Set the entity to delete.
+      $query = db_delete('metatag')
+        ->condition('entity_type', $entity_type);
+
+      // If revision IDs were specified then just use those in the query.
+      if (!empty($revision_ids)) {
+        $query->condition('revision_id', $revision_ids, 'IN');
+      }
+      // No revision IDs were specified, so work from the entity IDs.
+      else {
+        $query->condition('entity_id', $entity_ids, 'IN');
+      }
+
+      // Limit to a language if one was specified.
+      if (!empty($langcode)) {
+        $query->condition('language', $langcode);
+      }
+
+      // Perform the deletion(s).
+      $query->execute();
+
+      // Clear cached data.
+      metatag_metatags_cache_clear($entity_type, $entity_ids);
+
+      // Clear the caches for these entities.
+      entity_get_controller($entity_type)->resetCache($entity_ids);
+
+      return TRUE;
+    }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception('metatag', $e);
+      throw $e;
+    }
+  }
+  else {
+    watchdog('metatag', 'No entity IDs or revision IDs were submitted to metatag_metatags_delete_multiple().');
+  }
+
+  return FALSE;
+}
+
+/**
+ * Clear the cached records for a given entity type or entity ID.
+ *
+ * @param string $entity_type
+ *   The entity type to clear.
+ */
+function metatag_metatags_cache_clear($entity_type, $entity_ids = NULL) {
+  if (empty($entity_ids)) {
+    cache_clear_all("output:$entity_type", 'cache_metatag', TRUE);
+  }
+  else {
+    if (!is_array($entity_ids)) {
+      $entity_ids = array($entity_ids);
+    }
+    foreach ($entity_ids as $entity_id) {
+      cache_clear_all("output:$entity_type:$entity_id", 'cache_metatag');
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_load().
+ */
+function metatag_entity_load($entities, $entity_type) {
+  // Wrap this in a try-catch block to work around occasions when the schema
+  // hasn't been updated yet.
+  try {
+    if (metatag_entity_supports_metatags($entity_type)) {
+      // Get the revision_ids.
+      $revision_ids = array();
+
+      // Track the entity IDs for values to load.
+      $entity_ids = array();
+
+      // Some entities don't support revisions.
+      $supports_revisions = TRUE;
+
+      // Extract the revision ID and verify the entity's bundle is supported.
+      foreach ($entities as $key => $entity) {
+        list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+
+        // Verify that each entity bundle supports Metatag.
+        if (metatag_entity_supports_metatags($entity_type, $bundle)) {
+          $entity_ids[] = $entity_id;
+
+          if (!empty($revision_id)) {
+            $revision_ids[] = $revision_id;
+          }
+        }
+      }
+
+      // Only proceed if either there were revision IDs identified, or the
+      // entity doesn't support revisions anyway.
+      if (!empty($entity_ids)) {
+        // Load all meta tags for these entities.
+        $metatags = metatag_metatags_load_multiple($entity_type, $entity_ids, $revision_ids);
+
+        // Assign the metatag records for the correct revision ID.
+        if (!empty($metatags)) {
+          foreach ($entities as $entity_id => $entity) {
+            list($entity_id, $revision_id) = entity_extract_ids($entity_type, $entity);
+            $revision_id = intval($revision_id);
+            $entities[$entity_id]->metatags = isset($metatags[$entity_id][$revision_id]) ? $metatags[$entity_id][$revision_id] : array();
+          }
+        }
+      }
+    }
+  }
+  catch (Exception $e) {
+    watchdog('metatag', 'Error loading meta tag data, do the <a href="@update">database updates</a> need to be run? The error occurred when loading record(s) %ids for the %type entity type. The error message was: %error',
+      array(
+        '@update' => base_path() . 'update.php',
+        '%ids' => implode(', ', array_keys($entities)),
+        '%type' => $entity_type,
+        '%error' => $e->getMessage(),
+      ),
+    WATCHDOG_WARNING);
+
+    // Don't display the same message twice for Drush.
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Run your updates, like drush updb.'));
+    }
+    // Only message people who can see it in watchdog and can likely fix it.
+    elseif (user_access('access site reports')) {
+      drupal_set_message(t('Error loading meta tag data, do the <a href="@update">database updates</a> need to be run?', array('@update' => base_path() . 'update.php')), 'error');
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_insert().
+ */
+function metatag_entity_insert($entity, $entity_type) {
+  if (isset($entity->metatags)) {
+    list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+
+    // Verify that this entity type / bundle is supported.
+    if (!metatag_entity_supports_metatags($entity_type, $bundle)) {
+      return;
+    }
+
+    $revision_id = intval($revision_id);
+
+    // Determine the entity's language.
+    $langcode = entity_language($entity_type, $entity);
+
+    // Unfortunately due to how core works, the normal entity_language()
+    // function returns 'und' instead of the node's language during node
+    // creation.
+    if ((empty($langcode) || $langcode == LANGUAGE_NONE) && !empty($entity->language)) {
+      $langcode = $entity->language;
+    }
+
+    // If no language was still found, use the 'no language' value.
+    if (empty($langcode)) {
+      $langcode = LANGUAGE_NONE;
+    }
+
+    // Work-around for initial entity creation where a language was selection
+    // but where it's different to the form's value.
+    if (!isset($entity->metatags[$langcode]) && isset($entity->metatags[LANGUAGE_NONE])) {
+      $entity->metatags[$langcode] = $entity->metatags[LANGUAGE_NONE];
+      unset($entity->metatags[LANGUAGE_NONE]);
+    }
+
+    // Support for Workbench Moderation.
+    if ($entity_type == 'node' && _metatag_isdefaultrevision($entity)) {
+      return;
+    }
+
+    metatag_metatags_save($entity_type, $entity_id, $revision_id, $entity->metatags, $bundle);
+  }
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function metatag_entity_update($entity, $entity_type) {
+  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  // If this entity object isn't allowed meta tags, don't continue.
+  if (!metatag_entity_supports_metatags($entity_type, $bundle)) {
+    return;
+  }
+
+  $revision_id = intval($revision_id);
+
+  if (isset($entity->metatags)) {
+    // Determine the entity's new language. This will always be accurate as the
+    // language value will already have been updated by the time this function
+    // executes, and it will be loaded for the correct edit process.
+    $new_language = metatag_entity_get_language($entity_type, $entity);
+
+    // If applicable, determine the entity's original language. This cannot be
+    // obtained via the normal API as that data will already have been updated,
+    // instead check to see if the entity has an old-fasioned 'language' value.
+    if (isset($entity->original) && isset($entity->language) && isset($entity->original->language)) {
+      $old_language = $entity->original->language;
+
+      // If the language has changed then additional checking needs to be done.
+      // Need to compare against the entity's raw language value as they will
+      // be different when updating a translated entity, versus an untranslated
+      // entity or a source entity for translation, and give a false positive.
+      if ($new_language == $entity->language && $new_language != $old_language) {
+        // If this entity is not translated, or if it is translated but the
+        // translation was previously created, then some language cleanup needs
+        // to be done.
+        if (!isset($entity->translation) || (isset($entity->translation) && !empty($entity->translation['created']))) {
+          // Delete the old language record. This will not affect old revisions.
+          db_delete('metatag')
+            ->condition('entity_type', $entity_type)
+            ->condition('entity_id', $entity_id)
+            ->condition('revision_id', $revision_id)
+            ->condition('language', $old_language)
+            ->execute();
+
+          // Swap out the metatag values for the two languages.
+          if (isset($entity->metatags[$old_language])) {
+            $entity->metatags[$new_language] = $entity->metatags[$old_language];
+            unset($entity->metatags[$old_language]);
+          }
+        }
+      }
+    }
+
+    // Support for Workbench Moderation.
+    if ($entity_type == 'node' && _metatag_isdefaultrevision($entity)) {
+      return;
+    }
+
+    // Save the record.
+    metatag_metatags_save($entity_type, $entity_id, $revision_id, $entity->metatags, $bundle);
+  }
+  else {
+    // Still ensure the meta tag output is cached.
+    metatag_metatags_cache_clear($entity_type, $entity_id);
+  }
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function metatag_entity_delete($entity, $entity_type) {
+  list($entity_id) = entity_extract_ids($entity_type, $entity);
+  metatag_metatags_delete($entity_type, $entity_id);
+}
+
+/**
+ * Implements hook_field_attach_delete_revision().
+ */
+function metatag_field_attach_delete_revision($entity_type, $entity) {
+  list($entity_id, $revision_id) = entity_extract_ids($entity_type, $entity);
+  $revision_id = intval($revision_id);
+  metatag_metatags_delete($entity_type, $entity_id, $revision_id);
+}
+
+/**
+ * Build and alter metatag instance name.
+ *
+ * @param object $entity
+ *   The entity object to generate the metatags instance name for.
+ * @param string $entity_type
+ *   The entity type of the entity.
+ * @param string $bundle
+ *   The bundle of the entity.
+ *
+ * @return string
+ *   The resulting name of the config instance.
+ */
+function metatag_get_entity_metatags_instance($entity, $entity_type, $bundle) {
+  $instance = "{$entity_type}:{$bundle}";
+  drupal_alter('metatag_get_entity_metatags_instance', $instance, $entity, $entity_type, $bundle);
+  return $instance;
+}
+
+/**
+ * Implements hook_entity_view().
+ *
+ * Provides additional argument to allow the display to be forced, to work
+ * around problems elsewhere in the APIs.
+ */
+function metatag_entity_view($entity, $entity_type, $view_mode, $langcode, $force = FALSE) {
+  // Only run this function once per page load, for an entity which is allowed
+  // metatags.
+  static $i_will_say_this_only_once = FALSE;
+
+  // Only proceed if this entity object is the page being viewed.
+  if (_metatag_entity_is_page($entity_type, $entity)) {
+    // Get the entity's extra information.
+    list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+
+    // If this entity object isn't allowed meta tags, don't continue.
+    if (!metatag_entity_supports_metatags($entity_type, $bundle)) {
+      return;
+    }
+
+    // Some API calls need to force the data loading.
+    if (!$force) {
+      // Only run this function once per page load.
+      if ($i_will_say_this_only_once) {
+        return;
+      }
+      $i_will_say_this_only_once = TRUE;
+    }
+
+    // CTools uses 'page_manager' view mode to indicate the full entity display
+    // page rather than 'full', so streamline the internal processes.
+    if ($view_mode == 'page_manager') {
+      $view_mode = 'full';
+    }
+
+    // Generate metatags output.
+    if ($output = metatag_generate_entity_metatags($entity, $entity_type, $langcode, $view_mode)) {
+      $instance = metatag_get_entity_metatags_instance($entity, $entity_type, $bundle);
+      // We need to register the term's metatags, so we can later fetch them.
+      // @see metatag_page_build().
+      metatag_page_set_metatags($instance, $output);
+    }
+  }
+}
+
+/**
+ * Generate the metatags for a given entity.
+ *
+ * @param object $entity
+ *   The entity object to generate the metatags for.
+ * @param string $entity_type
+ *   The entity type of the entity.
+ * @param string $langcode
+ *   The language code used for rendering the entity.
+ * @param string $view_mode
+ *   The view mode the entity is rendered in.
+ * @param bool $cached
+ *   TRUE if metatags can be loaded from and saved to the cache. FALSE if the
+ *   cache should be bypassed.
+ *
+ * @return mixed
+ *   A renderable array of metatags for the given entity.
+ *   If this entity object isn't allowed meta tags, return FALSE (empty).
+ */
+function metatag_generate_entity_metatags($entity, $entity_type, $langcode = NULL, $view_mode = 'full', $cached = TRUE) {
+  // Obtain some details of the entity that are needed elsewhere.
+  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  // If this entity object isn't allowed meta tags, don't continue.
+  if (!metatag_entity_supports_metatags($entity_type, $bundle)) {
+    return;
+  }
+
+  $revision_id = intval($revision_id);
+
+  // Check if a specific metatag config exists, otherwise just use the global
+  // one, stripping out the bundle.
+  $instance = metatag_get_entity_metatags_instance($entity, $entity_type, $bundle);
+  if (!metatag_config_load_with_defaults($instance, FALSE)) {
+    $instance = "{$entity_type}";
+  }
+
+  // Determine the language this entity actually uses.
+  $entity_language = metatag_entity_get_language($entity_type, $entity);
+
+  // If no language was requested, try the language defined for this page
+  // request.
+  if (empty($langcode)) {
+    $langcode = $GLOBALS['language_content']->language;
+  }
+
+  // This entity doesn't have any languages defined, i.e. it uses 'und'. This
+  // can't conflict with loading the wrong language as entities either have no
+  // language or they have specific one(s), they can't have both.
+  if ($entity_language == LANGUAGE_NONE) {
+    $langcode = LANGUAGE_NONE;
+  }
+
+  // If there are no meta tags for the currently identified language, and there
+  // *are* meta tags defined for the entity's default language, use the entity's
+  // default language's values, unless the "Don't load entity's default
+  // language values if no languages match" option is enabled on the advanced
+  // settings page.
+  elseif (empty($entity->metatags[$langcode]) && !empty($entity->metatags[$entity_language]) && !variable_get('metatag_entity_no_lang_default', FALSE)) {
+    $langcode = $entity_language;
+  }
+
+  // Other scenarios.
+  else {
+    // There's no need to do anything else - either there are meta tag values
+    // created for the requested language or there aren't.
+  }
+
+  $cid = FALSE;
+  $key = FALSE;
+  $metatag_variants = array();
+
+  // Caching is enabled.
+  if ($cached && variable_get('metatag_cache_output', FALSE)) {
+    // All possible variants of the metatags for this entity are stored in a
+    // single cache entry.
+    $cid = "output:$entity_type:$entity_id";
+
+    // All applicable pieces for this current page.
+    $key_parts = array(
+      'entity_type' => $entity_type,
+      'bundle' => $bundle,
+      'entity_id' => $entity_id,
+      'revision_id' => $revision_id,
+      // Cache separately based on the language of the passed-in entity and the
+      // overall active language of the page.
+      'langcode' => $langcode,
+      'language_content' => $GLOBALS['language_content']->language,
+      'view_mode' => $view_mode,
+    );
+    $key = metatag_cache_default_cid_parts($key_parts);
+
+    if ($cache = metatag_cache_get($cid)) {
+      $metatag_variants = $cache->data;
+    }
+  }
+
+  // If a cached object exists for this key, return it.
+  if (!empty($key) && isset($metatag_variants[$key])) {
+    $output = $metatag_variants[$key];
+  }
+
+  // Otherwise, generate the output tags.
+  else {
+    // Separate the meta tags.
+    $metatags = isset($entity->metatags) ? $entity->metatags : array();
+
+    // Build options for meta tag rendering.
+    $options = array(
+      'entity' => $entity,
+      'entity_type' => $entity_type,
+      'view_mode' => $view_mode,
+    );
+
+    // Ensure we actually pass a language object rather than language code.
+    $languages = language_list();
+    if (isset($languages[$langcode])) {
+      $options['language'] = $languages[$langcode];
+    }
+
+    // Include token replacement data. Don't reload the entity object as doing
+    // so would conflict with content editorial workflows.
+    if (!empty($entity_id)) {
+      $token_type = token_get_entity_mapping('entity', $entity_type);
+      $options['token data'][$token_type] = $entity;
+    }
+
+    // Render the metatags and save to the cache.
+    $output = metatag_metatags_view($instance, $metatags, $options);
+
+    // If output caching is enabled, store the data for later.
+    if (!empty($key) && !empty($cid)) {
+      $metatag_variants[$key] = $output;
+      metatag_cache_set($cid, $metatag_variants);
+    }
+  }
+
+  return $output;
+}
+
+/**
+ * Generate the metatags for a given entity.
+ *
+ * @param object $entity_id
+ *   The entity id of the entity to generate the metatags for.
+ * @param string $entity_type
+ *   The entity type of the entity to generate the metatags for.
+ * @param string $langcode
+ *   The language code used for rendering the entity.
+ *
+ * @return array
+ *   A renderable array of metatags for the given entity.
+ */
+function metatags_get_entity_metatags($entity_id, $entity_type, $langcode = NULL) {
+  $entities = entity_load($entity_type, array($entity_id));
+  $entity = reset($entities);
+  return !empty($entity) ? metatag_generate_entity_metatags($entity, $entity_type, $langcode) : array();
+}
+
+/**
+ * Build a renderable array of meta tag output.
+ *
+ * @param string $instance
+ *   The configuration instance key of the meta tags to use, e.g.
+ *   "node:article".
+ * @param array $metatags
+ *   An array of meta tag data.
+ * @param array $options
+ *   (optional) An array of options including the following keys and values:
+ *   - language: A language object.
+ *   - token data: An array of data to pass into token_replace() during
+ *                 meta tag value generation.
+ */
+function metatag_metatags_view($instance, array $metatags = array(), array $options = array()) {
+  $output = array();
+
+  // Convert language codes to a language object.
+  if (isset($options['language']) && is_string($options['language'])) {
+    $languages = language_list();
+    $options['language'] = isset($languages[$options['language']]) ? $languages[$options['language']] : NULL;
+  }
+
+  if (empty($options['language'])) {
+    $options['language'] = $GLOBALS['language_content'];
+  }
+
+  // If there are any tags, determine the translation to display.
+  if (!empty($metatags)) {
+    // Get the display language; default to the entity's language.
+    if (isset($options['language']) && isset($options['language']->language) && isset($metatags[$options['language']->language])) {
+      $metatags = $metatags[$options['language']->language];
+    }
+    // If no language requested, use the no-language value.
+    elseif (!empty($metatags[LANGUAGE_NONE])) {
+      $metatags = $metatags[LANGUAGE_NONE];
+    }
+    else {
+      $metatags = array();
+    }
+  }
+
+  // Add any default tags to the mix.
+  $metatags += metatag_config_load_with_defaults($instance);
+
+  $options['instance'] = $instance;
+
+  // Don't output meta tags that only contain the pager.
+  $current_pager = metatag_get_current_pager();
+
+  foreach ($metatags as $metatag => $data) {
+    if ((!empty($data['value']) || (isset($data['value']) && is_numeric($data['value'])))
+      && $metatag_instance = metatag_get_instance($metatag, $data)) {
+      $tag_output = $metatag_instance->getElement($options);
+      // Don't output the pager if that's all there is.
+      if ($tag_output != $current_pager) {
+        $output[$metatag] = $tag_output;
+      }
+    }
+  }
+
+  // Allow the output meta tags to be modified using
+  // hook_metatag_metatags_view_alter().
+  drupal_alter('metatag_metatags_view', $output, $instance, $options);
+
+  return $output;
+}
+
+/**
+ * Get the pager string for the current page.
+ *
+ * @return string
+ *   Returns a string based upon the 'metatag_pager_string' variable and the
+ *   current page number.
+ */
+function metatag_get_current_pager() {
+  if (isset($_GET['page']) && !empty($_GET['page']) && is_numeric($_GET['page'])) {
+    $page = intval($_GET['page']) + 1;
+    if ($page > 1) {
+      $pager = variable_get('metatag_pager_string', 'Page PAGER | ');
+      return str_replace('PAGER', $page, $pager);
+    }
+  }
+}
+
+/**
+ * Returns metatags values.
+ */
+function metatag_metatags_values($instance, array $metatags = array(), array $options = array()) {
+  $values = array();
+
+  // Apply defaults to the data for each language.
+  foreach ($metatags as $language => $metatag) {
+    $metatags[$language] += metatag_config_load_with_defaults($instance);
+  }
+
+  // Generate output only if we have a valid language.
+  if (isset($options['language']) && is_string($options['language']) && isset($metatags[$options['language']])) {
+    $language = $options['language'];
+
+    // Convert language codes to a language object.
+    $languages = language_list();
+    $options['language'] = isset($languages[$language]) ? $languages[$language] : NULL;
+    $options['instance'] = $instance;
+    // Get output elements.
+    foreach ($metatags[$language] as $metatag => $data) {
+      if ($metatag_instance = metatag_get_instance($metatag, $data)) {
+        $values[$metatag] = $metatag_instance->getValue($options);
+      }
+    }
+  }
+
+  return array_filter($values, 'drupal_strlen');
+}
+
+/**
+ * Build a FAPI array for editing meta tags.
+ *
+ * @param array $form
+ *   The current FAPI array.
+ * @param string $instance
+ *   The configuration instance key of the metatags to use, e.g. "node:article".
+ * @param array $metatags
+ *   An array of metatag data.
+ * @param array $options
+ *   (optional) An array of options including the following keys and values:
+ *   - token types: An array of token types to be passed to theme_token_tree().
+ */
+function metatag_metatags_form(array &$form, $instance, array $metatags = array(), array $options = array()) {
+  $info = metatag_get_info();
+  if (empty($info['tags'])) {
+    return;
+  }
+
+  // Work out the language code to use, default to NONE.
+  $langcode = LANGUAGE_NONE;
+  if (!empty($form['#entity_type'])) {
+    if (!empty($form['#entity'])) {
+      $langcode = metatag_entity_get_language($form['#entity_type'], $form['#entity']);
+    }
+    else {
+      $entity_info = entity_get_info($form['#entity_type']);
+      if (!empty($entity_info['token type'])) {
+        $entity_key = '#' . $entity_info['token type'];
+        if (!empty($form[$entity_key])) {
+          $langcode = metatag_entity_get_language($form['#entity_type'], $form[$entity_key]);
+        }
+      }
+    }
+  }
+
+  // Merge in the default options.
+  $options += array(
+    'token types' => array(),
+    'defaults' => metatag_config_load_with_defaults($instance),
+    'instance' => $instance,
+  );
+
+  // Trigger hook_metatag_token_types_alter().
+  // Allow the defined tokens to be modified.
+  drupal_alter('metatag_token_types', $options);
+
+  $form['metatags'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Meta tags'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#multilingual' => TRUE,
+    '#tree' => TRUE,
+    '#access' => user_access('edit meta tags') || user_access('administer meta tags'),
+    '#weight' => 40,
+    '#language' => $langcode,
+    '#attributes' => array(
+      'class' => array('metatags-form'),
+    ),
+  );
+  $form['metatags'][$langcode] = array(
+    '#metatag_defaults' => $options['defaults'],
+    '#type' => 'container',
+    '#multilingual' => TRUE,
+    '#tree' => TRUE,
+  );
+  // Show a different intro message for entity pages vs config pages.
+  if (isset($form['#entity'])) {
+    $form['metatags']['intro_text'] = array(
+      '#markup' => '<p>' . t('Configure the meta tags below. Tokens, e.g. "[node:summary]", automatically insert the corresponding information from that field or value, which helps to avoid redundant meta data and possible search engine penalization; see the "Browse available tokens" popup for more details.') . '</p>',
+      '#weight' => -10,
+    );
+  }
+  else {
+    $form['metatags']['intro_text'] = array(
+      '#markup' => '<p>' . t('Configure the meta tags below. Use tokens (see the "Browse available tokens" popup) 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>',
+      '#weight' => -10,
+    );
+  }
+
+  // Only support vertical tabs if there is a vertical tab element.
+  foreach (element_children($form) as $key) {
+    if (isset($form[$key]['#type']) && $form[$key]['#type'] == 'vertical_tabs') {
+      $form['metatags']['#group'] = $key;
+      $form['metatags']['#attached']['js']['vertical-tabs'] = drupal_get_path('module', 'metatag') . '/metatag.vertical-tabs.js';
+      break;
+    }
+  }
+
+  // Merge in the default meta tag configurations.
+  $metatags += $options['defaults'];
+
+  // This will be used later.
+  $group_metatag_access = array();
+
+  // Build the form for each metatag.
+  foreach ($info['tags'] as $metatag => $metatag_info) {
+    // @todo Replace context matching with hook_metatag_access().
+    if (isset($options['context']) && isset($metatag_info['context'])) {
+      if (!in_array($options['context'], $metatag_info['context'])) {
+        continue;
+      }
+    }
+
+    $metatag_instance = metatag_get_instance($metatag, isset($metatags[$metatag]) ? $metatags[$metatag] : array());
+    if (empty($metatag_instance)) {
+      continue;
+    }
+
+    // Get the form element from the meta tag class.
+    $metatag_form = $metatag_instance->getForm($options);
+
+    // Add a default value form element.
+    if (isset($options['defaults'][$metatag]['value'])) {
+      $metatag_form['default'] = array(
+        '#type' => 'hidden',
+        '#value' => $options['defaults'][$metatag]['value'],
+      );
+    }
+
+    // Optional extended edit permissions.
+    if (variable_get('metatag_extended_permissions', FALSE)) {
+      $metatag_form['#access'] = user_access('edit meta tag: ' . $metatag) || user_access('administer meta tags');
+    }
+    else {
+      $metatag_form['#access'] = $form['metatags']['#access'];
+    }
+
+    if (!empty($metatag_info['group'])) {
+      $group_key = $metatag_info['group'];
+      if (isset($info['groups'][$group_key]['label']) && !isset($form['metatags'][$langcode][$group_key])) {
+        $group = $info['groups'][$group_key] + array('form' => array(), 'description' => NULL);
+        $form['metatags'][$langcode][$group_key] = $group['form'] + array(
+          '#type' => 'fieldset',
+          '#title' => $group['label'],
+          '#description' => !empty($group['description']) ? $group['description'] : '',
+          '#collapsible' => TRUE,
+          '#collapsed' => TRUE,
+        );
+      }
+      $form['metatags'][$langcode][$group_key][$metatag] = $metatag_form + array(
+        '#parents' => array('metatags', $langcode, $metatag),
+      );
+
+      // Hide the fieldset itself if there is not at least one of the meta tag
+      // fields visible.
+      if (variable_get('metatag_extended_permissions', FALSE)) {
+        $form['metatags'][$langcode][$group_key]['#access'] = count(element_get_visible_children($form['metatags'][$langcode][$group_key])) > 0;
+      }
+      else {
+        $form['metatags'][$langcode][$group_key]['#access'] = $form['metatags']['#access'];
+      }
+      // Structure the access parameter into this array, and make use of it
+      // later when we move on. Besides, this foreach is getting heavy.
+      $group_metatag_access[$group_key] = $form['metatags'][$langcode][$group_key]['#access'];
+    }
+    else {
+      $form['metatags'][$langcode][$metatag] = $metatag_form;
+    }
+  }
+
+  // Hide the fieldset itself if there is not at least one of the meta tag
+  // fields visible; only bother checking this if the user had edit access in
+  // the first place.
+  if ($form['metatags']['#access'] && variable_get('metatag_extended_permissions', FALSE)) {
+    $form['metatags']['#access'] = count(element_get_visible_children($form['metatags'][$langcode])) > 0;
+  }
+
+  // Check the #access of each group. If it passed, we display options for
+  // tokens. By this we update the #description of each group.
+  if ($form['metatags']['#access']) {
+    // Check if each meta tag group is being displayed.
+    if (!empty($group_metatag_access)) {
+      // Built the token browser link. For value "all" theme_token_tree()
+      // compares with string, not array.
+      if (in_array('all', $options['token types'])) {
+        $options['token types'] = 'all';
+      }
+      $token_listing_link = theme('token_tree',
+        array(
+          'token_types' => $options['token types'],
+          'dialog' => TRUE,
+        )
+      );
+
+      foreach ($group_metatag_access as $group_key => $token_access) {
+        if ($token_access) {
+          // Update the description.
+          if (isset($form['metatags'][$langcode][$group_key]['#description'])) {
+            $form['metatags'][$langcode][$group_key]['#description'] .= '<br />';
+          }
+          else {
+            $form['metatags'][$langcode][$group_key]['#description'] = '';
+          }
+
+          // Add the token browser popup link.
+          $form['metatags'][$langcode][$group_key]['#description'] .= $token_listing_link;
+        }
+      }
+    }
+  }
+
+  // Add a submit handler to compare the submitted values against the default
+  // values.
+  $form += array('#submit' => array());
+  if (module_exists('commerce') && isset($form['#entity_type']) && $form['#entity_type'] == 'commerce_product') {
+    $form['actions']['submit']['#submit'][] = 'metatag_commerce_product_form_submit';
+  }
+  else {
+    array_unshift($form['#submit'], 'metatag_metatags_form_submit');
+  }
+}
+
+/**
+ * Form API submission callback.
+ *
+ * Unset meta tag values that equal their default values, and load any
+ * additional meta tag values for other languages so that they can be properly
+ * saved later on.
+ *
+ * @see metatag_metatags_save()
+ */
+function metatag_metatags_form_submit($form, &$form_state) {
+  if (!empty($form_state['values']['metatags'])) {
+    // Unset meta tag values that equal their default values.
+    foreach ($form_state['values']['metatags'] as $langcode => $values) {
+      if (!empty($form['metatags'][$langcode]['#metatag_defaults'])) {
+        metatag_filter_values_from_defaults($form_state['values']['metatags'][$langcode], $form['metatags'][$langcode]['#metatag_defaults']);
+      }
+    }
+
+    // Need to load the entity's values for other languages, otherwise they will
+    // be incorrectly deleted later on.
+    if (isset($form['#entity']) && !empty($form['#entity']->metatags)) {
+      foreach ($form['#entity']->metatags as $langcode => $values) {
+        if (!isset($form_state['values']['metatags'][$langcode])) {
+          $form_state['values']['metatags'][$langcode] = $values;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Form API submission callback for Commerce product.
+ *
+ * Unlike metatag_metatags_form_submit.
+ *
+ * @see metatag_metatags_save()
+ */
+function metatag_commerce_product_form_submit($form, &$form_state) {
+  // Trigger the normal meta tag form submission.
+  metatag_metatags_form_submit($form, $form_state);
+
+  // The entity being saved.
+  $entity_type = 'commerce_product';
+  $product = $form_state[$entity_type];
+  $entity_id = $product->product_id;
+  $revision_id = $product->revision_id;
+
+  // Get the full entity details.
+  list(, , $bundle) = entity_extract_ids($entity_type, $product);
+
+  // Update the meta tags for this entity type.
+  metatag_metatags_save($entity_type, $entity_id, $revision_id, $form_state['values']['metatags'], $bundle);
+}
+
+/**
+ * Implements hook_field_extra_fields().
+ */
+function metatag_field_extra_fields() {
+  $extra = array();
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if (!empty($entity_info['bundles'])) {
+      foreach (array_keys($entity_info['bundles']) as $bundle) {
+        if (metatag_entity_supports_metatags($entity_type, $bundle)) {
+          $extra[$entity_type][$bundle]['form']['metatags'] = array(
+            'label' => t('Meta tags'),
+            'description' => t('Meta tag module form elements.'),
+            'weight' => 40,
+          );
+        }
+      }
+    }
+  }
+  return $extra;
+}
+
+/**
+ * Check whether the requested entity type (and bundle) support metatag.
+ *
+ * By default the entities are disabled, only certain entities will have been
+ * enabled during installation. If an entity type is enabled it is assumed that
+ * the entity bundles will also be enabled by default.
+ *
+ * @see metatag_entity_type_is_suitable()
+ */
+function metatag_entity_supports_metatags($entity_type = NULL, $bundle = NULL) {
+  $entity_types = &drupal_static(__FUNCTION__);
+
+  // Identify which entities & bundles are supported the first time the
+  // function is called.
+  if (!isset($entity_types)) {
+    foreach (entity_get_info() as $entity_name => $entity_info) {
+      // Verify that this entity type is suitable.
+      $entity_types[$entity_name] = metatag_entity_type_is_suitable($entity_name, $entity_info);
+
+      // The entity type technically supports entities.
+      if (!empty($entity_types[$entity_name])) {
+        // Entiy types are enabled by default.
+        // Allow entities to be disabled by assigning a variable
+        // 'metatag_enable_{$entity_type}' the value FALSE, e.g.:
+        //
+        // // Disable metatags for file_entity.
+        // $conf['metatag_enable_file'] = FALSE;.
+        //
+        // @see Settings page.
+        if (variable_get('metatag_enable_' . $entity_name, FALSE) == FALSE) {
+          $entity_types[$entity_name] = FALSE;
+        }
+
+        // Check each bundle.
+        else {
+          $entity_types[$entity_name] = array();
+          foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+            // If only one bundle exists, take configuration for entity, to
+            // reflect options as they are available in the UI.
+            if (count($entity_info['bundles']) === 1) {
+              $entity_types[$entity_name][$bundle_name] = variable_get('metatag_enable_' . $entity_name, FALSE) == TRUE;
+              continue;
+            }
+
+            // Allow bundles to be disabled by assigning a variable
+            // 'metatag_enable_{$entity_type}__{$bundle}' the value FALSE, e.g.:
+            //
+            // // Disable metatags for carousel nodes.
+            // $conf['metatag_enable_node__carousel'] = FALSE;.
+            //
+            // @see Settings page.
+            if (variable_get('metatag_enable_' . $entity_name . '__' . $bundle_name, TRUE) == FALSE) {
+              $entity_types[$entity_name][$bundle_name] = FALSE;
+            }
+            else {
+              $entity_types[$entity_name][$bundle_name] = TRUE;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // It was requested to check a specific entity.
+  if (isset($entity_type)) {
+    // It was also requested to check a specific bundle for this entity.
+    if (isset($bundle)) {
+      $supported = !empty($entity_types[$entity_type][$bundle]);
+    }
+
+    // Check the entity.
+    else {
+      $supported = !empty($entity_types[$entity_type]);
+    }
+
+    return $supported;
+  }
+
+  // If nothing specific was requested, return the complete list of supported
+  // entities & bundles.
+  return $entity_types;
+}
+
+/**
+ * Enable support for a specific entity type if setting does not exist.
+ *
+ * @param string $entity_type
+ *    The entity type.
+ * @param string $bundle
+ *    The bundle of the entity.
+ * @param bool $force_enable
+ *   If TRUE, then the type is enabled regardless of any stored variables.
+ *
+ * @return bool
+ *   TRUE if either the bundle or entity type was enabled by this function.
+ */
+function metatag_entity_type_enable($entity_type, $bundle = NULL, $force_enable = FALSE) {
+  // The bundle was defined.
+  $bundle_set = FALSE;
+  if (isset($bundle)) {
+    $stored_bundle = variable_get('metatag_enable_' . $entity_type . '__' . $bundle, NULL);
+    if ($force_enable || !isset($stored_bundle)) {
+      variable_set('metatag_enable_' . $entity_type . '__' . $bundle, TRUE);
+      $bundle_set = TRUE;
+    }
+  }
+
+  // Always enable the entity type, because otherwise there's no point in
+  // enabling the bundle.
+  $entity_type_set = FALSE;
+  $stored_entity_type = variable_get('metatag_enable_' . $entity_type, NULL);
+  if ($force_enable || !isset($stored_entity_type)) {
+    variable_set('metatag_enable_' . $entity_type, TRUE);
+    $entity_type_set = TRUE;
+  }
+
+  // Clear the static cache so that the entity type / bundle will work.
+  drupal_static_reset('metatag_entity_supports_metatags');
+
+  return $bundle_set || $entity_type_set;
+}
+
+/**
+ * Disable support for a specific entity type.
+ *
+ * @param string $entity_type
+ *    The entity type.
+ * @param string $bundle
+ *    The bundle of the entity.
+ */
+function metatag_entity_type_disable($entity_type, $bundle = NULL) {
+  // The bundle was defined.
+  if (isset($bundle)) {
+    variable_set('metatag_enable_' . $entity_type . '__' . $bundle, FALSE);
+  }
+  // The bundle was not defined.
+  else {
+    variable_set('metatag_enable_' . $entity_type, FALSE);
+  }
+
+  // Clear the static cache so that the entity type / bundle will work.
+  drupal_static_reset('metatag_entity_supports_metatags');
+}
+
+/**
+ * Add meta tags to be added later with metatag_page_build().
+ *
+ * @param string $instance
+ *   The configuration instance key of the meta tags, e.g. "node:article".
+ * @param array $metatags
+ *   An array of meta tags from metatag_metatags_view().
+ */
+function metatag_page_set_metatags($instance, $metatags) {
+  $page_metatags = &drupal_static(__FUNCTION__, array());
+  $page_metatags[$instance] = $metatags;
+}
+
+/**
+ * Retrieve the array of meta tags to be added with metatag_page_build().
+ */
+function metatag_page_get_metatags() {
+  // @todo Add alter to this result?
+  return drupal_static('metatag_page_set_metatags', array());
+}
+
+/**
+ * Implements hook_page_build().
+ */
+function metatag_page_build(&$page) {
+  // By default do not add meta tags to admin pages. To enable meta tags on
+  // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+  if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+    return;
+  }
+
+  // Special consideration for the Me module, which uses the "user/me" path and
+  // will cause problems.
+  if (arg(0) == 'user' && arg(1) == 'me' && function_exists('me_menu_alter')) {
+    return;
+  }
+
+  // The page region can be changed.
+  $region = variable_get('metatag_page_region', 'content');
+
+  // Ensure these arrays exist, otherwise several use cases will fail.
+  if (!isset($page[$region]) || !is_array($page[$region])) {
+    $page[$region] = array();
+  }
+  if (!isset($page[$region]['metatags']) || !is_array($page[$region]['metatags'])) {
+    $page[$region]['metatags'] = array();
+  }
+
+  // The front page has special consideration. Also, check if this is an error
+  // (403/404) page, those also require separate handling.
+  $instance = 'global:frontpage';
+  if ((drupal_is_front_page() && metatag_config_is_enabled($instance))
+    || ($instance = metatag_is_error_page())) {
+
+    // Generate the cache ID.
+    $cid_parts = array(
+      'instance' => $instance,
+    );
+    $cid = metatag_cache_default_cid_parts($cid_parts);
+
+    if ($cache = metatag_cache_get($cid)) {
+      $metatags = $cache->data;
+    }
+    else {
+      $metatags = metatag_metatags_view($instance, array());
+      // If output caching is enabled, save this for later.
+      if (variable_get('metatag_cache_output', FALSE)) {
+        metatag_cache_set($cid, $metatags);
+      }
+    }
+
+    $page[$region]['metatags'][$instance] = $metatags;
+  }
+
+  // Load any meta tags assigned via metatag_page_set_metatags(). Note: this
+  // must include the necessary defaults.
+  else {
+    $page[$region]['metatags'] += metatag_page_get_metatags();
+  }
+
+  // If no meta tags were loaded at least load the global defaults. This may be
+  // disabled, see README.txt for details.
+  if (empty($page[$region]['metatags']) && variable_get('metatag_load_all_pages', TRUE)) {
+    $instance = 'global';
+
+    // Generate the cache ID.
+    $cid_parts = array(
+      'instance' => $instance,
+      'path' => request_path(),
+    );
+    $cid = metatag_cache_default_cid_parts($cid_parts);
+
+    if ($cache = metatag_cache_get($cid)) {
+      $metatags = $cache->data;
+    }
+    else {
+      $metatags = metatag_metatags_view($instance, array());
+      // If output caching is enabled, save this for later.
+      if (variable_get('metatag_cache_output', FALSE)) {
+        metatag_cache_set($cid, $metatags);
+      }
+    }
+    $page[$region]['metatags'][$instance] = $metatags;
+  }
+}
+
+/**
+ * Returns whether the current page is the page of the passed in entity.
+ *
+ * @param string $entity_type
+ *    The entity type; e.g. 'node' or 'user'.
+ * @param object $entity
+ *    The entity object.
+ *
+ * @return mixed
+ *   TRUE if the current page is the page of the specified entity, or FALSE
+ *   otherwise. If $entity_type == 'comment' return empty (FALSE).
+ */
+function _metatag_entity_is_page($entity_type, $entity) {
+  // Exclude comment entities as this conflicts with comment_fragment.module.
+  if ($entity_type == 'comment') {
+    return;
+  }
+
+  $uri = entity_uri($entity_type, $entity);
+  $current_path = current_path();
+
+  // Support for Workbench Moderation - if this is a node, check if the content
+  // type supports moderation.
+  if ($entity_type == 'node' && function_exists('workbench_moderation_node_type_moderated') && workbench_moderation_node_type_moderated($entity->type) === TRUE) {
+    return !empty($uri['path']) && ($current_path == $uri['path'] || $current_path == $uri['path'] . '/draft');
+  }
+
+  // Support for core node revisions.
+  elseif (!empty($uri['path']) && strpos($current_path, $uri['path']) === 0 && strpos($current_path, '/revisions/') && strpos($current_path, '/view')) {
+    return TRUE;
+  }
+
+  // Any other page.
+  else {
+    return !empty($uri['path']) && $current_path == $uri['path'];
+  }
+}
+
+/**
+ * Implements hook_field_attach_rename_bundle().
+ */
+function metatag_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
+  $instance_old = $entity_type . ':' . $bundle_old;
+  $instance_new = $entity_type . ':' . $bundle_new;
+  if ($config = metatag_config_load($instance_old)) {
+    $config->instance = $instance_new;
+    metatag_config_save($config);
+    $config->instance = $instance_old;
+    metatag_config_delete($config);
+  }
+}
+
+/**
+ * Implements hook_field_attach_delete_bundle().
+ */
+function metatag_field_attach_delete_bundle($entity_type, $bundle) {
+  $instance = $entity_type . ':' . $bundle;
+  if ($config = metatag_config_load($instance)) {
+    metatag_config_delete($config);
+  }
+}
+
+/**
+ * Implements hook_field_attach_form().
+ */
+function metatag_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
+  // Entity_Translation will trigger this hook again, skip it.
+  if (!empty($form_state['entity_translation']['is_translation'])) {
+    return;
+  }
+
+  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  if (!metatag_entity_supports_metatags($entity_type, $bundle)) {
+    return;
+  }
+
+  $instance = metatag_get_entity_metatags_instance($entity, $entity_type, $bundle);
+
+  // Grab the meta tags for display in the form if there are any.
+  if (!empty($entity->metatags)) {
+    // Identify the language to use with this entity.
+    $entity_language = metatag_entity_get_language($entity_type, $entity);
+
+    // If this is a new translation using Entity Translation, load the meta
+    // tags from the entity's original language.
+    if (module_exists('entity_translation') && empty($form['#entity_translation_source_form']) && ($handler = entity_translation_entity_form_get_handler($form, $form_state)) && isset($entity->metatags[$handler->getSourceLanguage()])) {
+      $metatags = $entity->metatags[$handler->getSourceLanguage()];
+    }
+    // Determine from where we should get the tags.
+    elseif (isset($entity->metatags[$langcode])) {
+      // Set the tags to the translation set matching that of the form.
+      $metatags = $entity->metatags[$langcode];
+    }
+    // There is no translation for this entity's tags in the current
+    // language. Instead, display tags in the language of the entity, the
+    // source language of translations. The will provide translators with the
+    // original text to translate.
+    elseif (isset($entity->metatags[$entity_language])) {
+      $metatags = $entity->metatags[$entity_language];
+    }
+    // This is a preview so set the tags to the raw submission data.  No
+    // language has been set.
+    else {
+      $metatags = $entity->metatags;
+    }
+  }
+  else {
+    $metatags = array();
+  }
+
+  // Certain circumstances can result in $metatags not being an array.
+  if (!is_array($metatags)) {
+    $metatags = array();
+  }
+
+  $options['token types'] = array(
+    token_get_entity_mapping('entity', $entity_type),
+  );
+  $options['context'] = $entity_type;
+
+  // @todo Remove metatag_form_alter() when https://www.drupal.org/node/1284642 is fixed in core.
+  // metatag_metatags_form($form, $instance, $metatags, $options);
+  $form['#metatags'] = array(
+    'instance' => $instance,
+    'metatags' => $metatags,
+    'options' => $options,
+  );
+}
+
+/**
+ * Implements hook_form_alter().
+ *
+ * @todo Remove this when https://www.drupal.org/node/1284642 is fixed in core.
+ */
+function metatag_form_alter(&$form, $form_state, $form_id) {
+  if (!empty($form['#metatags']) && !isset($form['metatags'])) {
+    extract($form['#metatags']);
+    metatag_metatags_form($form, $instance, $metatags, $options);
+    unset($form['#metatags']);
+  }
+}
+
+/**
+ * Get the meta tag information array of a meta tag.
+ *
+ * @param string $name
+ *   The meta tag name, e.g. description, for which the info shall be returned,
+ *   or NULL to return an array with info about all meta tags.
+ */
+function metatag_get_info($type = NULL, $name = NULL) {
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['metatag_info'] = &drupal_static(__FUNCTION__);
+  }
+  $info = &$drupal_static_fast['metatag_info'];
+
+  global $language;
+  if (!isset($info)) {
+    // hook_metatag_info() includes translated strings, so each language is
+    // cached separately.
+    $cid = 'info:' . $language->language;
+
+    if ($cache = metatag_cache_get($cid)) {
+      $info = $cache->data;
+    }
+    else {
+      // Obtain all metatag specs defined in other modules using
+      // hook_metatag_info().
+      $info = module_invoke_all('metatag_info');
+      $info += array('tags' => array(), 'groups' => array());
+
+      // Merge in default values.
+      foreach ($info['tags'] as $key => $data) {
+        $info['tags'][$key] += array(
+          // Merge in default values.
+          'name' => $key,
+          'class' => 'DrupalTextMetaTag',
+        );
+      }
+
+      // Let other modules alter the entity info using
+      // hook_metatag_info_alter().
+      drupal_alter('metatag_info', $info);
+
+      metatag_cache_set($cid, $info);
+    }
+  }
+
+  if (isset($type) && isset($name)) {
+    return isset($info[$type][$name]) ? $info[$type][$name] : FALSE;
+  }
+  elseif (isset($type)) {
+    return isset($info[$type]) ? $info[$type] : array();
+  }
+  else {
+    return $info;
+  }
+}
+
+/**
+ * Return instance of metatag.
+ */
+function metatag_get_instance($metatag, array $data = array()) {
+  $info = metatag_get_info('tags', $metatag);
+  if (!empty($info['class']) && class_exists($info['class'])) {
+    $class = $info['class'];
+    return new $class($info, $data);
+  }
+}
+
+/**
+ * Return the string value of a meta tag.
+ *
+ * @param string $metatag
+ *   The meta tag string.
+ * @param array $data
+ *   The array of data for the meta tag class instance.
+ * @param array $options
+ *   An optional array of additional options to pass to the getValue() method
+ *   of the meta tag class instance.
+ *   - raw: A boolean if TRUE will not perform token replacement.
+ *
+ * @return string
+ *   A string value.
+ */
+function metatag_get_value($metatag, array $data, array $options = array()) {
+  $value = '';
+  if ($metatag_instance = metatag_get_instance($metatag, $data)) {
+    $options["instance"] = $metatag;
+    $value = $metatag_instance->getValue($options);
+    if (is_array($value)) {
+      $value = implode(', ', $value);
+    }
+  }
+  return $value;
+}
+
+/**
+ * Set a variable to be altered in metatag_preprocess_html().
+ *
+ * @see metatag_get_preprocess_variables()
+ * @see metatag_preprocess_html()
+ * @see metatag_preprocess_maintenance_page()
+ */
+function metatag_set_preprocess_variable($hook, $variable, $value) {
+  $variables = &drupal_static(__FUNCTION__, array());
+  $variables[$hook][$variable] = $value;
+}
+
+/**
+ * Return an array of variables to be altered in preprocess functions.
+ *
+ * @see metatag_set_preprocess_variable()
+ * @see metatag_preprocess_html()
+ * @see metatag_preprocess_maintenance_page()
+ */
+function metatag_get_preprocess_variables($hook) {
+  $variables = drupal_static('metatag_set_preprocess_variable', array());
+  return isset($variables[$hook]) ? $variables[$hook] : array();
+}
+
+/**
+ * Implements hook_preprocess_html().
+ */
+function metatag_preprocess_html(&$variables) {
+  foreach (metatag_get_preprocess_variables('html') as $variable => $value) {
+    $variables[$variable] = $value;
+  }
+}
+
+/**
+ * Implements hook_preprocess_maintenance_page().
+ */
+function metatag_preprocess_maintenance_page(&$variables) {
+  foreach (metatag_get_preprocess_variables('html') as $variable => $value) {
+    $variables[$variable] = $value;
+  }
+}
+
+/**
+ * Implements hook_html_head_alter().
+ *
+ * Hide tags added by core that are now handled by metatag.
+ */
+function metatag_html_head_alter(&$elements) {
+  $metatags = array();
+  $other_tags = array();
+  foreach ($elements as $key => $data) {
+    // Identify meta tags added by the Metatag module.
+    if (strpos($key, 'metatag_') === 0) {
+      $metatags[] = $key;
+    }
+    // Identify meta tags added by other modules.
+    else {
+      $other_tags[] = $key;
+    }
+  }
+
+  // The meta tag keys to look for.
+  $metatag_keys = array('name', 'property');
+
+  // Attributes to look for.
+  $attributes = array('name', 'rel');
+
+  // Look for meta tags that were added by other modules and hide them.
+  foreach ($metatags as $metatag_name) {
+    $metatag = &$elements[$metatag_name];
+
+    // Setting the #access attribute to these will stop them from being output
+    // but still leave the tags present for other modules to interact with.
+    foreach ($other_tags as $other_tag) {
+      $other = &$elements[$other_tag];
+
+      // Look for other meta tags that have one of the defined attributes which
+      // matches one of the values from Metatag's tag.
+      foreach ($attributes as $attribute) {
+        if (isset($other['#attributes'], $other['#attributes'][$attribute]) && is_string($other['#attributes'][$attribute])) {
+          foreach ($metatag_keys as $metatag_key) {
+            if (isset($metatag[$metatag_key])) {
+              if (strtolower($other['#attributes'][$attribute]) == $metatag[$metatag_key]) {
+                $other['#access'] = FALSE;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // If the 'leave core tags' option is disabled then the following meta tags
+  // will be removed if they're provided by core.
+  if (!variable_get('metatag_leave_core_tags', FALSE)) {
+    $core_tags = array(
+      'generator',
+      'canonical',
+      'shortlink',
+      // Leave the shortcut icon, that's more of a theming thing.
+      // 'shortcut icon',.
+    );
+    foreach ($elements as $name => &$element) {
+      // Ignore meta tags provided by Metatag.
+      if (strpos($name, 'metatag_') === 0) {
+        continue;
+      }
+
+      // Setting the #access attribute to these will stop them from being output
+      // but still leave the tags present for other modules to interact with.
+      foreach ($core_tags as $tag) {
+        if (!empty($element['#attributes']['rel']) && $element['#attributes']['rel'] == $tag) {
+          $element['#access'] = FALSE;
+        }
+        elseif (!empty($element['#attributes']['name']) && strtolower($element['#attributes']['name']) == $tag) {
+          $element['#access'] = FALSE;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_get_form().
+ */
+function metatag_metatag_get_form($metatag, array $data = array(), array $options = array()) {
+  $instance = metatag_get_instance($metatag, $data);
+  return $instance->getForm($options);
+}
+
+/**
+ * Returns Instance info if exists otherwise return FALSE.
+ */
+function metatag_config_instance_info($instance = NULL) {
+  global $language;
+
+  $info = &drupal_static(__FUNCTION__);
+
+  // hook_metatag_info() includes translated strings, so each language is cached
+  // separately.
+  $cid = 'metatag:config:instance:info:' . $language->language;
+
+  if (!isset($info)) {
+    if ($cache = metatag_cache_get($cid)) {
+      $info = $cache->data;
+    }
+    else {
+      // Allow modules to act upon the record insertion using
+      // hook_metatag_config_instance_info().
+      $info = module_invoke_all('metatag_config_instance_info');
+
+      // Allow other modules to customize the data using
+      // hook_metatag_config_instance_info_alter().
+      drupal_alter('metatag_config_instance_info', $info);
+
+      metatag_cache_set($cid, $info);
+    }
+  }
+
+  if (isset($instance)) {
+    return isset($info[$instance]) ? $info[$instance] : FALSE;
+  }
+  else {
+    return $info;
+  }
+}
+
+/**
+ * Filter out meta tag values that equal the default values.
+ *
+ * @todo Use information in $values[$metatag]['default'] rather than a $defaults parameter.
+ */
+function metatag_filter_values_from_defaults(array &$values, array $defaults = array()) {
+  foreach ($values as $metatag => $data) {
+    $default = isset($data['default']) ? $data['default'] : (isset($defaults[$metatag]['value']) ? $defaults[$metatag]['value'] : NULL);
+    if (isset($default) && isset($data['value']) && $default === $data['value']) {
+      // Meta tag has a default, and it matches user-submitted value.
+      unset($values[$metatag]);
+    }
+    elseif (!isset($default) && (is_string($data['value']) && !drupal_strlen($data['value']) || (is_array($data['value']) && !array_filter($data['value'])))) {
+      // Metatag does not have a default, and user did not submit a value.
+      unset($values[$metatag]);
+    }
+    if (isset($values[$metatag]['default'])) {
+      // Unset the default hidden value.
+      unset($values[$metatag]['default']);
+    }
+  }
+}
+
+/**
+ * Return all the parents of a given configuration instance.
+ *
+ * @param string $instance
+ *   A meta tag configuration instance.
+ *
+ * @return array
+ *   An array of instances starting with the $instance parameter, with the end
+ *   of the array being the global instance.
+ */
+function metatag_config_get_parent_instances($instance, $include_global = TRUE) {
+  $parents = array();
+  $segments = explode(':', $instance);
+  while (count($segments) > 0) {
+    $parents[] = implode(':', $segments);
+    array_pop($segments);
+  }
+  if ($include_global && end($parents) !== 'global') {
+    $parents[] = 'global';
+  }
+  reset($parents);
+  return $parents;
+}
+
+/**
+ * Get the proper label of a configuration instance.
+ *
+ * @param string $instance
+ *   A meta tag configuration instance.
+ */
+function metatag_config_instance_label($instance) {
+  $labels = &drupal_static(__FUNCTION__, array());
+
+  if (!isset($labels[$instance])) {
+    $instance_parts = explode(':', $instance);
+    $instance_part = array_pop($instance_parts);
+    if ($context = metatag_config_instance_info($instance)) {
+      $labels[$instance] = $context['label'];
+    }
+    else {
+      $labels[$instance] = t('Unknown (@instance)', array('@instance' => $instance_part));
+    }
+    // Normally the following would use metatag_config_get_parent_instances()
+    // but since we already sliced the instance by separator and removed the
+    // last segment, putting the array back together gives us this instance's
+    // parent.
+    if (!empty($instance_parts)) {
+      $labels[$instance] = metatag_config_instance_label(implode(':', $instance_parts)) . ': ' . $labels[$instance];
+    }
+  }
+
+  return $labels[$instance];
+}
+
+/**
+ * Title callback for meta tag configuration instances.
+ */
+function metatag_config_title($config) {
+  return metatag_config_instance_label($config->instance);
+}
+
+/**
+ * Access callback for meta tag configuration instances.
+ */
+function metatag_config_access($op, $config = NULL) {
+  if (!user_access('administer meta tags')) {
+    return FALSE;
+  }
+
+  if ($op == 'enable') {
+    return !empty($config->disabled);
+  }
+  elseif ($op == 'disable') {
+    return empty($config->disabled);
+  }
+  elseif ($op == 'delete') {
+    return ($config->export_type & EXPORT_IN_DATABASE) && !($config->export_type & EXPORT_IN_CODE);
+  }
+  elseif ($op == 'revert') {
+    return ($config->export_type & EXPORT_IN_DATABASE) && ($config->export_type & EXPORT_IN_CODE);
+  }
+
+  return FALSE;
+}
+
+/**
+ * Checks if a metatag configuration record is enabled.
+ *
+ * @param string $instance
+ *   The configuration instance machine name.
+ *
+ * @return bool
+ *   TRUE if the configuration is enabled, or FALSE otherwise.
+ */
+function metatag_config_is_enabled($instance, $include_defaults = FALSE, $include_global = TRUE) {
+  if ($include_defaults) {
+    $instances = metatag_config_get_parent_instances($instance, $include_global);
+    $configs = metatag_config_load_multiple($instances);
+
+    // Check if one of the configs is enabled.
+    foreach ($configs as $config) {
+      if (empty($config->disabled)) {
+        return TRUE;
+      }
+    }
+
+    // No enabled configs found.
+    return FALSE;
+  }
+  else {
+    $config = metatag_config_load($instance);
+    return !empty($config) && empty($config->disabled);
+  }
+}
+
+/**
+ * Wrapper around entity_language().
+ *
+ * @param mixed $entity_type
+ *   An entity type's machine name.
+ * @param object $entity
+ *   The entity to review; will be typecast to an object if an array is passed.
+ *
+ * @return string
+ *   A string indicating the language code to be used; returns LANGUAGE_NONE if
+ *   the entity does not have a language assigned.
+ */
+function metatag_entity_get_language($entity_type, $entity) {
+  // Determine the entity's language, af.
+  $langcode = entity_language($entity_type, (object) $entity);
+
+  // If no matching language was found, which will happen for e.g. terms and
+  // users, it is normally recommended to use the system default language.
+  // However, as the system default language can change, this could potentially
+  // cause data loss / confusion problems; as a result use the system "no
+  // language" value to avoid any potential problems.
+  if (empty($langcode)) {
+    $langcode = LANGUAGE_NONE;
+  }
+
+  return $langcode;
+}
+
+/**
+ * Implements hook_features_api().
+ */
+function metatag_features_api() {
+  $components = array(
+    'metatag' => array(
+      'name' => t('Metatag'),
+      'feature_source' => TRUE,
+      'default_hook' => 'metatag_export_default',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'file' => drupal_get_path('module', 'metatag') . '/metatag.features.inc',
+    ),
+  );
+  return $components;
+}
+
+/**
+ * Implements hook_views_post_render().
+ *
+ * Try loading meta tags from a Views page display.
+ */
+function metatag_views_post_render(&$view, &$output, &$cache) {
+  // By default do not add meta tags to admin pages. To enable meta tags on
+  // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+  if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+    return;
+  }
+
+  // If display is not set for some reason, get out to prevent PHP notices.
+  if (!isset($view->display[$view->current_display])) {
+    return;
+  }
+
+  // Build a shortcut to the current display object.
+  $display = $view->display[$view->current_display];
+
+  // Only proceed if this view is a full page and has a valid path, don't
+  // process block or other Views display objects.
+  if ($display->display_plugin == 'page' && !empty($display->display_options['path'])) {
+    // Try to work out what entity type this is.
+    $entity_type = '';
+
+    // All paths must have a placeholder.
+    $placeholder_pos = strpos($display->display_options['path'], '%');
+    if ($placeholder_pos !== FALSE) {
+      // The first argument must be a numeric entity ID.
+      if (!empty($view->args) && is_numeric($view->args[0])) {
+        // The first argument should be an entity ID.
+        $id = $view->args[0];
+
+        // Taxonomy terms are the most commonly used item, so check that first.
+        if ($display->display_options['path'] == 'taxonomy/term/%' || $display->display_options['path'] == 'taxonomy/term/%/%') {
+          $entity_type = 'taxonomy_term';
+        }
+        // Node pages.
+        elseif ($display->display_options['path'] == 'node/%') {
+          $entity_type = 'node';
+        }
+        // User pages.
+        elseif ($display->display_options['path'] == 'user/%') {
+          $entity_type = 'user';
+        }
+      }
+    }
+
+    // Check for other types of entities.
+    if (empty($entity_type)) {
+      // Trigger hook_metatag_views_post_render_get_entity().
+      $hook = 'metatag_views_post_render_get_entity';
+      foreach (module_implements($hook) as $module) {
+        $function = $module . '_' . $hook;
+        if (function_exists($function)) {
+          $entity_type = call_user_func($function, $view);
+          // If an entity type was identified, stop checking.
+          if (!empty($entity_type)) {
+            break;
+          }
+        }
+      }
+    }
+
+    // If an entity type was identified, try loading the entity.
+    if (!empty($entity_type)) {
+      // Try loading the requested entity.
+      $entities = entity_load($entity_type, array($id));
+      if (!empty($entities)) {
+        $entity = array_pop($entities);
+
+        // Trigger our hook_entity_view().
+        metatag_entity_view($entity, $entity_type, 'full', NULL, TRUE);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_ctools_render_alter().
+ *
+ * Temporary solution to load meta tags on entity pages that are driven by
+ * CTools display handlers.
+ */
+function metatag_ctools_render_alter(&$info, $page, $context) {
+  // By default do not add meta tags to admin pages. To enable meta tags on
+  // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+  if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+    return;
+  }
+
+  // Only proceed if this is a full page (don't process individual panes) and
+  // there's an 'admin path' for the current task.
+  if ($page && !empty($context['task']['admin path'])) {
+    // Loop over each context.
+    foreach ($context['contexts'] as $context_argument) {
+      if (is_array($context_argument->type) && !empty($context_argument->data)) {
+        if (in_array('entity', $context_argument->type)) {
+          $entity = $context_argument->data;
+          $entity_type = str_replace('entity:', '', $context_argument->plugin);
+
+          // Verify this is an appropriate entity.
+          $entity_info = entity_get_info($entity_type);
+          if (!empty($entity_info) && _metatag_entity_is_page($entity_type, $entity)) {
+            // Load the meta tags for this entity.
+            global $language;
+            metatag_entity_view($entity, $entity_type, 'full', $language->language, TRUE);
+
+            // Don't bother looping over any more contexts, an entity has been
+            // found.
+            break;
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Checks if this entity is the default revision (published).
+ *
+ * Only needed when running Workbench Moderation v1; v3 is skipped.
+ *
+ * @param object $entity
+ *   The entity object, e.g., $node.
+ *
+ * @return bool
+ *   TRUE if the entity is the default revision, FALSE otherwise.
+ */
+function _metatag_isdefaultrevision($entity) {
+  // D7 "Forward revisioning" is complex and causes a node_save() with the
+  // future node in node table. This fires hook_node_update() twice and cause
+  // abnormal behaviour in metatag.
+  //
+  // The steps taken by Workbench Moderation is to save the forward revision
+  // first and overwrite this with the live version in a shutdown function in
+  // a second step. This will confuse metatag. D7 has no generic property
+  // in the node object, if the node that is updated is the 'published' version
+  // or only a draft of a future version.
+  //
+  // This behaviour will change in D8 where $node->isDefaultRevision has been
+  // introduced. See below links for more details.
+  // - https://www.drupal.org/node/1879482
+  // - https://www.drupal.org/node/218755
+  // - https://www.drupal.org/node/1522154
+  //
+  // Every moderation module saving a forward revision needs to return FALSE.
+  // @todo: Refactor this workaround under D8.
+
+  // Workbench Moderation v1 uses the hook_node_presave() for some custom logic.
+  // This was replaced with hook_entity_presave() in v3, so only proceed if the
+  // old hook implementation is present.
+  if (function_exists('workbench_moderation_node_presave')) {
+    // If this is a node, check if the content type supports moderation.
+    if (function_exists('workbench_moderation_node_type_moderated') && workbench_moderation_node_type_moderated($entity->type) === TRUE) {
+      return !empty($entity->workbench_moderation['updating_live_revision']);
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+ * Generate the cache ID to use with metatag_cache_get/metatag_cache_set calls.
+ *
+ * @param array $cid_parts
+ *   A list of values to be used.
+ *
+ * @return string
+ *   The cache ID string.
+ */
+function metatag_cache_default_cid_parts(array $cid_parts = array()) {
+  // The initial parts, control the order of the parts.
+  $cid_part_defaults = array(
+    'cache_type' => 'output',
+    'instance' => '',
+    'entity_type' => '',
+    'entity_id' => '',
+    'bundle' => '',
+    'langcode' => $GLOBALS['language_content']->language,
+    'revision_id' => '',
+    'view_mode' => '',
+    'status' => 200,
+    'protocol' => $GLOBALS['is_https'] ? 'https' : 'http',
+    'hostname' => $_SERVER['HTTP_HOST'],
+    'base_path' => base_path(),
+  );
+  $cid_parts = array_merge($cid_part_defaults, $cid_parts);
+
+  // Add the HTTP status code.
+  $headers = drupal_get_http_header();
+  if (isset($headers['status'])) {
+    $cid_parts['status'] = intval($headers['status']);
+  }
+
+  // Allow each page in a sequence to have different values.
+  if (isset($_GET['page'])) {
+    $cid_parts['page'] = $_GET['page'];
+  }
+
+  // Allow other modules to customize the data using
+  // hook_metatag_page_cache_cid_parts_alter().
+  drupal_alter('metatag_page_cache_cid_parts', $cid_parts);
+
+  // Remove empty parts.
+  $cid_parts = array_filter($cid_parts);
+
+  // Concatenate the cache ID parts, trim the results to 255 chars.
+  return substr(implode(':', $cid_parts), 0, 255);
+}
+
+/**
+ * Wrapper for cache_set.
+ *
+ * @see cache_set()
+ */
+function metatag_cache_set($cid, $data) {
+  // By default the cached data will not expire.
+  $expire = CACHE_PERMANENT;
+
+  // Triggers hook_metatag_cache_set_expire_alter().
+  drupal_alter("metatag_cache_set_expire", $expire, $cid, $data);
+  return cache_set($cid, $data, 'cache_metatag', $expire);
+}
+
+/**
+ * Wrapper for cache_get.
+ *
+ * @see cache_get()
+ */
+function metatag_cache_get($cid) {
+  // Try to load the object.
+  return cache_get($cid, 'cache_metatag');
+}
+
+/**
+ * Determines if we are in an error page and return the appropriate instance.
+ *
+ * @return string
+ *   String of error.
+ */
+function metatag_is_error_page() {
+  $known_errors = array(
+    'global:403' => '403 Forbidden',
+    'global:404' => '404 Not Found',
+  );
+  $headers = drupal_get_http_header();
+  if (isset($headers['status'])) {
+    foreach ($known_errors as $error => $status) {
+      if ($status == $headers['status']) {
+        return $error;
+      }
+    }
+  }
+  return '';
+}
+
+/**
+ * Implements hook_admin_menu_cache_info().
+ */
+function metatag_admin_menu_cache_info() {
+  $caches['metatag'] = array(
+    'title' => t('Metatag'),
+    'callback' => 'metatag_config_cache_clear',
+  );
+  return $caches;
+}
+
+/**
+ * Identify whether an entity type is technically capable of having meta tags.
+ *
+ * In order to be capable of having meta tags, an entity type must have view
+ * modes, must be fieldable, and may not be a configuration entity.
+ *
+ * @param string $entity_type
+ *    The entity type.
+ * @param array $entity_info
+ *    Entity information.
+ *
+ * @return bool
+ *    Return TRUE if suitable.
+ */
+function metatag_entity_type_is_suitable($entity_type, $entity_info = array()) {
+  $suitable = TRUE;
+
+  // If the entity info was not passed along, load it.
+  if (empty($entity_info)) {
+    $entity_info = entity_get_info($entity_type);
+  }
+
+  // Configuration entities may not have meta tags.
+  if (isset($entity_info['configuration']) && $entity_info['configuration'] == TRUE) {
+    $suitable = FALSE;
+  }
+
+  // Entities must have bundles.
+  elseif (empty($entity_info['bundles'])) {
+    $suitable = FALSE;
+  }
+
+  // The entity type must be fieldable.
+  elseif (empty($entity_info['fieldable'])) {
+    $suitable = FALSE;
+  }
+
+  else {
+    // Ignore some view modes that are automatically added by certain modules.
+    unset($entity_info['view modes']['ical']);
+    unset($entity_info['view modes']['diff_standard']);
+    unset($entity_info['view modes']['token']);
+
+    // There must be view modes.
+    if (empty($entity_info['view modes'])) {
+      $suitable = FALSE;
+    }
+
+    else {
+      // Specifically disable some entity types.
+      $excluded = array(
+        // Comment module.
+        'comment',
+        // Field Collection module.
+        'field_collection_item',
+        // Paragraphs module.
+        'paragraphs_item',
+      );
+      if (in_array($entity_type, $excluded)) {
+        $suitable = FALSE;
+      }
+    }
+  }
+
+  // Trigger hook_metatag_entity_type_is_supported_alter() to allow other
+  // modules to either enable or disable certain entity types.
+  drupal_alter('metatag_entity_type_is_supported', $suitable, $entity_type, $entity_info);
+
+  return $suitable;
+}
+
+/**
+ * Implements hook_node_type_insert().
+ *
+ * When a content type is created, enable it for use with Metatag.
+ */
+function metatag_node_type_insert($info) {
+  if (metatag_entity_supports_metatags('node')) {
+    if (metatag_entity_type_enable('node', $info->type)) {
+      drupal_set_message(t('Metatag support has been enabled for the @label content type.', array('@label' => $info->name)));
+    }
+  }
+}
+
+/**
+ * Implements hook_node_type_delete().
+ *
+ * When a content type is deleted, remove the corresponding Metatag variable.
+ */
+function metatag_node_type_delete($info) {
+  variable_del('metatag_enable_node__' . $info->type);
+}
+
+/**
+ * Implements hook_taxonomy_vocabulary_insert().
+ *
+ * When a vocabulary is created, enable it for use with Metatag.
+ */
+function metatag_taxonomy_vocabulary_insert($vocabulary) {
+  if (metatag_entity_supports_metatags('taxonomy_term')) {
+    if (metatag_entity_type_enable('taxonomy_term', $vocabulary->machine_name)) {
+      drupal_set_message(t('Metatag support has been enabled for the @label vocabulary.', array('@label' => $vocabulary->name)));
+    }
+  }
+}
+
+/**
+ * Implements hook_taxonomy_vocabulary_delete().
+ *
+ * When a vocabulary is deleted, remove the corresponding Metatag variable.
+ */
+function metatag_taxonomy_vocabulary_delete($info) {
+  variable_del('metatag_enable_taxonomy_term__' . $info->machine_name);
+}
+
+/**
+ * Implements hook_workbench_moderation_transition().
+ *
+ * Clear a node's caches when its Workbench Moderation state is changed.
+ */
+function metatag_workbench_moderation_transition($node, $previous_state, $new_state) {
+  metatag_metatags_cache_clear('node', array($node->nid));
+}
+
+/**
+ * Sort callback for sorting by metatag instance string values.
+ */
+function _metatag_config_instance_sort($a, $b) {
+  $a_contexts = explode(':', $a);
+  $b_contexts = explode(':', $b);
+
+  // Global config always comes first.
+  if ($a_contexts[0] == 'global' && $b_contexts[0] != 'global') {
+    return -1;
+  }
+  elseif ($b_contexts[0] == 'global' && $a_contexts[0] != 'global') {
+    return 1;
+  }
+
+  for ($i = 0; $i < max(count($a_contexts), count($b_contexts)); $i++) {
+    $a_context = isset($a_contexts[$i]) ? $a_contexts[$i] : '';
+    $b_context = isset($b_contexts[$i]) ? $b_contexts[$i] : '';
+    if ($a_context == $b_context) {
+      continue;
+    }
+    else {
+      return strcmp($a_context, $b_context);
+    }
+  }
+}
+
+/**
+ * Translations & internationalization (i18n).
+ */
+
+/**
+ * Implements hook_entity_translation_delete().
+ *
+ * Required for content translations being handled via Entity_Translation to
+ * remove the appropriate record when a translation is removed without the
+ * corresponding entity record also being removed.
+ */
+function metatag_entity_translation_delete($entity_type, $entity, $langcode) {
+  // Get the entity's ID.
+  list($entity_id, $revision_id) = entity_extract_ids($entity_type, $entity);
+  $revision_id = intval($revision_id);
+
+  // Delete the translation.
+  metatag_metatags_delete($entity_type, $entity_id, $revision_id, $langcode);
+}
+
+/**
+ * Translates the metatag if i18n_string integration is enabled.
+ *
+ * @param string $string
+ *   String in default language or array of strings to be translated.
+ * @param string $tag_name
+ *   The internal name of the meta tag being translated.
+ * @param mixed $context
+ *   A context string to use with i18n, or the $options array from a Metatag::
+ *   getValue() method; if the latter it will be used to generate the full
+ *   context.
+ * @param string $langcode
+ *   The language code to submit instead of the current page's language.
+ * @param bool $update
+ *   Whether or not to create/update records in {locales_source}.
+ *
+ * @return string
+ *   The translated string if i18n_string is enabled, otherwise just returns the
+ *   original string.
+ *
+ * @see i18n_string_translate()
+ */
+function metatag_translate_metatag($string, $tag_name, $context, $langcode = NULL, $update = TRUE) {
+  if (module_exists('i18n_string') && !variable_get('metatag_i18n_disabled', FALSE)) {
+    // By default do not add meta tags to admin pages. To enable meta tags on
+    // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+    static $page_is_admin;
+    if (is_null($page_is_admin)) {
+      $page_is_admin = FALSE;
+      if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+        $page_is_admin = TRUE;
+      }
+    }
+    if ($page_is_admin) {
+      return $string;
+    }
+
+    // If the context is an array then it is the $options from the meta tag
+    // generator and needs some custom tailoring. Doing it this way to avoid an
+    // unnecessary entity_extract_ids() call when i18n isn't being used.
+    if (is_array($context)) {
+      // Optionally disable output generation.
+      if (!variable_get('metatag_i18n_translate_output', FALSE)) {
+        return $string;
+      }
+
+      // Output generation was enabled, so continue as normal.
+      $new_context = 'output:';
+      if (drupal_is_front_page()) {
+        $new_context .= 'frontpage';
+      }
+      // If this is an entity page, use the entity as the context.
+      elseif (!empty($context['entity_type']) && !empty($context['entity'])) {
+        list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $context['entity']);
+        $new_context .= $context['entity_type'] . ':' . $entity_id;
+      }
+      // Otherwise, use the page URL.
+      else {
+        // Trim this to avoid SQL errors on the {locales_source} table.
+        // length = 255 - strlen('metatag:output:page:') - strlen(metatag);
+        $strlen = 255 - strlen('metatag:output:page:' . $tag_name);
+        $new_context .= 'page:' . drupal_substr(current_path(), 0, $strlen);
+      }
+      $context = $new_context;
+    }
+
+    $options = array(
+      // Automatically create/update the {locales_source} record if one wasn't
+      // found.
+      'update' => $update,
+      // Translate the string.
+      'translate' => TRUE,
+    );
+
+    // If the langcode was passed in, add it to the options passed to i18n.
+    if (!empty($langcode)) {
+      $options['langcode'] = $langcode;
+    }
+
+    // By default disable the watchdog logging of translation messages.
+    $options['watchdog'] = variable_get('metatag_i18n_enable_watchdog', FALSE);
+
+    // Triggers hook_metatag_i18n_context_alter() - allows the i18n string to
+    // be altered before being used.
+    drupal_alter('metatag_i18n_context', $context, $tag_name);
+
+    // If the context was erased just send back the original string - it's
+    // unlikely, but it could happen.
+    if (empty($context)) {
+      return $string;
+    }
+
+    // The 'name' is split up by i18n_string into two components - the textgroup
+    // is the first item, the others are joined together with a ':' separator
+    // to make the context. In order to have the contexts show with "metatag" as
+    // the first part of the context, it has to be added twice to the name.
+    $name = array(
+      'metatag',
+      $context,
+      $tag_name,
+    );
+
+    // Notify i18n of the string, and obtain a translation if one is available.
+    return i18n_string($name, $string, $options);
+  }
+
+  // If the i18n_string module isn't enabled then just pass back the string
+  // as-is.
+  else {
+    return $string;
+  }
+}
+
+/**
+ * Translate a set of metatags to the current language.
+ *
+ * @param array $metatags
+ *   List of meta tags to be translated.
+ * @param string $context
+ *   An optional context to use with i18n.
+ * @param string $langcode
+ *   The language code to submit instead of the current page's language.
+ * @param bool $update
+ *   Whether or not to create/update records in {locales_source}.
+ */
+function metatag_translate_metatags(&$metatags, $context = NULL, $langcode = NULL, $update = TRUE) {
+  if (!empty($metatags)) {
+    foreach ($metatags as $key => $data) {
+      if (!empty($data['value']) && is_string($data['value'])) {
+        $metatags[$key] = array(
+          'value' => metatag_translate_metatag($data['value'], $key, $context, $langcode, $update),
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Update the translated definitions of meta tags.
+ *
+ * @param array $metatags
+ *   List of meta tags to have their translations updated.
+ * @param string $context
+ *   The string that will be used to group strings in the translation UI.
+ */
+function metatag_translations_update($metatags, $context) {
+  // Store the context as it was originally provided.
+  $original_context = $context;
+
+  // Update the i18n string.
+  if (module_exists('i18n_string') && !variable_get('metatag_i18n_disabled', FALSE)) {
+    $options = array();
+
+    // By default disable the watchdog logging of translation messages.
+    $options['watchdog'] = variable_get('metatag_i18n_enable_watchdog', FALSE);
+
+    foreach ($metatags as $tag_name => $data) {
+      // Revert the context, so that it can be changed if needed.
+      $context = $original_context;
+
+      if (!empty($data['value']) && is_string($data['value'])) {
+        // Triggers hook_metatag_i18n_context_alter() - allows the i18n string
+        // to be altered before being used.
+        drupal_alter('metatag_i18n_context', $context, $tag_name);
+
+        // Don't do anything if the context was erased - it's unlikely, but it
+        // could happen.
+        if (empty($context)) {
+          continue;
+        }
+
+        // The textgroup is the first part of the string.
+        i18n_string_update("metatag:{$context}:{$tag_name}", $data['value'], $options);
+      }
+    }
+  }
+}
+
+/**
+ * Remove the translated definitions of meta tags.
+ *
+ * @param array $metatags
+ *   List of meta tags to have their translations updated.
+ * @param string $context
+ *   The string that will be used to group strings in the translation UI.
+ */
+function metatag_translations_delete($metatags, $context) {
+  // Store the context as it was originally provided.
+  $original_context = $context;
+
+  // Update the i18n string.
+  if (module_exists('i18n_string') && !variable_get('metatag_i18n_disabled', FALSE)) {
+    $options = array();
+
+    // By default disable the watchdog logging of translation messages.
+    $options['watchdog'] = variable_get('metatag_i18n_enable_watchdog', FALSE);
+
+    foreach ($metatags as $tag_name => $data) {
+      // Revert the context, so that it can be changed if needed.
+      $context = $original_context;
+
+      if (!empty($data['value']) && is_string($data['value'])) {
+        // Triggers hook_metatag_i18n_context_alter() - allows the i18n string
+        // to be altered before being used.
+        drupal_alter('metatag_i18n_context', $context, $tag_name);
+
+        // Don't do anything if the context was erased - it's unlikely, but it
+        // could happen.
+        if (empty($context)) {
+          continue;
+        }
+
+        // The textgroup is the first part of the string.
+        i18n_string_remove("metatag:{$context}:{$tag_name}", $data['value'], $options);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_config_insert().
+ *
+ * Implements hook_metatag_config_insert() on behalf of i18n_string.
+ */
+function i18n_string_metatag_config_insert($config) {
+  $context = 'metatag_config:' . $config->instance;
+  metatag_translations_update($config->config, $context);
+}
+
+/**
+ * Implements hook_config_update().
+ *
+ * Implements hook_metatag_config_update() on behalf of i18n_string.
+ */
+function i18n_string_metatag_config_update($config) {
+  // Defer to the 'insert' function.
+  i18n_string_metatag_config_insert($config);
+}
+
+/**
+ * Implements hook_config_delete().
+ *
+ * Implements hook_metatag_config_delete() on behalf of i18n_string.
+ */
+function i18n_string_metatag_config_delete($config) {
+  $context = 'metatag_config:' . $config->instance;
+  metatag_translations_delete($config->config, $context);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.search_api.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.search_api.inc
new file mode 100644
index 0000000000000000000000000000000000000000..84b3fae6f94882fcf9284347389244b4f1bc8d17
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.search_api.inc
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @file
+ * Contains MetatagSearchAlterCallback.
+ */
+
+/**
+ * Implements hook_search_api_alter_callback_info().
+ */
+function metatag_search_api_alter_callback_info() {
+  return array(
+    'search_api_metatag_alter_callback' => array(
+      'name' => t('Meta tags'),
+      'description' => t("Adds the item's meta tags to the indexed data."),
+      'class' => 'MetatagSearchAlterCallback',
+    ),
+  );
+}
+
+/**
+ * Adds meta tag values to the indexed items.
+ */
+if (class_exists('SearchApiAbstractAlterCallback')) {
+  class MetatagSearchAlterCallback extends SearchApiAbstractAlterCallback {
+
+    /**
+     * {@inheritdoc}
+     */
+    public function supportsIndex(SearchApiIndex $index) {
+      // Only works on entities.
+      return (bool) $index->getEntityType();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function alterItems(array &$items) {
+      $entity_type = $this->index->getEntityType();
+      $tags = metatag_get_info('tags');
+      foreach ($items as $id => $item) {
+        foreach (array_keys($tags) as $tag) {
+          $items[$id]->{'metatag_' . $tag} = NULL;
+          if (isset($item->language) && isset($item->metatags[$item->language][$tag])) {
+            $instance = metatag_get_instance($tag, $item->metatags[$item->language][$tag]);
+            $items[$id]->{'metatag_' . $tag} = $instance->getValue(array('token data' => array($entity_type => $item)));
+          }
+        }
+      }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function propertyInfo() {
+      $properties = array();
+
+      // Get available meta tags.
+      $tags = metatag_get_info('tags');
+      foreach ($tags as $id => $tag) {
+        switch ($tag['class']) {
+          case 'DrupalLinkMetaTag':
+            $type = 'uri';
+            break;
+          default:
+            $type = 'text';
+            break;
+        }
+        $properties['metatag_' . $id] = array(
+          'label' => t('Meta tag: @label', array('@label' => $tag['label'])),
+          'description' => t('@label meta tag attached to an item.', array('@label' => $tag['label'])),
+          'type' => $type,
+        );
+      }
+
+      return $properties;
+    }
+
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.theme.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.theme.inc
new file mode 100644
index 0000000000000000000000000000000000000000..819200782cc0bfd629d1a5550878236779cdf698
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.theme.inc
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Theme callbacks for the metatag module.
+ */
+
+/**
+ * Theme callback for a normal meta tag.
+ *
+ * The format is:
+ * <meta name="[name]" content="[value]" />
+ */
+function theme_metatag($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name'  => 'name',
+    '#value' => 'content',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Theme callback for a normal meta tag.
+ *
+ * The format is:
+ * <meta http-equiv="[name]" content="[value]" />
+ */
+function theme_metatag_http_equiv($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name' => 'http-equiv',
+    '#value' => 'content',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Theme callback for a rel link tag.
+ *
+ * The format is:
+ * <link rel="[name]" href="[value]" />
+ */
+function theme_metatag_link_rel($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name' => 'rel',
+    '#value' => 'href',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Theme callback for a rev link tag.
+ *
+ * The format is:
+ * <link rev="[name]" href="[value]" />
+ */
+function theme_metatag_link_rev($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name' => 'rev',
+    '#value' => 'href',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Theme callback for a proprty meta tag.
+ *
+ * The format is:
+ * <meta property="[name]" content="[value]" />
+ */
+function theme_metatag_property($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name' => 'property',
+    '#value' => 'content',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.tokens.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.tokens.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b4a053e70c191dd5bd96bc0cb6beddb34e27844c
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.tokens.inc
@@ -0,0 +1,250 @@
+<?php
+/**
+ * @file
+ * Custom tokens for Metatag.
+ */
+
+/**
+ * Implements hook_token_info().
+ */
+function metatag_token_info() {
+  $info = array();
+
+  $info['types']['metatag'] = array(
+    'name' => t('Meta tags'),
+    'description' => t('Generated by the Metatag module, may not be used to fill in other meta tags.'),
+  );
+
+  $metatag_info = metatag_get_info();
+
+  foreach ($metatag_info['tags'] as $value) {
+    if (isset($value['group'], $metatag_info['groups'][$value['group']], $metatag_info['groups'][$value['group']]['label'])) {
+      $label = $metatag_info['groups'][$value['group']]['label'] . ': ' . $value['label'];
+    }
+    else {
+      $label = t('Basic tags') . ': ' . $value['label'];
+    }
+    $info['tokens']['metatag'][$value['name']] = array(
+      'name' => $label,
+      'description' => $value['description'],
+    );
+  }
+
+  if (module_exists('taxonomy')) {
+    $info['tokens']['term']['metatag'] = array(
+      'name' => t('Meta tags'),
+      'description' => t('Meta tags for this taxonomy term.'),
+      'type' => 'metatag',
+    );
+  }
+
+  if (module_exists('node')) {
+    $info['tokens']['node']['metatag'] = array(
+      'name' => t('Meta tags'),
+      'description' => t('Meta tags for this node.'),
+      'type' => 'metatag',
+    );
+  }
+
+  if (module_exists('user')) {
+    $info['tokens']['user']['metatag'] = array(
+      'name' => t('Meta tags'),
+      'description' => t('Meta tags for this user.'),
+      'type' => 'metatag',
+    );
+  }
+
+  // A custom pager.
+  $pager = variable_get('metatag_pager_string', 'Page PAGER | ');
+  $page = str_replace('PAGER', 12, $pager);
+  $info['tokens']['current-page']['pager'] = array(
+    'name' => t('Custom pager'),
+    'description' => t('A custom pager (from the Metatag module). Currently set to "@pager" which would be output as e.g. "@page".', array('@pager' => $pager, '@page' => $page)),
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function metatag_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $replacements = array();
+
+  $sanitize = !empty($options['sanitize']);
+
+  // Metatag tokens.
+  if ($type == 'metatag' && !empty($data['metatag'])) {
+    $metatag = $data['metatag'];
+    foreach ($tokens as $name => $original) {
+      if (isset($metatag[$name])) {
+        $replacements[$original] = $sanitize ? filter_xss($metatag[$name]) : $metatag[$name];
+      }
+    }
+  }
+
+  // Token tokens.
+  if ($type == 'term' && !empty($data['term'])) {
+    $term = $data['term'];
+
+    if ($metatag_tokens = token_find_with_prefix($tokens, 'metatag')) {
+      $result = metatag_token_generate_array($term, 'taxonomy_term', $term->vocabulary_machine_name);
+      $replacements += token_generate('metatag', $metatag_tokens, array('metatag' => $result), $options);
+    }
+  }
+
+  // Node tokens.
+  if ($type == 'node' && !empty($data['node'])) {
+    $node = $data['node'];
+
+    if ($metatag_tokens = token_find_with_prefix($tokens, 'metatag')) {
+      $result = metatag_token_generate_array($node, 'node', $node->type);
+      $replacements += token_generate('metatag', $metatag_tokens, array('metatag' => $result), $options);
+    }
+  }
+
+  // User tokens.
+  if ($type == 'user' && !empty($data['user'])) {
+    $account = $data['user'];
+
+    if ($metatag_tokens = token_find_with_prefix($tokens, 'metatag')) {
+      $result = metatag_token_generate_array($account, 'user', 'user');
+      $replacements += token_generate('metatag', $metatag_tokens, array('metatag' => $result), $options);
+    }
+  }
+
+  // Custom pager.
+  if ($type == 'current-page') {
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'pager':
+          $pager = metatag_get_current_pager();
+          if (!empty($pager)) {
+            $replacements[$original] = $pager;
+          }
+          break;
+      }
+    }
+  }
+
+  return $replacements;
+}
+
+/**
+ * Generate an array of meta tags for a given entity.
+ */
+function metatag_token_generate_array($entity, $entity_type, $bundle) {
+  if (metatag_entity_supports_metatags($entity_type, $bundle)) {
+    $token_type = token_get_entity_mapping('entity', $entity_type);
+
+    $instance = metatag_get_entity_metatags_instance($entity, $entity_type, $bundle);
+    $options = array();
+    $options['token data'][$token_type] = $entity;
+    $options['entity'] = $entity;
+
+    $metatags = array();
+    if (!empty($entity->metatags)) {
+      $language = metatag_entity_get_language($entity_type, $entity);
+      if (!empty($entity->metatags[$language])) {
+        $metatags = $entity->metatags[$language];
+      }
+    }
+    $metatags += metatag_config_load_with_defaults($instance);
+    // Process it for entity metatag replacement to avoid infinite recursion.
+    $metatags = _metatag_token_process_metatag($metatags, $token_type);
+
+    $result = array();
+    foreach ($metatags as $metatag => $data) {
+      if ($metatag_instance = metatag_get_instance($metatag, $data)) {
+        $result[$metatag] = $metatag_instance->getValue($options);
+      }
+    }
+    return $result;
+  }
+
+  return NULL;
+}
+
+/**
+ * Loop through metatags to avoid recursion on entity tokens. It will replace
+ * entity metatag token to its actual entity metatag field value.
+ *
+ * @param array $metatags
+ *   An array of entity metatag tokens.
+ * @param string $token_type
+ *   The entity token type, such as 'node' or 'term'.
+ *
+ * @return array
+ *   Return metatags array with entity metatag tokens replaced.
+ */
+function _metatag_token_process_metatag($metatags, $token_type) {
+  foreach ($metatags as $metatag => $data) {
+    // Skip values that are not strings.
+    if (!is_string($data['value'])) {
+      continue;
+    }
+
+    // Explode all metatag token in field.
+    $data_tokens = token_scan($data['value']);
+    if (isset($data_tokens[$token_type])) {
+      foreach ($data_tokens[$token_type] as $key => $value) {
+        $metatag_parts = explode(':', $key);
+        // Check entity metatag token. Like [<entity_token_type>:metatag:<xyz>].
+        if ($metatag_parts[0] == 'metatag') {
+          $entity_field = implode(':', array_slice($metatag_parts, 1));
+          // If a value is not set here it will trigger an infinite loop.
+          $metatags[$metatag]['value'] = '';
+
+          // If the meta tag was defined then try parsing it.
+          if (!empty($metatags[$entity_field]['value'])) {
+            // Entity metatag field may contain other entity metatag token
+            // that need to be replaced too.
+            $replaced_value = metatag_token_entitymetatagtoken_replace($metatags, $metatags[$entity_field]['value'], $token_type);
+            $metatags[$metatag]['value'] = str_replace($value, $replaced_value, $metatags[$metatag]['value']);
+          }
+        }
+      }
+    }
+  }
+
+  return $metatags;
+}
+
+/**
+ * Replace entity metatag token with actual entity metatag field value.
+ *
+ * @param array $metatags
+ *   An array entity metatag tokens.
+ * @param string $token
+ *   A token to be replaced.
+ * @param string $token_type
+ *   The entity token type, such as 'node' or 'term'.
+ * @param array $search_tokens
+ *   An array of tokens to search for.
+ * @param array $replace_tokens
+ *   An array of tokens to be replaced.
+ *
+ * @return string
+ *   The replaced value of $token.
+ */
+function metatag_token_entitymetatagtoken_replace($metatags, $token, $token_type, $search_tokens = array(), $replace_tokens = array()) {
+  $data_tokens = token_scan($token);
+  // Check field has tokens.
+  if (isset($data_tokens[$token_type])) {
+    // Go through each token in field and find entity metatag tokens.
+    foreach ($data_tokens[$token_type] as $key => $value) {
+      $metatag_parts = explode(':', $key);
+      if ($metatag_parts[0] == 'metatag' && !in_array($value, $search_tokens)) {
+        // Entity metatag field value.
+        $entity_field = implode(':', array_slice($metatag_parts, 1));
+        $replaced_value = metatag_token_entitymetatagtoken_replace($metatags, $metatags[$entity_field]['value'], $token_type, $replace_tokens, $search_tokens);
+        $replace_tokens[] = $replaced_value;
+        $search_tokens[] = $value;
+      }
+    }
+    return str_replace($search_tokens, $replace_tokens, $token);
+  }
+  else {
+    return $token;
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.variable.inc b/profiles/wcm_base/modules/contrib/metatag/metatag.variable.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ea7b0013bcf05661d629bd229a242f2042fa8be0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.variable.inc
@@ -0,0 +1,37 @@
+<?php
+/**
+ * @file
+ * Definition of variables for Variable API module.
+ */
+
+/**
+ * Implements hook_variable_info().
+ */
+function metatag_variable_info($options) {
+
+  $variables['metatag_pager_string'] = array(
+    'title' => t('Custom pager string', array(), $options),
+    'type' => 'string',
+    'description' => t('When the current page includes a pager, e.g. the URL contains "?page=42", the [current-page:pager] token may be added to a meta tag to differentiate between two pages that would otherwise have the same meta tags. The value "PAGER" (must be in uppercase) will be replaced by the actual page count. Note: the pager will only output if the page number is 2 or above and the string "page=NUMBER" is in the URL.<br />For best use, it may be worthwhile to add the [current-page:pager] to the page title to the left of the site name, to the start of description tags, etc.', array(), $options),
+    'default' => 'Page PAGER | ',
+    'group' => 'metatag',
+    'localize' => TRUE,
+    'multidomain' => TRUE,
+  );
+
+  return $variables;
+}
+
+/**
+ * Implements hook_variable_group_info().
+ */
+function metatag_variable_group_info() {
+  $groups['metatag'] = array(
+    'title' => t('Metatag'),
+    'description' => t('Configure meta tags on your website.'),
+    'access' => 'administer meta tags',
+    'path' => array('admin/config/search/metatags/settings'),
+  );
+
+  return $groups;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag.vertical-tabs.js b/profiles/wcm_base/modules/contrib/metatag/metatag.vertical-tabs.js
new file mode 100644
index 0000000000000000000000000000000000000000..242cf615d44fec6d6ad42bc7c1891c679a30a348
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag.vertical-tabs.js
@@ -0,0 +1,57 @@
+/**
+ * @file
+ * Custom JS for controlling the Metatag vertical tab.
+ */
+
+(function ($) {
+  'use strict';
+
+Drupal.behaviors.metatagFieldsetSummaries = {
+  attach: function (context) {
+    $('fieldset.metatags-form', context).drupalSetSummary(function (context) {
+      var vals = [];
+      $("input[type='text'], select, textarea", context).each(function() {
+        var input_field = $(this).attr('name');
+        // Verify the field exists before proceeding.
+        if (input_field === undefined) {
+          return false;
+        }
+        var default_name = input_field.replace(/\[value\]/, '[default]');
+        var default_value = $("input[type='hidden'][name='" + default_name + "']", context);
+        if (default_value.length && default_value.val() === $(this).val()) {
+          // Meta tag has a default value and form value matches default value.
+          return true;
+        }
+        else if (!default_value.length && !$(this).val().length) {
+          // Meta tag has no default value and form value is empty.
+          return true;
+        }
+        var label = $("label[for='" + $(this).attr('id') + "']").text();
+        vals.push(Drupal.t('@label: @value', {
+          '@label': $.trim(label),
+          '@value': Drupal.truncate($(this).val(), 25) || Drupal.t('None')
+        }));
+      });
+      if (vals.length === 0) {
+        return Drupal.t('Using defaults');
+      }
+      else {
+        return vals.join('<br />');
+      }
+    });
+  }
+};
+
+/**
+ * Encode special characters in a plain-text string for display as HTML.
+ */
+Drupal.truncate = function (str, limit) {
+  if (str.length > limit) {
+    return str.substr(0, limit) + '...';
+  }
+  else {
+    return str;
+  }
+};
+
+})(jQuery);
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..653e74b92c7b76a0e3bcbde59b1fad0e3e9d4896
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/README.txt
@@ -0,0 +1,40 @@
+Metatag: App Links
+------------------
+This module adds the App Links meta tags, provided by the applinks.org [1].
+
+The following tags are provided:
+* al:android:package
+* al:android:url
+* al:android:class
+* al:android:app_name
+* al:ios:url
+* al:ios:app_store_id
+* al:ios:app_name
+* al:ipad:url
+* al:ipad:app_store_id
+* al:ipad:app_name
+* al:iphone:url
+* al:iphone:app_store_id
+* al:iphone:app_name
+* al:windows_phone:url
+* al:windows_phone:app_id
+* al:windows_phone:app_name
+* al:windows:url
+* al:windows:app_id
+* al:windows:app_name
+* al:windows_universal:url
+* al:windows_universal:app_id
+* al:windows_universal:app_name
+* al:web:url
+* al:web:should_fallback
+
+
+Credits
+------------------------------------------------------------------------------
+The initial development was by Andrew Berry [2].
+
+
+References
+------------------------------------------------------------------------------
+1: http://applinks.org/
+2: https://www.drupal.org/u/deviantintegral
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.info b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.info
new file mode 100644
index 0000000000000000000000000000000000000000..e8a16962688846ea53e2334edf1b50bb23c24fe1
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.info
@@ -0,0 +1,16 @@
+name = Metatag: App Links
+description = "Provides support for applinks.org meta tags."
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_app_links.test
+files[] = tests/metatag_app_links.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bc7736a6541bff6662729f97909dd681d959d6bb
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.metatag.inc
@@ -0,0 +1,162 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag:App Links module.
+ */
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_app_links_metatag_info() {
+  $info['groups']['app_links'] = array(
+    'label' => t('App Links'),
+    'description' => t('Meta tags used to expose app Links for app deep linking. See <a href="@url">applinks.org</a> for details and documentation.', array('@url' => 'http://applinks.org')),
+    'form' => array(
+      '#weight' => 90,
+    ),
+  );
+
+  // Default values for each meta tag.
+  $defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'app_links',
+    'element' => array(
+      '#theme' => 'metatag_property',
+    ),
+  );
+  // Stack these codes after most others.
+  $weight = 80;
+
+  $info['tags']['al:android:package'] = array(
+    'label' => t('Android app package ID'),
+    'description' => t('A fully-qualified package name for intent generation. <strong>This attribute is required by the app Links specification.</strong>'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['al:android:url'] = array(
+    'label' => t('Android app URL scheme'),
+    'description' => t('A custom scheme for the Android app.'),
+  ) + $defaults;
+
+  $info['tags']['al:android:class'] = array(
+    'label' => t('Android app Activity Class'),
+    'description' => t('A fully-qualified Activity class name for intent generation.'),
+  ) + $defaults;
+
+  $info['tags']['al:android:app_name'] = array(
+    'label' => t('Android app name'),
+    'description' => t('The name of the app (suitable for display)'),
+  ) + $defaults;
+
+  $info['tags']['al:ios:url'] = array(
+    'label' => t('iOS app URL scheme'),
+    'description' => t('A custom scheme for the iOS app. <strong>This attribute is required by the app Links specification.</strong>'),
+  ) + $defaults;
+
+  $info['tags']['al:ios:app_store_id'] = array(
+    'label' => t('iOS app store ID'),
+    'description' => t('The app ID for the app Store.'),
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $defaults;
+
+  $info['tags']['al:ios:app_name'] = array(
+    'label' => t('iOS app name'),
+    'description' => t('The name of the app (suitable for display)'),
+  ) + $defaults;
+
+  $info['tags']['al:ipad:url'] = array(
+    'label' => t('iPad app URL scheme'),
+    'description' => t('A custom scheme for the iPad app. <strong>This attribute is required by the app Links specification.</strong>'),
+  ) + $defaults;
+
+  $info['tags']['al:ipad:app_store_id'] = array(
+    'label' => t('iPad app store ID'),
+    'description' => t('The app ID for the app Store.'),
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $defaults;
+
+  $info['tags']['al:ipad:app_name'] = array(
+    'label' => t('iPad app name'),
+    'description' => t('The name of the app (suitable for display)'),
+  ) + $defaults;
+
+  $info['tags']['al:iphone:url'] = array(
+    'label' => t('iPhone app URL'),
+    'description' => t('A custom scheme for the iPhone app. <strong>This attribute is required by the app Links specification.</strong>'),
+  ) + $defaults;
+
+  $info['tags']['al:iphone:app_store_id'] = array(
+    'label' => t('iPhone app store ID'),
+    'description' => t('The app ID for the app Store.'),
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $defaults;
+
+  $info['tags']['al:iphone:app_name'] = array(
+    'label' => t('iPhone app name'),
+    'description' => t('The name of the app (suitable for display)'),
+  ) + $defaults;
+
+  $info['tags']['al:windows_phone:url'] = array(
+    'label' => t('Windows Phone app URL scheme'),
+    'description' => t('A custom scheme for the Windows Phone app. <strong>This attribute is required by the app Links specification.</strong>'),
+  ) + $defaults;
+
+  $info['tags']['al:windows_phone:app_id'] = array(
+    'label' => t('Windows Phone app GUID'),
+    'description' => t('The app ID (a GUID) for app store.'),
+  ) + $defaults;
+
+  $info['tags']['al:windows_phone:app_name'] = array(
+    'label' => t('Windows Phone app name'),
+    'description' => t('The name of the app (suitable for display)'),
+  ) + $defaults;
+
+  $info['tags']['al:windows:url'] = array(
+    'label' => t('Windows app URL scheme'),
+    'description' => t('A custom scheme for the Windows app. <strong>This attribute is required by the app Links specification.</strong>'),
+  ) + $defaults;
+
+  $info['tags']['al:windows:app_id'] = array(
+    'label' => t('Windows app GUID'),
+    'description' => t('The app ID (a GUID) for app store.'),
+  ) + $defaults;
+
+  $info['tags']['al:windows:app_name'] = array(
+    'label' => t('Windows app name'),
+    'description' => t('The name of the app (suitable for display)'),
+  ) + $defaults;
+
+  $info['tags']['al:windows_universal:url'] = array(
+    'label' => t('Windows Universal app URL scheme'),
+    'description' => t('A custom scheme for the Windows Universal app. <strong>This attribute is required by the app Links specification.</strong>'),
+  ) + $defaults;
+
+  $info['tags']['al:windows_universal:app_id'] = array(
+    'label' => t('Windows Universal app GUID'),
+    'description' => t('The app ID (a GUID) for app store.'),
+  ) + $defaults;
+
+  $info['tags']['al:windows_universal:app_name'] = array(
+    'label' => t('Windows Universal app name'),
+    'description' => t('The name of the app (suitable for display)'),
+  ) + $defaults;
+
+  $info['tags']['al:web:url'] = array(
+    'label' => t('Web URL'),
+    'description' => t('The web URL; defaults to the URL for the content that contains this tag.'),
+  ) + $defaults;
+
+  $info['tags']['al:web:should_fallback'] = array(
+    'label' => t('Should fallback'),
+    'description' => t('Indicates if the web URL should be used as a fallback; defaults to "true".'),
+  ) + $defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.module b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.module
new file mode 100644
index 0000000000000000000000000000000000000000..f5b6961ebfdd4f04bb953dcb96fda34253451548
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/metatag_app_links.module
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Primary hook implementations for Metatag:App Links.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_app_links_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/tests/metatag_app_links.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/tests/metatag_app_links.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..cff79c25fbff71837fdafa488343600eb79a1454
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/tests/metatag_app_links.tags.test
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * Tests that each of the Metatag App Links tags work correctly.
+ */
+class MetatagAppLinksTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: App Links',
+      'description' => 'Test the App Links meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    '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:url',
+    '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',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_name_attribute = 'property';
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_app_links';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    // All of the tags have their underlines replaced with colons.
+
+    // Start with the beginning of the string.
+    $tag_name = str_replace('al_', 'al:', $tag_name);
+
+    // The three-ish standard tag names.
+    $tag_name = str_replace('_app_id', ':app_id', $tag_name);
+    $tag_name = str_replace('_app_name', ':app_name', $tag_name);
+    $tag_name = str_replace('_app_store_id', ':app_store_id', $tag_name);
+    $tag_name = str_replace('_url', ':url', $tag_name);
+
+    // One-offs.
+    $tag_name = str_replace('_class', ':class', $tag_name);
+    $tag_name = str_replace('_package', ':package', $tag_name);
+    $tag_name = str_replace('_should_fallback', ':should_fallback', $tag_name);
+
+    return $tag_name;
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/tests/metatag_app_links.test b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/tests/metatag_app_links.test
new file mode 100644
index 0000000000000000000000000000000000000000..8204d7fe34d6928185be0eb479e239685504f2fe
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_app_links/tests/metatag_app_links.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag AppLinks module.
+ */
+class MetatagAppLinksTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag AppLinks tests',
+      'description' => 'Test the Metatag:AppLinks module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_app_links';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_context/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5ddf0db7013983d710ba3a283a66f4da615b7383
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/README.txt
@@ -0,0 +1,31 @@
+Metatag Context
+---------------
+This module is provides a Metatag reaction for Context [1], thus allowing meta
+tags to be assigned to specific paths and other conditions.
+
+Configuration can controlled via the normal Context UI module or the new admin
+page available at: admin/config/search/metatags/context
+
+Included with the module are default Context configurations that may be enabled
+from the Context UI admin page and then customized as necessary. The included
+configurations are:
+  * user_login - for anonymous users accessing the user and user/login pages.
+  * user_register - for anonymous users accessing the user registration page.
+  * forum - for the main forum page from the Forum module. Topic pages are
+    handled as regular nodes, sub-forum pages are handled as regular term pages.
+  * blog - for the main blog page. Note: it does not cover the per-user blog
+    pages too.
+
+
+Credits
+------------------------------------------------------------------------------
+This module is based on the Context Metadata [2] module. The initial
+development was by Marcin Pajdzik [3] (sponsored by Dennis Publishing [4]).
+
+
+References
+------------------------------------------------------------------------------
+1: https://www.drupal.org/project/context
+2: https://www.drupal.org/project/context_metadata
+3: https://www.drupal.org/u/marcin-pajdzik
+4: http://www.dennis.co.uk/
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.admin.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.admin.inc
new file mode 100644
index 0000000000000000000000000000000000000000..edd17edf1f3fe6b1307bb53fbf235c7c12b7cc4e
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.admin.inc
@@ -0,0 +1,261 @@
+<?php
+/**
+ * @file
+ * Admin settings page for Metatag Context.
+ */
+
+/**
+ * Provides administration overview page for metatags by path settings.
+ */
+function metatag_context_context_overview() {
+  $contexts = context_enabled_contexts(TRUE);
+
+  $header = array(t('Name'), t('Paths'), t('Weight'), t('Operations'));  $rows = array();
+
+  $caption = t('Values assigned here inherit from the <a href="@url" title="Edit the global default meta tags.">global defaults</a>. Use the weight to specify the order the context meta tags run.', array('@url' => url('admin/config/search/metatags/config/global')));
+
+  foreach ($contexts as $name => $context) {
+    // Only show context items that are specifically selected to be "Shown on
+    // metatag admin page".
+    if (isset($context->reactions['metatag_context_reaction']['metatag_admin']) &&  $context->reactions['metatag_context_reaction']['metatag_admin']) {
+      $ops = array(
+        l(t('Edit'), 'admin/config/search/metatags/context/' . $context->name, array('query' => array('destination' => 'admin/config/search/metatags/context'))),
+        l(t('Delete'), 'admin/config/search/metatags/context/' . $context->name . '/delete', array('query' => array('destination' => 'admin/config/search/metatags/context'))),
+      );
+      $rows[] = array(
+        'name' => $context->name,
+        'path' => isset($context->conditions['path']) ? htmlspecialchars(implode(', ', $context->conditions['path']['values'])) : t('No path condition.'),
+        'weight' => isset($context->reactions['metatag_context_reaction']['weight']) ? $context->reactions['metatag_context_reaction']['weight'] : 0,
+        'ops' => implode(' | ', $ops),
+      );
+    }
+  }
+  uasort($rows, 'drupal_sort_weight');
+
+  return theme('table', array('header' => $header, 'rows' => $rows, 'caption' => $caption));
+}
+
+/**
+ * FormAPI callback to build the 'config_add' form.
+ */
+function metatag_context_config_add_form($form, &$form_state) {
+  $form['name'] = array(
+    '#title' => 'Name',
+    '#type' => 'textfield',
+    '#default_value' => '',
+    '#description' => 'The unique ID for this metatag path context rule. This must contain only lower case letters, numbers and underscores.',
+    '#required' => 1,
+    '#maxlength' => 255,
+    '#element_validate' => array('metatag_context_edit_name_validate'),
+  );
+
+  $form['actions']['#type'] = 'actions';
+  $form['actions']['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add and configure'),
+  );
+  $form['actions']['cancel'] = array(
+    '#type' => 'link',
+    '#title' => t('Cancel'),
+    '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags/context',
+  );
+  return $form;
+}
+
+/**
+ * FormAPI callback to validate the 'edit_name' field.
+ */
+function metatag_context_edit_name_validate($element, &$form_state) {
+  // Check for string identifier sanity.
+  if (!preg_match('!^[a-z0-9_-]+$!', $element['#value'])) {
+    form_error($element, t('The name can only consist of lowercase letters, underscores, dashes, and numbers.'));
+    return;
+  }
+
+  // Ensure the CTools exportables system is loaded.
+  ctools_include('export');
+
+  // Check for name collision.
+  if ($exists = ctools_export_crud_load('context', $element['#value'])) {
+    form_error($element, t('A context with this name already exists. Please choose another name or delete the existing item before creating a new one.'));
+  }
+}
+
+/**
+ * FormAPI callback to save the 'edit_name' form.
+ */
+function metatag_context_config_add_form_submit($form, &$form_state) {
+  $context = metatag_context_load_default_context();
+  $context->name = $form_state['values']['name'];
+  context_save($context);
+
+  // Update the i18n strings.
+  if (!empty($context->reactions['metatag_context_reaction']['metatags'][LANGUAGE_NONE])) {
+    metatag_translations_update($context->reactions['metatag_context_reaction']['metatags'][LANGUAGE_NONE], 'metatag_context:' . $context->name);
+  }
+
+  $form_state['redirect'] = 'admin/config/search/metatags/context/' . $context->name;
+}
+
+/**
+ * FormAPI callback to build the edit form.
+ */
+function metatag_context_config_edit_form($form, &$form_state, $context) {
+  $form_state['metatag_context']['context'] = $context;
+
+  // Empty form to start with.
+  $form = array();
+  // Don't care about the instance name, the data is being managed by Context
+  // and not Metatag.
+  $instance = "";
+  $options = array(
+    'token types' => array('node', 'term', 'user'),
+  );
+
+  $metatags = $context->reactions['metatag_context_reaction']['metatags'];
+  if (!isset($metatags[LANGUAGE_NONE])) {
+    $metatags = array(
+      LANGUAGE_NONE => $metatags,
+    );
+  }
+
+  // Load the METATAG form.
+  metatag_metatags_form($form, $instance, $metatags[LANGUAGE_NONE], $options);
+
+  $form['paths'] = array(
+    '#title' => 'Path',
+    '#description' => t('Set this metatag context when any of the paths above match the page path. Put each path on a separate line. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to exclude one or more paths. Use <code>&lt;front&gt;</code> for the site front page. Only local paths (e.g. "example/page") will work, do not use relative URLs ("/example/page") or absolute URLs ("http://example.com/example/page").'),
+    '#type' => 'textarea',
+    '#default_value' => isset($context->conditions['path']['values']) ? html_entity_decode(implode('&#13;&#10;', $context->conditions['path']['values'])) : '',
+    '#required' => 1,
+    '#weight' => -100,
+  );
+
+  // If other conditions are assigned, mention it.
+  $conditions = array_keys($context->conditions);
+  foreach ($conditions as $key => $condition) {
+    if ($condition == 'path') {
+      unset($conditions[$key]);
+    }
+  }
+  if (!empty($conditions)) {
+    $form['other_conditions'] = array(
+      '#prefix' => '<p><em>',
+      '#markup' => t('Other conditions have been assigned that must be controlled through the main Context settings page.'),
+      '#suffix' => '</em></p>',
+      '#weight' => -99.9,
+    );
+  }
+
+  $form['help'] = array(
+    '#prefix' => '<hr /><p><em>',
+    '#markup' => t('Values assigned here inherit from the <a href="@url" title="Edit the global default meta tags.">global defaults</a>.', array('@url' => url('admin/config/search/metatags/config/global'))),
+    '#suffix' => '</em></p>',
+    '#weight' => -99,
+  );
+
+  $form['metatags']['#type'] = 'container';
+  unset($form['metatags']['#collapsed']);
+  unset($form['metatags']['#collapsible']);
+
+  $form['actions']['#type'] = 'actions';
+  $form['actions']['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  $form['actions']['cancel'] = array(
+    '#type' => 'link',
+    '#title' => t('Cancel'),
+    '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags/context',
+  );
+  $form['#submit'][] = 'metatag_context_config_edit_form_submit';
+
+  return $form;
+}
+
+/**
+ * FormAPI callback for the final submission.
+ */
+function metatag_context_config_edit_form_submit($form, &$form_state) {
+  $context = $form_state['metatag_context']['context'];
+  $context->reactions['metatag_context_reaction']['metatags'] = $form_state['values']['metatags'];
+  $paths = explode("\n", str_replace("\r", "", $form_state['values']['paths']));
+  $paths = array_combine($paths, $paths);
+  $context->conditions['path']['values'] = $paths;
+  context_save($context);
+
+  // Update the i18n strings.
+  if (!empty($context->reactions['metatag_context_reaction']['metatags'][LANGUAGE_NONE])) {
+    metatag_translations_update($context->reactions['metatag_context_reaction']['metatags'][LANGUAGE_NONE], 'metatag_context:' . $context->name);
+  }
+
+  $form_state['redirect'] = 'admin/config/search/metatags/context';
+}
+
+/**
+ * FormAPI callback to build the 'delete' form.
+ */
+function metatag_context_delete_form($form, &$form_state, $context) {
+  $form_state['metatag_context']['context'] = $context;
+
+  $form['delete'] = array(
+    '#value' => 'This action will permanently remove this item from your database.'
+  );
+
+  $form['actions']['#type'] = 'actions';
+  $form['actions']['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Delete'),
+  );
+  $form['actions']['cancel'] = array(
+    '#type' => 'link',
+    '#title' => t('Cancel'),
+    '#href' => isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/search/metatags/context',
+  );
+  $form['#submit'][] = 'metatag_context_delete_form_submit';
+
+  return $form;
+}
+
+/**
+ * FormAPI submission callback for the 'delete' form.
+ */
+function metatag_context_delete_form_submit($form, &$form_state) {
+  context_delete($form_state['metatag_context']['context']);
+  $form_state['redirect'] = 'admin/config/search/metatags/context';
+}
+
+/**
+ * Create a default Metatag-focused context.
+ *
+ * @return object
+ *   A context structure in the form of a StdClass object.
+ */
+function metatag_context_load_default_context() {
+  $context = new stdClass();
+  $context->disabled = FALSE; /* Edit this to true to make a default context disabled initially */
+  $context->api_version = 3;
+  $context->name = 'default_metatag_context';
+  $context->description = '';
+  $context->tag = 'Metatag';
+  $context->metatag = TRUE;
+  $context->conditions = array(
+    'path' => array(
+      'values' => array(
+      ),
+    ),
+  );
+  $context->reactions = array(
+    'metatag_context_reaction' => array(
+      'metatags' => array(),
+      'metatag_admin' => 1,
+    ),
+  );
+  $context->condition_mode = 0;
+  $context->weight = 0;
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Metatag');
+  return $context;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.context.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.context.inc
new file mode 100644
index 0000000000000000000000000000000000000000..2a75cc77a5a5ffcac879b6befe4893b8efc5a8bb
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.context.inc
@@ -0,0 +1,340 @@
+<?php
+/**
+ * @file
+ * Context reaction for Metatag.
+ */
+
+class metatag_context_reaction extends context_reaction {
+  function options_form($context) {
+    $form = array();
+
+    // Don't care about the instance name, the data is being managed by
+    // Context and not Metatag.
+    $instance = "";
+
+    // Load the previously saved settings.
+    $data = $this->fetch_from_context($context);
+    if (!isset($data['metatags'])) {
+      $data['metatags'] = array();
+    }
+
+    // Support the pre-v1.0 data structures that were not nested with the
+    // language code.
+    if (!isset($data['metatags'][LANGUAGE_NONE])) {
+      $data['metatags'] = array(
+        LANGUAGE_NONE => $data['metatags'],
+      );
+    }
+
+    // Provide token types.
+    $options = array(
+      'token types' => array('node', 'term', 'user'),
+    );
+
+    $form['help'] = array(
+      '#prefix' => '<p><em>',
+      '#markup' => t('Values assigned here inherit from the <a href="@url" title="Edit the global default meta tags.">global defaults</a> and will override any other meta tags assigned elsewhere.', array('@url' => url('admin/config/search/metatags/config/global'))),
+      '#suffix' => '</em></p>',
+    );
+
+    $form['basic_header'] = array(
+      '#prefix' => '<hr /><h3>',
+      '#markup' => t('Basic tags'),
+      '#suffix' => '</h3>',
+    );
+
+    // Load the basic Metatag form.
+    metatag_metatags_form($form, $instance, $data['metatags'][LANGUAGE_NONE], $options);
+
+    // Stop the meta tag fields appearing within a fieldset.
+    $form['metatags']['#type'] = 'container';
+    unset($form['metatags']['#collapsed']);
+    unset($form['metatags']['#collapsible']);
+    unset($form['#submit']);
+
+    // Flatten the fieldsets because otherwise the Context module will not save
+    // them properly.
+    foreach (element_children($form['metatags'][LANGUAGE_NONE]) as $fieldset) {
+      $child = $form['metatags'][LANGUAGE_NONE][$fieldset];
+      if (isset($child['#type']) && $child['#type'] == 'fieldset') {
+        $form['metatags'][LANGUAGE_NONE][$fieldset . '_heading'] = array(
+          '#prefix' => '<hr /><h3>',
+          '#markup' => $form['metatags'][LANGUAGE_NONE][$fieldset]['#title'],
+          '#suffix' => '</h3>',
+        );
+        if (isset($form['metatags'][LANGUAGE_NONE][$fieldset]['#description'])) {
+          $form['metatags'][LANGUAGE_NONE][$fieldset . '_description'] = array(
+            '#prefix' => '<p>',
+            '#markup' => $form['metatags'][LANGUAGE_NONE][$fieldset]['#description'],
+            '#suffix' => '</p>',
+          );
+        }
+        foreach ($form['metatags'][LANGUAGE_NONE][$fieldset] as $key => $value) {
+          if (substr($key, 0, 1) == '#') {
+            unset($form['metatags'][LANGUAGE_NONE][$fieldset][$key]);
+            continue;
+          }
+          $form['metatags'][LANGUAGE_NONE][$key] = $value;
+          unset($form['metatags'][LANGUAGE_NONE][$key]['#parents']);
+          unset($form['metatags'][LANGUAGE_NONE][$fieldset][$key]);
+        }
+        unset($form['metatags'][LANGUAGE_NONE][$fieldset]);
+      }
+    }
+
+    // Show all takens.
+    $form['metatags']['tokens']['#token_types'] = 'all';
+
+    $form['metatag_admin'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show on metatag admin page.'),
+      '#weight' => -98,
+      '#default_value' => isset($data['metatag_admin']) ? $data['metatag_admin'] : '',
+    );
+
+    // Add weight for current metatag_context.
+    $default_weight = 0;
+    if (!empty($context->reactions['metatag_context_reaction']['weight'])) {
+      $default_weight = (int) $context->reactions['metatag_context_reaction']['weight'];
+    }
+    $form['weight'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Weight'),
+      '#size' => 2,
+      '#default_value' => $default_weight,
+      '#description' => t('A higher weight will make this context be executed later, overriding other context meta tags.'),
+      '#weight' => -99,
+    );
+
+    return $form;
+  }
+
+  /**
+   * Output a list of active contexts.
+   */
+  function execute() {
+    $output = &drupal_static('metatag_context');
+
+    if (!isset($output)) {
+      $metatags = array();
+      $output = array();
+      $contexts = context_active_contexts();
+      $options = array();
+      $instance_names = array();
+
+      foreach ($contexts as $context) {
+        if (!empty($context->reactions['metatag_context_reaction']['metatags'])) {
+          $metadata_array = $context->reactions['metatag_context_reaction']['metatags'];
+          if (isset($metadata_array[LANGUAGE_NONE])) {
+            $metadata_array = $metadata_array[LANGUAGE_NONE];
+          }
+
+          // Translate all of the meta tags using i18n, but don't update the
+          // strings.
+          metatag_translate_metatags($metadata_array, 'metatag_context:' . $context->name, NULL, FALSE);
+
+          // Add the meta tags to the output.
+          foreach ($metadata_array as $langcode => $tags) {
+            foreach ($tags as $name => $value) {
+              $metatags[$langcode][$name] = $value;
+            }
+          }
+
+          // Add this context to the list of instances.
+          $weight = isset($context->reactions['metatag_context_reaction']['weight'])
+            ? $context->reactions['metatag_context_reaction']['weight']
+            : 0;
+          $instance_names[] = array('name' => $context->name, 'weight' => $weight);
+        }
+      }
+
+      // Only proceed if metatags were assigned.
+      if (!empty($metatags)) {
+        // Load the global defaults.
+        $metatags += metatag_config_load_with_defaults('');
+
+        // Sort by weight.
+        uasort($instance_names, 'drupal_sort_weight');
+
+        // Keep names only.
+        $instance_names = array_map('current', $instance_names);
+
+        // Compile the identifier for this combination based on the context
+        // names.
+        $instance = 'context:' . implode(',', $instance_names);
+        $options['instance'] = $instance;
+
+        // If an entity & entity type were saved elsewhere, grab them for later.
+        // @see hook_entity_prepare_view().
+        $entities = drupal_static('metatag_context_entities');
+        if (!empty($entities) && (count($entities[1]) == 1)) {
+          $data = array_values($entities[1]);
+          $options['entity'] = $data[0];
+          $options['entity_type'] = $entities[0];
+          $options['token data'] = array($entities[0] => $data[0]);
+        }
+
+        // Don't output meta tags that only contain the pager.
+        $current_pager = metatag_get_current_pager();
+
+        foreach ($metatags as $metatag => $data) {
+          if ($metatag_instance = metatag_get_instance($metatag, $data)) {
+            $tag_output = $metatag_instance->getElement($options);
+            // Don't output the pager if that's all there is.
+            if ($tag_output != $current_pager) {
+              $output[$metatag] = $tag_output;
+            }
+          }
+        }
+
+        // Allow the output meta tags to be modified using
+        // hook_metatag_metatags_view_alter().
+        drupal_alter('metatag_metatags_view', $output, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_context_default_contexts().
+ */
+function metatag_context_context_default_contexts() {
+  $defaults = array();
+
+  $context = new stdClass();
+  $context->disabled = TRUE; /* Edit this to true to make a default context disabled initially */
+  $context->api_version = 3;
+  $context->name = 'metatag_context_user_login';
+  $context->description = 'A default Metatag:Context definition for the user login page. This needs to be enabled and then it can be customized as needed.';
+  $context->tag = 'Metatag';
+  $context->conditions = array(
+    'path' => array(
+      'values' => array(
+        'user' => 'user',
+        'user/login' => 'user/login',
+      ),
+    ),
+    'user' => array(
+      'values' => array(
+        'anonymous user' => 'anonymous user',
+      ),
+    ),
+  );
+  $context->reactions = array(
+    'metatag_context_reaction' => array(
+      'metatags' => array(
+        'und' => array(
+          'title' => array(
+            'value' => '[current-page:title] | [site:name]',
+            'default' => '[current-page:title] | [site:name]',
+          ),
+        ),
+      ),
+      'metatag_admin' => 1,
+    ),
+  );
+  $context->condition_mode = 1;
+  $defaults[$context->name] = $context;
+
+  $context = new stdClass();
+  $context->disabled = TRUE; /* Edit this to true to make a default context disabled initially */
+  $context->api_version = 3;
+  $context->name = 'metatag_context_user_register';
+  $context->description = 'A default Metatag:Context definition for the user registration page. This needs to be enabled and then it can be customized as needed.';
+  $context->tag = 'Metatag';
+  $context->conditions = array(
+    'path' => array(
+      'values' => array(
+        'user/register' => 'user/register',
+      ),
+    ),
+    'user' => array(
+      'values' => array(
+        'anonymous user' => 'anonymous user',
+      ),
+    ),
+  );
+  $context->reactions = array(
+    'metatag_context_reaction' => array(
+      'metatags' => array(
+        'und' => array(
+          'title' => array(
+            'value' => '[current-page:title] | [site:name]',
+            'default' => '[current-page:title] | [site:name]',
+          ),
+        ),
+      ),
+      'metatag_admin' => 1,
+    ),
+  );
+  $context->condition_mode = 1;
+  $defaults[$context->name] = $context;
+
+  if (module_exists('forum')) {
+    $context = new stdClass();
+    $context->disabled = TRUE; /* Edit this to true to make a default context disabled initially */
+    $context->api_version = 3;
+    $context->name = 'metatag_context_forum';
+    $context->description = 'A default Metatag:Context definition for the main forum page. This needs to be enabled and then it can be customized as needed.';
+    $context->tag = 'Metatag';
+    $context->conditions = array(
+      'path' => array(
+        'values' => array(
+          'forum' => 'forum',
+        ),
+      ),
+    );
+    $context->reactions = array(
+      'metatag_context_reaction' => array(
+        'metatags' => array(
+          'und' => array(
+            'title' => array(
+              'value' => '[current-page:title] | [site:name]',
+              'default' => '[current-page:title] | [site:name]',
+            ),
+          ),
+        ),
+        'metatag_admin' => 1,
+      ),
+    );
+    $context->condition_mode = 1;
+    $defaults[$context->name] = $context;
+  }
+
+  if (module_exists('blog')) {
+    $context = new stdClass();
+    $context->disabled = TRUE; /* Edit this to true to make a default context disabled initially */
+    $context->api_version = 3;
+    $context->name = 'metatag_context_blog';
+    $context->description = 'A default Metatag:Context definition for the main blog page. This needs to be enabled and then it can be customized as needed. Note: this does not cover the individual user blog pages, only the main blog page.';
+    $context->tag = 'Metatag';
+    $context->conditions = array(
+      'path' => array(
+        'values' => array(
+          'blog' => 'blog',
+        ),
+      ),
+    );
+    $context->reactions = array(
+      'metatag_context_reaction' => array(
+        'metatags' => array(
+          'und' => array(
+            'title' => array(
+              'value' => '[current-page:title] | [site:name]',
+              'default' => '[current-page:title] | [site:name]',
+            ),
+          ),
+        ),
+        'metatag_admin' => 1,
+      ),
+    );
+    $context->condition_mode = 1;
+    $defaults[$context->name] = $context;
+  }
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Metatag');
+
+  return $defaults;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.i18n.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.i18n.inc
new file mode 100644
index 0000000000000000000000000000000000000000..676b78de8f096bda4a2214325a2b8de0bc88d27c
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.i18n.inc
@@ -0,0 +1,126 @@
+<?php
+/**
+ * @file
+ * Internationalization (i18n) hooks.
+ */
+
+/**
+ * Implements hook_i18n_object_info().
+ */
+function metatag_context_i18n_object_info() {
+  $info['metatag_context'] = array(
+    'title' => t('Metatag:Context configurations'),
+    // Callback to load all config objects.
+    'list callback' => 'metatag_context_i18n_list_contexts',
+    // The object load callback.
+    // 'load callback' => 'metatag_context_i18n_load',
+    // @todo Custom i18n object overrides.
+    // 'class' => 'metatag_context_i18n_metatag',
+    // @todo Is this needed? What does it do?
+    // 'translation set' => TRUE,
+
+    // The object key field.
+    'key' => 'name',
+    // Placeholders for automatic paths. This connects the 'key' to strings in
+    // the paths listed below.
+    // 'placeholders' => array(
+    //   '%name' => 'name',
+    // ),
+    // To produce edit links automatically.
+    // 'edit path' => 'admin/config/search/metatags/config/%instance',
+    // Auto-generate a 'translate' tab.
+    // 'translate tab' => 'admin/config/search/metatags/config/%instance/translate',
+
+    // Properties for string translation.
+    'string translation' => array(
+      // The textgroup, type and (below) name will be concatenated into a single
+      // string as the {locales_source} context.
+      'textgroup' => 'metatag',
+      'type' => 'metatag_context',
+      // Table where the object is stored, to automate string lists.
+      'table' => 'context',
+      // Translatable properties of these objects, this will be added later.
+      'properties' => array(),
+      // The path to translate individual strings.
+      // 'translate path' => 'admin/config/search/metatags/config/%instance/translate/%i18n_language',
+    ),
+  );
+
+  // Compile all of the tags to add to the translation stack.
+  $meta_tag_info = metatag_get_info();
+  $groups = $meta_tag_info['groups'];
+  foreach ($meta_tag_info['tags'] as $tag_info) {
+    // Ignore certain field types that aren't translatable, mostly fields that
+    // list predetermined options in various forms.
+    if (!empty($tag_info['class']) && $tag_info['class'] == 'DrupalListMetaTag') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#type']) && $tag_info['form']['#type'] == 'select') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#options'])) {
+      continue;
+    }
+
+    // Build a suitable structure for this meta tag.
+    $tag_name = $tag_info['name'];
+    $tag_group = $tag_info['group'];
+    $group_label = isset($groups[$tag_group]['label']) ? $groups[$tag_group]['label'] : $tag_group;
+    $info['metatag_context']['string translation']['properties'][$tag_name] = array(
+      'title' => $group_label . ': ' . $tag_info['label'],
+      'field' => "reactions.metatag_context_reaction.und.{$tag_name}.value",
+    );
+  }
+
+  return $info;
+}
+
+/**
+ * Implements hook_i18n_string_list().
+ *
+ * @todo Functionality to delete translation records when Panels are deleted.
+ */
+function metatag_context_i18n_string_list($group) {
+  if ($group == 'metatag' || $group == 'all') {
+    $strings = array();
+
+    foreach (context_context_list() as $context_name) {
+      $context = context_load($context_name);
+      if (!empty($context->reactions['metatag_context_reaction']['metatags'][LANGUAGE_NONE])) {
+        $new_strings = array();
+        foreach ($context->reactions['metatag_context_reaction']['metatags'][LANGUAGE_NONE] as $name => $value) {
+          if (isset($value['value'])) {
+            // Don't translate meta tags that are arrays.
+            if (is_array($value['value'])) {
+              continue;
+            }
+            // Collapse the array down one level.
+            else {
+              $new_strings[$name] = $value['value'];
+            }
+          }
+        }
+        $strings['metatag']['metatag_context'][$context->name] = $new_strings;
+      }
+    }
+
+    return $strings;
+  }
+}
+
+/**
+ * List callback.
+ */
+function metatag_context_i18n_list_contexts() {
+  ctools_include('export');
+  $configs = ctools_export_crud_load_all('metatag_config');
+  if (!empty($configs)) {
+    // Unserialize the config array.
+    foreach ($configs as &$config) {
+      if (is_string($config->config)) {
+        $config->config = unserialize($config->config);
+      }
+    }
+    return $configs;
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.info b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.info
new file mode 100644
index 0000000000000000000000000000000000000000..28758f71381cc7c88ac8dfc02e9cb8136e561742
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.info
@@ -0,0 +1,20 @@
+name = Metatag: Context
+description = "Assigned Metatag using Context definitions, allowing them to be assigned by path and other criteria."
+package = SEO
+core = 7.x
+
+configure = admin/config/search/metatags/context
+
+dependencies[] = metatag:metatag
+dependencies[] = context:context
+
+; Tests.
+files[] = tests/metatag_context.test
+files[] = tests/metatag_context.i18n.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.install b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.install
new file mode 100644
index 0000000000000000000000000000000000000000..78415ce60305a4e2101699c3e87e909c00d55725
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.install
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Installation and update hooks for Metatag:Context.
+ */
+
+/**
+ * Implements hook_enable().
+ */
+function metatag_context_enable() {
+  // Clear the cache so Context and CTools know about this plugin.
+  cache_clear_all('plugins:context:plugins', 'cache');
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5a9058cccf77cf102322781f2622993a421cc9ed
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.metatag.inc
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_context module.
+ */
+
+/**
+ * Implements hook_metatag_config_instance_info().
+ */
+function metatag_context_metatag_config_instance_info() {
+  $info['context'] = array('label' => t('Context'));
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.module b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.module
new file mode 100644
index 0000000000000000000000000000000000000000..0e54f352a4b034eb0efa805005f41678560b54ad
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/metatag_context.module
@@ -0,0 +1,132 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag Context.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function metatag_context_menu() {
+  $items['admin/config/search/metatags/context'] = array(
+    'title' => 'By path',
+    'page callback' => 'metatag_context_context_overview',
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag_context.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['admin/config/search/metatags/context/add'] = array(
+    'title' => 'Add a meta tag by path',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_context_config_add_form'),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag_context.admin.inc',
+    'type' => MENU_LOCAL_ACTION,
+  );
+  $items['admin/config/search/metatags/context/%context'] = array(
+    'title' => 'Configure metatags by path',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_context_config_edit_form', 5),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag_context.admin.inc',
+  );
+  $items['admin/config/search/metatags/context/%context/delete'] = array(
+    'title' => 'Delete metatags by path',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_context_delete_form', 5),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag_context.admin.inc',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_context_plugins().
+ */
+function metatag_context_context_plugins() {
+  return array(
+    'metatag_context_reaction' => array(
+      'handler' => array(
+        'path' => drupal_get_path('module', 'metatag_context'),
+        'file' => 'metatag_context.context.inc',
+        'class' => 'metatag_context_reaction',
+        'parent' => 'context_reaction',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_context_registry().
+ */
+function metatag_context_context_registry() {
+  return array(
+    'reactions' => array(
+      'metatag_context_reaction' => array(
+        'title' => t('Meta Data'),
+        'description' => t('Control page meta tags using the Metatag module.'),
+        'plugin' => 'metatag_context_reaction',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_context_page_reaction().
+ */
+function metatag_context_context_page_reaction() {
+  if ($plugin = context_get_plugin('reaction', 'metatag_context_reaction')) {
+    $plugin->execute();
+  }
+}
+
+/**
+ * Implements hook_entity_prepare_view().
+ */
+function metatag_context_entity_prepare_view($entities, $entity_type, $langcode = NULL) {
+  // Store the current entities.
+  drupal_static('metatag_context_entities', array($entity_type, $entities));
+}
+
+/**
+ * Implements hook_page_alter().
+ */
+function metatag_context_page_alter(&$page) {
+  // By default do not add meta tags to admin pages. To enable meta tags on
+  // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+  if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+    return;
+  }
+
+  // Load the meta tags that have been generated for this page.
+  $metatags = drupal_static('metatag_context', array());
+
+  if (!empty($metatags)) {
+    // The page region can be changed.
+    $region = variable_get('metatag_page_region', 'content');
+    $page[$region]['metatags']['context'] = $metatags;
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_context_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "context" && $api == "context") {
+    return array("version" => "3");
+  }
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function metatag_context_module_implements_alter(&$implementations, $hook) {
+  if ($hook == 'page_alter') {
+    // Run metatag_context_page_alter() last.
+    $group = $implementations['metatag_context'];
+    unset($implementations['metatag_context']);
+    $implementations['metatag_context'] = $group;
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context.i18n.test b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context.i18n.test
new file mode 100644
index 0000000000000000000000000000000000000000..12e9495f4b2a028d12a6061e91df2f2818e1f09a
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context.i18n.test
@@ -0,0 +1,139 @@
+<?php
+
+/**
+ * Tests the Metatag:Context module for i18n integration.
+ */
+class MetatagContextI18nTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag:Context tests, with i18n',
+      'description' => 'Test Metatag integration with the Context and i18n modules.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'context', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'context';
+    $modules[] = 'metatag_context';
+
+    // Enable the hidden submodule to manage some default configs.
+    $modules[] = 'metatag_context_tests';
+
+    // Needed for translations.
+    $modules[] = 'locale';
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable all of the modules that are needed.
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'translate admin strings',
+      'translate user-defined strings',
+      // Needed for the content type.
+      'administer languages',
+      'translate interface',
+      'bypass node access',
+    );
+    // This replaces the one from MetatagContextTest().
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+    
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+  /**
+   * Verify that strings are added to the translation system.
+   */
+  public function testContextI18n() {
+    // Generate a test object with English strings.
+    $object_en = $this->createTestObject('frontpage_metatags', '<front>');
+    // Generate a copy of that object only designed for loading on the French
+    // front page.
+    $object_fr = $this->createTestObject('frontpage_metatags', 'fr');
+    foreach (array('title', 'description', 'abstract', 'keywords') as $tag) {
+      $object_fr->$tag = $object_fr->$tag . ' in French';
+    }
+
+    // Create the English test object and check their content.
+    $this->generateByPathConfig($object_en);
+    $this->editByPathConfig($object_en);
+    $this->checkByPathConfig($object_en);
+
+    // Check each of the meta tags that were transmitted.
+    foreach (array('title', 'description', 'abstract', 'keywords') as $tag) {
+      $i18n_context = 'metatag_context:' . $object_en->name . ':' . $tag;
+      $lid = $this->getTranslationLidByContext($i18n_context);
+      $this->assertNotEqual($lid, 0, "Found the {locales_source} record for the {$tag} tag.");
+
+      // Save a translation for this tag.
+      $this->saveTranslationString($lid, $i18n_context, 'fr', $object_en->$tag, $object_fr->$tag);
+    }
+
+    // Confirm the configuration still works.
+    $this->checkByPathConfig($object_en);
+
+    // Confirm the French configuration works too.
+    $this->checkByPathConfig($object_fr);
+  }
+
+  /**
+   * Test the Metatag:Context translations for an exported configuration.
+   */
+  public function testExportedContext() {
+    // Plan out the different translation string tests.
+    $string_en = 'Metatag:Context test description tag.';
+    $string_fr = 'French page description';
+    $config_name = 'metatag_context:metatag_context_test:description';
+    $path = 'metatag-context-test';
+
+    // Confirm the string is present as it has been grabbed by the string-
+    // refresh triggered in $this->setUp().
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the generator tag.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the description tag.');
+
+    // Save the translation string.
+    $this->saveTranslationString($lid, $config_name, 'fr', $string_en, $string_fr);
+
+    // Load the English page again.
+    $this->drupalGet($path);
+    $this->assertResponse(200, 'Loaded the default test page again.');
+
+    // Confirm the page's description is what we set it to.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_en);
+    $this->assertNotEqual($xpath[0]['content'], $string_fr);
+
+    // Load the French page.
+    $this->drupalGet('fr/' . $path);
+    $this->assertResponse(200, 'Loaded the French test page.');
+
+    // Confirm the generator string was translated.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_fr);
+    $this->assertNotEqual($xpath[0]['content'], $string_en);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context.test b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context.test
new file mode 100644
index 0000000000000000000000000000000000000000..aea205ac516a8fd86d277becd93fd84845714618
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context.test
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * Functional tests for the Metatag:Context module.
+ */
+class MetatagContextTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag:Context tests',
+      'description' => 'Test basic Metatag:Context functionality.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'context'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'context';
+    $modules[] = 'metatag_context';
+
+    // Enable the hidden submodule to manage some default configs.
+    $modules[] = 'metatag_context_tests';
+
+    parent::setUp($modules);
+
+    // Create user.
+    $perms = array(
+      'bypass node access',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Create a content type, with underscores.
+    $type_name = strtolower($this->randomName(8)) . '_test';
+    $type = $this->createContentType($type_name, $type_name);
+    $this->type = $type->type;
+
+    // Store a valid URL name, with hyphens instead of underscores.
+    $this->hyphen_type = str_replace('_', '-', $this->type);
+  }
+
+  /**
+   * Test handling a node.
+   */
+  public function testNode() {
+    // Create a node.
+    $this->drupalPost('node/add/' . $this->hyphen_type, array('title' => $this->randomName(8)), t('Save'));
+    $this->assertResponse(200);
+
+    // Generate metatags and check content.
+    $test_object = $this->createTestObject('node_metatags', 'node/1');
+    $this->generateByPathConfig($test_object);
+    $this->editByPathConfig($test_object);
+    $this->checkByPathConfig($test_object);
+
+    // Edit metatag and check content.
+    $test_object->title = 'New title';
+    $test_object->description = '';
+    $this->editByPathConfig($test_object);
+    $this->checkByPathConfig($test_object);
+  }
+
+  /**
+   * Test handling the front page.
+   */
+  public function testFrontPage() {
+    // Generate metatags and check content.
+    $test_object = $this->createTestObject('frontpage_metatags', '<front>');
+    $this->generateByPathConfig($test_object);
+    $this->editByPathConfig($test_object);
+    $this->checkByPathConfig($test_object);
+
+    // Edit metatag and check content.
+    $test_object->title = 'A different title';
+    $test_object->description = '';
+    $this->editByPathConfig($test_object);
+    $this->checkByPathConfig($test_object);
+  }
+
+  /**
+   * Test the Context integration.
+   */
+  public function testExportedPage() {
+    $this->drupalGet('metatag-context-test');
+    $this->assertResponse(200);
+
+    // Test the page title.
+    $this->assertTitle('Metatag:Context test page title tag');
+
+    // Test the description meta tag.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Metatag:Context test description tag.');
+
+    // Test the keywords meta tag.
+    $xpath = $this->xpath("//meta[@name='keywords']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one keywords meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Test, page, keywords');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.context.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.context.inc
new file mode 100644
index 0000000000000000000000000000000000000000..83481c3b7fd303948430c4b98bb5c4aea2dd5349
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.context.inc
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @file
+ * Context reaction for Metatag:Context tests.
+ */
+
+/**
+ * Implements hook_context_default_contexts().
+ */
+function metatag_context_tests_context_default_contexts() {
+  $defaults = array();
+
+  $context = new stdClass();
+  $context->disabled = FALSE; /* Edit this to true to make a default context disabled initially */
+  $context->api_version = 3;
+  $context->name = 'metatag_context_test';
+  $context->description = 'A default Metatag:Context definition for a test page.';
+  $context->tag = 'Metatag';
+  $context->conditions = array(
+    'path' => array(
+      'values' => array(
+        'metatag-context-test' => 'metatag-context-test',
+      ),
+    ),
+  );
+  $context->reactions = array(
+    'metatag_context_reaction' => array(
+      'metatags' => array(
+        'und' => array(
+          'title' => array(
+            'value' => 'Metatag:Context test page title tag',
+          ),
+          'description' => array(
+            'value' => 'Metatag:Context test description tag.',
+          ),
+          'abstract' => array(
+            'value' => '',
+          ),
+          'keywords' => array(
+            'value' => 'Test, page, keywords',
+          ),
+        ),
+      ),
+      'metatag_admin' => 1,
+    ),
+  );
+  $context->condition_mode = 1;
+  $defaults[$context->name] = $context;
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('A default Metatag:Context definition for a test page.');
+  t('Metatag');
+
+  return $defaults;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.info b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.info
new file mode 100644
index 0000000000000000000000000000000000000000..14a3a3edbb551b38ff39c4fd157a6eb95e22fbe0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.info
@@ -0,0 +1,17 @@
+name = Metatag:Context Tests
+description = Helper module for testing metatag_context.module.
+core = 7.x
+
+; Don't show this on the modules admin page.
+hidden = TRUE
+
+dependencies[] = context:context
+dependencies[] = metatag:metatag
+dependencies[] = metatag:metatag_context
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.module b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.module
new file mode 100644
index 0000000000000000000000000000000000000000..01986d5972fe807a0cd24945dec825f06d1f620d
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_context/tests/metatag_context_tests.module
@@ -0,0 +1,35 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag:Context tests.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_context_tests_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "context" && $api == "context") {
+    return array("version" => "3");
+  }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function metatag_context_tests_menu() {
+  $items['metatag-context-test'] = array(
+    'title' => t('Metatag:Context test page'),
+    'page callback' => 'metatag_context_tests_test_page',
+    'access callback' => TRUE,
+  );
+
+  return $items;
+}
+
+/**
+ * Menu callback for displaying the test page.
+ */
+function metatag_context_tests_test_page() {
+  return t('Hello');
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ffa30ecb340c71fdf826305afab9eec3bf504500
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/README.txt
@@ -0,0 +1,37 @@
+Metatag: Dublin Core
+--------------------
+This module adds the fifteen Dublin Core Metadata Element Set [1] to the
+available meta tags, as defined by the Dublin Core Metadata Institute [2]. Forty
+additional tags may be added via the Metatag: Dublin Core Advanced submodule.
+
+The following tags are provided:
+* 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
+
+
+Credits
+------------------------------------------------------------------------------
+The initial development was by Marty2081 [3] (sponsored by Gemeentemuseum Den
+Haag. [4]), with contributions by many in the community [5].
+
+
+References
+------------------------------------------------------------------------------
+1: http://www.dublincore.org/documents/dces/
+2: http://www.dublincore.org/
+3: https://www.drupal.org/u/marty2081
+4: http://www.gemeentemuseum.nl/
+5: https://www.drupal.org/node/1491616
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.info b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.info
new file mode 100644
index 0000000000000000000000000000000000000000..43b22a3a592c36b04a41cb8f16efd6b091761b58
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.info
@@ -0,0 +1,16 @@
+name = Metatag: Dublin Core
+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>.
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_dc.test
+files[] = tests/metatag_dc.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.install b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.install
new file mode 100644
index 0000000000000000000000000000000000000000..71c5abb6b8cdeaff68a4641787bc47edf5c669cf
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.install
@@ -0,0 +1,12 @@
+<?php
+/**
+ * @file
+ * Installation and update scripts for metatag_dc_advanced.
+ */
+
+/**
+ * The Dublic Core Additional Tags meta tags are now in a new submodule.
+ */
+function metatag_dc_update_7100() {
+  drupal_set_message(t('The Dublic Core Additional Tags meta tags have been moved into the new "Metatag: Dublin Core Advanced" submodule.'));
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ae0a7c8b44a9520901742bff659df04c26a833e5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.metatag.inc
@@ -0,0 +1,212 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_dc module.
+ */
+
+/**
+ * Implements hook_metatag_bundled_config_alter().
+ */
+function metatag_dc_metatag_bundled_config_alter(array &$configs) {
+  foreach ($configs as &$config) {
+    switch ($config->instance) {
+      case 'global':
+        $config->config += array(
+          'dcterms.format' => array('value' => 'text/html'),
+          'dcterms.identifier' => array('value' => '[current-page:url:absolute]'),
+          'dcterms.title' => array('value' => '[current-page:title]'),
+          'dcterms.type' => array('value' => 'Text'),
+        );
+        break;
+
+      case 'global:frontpage':
+        $config->config += array(
+          'dcterms.description' => array('value' => '[site:slogan]'),
+          'dcterms.identifier' => array('value' => '[site:url]'),
+          'dcterms.title' => array('value' => '[site:name]'),
+        );
+        break;
+
+      // On error pages point everything to the homepage.
+      case 'global:403':
+      case 'global:404':
+        $config->config += array(
+          'dcterms.identifier' => array('value' => '[site:url]'),
+          'dcterms.title' => array('value' => '[site:name]'),
+        );
+        break;
+
+      case 'node':
+        $config->config += array(
+          'dcterms.creator' => array('value' => '[node:author]'),
+          'dcterms.date' => array('value' => '[node:created:custom:Y-m-d\TH:iP]'),
+          'dcterms.description' => array('value' => '[node:summary]'),
+          'dcterms.language' => array('value' => '[node:language]'),
+          'dcterms.title' => array('value' => '[node:title]'),
+        );
+        break;
+
+      case 'taxonomy_term':
+        $config->config += array(
+          'dcterms.description' => array('value' => '[term:description]'),
+          'dcterms.title' => array('value' => '[term:name]'),
+        );
+        break;
+
+      case 'user':
+        $config->config += array(
+          'dcterms.creator' => array('value' => '[user:name]'),
+          'dcterms.date' => array('value' => '[user:created:custom:Y-m-d\TH:iP]'),
+          'dcterms.title' => array('value' => '[user:name]'),
+        );
+        break;
+    }
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ * Dublin Core Elements taken from http://purl.org/dc/elements/1.1/.
+ */
+function metatag_dc_metatag_info() {
+  $info['groups']['dublin-core'] = array(
+    'label' => t('Dublin Core Basic Tags'),
+    'description' => t('The Dublin Core Metadata Element Set, aka "Dublin Core meta tags", are a set of internationally standardized metadata tags used to describe content to make identification and classification of content easier; the standards are controlled by the <a href="@url">Dublin Core Metadata Initiative (DCMI)</a>.', array('@url' => 'http://dublincore.org/')),
+    'form' => array(
+      '#weight' => 70,
+    ),
+  );
+
+  // Dublin Core meta tags stack after the Twitter Cards tags.
+  $weight = 70;
+
+  // Basic tags.
+  $defaults = array(
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'dublin-core',
+    'element' => array(
+      '#type' => 'term',
+      '#theme' => 'metatag_dc',
+    ),
+  );
+
+  $info['tags']['dcterms.title'] = array(
+    'label' => t('Title'),
+    'description' => t('The name given to the resource.'),
+    'element' => array(
+      '#type' => 'term',
+      '#theme' => 'metatag_dc',
+    ),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.creator'] = array(
+    'label' => t('Creator'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.subject'] = array(
+    'label' => t('Subject'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.description'] = array(
+    'label' => t('Description'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.publisher'] = array(
+    'label' => t('Publisher'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.contributor'] = array(
+    'label' => t('Contributor'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.date'] = array(
+    'label' => t('Date'),
+    'description' => t('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].'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  ) + $defaults;
+  $info['tags']['dcterms.type'] = array(
+    'label' => t('Type'),
+    'description' => t('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.'),
+    'form' => array(
+      '#type' => 'select',
+      '#options' => _metatag_dc_dcmi_type_vocabulary_options(),
+      '#empty_option' => t('- None -'),
+    ),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.format'] = array(
+    'label' => t('Format'),
+    'description' => t('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].'),
+    'devel_generate' => array(
+      'maxlength' => 1,
+    ),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.identifier'] = array(
+    'label' => t('Identifier'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.source'] = array(
+    'label' => t('Source'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.language'] = array(
+    'label' => t('Language'),
+    'description' => t('A language of the resource. Recommended best practice is to use a controlled vocabulary such as RFC 4646 [RFC4646].'),
+    'is_language' => TRUE,
+    'devel_generate' => array(
+      'maxlength' => 1,
+    ),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.relation'] = array(
+    'label' => t('Relation'),
+    'description' => t('A related resource. Recommended best practice is to identify the related resource by means of a string conforming to a formal identification system.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.coverage'] = array(
+    'label' => t('Coverage'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.rights'] = array(
+    'label' => t('Rights'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  return $info;
+}
+
+/**
+ * List the DCMI 'type' options.
+ *
+ * Types taken from http://dublincore.org/documents/dcmi-type-vocabulary/.
+ */
+function _metatag_dc_dcmi_type_vocabulary_options() {
+  $options = array(
+    'Collection',
+    'Dataset',
+    'Event',
+    'Image',
+    'InteractiveResource',
+    'MovingImage',
+    'PhysicalObject',
+    'Service',
+    'Software',
+    'Sound',
+    'StillImage',
+    'Text',
+  );
+  return drupal_map_assoc($options);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.module b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.module
new file mode 100644
index 0000000000000000000000000000000000000000..648fab0f2989c2a45ae79f8fadf61f84a4980c9c
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/metatag_dc.module
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_dc module.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_dc_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_dc_theme() {
+  $info['metatag_dc'] = array(
+    'render element' => 'element',
+  );
+
+  return $info;
+}
+
+/**
+ * Theme callback for a Dublin Core meta tag.
+ */
+function theme_metatag_dc($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name' => 'name',
+    '#schema' => 'schema',
+    '#value' => 'content',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc/tests/metatag_dc.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/tests/metatag_dc.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..8ef5f0456f1ac93df914fce5e2328ca74a2c94d8
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/tests/metatag_dc.tags.test
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Dublin Core tags work correctly.
+ */
+class MetatagDcTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Dublin Core',
+      'description' => 'Test the Dublin Core meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    '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}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_dc';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    return str_replace('dcterms_', 'dcterms.', $tag_name);
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_key() for 'dcterms.type'.
+   */
+  public function dcterms_type_test_key() {
+    return 'metatags[und][dcterms.type][value]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'dcterms.type'.
+   */
+  public function dcterms_type_test_value() {
+    return 'Text';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'dcterms.type'.
+   */
+  public function dcterms_type_test_field_xpath() {
+    return "//select[@name='metatags[und][dcterms.type][value]']";
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc/tests/metatag_dc.test b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/tests/metatag_dc.test
new file mode 100644
index 0000000000000000000000000000000000000000..00049db2e61ab7f522833d36353a2cb75e6dfb09
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc/tests/metatag_dc.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag DC module.
+ */
+class MetatagDcTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag DC tests',
+      'description' => 'Test the Metatag:DC module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_dc';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a6dc051bbdce96a59ba0420ecbd808a111c984f5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/README.txt
@@ -0,0 +1,52 @@
+Metatag: Dublin Core Advanced
+-----------------------------
+This module adds the forty additional Dublin Core Metadata tags to the available
+meta tags, as defined by the Dublin Core Metadata Institute [1]; it also adds
+forty tags which may be useful for certain sites.
+
+Additional DCMI Metadata Terms meta tags:
+* dcterms.abstract
+* dcterms.accessRights
+* dcterms.accrualMethod
+* dcterms.accrualPeriodicity
+* dcterms.accrualPolicy
+* dcterms.alternative
+* dcterms.audience
+* dcterms.available
+* dcterms.bibliographicCitation
+* dcterms.conformsTo
+* dcterms.created
+* dcterms.dateAccepted
+* dcterms.dateCopyrighted
+* dcterms.dateSubmitted
+* dcterms.educationLevel
+* dcterms.extent
+* dcterms.hasFormat
+* dcterms.hasPart
+* dcterms.hasVersion
+* dcterms.instructionalMethod
+* dcterms.isFormatOf
+* dcterms.isPartOf
+* dcterms.isReferencedBy
+* dcterms.isReplacedBy
+* dcterms.isRequiredBy
+* dcterms.isVersionOf
+* dcterms.issued
+* dcterms.license
+* dcterms.mediator
+* dcterms.medium
+* dcterms.modified
+* dcterms.provenance
+* dcterms.references
+* dcterms.replaces
+* dcterms.requires
+* dcterms.rightsHolder
+* dcterms.spatial
+* dcterms.tableOfContents
+* dcterms.temporal
+* dcterms.valid
+
+
+References
+------------------------------------------------------------------------------
+1: http://www.dublincore.org/
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.info b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.info
new file mode 100644
index 0000000000000000000000000000000000000000..eb9f8fd0c11f5721b1cc5203ba6530e5797ff5ed
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.info
@@ -0,0 +1,17 @@
+name = Metatag: Dublin Core Advanced
+description = Provides forty additional meta tags from the <a href="http://dublincore.org/">Dublin Core Metadata Institute</a>.
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+dependencies[] = metatag:metatag_dc
+
+; Tests.
+files[] = tests/metatag_dc_advanced.test
+files[] = tests/metatag_dc_advanced.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1fe3a6d63ad91dd23135e756cd046e63fea5b4bf
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.metatag.inc
@@ -0,0 +1,268 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_dc module.
+ */
+
+/**
+ * Implements hook_metatag_bundled_config_alter().
+ */
+function metatag_dc_advanced_metatag_bundled_config_alter(array &$configs) {
+  foreach ($configs as &$config) {
+    switch ($config->instance) {
+      case 'node':
+        $config->config += array(
+          'dcterms.modified' => array('value' => '[node:changed:custom:Y-m-d\TH:iP]'),
+        );
+        break;
+    }
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ * Dublin Core Elements taken from http://purl.org/dc/elements/1.1/.
+ */
+function metatag_dc_advanced_metatag_info() {
+  $info['groups']['dublin-core-additional'] = array(
+    'label' => t('Dublin Core Additional Tags'),
+    'description' => t('These tags are not part of the Metadata Element Set but may be useful for certain scenarios.'),
+    'form' => array(
+      '#weight' => 71,
+    ),
+  );
+
+  // Dublin Core meta tags stack after the Twitter Cards tags.
+  $weight = 80;
+
+  // Additional tags.
+  $defaults = array(
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'dublin-core-additional',
+    'element' => array(
+      '#type' => 'term',
+      '#theme' => 'metatag_dc',
+    ),
+  );
+
+  $info['tags']['dcterms.abstract'] = array(
+    'label' => t('Abstract'),
+    'description' => t('A summary of the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.accessRights'] = array(
+    'label' => t('Access rights'),
+    'description' => t('Information about who can access the resource or an indication of its security status.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.accrualMethod'] = array(
+    'label' => t('Accrual Method'),
+    'description' => t('The method by which items are added to a collection.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.accrualPeriodicity'] = array(
+    'label' => t('Accrual Periodicity'),
+    'description' => t('The frequency with which items are added to a collection.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.accrualPolicy'] = array(
+    'label' => t('Accrual Policy'),
+    'description' => t('The policy governing the addition of items to a collection.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.alternative'] = array(
+    'label' => t('Alternative Title'),
+    'description' => t('An alternative name for the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.audience'] = array(
+    'label' => t('Audience'),
+    'description' => t('A class of entity for whom the resource is intended or useful.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.available'] = array(
+    'label' => t('Date Available'),
+    'description' => t('Date (often a range) that the resource became or will become available.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  ) + $defaults;
+  $info['tags']['dcterms.bibliographicCitation'] = array(
+    'label' => t('Bibliographic Citation'),
+    'description' => t('A bibliographic reference for the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.conformsTo'] = array(
+    'label' => t('Conforms To'),
+    'description' => t('An established standard to which the described resource conforms.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.created'] = array(
+    'label' => t('Date Created'),
+    'description' => t('Date of creation of the resource.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  ) + $defaults;
+  $info['tags']['dcterms.dateAccepted'] = array(
+    'label' => t('Date Accepted'),
+    'description' => t('Date of acceptance of the resource.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  ) + $defaults;
+  $info['tags']['dcterms.dateCopyrighted'] = array(
+    'label' => t('Date Copyrighted'),
+    'description' => t('Date of copyright.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  ) + $defaults;
+  $info['tags']['dcterms.dateSubmitted'] = array(
+    'label' => t('Date Submitted'),
+    'description' => t('Date of submission of the resource.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  ) + $defaults;
+  $info['tags']['dcterms.educationLevel'] = array(
+    'label' => t('Audience Education Level'),
+    'description' => t('A class of entity, defined in terms of progression through an educational or training context, for which the described resource is intended.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.extent'] = array(
+    'label' => t('Extent'),
+    'description' => t('The size or duration of the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.hasFormat'] = array(
+    'label' => t('Has Format'),
+    'description' => t('A related resource that is substantially the same as the pre-existing described resource, but in another format.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.hasPart'] = array(
+    'label' => t('Has Part'),
+    'description' => t('A related resource that is included either physically or logically in the described resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.hasVersion'] = array(
+    'label' => t('Has Version'),
+    'description' => t('A related resource that is a version, edition, or adaptation of the described resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.instructionalMethod'] = array(
+    'label' => t('Instructional Method'),
+    'description' => t('A process, used to engender knowledge, attitudes and skills, that the described resource is designed to support.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.isFormatOf'] = array(
+    'label' => t('Is Format Of'),
+    'description' => t('A related resource that is substantially the same as the described resource, but in another format.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.isPartOf'] = array(
+    'label' => t('Is Part Of'),
+    'description' => t('A related resource in which the described resource is physically or logically included.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.isReferencedBy'] = array(
+    'label' => t('Is Referenced By'),
+    'description' => t('A related resource that references, cites, or otherwise points to the described resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.isReplacedBy'] = array(
+    'label' => t('Is Replaced by'),
+    'description' => t('A related resource that supplants, displaces, or supersedes the described resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.isRequiredBy'] = array(
+    'label' => t('Is Required By'),
+    'description' => t('A related resource that requires the described resource to support its function, delivery, or coherence.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.isVersionOf'] = array(
+    'label' => t('Is Version Of'),
+    'description' => t('A related resource of which the described resource is a version, edition, or adaptation.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.issued'] = array(
+    'label' => t('Date Issued'),
+    'description' => t('Date of formal issuance (e.g., publication) of the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.license'] = array(
+    'label' => t('License'),
+    'description' => t('A legal document giving official permission to do something with the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.mediator'] = array(
+    'label' => t('Mediator'),
+    'description' => t('An entity that mediates access to the resource and for whom the resource is intended or useful.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.medium'] = array(
+    'label' => t('Medium'),
+    'description' => t('The material or physical carrier of the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.modified'] = array(
+    'label' => t('Modified Date'),
+    'description' => t('Date on which the resource was changed.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'date',
+    ),
+  ) + $defaults;
+  $info['tags']['dcterms.provenance'] = array(
+    'label' => t('Provenance'),
+    'description' => t('A statement of any changes in ownership and custody of the resource since its creation that are significant for its authenticity, integrity, and interpretation.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.references'] = array(
+    'label' => t('References'),
+    'description' => t('A related resource that is referenced, cited, or otherwise pointed to by the described resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.replaces'] = array(
+    'label' => t('Replaces'),
+    'description' => t('A related resource that is supplanted, displaced, or superseded by the described resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.requires'] = array(
+    'label' => t('Requires'),
+    'description' => t('A related resource that is required by the described resource to support its function, delivery, or coherence.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.rightsHolder'] = array(
+    'label' => t('Rights Holder'),
+    'description' => t('A person or organization owning or managing rights over the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.spatial'] = array(
+    'label' => t('Spatial'),
+    'description' => t('Spatial characteristics of the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.tableOfContents'] = array(
+    'label' => t('Table Of Contents'),
+    'description' => t('A list of subunits of the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.temporal'] = array(
+    'label' => t('Temporal'),
+    'description' => t('Temporal characteristics of the resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['dcterms.valid'] = array(
+    'label' => t('Valid'),
+    'description' => t('Date (often a range) of validity of a resource.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.module b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.module
new file mode 100644
index 0000000000000000000000000000000000000000..7f1af44291f2a9d46f666d00c9e4933bb814e7a6
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/metatag_dc_advanced.module
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_dc_advanced module.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_dc_advanced_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/tests/metatag_dc_advanced.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/tests/metatag_dc_advanced.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..015dc71f0be8714632bc5a0f83dbcc78ae2a46a8
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/tests/metatag_dc_advanced.tags.test
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Advanced Dublin Core tags work correctly.
+ */
+class MetatagDcAdvancedTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Dublin Core Advanced',
+      'description' => 'Test the Advanced Dublin Core meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'dcterms.abstract',
+    'dcterms.accessRights',
+    'dcterms.accrualMethod',
+    'dcterms.accrualPeriodicity',
+    'dcterms.accrualPolicy',
+    'dcterms.alternative',
+    'dcterms.audience',
+    'dcterms.available',
+    'dcterms.bibliographicCitation',
+    'dcterms.conformsTo',
+    'dcterms.created',
+    'dcterms.dateAccepted',
+    'dcterms.dateCopyrighted',
+    'dcterms.dateSubmitted',
+    'dcterms.educationLevel',
+    'dcterms.extent',
+    'dcterms.hasFormat',
+    'dcterms.hasPart',
+    'dcterms.hasVersion',
+    'dcterms.instructionalMethod',
+    'dcterms.isFormatOf',
+    'dcterms.isPartOf',
+    'dcterms.isReferencedBy',
+    'dcterms.isReplacedBy',
+    'dcterms.isRequiredBy',
+    'dcterms.isVersionOf',
+    'dcterms.issued',
+    'dcterms.license',
+    'dcterms.mediator',
+    'dcterms.medium',
+    'dcterms.modified',
+    'dcterms.provenance',
+    'dcterms.references',
+    'dcterms.replaces',
+    'dcterms.requires',
+    'dcterms.rightsHolder',
+    'dcterms.spatial',
+    'dcterms.tableOfContents',
+    'dcterms.temporal',
+    'dcterms.valid',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_dc_advanced';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    return str_replace('dcterms_', 'dcterms.', $tag_name);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/tests/metatag_dc_advanced.test b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/tests/metatag_dc_advanced.test
new file mode 100644
index 0000000000000000000000000000000000000000..af9362b2fa148d414361cda78b7ffc9d89629c5f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_dc_advanced/tests/metatag_dc_advanced.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag DC Advanced module.
+ */
+class MetatagDcAdvancedTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag DC Advanced tests',
+      'description' => 'Test the Metatag:DC Advanced module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_dc_advanced';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_devel/metatag_devel.info b/profiles/wcm_base/modules/contrib/metatag/metatag_devel/metatag_devel.info
new file mode 100644
index 0000000000000000000000000000000000000000..38c290e4555803fe6c9065db96e2fc9cae17df2c
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_devel/metatag_devel.info
@@ -0,0 +1,16 @@
+name = Metatag: Devel
+description = Provides development / debugging functionality for the Metatag module. Integrates with Devel Generate.
+package = Development
+core = 7.x
+tags[] = developer
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_devel.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_devel/metatag_devel.module b/profiles/wcm_base/modules/contrib/metatag/metatag_devel/metatag_devel.module
new file mode 100644
index 0000000000000000000000000000000000000000..1429e721ccb2a560836403326c130d259694d391
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_devel/metatag_devel.module
@@ -0,0 +1,181 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag:Devel.
+ */
+
+/**
+ * Implements hook_form_FORM_ID_alter() for devel_generate_content_form.
+ *
+ * Add extra options.
+ */
+function metatag_devel_form_devel_generate_content_form_alter(&$form, &$form_state, $form_id) {
+  $form['metatag_skip'] = array(
+    '#type' => 'select',
+    '#title' => t('Skip some meta tag values'),
+    '#options' => array(
+      0 => t("All meta tags given a value"),
+      2 => t('Every 2nd value'),
+      3 => t('Every 3rd value'),
+      4 => t('Every 4th value'),
+      5 => t('Every 5th value'),
+    ),
+    '#default' => 0,
+    '#description' => t('Control whether all of the meta tags will be given values, or .'),
+  );
+
+  // Move the submit button to after the rest of the fields.
+  $form['submit']['#weight'] = 100;
+}
+
+/**
+ * Implements hook_node_insert().
+ *
+ * Integrate with Devel Generate.
+ */
+function metatag_devel_node_insert($node) {
+  // Check to see if the node is generated by Devel Generate.
+  if (isset($node->devel_generate)) {
+    $metatags = array();
+
+    // Max length of words.
+    $title_length = $node->devel_generate['title_length'];
+
+    // Pregenerate the URL.
+    $url = url('<front>', array('absolute' => TRUE));
+
+    // Types of images.
+    $image_types = array('jpg' => 'jpg', 'png' => 'png', 'gif' => 'gif');
+
+    // Optionally skip some meta tags.
+    $skip = $node->devel_generate['metatag_skip'];
+
+    // Generate some meta tags.
+    $count = 0;
+    foreach (metatag_get_info('tags') as $tag => $tag_info) {
+      // Optionally skip records.
+      if (empty($skip) || $count == 0 || (($count % $skip) == 0)) {
+        // Default to ten words per tag.
+        $maxlength = 10;
+
+        // By default, just assume a simple text value.
+        $type = 'text';
+        if (strpos($tag, 'title') !== FALSE) {
+          $maxlength = $title_length;
+        }
+
+        // Allow tags to customize the generation settings.
+        if (!empty($tag_info['devel_generate'])) {
+          if (!empty($tag_info['devel_generate']['type'])) {
+            $type = $tag_info['devel_generate']['type'];
+          }
+          if (!empty($tag_info['devel_generate']['maxlength'])) {
+            $maxlength = $tag_info['devel_generate']['maxlength'];
+          }
+        }
+
+        // Work out how to handle possibly more complicated meta tags.
+        elseif (isset($tag_info['form']) && is_array($tag_info['form'])) {
+          // Textarea fields can be longer than other tags.
+          if (isset($tag_info['form']['#type']) && $tag_info['form']['#type'] == 'textarea') {
+            $maxlength = 20;
+          }
+          // Anything with an '#options' value will have one item picked at
+          // random.
+          elseif (isset($tag_info['form']['#options'])) {
+            $type = 'select';
+          }
+        }
+
+        // Simple values.
+        if ($type == 'text') {
+          $metatags[$tag]['value'] = devel_create_greeking($maxlength, TRUE);
+        }
+
+        // Select lists, pick a value at random.
+        elseif ($type == 'select') {
+          // Nested arrays, aka opgroups - collapse it down to one level.
+          if (is_array($tag_info['form']['#options'])) {
+            $options = array();
+            foreach ($tag_info['form']['#options'] as $option => $subopts) {
+              if (is_array($subopts)) {
+                $options += array_keys($subopts);
+              }
+              else {
+                $options[] = $option;
+              }
+            }
+          }
+          else {
+            $options = $tag_info['form']['#options'];
+          }
+          $metatags[$tag]['value'] = array_rand(drupal_map_assoc($options));
+
+          // Support checkboxes, which require the default value be an array.
+          if ($tag_info['class'] == 'DrupalListMetaTag') {
+            $metatags[$tag]['value'] = array($metatags[$tag]['value']);
+          }
+        }
+
+        // URL values.
+        elseif ($type == 'url') {
+          $metatags[$tag]['value'] = $url . strtolower(str_replace(' ', '/', devel_create_greeking($maxlength, TRUE)));
+        }
+
+        // Image URL values.
+        elseif ($type == 'image') {
+          $filepath = strtolower(str_replace(' ', '/', devel_create_greeking($maxlength, TRUE)));
+          $ext = array_rand($image_types);
+          $metatags[$tag]['value'] = $url . $filepath . '.' . $ext;
+        }
+
+        // Integers, generate an integer between 0 and 999.
+        elseif ($type == 'integer') {
+          $metatags[$tag]['value'] = rand(0, 999);
+        }
+
+        // Floats, generate an integer between 0 and 999.
+        elseif ($type == 'float') {
+          $metatags[$tag]['value'] = rand(0, 999) . '.' . rand(0, 999);
+        }
+
+        // Phone numbers will be given the US format of XXX-XXX-XXXX.
+        elseif ($type == 'phone') {
+          $metatags[$tag]['value'] = rand(100, 999) . '-' . rand(100, 999) . '-' . rand(1000, 9999);
+        }
+
+        // Email addresses.
+        elseif ($type == 'email') {
+          $metatags[$tag]['value'] = strtolower(devel_create_greeking(1, TRUE) . '@' . devel_create_greeking(1, TRUE) . '.com');
+        }
+
+        // Canonical URL values - just fill in the absolute URL for the current
+        // page.
+        elseif ($type == 'canonical') {
+          $metatags[$tag]['value'] = '[current-page:url:absolute]';
+        }
+
+        // Twitter usernames.
+        elseif ($type == 'twitter') {
+          $metatags[$tag]['value'] = '@' . devel_create_greeking(1, TRUE);
+        }
+
+        // Replace spaces in keyword fields with commas.
+        if (strpos($tag, 'keyword') !== FALSE) {
+          $metatags[$tag]['value'] = str_replace(' ', ',', $metatags[$tag]['value']);
+        }
+      }
+
+      // Bump the counter.
+      $count++;
+    }
+
+    // Adjust the values for the nested language structure.
+    $metatags = array(
+      $node->language => $metatags,
+    );
+
+    // Save the meta tags.
+    metatag_metatags_save('node', $node->nid, $node->vid, $metatags);
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_devel/tests/metatag_devel.test b/profiles/wcm_base/modules/contrib/metatag/metatag_devel/tests/metatag_devel.test
new file mode 100644
index 0000000000000000000000000000000000000000..f1e3bdda52dbecdfed19cf8270542fb9033f91fc
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_devel/tests/metatag_devel.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag Devel module.
+ */
+class MetatagDevelest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Devel tests',
+      'description' => 'Test the Metatag:Devel module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_devel';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.info b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.info
new file mode 100644
index 0000000000000000000000000000000000000000..29a73854856dbecf14233a63041a4909264ea0b4
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.info
@@ -0,0 +1,16 @@
+name = Metatag: Facebook
+description = "Provides support for Facebook's custom meta tags."
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_facebook.test
+files[] = tests/metatag_facebook.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.install b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.install
new file mode 100644
index 0000000000000000000000000000000000000000..61561de7f9d826b9689c1833f79fa1c1ac766bde
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.install
@@ -0,0 +1,5 @@
+<?php
+/**
+ * @file
+ * Installation and update scripts for Metatag:Facebook.
+ */
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..56f5d42b804c85c263065dcf77625835cdccf6f6
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.metatag.inc
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag:Facebook module.
+ */
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_facebook_metatag_info() {
+  $info['groups']['facebook'] = array(
+    'label' => t('Facebook'),
+    'description' => t("Meta tags used to integrate with Facebook's APIs. Most sites do not need to use these, they are primarily of benefit for sites using either the Facebook widgets, the Facebook Connect single-signon system, or are using Facebook's APIs in a custom way. Sites that do need these meta tags usually will only need to set them globally."),
+    'form' => array(
+      '#weight' => 55,
+    ),
+  );
+
+  // Facebook meta tags stack after the simple tags.
+  $weight = 20;
+
+  // Default values for each meta tag.
+  $tag_info_defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'facebook',
+    'element' => array(
+      '#theme' => 'metatag_property',
+    ),
+  );
+
+  $info['tags']['fb:admins'] = array(
+    'label' => t('Admins'),
+    'description' => t('A comma-separated list of Facebook user IDs of people who are considered administrators or moderators of this page.'),
+    'weight' => ++$weight,
+    'multiple' => TRUE,
+  ) + $tag_info_defaults;
+
+  $info['tags']['fb:app_id'] = array(
+    'label' => t('Application ID'),
+    'description' => t('A comma-separated list of Facebook Platform Application IDs applicable for this site.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $tag_info_defaults;
+
+  // If the FB_Social module is installed already, disable the app_id field.
+  if (module_exists('fb_social')) {
+    $info['tags']['fb:app_id']['form']['#disabled'] = TRUE;
+    $info['tags']['fb:app_id']['form']['#description'] = t('The FB_Social module will automatically output this meta tag, go to the <a href="!fb_social">FB_Social settings page</a> to customize it.', array('!fb_social' => url('admin/structure/fbsocial')));
+  }
+
+  $info['tags']['fb:pages'] = array(
+    'label' => t('Pages'),
+    'description' => t('Facebook Instant Articles claim URL token.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $tag_info_defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.module b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.module
new file mode 100644
index 0000000000000000000000000000000000000000..faf572d1f783c1da8f1967d347ad123cd42a0204
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/metatag_facebook.module
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag:Facebook.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_facebook_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_preprocess_html().
+ */
+function metatag_facebook_preprocess_html(&$variables) {
+  // Fall back to hook_rdf_namespaces if the rdf module is enabled.
+  if (module_exists('rdf')) {
+    return;
+  }
+
+  $variables['rdf_namespaces'] .= "\n  xmlns:fb=\"http://ogp.me/ns/fb#\"";
+}
+
+/**
+ * Implements hook_rdf_namespaces().
+ */
+function metatag_facebook_hook_rdf_namespaces() {
+  return array('fb' => 'http://ogp.me/ns/fb#');
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/tests/metatag_facebook.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/tests/metatag_facebook.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..03e14cbc70aeeaae82a2323aee30aca6e5d0db21
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/tests/metatag_facebook.tags.test
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Facebook tags work correctly.
+ */
+class MetatagFacebookTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Facebook',
+      'description' => 'Test the Facebook meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_facebook';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'fb:admins',
+    'fb:app_id',
+    'fb:pages',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_name_attribute = 'property';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    return str_replace('fb_', 'fb:', $tag_name);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/tests/metatag_facebook.test b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/tests/metatag_facebook.test
new file mode 100644
index 0000000000000000000000000000000000000000..2947680f8864640ba2e05a83ae33d82ee3ec4cfa
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_facebook/tests/metatag_facebook.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag Facebook module.
+ */
+class MetatagFacebookTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Facebook tests',
+      'description' => 'Test the Metatag:Facebook module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_facebook';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.info b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.info
new file mode 100644
index 0000000000000000000000000000000000000000..126bb8743d5304b7d3d28fc30339fd37544862d0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.info
@@ -0,0 +1,19 @@
+name = Metatag: favicons
+description = "Provides support for many different favicons."
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Custom class for mask-icon.
+files[] = metatag_favicons.mask-icon.class.inc
+
+; Tests.
+files[] = tests/metatag_favicons.test
+files[] = tests/metatag_favicons.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.install b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.install
new file mode 100644
index 0000000000000000000000000000000000000000..dba8c8a0b5b209d06e3b5e743d49b32157040c46
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.install
@@ -0,0 +1,16 @@
+<?php
+/**
+ * @file
+ * Update scripts, etc for the Metatag Favicons module.
+ */
+
+/**
+ * Implementations of hook_update_N().
+ */
+
+/**
+ * Clear the Metatag caches so the updated mask-icon spec can be used.
+ */
+function metatag_favicons_update_7100() {
+  metatag_config_cache_clear();
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.mask-icon.class.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.mask-icon.class.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1200756564186214e13478fdffab691c6177822f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.mask-icon.class.inc
@@ -0,0 +1,104 @@
+<?php
+/**
+ * @file
+ * Custom class for the mask-icon meta tag's custom data.
+ */
+
+/**
+ * Mask icon meta tag controller.
+ */
+class DrupalMaskIconMetaTag extends DrupalTextMetaTag {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getForm(array $options = array()) {
+    $form['value'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->info['label'],
+      '#default_value' => isset($this->data['value']) ? $this->data['value'] : '',
+      '#description' => isset($this->info['description']) ? $this->info['description'] : '',
+      '#maxlength' => 1024,
+      '#weight' => $this->getWeight(),
+    );
+    $form['color'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Icon: SVG color'),
+      '#default_value' => isset($this->data['color']) ? $this->data['color'] : '',
+      '#description' => t('Provides a color for the SVG icon. Per <a href="@specs_url">Apple\'s specifications</a>, it may be a hexadecimal value (e.g. "#990000"), an RGB value (e.g. "rgb(153, 0, 0)"), or a recognized color-keyword (e.g. "red", "lime", "navy", etc). Will only be output if the SVG icon meta tag has a value.', array('@specs_url' => 'https://developer.apple.com/library/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9_0.html#//apple_ref/doc/uid/TP40014305-CH9-SW20')),
+      '#maxlength' => 10,
+      '#weight' => $form['value']['#weight'] + 0.01,
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue(array $options = array()) {
+    $value = array(
+      'value' => '',
+      'color' => NULL,
+    );
+
+    // The 'color' attribute will only be output if the 'value' is present.
+    if (!empty($this->data['value'])) {
+      // Pass the 'value' through the parent logic.
+      $value['value'] = parent::getValue($options);
+
+      // Get the optional 'color' attribute.
+      if (!empty($this->data['color'])) {
+        $value['color'] = check_plain($this->tidyValue($this->data['color']));
+      }
+    }
+
+    return $value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getElement(array $options = array()) {
+    $value = $this->getValue($options);
+
+    // This meta tag has two separate values.
+    $color = $value['color'];
+    $value = $value['value'];
+
+    // Don't bother proceeding if the 'value' is empty.
+    if (strlen($value) === 0) {
+      return array();
+    }
+
+    // The stack of elements that will be output.
+    $elements = array();
+
+    // Dynamically add each option to this setting.
+    $base_element = isset($this->info['element']) ? $this->info['element'] : array();
+
+    // Combine the base configuration for this meta tag with the value.
+    $element = $base_element + array(
+      '#theme' => 'metatag',
+      '#tag' => 'link',
+      '#id' => 'metatag_' . $this->info['name'] . '_' . 1,
+      '#rel' => $this->info['name'],
+      '#name' => $this->info['name'],
+      '#value' => $value,
+      '#color' => $color,
+      '#weight' => $this->getWeight(),
+    );
+
+    // Add header information if desired.
+    if (!empty($this->info['header'])) {
+      $element['#attached']['drupal_add_http_header'][] = array($this->info['header'], $value);
+    }
+
+    $elements[] = array($element, $element['#id']);
+
+    return array(
+      '#attached' => array('drupal_add_html_head' => $elements),
+    );
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..70033172cca0e6865d2cfb5df114b1d84d923f65
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.metatag.inc
@@ -0,0 +1,281 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag:favicons module.
+ */
+
+/**
+ * Implements hook_metatag_bundled_config_alter().
+ */
+function metatag_favicons_metatag_bundled_config_alter(&$config) {
+  $favicon = metatag_favicons_get_theme_favicon();
+  if (!empty($favicon)) {
+    $config['global']->config['shortcut icon'] = array('value' => $favicon);
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_favicons_metatag_info() {
+  $info['groups']['favicons'] = array(
+    'label' => t('Favicons & touch icons'),
+    'description' => t('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.'),
+    'form' => array(
+      '#weight' => 100,
+    ),
+  );
+
+  // favicons meta tags stack after the simple tags.
+  $weight = 100;
+
+  // Default values for each meta tag.
+  $favicon_defaults = array(
+    'description' => '',
+    'class' => 'DrupalLinkMetaTag',
+    'group' => 'favicons',
+    'url' => TRUE,
+    'context' => array('global'),
+  );
+
+  $info['tags']['shortcut icon'] = array(
+    'label' => t('Default shortcut icon'),
+    'description' => t('The traditional favicon, must be either a GIF, ICO, JPG/JPEG or PNG image.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'shortcut icon',
+      '#theme' => 'metatag_shortcut_icon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['mask-icon'] = array(
+    'label' => t('Icon: SVG'),
+    'description' => t('A grayscale scalable vector graphic (SVG) file.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_mask_icon',
+    ),
+    'class' => 'DrupalMaskIconMetaTag',
+    'replaces' => array('icon_any'),
+  ) + $favicon_defaults;
+
+  $info['tags']['icon_16x16'] = array(
+    'label' => t('Icon: 16px x 16px'),
+    'description' => t('A PNG image that is 16px wide by 16px high.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'icon',
+      '#sizes' => '16x16',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['icon_32x32'] = array(
+    'label' => t('Icon: 32px x 32px'),
+    'description' => t('A PNG image that is 32px wide by 32px high.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'icon',
+      '#sizes' => '32x32',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['icon_96x96'] = array(
+    'label' => t('Icon: 96px x 96px'),
+    'description' => t('A PNG image that is 96px wide by 96px high.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'icon',
+      '#sizes' => '96x96',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['icon_192x192'] = array(
+    'label' => t('Icon: 192px x 192px'),
+    'description' => t('A PNG image that is 192px wide by 192px high.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'icon',
+      '#sizes' => '192x192',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon'] = array(
+    'label' => t('Apple touch icon: 60px x 60px'),
+    'description' => t('A PNG image that is 60px wide by 60px high. Used with the non-Retina iPhone, iPod Touch, and Android 2.1+ devices.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon_72x72'] = array(
+    'label' => t('Apple touch icon: 72px x 72px'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#sizes' => '72x72',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon_76x76'] = array(
+    'label' => t('Apple touch icon: 76px x 76px'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#sizes' => '76x76',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon_114x114'] = array(
+    'label' => t('Apple touch icon: 114px x 114px'),
+    'description' => t('A PNG image that is 114px wide by 114px high. Used with iPhone with @2x display running iOS <= 6.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#sizes' => '114x114',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon_120x120'] = array(
+    'label' => t('Apple touch icon: 120px x 120px'),
+    'description' => t('A PNG image that is 120px wide by 120px high. Used with iPhone with @2x display running iOS >= 7.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#sizes' => '120x120',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon_144x144'] = array(
+    'label' => t('Apple touch icon: 144px x 144px'),
+    'description' => t('A PNG image that is 144px wide by 144px high. Used with iPad with @2x display running iOS <= 6.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#sizes' => '144x144',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon_152x152'] = array(
+    'label' => t('Apple touch icon: 152px x 152px'),
+    'description' => t('A PNG image that is 152px wide by 152px high. Used with iPad with @2x display running iOS >= 7.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#sizes' => '152x152',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon_180x180'] = array(
+    'label' => t('Apple touch icon: 180px x 180px'),
+    'description' => t('A PNG image that is 180px wide by 180px high. Used with iPhone 6 Plus with @3x display.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon',
+      '#sizes' => '180x180',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed'] = array(
+    'label' => t('Apple touch icon (precomposed): 57px x 57px'),
+    'description' => t('A PNG image that is 57px wide by 57px high. Used with the non-Retina iPhone, iPod Touch, and Android 2.1+ devices.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed_72x72'] = array(
+    'label' => t('Apple touch icon (precomposed): 72px x 72px'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#sizes' => '72x72',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed_76x76'] = array(
+    'label' => t('Apple touch icon (precomposed): 76px x 76px'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#sizes' => '76x76',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed_114x114'] = array(
+    'label' => t('Apple touch icon (precomposed): 114px x 114px'),
+    'description' => t('A PNG image that is 114px wide by 114px high. Used with iPhone with @2x display running iOS <= 6.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#sizes' => '114x114',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed_120x120'] = array(
+    'label' => t('Apple touch icon (precomposed): 120px x 120px'),
+    'description' => t('A PNG image that is 120px wide by 120px high. Used with iPhone with @2x display running iOS >= 7.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#sizes' => '120x120',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed_144x144'] = array(
+    'label' => t('Apple touch icon (precomposed): 144px x 144px'),
+    'description' => t('A PNG image that is 144px wide by 144px high. Used with iPad with @2x display running iOS <= 6.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#sizes' => '144x144',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed_152x152'] = array(
+    'label' => t('Apple touch icon (precomposed): 152px x 152px'),
+    'description' => t('A PNG image that is 152px wide by 152px high. Used with iPad with @2x display running iOS >= 7.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#sizes' => '152x152',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  $info['tags']['apple-touch-icon-precomposed_180x180'] = array(
+    'label' => t('Apple touch icon (precomposed): 180px x 180px'),
+    'description' => t('A PNG image that is 180px wide by 180px high. Used with iPhone 6 Plus with @3x display.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#rel' => 'apple-touch-icon-precomposed',
+      '#sizes' => '180x180',
+      '#theme' => 'metatag_favicon',
+    ),
+  ) + $favicon_defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.module b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.module
new file mode 100644
index 0000000000000000000000000000000000000000..62cb415c7ae7afc94df0265fbf1adaefb544fde9
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/metatag_favicons.module
@@ -0,0 +1,179 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag:favicons.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_favicons_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_favicons_theme() {
+  $info['metatag_favicon'] = array(
+    'render element' => 'element',
+  );
+
+  $info['metatag_mask_icon'] = array(
+    'render element' => 'element',
+  );
+
+  $info['metatag_shortcut_icon'] = array(
+    'render element' => 'element',
+  );
+  return $info;
+}
+
+/**
+ * Implements hoko_html_head_alter().
+ *
+ * Remove the default shortcut icon if one was set by Metatag.
+ */
+function metatag_favicons_html_head_alter(&$elements) {
+  if (isset($elements['metatag_shortcut icon'])) {
+    foreach ($elements as $key => $element) {
+      if (isset($element['#tag']) && $element['#tag'] == 'link') {
+        if (isset($element['#attributes']) && is_array($element['#attributes'])) {
+          if (isset($element['#attributes']['rel'])) {
+            if ($element['#attributes']['rel'] == 'shortcut icon') {
+              unset($elements[$key]);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Theme callback for a favicon meta tag.
+ *
+ * The format is:
+ * <link rel="[rel]" href="[value]" sizes="[sizes]" />
+ */
+function theme_metatag_favicon($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#rel' => 'rel',
+    '#value' => 'href',
+    '#sizes' => 'sizes',
+    '#mask' => 'mask',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Theme callback for the mask-icon meta tag.
+ *
+ * The format is:
+ * <link rel="mask-icon" href="[value]" sizes="[sizes]" />
+ */
+function theme_metatag_mask_icon($variables) {
+  $element = &$variables['element'];
+
+  $args = array(
+    '#rel' => 'rel',
+    '#value' => 'href',
+    '#color' => 'color',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Theme callback for a shortcut icon meta tag.
+ *
+ * The format is:
+ * <link rel="[rel]" href="[value]" type="[type]" />
+ */
+function theme_metatag_shortcut_icon($variables) {
+  $element = &$variables['element'];
+
+  // Extract the MIME type.
+  $element['#type'] = metatag_favicons_get_mime_type($element['#value']);
+
+  $args = array(
+    '#rel' => 'rel',
+    '#value' => 'href',
+    '#type' => 'type',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Helper function to get the theme's favicon URL.
+ *
+ * @return string
+ *  The absolute URL to the favicon, empty string if not found.
+ */
+function metatag_favicons_get_theme_favicon() {
+  $favicon_url = '';
+
+  // Is the favicon enabled?
+  if (theme_get_setting('toggle_favicon')) {
+    $favicon_url = theme_get_setting('favicon');
+  }
+
+  return $favicon_url;
+}
+
+/**
+ * Returns the correct MIME type for favicons.
+ *
+ * @param string $uri
+ *   The URI, or URL, of the favicon to be checked.
+ *
+ * @return string
+ *  The MIME type on success, an empty string on failure.
+ */
+function metatag_favicons_get_mime_type($uri) {
+  // Look for the last period in the URL.
+  $extension_dot = strrpos($uri, '.');
+  $type = '';
+
+  // URLs must have a file extension in order for this to work.
+  if ($extension_dot) {
+    $extension = strtolower(substr($uri, $extension_dot + 1));
+
+    // Work out the file's extension.
+    switch ($extension) {
+      case 'ico':
+        $type = 'vnd.microsoft.icon';
+        break;
+
+      // Rename JPEG images as JPG.
+      case 'jpeg':
+        $extension = 'jpeg';
+
+      // Basic image types.
+      case 'gif':
+      case 'jpg':
+      case 'png':
+        // Keep the extension as it is.
+        break;
+
+      // This shouldn't happen, only GIF, JPG, ICO or PNG files are supported.
+      default:
+        $extension = '';
+    }
+
+    // Only compile the MIME type if a supported extension was found.
+    if (!empty($extension)) {
+      $type = 'image/' . $extension;
+    }
+  }
+
+  return $type;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/druplicon-vector.svg b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/druplicon-vector.svg
new file mode 100644
index 0000000000000000000000000000000000000000..76208076ff78b126812ba65e889d67dbcd612ece
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/druplicon-vector.svg
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 755 826" enable-background="new 0 0 755 826" xml:space="preserve">
+<metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c014 79.156821, 2014/08/29-03:07:50        ">
+   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+      <rdf:Description rdf:about=""
+            xmlns:xmp="http://ns.adobe.com/xap/1.0/"
+            xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/"
+            xmlns:dc="http://purl.org/dc/elements/1.1/"
+            xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+            xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
+         <xmp:CreateDate>2005-04-19T17:04:57Z</xmp:CreateDate>
+         <xmp:ModifyDate>2005-04-19T18:04:24Z</xmp:ModifyDate>
+         <xmp:CreatorTool>Illustrator</xmp:CreatorTool>
+         <xmp:Thumbnails>
+            <rdf:Alt>
+               <rdf:li rdf:parseType="Resource">
+                  <xmpGImg:width>224</xmpGImg:width>
+                  <xmpGImg:height>256</xmpGImg:height>
+                  <xmpGImg:format>JPEG</xmpGImg:format>
+                  <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADgAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FWA/npcMn5a6jaxScLvUJbWzswKgtLJcxniCP8hWOZWjH7wHutw9cf3RHfX3pd+Un5&#xA;kzalPdeTPMcoXzXoryW5kYn/AEyOBihkUnrIvH4x1P2v5uM9XpuH1x+k/pa9HquL0S+qO3vr9L0/&#xA;MJ2DsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVea/mXL+lvP&#xA;PkfypEQ3+nHWr5R9pIrFSYuXbjIxdfmMzNP6YSl5V83B1J4skIed/L8F5D+dNld6V+Z93qGnSta3&#xA;ytDe2dwmzK5Ran/g1ObzRQGXTgHpYef18zh1RI5Gi9r/ACm/NKx876SYp+Nt5isVA1Kx6V7evFXr&#xA;Gx6/ynY/sltDqtKcUvJ6LR6sZo/0vxuz3MVzHYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYqo317aWNnPe3kqwWltG0s8zmioiDkzH5AYYxJNBEpACzyebflXDeeZfMWs/&#xA;mRfRvFDqI+oeXoJKhk0+Ft34ksB6jqCaftcqbHMzUkQiMY6c/e4OlBnI5T12Hued/wDOQXA+elIN&#xA;WFpErD5FiP15vOx/7n4vP9t/3/wDzWxvtU0jVLfWdGnNrqlm3KKVejDoUYHYqw2IOxGZmp04yBwd&#xA;LqTilb6l/K780tK88aWacbTXLVR+kNOJ3Hb1Yq7tGT/wJ2PYnk9TpjiPk9lpNXHLH+kzjMZy3Yq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqg9X1jS9H06fUtUuY7Oxt15TTymi&#xA;geHuT0AG5OwyUIGRoc2M5iIsmg8yePW/zauovUim0r8t4XEhR6x3OrOhqtQN0twRUePXrThmXHAO&#xA;/J934/Hng1LUHux/7r9n493SLy803QtMjRUWGCBBFa2sYCiiCioqjoAPuzFhAzk5eTJHHF8peftf&#xA;bXfNF3fc+aA+nGw6EKTWntyJp7Z2Okw+HjAeH1ufxMhkx7MlxW7S51DTtRg1XSbl7HVLVuUFzGaH&#xA;pQhuxBGxB2I2O2Y+fTxyCi5On1MsZsPe/wAvP+chdI1IRaX5vCaRq1OK3x2s5zUAHkf7ljXfl8O3&#xA;2hsuc3qezpQPp5fj5vU6TtOGQVLY9/45PYo5I5I1kjYPG4DI6moIO4II6g5rXagt4q7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqwvzN+aOlabqB0PRLeTzF5nNQuk2JB9Mg0JuZt0hVT&#xA;9qu47im+ZGPTEjil6Y97i5NUAeGPql3D9KW6X+W+ra7qEOu/mLdJqV1F8dloEFRptofEoSfWfxZv&#xA;l8W1Jy1AiOHHsO/qWENMZHiyGz3dAyvzDrN9pkI+q2lY6AfWDT017AcV3++mQwYhM7lsz5pQGweM&#xA;fmjqnmKbTPrMc5MLHhfPWjhGoFVewQk0NP65vdBjgJVXued7RyZDG726vIs3Lo3Yq7FVkkUcqlJF&#xA;DKexyMog7FMZEGwnvlLz7528nOBod+ZbAGraVd1ltz1J4ioKVJ/YK175r9R2dCbs9L2pPHt0+z8e&#xA;57V5P/5yN8qaoyWnmGJ9A1BqLzkrJaOSQNpVFUqST8a8QP2s0efs6cOW70Gn7Uxz57fc9Wtbq1u7&#xA;eO5tZkuLaZQ8U0TB0dT0KspII+WYBBBouyBBFhVwJdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;Yn5r/M3yx5duV05nk1LXZTxg0TT1+sXbMQCAyLsmxr8ZG3SuX49PKQvlHvLj5dTGBrnLuDHzoP5m&#xA;+dW5eYLz/CXl9+ui6dIHvpUI+zPdAUQGvRO2xWu+W8ePH9I4pd55fJp8PLl+o8Ee4c/mzXyz5S8u&#xA;eWLAWOh2MdnBt6hQVkkI/akkNXc/6xzHyZZTNyLlY8UYCoik3ytsSHzlfxQaS1sTWa5IVV/yVILH&#xA;+GZOlgTK+5xdXMCFd7w38zdWjg0lNOU1mu2DMvhHGeVT82Ap9OdBocdy4u55rtDJUeHveYZtXTux&#xA;V2KuxV2KrXjSReLqGU9jvgIB5pEiOSYeW/Mvmryrcev5c1KS0UnlLZOfUtpO3xRNVa070r4EZg59&#xA;BCYc/T9ozxnm9w8if85FaJqkkeneaoV0TUn+FbqpNlIf9diTF/siV/ys0Op7OnDlv+Ptej0vakMn&#xA;1bfd+x7Ajq6h0IZGAKsDUEHoQc1ztG8VdirsVdirsVdirsVdirsVdirsVQWs61pOi6dNqWq3UdnY&#xA;wDlLPKaD5DuzHso3J2GShAyNDmwnMRFk0Hmo13z/APmPJw8uer5W8nE/Frkq0vrte/1VP91qez19&#xA;+XVczODHi+r1T7ugcLjyZvp9EO/qWa+TvIHlfyjamLR7QLPL/vTfSn1LmY+Mkp3678RRfbMbLnlM&#xA;7uVh08MY9IZFlTc7FUHquq2um2pnnO/SOMfaZvAZZjxmZoNeXKICy8r80+Z0ijn1XUXoBtHGO/8A&#xA;LGg/z8c3GnwcoxdHqdRVyk8N1jVrrVdQlvbk/HIfhQdEUfZUewzfY8YhGg85lyGcrKCyxrdirsVd&#xA;irsVdirsVWSxRyoUkUMp7HIyiCKKYyINhlXkP80/NfkZ0ghY6r5fB+PS52NYgTyLW77lD12+zudq&#xA;75qtX2bGe45/j5u50XakobHl+Pk+mvJ3nfy55v0sajolz6qCgnt3os0LkfYlSp4nbr0PYnOdy4ZY&#xA;zRenw545BcU+ypudirsVdirsVdirsVdirsVY753886R5R01Lm953F7dN6OmaZAOVxdTGlEjQVPUj&#xA;k1KCo7kA3YcJmduXUtOfOMY35nkO9imjfl/rPmnUYfM35jcZZI/i0vyuhraWineswqRLKf2q/TUU&#xA;C3TziA4cfxPe48NPLIePL8I9A9NACgKooBsAOgGYbnOxV2KoDWNatNLg9SY8pG/uoR9pj/Ae+WYs&#xA;RmdmrLmEBu8x8y+ZlCS6nqkoSJBRVHQeCIvic2+DB/DF0uo1H8UninmXzJea5e+rL+7t46i3twdl&#xA;B7nxY9zm9wYRjFdXns+c5DZ5JRlzQ7FXYq7FXYq7FXYq7FXYq7FVfRdY1vy5qyaz5fuTaX6Aq6je&#xA;OZCatHIh2ZTTv336gHMPU6SOQcnN0uslilzfUP5Yfmpo/njT2VQLPXLVa3+mM1WUVp6kZNOcZJ6/&#xA;snY9ieW1OlliPk9fpdXHMNubN8xnLdirsVdirsVdirsVY356872XlTTI5mha+1W9f0NJ0qHea5nP&#xA;RVAqeK1HNqbfMgG7DhMz3Acy0Z84xjvJ5BJvIvkLUIdQk83ecJFvvN96tFUbwWEJ6W9sNwKV+Jh9&#xA;53Zp5swI4IbRH2teDAQeOe8z9jPcxnLdirsVY/rvmy2seUFrSe7Gx/kQ+5HU+wzJw6Yy3OwcTNqh&#xA;HYbl5r5l8021jG99qc5knk+xHsXc+CjwH3DNrgwGW0Q6fUakR9Uju8f8w+Y7/W7v1rg8IV/uLdSe&#xA;CD+LeJzdYcIxig6HPnlkNlKsuaXYq7FXYq7FXYq7FXYq7FXYq7FXYq3aXepaZqVvq+kXDWeq2bc7&#xA;e4T7irA7MrDYg7EbHbMfUacZBRcnTamWOQIL6o/Kz8zLDzxoplKi21qzCpqliK0Vz0kjqSfTehpX&#xA;cdD4nktVpjilXR7PSaoZo31ZtmM5bsVdirsVdiqU+afM+leWdDuNY1NytvAKJGorJLI2yRRr+07n&#xA;YfedqnLMWMzlQa8uUY48RYv5B8q6jdag/nnzWofzJfpxsrU7pp1o1SkEVf2yG+Nvc+JrfnyADgj9&#xA;I+0uPp8RJ8Sf1H7Az7MRzHYqhr/UrKwh9W6lEa/sr1Zj4KOpycIGRoMJ5IxFlhWs+bry95Q21ba2&#xA;OxofjYe5HT5DM/FphHc7l1ubVGWw2DzXzN59sdMDW1lxur4VBANY4z/lEdT7DNrg0hnudg6fUa2M&#xA;No7yeYahqN7qF011eStNM/Vj2HgB0A9hm0hARFB1E5mRs80Pk2DsVdirsVdirsVdirsVdirsVdir&#xA;sVdirsVV9H8w6t5X1y18w6O/C7tmpNGa8Joj9qKQDqrf2jcDMHW6cZI7ufoNTLHLZ9feTfNulebP&#xA;L1rremPWG4FJIiQXilXZ4nHZlP3ihGxGcnlxmEqL2eHKMkeIJ1lba7FXYq7FXi8OuW/5gfmFDeu3&#xA;PyloVyINKjagjubsf3t038yj7MftvsSc2kcRxYz/ADiHUSyjNlH8wF7RmrduhrzUrCzXldTpF7E/&#xA;Efko3OTjCUuQYTyRjzLGdT887GPTo6dvXlH/ABFf6/dmXj0n85wsmt/msH1/zLaWSm71W7/eN9lW&#xA;PKR6dlXr/AZsMOAy2iHW59QI7yLzHzH+YGo6lyt7KtnZHY0P71x/lMOnyH45tMOkjHc7l0+fWyns&#xA;NgxXMxwnYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqpXK8oHHsT92+QmNizgakGVfkr+YzeTf&#xA;NC297KV8v6syxXoP2YZekdwPDj0f/J8aDNHrtNxxscw9B2fquCVH6S+us0D0jsVdiryj/nIPz2+h&#xA;+Wk0DT5Aura8GhalC0VpSkznuOdeC7fzU3XM/s/T8c77vvdb2lqfDhXU/d+1j/kyzt7PytpkFv8A&#xA;YECOSP5pBzf/AIZjmxzCpEOtwG4AslOr6qUCG8m4AU4+o3T78x/Cj3ByPFn3lKNT1nTtPjM1/cpC&#xA;DuOZqzfJRVm+jLoY5S2iGjJljHeRYLrn5nTPyh0eL0l6fWpQC3zVOg+mvyzYYtCOcnW5u0CdoMIu&#xA;bq5upmnuZWmmfdpHJYn6TmdGIAoOulIk2VLJIdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;VWS/3T/6p/VkZckx5hJmUMpU9DmCRbsAafU3/OPfnxvMPlL9D3snLVdCCwMSd5LYgiB/9iF4H5An&#xA;rnPa7BwTvoXp+z9Rxwo8w9VzCc9xIUEk0A3JPQDFXxt5281SebvOepa8WLWZf6tpaGtFtYiQlASe&#xA;PP7bD+YnOt7P0/BB4vtPU+JP8fBW0fznrulW4treVXt1rwilXkFruaHY/jmTk00JmzzcXFqpwFDk&#xA;q3nn7zPcqV+tCBT1EKhT/wAFuw+/BHSYx0TPWZD1pIZppppGlmkaWRt2dyWY/MnMgADk4xJO5WYU&#xA;OxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KqN03G3c+Ip9+2QyH0lnjFyCVZhuayr8&#xA;rfN58p+etO1SR+FhM31TUt6D6vMQCzdf7tuL/wCxzE1mHjge9zdDn8OYPR9oZzb1Tz/89fMz6D+X&#xA;GoGElbvVCum2xAB3uAfUr4fuVkofGmZeix8WQeW7h6/LwYj57fj4PlyCIRQpGOiin0987GEaFPDT&#xA;lxElUyTF2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KoPUXoip4mp+jKMx2&#xA;pvwDe0BmO5K115IV8cBFhINF9ifkv5pPmP8ALvS7qV+d5aJ9RvDuT6lvRQWJ6s8fBz885nVY+DIQ&#xA;9Zo8vHjB7tnlv/OS+sG6816Hoa0MdhbPey0NfjnfgoYdiohqP9bNp2Pi5n8bf2uo7by1UfL7/wCx&#xA;5VnRPMuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KpTdS+pMzDoNl+Qz&#xA;DySsubjjQUsgzdir3T/nFjXWS+17y87MVkSPULdK/CpU+lMaeLc4/uzTdp4+Une9k5OcWD/mdqQ1&#xA;T80fMt2BxWG4WyUVr/vKghb72jrm17LhWMe7793T9r5OLKff92zHs2bqnYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqhr2f04+A+2/4DKss6FNuKFm0tzFct2KuxVnP5HaqNN/&#xA;NTRmZykN561nLT9r1Ym9Nf8AkaEzB18Lxl2HZs6yhIJb+XUtS1LU5TWW/vJ7mQ7btK5Y9AB1ObPS&#xA;Q4YU6rWz4slt5lOI7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqsllWJC7dug&#xA;8TkZSoWyjEk0lMkjSOXbqcw5GzbmxjQpbgS7FXYqmXle/XTvNeh6gwqtnqFrMw6VWOZWI6HsMp1E&#xA;bgQ5GmlwzB81ul/7wxnuSxP/AARzP0/0B12o+sovLmh2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KrXdUUsxoBgJpIBJSu4naZ6nZR9kZiTnxFzIQ4QpZBm7FXYq7FVkrFFDjqrBhT2&#xA;ORnyZw5pnpX+8EX+y/4kcy9P9AcLUfWUXlzS7FXYq7FXYq7FXYqitM0nU9Vu0s9NtZbu6f7MUKl2&#xA;p4mnQe5yGTJGAuRoM8eOUzURZeo+Xv8AnHbzBdosut3sWmqdzbxj6xL8mIKxj6GbNRm7ZgNoDi+x&#xA;3WDsLJLeZ4ftZrZf849eR4U/0ia9unpuWlRBX2CIv6zmDLtnMeVB2MOw8I5mRRc35C/l5ItEt7iI&#xA;0pVJ2Jr4/Hy3yA7Xz94+TM9i6c9D80g1b/nG7R5FZtJ1ae3fqEukSZT7VT0iPuOZGPtuX8UQfd+C&#xA;4uXsCB+iRHv3/U848y/k/wCeNBVppLP69aLubiyJlAH+UlBIPnxpm0wdpYcm10fN1Oo7LzYt64h5&#xA;fi2FZnuudirsVdirsVdiqySRI15OaDBKQHNMYknZLLi4eZt9lHRcxJzMnMhARUsgzdiqc6D5N81a&#xA;/U6NpVzeoDRpY4z6QPgZDRAfmcqyZoQ+o03Y8E5/SCUXrX5b+etFga41LRLqG3QVknCepGo8WePm&#xA;q/ScjDU45bAhlk0uWAsxLG8vcdTuP7pvo/XkZ8mcOabWUTwrLbuKPBLJGw8Crb5laY3FxNUKmicv&#xA;cd2KuxV2KuxV2Ksz/Ln8stV843nME2ujwNS6viK1PX04gftP+C9T2Bwdbro4B3y7nYaDs+WoPdAc&#xA;z+p9K+WfKmg+WrAWWkWqwJQerL1llYftSP1Y/q7ZyufUTyyuRew0+mhhjwwFJvlLe7FXYq7FXYqw&#xA;vzp+U3lXzQrzvD9Q1RqkX9uoDFv+LU2WT6fi98z9L2hkxbc49xddq+zMWbeuGXeP0975786/l15k&#xA;8pXFL+H1bJzSDUIatC/gCf2G/wAlvornSaXW48w9PPueV1egyYD6ht39GMZluG7FXYqpT3EcK77s&#xA;ei5CcxFnCBklk0zytyY/IdhmLKRLlxiI8lmRZJjoPl3Wtf1FNO0e0kvLuTcJGNlHdnY0VVHixpkM&#xA;mSMBcjQbMeKUzURZfQ3kD/nHbRNKEd95oZNV1AUYWa1+qRnwYGhlP+tRfY9c02o7RlLaGw+13um7&#xA;LjHefqP2ftewQwwwRJDCixRRgLHGgCqqjoABsBmtJt2oFL+uxwJfPP5//lXY6fAfNuhwCC3LhNVt&#xA;YxRFaRqLOo/Z5MQrAdyD45uez9WZeiXwdF2noxEeJH4/reEtGZSkQFTI6qB7k0zZzOzqMY3Zp55s&#xA;JdO/MPzRZSoIz+kJbhEGw9O5YzR0H+o4yXZs7xj4I7Uhw5T7ylGbB1rsVdirsVdiqfeSPKV75q8w&#xA;2+k21URv3l1PSoihUjm/40HuRmNqtQMMDI/guTo9Mc2QQHx9z610bR9O0bTLfTdOhEFpbKEjRfxY&#xA;nuzHcnuc47LklORlLmXusWKOOIjEUAjMrbHYq7FXYq7FXYq7FVK6tLW7tpLa6hSe3lHGWGRQ6Mp7&#xA;FTscMZGJsbFjKIkKIsPDvzD/ACGlh9XU/KamWLdpdJY1de59Bj9of5B38CemdBo+1gfTk+f63m9d&#xA;2KR6sX+l/U8YljkikaOVTHIhKujAhlI2IIPTN4Dbz5FbIG4vlWqxbt/N2GVTy1yboYb5oFmZiSxq&#xA;T1JzHJtyQKawK9J/Lj8kPMXmsxX99y0vQmowuZF/ezL1/cIex/nbbw5dMwdTro49hvJ2Gl7Pnl3O&#xA;0fxyfTHlXyf5f8raaun6LarbxbGWU/FLK380jndj+A7UGaPLmlkNyL0OHBDGKiE5ypudirsVS7zH&#xA;o8OtaBqOkzAFL63kgqexdSFb/YnfJ458MhLua8sOOJj3h8X+TNP+u+ePL+nyoeM2pWyTJ0IQTLz6&#xA;+C1zpNTKoE+TyuljeQDzD0X/AJyG0Y6f+ZEGpKjCDWrJC0h+yZ7f92yqf8mNY6/PKex8u1fjvcjt&#xA;vFUuLv8A7P1PPM3rzzsVdirsVdir6N/5x/8ALEdh5Wk1qRP9L1aQ8GPUW8JKKPpcMffbOY7Yz8WT&#xA;g6R+963sTT8OLjPOX3B6lmod07FXYq7FXYq7FXYq7FXYq7FWF+ffyn8secYmkuUNlqdKJqNuAHNO&#xA;glX7Mg+e/gRmZp9bkxbA3HucLU6DHl3IqXe8C8y/kB+YGkTObO2XWLMH4J7Rhzp25QsQ9f8AV5D3&#xA;za4u0McuZouly9m5Y8hxDyQeh/kd+ZOrSqv6LOnwk0a4vmEKrv8AyfFKfoTJ5Ndij1v3McfZ+aXS&#xA;ve9r8h/kB5X8vPHe6sRrOqJRlMq0t42G/wAEW/IjxevsBmq1HaE57D0h2+m7NhDeXqP2PUumwzAd&#xA;k7FXYq7FXYq7FXyp+SWlDU/zmFwkY+r6aLy9ZG3Cg1hTr3V5lIze66dYq9zzvZ0LzX3W9Q/5yU8v&#xA;G+8kwa1CtbnQrlZWPf0JyIpAB/r+mfkDmF2dl4cld/6HYdqYePHfd+n8B88qwZQy7qwqD7HOtBt4&#xA;sil2FDsVdirsVfZHk+ySx8qaPaIABDZQKadz6a8j26nfOH1MuLJI+ZfQNLDhxRH9EJvlLe7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq07oil3YKo3LE0A+k4qst7m2uY/Ut5UmjrTnGwZaj3FcJBHNAIPJUwJdir&#xA;sVdirsVdiqB17UV0zQ9R1JjRbK2muCf+MUZfv8snjjxSA7ywyT4Yk9weLf8AOLPl/hputeYpFHK6&#xA;mSytmIPIJCvqSEduLtIv0rmw7SyXIRdZ2ViqJl8Htuq6baappl3pt4pe0vYZLe4UGhMcqlGoe2xz&#xA;XRkYkEdHaTiJAg9Xxbe6Te6Hq1/oN8P9L0ud4HahAdQfgkXkAeLr8S+xGdjo8onAU8NrcJxzIKzM&#xA;tw3Yq7FXYq+zvLcyT+XdKnjNY5bO3dD7NEpHTOGzipyHmX0HTm8cT/RH3JjlTc7FXYq7FXYq7FXY&#xA;q7FXYqhdU1XTdKspL7UrqO0s4hWSeZgij2qe57DvkowMjQFljOYiLJoPD/PH/OSyIz2flC2ElKqd&#xA;Tu1PE+8UOx+l/wDgc2uDszrP5Om1Ha3TGPiXiuvebPMvmCczazqU965NQsrn01/1IxRE+SgZtMeK&#xA;MPpFOoyZpzNyNqWheY9d0C9W90e9lsrhSCWiYgMB2dfsuPZgRhyY4zFSFox5ZQNxNPpT8qfzv0/z&#xA;T6Wka1wsdf8AsxsPhhuT/wAV1Pwyf5Hft4DR6vQnH6o7x+56DR9oDJ6ZbS+96rmvdm7FXYq7FXYq&#xA;84/P/XTpn5cXltCSbzV5I7C2Rd2YyNycAe8aMPpzL0ULyX3OF2hOsRHfsyfyB5YTyv5O0rQxT1bS&#xA;AfWSDUGeQmSYg7beozU9spzZOOZLfgxcEBFkGVNzwP8A5yS8mNDPZ+drKIlAFs9ZCD9kmkEzUHif&#xA;TJJ/kGbjsvU8J4T+PxzdH2vpeIcQ/Hd+r5PGwQQCDUHcHOmeUbxV2KuxV9Qfkj5hj1byJa25at1p&#xA;RNpMvfivxRGnh6ZA+YOcl2ph4MxPSW72fZGfjwAdY7fqZ/mudo7FXYq7FXYq7FXYq7pucVeW/mB+&#xA;fnlry76tjo/HWNXWqkRt/o0Tf8WSD7RH8qfIkZn6fQSnvL0h1up7Shj2j6pfY+dPNnnbzL5rvvre&#xA;tXjT8SfRtx8MMQPaOMbD59T3ObvDgjjFRDoc2onlNyKRZa0OxV2Kto7o6ujFXUhlZTQgjcEEYpfS&#xA;n5LfnSdcMXlzzHKq6sqhbG+Y0+sgbcHr/u3wP7Xz66PW6Lg9UeX3PQaDX8fon9XQ9/7Xsuax2zsV&#xA;dirsVeUXHHzz+ckEUZ9TQPIg9WZgapJqcp+FdiP7opX2KEftZmj93i/pT+515/e5v6MPver5hOwd&#xA;iqF1bS7DVtNudM1CIT2V5G0M8TdCjih+R8COmSjIxNhjOIkKPIvjTzf5b1LyT5nuvL99WWGM+pY3&#xA;JFPWtnJ9OQfdRh2YEds6nR6viiHj9dojCZQUc0UgqjA+3fNiJA8nWSiRzX5Ji7FWU/l156u/J+vL&#xA;eoplsZwIr+2H7cda8lr+2nVfu75h63SDNCuvRzdDrDgnxdDzD6o0TXNK1zTYtR0u4W5tJh8Lr1B7&#xA;qwO6sO4OcjlxSxy4ZCi9rhzRyR4omwjsrbXYq7FXYq7FWFedfzd8meVEkjubsXmpLULp1qRJLyHa&#xA;Qj4Y/wDZGvgDmVg0c8nIUO9w9RrseLmbPcHz158/Orzb5sElqr/ozR3qPqFuxq6ntNLsz/LZfbNz&#xA;p9FDHvzk6LU6/Jl25R7nn+ZjgvVvyy/IfVvM0cWq6276Zor0aJQALidfFA1Qin+Zhv2BG+a/Va8Q&#xA;2jvJ2ek7Olk9Uto/aXveiflf5A0aER2eh2rMOs1xGLiUn/Xl5sPo2zUT1WSXORd3j0eKHKI+9Mjo&#xA;nlK5/cmwsJu/p+jC/T2ocr45jqWzw8Z6BIfMf5Ofl7rttJG+kw2NwwPC7sVFu6sf2qIAjf7JTl2P&#xA;WZIHnfvaMuhxTHKvc+VvOvlHUfKfmK60W++J4TyhnAossLbpIvzHUdjUds6DBmGSIkHmtRgOKZiU&#xA;kR3R1dGKupDKymhBG4IIy1qfSn5NfnZFrKQeXfMkwTWRSOzvn2W58Ec9pf8AiX+t10et0PD6o/T9&#xA;z0Gg7Q4/RP6u/v8A2vZc1jtnYq89/N78xn8saZFpWjg3HmvWSLfS7WMc3QyHh6xX5miDu3sDmVpc&#xA;HGbP0hw9XqeAcMfrPJOfy28lx+UPKltpjMJtQkJudUualjLdS0MjVO5AoFB8BXrlefLxyvp0bdNh&#xA;8OFderKcpb3Yq7FWCfm9+Wtv538u+nDxi1yx5S6XcHYFj9qFz/JJT6DQ+IOTpdQccvJxNXphlj5j&#xA;k+Q54Lq1uprS7ia3vLZ2iuIHBV0dDRlIPQgjOkhMSFh5acDE0Vy3VwvRz9O/68tGSQ6tJxxPRd9e&#xA;uf5vwGHxZI8GLje3J/bp9Ax8WS+FFNfLfnbzR5bvfrej38ls5p6kezRSAdnjaqt923bKM2OOUVLd&#xA;yMGWWI3A09e0P/nKOVY1TXdEDuPtXFlJxB/55S8v+TmavJ2X/NPzdvj7Y/nR+TJ4P+cl/wAv5FBk&#xA;t9RhboVaGI/TVZW2yg9mZPJyB2ti7pfj4omT/nI78t0Qsr3kh/lW33/4ZlGR/k3L5Mj2rh8/kx3W&#xA;f+co9KRGXRdFnncj4ZLyRIQD4lI/Vr/wQy6HZZ/iPyaMnbEf4Y/N5j5p/On8wPMSvDNf/ULN6g2t&#xA;iDCpB7M9TIw9i1Mz8Wixw6WfN12bX5cnM0PJgvXc5luE7FXsX/OPn5c6R5gurrXtXRbm202RYray&#xA;ahR5ivLnKp6qopQdCflmt7Q1MoARj1dt2ZpYzJlLcDo9R/NH85dI8nRNp9iEv/MDL8NrX93ACNmn&#xA;K/eEG59hvmv0uill3O0XY6zXxxbDeX45vmjzH5381+Y7h5tY1Oe5Dmog5FYV9liWiL92b3HghAek&#xA;PPZdRPIfUbSNWKkMpoRuCOoOWtT2H8k/zc1bT9dttA1y8e60i/YQ28s7F2t5m2jo7VPpsfhIOw67&#xA;b11uu0YMeKI3DtOz9bKMhGRuJ+xk/wDzlHpNgdK0bV+SrqCTtaBP2pIXQyE/KNk/4bKOy5mzHo5P&#xA;bEBwxl15PnfNy6F3TcYq9e8jf85Fa/otqlhr1udZtYwFiuefC5VR2ZiGEn00Puc1ufs6MjcfS7XT&#xA;9qSgKkOIfanevf8AOUkjWjpomjejcMpAubuUOEPiIkA5fS30ZVDssDeR2bsna5IqMd/NMvyO8j6v&#xA;qmoyfmR5taS41K8BOkLP9oIw4m4K9qr8MQ6cdwKFTlGszADw4cg36HASfEnuTy/X+p7fmudq7FXY&#xA;q7FXYq8j/O38nB5oibzBoUap5jt0pNCKKLyNBQKT09RQKKe4+E9qZ+j1fhmj9LrtdovEHFH6vvfM&#xA;LLIkjxSo0U0TFJYnBVlZTQqwO4IOb6MgQ83KJBouyTF2KuxV2KuxV2KuxV2KuxV2Kpv5f83+ZvLw&#xA;uRomoy2IvFCXHpEDkFrQ7g0IqaMN8ryYYT+oXTbizzx3wmrSqaaWaV5pnaSWQlpJHJZmYmpJJ3JO&#xA;WAU1k2txQ7FXdNxiqO1bXda1idJ9Wvp7+aNQkclxI0hVR2BYmgyEMcY8hTOeSUzcjaBybB2KtEgC&#xA;p6Ypeo/kr+UM3m29TXdaiZPLNq/7qJgQbyVD9kf8VKftt3+yO/HWa3WcPpjzdroNFxnil9P3vqlE&#xA;REVEUKigBVAoABsAAM0b0LeKuxV2KuxV2KuxV5N+cH5I2vmoSa3oIS18yIKyIaLFdhR9l+yyfyv0&#xA;7N4rnaXWHHsfpdfrNCMm8fq+98x3tne2F7NYahbvaX1u3Ce2lUq6t7g5voZBIWHnMmMxNFSybW7F&#xA;XYq7FXYq7FWU/l9+XWued9TktNOKQwWwV7y8lrwiVyQuw3Zm4niPbtmPqNTHELLk6bSyzGgyDz1+&#xA;RPmzyxALy1/3M6eFrNNbRsJIiOvOKrNxp+0K+9Mpwa+GTY+kt+p7OnjFj1B5tmc692KuxV2KuxVd&#xA;HHJJIscal5HIVEUEkk9AAMUgPU/IX/OP/mfXZY7rXVfRtJ2LCQUupB1okZ+x836eBzX6jtCENo+o&#xA;/Y7LTdmTnvL0x+1i35o+TrLyj5wudGsZ5Li0jjiliaYqZQJEBKuVCqTX2G2ZGlzHJDiPNxtZgGLI&#xA;YjkxJmVRUmgy8mnGAt6v+Uf5H33meSDW/MUb2nlwUkgtjVJbzuPdIj3bqR9n+YazV63h9MebttF2&#xA;eZeqX0/e+n7W1trS2itbWJILaBFjhhjUKiIooqqo2AAzSkkmy78AAUFXAl2KuxV2KuxV2KuxV2Ks&#xA;O/MP8rPLXnizAv4/q2pxLxtNUhA9aPuFbp6iV/Zb3oQd8vwaiWM7cnG1GljlG/PvfL3nr8tfNnkm&#xA;5K6rb+tpzNxt9VgBaB69Axp8D/5LfRUb5vcGrjkHm89qdFPGfJiwIIqNxmW4beKHYq7FXYq9C/J3&#xA;8zk8katcreQtPpOpemt36f8AeRtGW4SKD1oHbkvf6Mw9ZpfFG3MOfodX4Mjf0l9UaF5h0TXrBL/R&#xA;7yK9tX/biapU/wArr9pW9mFc5/JjlA1IU9JjyxmLibCR+Y/yq8g+YZHm1HSIfrT7tdQVglLH9pmi&#xA;K8z/AK1ctx6vJDkWnLo8U+Y3YRe/84w+TpW5WepX9sD+y5ilA+XwIfxzLj2pPqA4cuyMfQlLf+hW&#xA;LD/qYpf+kVf+qmT/AJVP837Wv+Rx/O+xfF/zizpQesuvzungluin7y7fqwHtU/zUjseP877E90z/&#xA;AJxt/Ly1YNdNe6gR1SaYIh/5ErE3/DZVLtLKeVBuh2ViHOyzKy0DyH5Msmu7e0sdHt4xR7x+CNQ9&#xA;mmk+M/ItmNLJkymiTJy44sWIWAIvMfPv/OSNhbxyWPlCL6zcmqnVJ1Kwp7xRt8Tn3ag9jmdp+zSd&#xA;5/J12p7VA2x/N4NXzB5n11liSfV9av3LMFBkkdj1Jp0AH0AeAzamUcce4B1AhPJLvJe+fll/zjtZ&#xA;6c0Wr+chHfagKPDpS0e2hPX96ekrDw+x/rZp9TrzLaPLvd3pezhHefPue3AU2HTNa7V2KuxV2Kux&#xA;V2KuxV2KuxV2KuxVTubW2ureS2uoknt5lKSwyqHR1OxVlaoIPvhBI3CCARReM+d/+caNE1BpL3yp&#xA;c/oi8b4jYzcns2O32SOUkXc/tDsAM2GDtCUdpbus1HZkZbx2eFeaPI/m/wAqy8Ne0yW1iJ4pdqPU&#xA;t3J6cZU5JX2rX2zbYtTCfIumzaSePmEjVlYVBrl4LjEU3hQ7FXYqjdJ1rV9Huhd6VezWNyP92wSN&#xA;GxHgeJFR7HIzhGQoi2cMkom4mnoej/8AORf5i2CBLp7XU1G3K5h4vT/WgMX3kHMKfZ2I8rDnw7Uy&#xA;x50WS23/ADlPqCgfWfLsUp/a9O5aOvy5RyZQeyh0l9jkDtg9Y/art/zlU3E8fLADU2Jvqivy+rjB&#xA;/JX9L7P2p/ln+j9v7EFcf85Sa4w/0bQraM06ySySb/7ER5IdlR6yLE9sS6RDH9X/AOci/wAxr5GS&#xA;3ltdNU7crWGrU/1pzN94y6HZ2Ic7LRPtTNLlQ9zA7rVPM/mnU0SWa81zUpKiGIGS4k8SEUcqD2UZ&#xA;kgwxjagHEIyZTvZL0zyZ/wA42eZtUMd15nuBo1iaE2cRWW7ddjQkVjjqD1JYjuuYGbtEDaO7stP2&#xA;XI7y2+9775S8jeV/KVj9U0KxS2DAevOfjmlI7ySNVm8adB2AzU5M0pm5F3OLBHGKiE+yttdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdiq2WKKaJ4pUWSKRSkkbgMrKwoQQdiCMQVIt555m/IL8t9cZ5UsW&#xA;0m7c1M+nN6Ir/wAYiGhp8kB98y8etyR624eXQYp9K9zzPW/+cXPMcBLaHrVtfRgE+leI9u9R0UFP&#xA;WVj7njmbDtMdQ6/J2Sf4SwXVPye/NHTAGuPL08yE0DWjJdV/2MLSMPpGZcNdjPVwp9n5Y9P0sav9&#xA;I1vTnKajpl3ZOOq3EEkRHTs4Hjl8c0TyLjywTjzCB9eMGhNCOxByfGGHAXfWIv5vwOPGF4CrW8N1&#xA;cuEtreadz0WKNnJr7AYDkASMUiyHT/y1/MXUZEjtfLWofvKcHnha3jNeh9SYIlPeuUS1mMdQ3x0W&#xA;U9Cy/Rv+cbfzGvqNfvZ6THUBlll9aWniqwiRD9LjMafaUBy3cvH2VM89nonl7/nGHyfZMsut31zr&#xA;MineIf6LAR7pGWk+6TMPJ2jM8tnPxdmY489/sepaH5a8v6DbfVdG0+CwhIAZYI1Qtx2Bdh8Tn3Yk&#xA;5hTySlzNufDHGAqIpMsgzdirsVdirsVdirsVdir/AP/Z</xmpGImg:image>
+               </rdf:li>
+            </rdf:Alt>
+         </xmp:Thumbnails>
+         <dc:format>image/svg+xml</dc:format>
+         <xmpTPg:MaxPageSize rdf:parseType="Resource">
+            <stDim:w>755.000000</stDim:w>
+            <stDim:h>826.000000</stDim:h>
+            <stDim:unit>Points</stDim:unit>
+         </xmpTPg:MaxPageSize>
+         <xmpTPg:NPages>1</xmpTPg:NPages>
+         <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
+         <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
+         <xmpTPg:PlateNames>
+            <rdf:Seq>
+               <rdf:li>Cyan</rdf:li>
+               <rdf:li>Magenta</rdf:li>
+               <rdf:li>Yellow</rdf:li>
+               <rdf:li>Black</rdf:li>
+            </rdf:Seq>
+         </xmpTPg:PlateNames>
+         <xmpTPg:SwatchGroups>
+            <rdf:Seq>
+               <rdf:li rdf:parseType="Resource">
+                  <xmpG:groupName>Default Swatch Group</xmpG:groupName>
+                  <xmpG:groupType>0</xmpG:groupType>
+               </rdf:li>
+            </rdf:Seq>
+         </xmpTPg:SwatchGroups>
+      </rdf:Description>
+   </rdf:RDF>
+</x:xmpmeta>
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                           
+<?xpacket end="w"?>
+	</metadata>
+<path fill="#00598E" d="M539.2,167.8c-39.8-24.8-77.2-34.5-114.8-59.2c-23.2-15.8-55.5-53.2-82.5-85.5c-5.2,51.8-21,72.8-39,87.8
+	c-38.2,30-62.2,39-95.2,57C179.9,182.1,29.2,272.1,29.2,465.6s162.8,336,343.5,336s337.5-131.2,337.5-330S563.2,182.8,539.2,167.8z"
+	/>
+<path fill="#FFFFFF" d="M478.2,633.5c12,0,24.8,0.8,33.8,6.8s14.2,19.5,17.2,27s0,12-6,15c-5.2,3-6,1.5-11.2-8.2s-9.8-19.5-36-19.5
+	s-34.5,9-47.2,19.5s-17.2,14.2-21.8,8.2s-3-12,5.2-19.5s21.8-19.5,34.5-24.8S466.2,633.5,478.2,633.5L478.2,633.5z"/>
+<path fill="#FFFFFF" d="M353.8,719c15,12,37.5,21.8,85.5,21.8S521,727.2,536,716c6.8-5.2,9.8-0.8,10.5,2.2s2.2,7.5-3,12.8
+	c-3.8,3.8-38.2,27.8-78.8,31.5s-95.2,6-128.2-24c-5.2-5.2-3.8-12.8,0-15.8s6.8-5.2,11.2-5.2S351.5,717.5,353.8,719L353.8,719z"/>
+<path fill="#0073BA" d="M170,662c57-0.8,67.5-10.5,117.8-33c271.5-121.5,321.8-232.5,331.5-258s24-66.8,9-112.5
+	c-2.9-8.8-5-15.9-6.5-21.6c-36.1-40.3-71.9-62.4-82.7-69.1c-39-24.8-77.3-34.5-114.8-59.2c-23.2-15-55.5-53.2-82.5-85.5
+	c-5.2,51.8-20.2,73.5-39,87.8c-38.2,30-62.2,39-95.2,57C179.8,182.8,29,272,29,465.5c0,61.8,16.6,118.4,45.1,166.8l7.4-0.3
+	C97.2,646.2,122,662.8,170,662z"/>
+<path fill="#004975" d="M539,167.8c-39-24.8-77.2-34.5-114.8-59.2c-23.2-15-55.5-53.2-82.5-85.5c-5.2,51.8-20.2,73.5-39,87.8
+	c-38.2,30-62.2,39-95.2,57C179.8,182.8,29,272,29,465.5c0,61.8,16.6,118.4,45.1,166.8c60.7,103.2,175.4,169.2,298.4,169.2
+	c180.8,0,337.5-131.2,337.5-330c0-109.1-44.3-185.5-88.3-234.6C585.6,196.5,549.8,174.5,539,167.8z M630.2,255.5
+	c49.2,61.6,74.2,134.2,74.2,216c0,47.4-9,92.2-26.8,133.2c-16.9,38.8-41.2,73.2-72.3,102.3c-61.5,57.4-144.1,89-232.7,89
+	c-43.8,0-86.8-8.4-127.8-24.9c-40.3-16.2-76.5-39.4-107.8-69C70.9,639.7,34.6,555.7,34.6,465.5c0-80.3,26.1-151.7,77.5-212.2
+	c39.3-46.2,81.7-71.8,98-80.6c8-4.3,15.4-8.2,22.6-11.9c22.6-11.6,44-22.6,73.4-45.6c15.7-11.9,32.4-30.8,39.5-78.7
+	c24.8,29.5,53.5,62.6,75.5,76.8c19.5,12.9,39.5,21.9,58.8,30.6c18.3,8.2,37.2,16.8,55.9,28.7c0,0,0.7,0.4,0.7,0.4
+	C591.4,207.1,620.6,243.6,630.2,255.5z"/>
+<path fill="#93C5E4" d="M345.5,38c10.5,30.8,9,46.5,9,53.2s-3.8,24.8-15.8,33.8c-5.2,3.8-6.8,6.8-6.8,7.5c0,3,6.8,5.2,6.8,12
+	c0,8.2-3.8,24.8-43.5,64.5s-96.8,75-141,96.8S89,326,83,315.5s2.2-33.8,30-64.5s115.5-75,115.5-75L338,99.5l6-29.2"/>
+<path fill="#FFFFFF" d="M345.5,37.2c-6.8,49.5-21.8,64.5-42,80.2c-33.8,25.5-66.8,41.2-74.2,45c-19.5,9.8-90,48.8-126.8,105
+	c-11.2,17.2,0,24,2.2,25.5s27.8,4.5,82.5-28.5S266,212,296.8,179.8c16.5-17.2,18.8-27,18.8-31.5c0-5.2-3.8-7.5-9.8-9
+	c-3-0.8-3.8-2.2,0-4.5S325.2,125,329,122s21.8-15,22.5-34.5S350.8,54.5,345.5,37.2L345.5,37.2z"/>
+<path fill="#FFFFFF" d="M176.8,582.5c0.8-58.5,55.5-113.2,124.5-114c87.8-0.8,148.5,87,192.8,86.2c37.5-0.8,109.5-74.2,144.8-74.2
+	c37.5,0,48,39,48,62.2s-7.5,65.2-25.5,91.5s-29.2,36-50.2,34.5c-27-2.2-81-86.2-115.5-87.8c-43.5-1.5-138,90.8-212.2,90.8
+	c-45,0-58.5-6.8-73.5-16.5C187.2,639.5,176,615.5,176.8,582.5L176.8,582.5z"/>
+<path fill="none" d="M628.2,258.5c15,45.8,0.8,87-9,112.5s-60,136.5-331.5,258c-50.2,22.5-60.8,32.2-117.8,33
+	c-48,0.8-72.8-15.8-88.5-30l-7.4,0.3c60.7,103.2,175.4,169.2,298.4,169.2c180.8,0,337.5-131.2,337.5-330
+	c0-109.1-44.3-185.5-88.3-234.6C623.2,242.6,625.4,249.7,628.2,258.5z"/>
+</svg>
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/metatag_favicons.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/metatag_favicons.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..cc25003c490da0738fe37d9ae98225ae429ef405
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/metatag_favicons.tags.test
@@ -0,0 +1,246 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Favicons tags work correctly.
+ */
+class MetatagFaviconsTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Favicons',
+      'description' => 'Test the Favicons meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'apple-touch-icon',
+    'apple-touch-icon-precomposed',
+    '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',
+    'apple-touch-icon-precomposed_72x72',
+    'apple-touch-icon-precomposed_76x76',
+    'apple-touch-icon_114x114',
+    'apple-touch-icon_120x120',
+    'apple-touch-icon_144x144',
+    'apple-touch-icon_152x152',
+    'apple-touch-icon_180x180',
+    'apple-touch-icon_72x72',
+    'apple-touch-icon_76x76',
+    'icon_16x16',
+    'icon_192x192',
+    'icon_32x32',
+    'icon_96x96',
+    'mask-icon',
+    'shortcut icon',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_favicons';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_tag = 'link';
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_name_attribute = 'rel';
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_value_attribute = 'href';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagValue() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'icon_16x16',
+   */
+  public function icon_16x16_test_output_xpath() {
+    return "//link[@rel='icon' and @sizes='16x16']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'icon_192x192',
+   */
+  public function icon_192x192_test_output_xpath() {
+    return "//link[@rel='icon' and @sizes='192x192']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'icon_32x32',
+   */
+  public function icon_32x32_test_output_xpath() {
+    return "//link[@rel='icon' and @sizes='32x32']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'icon_96x96',
+   */
+  public function icon_96x96_test_output_xpath() {
+    return "//link[@rel='icon' and @sizes='96x96']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed',
+   */
+  public function apple_touch_icon_precomposed_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and not(@sizes)]";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed_114x114',
+   */
+  public function apple_touch_icon_precomposed_114x114_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and @sizes='114x114']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed_120x120',
+   */
+  public function apple_touch_icon_precomposed_120x120_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and @sizes='120x120']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed_144x144',
+   */
+  public function apple_touch_icon_precomposed_144x144_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and @sizes='144x144']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed_152x152',
+   */
+  public function apple_touch_icon_precomposed_152x152_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and @sizes='152x152']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed_180x180',
+   */
+  public function apple_touch_icon_precomposed_180x180_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and @sizes='180x180']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed_72x72',
+   */
+  public function apple_touch_icon_precomposed_72x72_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and @sizes='72x72']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_precomposed_76x76',
+   */
+  public function apple_touch_icon_precomposed_76x76_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon-precomposed' and @sizes='76x76']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'apple_touch_icon',
+   */
+  public function apple_touch_icon_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and not(@sizes)]";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_114x114',
+   */
+  public function apple_touch_icon_114x114_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and @sizes='114x114']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_120x120',
+   */
+  public function apple_touch_icon_120x120_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and @sizes='120x120']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_144x144',
+   */
+  public function apple_touch_icon_144x144_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and @sizes='144x144']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_152x152',
+   */
+  public function apple_touch_icon_152x152_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and @sizes='152x152']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_180x180',
+   */
+  public function apple_touch_icon_180x180_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and @sizes='180x180']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_72x72',
+   */
+  public function apple_touch_icon_72x72_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and @sizes='72x72']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'apple_touch_icon_76x76',
+   */
+  public function apple_touch_icon_76x76_test_output_xpath() {
+    return "//link[@rel='apple-touch-icon' and @sizes='76x76']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath for 'mask-icon'.
+   */
+  public function mask_icon_test_tag_name() {
+    return 'mask-icon';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_tag_name for 'shortcut icon'.
+   */
+  public function shortcut_icon_test_tag_name() {
+    return 'shortcut icon';
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/metatag_favicons.test b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/metatag_favicons.test
new file mode 100644
index 0000000000000000000000000000000000000000..7cd8f25bf1370183efc481528dae248def40356c
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_favicons/tests/metatag_favicons.test
@@ -0,0 +1,228 @@
+<?php
+
+/**
+ * Tests for the Metatag Favicons module.
+ */
+class MetatagFaviconsTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Favicons tests',
+      'description' => 'Test the Metatag:Favicons module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_favicons';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+  /**
+   * Confirm the mask-icon meta tag works correctly.
+   */
+  public function testMaskIconValue() {
+    // The SVG image is copied from the archive obtained from
+    // https://www.drupal.org/about/media-kit/logos on 6/20/2016.
+    $svg_path = drupal_get_path('module', 'metatag_favicons') . '/tests/druplicon-vector.svg';
+    $relative_path = url($svg_path, array('absolute' => FALSE));
+    $absolute_path = url($svg_path, array('absolute' => TRUE));
+
+    // Testbot doesn't have "clean_url" enabled.
+    $relative_path = str_replace('?q=', '', $relative_path);
+    $absolute_path = str_replace('?q=', '', $absolute_path);
+
+    // Try filling in a path relative to the Drupal installation.
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $svg_path;
+    metatag_config_save($config);
+
+    // Load the config page.
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag's value is on the page.
+    $this->assertText(t('Icon: SVG') . ':');
+    $this->assertText($absolute_path);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertNotEqual((string)$xpath[0]['href'], $svg_path);
+    $this->assertEqual((string)$xpath[0]['href'], $absolute_path);
+
+    // Before proceeding, clear the site's caches.
+    drupal_flush_all_caches();
+
+    // Try filling in a relative path.
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $relative_path;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertNotEqual((string)$xpath[0]['href'], $svg_path);
+    $this->assertNotEqual((string)$xpath[0]['href'], $relative_path);
+
+    // Before proceeding, clear the site's caches.
+    drupal_flush_all_caches();
+
+    // Test filling in an absolute path.
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $absolute_path;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertNotEqual((string)$xpath[0]['href'], $svg_path);
+    $this->assertEqual((string)$xpath[0]['href'], $absolute_path);
+
+    // Before proceeding, clear the site's caches.
+    drupal_flush_all_caches();
+
+    // Test filling in an absolute path for an external file
+    $path = 'https://www.example.com/example.svg';
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $path;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertNotEqual((string)$xpath[0]['href'], $absolute_path);
+    $this->assertEqual((string)$xpath[0]['href'], $path);
+  }
+
+  /**
+   * Confirm the mask-icon meta tag 'color' attribute works correctly.
+   */
+  public function testMaskIconColor() {
+    // The SVG image is copied from the archive obtained from
+    // https://www.drupal.org/about/media-kit/logos on 6/20/2016.
+    $svg_path = drupal_get_path('module', 'metatag_favicons') . '/tests/druplicon-vector.svg';
+    $absolute_path = url($svg_path, array('absolute' => TRUE));
+
+    // Testbot doesn't have "clean_url" enabled.
+    $absolute_path = str_replace('?q=', '', $absolute_path);
+
+    // Try a color string.
+    $color = 'red';
+
+    // Update the global config.
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $svg_path;
+    $config->config['mask-icon']['color'] = $color;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertEqual((string)$xpath[0]['href'], $absolute_path);
+    $this->assertEqual((string)$xpath[0]['color'], $color);
+
+    // Before proceeding, clear the site's caches.
+    drupal_flush_all_caches();
+
+    // Try a color hex code.
+    $color = '#990000';
+
+    // Update the global config.
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $svg_path;
+    $config->config['mask-icon']['color'] = $color;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertEqual((string)$xpath[0]['href'], $absolute_path);
+    $this->assertEqual((string)$xpath[0]['color'], $color);
+
+    // Try a color RGB value.
+    $color = 'rgb(153, 0, 0)';
+
+    // Update the global config.
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $svg_path;
+    $config->config['mask-icon']['color'] = $color;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertEqual((string)$xpath[0]['href'], $absolute_path);
+    $this->assertEqual((string)$xpath[0]['color'], $color);
+
+    // Try empty color.
+    $color = '';
+
+    // Update the global config.
+    $config = metatag_config_load('global');
+    $config->config['mask-icon']['value'] = $svg_path;
+    $config->config['mask-icon']['color'] = $color;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm the meta tag is present.
+    $xpath = $this->xpath("//link[@rel='mask-icon']");
+    $this->assertEqual(count($xpath), 1, 'One mask-icon meta tag found.');
+    $this->assertEqual((string)$xpath[0]['href'], $absolute_path);
+    $this->assertFalse(isset($xpath[0]['color']));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4884d60fe73fca0a367fa89e786e6d7baf12e2e8
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/README.txt
@@ -0,0 +1,22 @@
+Metatag: Google Custom Search Engine (CSE)
+------------------------------------------
+This module adds certain meta tags that are primarily used by Google's Custom
+Search Engine aka "CSE".
+
+The following meta tags are provided:
+* thumbnail
+* department
+* audience
+* doc_status
+* rating
+
+
+Credits
+------------------------------------------------------------------------------
+The initial development was by Carlos E Basqueira [3].
+
+
+References
+------------------------------------------------------------------------------
+1: http://www.dublincore.org/documents/dces/
+2: https://www.drupal.org/u/cebasqueira
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.info b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.info
new file mode 100644
index 0000000000000000000000000000000000000000..d23e4aa208ee87037df9e4f7cb6daddd5c2fe160
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.info
@@ -0,0 +1,16 @@
+name = "Metatag: Google Custom Search Engine (CSE)"
+description = "Provides support for meta tags used for Google Custom Search Engine."
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_google_cse.test
+files[] = tests/metatag_google_cse.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.install b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.install
new file mode 100644
index 0000000000000000000000000000000000000000..d30cebce71a177b45a43c53b01703e11b55b82a3
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.install
@@ -0,0 +1,5 @@
+<?php
+/**
+ * @file
+ * Installation and update scripts for Metatag:Google CSE.
+ */
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ca0f6806b1a465c627da6de22f23d8de2e9f39e3
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.metatag.inc
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag:Google CSE.
+ */
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_google_cse_metatag_info() {
+  $info['groups']['google_cse'] = array(
+    'label' => t('Google Custom Search Engine (CSE)'),
+    'description' => t("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."),
+    'form' => array(
+      '#weight' => 80,
+    ),
+  );
+
+  $weight = 80;
+
+  // Default values for each meta tag.
+  $tag_info_defaults = array(
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'google_cse',
+    'element' => array(
+      '#theme' => 'metatag_google_cse',
+    ),
+  );
+
+  $info['tags']['thumbnail'] = array(
+    'label' => t('Thumbnail'),
+    'description' => t('Use a url of a valid image.'),
+    'image' => TRUE,
+    'weight' => ++$weight,
+  ) + $tag_info_defaults;
+
+  $info['tags']['department'] = array(
+    'label' => t('Department'),
+    'description' => t('Department tag.'),
+    'weight' => ++$weight,
+  ) + $tag_info_defaults;
+
+  $info['tags']['audience'] = array(
+    'label' => t('Content audience'),
+    'description' => t('The content audience, e.g. "all".'),
+    'weight' => ++$weight,
+  ) + $tag_info_defaults;
+
+  $info['tags']['doc_status'] = array(
+    'label' => t('Document status'),
+    'description' => t('The document status, e.g. "draft".'),
+    'weight' => ++$weight,
+  ) + $tag_info_defaults;
+
+  $info['tags']['google_rating'] = array(
+    'label' => t('Results sorting'),
+    'description' => t('Works only with numeric values.'),
+    'weight' => ++$weight,
+  ) + $tag_info_defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.module b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.module
new file mode 100644
index 0000000000000000000000000000000000000000..c68e936e8a393c1b9ee4b124ea1ef3ba1c1cf0d5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/metatag_google_cse.module
@@ -0,0 +1,47 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag:Google CSE.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_google_cse_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_google_cse_theme() {
+  $info['metatag_google_cse'] = array(
+    'render element' => 'element',
+  );
+
+  return $info;
+}
+
+/**
+ * Theme callback for a normal meta tag.
+ *
+ * The format is:
+ * <meta name="[name]" content="[value]" />
+ */
+function theme_metatag_google_cse($variables) {
+  $element = &$variables['element'];
+
+  if ($element['#name'] === 'google_rating') {
+    $element['#name'] = 'rating';
+  }
+
+  $args = array(
+    '#name'  => 'name',
+    '#value' => 'content',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/tests/metatag_google_cse.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/tests/metatag_google_cse.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..26bd4c7b4ed470ea858360b78791ad21e7488e1f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/tests/metatag_google_cse.tags.test
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Google CSE tags work correctly.
+ */
+class MetatagGoogleCSETagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Google CSE',
+      'description' => 'Test the Metatag:Google CSE meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'audience',
+    'department',
+    'doc_status',
+    'google_rating',
+    'thumbnail',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'metatag_google_cse';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_tag_name() for 'google_rating'.
+   */
+  public function google_rating_test_tag_name() {
+    return 'rating';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'thumbnail'.
+   */
+  public function thumbnail_test_value() {
+    return $this->randomImageUrl();
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/tests/metatag_google_cse.test b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/tests/metatag_google_cse.test
new file mode 100644
index 0000000000000000000000000000000000000000..c10af51722abec627be0f46382d9227cf4e561ed
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_cse/tests/metatag_google_cse.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag Google CSE module.
+ */
+class MetatagGoogleCSETest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Google CSE tests',
+      'description' => 'Test the Metatag:Google CSE module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(array $modules = array()) {
+    $modules[] = 'metatag_google_cse';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cf7b2ed03e584f64dac16ebc4f68192c79d7aaac
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/README.txt
@@ -0,0 +1,46 @@
+Metatag: Google+
+----------------
+This module adds support for meta tag configuration for Google+ Snippet [1].
+
+The following Google+ tags are provided:
+
+* itemprop:name
+* itemprop:description
+* itemprop:image
+* author
+* publisher
+
+Also itemtype is provided to add schema in the HTML markup as follows:
+
+<html itemscope itemtype="http://schema.org/Article">
+
+
+Usage
+--------------------------------------------------------------------------------
+Page type (itemtype) provides default type options from the Google+ Snippet page
+[1]; to add other types either install select_or_other module [2] or use the
+Metatag hooks (see metatag.api.php).
+
+
+Installation
+--------------------------------------------------------------------------------
+The $schemaorg variable must be appended to the <html> tag in the html.tpl.php
+file being used on the site, and it must be added after the $rdf_namespaces
+variable, e.g.:
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print
+  $language->language; ?>" version="XHTML+RDFa 1.0" dir="<?php print
+  $language->dir; ?>"<?php print $rdf_namespaces; ?><?php print $schemaorg; ?>>
+
+
+Credits / Contact
+--------------------------------------------------------------------------------
+Originally developed by Eric Chen [3] and sponsored by Monkii [4].
+
+
+References
+--------------------------------------------------------------------------------
+1: https://developers.google.com/+/web/snippet/
+2. https://drupal.org/project/select_or_other
+3: https://drupal.org/user/265729
+4: http://monkii.com
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bafec70e9f6e9d9e3de97419682c417590a940f1
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.inc
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @file
+ * Metatag controller for Google+.
+ */
+
+/**
+ * Schema meta tag controller.
+ *
+ * This extends DrupalTextMetaTag as we need to alter variables in
+ * template_preprocess_html() rather output a normal meta tag.
+ *
+ * This controller is little different from DrupalTitleMetaTag and same value in
+ * the itemtype instead of title. So in the MYTHEME_preprocess_html(),
+ * $variable['itemtype'] will be provided.
+ */
+class DrupalSchemaMetaTag extends DrupalTextMetaTag {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getElement(array $options = array()) {
+    $element = array();
+    $value = $this->getValue($options);
+    $element['#attached']['metatag_set_preprocess_variable'][] = array('html', 'itemtype', $value);
+    return $element;
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.info b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.info
new file mode 100644
index 0000000000000000000000000000000000000000..3d405f015c4f2c39681998c6fb52d01fcb3a0677
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.info
@@ -0,0 +1,19 @@
+name = Metatag: Google+
+description = "Provides support for Google+ 'itemscope', 'author' and 'publisher' meta tags."
+package = SEO
+core = 7.x
+
+dependencies[] = metatag:metatag
+
+files[] = metatag_google_plus.inc
+
+; Tests.
+files[] = tests/metatag_google_plus.test
+files[] = tests/metatag_google_plus.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.install b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.install
new file mode 100644
index 0000000000000000000000000000000000000000..9e569fe5baa3c74c8256a9d0dadfe95a5220d27a
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.install
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @file
+ * Various update scripts for Metatag: Google Plus.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function metatag_google_plus_install() {
+  // Notify the site builder that the html.tpl.php must be updated.
+  metatag_google_plus_update_7100();
+}
+
+/**
+ * Implementations of hook_update_N().
+ */
+
+/**
+ * Notify the site builder that the html.tpl.php file needs to be changed.
+ */
+function metatag_google_plus_update_7100() {
+  drupal_set_message(t("Note that the template's html.tpl.php must be updated in order for the Metatag: Google+ module to work correctly. Please see its README.txt file for details."));
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ed9a04787b5ce437904679025b83414e0dfd0a82
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.metatag.inc
@@ -0,0 +1,154 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag Google+ module.
+ */
+
+/**
+ * Implements hook_metatag_bundled_config_alter().
+ */
+function metatag_google_plus_metatag_bundled_config_alter(array &$configs) {
+  foreach ($configs as &$config) {
+    switch ($config->instance) {
+      case 'global':
+        $config->config += array(
+          'itemprop:name' => array('value' => '[current-page:title]'),
+        );
+        break;
+
+      case 'global:frontpage':
+        $config->config += array(
+          'itemprop:name' => array('value' => '[site:name]'),
+          'itemprop:description' => array('value' => '[site:slogan]'),
+        );
+        break;
+
+      // On error pages point everything to the homepage.
+      case 'global:403':
+      case 'global:404':
+        $config->config += array(
+          'itemprop:name' => array('value' => '[site:name]'),
+        );
+        break;
+
+      case 'node':
+        $config->config += array(
+          'itemprop:description' => array('value' => '[node:summary]'),
+          'itemprop:name' => array('value' => '[node:title]'),
+          'itemtype' => array('value' => 'Article'),
+        );
+        break;
+
+      case 'taxonomy_term':
+        $config->config += array(
+          'itemprop:description' => array('value' => '[term:description]'),
+          'itemprop:name' => array('value' => '[term:name]'),
+        );
+        break;
+
+      case 'user':
+        $config->config += array(
+          'itemprop:name' => array('value' => '[user:name]'),
+          'itemtype' => array('value' => 'Person'),
+        );
+        if (variable_get('user_pictures')) {
+          $config->config += array(
+            'itemprop:image' => array('value' => '[user:picture:url]'),
+          );
+        }
+        break;
+    }
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_google_plus_metatag_info() {
+  $info['groups']['google-plus'] = array(
+    'label' => t('Google+'),
+    'description' => t('A set of meta tags specially for controlling the summaries displayed when content is shared on <a href="!url">Google+</a>.', array('!url' => 'https://plus.google.com/')),
+    'form' => array(
+      '#weight' => 80,
+    ),
+  );
+
+  // Google+ meta tags stack after the Twitter Cards tags.
+  $weight = 60;
+
+  // Defaults used for all cards.
+  $defaults = array(
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'google-plus',
+    'element' => array(
+      '#theme' => 'metatag_google_plus',
+    ),
+  );
+
+  $info['tags']['itemtype'] = array(
+    'label' => t('Page type'),
+    'description' => t('Schema type. <a href="!url">More schema info</a>. If your page type does not exist in options above, please install <a href="!url2">select_or_other</a> module to enter page type manually.', array('!url' => 'http://schema.org/docs/schemas.html', '!url2' => 'https://drupal.org/project/select_or_other')),
+    'class' => 'DrupalSchemaMetaTag',
+    'weight' => ++$weight,
+    'select_or_other' => TRUE,
+    'form' => array(
+      '#type' => 'select',
+      '#options' => array(
+        'Article' => t('Article'),
+        'Blog' => t('Blog'),
+        'Book' => t('Book'),
+        'Event' => t('Event'),
+        'LocalBusiness' => t('Local Business'),
+        'Organization' => t('Organization'),
+        'Person' => t('Person'),
+        'Product' => t('Product'),
+        'Review' => t('Review'),
+      ),
+      '#empty_option' => t('- None -'),
+    ),
+  ) + $defaults;
+
+  $info['tags']['itemprop:name'] = array(
+    'label' => t('Title'),
+    'description' => t('A Google+ title for the page being shared. Keep keywords towards the front.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['itemprop:description'] = array(
+    'label' => t('Description'),
+    'description' => t('Longer form description, you’ve 200 words here that can specifically reference your presence on Google+'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['itemprop:image'] = array(
+    'label' => t('Image URL'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'image' => TRUE,
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  ) + $defaults;
+
+  $info['tags']['author'] = array(
+    'label' => t('Author URL'),
+    'description' => t("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."),
+    'class' => 'DrupalLinkMetaTag',
+    'weight' => ++$weight,
+    'element' => array(),
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $defaults;
+  $info['tags']['publisher'] = array(
+    'label' => t('Publisher URL'),
+    'description' => t("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."),
+    'class' => 'DrupalLinkMetaTag',
+    'weight' => ++$weight,
+    'element' => array(),
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $defaults;
+
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.module b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.module
new file mode 100644
index 0000000000000000000000000000000000000000..3375f16e75ad624feb80d44ba20be9ea0c49cffc
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/metatag_google_plus.module
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag: Google+.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_google_plus_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_google_plus_theme() {
+  $info['metatag_google_plus'] = array(
+    'render element' => 'element',
+  );
+
+  return $info;
+}
+
+/**
+ * Theme callback for an Google+ meta tag.
+ *
+ * The format is:
+ * <meta itemprop="[itemprop]" content="[value]" />
+ */
+function theme_metatag_google_plus($variables) {
+  $element = &$variables['element'];
+
+  // The format is e.g. 'itemprop:name'. Remove 'itemprop:' and store the rest
+  // in '#itemprop'.
+  $element['#itemprop'] = substr($element['#name'], 9);
+  $args = array(
+    '#itemprop' => 'itemprop',
+    '#value' => 'content',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Implements hook_preprocess_html().
+ *
+ * Add itemtype when available.
+ *
+ * Note: The $schemaorg variable must be added to the html tag of the
+ *   html.tpl.php template after the $rdf_namespaces variable, see README.txt
+ *   for details.
+ */
+function metatag_google_plus_preprocess_html(&$variables) {
+  if (!isset($variables['schemaorg'])) {
+    $variables['schemaorg'] = '';
+  }
+
+  if (isset($variables['itemtype']) && !function_exists('zen_preprocess_html')) {
+    $variables['schemaorg'] .= " itemscope itemtype=\"http://schema.org/{$variables['itemtype']}\"";
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/tests/metatag_google_plus.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/tests/metatag_google_plus.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..0ba0a5ca221f3a0fe8961f5ccaf636e675ce41a7
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/tests/metatag_google_plus.tags.test
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * Tests that each of the Metatag GooglePlus tags work correctly.
+ */
+class MetatagGooglePlusTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: GooglePlus',
+      'description' => 'Test the Google Plus meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    // @todo Can't test the output of this tag, it depends upon changes to the
+    // html.tpl.php file.
+    // 'itemtype',
+    'itemprop:name',
+    'itemprop:description',
+    'itemprop:image',
+    'author',
+    'publisher',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_google_plus';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    // The itemprop meta tags don't have 'itemprop' in their attribute value,
+    // 'itemprop' is the name of the attribute itself.
+    return str_replace('itemprop_', '', $tag_name);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_name_attribute = 'itemprop';
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'author'.
+   */
+  public function author_test_output_xpath() {
+    return "//link[@rel='author']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'author'.
+   */
+  public function author_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_key() for 'itemtype'.
+   */
+  public function itemtype_test_key() {
+    return 'metatags[und][itemtype][value]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'itemtype'.
+   */
+  public function itemtype_test_value() {
+    return 'Article';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'itemprop_image'.
+   */
+  public function itemprop_image_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'itemtype'.
+   */
+  public function itemtype_test_field_xpath() {
+    return "//select[@name='metatags[und][itemtype][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'itemtype'.
+   */
+  public function itemtype_test_output_xpath() {
+    return "//html[@rel='itemtype']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'publisher'.
+   */
+  public function publisher_test_output_xpath() {
+    return "//link[@rel='publisher']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'publisher'.
+   */
+  public function publisher_test_value_attribute() {
+    return 'href';
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/tests/metatag_google_plus.test b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/tests/metatag_google_plus.test
new file mode 100644
index 0000000000000000000000000000000000000000..1394bb0d2750861fe53701ef6e5921666a23ec0f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_google_plus/tests/metatag_google_plus.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag GooglePlus module.
+ */
+class MetatagGooglePlusTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag GooglePlus tests',
+      'description' => 'Test the Metatag:GooglePlus module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_google_plus';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..89855028b4935ca1f24873cdf0e23255e60619e0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/README.txt
@@ -0,0 +1,39 @@
+Metatag: hreflang
+-----------------
+This module automatically adds hreflang meta tags for each locale currently
+enabled on the site. It also provides support for the hreflang=x-default meta
+tag.
+
+This is similar to the Alternative hreflang [1] module. That module
+automatically adds the hreflang tag to every page for every enabled locale,
+which may not be what a site needs. This module allows the site builder control
+over what tags are shown.
+
+The module also provides new tokens to output the URLs of each of the current
+node's translations, and assigns these as the defaults for the meta tags. As
+such, this module may not need additional configuration once it is enabled, but
+it's always worth confirming the output is as expected.
+
+This module works best when the Translation or Entity Translation modules are
+enabled and configured.
+
+
+Configuration
+--------------------------------------------------------------------------------
+ 1. By default if the hreflang="x-default" meta tag matches one of the
+    hreflang="LANGCODE" meta tags that hreflang="LANGCODE" meta tag will be
+    removed. It is possible to change this so that the meta tag is not removed
+    by enabling the "Allow hreflang tag that matches the x-default tag" option
+    on the main Metatag settings page:
+      admin/config/search/metatags/settings
+
+
+Credits / Contact
+--------------------------------------------------------------------------------
+Originally developed by Damien McKenna [2].
+
+
+References
+--------------------------------------------------------------------------------
+1: https://www.drupal.org/project/hreflang
+2: https://www.drupal.org/u/damienmckenna.
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.info b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.info
new file mode 100644
index 0000000000000000000000000000000000000000..5eb15ba0498f8675364c797a2b917ff174a2fa25
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.info
@@ -0,0 +1,25 @@
+name = Metatag: hreflang
+description = Provides support for the hreflang meta tag with some extra logic to simplify it.
+package = SEO
+core = 7.x
+
+dependencies[] = metatag:metatag
+
+; The locale module is required in order to have multiple languages/locales.
+dependencies[] = drupal:locale
+
+; Tests.
+files[] = tests/metatag_hreflang.test
+files[] = tests/metatag_hreflang.tags.test
+
+; Entity Translation integration.
+test_dependencies[] = devel:devel
+test_dependencies[] = entity_translation:entity_translation
+files[] = tests/metatag_hreflang.with_entity_translation.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.install b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.install
new file mode 100644
index 0000000000000000000000000000000000000000..0a25f3a7276e6a005260c1b5f3446990bfa5da9b
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.install
@@ -0,0 +1,70 @@
+<?php
+/**
+ * @file
+ * Various update scripts for Metatag:hrelang.
+ */
+
+/**
+ * Implements hook_requirements().
+ */
+function metatag_hreflang_requirements($phase) {
+  $requirements = array();
+  // Ensure translations don't break during installation.
+  $t = get_t();
+
+  if ($phase == 'runtime') {
+    // Check if the Alternative Hreflang module is present.
+    if (module_exists('hreflang')) {
+      $requirements['metatag_hreflang'] = array(
+        'severity' => REQUIREMENT_ERROR,
+        'title' => 'Metatag',
+        'value' => $t('The Metatag:hreflang module should not be used at the same time as the hreflang module.'),
+        'description' => $t('If both the Metatag:hreflang module and the Alternative Hreflang (hreflang) module are used at the same time it is likely that they will output duplicate meta tags. As a result, it is recommended to only use one at a time.'),
+      );
+    }
+  }
+
+  return $requirements;
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function metatag_hreflang_uninstall() {
+  // Delete any custom variables that are used.
+  variable_del('metatag_hreflang_allow_dupe');
+}
+
+/**
+ * Implementations of hook_update_N().
+ */
+
+/**
+ * Clear the Metatag cache so the updated hreflang default is caught.
+ */
+function metatag_hreflang_update_7101() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
+
+/**
+ * Fix hreflang=xdefault for config definitions.
+ */
+function metatag_hreflang_update_7102() {
+  module_load_include('install', 'metatag');
+  $meta_tag = 'hreflang_xdefault';
+  $old_value = '[node:source:url]';
+  $new_value = '[node:url-original]';
+  return metatag_update_replace_config_value($meta_tag, $old_value, $new_value);
+}
+
+/**
+ * Fix hreflang=xdefault for all entities.
+ */
+function metatag_hreflang_update_7103() {
+  module_load_include('install', 'metatag');
+  $meta_tag = 'hreflang_xdefault';
+  $old_value = '[node:source:url]';
+  $new_value = '[node:url-original]';
+  return metatag_update_replace_entity_value($sandbox, $meta_tag, $old_value, $new_value);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..7def3be86cea9cc5eb067c8f8d66a18ff6b8e233
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.metatag.inc
@@ -0,0 +1,96 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag:hreflang module.
+ */
+
+/**
+ * Implements hook_metatag_bundled_config_alter().
+ *
+ * This provides recommended defaults that should be sufficient for most sites.
+ */
+function metatag_hreflang_metatag_bundled_config_alter(array &$configs) {
+  // This only makes sense if either the Translation or Entity Translation
+  // modules are enabled.
+  if (!(module_exists('translation') || module_exists('entity_translation'))) {
+    return;
+  }
+
+  foreach ($configs as &$config) {
+    switch ($config->instance) {
+      case 'node':
+        // The x-default should default to the source language.
+        $config->config += array(
+          'hreflang_xdefault' => array('value' => '[node:url-original]'),
+        );
+
+        // Add all of the other hreflang values.
+        $languages = language_list('enabled');
+        if (!empty($languages[1])) {
+          foreach (array_keys($languages[1]) as $langcode) {
+            $config->config += array(
+              'hreflang_' . $langcode => array('value' => '[node:url-' . $langcode . ']'),
+            );
+          }
+        }
+        break;
+    }
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_hreflang_metatag_info() {
+  $info['groups']['hreflang'] = array(
+    'label' => t('Alternative language links (hreflang)'),
+    'description' => t('These meta tags are designed to point visitors to versions of the current page in other languages. It is recommended to use the default "[node:url-LANGCODE]" tokens for the hreflang values, they will only be output if a translation exists for that locale. Also, it is suggested to use the "[node:source:url]" token for the default locale.'),
+    'form' => array(
+      '#weight' => 60,
+    ),
+  );
+
+  $weight = 100;
+
+  // Default values for each meta tag.
+  $tag_info_defaults = array(
+    'description' => '',
+    'class' => 'DrupalLinkMetaTag',
+    'group' => 'hreflang',
+  );
+
+  $info['tags']['hreflang_xdefault'] = array(
+    'label' => t('Default locale (x-default)'),
+    'description' => t('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.'),
+    'weight' => $weight,
+    'element' => array(
+      '#theme' => 'metatag_link_hreflang',
+      '#hreflang' => 'x-default',
+    ),
+  ) + $tag_info_defaults;
+  if (variable_get('metatag_hreflang_allow_dupe', FALSE)) {
+    $info['tags']['hreflang_xdefault']['description'] .= ' ' . t('If this string matches one of the values below the other value will not be removed.');
+  }
+  else {
+    $info['tags']['hreflang_xdefault']['description'] .= ' ' . t('If this string matches one of the values below that other tag will be removed, thus ensuring that there is only one hreflang meta tag for each possible variation of this page.');
+  }
+
+  // Add a meta tag for each locale enabled.
+  $languages = language_list('enabled');
+  if (!empty($languages[1])) {
+    foreach ($languages[1] as $langcode => $locale) {
+      // Getting granular with these so they're all grouped together.
+      $weight += 0.01;
+      $info['tags']['hreflang_' . $langcode] = array(
+        'label' => t('hreflang value for :language (:native)', array(':language' => t($locale->name), ':native' => $locale->native)),
+        'weight' => $weight,
+        'element' => array(
+          '#theme' => 'metatag_link_hreflang',
+          '#hreflang' => $langcode,
+        ),
+      ) + $tag_info_defaults;
+    }
+  }
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.module b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.module
new file mode 100644
index 0000000000000000000000000000000000000000..6465c4357363e5199ed935017f5b422e698bcd46
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.module
@@ -0,0 +1,86 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag:hreflang.
+ */
+
+// @todo Clear caches for all versions of an entity when a translation is edited
+// so that the hreflang meta tags update appropriately.
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_hreflang_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_hreflang_theme() {
+  $info['metatag_link_hreflang'] = array(
+    'render element' => 'element',
+  );
+  return $info;
+}
+
+/**
+ * Theme callback for a rel link tag with the hreflang.
+ *
+ * The format is:
+ * <link rel="[name]" hreflang="[langcode]" href="[value]" />
+ */
+function theme_metatag_link_hreflang($variables) {
+  $element = &$variables['element'];
+  $element['#name'] = 'alternate';
+  $args = array(
+    '#name' => 'rel',
+    '#hreflang' => 'hreflang',
+    '#value' => 'href',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter for metatag_admin_settings_form().
+ */
+function metatag_hreflang_form_metatag_admin_settings_form_alter(&$form, &$form_state, $form_id) {
+  $form['advanced']['metatag_hreflang_allow_dupe'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Allow hreflang tag that matches the x-default tag'),
+    '#description' => t('It is recommended to not have hreflang="x-default" and hreflang="SOMELANGCODE" meta tags pointing at the same URL. By default if there is a hreflang="SOMELANGCODE" meta tag with the same URL as the hreflang="x-default" meta tag then the hreflang="SOMELANGCODE" tag will be removed. Checking '),
+    '#default_value' => variable_get('metatag_hreflang_allow_dupe', FALSE),
+  );
+}
+
+/**
+ * Implements hook_metatag_metatags_view_alter().
+ *
+ * Remove any hreflang="LANGCODE" values that match hreflang="x-default". Using
+ * this hook instead of hook_html_head_alter() as it gets closer to Metatag's
+ * data structures, and the results are cached so this won't be executed on
+ * every page request.
+ */
+function metatag_hreflang_metatag_metatags_view_alter(&$output, $instance, $options) {
+  // This behaviour may be disabled from the Metatag settings page.
+  if (!variable_get('metatag_hreflang_allow_dupe', FALSE)) {
+    if (!empty($output['hreflang_xdefault'])) {
+      $default = $output['hreflang_xdefault']['#attached']['drupal_add_html_head'][0][0]['#value'];
+      foreach ($output as $tag_name => &$tag) {
+        // Skip the x-default tag.
+        if ($tag_name == 'hreflang_xdefault') {
+          continue;
+        }
+        if (strpos($tag_name, 'hreflang_') === 0) {
+          if ($tag['#attached']['drupal_add_html_head'][0][0]['#value'] == $default) {
+            $tag['#attached']['drupal_add_html_head'][0][0]['#access'] = FALSE;
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.test b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.test
new file mode 100644
index 0000000000000000000000000000000000000000..99dad0870e45d52212393db5c756d81d04f5cc1d
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.test
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @file
+ * Tests for the Metatag module to ensure the hreflang meta tags work correctly.
+ */
+
+class MetatagHreflangTest extends MetatagTestHelper {
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for hreflang',
+      'description' => 'Test Metatag integration with the locale module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need Locale for the multiple languages.
+    $modules[] = 'locale';
+
+    parent::setUp($modules);
+  }
+
+  // @todo Make sure the hreflang meta tag is added for each enabled language.
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.tokens.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.tokens.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a7a84e605f4549c9c33ae698242ebf57dc7fe901
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/metatag_hreflang.tokens.inc
@@ -0,0 +1,91 @@
+<?php
+/**
+ * @file
+ * Custom tokens for Metatag:hreflang.
+ */
+
+/**
+ * Implements hook_token_info().
+ */
+function metatag_hreflang_token_info() {
+  // This only makes sense if either the Translation or Entity Translation
+  // modules are enabled.
+  if (!(module_exists('translation') || module_exists('entity_translation'))) {
+    return;
+  }
+
+  // Don't do anything if the patch was applied to Entity Translation to add
+  // these.
+  // @see https://www.drupal.org/node/2603056
+  if (module_load_include('tokens.inc', 'entity_translation')) {
+    return;
+  }
+
+  $info = array();
+
+  $languages = language_list('enabled');
+
+  // Verify there are multiple languages enabled.
+  if (!empty($languages[1]) && is_array($languages[1]) && count($languages[1]) > 1) {
+    if (module_exists('node')) {
+      foreach ($languages[1] as $langcode => $language) {
+        $info['tokens']['node']['url-' . $langcode] = array(
+          'name' => t('URL (@lang translation)', array('@lang' => $language->name)),
+          'description' => t('The URL for the %lang translation of the node, if available.', array('%lang' => $language->name)),
+        );
+      }
+    }
+  }
+
+  $info['tokens']['node']['url-original'] = array(
+    'name' => t('URL (original language)'),
+    'description' => t("The URL for the node that is the original source for the current node's translation."),
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function metatag_hreflang_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $replacements = array();
+
+  $sanitize = !empty($options['sanitize']);
+
+  // Node tokens.
+  if ($type == 'node' && !empty($data['node'])) {
+    // Shortcuts.
+    $node = $data['node'];
+
+    // Only generate tokens if there are multiple translations.
+    if (isset($node->translations) && !empty($node->translations->data)) {
+      $languages = language_list('enabled');
+      if (!empty($languages[1]) && is_array($languages[1]) && count($languages[1]) > 1) {
+        foreach ($tokens as $name => $original) {
+          // The original entity's URL.
+          if ($name == 'url-original') {
+            if (isset($node->translations->original, $languages[1][$node->translations->original])) {
+              $url_options = $options;
+              $url_options['language'] = $languages[1][$node->translations->original];
+              $url_options['absolute'] = TRUE;
+              $replacements[$original] = url('node/' . $node->nid, $url_options);
+            }
+          }
+
+          // Separate URLs for each translation.
+          foreach ($node->translations->data as $langcode => $translation) {
+            if ($name == 'url-' . $langcode) {
+              $url_options = $options;
+              $url_options['language'] = $languages[1][$langcode];
+              $url_options['absolute'] = TRUE;
+              $replacements[$original] = url('node/' . $node->nid, $url_options);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return $replacements;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..ced718686e49d452730c4c07db6b3c2e21c0bba9
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.tags.test
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Hreflang tags work correctly.
+ */
+class MetatagHreflangTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Hreflang',
+      'description' => 'Test the Hreflang meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'hreflang_xdefault',
+    // Additional meta tags added at the end of setUp().
+    // @see setUp()
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_hreflang';
+    parent::setUp($modules);
+
+    // Create an admin user that can also manage locales.
+    $perms = array(
+      // For Locale, so languages can be added.
+      'administer languages',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Add some new languages.
+    foreach ($this->supportedLocales() as $langcode) {
+      if ($langcode != 'en') {
+        $this->addSiteLanguage($langcode);
+      }
+    }
+
+    // Clear all the caches so that all of the various hooks are activated and
+    // the appropriate tokens, fields, meta tags, etc are available.
+    drupal_flush_all_caches();
+
+    // Additional meta tags that will be available.
+    foreach ($this->supportedLocales() as $langcode) {
+      $this->tags[] = 'hreflang_' . $langcode;
+    }
+  }
+
+  /**
+   * The list of locales that are being tested.
+   *
+   * @return array
+   *   A simple list of language codes.
+   */
+  private function supportedLocales() {
+    return array(
+      'de',
+      'fr',
+      'es',
+      // English is automatic, so remember to not try enabling it.
+      'en',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_tag = 'link';
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_name_attribute = 'hreflang';
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_value_attribute = 'href';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagValue() {
+    return base_path() . $this->randomMachineName() . '/' . $this->randomMachineName();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    $tag_name = str_replace('xdefault', 'x-default', $tag_name);
+    return str_replace('hreflang_', '', $tag_name);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.test b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.test
new file mode 100644
index 0000000000000000000000000000000000000000..baf7b42cced092deef3b6c5244c610e685fc1f37
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag HrefLang module.
+ */
+class MetatagHreflangTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Hreflang tests',
+      'description' => 'Test the Metatag:Hreflang module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_hreflang';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.with_entity_translation.test b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.with_entity_translation.test
new file mode 100644
index 0000000000000000000000000000000000000000..735256dd447ff0fbabcf208baf04da7635a6ba73
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_hreflang/tests/metatag_hreflang.with_entity_translation.test
@@ -0,0 +1,278 @@
+<?php
+
+/**
+ * Tests for hreflang handle when Entity Translation is used.
+ */
+class MetatagHreflangWithEntityTranslationTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tests for hreflang with Entity Translation',
+      'description' => 'Test Metatag:hreflang with the Entity Translation module.',
+      'group' => 'Metatag',
+      'dependencies' => array('devel', 'entity_translation'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Used for debugging some token values.
+    $modules[] = 'devel';
+
+    // Need Locale for the multiple languages.
+    $modules[] = 'locale';
+
+    // Need Entity Translation for the tokens to work.
+    $modules[] = 'entity_translation';
+
+    // This module.
+    $modules[] = 'metatag_hreflang';
+
+    // Enable all of the modules & install the site.
+    parent::setUp($modules);
+
+    // Add some new languages.
+    $this->setupLocales($this->supportedLocales());
+
+    // The content that will be used.
+    $content_type = 'page';
+
+    // Create an admin user that can also manage locales.
+    $perms = array(
+      // For Locale, so languages can be added.
+      'administer languages',
+
+      // For Entity Translation, so content can be translated.
+      'translate any entity',
+
+      // For Devel, for access to the node's "devel" tab.
+      'access devel information',
+
+      // For Field UI, so field settings can be changed.
+      'administer fields',
+
+      // For Node, so content type settings can be changed.
+      'administer content types',
+
+      // For Node, so content can be created and edited.
+      'create ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Enable translation support for the content type.
+    variable_set('language_content_type_' . $content_type, ENTITY_TRANSLATION_ENABLED);
+
+    // Allow the body field to be translated.
+    $this->drupalGet('admin/structure/types/manage/' . $content_type . '/fields/body');
+    $this->assertResponse(200);
+    $this->assertFieldByName('field[translatable]');
+    $edit = array(
+      'field[translatable]' => TRUE,
+    );
+    $this->drupalPost(NULL, $edit, t('Save settings'));
+
+    // Clear all the caches so that all of the various hooks are activated and
+    // the appropriate tokens, fields, meta tags, etc are available.
+    drupal_flush_all_caches();
+  }
+
+  /**
+   * The list of locales that are being tested.
+   *
+   * @return array
+   *   A simple list of language codes.
+   */
+  private function supportedLocales() {
+    return array(
+      'de',
+      'fr',
+      'es',
+      'en',
+    );
+  }
+
+  /**
+   * Assert that the appropriate hreflang meta tag fields are present.
+   *
+   * @param string $form_langcode
+   *   The langcode of the current form. Defaults to LANGUAGE_NONE, which is
+   *   what is used on an empty node/add form.
+   */
+  private function assertHreflangFields($form_langcode = LANGUAGE_NONE) {
+    // The x-default field has a specific default.
+    $this->assertFieldByName("metatags[{$form_langcode}][hreflang_xdefault][value]", "[node:url-original]", 'Found the hreflang=x-default meta tag and it has the correct default value.');
+
+    // Confirm each of the support locales has its own field and the appropriate
+    // default value.
+    foreach ($this->supportedLocales() as $langcode) {
+      $this->assertFieldByName("metatags[{$form_langcode}][hreflang_{$langcode}][value]", "[node:url-{$langcode}]", format_string('Found the hreflang field for the "%lang" locale and it has the correct default value.', array('%lang' => $langcode)));
+    }
+  }
+
+  /**
+   * Confirm that each locale has a field added and shows the appropriate
+   * default value.
+   */
+  function testFormFields() {
+    $this->drupalGet('node/add/page');
+    $this->assertResponse(200);
+
+    // Confirm the fields exist.
+    $this->assertHreflangFields();
+  }
+
+  /**
+   * Confirm that the meta tags output are correct.
+   */
+  function testOutput() {
+    // All of the locales we're supporting in these tests. The languages have
+    // been enabled already, so this gets a list of language objects.
+    $languages = language_list('enabled');
+    $locales = $languages[1];
+
+    // Identify the site's default language.
+    $default_language = language_default('language');
+
+    // Create an English node so it can be translated.
+    $args = array(
+      'language' => $default_language,
+    );
+    $node = $this->drupalCreateNode($args);
+    $this->verbose($node);
+
+    // Load the translation page.
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->assertResponse(200);
+    $this->assertText(t('Not translated'));
+
+    // Confirm that there are links to translate the node.
+    $urls = array();
+    foreach ($locales as $langcode => $locale) {
+      // There won't be a link to translate to English, that's the default
+      // language for thos node.
+      if ($langcode == $default_language) {
+        continue;
+      }
+
+      // Confirm that a link to translate the node into each locale exists.
+      $url = 'node/' . $node->nid . '/edit/add/' . $node->language . '/' . $langcode;
+      $urls[$langcode] = $url;
+      // @todo This fails in testbot.
+      // $this->assertLinkbyHref(url($url));
+    }
+
+    // Check each of the 'translate' pages loads properly.
+    foreach ($urls as $langcode => $url) {
+      // Confirm the 'translate' page loads.
+      $this->drupalGet($url);
+      $this->assertResponse(200);
+
+      // Confirm all of the hreflang fields exist.
+      $this->assertHreflangFields($langcode);
+
+      // Save the translation.
+      $edit = array(
+        // Add a custom title.
+        "metatags[{$langcode}][title][value]" => "Tranlation for {$langcode}",
+      );
+      $this->drupalPost(NULL, $edit, t('Save'));
+    }
+
+    // Load the translation page again to confirm everything was translated.
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->assertResponse(200);
+    $this->assertNoText(t('Not translated'));
+
+    // Load the node's devel page to see the translations data.
+    $this->drupalGet('node/' . $node->nid . '/devel');
+    $this->assertResponse(200);
+
+    // Load the node's devel page and confirm each of the tokens is available.
+    $this->drupalGet('node/' . $node->nid . '/devel/token');
+    $this->assertResponse(200);
+    foreach ($locales as $langcode => $locale) {
+      $this->assertText("[node:url-{$langcode}]");
+    }
+
+    // Load the node page again, confirm each hreflang meta tag.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+    $xpath = $this->xpath("//link[@rel='alternate']");
+    $this->verbose($xpath);
+    $this->assertEqual(count($xpath), count($locales), 'The correct number of hreflang meta tags was found');
+
+    // Try to find the position of the xdefault value in the $xpath structure.
+    $xdefault_pos = NULL;
+    // This is slightly messy logic as the sort order of $locales may be
+    // different to the meta tags.
+    foreach ($locales as $langcode => $locale) {
+      $found = FALSE;
+      foreach ($xpath as $ctr => $item) {
+        if ($item['hreflang'] == 'x-default') {
+          $xdefault_pos = $ctr;
+        }
+        elseif ($item['hreflang'] == $langcode) {
+          $found = TRUE;
+          $this->assertEqual($xpath[$ctr]['hreflang'], $langcode);
+          // @todo Fix this. Not sure why, but the url() call returns the URL
+          // without the language prefix.
+          // $url_options = array(
+          //   'language' => $locale,
+          //   'absolute' => TRUE,
+          // );
+          // $this->assertEqual($xpath[$ctr]['href'], url('node/' . $node->nid, $url_options));
+        }
+      }
+
+      // The node's default language should not have been found, it should have
+      // been turned into an xdefault.
+      if ($langcode == $node->language) {
+        $this->assertFalse((bool)$found, format_string("A regular hreflang meta tag for the node's default language (%lang) was not found.", array('%lang' => $langcode)));
+      }
+
+      // Translations should have been found.
+      else {
+        $this->assertTrue((bool)$found, format_string('The hreflang meta tag for %lang was found.', array('%lang' => $langcode)));
+      }
+    }
+
+    // Confirm the hreflang=xdefault meta tag was found.
+    $this->assertNotNull($xdefault_pos, 'The hreflang=xdefault meta tag was found.');
+    if (!is_null($xdefault_pos)) {
+      $this->assertEqual($xpath[$xdefault_pos]['href'], url('node/' . $node->nid, array('absolute' => TRUE)), 'Found the x-default value.');
+    }
+
+    // Enable the xdefault-dupe option.
+    variable_set('metatag_hreflang_allow_dupe', TRUE);
+    metatag_config_cache_clear();
+
+    // Load the node page again.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Confirm there are now more meta tags.
+    $xpath = $this->xpath("//link[@rel='alternate']");
+    $this->verbose($xpath);
+    $this->assertEqual(count($xpath), count($locales) + 1, 'The correct number of hreflang meta tags was found.');
+    $found = FALSE;
+    foreach ($xpath as $ctr => $item) {
+      if ($item['hreflang'] == $node->language) {
+        $found = $ctr;
+      }
+    }
+    $this->assertTrue((bool)$found, "Found an hreflang meta tag for the node's default locale.");
+    if ($found) {
+      $this->assertEqual($xpath[$found]['hreflang'], $node->language);
+    }
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b8e6213a98a87979e60d84300cc0c88b08392257
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/README.txt
@@ -0,0 +1,35 @@
+Metatag: Importer
+-----------------
+This module imports data from other modules. An administrative interface is
+provided (admin/config/search/metatags/importer), as well as a series of Drush
+commands:
+* metatag-convert-page-title - Convert data from the Page Title module.
+
+
+Known Issues
+--------------------------------------------------------------------------------
+- The admin page (currently) only supports migrating data from Nodewords.
+- The Drush commands (currently) only supports migrating data from Page Title.
+- Only entities are currently supported, other configuration types will be
+  supported soon.
+
+
+Credits / Contact
+--------------------------------------------------------------------------------
+Currently maintained by Damien McKenna [1]. Originally developed by jantoine [2]
+with contributions by drupalninja99 [3], stuart.crouch [4], subhojit777 [5],
+KarlShea [6], stefan.r [7], HyperGlide [8] and jenlampton [9].
+
+
+
+References
+--------------------------------------------------------------------------------
+1: https://www.drupal.org/u/damienmckenna
+2: https://www.drupal.org/u/jantoine
+3: https://www.drupal.org/u/drupalninja99
+4: https://www.drupal.org/u/stuart.crouch
+5: https://www.drupal.org/u/subhojit777
+6: https://www.drupal.org/u/karlshea
+7: https://www.drupal.org/u/stefan.r
+8: https://www.drupal.org/u/hyperglide
+9: https://www.drupal.org/u/jenlampton
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.admin.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.admin.inc
new file mode 100644
index 0000000000000000000000000000000000000000..80a18124a9faaf26769444d3662d11a00599b0e2
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.admin.inc
@@ -0,0 +1,18 @@
+<?php
+/**
+ * @file
+ * Starter page.
+ */
+
+/**
+ * Page callback to display the initial help page.
+ */
+function metatag_importer_admin_page() {
+  $output = array(
+    '#type' => 'markup',
+    '#markup' => t('Use the links above to import data from another module.'),
+    '#prefix' => '<p>',
+    '#suffix' => '<p>',
+  );
+  return $output;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.drush.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.drush.inc
new file mode 100644
index 0000000000000000000000000000000000000000..af86d7711a534cdc798cfb1bd0bc61b2dd49af76
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.drush.inc
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @file
+ * Drush integration for the Metatag Importer module.
+ */
+
+/**
+ * Implements hook_drush_command().
+ */
+function metatag_importer_drush_command() {
+  // This needs to be fixed.
+  // $items['metatag-convert-nodewords'] = array(
+  //   'description' => dt('Convert data from Nodewords into Metatag.'),
+  //   'drupal dependencies' => array('metatag'),
+  // );
+
+  $items['metatag-convert-page-title'] = array(
+    'description' => dt('Convert data from Page Title into Metatag.'),
+    'drupal dependencies' => array('metatag'),
+  );
+  
+  return $items;
+}
+
+/**
+ * Callback to convert all Nodewords data.
+ */
+function drush_metatag_importer_metatag_convert_nodewords() {
+  if (!drush_confirm(dt('Ready to convert all data from Nodewords?'))) {
+    return;
+  }
+
+  // Need to make sure the Nodewords table actually exists.
+  if (!db_table_exists('nodewords')) {
+    drush_set_error('metatag_importer', dt('Could not find the nodewords table.'));
+    return;
+  }
+
+  // Offload all of the logic to the code contained in the admin file.
+  include('metatag_importer.nodewords.inc');
+
+  // Start the import.
+  // @todo This isn't working.
+  _metatag_importer_import();
+
+  drush_print(dt('Data converesion finished.'));
+}
+
+/**
+ * Callback to convert Page Title data.
+ */
+function drush_metatag_importer_metatag_convert_page_title() {
+  if (!db_table_exists('page_title')) {
+    drush_set_error('metatag_importer', dt('Could not find the page_title table!'));
+    return;
+  }
+
+  $records = db_query("SELECT COUNT(id) FROM {page_title} WHERE type IN ('node', 'taxonomy_term', 'user')")->fetchField();
+
+  if (empty($records)) {
+    return dt('There are no page_title records to convert!');
+  }
+
+  if (!drush_confirm(dt('Ready to convert !count record(s) from Page Title?', array('!count' => $records)))) {
+    return;
+  }
+
+  include('metatag_importer.page_title.inc');
+
+  // Start the importer.
+  $count = metatag_importer_for_page_title();
+
+  drush_print(dt('Converted !count record(s) from the Page Title module.', array('!count' => $count)));
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.info b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.info
new file mode 100644
index 0000000000000000000000000000000000000000..63a1fc5d23e7eb7413844d2bd1263d52cffa8213
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.info
@@ -0,0 +1,17 @@
+name = Metatag Importer
+description = Import data from other modules into Metatag.
+core = 7.x
+package = SEO
+
+; Need Metatag.
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_importer.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.module b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.module
new file mode 100644
index 0000000000000000000000000000000000000000..0ba21e0ba1b11f7f4cec51ad9816c289807a4462
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.module
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function metatag_importer_menu() {
+  $items['admin/config/search/metatags/importer'] = array(
+    'title' => 'Importer',
+    'description' => 'Migrate settings and data from various modules to the Metatag module.',
+    'page callback' => 'metatag_importer_admin_page',
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag_importer.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+  );
+
+  $items['admin/config/search/metatags/importer/nodewords'] = array(
+    'title' => 'Import from Nodewords',
+    'description' => 'Migrate settings and data from the Drupal 6 Nodewords module to the Drupal 7 Metatag module.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_importer_nodewords_form'),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag_importer.nodewords.inc',
+    'type' => MENU_LOCAL_ACTION,
+  );
+
+  $items['admin/config/search/metatags/importer/page-title'] = array(
+    'title' => 'Import from Page Title',
+    'description' => 'Migrate settings and data from the Drupal 6 Nodewords module to the Drupal 7 Metatag module.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('metatag_importer_page_title_form'),
+    'access arguments' => array('administer meta tags'),
+    'file' => 'metatag_importer.page_title.inc',
+    'type' => MENU_LOCAL_ACTION,
+  );
+
+  return $items;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.nodewords.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.nodewords.inc
new file mode 100644
index 0000000000000000000000000000000000000000..63b25d09d2cc427f4660054648ac392ffce355e7
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.nodewords.inc
@@ -0,0 +1,543 @@
+<?php
+
+/**
+ * @file
+ * Convert data from Nodewords to Metatag.
+ */
+
+// The Nodwords record types.
+define('NODEWORDS_TYPE_DEFAULT',    1);
+define('NODEWORDS_TYPE_ERRORPAGE',  2);
+define('NODEWORDS_TYPE_FRONTPAGE',  3);
+define('NODEWORDS_TYPE_NONE',       0);
+define('NODEWORDS_TYPE_NODE',       5);
+define('NODEWORDS_TYPE_PAGE',      10);
+define('NODEWORDS_TYPE_PAGER',      4);
+define('NODEWORDS_TYPE_TERM',       6);
+define('NODEWORDS_TYPE_TRACKER',    7);
+define('NODEWORDS_TYPE_USER',       8);
+define('NODEWORDS_TYPE_VOCABULARY', 9);
+
+/**
+ * Form generator for the migration selection form.
+ */
+function metatag_importer_nodewords_form($form, &$form_state) {
+  $types = array();
+  if (db_table_exists('nodewords')) {
+    $types += _metatag_importer_list_nodewords();
+  }
+
+  if (!empty($types)) {
+    $form['types'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Records to import'),
+      '#options' => $types,
+      '#disabled' => TRUE,
+    );
+
+    $form['notes'] = array(
+      '#markup' => '<p>' . t('Notes') . ':' . '</p>'
+        . '<ul>'
+        . '  <li>' . t('All compatible records will be imported.') . '</li>'
+        . '  <li>' . t('Records <strong>will be removed</strong> from the {nodewords} table upon completion, make sure to keep a backup of the table in case needed.') . '</li>'
+        . '  <li>' . t('The import process may take some time, please be patient.') . '</li>'
+        . '  <li>' . t('Nodewords stored each meta tag as a separate record, so there were many records for each entity or configuration.') . '</li>'
+        . '  <li>' . t('Empty values will be removed, no additional logic is added to verify them.') . '</li>'
+        . '  <li>' . t('Only node, taxonomy term, user, global, front page and error page records will be converted.') . '</li>'
+        . '  <li>' . t('Custom paths, trackers, pagers and vocabularies are not supported yet.') . '</li>'
+        . '</ul>',
+    );
+
+    $form['actions']['migrate'] = array(
+      '#type' => 'submit',
+      '#value' => t('Migrate all records'),
+    );
+  }
+  else {
+    $form['ohbother'] = array(
+      '#markup' => t('Nothing has been found that needs to be imported.'),
+      '#prefix' => '<p>',
+      '#suffix' => '</p>',
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Handles submission of the Nodewords migration form.
+ */
+function metatag_importer_nodewords_form_submit($form, &$form_state) {
+  $types = array_filter($form_state['values']['types']);
+  _metatag_importer_import($types);
+}
+
+function _metatag_importer_list_nodewords() {
+  $keys = array(
+    NODEWORDS_TYPE_DEFAULT => t('Default'),
+    NODEWORDS_TYPE_ERRORPAGE => t('Error page'),
+    NODEWORDS_TYPE_FRONTPAGE => t('Front page'),
+    NODEWORDS_TYPE_NONE => t('None'),
+    NODEWORDS_TYPE_NODE => t('Node'),
+    NODEWORDS_TYPE_PAGE => t('Page'),
+    NODEWORDS_TYPE_PAGER => t('Pager'),
+    NODEWORDS_TYPE_TERM => t('Taxonomy term'),
+    NODEWORDS_TYPE_TRACKER => t('Tracker'),
+    NODEWORDS_TYPE_USER => t('User'),
+    NODEWORDS_TYPE_VOCABULARY => t('Vocabulary'),
+  );
+
+  // Get a list of all records grouped by type.
+  $query = db_select('nodewords', 'nw')
+    ->fields('nw', array('type'))
+    ->orderBy('nw.type')
+    ->orderBy('nw.id')
+    // Exclude records that are empty.
+    ->condition('nw.content', 'a:1:{s:5:"value";s:0:"";}', '<>')
+    ->groupBy('nw.type');
+  // Group-by.
+  $query->addExpression('COUNT(nw.id)', 'id_count');
+  $filtered = $query->execute();
+
+  // Get a list of all records grouped by type.
+  $query = db_select('nodewords', 'nw')
+    ->fields('nw', array('type'))
+    ->orderBy('nw.type')
+    ->orderBy('nw.id')
+    ->groupBy('nw.type');
+  // Group-by.
+  $query->addExpression('COUNT(nw.id)', 'id_count');
+  $all = $query->execute()->fetchAllKeyed();
+
+  $types = array();
+  foreach ($filtered as $record) {
+    $types['nodewords:' . $record->type] = t('Nodewords: @type - @non_empty records with values, @total total.',
+      array(
+        '@type' => $keys[$record->type],
+        '@non_empty' => $record->id_count,
+        '@total' => $all[$record->type],
+      ));
+  }
+
+  return $types;
+}
+
+/**
+ * Migrates Nodewords data to the Metatag module.
+ */
+function _metatag_importer_import(array $types = array()) {
+  $batch = array(
+    'title' => t('Importing Nodewords data..'),
+    'operations' => array(
+      array('_metatag_importer_migrate', array($types)),
+    ),
+    'finished' => '_metatag_importer_finished',
+    'file' => drupal_get_path('module', 'metatag_importer') . '/metatag_importer.nodewords.inc',
+  );
+  batch_set($batch);
+
+  // Kick off the batch.
+  batch_process();
+}
+
+/**
+ * Migrates Nodewords data to the Metatag module.
+ */
+function _metatag_importer_migrate(array $types = array(), &$context = array()) {
+  // Process this number of {nodewords} records at a time.
+  $limit = 50;
+
+  if (empty($context['sandbox'])) {
+    // @todo Expand this so it can handle other types of things.
+    foreach ($types as $key => $val) {
+      $types[$key] = str_replace('nodewords:', '', $val);
+    }
+
+    $context['sandbox']['progress'] = 0;
+    $context['sandbox']['current'] = 0;
+    $query = db_select('nodewords', 'nw')
+      ->fields('nw', array('mtid'))
+      ->orderBy('nw.mtid');
+    if (!empty($types)) {
+      $query->condition('nw.type', $types, 'IN');
+    }
+    $context['sandbox']['dataset'] = array_keys($query->execute()->fetchAllAssoc('mtid', PDO::FETCH_ASSOC));
+    $context['sandbox']['max'] = count($context['sandbox']['dataset']);
+
+    // Track all of the entities that could not be loaded.
+    $context['sandbox']['skipped'] = array();
+  }
+
+  // Retrieve Nodewords data.
+  $query = db_select('nodewords', 'nw')
+    ->fields('nw', array('mtid', 'type', 'id', 'name', 'content'))
+    // Continue on from the last record that was processed.
+    ->condition('nw.mtid', $context['sandbox']['current'], '>')
+    ->orderBy('nw.mtid');
+  // @todo Finish off / test the $types handling.
+  // if (!empty($types)) {
+  //   $query->condition('nw.type', $types, 'IN');
+  // }
+  $query->range(0, $limit);
+  $results = $query->execute();
+
+  // Records that are being converted.
+  $records = array();
+
+  // Track records that are converted and will be ready to be deleted.
+  $to_delete = array();
+
+  // Convert Nodewords data into the Metatag format.
+  foreach ($results as $result) {
+    // Log the progress.
+    $context['sandbox']['current'] = $result->mtid;
+    $context['sandbox']['progress']++;
+
+    // Convert the Nodewords record 'type' into something Metatag can use.
+    $type = _metatag_importer_convert_type($result->type);
+
+    // Skip record types we're not handling just yet.
+    if (empty($type)) {
+      continue;
+    }
+
+    // This could be an entity ID, but also possibly just a placeholder integer.
+    $record_id = $result->id;
+
+    // Check if this record was skipped previously.
+    if (isset($context['sandbox']['skipped'][$type][$record_id])) {
+      // Delete this record anyway.
+      $to_delete[] = $result->mtid;
+      continue;
+    }
+
+    // If this record is for an entity, verify that the entity exists.
+    if (in_array($type, array('node', 'taxonomy_term', 'user'))) {
+      $entity = entity_load($type, array($record_id));
+      if (empty($entity)) {
+        $context['sandbox']['skipped'][$type][$record_id] = $record_id;
+        watchdog('metatag_importer', 'Unable to load @entity_type ID @id', array('@entity_type' => $type, '@id' => $record_id), WATCHDOG_WARNING);
+
+        // Delete this record anyway.
+        $to_delete[] = $result->mtid;
+        continue;
+      }
+    }
+
+    // Process the meta tag value, possibly also rename the meta tag name
+    // itself.
+    list($meta_tag, $value) = _metatag_importer_convert_data($result->name, unserialize($result->content));
+
+    // Don't import empty values.
+    if (!empty($value)) {
+      // Add the value to the stack.
+      $records[$type][$record_id][$meta_tag] = $value;
+    }
+
+    // Note that this record is ready to be deleted.
+    $to_delete[] = $result->mtid;
+  }
+
+  // Update or create Metatag records.
+  foreach ($records as $type => $data) {
+    foreach ($data as $record_id => $values) {
+      switch ($type) {
+        // Standard D7 entities are converted to {metatag} records using
+        // metatag_metatags_save().
+        case 'node':
+        case 'taxonomy_term':
+        case 'user':
+          // watchdog('metatag_importer', 'Importing meta tags for @entity_type ID @id..', array('@entity_type' => $type, '@id' => $record_id), WATCHDOG_INFO);
+          $entity = entity_load($type, array($record_id));
+          $entity = reset($entity);
+          $langcode = metatag_entity_get_language($type, $entity);
+          list($entity_id, $revision_id, $bundle) = entity_extract_ids($type, $entity);
+
+          // Add these meta tags to the entity, overwriting anything that's
+          // already there.
+          foreach ($values as $name => $value) {
+            $entity->metatags[$langcode][$name] = $value;
+          }
+
+          metatag_metatags_save($type, $entity_id, $revision_id, $entity->metatags);
+          // watchdog('metatag_importer', 'Imported meta tags for @entity_type ID @id.', array('@entity_type' => $type, '@id' => $record_id), WATCHDOG_INFO);
+          break;
+
+        // Other Nodewords settings are converted to {metatag_config} records
+        // using metatag_config_save().
+        case 'global':
+        case 'global:frontpage':
+        case 'global:404':
+          $config = metatag_config_load($type);
+
+          // If a configuration was not found create a config object.
+          if (empty($config)) {
+            $config = (object) array(
+              'instance' => $type,
+            );
+          }
+
+          // Add these meta tags to the configuration, overwriting anything
+          // that's already there.
+          foreach ($values as $name => $value) {
+            $config->config[$name] = $value;
+          }
+
+          // Save the configuration.
+          metatag_config_save($config);
+          break;
+
+        // // A 'vocabulary' setting becomes a default configuration.
+        // case 'vocabulary':
+        //   $metatags = metatag_metatags_load($record->entity_type, $record->entity_id);
+        //   $metatags = array_merge($metatags, $record->data);
+        //   $vocabulary = taxonomy_vocabulary_load($record->entity_id);
+        //   metatag_metatags_save($record->entity_type, $record->entity_id, $vocabulary->vid, $metatags);
+        //   break;
+      }
+    }
+  }
+
+  // Delete some records.
+  if (!empty($to_delete)) {
+    db_delete('nodewords')
+      ->condition('mtid', $to_delete)
+      ->execute();
+  }
+
+  $context['finished'] = (empty($context['sandbox']['max']) || $context['sandbox']['progress'] >= $context['sandbox']['max']) ? TRUE : ($context['sandbox']['progress'] / $context['sandbox']['max']);
+
+  if ($context['finished'] === TRUE) {
+    drupal_set_message(t('Imported @imported Nodewords records.', array('@imported' => $context['sandbox']['progress'])));
+    if (!empty($context['sandbox']['skipped'])) {
+      drupal_set_message(t('@skipped records were skipped because the corresponding entities were previously deleted.', array('@skipped' => count($context['sandbox']['skipped']))));
+    }
+  }
+}
+
+/**
+ * BatchAPI callback for when the import finishes.
+ */
+function _metatag_importer_finished($success, $results, $operations) {
+  if ($success) {
+    // Here we do something meaningful with the results.
+    $message = t("!count items were processed.", array(
+      '!count' => count($results),
+    ));
+    $message .= theme('item_list', array('items' => $results));
+    drupal_set_message($message);
+  }
+  else {
+    // An error occurred.
+    // $operations contains the operations that remained unprocessed.
+    $error_operation = reset($operations);
+    $message = t('An error occurred while processing %error_operation with arguments: @arguments', array(
+      '%error_operation' => $error_operation[0],
+      '@arguments' => print_r($error_operation[1], TRUE),
+    ));
+    drupal_set_message($message, 'error');
+  }
+}
+
+/**
+ * Converts the Nodewords type to a Metatag entity or Metatag config instance.
+ *
+ * @param $type
+ *   Nodewords type.
+ *
+ * @return
+ *   Metatag entity type or configuration instance.
+ */
+function _metatag_importer_convert_type($type) {
+  // define('NODEWORDS_TYPE_DEFAULT',    1);
+  // define('NODEWORDS_TYPE_ERRORPAGE',  2);
+  // define('NODEWORDS_TYPE_FRONTPAGE',  3);
+  // define('NODEWORDS_TYPE_NONE',       0);
+  // define('NODEWORDS_TYPE_NODE',       5);
+  // define('NODEWORDS_TYPE_PAGE',      10);
+  // define('NODEWORDS_TYPE_PAGER',      4);
+  // define('NODEWORDS_TYPE_TERM',       6);
+  // define('NODEWORDS_TYPE_TRACKER',    7);
+  // define('NODEWORDS_TYPE_USER',       8);
+  // define('NODEWORDS_TYPE_VOCABULARY', 9);
+  switch ($type) {
+    case 1:
+      return 'global';
+
+    case 2:
+      return 'global:404';
+
+    case 3:
+      return 'global:frontpage';
+
+    // @todo Not yet sure how to handle pager items?
+    // case 4:
+    //   return 'pager';
+
+    case 5:
+      return 'node';
+
+    case 6:
+      return 'taxonomy_term';
+
+    // @todo Not sure what to do with tracker pages.
+    // case 7:
+    //   return 'tracker';
+
+    case 8:
+      return 'user';
+
+    // @todo Vocabulary records need to be converted to a config for that entity
+    // bundle.
+    // case 9:
+    //   return 'vocabulary';
+
+    // @todo Page records need to be converted to Context definitions.
+    // case 10:
+    //   return 'page';
+  }
+
+  return FALSE;
+}
+
+/**
+ * Converts a meta tag's name and value from Nodewords to Metatag format.
+ *
+ * @param $name
+ *   Meta tag name.
+ * @param $value
+ *   Meta tag value in Nodewords format.
+ *
+ * @return
+ *   The two arguments returned after being converted, in an array.
+ */
+function _metatag_importer_convert_data($name, $value) {
+  // Initial simplification of simple values.
+  if (is_array($value) && isset($value['value']) && count($value) === 1 && empty($value['value'])) {
+    $value = FALSE;
+  }
+
+  // Reformat the meta tag data, and possibly name.
+  switch ($name) {
+    // The Dublin Core date value was stored as three separarate strings.
+    case 'dcterms.date':
+      // Skip this value if it doesn't contain an array of three values.
+      if (!is_array($value) || empty($value['month']) || empty($value['day']) || empty($value['year'])) {
+        $value = FALSE;
+      }
+      else {
+        $date = mktime(0, 0, 0, $value['month'], $value['day'], $value['year']);
+        $value = date('Y-m-d\TH:iP', $date);
+      }
+      break;
+
+    // The location meta tag gets renamed and converted to a semi-colon
+    // -separated string.
+    case 'location':
+      // Catch empty values.
+      if (!is_array($value) || empty($value['latitutde']) || empty($value['longitude'])) {
+        $value = FALSE;
+      }
+      else {
+        $name = 'geo.position';
+        $value = implode(';', $value);
+      }
+      break;
+
+    // These values always seem to be wrong, just use the Metatag defaults.
+    case 'og:type':
+      $value = FALSE;
+      break;
+
+    // Nodewords handle the title tag differently.
+    case 'page_title':
+      $name = 'title';
+      // Remove two options that are no longer used.
+      unset($value['append']);
+      unset($value['divider']);
+      break;
+
+    // A bug in Nodewords resulted in lots of junk data for this meta tag.
+    case 'revisit-after':
+      if (isset($value['value']) && intval($value['value']) === 1) {
+        $value = FALSE;
+      }
+
+    // Robots needs some extra processing.
+    case 'robots':
+      // The value didn't exist or it was set to use the defaults.
+      if (!is_array($value) || empty($value['value']) || !empty($value['use_default'])) {
+        $value = FALSE;
+      }
+      // Try parsing the data.
+      else {
+        $robot_data = array();
+
+        // Convert each value to display the name if it is "on" and 0 if it is
+        // off.
+        $found = FALSE;
+        foreach ($value['value'] as $robot_key => $robot_val) {
+          // Ignore junk values.
+          if ($robot_key == 'value') {
+            continue;
+          }
+
+          // Only keep non-empty values.
+          elseif (!empty($robot_val)) {
+            $robot_data[$robot_key] = $robot_key;
+            $found = TRUE;
+          }
+        }
+
+        // Catch empty values.
+        if (empty($robot_data)) {
+          $value = FALSE;
+        }
+
+        // Return any data that's remaining. The data must be stored in an
+        // array with a single item named 'value'.
+        else {
+          $value = array(
+            'value' => $robot_data,
+          );
+        }
+      }
+      break;
+
+    // This meta tag was renamed.
+    case 'shorturl':
+      $name = 'shortlink';
+      break;
+
+    // Everything else should be ok.
+    default:
+      // Nothing to see here.
+  }
+
+  // A final tidy-up.
+  if (is_array($value)) {
+    foreach ($value as $key => $val) {
+      $value[$key] = trim($val);
+    }
+    $value = array_filter($value);
+  }
+
+  return array($name, $value);
+}
+
+
+/**
+ * The following will not be converted because they refer to site-wide defaults
+ * that should be customized appropriately based on the D7 site's content type
+ * architecture.
+ */
+
+// 'nodewords_metatags_generation_method_' . $type:
+// 0 - NODEWORDS_GENERATION_NEVER - never auto-generate the string.
+// 1 - NODEWORDS_GENERATION_WHEN_EMPTY - when the field is empty. Default.
+// 2 - NODEWORDS_GENERATION_ALWAYS - always use the generated string.
+
+// 'nodewords_metatags_generation_method_' . $type:
+// 1 - NODEWORDS_GENERATION_BODY - use the body field.
+// 2 - NODEWORDS_GENERATION_TEASER - use the node teaser. Default.
+// 3 - NODEWORDS_GENERATION_TEASER_BODY - use teaser, failover to body if empty.
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.page_title.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.page_title.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5bc28425c51af4d1250fd7204b2bf3392768023b
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/metatag_importer.page_title.inc
@@ -0,0 +1,131 @@
+<?php
+/**
+ * @file
+ * Functionality for migrating data from the Page Title module.
+ */
+
+/**
+ * FormAPI callback for the Page Title importer.
+ */
+function metatag_importer_page_title_form($form, &$form_state) {
+  $form['help'] = array(
+    '#markup' => t('To migrate data from Page Title it is necessary to use Drush. See "drush metatag-convert-page-title" for details.'),
+    '#prefix' => '<p>',
+    '#suffix' => '</p>',
+  );
+  return $form;
+}
+
+/**
+ * Migrate data from the page_title table, if available.
+ *
+ * @return int
+ *   The number of records that were converted.
+ */
+function metatag_importer_for_page_title() {
+  $converted = 0;
+  $page_titles = db_select('page_title', 'pt')
+    ->fields('pt', array('type', 'id', 'page_title'))
+    ->execute();
+
+  // Get general metatag config settings.
+  $metatag_config_global = metatag_config_load('global');
+  $metatag_config_node = metatag_config_load('node');
+  $metatag_config_taxonomy_term = metatag_config_load('taxonomy_term');
+  $metatag_config_user = metatag_config_load('user');
+
+  // Track any records that are skipped.
+  $skipped = array();
+
+  // Loop over each of the page_title records.
+  while ($pt_data = $page_titles->fetchObject()) {
+    $entity_type = $pt_data->type;
+    $entity_id = $pt_data->id;
+
+    // Load the entity.
+    $entity = entity_load($entity_type, array($entity_id));
+    if (empty($entity)) {
+      $skipped[] = $entity_type . ':' . $entity_id;
+      continue;
+    }
+
+    $entity = reset($entity);
+
+    // Extract additional values from the entity.
+    $langcode = metatag_entity_get_language($entity_type, $entity);
+    list($entity_id, $revision_id) = entity_extract_ids($entity_type, $entity);
+
+    // Load any possible existing meta tags for this object.
+    $data = metatag_metatags_load($entity_type, $entity_id);
+
+    // Drop back one level because the results will be keyed by revision_id.
+    if (!empty($data)) {
+      $data = reset($data);
+    }
+
+    switch ($entity_type) {
+      case 'node':
+        $metatag_config_node_type = metatag_config_load('node:' . $entity->type);
+
+        if (!empty($metatag_config_node_type) && isset($metatag_config_node_type->config['title'])) {
+          $title_setting = $metatag_config_node_type->config['title']['value'];
+        }
+        elseif (isset($metatag_config_node->config['title'])) {
+          $title_setting = $metatag_config_node->config['title']['value'];
+        }
+        else {
+          $title_setting = $metatag_config_global->config['title']['value'];
+        }
+        $metatag_title = str_replace('[current-page:title]', trim($pt_data->page_title), $title_setting);
+        $metatag_title = str_replace('[node:title]', trim($pt_data->page_title), $metatag_title);
+        break;
+
+      case 'taxonomy_term':
+        $metatag_config_vocabulary_type = metatag_config_load('taxonomy_term:' . $entity->vocabulary_machine_name);
+
+        if (!empty($metatag_config_vocabulary_type) && isset($metatag_config_vocabulary_type->config['title'])) {
+          $title_setting = $metatag_config_vocabulary_type->config['title']['value'];
+        }
+        elseif (isset($metatag_config_taxonomy_term->config['title'])) {
+          $title_setting = $metatag_config_taxonomy_term->config['title']['value'];
+        }
+        else {
+          $title_setting = $metatag_config_global->config['title']['value'];
+        }
+        $metatag_title = str_replace('[current-page:title]', trim($pt_data->page_title), $title_setting);
+        $metatag_title = str_replace('[term:name]', trim($pt_data->page_title), $metatag_title);
+        break;
+
+      case 'user':
+        if (isset($metatag_config_user->config['title'])) {
+          $title_setting = $metatag_config_user->config['title']['value'];
+        }
+        else {
+          $title_setting = $metatag_config_global->config['title']['value'];
+        }
+        $metatag_title = str_replace('[current-page:title]', trim($pt_data->page_title), $title_setting);
+        $metatag_title = str_replace('[user:name]', trim($pt_data->page_title), $metatag_title);
+        break;
+
+      // Something else? Leave such records for another time.
+      default:
+        $skipped[] = $entity_type . ':' . $entity_id;
+        // Jump back to the outer for() loop.
+        continue 2;
+    }
+    $data[$langcode]['title']['value'] = $metatag_title;
+
+    metatag_metatags_save($entity_type, $entity_id, $revision_id, $data);
+    $converted += db_delete('page_title')
+      ->condition('type', $entity_type)
+      ->condition('id', $entity_id)
+        ->execute();
+  }
+
+  // Log any records that were skipped.
+  if (!empty($skipped)) {
+    watchdog('metatag_importer', "Failed to convert the following page_title records: :records", array(':records' => implode(', ', $skipped)));
+  }
+
+  return $converted;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_importer/tests/metatag_importer.test b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/tests/metatag_importer.test
new file mode 100644
index 0000000000000000000000000000000000000000..83d6f623316b6969c5f7c9a93ee4d1d832b67c94
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_importer/tests/metatag_importer.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag Importer module.
+ */
+class MetatagImporterTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Importer tests',
+      'description' => 'Test the Metatag:Importer module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_importer';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the importer admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags/importer');
+    $this->assertResponse(200);
+
+    // Confirm the page is loaded.
+    $this->assertText(t('Use the links above to import data from another module.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0127443616a07d2dae6929c23ee5b75cfc5abd3c
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/README.txt
@@ -0,0 +1,91 @@
+Metatag: Mobile
+---------------
+This submodule of Metatag adds a number of new meta tags commonly used for
+tailoring the experience of people using mobile devices.
+
+Mobile:
+  <meta name="theme-color" content="[VALUE]" />
+  <meta name="MobileOptimized" content="[VALUE]" />
+  <meta name="HandheldFriendly" content="[VALUE]" />
+  <meta name="viewport" content="[VALUE]" />
+  <meta http-equiv="cleartype" content="[VALUE]" />
+  <link rel="amphtml" href="[VALUE]" />
+
+iOS:
+  <meta name="apple-itunes-app" content="[VALUE]" />
+  <meta name="apple-mobile-web-app-capable" content="[VALUE]" />
+  <meta name="apple-mobile-web-app-status-bar-style" content="[VALUE]" />
+  <meta name="apple-mobile-web-app-title" content="[VALUE]" />
+  <meta name="format-detection" content="[VALUE]" />
+  <link rel="alternate" href="ios-app://[VALUE]" />
+
+Android:
+  <link rel="manifest" href="[VALUE]" />
+  <link rel="alternate" href="android-app://[VALUE]" />
+
+Windows:
+  <meta http-equiv="X-UA-Compatible" content="[VALUE]" />
+  <meta name="application-name" content="[VALUE]" />
+  <meta name="msapplication-allowDomainApiCalls" content="[VALUE]" />
+  <meta name="msapplication-allowDomainMetaTags" content="[VALUE]" />
+  <meta name="msapplication-badge" content="[VALUE]" />
+  <meta name="msapplication-config" content="[VALUE]" />
+  <meta name="msapplication-navbutton" content="[VALUE]" />
+  <meta name="msapplication-notification" content="[VALUE]" />
+  <meta name="msapplication-square150x150logo" content="[VALUE]" />
+  <meta name="msapplication-square310x310logo" content="[VALUE]" />
+  <meta name="msapplication-square70x70logo" content="[VALUE]" />
+  <meta name="msapplication-wide310x150logo" content="[VALUE]" />
+  <meta name="msapplication-starturl" content="[VALUE]" />
+  <meta name="msapplication-task" content="[VALUE]" />
+  <meta name="msapplication-task-separator" content="[VALUE]" />
+  <meta name="msapplication-tilecolor" content="[VALUE]" />
+  <meta name="msapplication-tileimage" content="[VALUE]" />
+  <meta name="msapplication-tooltip" content="[VALUE]" />
+  <meta name="msapplication-window" content="[VALUE]" />
+
+
+Configuration
+--------------------------------------------------------------------------------
+By default the two link alternate meta tags include a prefix - "android-app://" and "ios-app://". To remove this prefix just change the theme
+functions, e.g.:
+
+/**
+ * Implements theme_metatag_mobile_android_app().
+ *
+ * Remove the default prefix.
+ */
+function MYTHEME_metatag_mobile_android_app($variables) {
+  // Pass everything through to the normal 'link' tag theme.
+  $variables['element']['#name'] = 'alternate';
+
+  // Don't actually want this.
+  // $variables['element']['#value'] = 'android-app://' . $variables['element']['#value'];
+
+  return theme('metatag_link_rel', $variables);
+}
+
+/**
+ * Implements theme_metatag_mobile_ios_app().
+ *
+ * Remove the default prefix.
+ */
+function MYTHEME_metatag_mobile_ios_app($variables) {
+  // Pass everything through to the normal 'link' tag theme.
+  $variables['element']['#name'] = 'alternate';
+
+  // Don't actually want this.
+  // $variables['element']['#value'] = 'ios-app://' . $variables['element']['#value'];
+
+  return theme('metatag_link_rel', $variables);
+}
+
+
+Credits / Contact
+--------------------------------------------------------------------------------
+Originally developed by Damien McKenna [1].
+
+
+References
+--------------------------------------------------------------------------------
+1: https://www.drupal.org/u/damienmckenna.
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.info b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.info
new file mode 100644
index 0000000000000000000000000000000000000000..87029b66f84b92fae98731f09add3f3b0cab83f5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.info
@@ -0,0 +1,16 @@
+name = "Metatag: Mobile & UI Adjustments"
+description = "Provides support for meta tags used to control the mobile browser experience."
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_mobile.test
+files[] = tests/metatag_mobile.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..2d4f50e104461986b4524ab6b4ae697ce3988fb5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.metatag.inc
@@ -0,0 +1,309 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag:Facebook module.
+ */
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_mobile_metatag_info() {
+  $info['groups']['mobile'] = array(
+    'label' => t('Mobile & UI Adjustments'),
+    'description' => t('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.'),
+    'form' => array(
+      '#weight' => 80,
+    ),
+  );
+  $info['groups']['apple_mobile'] = array(
+    'label' => t('Apple & iOS'),
+    'description' => t("Custom meta tags used by Apple's software, iOS, Safari, etc."),
+    'form' => array(
+      '#weight' => 81,
+    ),
+  );
+  $info['groups']['android_mobile'] = array(
+    'label' => t('Android'),
+    'description' => t('Custom meta tags used by the Android OS, browser, etc.'),
+    'form' => array(
+      '#weight' => 82,
+    ),
+  );
+  $info['groups']['windows_mobile'] = array(
+    'label' => t('Windows & Windows Mobile'),
+    'description' => t('Custom meta tags used by the Windows and Windows Mobile OSes, IE browser, etc.'),
+    'form' => array(
+      '#weight' => 83,
+    ),
+  );
+
+  $weight = 80;
+
+  // Default values for each meta tag.
+  $defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'mobile',
+  );
+
+  $info['tags']['theme-color'] = array(
+    'label' => t('Theme Color'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['MobileOptimized'] = array(
+    'label' => t('Mobile Optimized'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'multiple' => TRUE,
+  ) + $defaults;
+
+  $info['tags']['HandheldFriendly'] = array(
+    'label' => t('Handheld-Friendly'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'multiple' => TRUE,
+  ) + $defaults;
+
+  $info['tags']['viewport'] = array(
+    'label' => t('Viewport'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['cleartype'] = array(
+    'label' => t('Cleartype'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_http_equiv',
+    ),
+  ) + $defaults;
+
+  $info['tags']['amphtml'] = array(
+    'label' => t('AMP URL'),
+    'description' => t('Provides an absolute URL to an AMP-formatted version of the current page. See the <a href="@url">official AMP specifications</a> for details on how the page should be formatted.', array('@url' => 'https://www.ampproject.org/')),
+    'class' => 'DrupalLinkMetaTag',
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['alternate_handheld'] = array(
+    'label' => t('Handheld URL'),
+    'description' => t('Provides an absolute URL to a specially formatted version of the current page designed for "feature phones", mobile phones that do not support modern browser standards. See the <a href="@url">official Google Mobile SEO Guide</a> for details on how the page should be formatted.', array('@url' => 'https://developers.google.com/webmasters/mobile-sites/mobile-seo/other-devices?hl=en#feature_phones')),
+    'class' => 'DrupalLinkMetaTag',
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_mobile_alt_handheld',
+      '#name' => 'alternate',
+      '#media' => 'handheld',
+    ),
+  ) + $defaults;
+
+  // Default values for each meta tag.
+  $defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'apple_mobile',
+  );
+
+  $info['tags']['apple-itunes-app'] = array(
+    'label' => t('iTunes App details'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['apple-mobile-web-app-capable'] = array(
+    'label' => t('Web app capable?'),
+    'description' => t('If set to "yes", the application will run in full-screen mode; the default behavior is to use Safari to display web content.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['apple-mobile-web-app-status-bar-style'] = array(
+    'label' => t('Status bar color'),
+    'description' => t('Requires the "Web app capable" meta tag to be set to "yes". May be set to "default", "black", or "black-translucent".'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['apple-mobile-web-app-title'] = array(
+    'label' => t('Apple Mobile Web App Title'),
+    'description' => t('Overrides the long site title when using the Apple Add to Home Screen.'),
+    'weight' => ++$weight
+  ) + $defaults;
+
+  $info['tags']['format-detection'] = array(
+    'label' => t('Format detection'),
+    'description' => t('If set to "telephone=no" the page will not be checked for phone numbers, which would be presented.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['ios-app-link-alternative'] = array(
+    'label' => t('iOS app link alternative'),
+    'description' => t('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.'),
+    'class' => 'DrupalLinkMetaTag',
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_mobile_ios_app',
+    ),
+    'header' => FALSE,
+  ) + $defaults;
+
+  // Default values for each meta tag.
+  $defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'android_mobile',
+  );
+
+  $info['tags']['android-app-link-alternative'] = array(
+    'label' => t('Android app link alternative'),
+    'description' => t('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.'),
+    'class' => 'DrupalLinkMetaTag',
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_mobile_android_app',
+    ),
+    'header' => FALSE,
+  ) + $defaults;
+
+  $info['tags']['android-manifest'] = array(
+    'label' => t('Manifest'),
+    'description' => t('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.'),
+    'class' => 'DrupalLinkMetaTag',
+    'weight' => ++$weight,
+    'element' => array(
+      '#name' => 'manifest',
+    ),
+  ) + $defaults;
+
+  // Default values for each meta tag.
+  $defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'windows_mobile',
+  );
+
+  $info['tags']['x-ua-compatible'] = array(
+    'label' => t('X-UA-Compatible'),
+    'description' => t('Indicates to IE which rendering engine should be used for the current page.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_http_equiv',
+    ),
+  ) + $defaults;
+
+  $info['tags']['application-name'] = array(
+    'label' => t('Application name'),
+    'description' => t('The default name displayed with the pinned sites tile (or icon). Set the content attribute to the desired name.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-allowDomainApiCalls'] = array(
+    'label' => t('MSApplication - Allow domain API calls'),
+    'description' => t('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".'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-allowDomainMetaTags'] = array(
+    'label' => t('MSApplication - Allow domain meta tags'),
+    'description' => t('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".'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-badge'] = array(
+    'label' => t('MSApplication - Badge'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-config'] = array(
+    'label' => t('MSApplication - Config'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-navbutton-color'] = array(
+    'label' => t('MSApplication - Nav button color'),
+    'description' => t('Controls the color of the Back and Forward buttons in the pinned site browser window.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-notification'] = array(
+    'label' => t('MSApplication - Notification'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-square150x150logo'] = array(
+    'label' => t('MSApplication - Square logo, 150px x 150px'),
+    'description' => t('The URL to a logo file that is 150px by 150px.'),
+    'image' => TRUE,
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-square310x310logo'] = array(
+    'label' => t('MSApplication - Square logo, 310px x 310px'),
+    'description' => t('The URL to a logo file that is 310px by 310px.'),
+    'image' => TRUE,
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-square70x70logo'] = array(
+    'label' => t('MSApplication - Square logo, 70px x 70px'),
+    'description' => t('The URL to a logo file that is 70px by 70px.'),
+    'image' => TRUE,
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-wide310x150logo'] = array(
+    'label' => t('MSApplication - Wide logo, 310px x 150px'),
+    'description' => t('The URL to a logo file that is 310px by 150px.'),
+    'image' => TRUE,
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-starturl'] = array(
+    'label' => t('MSApplication - Start URL'),
+    'description' => t('The URL to the root page of the site.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-task'] = array(
+    'label' => t('MSApplication - Task'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-task-separator'] = array(
+    'label' => t('MSApplication - Task separator'),
+    'description' => t(''),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-tilecolor'] = array(
+    'label' => t('MSApplication - Tile color'),
+    'description' => t('The HTML color to use as the background color for the live tile.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-tileimage'] = array(
+    'label' => t('MSApplication - Tile image'),
+    'description' => t('The URL to an image to use as the background for the live tile.'),
+    'image' => TRUE,
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-tooltip'] = array(
+    'label' => t('MSApplication - Tooltip'),
+    'description' => t('Controls the text shown in the tooltip for the pinned site\'s shortcut.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['msapplication-window'] = array(
+    'label' => t('MSApplication - Window'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.module b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.module
new file mode 100644
index 0000000000000000000000000000000000000000..6451b27af030512352c553ba0650b9828c5d2c87
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/metatag_mobile.module
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag:Mobile.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_mobile_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_mobile_theme() {
+  $info['metatag_mobile_android_app'] = array(
+    'render element' => 'element',
+  );
+  $info['metatag_mobile_ios_app'] = array(
+    'render element' => 'element',
+  );
+  $info['metatag_mobile_alt_handheld'] = array(
+    'render element' => 'element',
+  );
+
+  return $info;
+}
+
+/**
+ * Theme callback for an Android app link meta tag.
+ *
+ * The format is:
+ * <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'] = 'alternate';
+  $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'] = 'alternate';
+  $variables['element']['#value'] = 'ios-app://' . $variables['element']['#value'];
+
+  return theme('metatag_link_rel', $variables);
+}
+
+
+/**
+ * Theme callback for a handheld-formatted alternative URL.
+ *
+ * The format is:
+ * <link rel="alternate" media="handheld" href="https://phone.example.com/the/page" />
+ */
+function theme_metatag_mobile_alt_handheld($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name' => 'rel',
+    '#media' => 'media',
+    '#value' => 'href',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
+
+/*
+* theme-color
+* MobileOptimized
+* HandheldFriendly
+* viewport
+* cleartype
+* apple-mobile-web-app-capable
+* apple-mobile-web-app-status-bar-style
+* format-detection
+* android-app
+*/
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/tests/metatag_mobile.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/tests/metatag_mobile.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..40806883b01bbf939742c8560fe58caf9d1fa3f6
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/tests/metatag_mobile.tags.test
@@ -0,0 +1,220 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Mobile tags work correctly.
+ */
+class MetatagMobileTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Mobile',
+      'description' => 'Test the mobile meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'alternate_handheld',
+    'amphtml',
+    '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',
+    'x-ua-compatible',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_mobile';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public 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 {meta_tag_name}_test_output_xpath() for 'alternate-handheld'.
+   */
+  public function alternate_handheld_test_output_xpath() {
+    return "//link[@rel='alternate' and @media='handheld']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'alternate-handheld'.
+   */
+  public function alternate_handheld_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'amphtml'.
+   */
+  public function amphtml_test_output_xpath() {
+    return "//link[@rel='amphtml']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'amphtml'.
+   */
+  public function amphtml_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'android-app-link-alternative'.
+   */
+  public function android_app_link_alternative_test_output_xpath() {
+    return "//link[@rel='alternate' and starts-with(@href, 'android-app:')]";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_preprocess_output() for
+   * 'android-app-link-alternative'.
+   */
+  public function android_app_link_alternative_test_preprocess_output($string) {
+    return 'android-app://' . $string;
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for
+   * 'android-app-link-alternative'.
+   */
+  public function android_app_link_alternative_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'android_manifest'.
+   */
+  public function android_manifest_test_output_xpath() {
+    return "//link[@rel='manifest']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'android_manifest'.
+   */
+  public function android_manifest_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_name_attribute() for 'cleartype'.
+   */
+  public function cleartype_test_name_attribute() {
+    return 'http-equiv';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for
+   * 'ios_app_link_alternative'.
+   */
+  public function ios_app_link_alternative_test_output_xpath() {
+    return "//link[@rel='alternate' and starts-with(@href, 'ios-app:')]";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_prefix() for
+   * 'ios_app_link_alternative'.
+   */
+  public function ios_app_link_alternative_test_preprocess_output($string) {
+    return 'ios-app://' . $string;
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for
+   * 'ios_app_link_alternative'.
+   */
+  public function ios_app_link_alternative_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'msapplication-square150x150logo'.
+   */
+  public function msapplication_square150x150logo_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'msapplication-square310x310logo'.
+   */
+  public function msapplication_square310x310logo_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'msapplication-square70x70logo'.
+   */
+  public function msapplication_square70x70logo_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'msapplication-tileimage'.
+   */
+  public function msapplication_tileimage_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'msapplication-wide310x150logo'.
+   */
+  public function msapplication_wide310x150logo_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_name_attribute() for 'x-ua-compatible'.
+   */
+  public function x_ua_compatible_test_name_attribute() {
+    return 'http-equiv';
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/tests/metatag_mobile.test b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/tests/metatag_mobile.test
new file mode 100644
index 0000000000000000000000000000000000000000..ba18baad1040a38553cad9bc1e5d33d285bc5793
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_mobile/tests/metatag_mobile.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag Mobile module.
+ */
+class MetatagMobileTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Mobile tests',
+      'description' => 'Test the Metatag:Mobile module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_mobile';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.info b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.info
new file mode 100644
index 0000000000000000000000000000000000000000..579140553f5433105d332dfccdf9e941855b8c11
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.info
@@ -0,0 +1,16 @@
+name = Metatag: OpenGraph
+description = Provides support for Open Graph Protocol meta tags.
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_opengraph.test
+files[] = tests/metatag_opengraph.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.install b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.install
new file mode 100644
index 0000000000000000000000000000000000000000..abe78df0ba506eb07a4ff8ec850209122a9b81d9
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.install
@@ -0,0 +1,110 @@
+<?php
+/**
+ * @file
+ * Installation and update scripts for Metatag:OpenGraph.
+ */
+
+/**
+ * Implements hook_requirements().
+ */
+function metatag_opengraph_requirements($phase) {
+  $requirements = array();
+  // Ensure translations don't break during installation.
+  $t = get_t();
+
+  if ($phase == 'runtime') {
+    if (module_exists('rdf')) {
+      // Work out the release of D7 that is currently running.
+      list($major, $minor) = explode('.', VERSION);
+      // Strip off any suffixes on the version string, e.g. "17-dev".
+      if (strpos('-', $minor)) {
+        list($minor, $suffix) = explode('-', $minor);
+      }
+
+      if ($minor < 33) {
+        $requirements['metatag_og_rdf'] = array(
+          'severity' => REQUIREMENT_WARNING,
+          'title' => 'Metatag:OpenGraph',
+          'value' => $t('RDF problems with Drupal core releases before v7.33'),
+          'description' => $t('The core RDF module in Drupal before v7.33 caused validation problems for Open Graph meta tags. The solution is to update to v7.33 or newer.'),
+        );
+      }
+    }
+  }
+
+  return $requirements;
+}
+
+/**
+ * Implements hook_update_dependencies().
+ */
+function metatag_opengraph_update_dependencies() {
+  // OpenGraph update 7103 requires the complete Metatag schema, so lets wait
+  // for Metatag update 7100 just to be sure.
+  $dependencies['metatag_opengraph'][7103] = array(
+    'metatag' => 7100,
+  );
+  return $dependencies;
+}
+
+/**
+ * Implementations of hook_update_N().
+ */
+
+/**
+ * Enable the new Metatag:Facebook submodule.
+ */
+function metatag_opengraph_update_7100() {
+  module_enable(array('metatag_facebook'));
+  drupal_set_message(t('Enabled the new Metatag:Facebook submodule. If the Facebook meta tags are not being used then it is safe to disable.'));
+}
+
+/**
+ * Leave a warning about the two og:type value changes.
+ */
+function metatag_opengraph_update_7101() {
+  drupal_set_message(t('The "Movie" and "TV Show" values for the "Content type" open graph meta tag changed, if this site used those values they will need to be manually updated.'));
+}
+
+/**
+ * The Open Graph Products meta tags are now in a new submodule.
+ */
+function metatag_opengraph_update_7102() {
+  drupal_set_message(t('The Open Graph Products meta tags have been moved into the new "Metatag: Open Graph Products" submodule.'));
+}
+
+/**
+ * Change og:video to og:video:url in all metatags.
+ */
+function metatag_opengraph_update_7103(&$sandbox) {
+  module_load_include('install', 'metatag');
+  $old_tag = 'og:video';
+  $new_tag = 'og:video:url';
+  return metatag_update_replace_entity_tag($sandbox, $old_tag, $new_tag);
+}
+
+/**
+ * Rename the 'og:video' meta tag to 'og:video:url' in the configs.
+ */
+function metatag_opengraph_update_7104() {
+  module_load_include('install', 'metatag');
+  $old_tag = 'og:video';
+  $new_tag = 'og:video:url';
+  return metatag_update_replace_config_tag($old_tag, $new_tag);
+}
+
+/**
+ * Clear the Metatag cache to pick up changes to og:video.
+ */
+function metatag_opengraph_update_7105() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
+
+/**
+ * Clear the Metatag cache to pick up changes to og:audio:secure_url.
+ */
+function metatag_opengraph_update_7106() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..784b97ddcfd43fb7566eaaf2963d27d6f9bb5bae
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.metatag.inc
@@ -0,0 +1,630 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_opengraph module.
+ */
+
+/**
+ * Implements hook_metatag_bundled_config_alter().
+ */
+function metatag_opengraph_metatag_bundled_config_alter(array &$configs) {
+  foreach ($configs as &$config) {
+    switch ($config->instance) {
+      case 'global':
+        $config->config += array(
+          'og:site_name' => array('value' => '[site:name]'),
+          'og:title' => array('value' => '[current-page:title]'),
+          'og:type' => array('value' => 'article'),
+          'og:url' => array('value' => '[current-page:url:absolute]'),
+        );
+        break;
+
+      case 'global:frontpage':
+        $config->config += array(
+          'og:description' => array('value' => '[site:slogan]'),
+          'og:title' => array('value' => '[site:name]'),
+          'og:type' => array('value' => 'website'),
+          'og:url' => array('value' => '[site:url]'),
+        );
+        break;
+
+      // On error pages point everything to the homepage.
+      case 'global:403':
+      case 'global:404':
+        $config->config += array(
+          'og:title' => array('value' => '[site:name]'),
+          'og:type' => array('value' => 'website'),
+          'og:url' => array('value' => '[site:url]'),
+        );
+        break;
+
+      case 'node':
+        $config->config += array(
+          'article:modified_time' => array('value' => '[node:changed:custom:c]'),
+          'article:published_time' => array('value' => '[node:created:custom:c]'),
+          'og:description' => array('value' => '[node:summary]'),
+          'og:title' => array('value' => '[node:title]'),
+          'og:updated_time' => array('value' => '[node:changed:custom:c]'),
+        );
+        break;
+
+      case 'taxonomy_term':
+        $config->config += array(
+          'og:description' => array('value' => '[term:description]'),
+          'og:title' => array('value' => '[term:name]'),
+        );
+        break;
+
+      case 'user':
+        $config->config += array(
+          'og:title' => array('value' => '[user:name]'),
+          'og:type' => array('value' => 'profile'),
+          'profile:username' => array('value' => '[user:name]'),
+        );
+        if (variable_get('user_pictures')) {
+          $config->config += array(
+            'og:image' => array('value' => '[user:picture:url]'),
+            // For now keep the old default.
+            // 'og:image:url' => array('value' => '[user:picture:url]'),
+          );
+        }
+        break;
+    }
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_opengraph_metatag_info() {
+  $info['groups']['open-graph'] = array(
+    'label' => t('Open Graph'),
+    'description' => t("The <a href=\"@ogp\">Open Graph meta tags</a> are used control how Facebook, Pinterest, LinkedIn and other social networking sites interpret the site's content.", array('@ogp' => 'http://ogp.me/')),
+    'form' => array(
+      '#weight' => 50,
+    ),
+  );
+
+  // Default values for each meta tag.
+  $og_defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'open-graph',
+    'element' => array(
+      '#theme' => 'metatag_property',
+    ),
+  );
+
+  // Open Graph meta tags stack after the Facebook tags.
+  $weight = 25;
+
+  $info['tags']['og:site_name'] = array(
+    'label' => t('Site name'),
+    'description' => t('A human-readable name for the site, e.g., <em>IMDb</em>.'),
+    'context' => array('global'),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+
+  $info['tags']['og:type'] = array(
+    'label' => t('Content type'),
+    'description' => t('The type of the content, e.g., <em>movie</em>.'),
+    'weight' => ++$weight,
+    'select_or_other' => TRUE,
+    'form' => array(
+      '#type' => 'select',
+      '#options' => _metatag_opengraph_type_options(),
+      '#empty_option' => t('- None -'),
+    ),
+    'devel_generate' => array(
+      'type' => 'select',
+    ),
+  ) + $og_defaults;
+
+  $info['tags']['og:url'] = array(
+    'label' => t('Page URL'),
+    'description' => t('Preferred page location or URL to help eliminate duplicate content for search engines, e.g., <em>http://www.imdb.com/title/tt0117500/</em>.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'canonical',
+    ),
+  ) + $og_defaults;
+
+  $info['tags']['og:title'] = array(
+    'label' => t('Content title'),
+    'description' => t('The title of the content, e.g., <em>The Rock</em>.'),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+
+  $info['tags']['og:determiner'] = array(
+    'label' => t('Content title determiner'),
+    'description' => t("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."),
+    'weight' => ++$weight,
+    'form' => array(
+      '#type' => 'select',
+      '#options' => array(
+        'auto' => 'Automatic',
+        'a' => 'A',
+        'an' => 'An',
+        'the' => 'The',
+      ),
+      '#empty_option' => t('- Ignore -'),
+    ),
+    'devel_generate' => array(
+      'type' => 'select',
+    ),
+  ) + $og_defaults;
+
+  $info['tags']['og:description'] = array(
+    'label' => t('Content description'),
+    'description' => t('A one to two sentence description of the content.'),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+
+  // Basic tags.
+  $info['tags']['og:updated_time'] = array(
+    'label' => t('Content modification date & time'),
+    'description' => t("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."),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+
+  $info['tags']['og:see_also'] = array(
+    'label' => t('See also'),
+    'description' => t('URLs to related content.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults;
+
+  $info['tags']['og:image'] = array(
+    'label' => t('Image'),
+    'description' => t('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. 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 the first one.'),
+    'multiple' => TRUE,
+    'image' => TRUE,
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:image:url'] = array(
+    'label' => t('Image URL'),
+    'description' => t('A alternative version of og:image and has exactly the same requirements; only one needs to be used. Note: some services do not accept this tag and will only accept the "image" tag above.'),
+    'multiple' => TRUE,
+    'image' => TRUE,
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:image:secure_url'] = array(
+    'label' => t('Secure image URL'),
+    'description' => t('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://". Note: if multiple images are added many services (e.g. Facebook) will default to the largest image, not the first one.'),
+    'multiple' => TRUE,
+    'secure' => TRUE,
+    'image' => TRUE,
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:image:type'] = array(
+    'label' => t('Image type'),
+    'description' => t('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.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults;
+  $info['tags']['og:image:width'] = array(
+    'label' => t('Image width'),
+    'description' => t('The width of the above image(s). Note: if both the unsecured and secured images are provided, they should both be the same size.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:image:height'] = array(
+    'label' => t('Image height'),
+    'description' => t('The height of the above image(s). Note: if both the unsecured and secured images are provided, they should both be the same size.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  ) + $og_defaults;
+
+  $info['tags']['og:latitude'] = array(
+    'label' => t('Latitude'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'float',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:longitude'] = array(
+    'label' => t('Longitude'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'float',
+    ),
+  ) + $og_defaults;
+
+  $info['tags']['og:street_address'] = array(
+    'label' => t('Street address'),
+    'weight' => ++$weight,
+    'replaces' => array(
+      'og:street-address',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:locality'] = array(
+    'label' => t('Locality'),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+  $info['tags']['og:region'] = array(
+    'label' => t('Region'),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+  $info['tags']['og:postal_code'] = array(
+    'label' => t('Postal/ZIP code'),
+    'weight' => ++$weight,
+    'replaces' => array(
+      'og:postal-code',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:country_name'] = array(
+    'label' => t('Country name'),
+    'weight' => ++$weight,
+    'replaces' => array(
+      'og:country-name',
+    ),
+  ) + $og_defaults;
+
+  $info['tags']['og:email'] = array(
+    'label' => t('Email'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'email',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:phone_number'] = array(
+    'label' => t('Phone number'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'phone',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:fax_number'] = array(
+    'label' => t('Fax number'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'phone',
+    ),
+  ) + $og_defaults;
+
+  $info['tags']['og:locale'] = array(
+    'label' => t('Locale'),
+    'description' => 'The locale these tags are marked up in, must be in the format language_TERRITORY. Default is en_US.',
+    'weight' => ++$weight,
+    'is_language' => TRUE,
+    'devel_generate' => array(
+      'maxlength' => 1,
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:locale:alternate'] = array(
+    'label' => t('Alternative locales'),
+    'description' => 'Other locales this content is available in, must be in the format language_TERRITORY, e.g. "fr_FR".',
+    'weight' => ++$weight,
+    'multiple' => TRUE,
+    'is_language' => TRUE,
+    'devel_generate' => array(
+      'maxlength' => 1,
+    ),
+  ) + $og_defaults;
+
+  // For the "article" og:type.
+  $article_defaults = array(
+    'dependencies' => array(
+      array(
+        'dependency' => 'og:type',
+        'attribute' => 'value',
+        'condition' => 'value',
+        'value' => 'article',
+      ),
+    ),
+  );
+  $info['tags']['article:author'] = array(
+    'label' => t('Article author'),
+    'description' => t("Links an article to an author's Facebook profile, should be either URLs to the author's profile page or their Facebook profile IDs."),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $article_defaults;
+  $info['tags']['article:publisher'] = array(
+    'label' => t('Article publisher'),
+    'description' => t("Links an article to a publisher's Facebook page."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $article_defaults;
+  $info['tags']['article:section'] = array(
+    'label' => t('Article section'),
+    'description' => t('The primary section of this website the content belongs to.'),
+    'weight' => ++$weight,
+  ) + $og_defaults + $article_defaults;
+  $info['tags']['article:tag'] = array(
+    'label' => t('Article tag(s)'),
+    'description' => t('Appropriate keywords for this content.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $article_defaults;
+  $info['tags']['article:published_time'] = array(
+    'label' => t('Article publication date & time'),
+    'description' => t("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."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $article_defaults;
+  $info['tags']['article:modified_time'] = array(
+    'label' => t('Article modification date & time'),
+    'description' => t("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."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $article_defaults;
+  $info['tags']['article:expiration_time'] = array(
+    'label' => t('Article expiration date & time'),
+    'description' => t("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."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $article_defaults;
+
+  // For the "profile" og:type.
+  $profile_defaults = array(
+    'dependencies' => array(
+      array(
+        'dependency' => 'og:type',
+        'attribute' => 'value',
+        'condition' => 'value',
+        'value' => 'profile',
+      ),
+    ),
+  );
+  $info['tags']['profile:first_name'] = array(
+    'label' => t('First name'),
+    'description' => t("The first name of the person who's Profile page this is."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $profile_defaults;
+  $info['tags']['profile:last_name'] = array(
+    'label' => t('Last name'),
+    'description' => t("The person's last name."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $profile_defaults;
+  $info['tags']['profile:username'] = array(
+    'label' => t('Username'),
+    'description' => t("A pseudonym / alias of this person."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $profile_defaults;
+  $info['tags']['profile:gender'] = array(
+    'label' => t('Gender'),
+    'description' => t("Any of Facebook's gender values should be allowed, the initial two being 'male' and 'female'."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $profile_defaults;
+
+  // Tags related to audio.
+  $info['tags']['og:audio'] = array(
+    'label' => t('Audio URL'),
+    'description' => t('The URL to an audio file that complements this object.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:audio:secure_url'] = array(
+    'label' => t('Audio secure URL'),
+    'description' => t('The secure URL to an audio file that complements this object. All "http://" URLs will automatically be converted to "https://".'),
+    'secure' => TRUE,
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:audio:type'] = array(
+    'label' => t('Audio type'),
+    'description' => t('The MIME type of the audio file. Examples include "application/mp3" for an MP3 file.'),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+
+  // For the "book" og:type.
+  $book_defaults = array(
+    'dependencies' => array(
+      array(
+        'dependency' => 'og:type',
+        'attribute' => 'value',
+        'condition' => 'value',
+        'value' => 'book',
+      ),
+    ),
+  );
+  $info['tags']['book:author'] = array(
+    'label' => t("Book's author"),
+    'description' => t("Links to the book's author's Facebook profile, should be either URLs to the author's profile page or their Facebook profile IDs."),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $book_defaults;
+  $info['tags']['book:isbn'] = array(
+    'label' => t("Book's ISBN"),
+    'description' => t("The book's <a href=\"http://en.wikipedia.org/wiki/International_Standard_Book_Number\">International Standard Book Number</a>, which may be in one of several formats."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $book_defaults;
+  $info['tags']['book:release_date'] = array(
+    'label' => t('Book release date'),
+    'description' => t("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."),
+    'weight' => ++$weight,
+  ) + $og_defaults + $book_defaults;
+  $info['tags']['book:tag'] = array(
+    'label' => t('Book tags'),
+    'description' => t('Appropriate keywords for this book.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $book_defaults;
+
+  // For the "video" og:type.
+  $video_defaults = array();
+  //   'dependencies' => array(
+  //     array(
+  //       'dependency' => 'og:type',
+  //       'attribute' => 'value',
+  //       'condition' => 'value',
+  //       'value' => 'profile',
+  //     ),
+  //   ),
+  // );
+  $info['tags']['og:video:url'] = array(
+    'label' => t('Video URL'),
+    'description' => t('The URL to a video file that complements this object.'),
+    'weight' => ++$weight,
+    'replaces' => array(
+      'og:video',
+    ),
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:video:secure_url'] = array(
+    'label' => t('Video secure URL'),
+    'description' => t('A URL to a video file that complements this object using the HTTPS protocol. All "http://" URLs will automatically be converted to "https://".'),
+    'secure' => TRUE,
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:video:width'] = array(
+    'label' => t('Video width'),
+    'description' => t('The width of the video.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:video:height'] = array(
+    'label' => t('Video height'),
+    'description' => t('The height of the video.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $og_defaults;
+  $info['tags']['og:video:type'] = array(
+    'label' => t('Video type'),
+    'description' => t('The MIME type of the video file. Examples include "application/x-shockwave-flash" for a Flash video, or "text/html" if this is a standalone web page containing a video.'),
+    'weight' => ++$weight,
+  ) + $og_defaults;
+  $info['tags']['video:actor'] = array(
+    'label' => t('Actor(s)'),
+    'description' => t('Links to the Facebook profiles for actor(s) that appear in the video.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $video_defaults;
+  $info['tags']['video:actor:role'] = array(
+    'label' => t("Actors' role"),
+    'description' => t("The roles of the actor(s)."),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $video_defaults;
+  $info['tags']['video:director'] = array(
+    'label' => t('Director(s)'),
+    'description' => t('Links to the Facebook profiles for director(s) that worked on the video.'),
+    'weight' => ++$weight,
+  ) + $og_defaults + $video_defaults;
+  $info['tags']['video:writer'] = array(
+    'label' => t('Scriptwriter(s)'),
+    'description' => t('Links to the Facebook profiles for scriptwriter(s) for the video.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $video_defaults;
+  $info['tags']['video:duration'] = array(
+    'label' => t('Video duration (seconds)'),
+    'description' => t('The length of the video in seconds'),
+    'weight' => ++$weight,
+  ) + $og_defaults + $video_defaults;
+  $info['tags']['video:release_date'] = array(
+    'label' => t('Release date'),
+    'description' => t('The date the video was released.'),
+    'weight' => ++$weight,
+  ) + $og_defaults + $video_defaults;
+  $info['tags']['video:tag'] = array(
+    'label' => t('Tag'),
+    'description' => t('Tag words associated with this video.'),
+    'multiple' => TRUE,
+    'weight' => ++$weight,
+  ) + $og_defaults + $video_defaults;
+  $info['tags']['video:series'] = array(
+    'label' => t('Series'),
+    'description' => t('The TV show this series belongs to.'),
+    'weight' => ++$weight,
+    'dependencies' => array(
+      array(
+        'dependency' => 'og:type',
+        'attribute' => 'value',
+        'condition' => 'value',
+        'value' => 'video.episode',
+      ),
+    ),
+  ) + $og_defaults + $video_defaults;
+
+  return $info;
+}
+
+function _metatag_opengraph_type_options() {
+  $options = array(
+    t('Activities') => array(
+      'activity' => t('Activity'),
+      'sport' => t('Sport'),
+    ),
+    t('Businesses') => array(
+      'bar' => t('Bar', array('context' => 'an establishment')),
+      'company' => t('Company'),
+      'cafe' => t('Cafe'),
+      'hotel' => t('Hotel'),
+      'restaurant' => t('Restaurant'),
+    ),
+    t('Groups') => array(
+      'cause' => t('Cause'),
+      'sports_league' => t('Sports league'),
+      'sports_team' => t('Sports team'),
+    ),
+    t('Organizations') => array(
+      'band' => t('Band'),
+      'government' => t('Government'),
+      'non_profit' => t('Non-profit'),
+      'school' => t('School'),
+      'university' => t('University'),
+    ),
+    t('People') => array(
+      'actor' => t('Actor'),
+      'athlete' => t('Athlete'),
+      'author' => t('Author'),
+      'director' => t('Director'),
+      'musician' => t('Musician'),
+      'politician' => t('Politician'),
+      'profile' => t('Profile'),
+      'public_figure' => t('Public figure'),
+    ),
+    t('Places') => array(
+      'city' => t('City'),
+      'country' => t('Country'),
+      'landmark' => t('Landmark'),
+      'place' => t('Place'),
+      'state_province' => t('State or province'),
+    ),
+    t('Products and Entertainment') => array(
+      'album' => t('Album'),
+      'book' => t('Book'),
+      'drink' => t('Drink'),
+      'food' => t('Food'),
+      'game' => t('Game'),
+      'product' => t('Product'),
+      'product.group' => t('Product group'),
+      'song' => t('Song'),
+      'video.movie' => t('Movie'),
+      'video.tv_show' => t('TV show'),
+      'video.episode' => t('TV show episode'),
+      'video.other' => t('Miscellaneous video'),
+    ),
+    t('Websites') => array(
+      'website' => t('Website'),
+      'article' => t('Article (inc blog)'),
+    ),
+  );
+
+  return $options;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.module b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.module
new file mode 100644
index 0000000000000000000000000000000000000000..602e8f8245fedd5feea34cfaaaba3c1f90a7f1f6
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/metatag_opengraph.module
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Implements hook_preprocess_html().
+ */
+function metatag_opengraph_preprocess_html(&$variables) {
+  // Fall back to hook_rdf_namespaces if the rdf module is enabled.
+  if (module_exists('rdf')) {
+    return;
+  }
+
+  // @TODO Would it be worth dynamically identifying whether these should be
+  // added, or just output them all?
+
+  // Need an extra namespace for the 'og' tags.
+  $variables['rdf_namespaces'] .= "\n  xmlns:og=\"http://ogp.me/ns#\"";
+  // Need an extra namespace for the "article" tags.
+  $variables['rdf_namespaces'] .= "\n  xmlns:article=\"http://ogp.me/ns/article#\"";
+  // Need an extra namespace for the "book" tags.
+  $variables['rdf_namespaces'] .= "\n  xmlns:book=\"http://ogp.me/ns/book#\"";
+  // Need an extra namespace for the "profile" tags.
+  $variables['rdf_namespaces'] .= "\n  xmlns:profile=\"http://ogp.me/ns/profile#\"";
+  // Need an extra namespace for the "video" tags.
+  $variables['rdf_namespaces'] .= "\n  xmlns:video=\"http://ogp.me/ns/video#\"";
+  // And for product tags.
+  $variables['rdf_namespaces'] .= "\n  xmlns:product=\"http://ogp.me/ns/product#\"";
+}
+
+/**
+ * Implements hook_rdf_namespaces().
+ */
+function metatag_opengraph_rdf_namespaces() {
+  return array(
+    'og' => 'http://ogp.me/ns#',
+    'article' => 'http://ogp.me/ns/article#',
+    'book' => 'http://ogp.me/ns/book#',
+    'profile' => 'http://ogp.me/ns/profile#',
+    'video' => 'http://ogp.me/ns/video#',
+    'product' => 'http://ogp.me/ns/product#',
+  );
+}
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_opengraph_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/*
+og:title = [node:title] / [user:name]
+og:type = article / profile
+og:image = ? / [user:picture:url]
+og:url = [node:url] / [user:url]
+og:description
+og:site_name = [site:name]
+
+og:latitude
+og:longitude
+og:street-address
+og:locality
+og:region
+og:postal-code
+og:country-name
+
+og:email
+og:phone_number
+og:fax_number
+
+og:video:url
+og:video:secure_url
+og:video:height
+og:video:width
+og:video:type
+
+og:audio
+og:audio:title
+og:audio:artist
+og:audio:album
+og:audio:type
+
+og:upc
+og:isbn
+*/
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/tests/metatag_opengraph.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/tests/metatag_opengraph.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..4f30767e2130c16fd11f773a5f0e3c670ab890d2
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/tests/metatag_opengraph.tags.test
@@ -0,0 +1,178 @@
+<?php
+
+/**
+ * Tests that each of the Metatag OpenGraph tags work correctly.
+ */
+class MetatagOpenGraphTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: OpenGraph',
+      'description' => 'Test the OpenGraph meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'article:author',
+    'article:expiration_time',
+    'article:modified_time',
+    'article:published_time',
+    'article:publisher',
+    'article:section',
+    'article:tag',
+    'book:author',
+    'book:isbn',
+    'book:release_date',
+    'book:tag',
+    'og:audio',
+    'og:audio:secure_url',
+    'og:audio:type',
+    'og:country_name',
+    'og:description',
+    'og:determiner',
+    'og:email',
+    'og:fax_number',
+    'og:image',
+    'og:image:height',
+    'og:image:secure_url',
+    'og:image:type',
+    'og:image:url',
+    'og:image:width',
+    'og:latitude',
+    'og:locale',
+    'og:locale:alternate',
+    '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:height',
+    'og:video:secure_url',
+    'og:video:type',
+    'og:video:url',
+    'og:video:width',
+    'profile:first_name',
+    'profile:gender',
+    'profile:last_name',
+    'profile:username',
+    'video:actor',
+    'video:actor:role',
+    'video:director',
+    'video:duration',
+    'video:release_date',
+    'video:series',
+    'video:tag',
+    'video:writer',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_opengraph';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_name_attribute = 'property';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    // All OG tags use colons to separate levels.
+    $tag_name = str_replace('_', ':', $tag_name);
+
+    // Fix a few specific tags.
+    $tag_name = str_replace('secure:url', 'secure_url', $tag_name);
+    $tag_name = str_replace(':time', '_time', $tag_name);
+    $tag_name = str_replace(':date', '_date', $tag_name);
+    $tag_name = str_replace(':name', '_name', $tag_name);
+    $tag_name = str_replace(':address', '_address', $tag_name);
+    $tag_name = str_replace('see:also', 'see_also', $tag_name);
+    $tag_name = str_replace(':number', '_number', $tag_name);
+    $tag_name = str_replace(':code', '_code', $tag_name);
+
+    return $tag_name;
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_key() for 'og:type'.
+   */
+  public function og_type_test_key() {
+    return 'metatags[und][og:type][value]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'og:type'.
+   */
+  public function og_type_test_value() {
+    return 'article';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'og:type'.
+   */
+  public function og_type_test_field_xpath() {
+    return "//select[@name='metatags[und][og:type][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_key() for 'og:determiner'.
+   */
+  public function og_determiner_test_key() {
+    return 'metatags[und][og:determiner][value]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'og:determiner'.
+   */
+  public function og_determiner_test_value() {
+    return 'a';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'og:determiner'.
+   */
+  public function og_determiner_test_field_xpath() {
+    return "//select[@name='metatags[und][og:determiner][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'og:image'.
+   */
+  public function og_image_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'og:image:url'.
+   */
+  public function og_image_url_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'og:image:secure_url'.
+   */
+  public function og_image_secure_url_test_value() {
+    return str_replace('http://', 'https://', $this->randomImageUrl());
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/tests/metatag_opengraph.test b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/tests/metatag_opengraph.test
new file mode 100644
index 0000000000000000000000000000000000000000..4d93995031eddb468aca17837016610f1d3d4c98
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph/tests/metatag_opengraph.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag OpenGraph module.
+ */
+class MetatagOpenGraphTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag OpenGraph tests',
+      'description' => 'Test the Metatag:OpenGraph module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_opengraph';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.info b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.info
new file mode 100644
index 0000000000000000000000000000000000000000..67c290f286d67ea19a355b39fc033ebf206ee49d
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.info
@@ -0,0 +1,17 @@
+name = Metatag: OpenGraph Products
+description = Provides additional Open Graph Protocol meta tags for describing products.
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+dependencies[] = metatag:metatag_opengraph
+
+; Tests.
+files[] = tests/metatag_opengraph_products.test
+files[] = tests/metatag_opengraph_products.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..fc07ba48d9c32487eb40c56a04c175bad9e547ae
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.metatag.inc
@@ -0,0 +1,164 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_opengraph_product module.
+ */
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_opengraph_products_metatag_info() {
+  // Open Graph products.
+  $info['groups']['open-graph-products'] = array(
+    'label' => t('Open Graph - Products'),
+    'description' => t("These Open Graph meta tags for describing products."),
+    'form' => array(
+      '#weight' => 51,
+    ),
+  );
+
+  // Default values for each meta tag.
+  $defaults = array(
+    'description' => '',
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'open-graph-products',
+    'element' => array(
+      '#theme' => 'metatag_property',
+    ),
+  );
+
+  $weight = 50;
+
+  $info['tags']['product:price:amount'] = array(
+    'label' => t('Price'),
+    'description' => t("The numeric price with decimal point, without currency indicator. Values below 0.01 may not be supported by clients."),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:price:currency'] = array(
+    'label' => t('Currency'),
+    'description' => t("The currency for the price (if any)."),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:availability'] = array(
+    'label' => t('Availability'),
+    'description' => t('Case-insensitive string, possible values: "instock", "pending", "oos"; per <a href="@url">Facebook\' documentation</a>.', array('@url' => 'https://developers.facebook.com/docs/reference/opengraph/object-type/product')),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:brand'] = array(
+    'label' => t('Brand'),
+    'description' => '',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:upc'] = array(
+    'label' => t('UPC'),
+    'description' => '',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:ean'] = array(
+    'label' => t('EAN'),
+    'description' => '',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:isbn'] = array(
+    'label' => t('ISBN'),
+    'description' => '',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:plural_title'] = array(
+    'label' => t('Plural Title'),
+    'description' => 'A title to be used to describe multiple items of this product',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:retailer'] = array(
+    'label' => t('Retailer ID'),
+    'description' => 'A Facebook ID (or reference to the profile) of the retailer.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:retailer_title'] = array(
+    'label' => t('Retailer Name'),
+    'description' => 'The name of the retailer.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:retailer_part_no'] = array(
+    'label' => t('Retailer SKU/Product Number'),
+    'description' => 'A retailer part number.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:mfr_part_no'] = array(
+    'label' => t('Manufacturer SKU/Part Number'),
+    'description' => 'A manufacturer part number.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:size'] = array(
+    'label' => t('Size'),
+    'description' => 'A size describing the product, such as S, M, L.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:product_link'] = array(
+    'label' => t('Product Link'),
+    'description' => 'A link to find out more about the product',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:category'] = array(
+    'label' => t('Category'),
+    // 'description' => 'A category',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:color'] = array(
+    'label' => t('Color'),
+    // 'description' => 'The product\'s color.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:material'] = array(
+    'label' => t('Material'),
+    'description' => 'A description of the material used to make the product.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:pattern'] = array(
+    'label' => t('Pattern'),
+    'description' => 'A description of the pattern used.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:shipping_cost:amount'] = array(
+    'label' => t('Shipping Cost Amount'),
+    'description' => 'The shipping costs.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:shipping_cost:currency'] = array(
+    'label' => t('Shipping Cost Currency'),
+    'description' => 'The shipping cost currency.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:weight:value'] = array(
+    'label' => t('Product Weight'),
+    'description' => 'The weight, without shipping materials.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:weight:units'] = array(
+    'label' => t('Product Weight Units'),
+    'description' => 'The unit of weight.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:shipping_weight:value'] = array(
+    'label' => t('Shipping Weight'),
+    'description' => 'The shipping weight.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:shipping_weight:units'] = array(
+    'label' => t('Shipping Weight Units'),
+    'description' => 'The unit of shipping weight.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:expiration_time'] = array(
+    'label' => t('Expiration'),
+    'description' => 'A time representing when the product expired, or will expire.',
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['product:condition'] = array(
+    'label' => t('Condition'),
+    'description' => 'The condition of the product.',
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.module b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.module
new file mode 100644
index 0000000000000000000000000000000000000000..d76136973866660293eaf3b7bd2c0cc134e471f8
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/metatag_opengraph_products.module
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for the metatag_opengraph_products module.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_opengraph_products_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/tests/metatag_opengraph_products.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/tests/metatag_opengraph_products.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..d0d5673ab3b96987ac19636faab231f0f0ca5b57
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/tests/metatag_opengraph_products.tags.test
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Tests that each of the Metatag OpenGraph Products tags work correctly.
+ */
+class MetatagOpenGraphProductsTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: OpenGraph Products',
+      'description' => 'Test the OpenGraph Products meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'product:availability',
+    'product:brand',
+    'product:category',
+    'product:color',
+    'product:condition',
+    'product:ean',
+    'product:expiration_time',
+    'product:isbn',
+    'product:material',
+    'product:mfr_part_no',
+    'product:pattern',
+    'product:plural_title',
+    'product:price:amount',
+    'product:price:currency',
+    'product:product_link',
+    'product:retailer',
+    'product:retailer_part_no',
+    'product:retailer_title',
+    'product:shipping_cost:amount',
+    'product:shipping_cost:currency',
+    'product:shipping_weight:units',
+    'product:shipping_weight:value',
+    'product:size',
+    'product:upc',
+    'product:weight:units',
+    'product:weight:value',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_opengraph_products';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $test_name_attribute = 'property';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    // All OG tags use colons to separate levels.
+    $tag_name = str_replace('_', ':', $tag_name);
+
+    // Fix a few specific tags.
+    $tag_name = str_replace(':weight', '_weight', $tag_name);
+    $tag_name = str_replace('product_weight', 'product:weight', $tag_name);
+    $tag_name = str_replace(':cost', '_cost', $tag_name);
+    $tag_name = str_replace(':part:no', '_part_no', $tag_name);
+    $tag_name = str_replace(':title', '_title', $tag_name);
+    $tag_name = str_replace(':link', '_link', $tag_name);
+    $tag_name = str_replace(':time', '_time', $tag_name);
+
+    return $tag_name;
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/tests/metatag_opengraph_products.test b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/tests/metatag_opengraph_products.test
new file mode 100644
index 0000000000000000000000000000000000000000..46e06f8b02821206a80d37e0167cefda15fa63ea
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_opengraph_products/tests/metatag_opengraph_products.test
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Tests for the Metatag OpenGraph Products module.
+ */
+class MetatagOpenGraphProductsTest extends MetatagTestHelper {
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag OpenGraph products tests',
+      'description' => 'Test the Metatag:OpenGraph Products module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_opengraph_products';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..58f9b6c50a93994c4127f5d13d0bd8e2dcef7e96
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/README.txt
@@ -0,0 +1,27 @@
+Metatag: Panels
+-----------------
+This module adds support for meta tag configuration for Panels pages.
+
+Configuration is done within the "Metatag" tab existent in the Page Manager
+variant configuration page.
+
+
+Known Issues
+--------------------------------------------------------------------------------
+- Only contexts of a type that is supported by the Token API work.
+- Only one context for each type is currently supported. If you have two 'node'
+contexts, only the first node is elligible for replacement.
+
+
+Credits / Contact
+--------------------------------------------------------------------------------
+Originally developed by Diogo Correia [1] and sponsored by DRI — Discovery / Reinvention / Integration [2].
+
+This module is based on Panels Breadcrumbs [3] and the Meta tag: Context module.
+
+
+References
+--------------------------------------------------------------------------------
+1: https://www.drupal.org/u/devuo
+2: http://dri-global.com
+3: https://www.drupal.org/project/panels_breadcrumbs
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.i18n.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.i18n.inc
new file mode 100644
index 0000000000000000000000000000000000000000..c2eaa42726c80be64f5ca51e5b4c46ff42e32fb4
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.i18n.inc
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @file
+ * Internationalization (i18n) hooks.
+ */
+
+/**
+ * Implements hook_i18n_object_info().
+ */
+function metatag_panels_i18n_object_info() {
+  // Compile all of the tags to add to the translation stack.
+  $meta_tag_info = metatag_get_info();
+  $groups = $meta_tag_info['groups'];
+  $properties = array();
+  foreach ($meta_tag_info['tags'] as $tag_info) {
+    // Ignore certain field types that aren't translatable, mostly fields that
+    // list predetermined options in various forms.
+    if (!empty($tag_info['class']) && $tag_info['class'] == 'DrupalListMetaTag') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#type']) && $tag_info['form']['#type'] == 'select') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#options'])) {
+      continue;
+    }
+
+    // Build a suitable structure for this meta tag.
+    $tag_name = $tag_info['name'];
+    $tag_group = $tag_info['group'];
+    $group_label = isset($groups[$tag_group]['label']) ? $groups[$tag_group]['label'] : $tag_group;
+    $properties[$tag_name] = array(
+      'title' => $group_label . ': ' . $tag_info['label'],
+      'field' => "conf.metatag_panels.metatags.{$tag_name}.value",
+    );
+  }
+
+  $info['metatag_panels'] = array(
+    'title' => t('Metatag:Panels configurations'),
+    // Callback to load all config objects.
+    'list callback' => 'metatag_panels_i18n_list_panels',
+    // The object load callback.
+    // 'load callback' => 'metatag_panels_i18n_load',
+    // @todo Custom i18n object overrides.
+    // 'class' => 'metatag_panels_i18n_metatag',
+    // @todo Is this needed? What does it do?
+    // 'translation set' => TRUE,
+
+    // The object's "key" field, this tells i18n_string to use the $panel->name
+    // attribute.
+    'key' => 'name',
+    // Placeholders for automatic paths. This connects the 'key' to strings in
+    // the paths listed below.
+    // 'placeholders' => array(
+    //   '%did' => 'did',
+    // ),
+    // To produce edit links automatically.
+    // 'edit path' => 'admin/config/search/metatags/config/%instance',
+    // Auto-generate a 'translate' tab.
+    // 'translate tab' => 'admin/config/search/metatags/config/%instance/translate',
+
+    // Properties for string translation.
+    'string translation' => array(
+      // The textgroup, type and (below) name will be concatenated into a single
+      // string as the {locales_source} context.
+      'textgroup' => 'metatag',
+      'type' => 'metatag_panels',
+      // Table where the object is stored, to automate string lists.
+      // 'table' => 'page_manager_handlers',
+      // Translatable properties of these objects, this will be added later.
+      'properties' => $properties,
+      // The path to translate individual strings.
+      // 'translate path' => 'admin/config/search/metatags/config/%instance/translate/%i18n_language',
+    ),
+  );
+
+  return $info;
+}
+
+/**
+ * List callback.
+ */
+function metatag_panels_i18n_list_panels() {
+  // Load all of the CTools objects.
+  ctools_include('export');
+  $all_objects = array();
+
+  // Load the handlers first.
+  $handlers = ctools_export_crud_load_all('page_manager_handlers');
+  if (!empty($handlers)) {
+    // Unserialize the config array.
+    foreach ($handlers as $name => $handler) {
+      if (!empty($handler)) {
+        if (is_string($handler->conf)) {
+          $handler->conf = unserialize($handler->conf);
+        }
+        if (!empty($handler->conf['metatag_panels']['enabled']) && !empty($handler->conf['metatag_panels']['metatags'])) {
+          $all_objects[$name] = $handler;
+        }
+      }
+    }
+  }
+
+  // Load the pages next, they need extra "handling".
+  $pages = ctools_export_crud_load_all('page_manager_pages');
+  if (!empty($pages)) {
+    // Unserialize the config array.
+    foreach ($pages as $key => $page) {
+      if (!empty($page) && !empty($page->default_handlers)) {
+        foreach ($page->default_handlers as $name => $handler) {
+          if (is_string($handler->conf)) {
+            $handler->conf = unserialize($handler->conf);
+          }
+          if (!empty($handler->conf['metatag_panels']['enabled']) && !empty($handler->conf['metatag_panels']['metatags'])) {
+            $all_objects[$name] = $handler;
+          }
+        }
+      }
+    }
+  }
+
+  return $all_objects;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.info b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.info
new file mode 100644
index 0000000000000000000000000000000000000000..0ed19662ed85cce6c7f49db2eed4cce23610ae86
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.info
@@ -0,0 +1,18 @@
+name = Metatag: Panels
+description = Provides Metatag integration within the Panels interface.
+package = SEO
+core = 7.x
+
+dependencies[] = metatag:metatag
+dependencies[] = panels:panels
+
+; Tests.
+files[] = tests/metatag_panels.test
+files[] = tests/metatag_panels.i18n.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..14a1981489c2ab620e6a46aef940c48a1130a808
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.metatag.inc
@@ -0,0 +1,13 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_panels module.
+ */
+
+/**
+ * Implements hook_metatag_config_instance_info().
+ */
+function metatag_panels_metatag_config_instance_info() {
+  $info['panels'] = array('label' => t('Panels'));
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.module b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.module
new file mode 100644
index 0000000000000000000000000000000000000000..72ca8f5c2c99b6ff45a81bbd4b0d662cc5dc172a
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/metatag_panels.module
@@ -0,0 +1,250 @@
+<?php
+/**
+ * @file
+ * Main file for metatag_panels module.
+ */
+
+/**
+ * Implements hook_page_manager_variant_operations_alter().
+ */
+function metatag_panels_page_manager_variant_operations_alter(&$operations, $handler) {
+  // Use this obnoxious construct to safely insert our item.
+  reset($operations['children']);
+  $children_operations = array();
+  while (list($key, $value) = each($operations['children'])) {
+    $children_operations[$key] = $value;
+    if ($key == 'context') {
+      $children_operations['meta'] = array(
+        'title' => t('Meta tags'),
+        'description' => t('Edit variant level meta tags.'),
+        'form' => 'metatag_panels_form',
+      );
+    }
+  }
+  $operations['children'] = $children_operations;
+}
+
+/**
+ * Metatag panels configuration form.
+ */
+function metatag_panels_form($form, $form_state) {
+  $handler = $form_state['handler'];
+
+  // Load available contexts
+  ctools_include('context-task-handler');
+  $contexts = ctools_context_handler_get_all_contexts($form_state['task'], $form_state['subtask'], $handler);
+
+  // Convert contexts into keywords readable by the token engine.
+  $token_types = array();
+
+  foreach ($contexts as $context) {
+    if ($context->keyword == 'taxonomy_term') {
+      $token_types[] = 'term';
+    }
+    else {
+      $token_types[] = $context->keyword;
+    }
+  }
+
+  // Allow the user to enable/disable meta tags for this panel.
+  $form['settings']['metatags_enabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable Metatag configuration.'),
+    '#default_value' => isset($handler->conf['metatag_panels']['enabled']) ? $handler->conf['metatag_panels']['enabled'] : FALSE,
+  );
+
+  // Don't set any metatag instance name as the configuration data is managed
+  // locally within panels.
+  $instance = '';
+  $options = array('token types' => $token_types);
+  $metatags = empty($handler->conf['metatag_panels']) ? array() : $handler->conf['metatag_panels']['metatags'];
+
+  // This leaves some possibility for future versions to support translation.
+  if (!isset($metatags[LANGUAGE_NONE])) {
+    $metatags = array(LANGUAGE_NONE => $metatags);
+  }
+
+  // Load the metatag form (passed by reference).
+  metatag_metatags_form($form, $instance, $metatags[LANGUAGE_NONE], $options);
+
+  // Add CTools substitutions list to the form.
+  $rows = array();
+  foreach ($contexts as $context) {
+    foreach (ctools_context_get_converters('%' . check_plain($context->keyword) . ':', $context) as $keyword => $title) {
+      $rows[] = array(
+        check_plain($keyword),
+        t('@identifier: @title', array('@title' => $title, '@identifier' => $context->identifier)),
+      );
+    }
+  }
+  if (!empty($rows)) {
+    $form['contexts'] = array(
+      '#title' => t('Substitutions'),
+      '#type' => 'fieldset',
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    $header = array(t('Keyword'), t('Value'));
+    $form['contexts']['context'] = array('#markup' => theme('table', array('header' => $header, 'rows' => $rows)));
+    $form['contexts']['#states'] = array(
+      'visible' => array(
+        ':input[name="metatags_enabled"]' => array('checked' => TRUE),
+      ),
+    );
+  }
+
+  // Modify metatag form defaults.
+  $form['metatags']['#collapsible'] = FALSE;
+  $form['metatags']['#collapsed'] = FALSE;
+
+  // Don't show the Metatag options until it's enabled.
+  $form['metatags']['#states'] = array(
+    'visible' => array(
+      ':input[name="metatags_enabled"]' => array('checked' => TRUE),
+    ),
+  );
+
+  return $form;
+}
+
+/**
+ * Submission handler for Metatag panels configuration form.
+ */
+function metatag_panels_form_submit($form, $form_state) {
+  $conf = array(
+    'enabled' => $form_state['values']['metatags_enabled'],
+    'metatags' => array(),
+  );
+
+  // Only bother saving the meta tags if they were enabled.
+  if ($conf['enabled']) {
+    $conf['metatags'] = $form_state['values']['metatags'][LANGUAGE_NONE];
+
+    // Translate the meta tags.
+    metatag_translations_update($conf['metatags'], 'metatag_panels:' . $form_state['handler']->name);
+  }
+
+  // Save the values for later.
+  $form_state['handler']->conf['metatag_panels'] = $conf;
+}
+
+/**
+ * Implements hook_ctools_render_alter().
+ */
+function metatag_panels_ctools_render_alter($info, $page, $context) {
+  // By default do not add meta tags to admin pages. To enable meta tags on
+  // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+  if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+    return;
+  }
+
+  $output = &drupal_static('metatag_panels');
+
+  $handler = $context['handler'];
+
+  if (empty($handler->conf['metatag_panels']) || !$handler->conf['metatag_panels']['enabled']) {
+    return;
+  }
+
+  $metatags = $handler->conf['metatag_panels']['metatags'];
+  if (!is_array($metatags) || empty($metatags)) {
+    $metatags = array();
+  }
+
+  // If meta tags were found but they're not nested for the language, fix it.
+  // This leaves some possibility for future versions to support translation.
+  if (!empty($metatags) && !isset($metatags[LANGUAGE_NONE])) {
+    $metatags = array(LANGUAGE_NONE => $metatags);
+  }
+
+  // Translate all of the meta tags using i18n.
+  metatag_translate_metatags($metatags[LANGUAGE_NONE], 'metatag_panels:' . $handler->name, NULL, FALSE);
+
+  // Append global defaults.
+  $all_metatags = array();
+  foreach ($metatags as $langcode => $values) {
+    if (!empty($values)) {
+      $all_metatags = $values + metatag_config_load_with_defaults('');
+    }
+  }
+  $metatags = $all_metatags;
+
+  if (empty($metatags)) {
+    return;
+  }
+
+  // Substitute Panels context variables.
+  foreach ($metatags as $metatag => $data) {
+    if (is_string($data['value']) && strpos($data['value'], '%') !== FALSE) {
+      $metatags[$metatag]['value'] = ctools_context_keyword_substitute($data['value'], array(), $context['handler']->conf['display']->context);
+    }
+  }
+
+  // Get the contexts that exist within this panel.
+  ctools_include('context-task-handler');
+  $task_object = ctools_context_handler_get_task_object($context['task'], $context['subtask'], $context['handler']);
+  $task_contexts = ctools_context_load_contexts($task_object, TRUE, $context['contexts']);
+
+  // Build the tokens out of CTools contexts.
+  $tokens = array();
+  foreach ($task_contexts as $task_context) {
+    $tokens[$task_context->keyword] = $task_context->data;
+  }
+
+  // Because of page execution order, sometimes the page title does not get set
+  // by Panels in time for metatags to use it, so we'll explicitly set it here
+  // if we need to.
+  if (!empty($info['title'])) {
+    drupal_set_title($info['title'], PASS_THROUGH);
+  }
+
+  // Don't output meta tags that only contain the pager.
+  $current_pager = metatag_get_current_pager();
+
+  // Build the Metatag.
+  $options = array(
+    'instance' => 'panels:' . $handler->name,
+    'token data' => $tokens,
+  );
+  foreach ($metatags as $metatag => $data) {
+    // Render CTools context substitution values prior to rendering the meta
+    // tag.
+    if (is_string($data['value'])) {
+      $data['value'] = ctools_context_keyword_substitute(trim($data['value']), array(), $task_contexts);
+    }
+    $metatag_instance = metatag_get_instance($metatag, $data);
+
+    if ($metatag_instance) {
+      $tag_output = $metatag_instance->getElement($options);
+      // Don't output the pager if that's all there is.
+      if ($tag_output != $current_pager) {
+        $output[$metatag] = $tag_output;
+      }
+    }
+  }
+
+  // Give third-parties the opportunity to alter the metatag for a given
+  // instance.
+  drupal_alter('metatag_metatags_view', $output, $options['instance']);
+}
+
+/**
+ * Implements hook_page_build().
+ *
+ * @see metatag_panels_ctools_render_alter()
+ */
+function metatag_panels_page_build(&$page) {
+  // By default do not add meta tags to admin pages. To enable meta tags on
+  // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+  if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+    return;
+  }
+
+  $metatags = drupal_static('metatag_panels');
+
+  if (!empty($metatags)) {
+    // The page region can be changed.
+    $region = variable_get('metatag_page_region', 'content');
+    $page[$region]['metatags']['global'] = $metatags;
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels.i18n.test b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels.i18n.test
new file mode 100644
index 0000000000000000000000000000000000000000..c537f37e6f8c26d35abde67ffda35d96f87a9346
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels.i18n.test
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * Tests for the Metatag module for the direct Panels integration, using i18n.
+ */
+class MetatagPanelsI18nTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag:Panels i18n tests',
+      'description' => 'Test Metatag integration via the Metatag:Panels module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'panels', 'page_manager', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'panels';
+    $modules[] = 'metatag_panels';
+
+    // Can't really do anything without Page Manager.
+    $modules[] = 'page_manager';
+
+    // Needed for translations.
+    $modules[] = 'locale';
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable the hidden submodule to manage some default configs.
+    $modules[] = 'metatag_panels_tests';
+
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      // From i18n.
+      'translate admin strings',
+      'translate user-defined strings',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+  /**
+   * Test the Metatag:Panels translations.
+   */
+  public function testExportedPage() {
+    // Plan out the different translation string tests.
+    $string_en = 'Test page description.';
+    $string_fr = 'French page description';
+    $config_name = 'metatag_panels:page_metatag_panels_test__default:description';
+    $path = 'metatag-panels-test';
+
+    // Confirm the string is present as it has been grabbed by the string-
+    // refresh triggered in $this->setUp().
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the generator tag.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the description tag.');
+
+    // Save the translation string.
+    $this->saveTranslationString($lid, $config_name, 'fr', $string_en, $string_fr);
+
+    // Load the English page again.
+    $this->drupalGet($path);
+    $this->assertResponse(200, 'Loaded the default test page again.');
+
+    // Confirm the page's description is what we set it to.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_en);
+    $this->assertNotEqual($xpath[0]['content'], $string_fr);
+
+    // Load the French page.
+    $this->drupalGet('fr/' . $path);
+    $this->assertResponse(200, 'Loaded the French test page.');
+
+    // Confirm the generator string was translated.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_fr);
+    $this->assertNotEqual($xpath[0]['content'], $string_en);
+  }
+
+  // @todo Test translations on an in-db page.
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels.test b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels.test
new file mode 100644
index 0000000000000000000000000000000000000000..b7961dc649d5cfcbadd7c89c10db480828dc255b
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels.test
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * Tests for the Metatag module for the direct Panels integration.
+ */
+class MetatagPanelsTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag:Panels tests',
+      'description' => 'Test Metatag integration via the Metatag:Panels module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'panels', 'page_manager'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'panels';
+
+    // Can't really do anything without Page Manager.
+    $modules[] = 'page_manager';
+
+    // Enable the hidden submodule to manage some default configs.
+    $modules[] = 'metatag_panels_tests';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Test the Panels integration.
+   */
+  public function testExportedPage() {
+    $this->drupalGet('metatag-panels-test');
+    $this->assertResponse(200);
+
+    // Test the page title.
+    $this->assertTitle('Test page title');
+
+    // Test the description meta tag.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Test page description.');
+
+    // Test the keywords meta tag.
+    $xpath = $this->xpath("//meta[@name='keywords']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one keywords meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Test, page, keywords');
+  }
+
+  // @todo Test an in-db page.
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.info b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.info
new file mode 100644
index 0000000000000000000000000000000000000000..ea1fce5060b25a19310facd7e957234c59baf47c
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.info
@@ -0,0 +1,18 @@
+name = Metatag:Panels Tests
+description = Helper module for testing metatag_panels.module.
+core = 7.x
+
+; Don't show this on the modules admin page.
+hidden = TRUE
+
+dependencies[] = ctools:ctools
+dependencies[] = ctools:page_manager
+dependencies[] = metatag:metatag
+dependencies[] = metatag:metatag_panels
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.module b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.module
new file mode 100644
index 0000000000000000000000000000000000000000..5fa12f90bf9574698ba215a1719234305095509b
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.module
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_panels_tests_ctools_plugin_api($module = NULL, $api = NULL) {
+  if ($module == "page_manager" && $api == "pages_default") {
+    return array("version" => "1");
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.pages_default.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.pages_default.inc
new file mode 100644
index 0000000000000000000000000000000000000000..55e76a0807e8076ecc33a38aba5f4e9042ed67a0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_panels/tests/metatag_panels_tests.pages_default.inc
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @file
+ * metatag_panels_tests.pages_default.inc
+ */
+
+/**
+ * Implements hook_default_page_manager_pages().
+ */
+function metatag_panels_tests_default_page_manager_pages() {
+  $page = new stdClass();
+  $page->disabled = FALSE; /* Edit this to true to make a default page disabled initially */
+  $page->api_version = 1;
+  $page->name = 'metatag_panels_test';
+  $page->task = 'page';
+  $page->admin_title = 'Metatag:Panels test';
+  $page->admin_description = '';
+  $page->path = 'metatag-panels-test';
+  $page->access = array();
+  $page->menu = array(
+    'type' => 'none',
+    'title' => '',
+    'weight' => '0',
+    'name' => 'navigation',
+    'parent' => array(
+      'type' => 'none',
+      'title' => '',
+      'weight' => 0,
+      'name' => 'navigation',
+    ),
+  );
+  $page->arguments = array();
+  $page->conf = array(
+    'admin_paths' => FALSE,
+  );
+  $page->default_handlers = array();
+  $handler = new stdClass();
+  $handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
+  $handler->api_version = 1;
+  $handler->name = 'page_metatag_panels_test__default';
+  $handler->task = 'page';
+  $handler->subtask = 'metatag_panels_test';
+  $handler->handler = 'panel_context';
+  $handler->weight = 0;
+  $handler->conf = array(
+    'title' => 'Page',
+    'no_blocks' => 0,
+    'pipeline' => 'standard',
+    'body_classes_to_remove' => '',
+    'body_classes_to_add' => '',
+    'css_id' => '',
+    'css' => '',
+    'contexts' => array(),
+    'relationships' => array(),
+    'name' => '',
+    'metatag_panels' => array(
+      'enabled' => 1,
+      'metatags' => array(
+        'title' => array(
+          'value' => 'Test page title',
+        ),
+        'description' => array(
+          'value' => 'Test page description.',
+        ),
+        'keywords' => array(
+          'value' => 'Test, page, keywords',
+        ),
+      ),
+    ),
+  );
+  $display = new panels_display();
+  $display->layout = 'onecol';
+  $display->layout_settings = array();
+  $display->panel_settings = array(
+    'style_settings' => array(
+      'default' => NULL,
+      'middle' => NULL,
+    ),
+  );
+  $display->cache = array();
+  $display->title = 'Testing';
+  $display->uuid = '14a1dc5e-6abd-41d5-a361-56c1c5404f32';
+  $display->content = array();
+  $display->panels = array();
+  $pane = new stdClass();
+  $pane->pid = 'new-8537d8cc-5b2d-4eac-b093-6b62f3fdc38a';
+  $pane->panel = 'middle';
+  $pane->type = 'custom';
+  $pane->subtype = 'custom';
+  $pane->shown = TRUE;
+  $pane->access = array();
+  $pane->configuration = array(
+    'admin_title' => 'Hello',
+    'title' => 'Hello there',
+    'body' => 'Hi.',
+    'format' => 'filtered_html',
+    'substitute' => TRUE,
+  );
+  $pane->cache = array();
+  $pane->style = array(
+    'settings' => NULL,
+  );
+  $pane->css = array();
+  $pane->extras = array();
+  $pane->position = 0;
+  $pane->locks = array();
+  $pane->uuid = '8537d8cc-5b2d-4eac-b093-6b62f3fdc38a';
+  $display->content['new-8537d8cc-5b2d-4eac-b093-6b62f3fdc38a'] = $pane;
+  $display->panels['middle'][0] = 'new-8537d8cc-5b2d-4eac-b093-6b62f3fdc38a';
+  $display->hide_title = PANELS_TITLE_FIXED;
+  $display->title_pane = 'new-8537d8cc-5b2d-4eac-b093-6b62f3fdc38a';
+  $handler->conf['display'] = $display;
+  $page->default_handlers[$handler->name] = $handler;
+  $pages['metatag_panels_test'] = $page;
+
+  return $pages;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1d0f2a4f179eff711a5efcc58e840a702cb5fdd1
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/README.txt
@@ -0,0 +1,45 @@
+Metatag: Twitter Cards
+----------------------
+This module adds the fourteen basic Twitter Cards meta tags [1]. The following
+tags are provided:
+
+* twitter:card
+* twitter:site
+* twitter:creator
+* twitter:url
+* twitter:title
+* twitter:description
+* twitter:image
+* twitter:image:width
+* twitter:image:height
+* twitter:image:alt
+* twitter:player
+* twitter:player:width
+* twitter:player:height
+* twitter:player:stream
+* twitter:player:stream:content_type
+
+
+Usage
+------------------------------------------------------------------------------
+The Twitter Cards meta tags are configured along with all other meta tags;
+on-form help is provided to aid with configuring the meta tags.
+
+After enabling and configuring the meta tags it is important to first test [2]
+the meta tags for compliance with Twitter's standards, and then apply [3] to
+have your site's usage approved.
+
+
+Credits
+------------------------------------------------------------------------------
+The initial development was by nico059 [4] with contributions by many in the
+community [5].
+
+
+References
+------------------------------------------------------------------------------
+1: https://dev.twitter.com/docs/cards
+2: https://dev.twitter.com/docs/cards/preview
+3: https://www.drupal.org/u/marty2081
+4: http://www.gemeentemuseum.nl/
+5: https://www.drupal.org/node/1664322
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.info b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.info
new file mode 100644
index 0000000000000000000000000000000000000000..c661c7a0bf9b48e43b4f3de6ae3cfbc3a0df9620
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.info
@@ -0,0 +1,16 @@
+name = Metatag: Twitter Cards
+description = "Provides support for Twitter's Card meta tags."
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_twitter_cards.test
+files[] = tests/metatag_twitter_cards.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.install b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.install
new file mode 100644
index 0000000000000000000000000000000000000000..d2ae3774cb67b55d22192cb3b7aec1df69fa7a50
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.install
@@ -0,0 +1,49 @@
+<?php
+/**
+ * @file
+ * Update scripts for the Metatag: Twitter Cards module.
+ */
+
+/**
+ * Implements hook_update_dependencies().
+ */
+function metatag_twitter_cards_update_dependencies() {
+  // Twitter Cards update 7100 requires the complete Metatag schema, so lets
+  // wait for Metatag update 7100 just to be sure.
+  $dependencies['metatag_twitter_cards'][7100] = array(
+    'metatag' => 7100,
+  );
+  return $dependencies;
+}
+
+/**
+ * Implementations of hook_update_N().
+ */
+
+/**
+ * Rename the 'twitter:image:src' meta tag back to 'twitter:image'. Sorry.
+ */
+function metatag_twitter_cards_update_7100(&$sandbox) {
+  module_load_include('install', 'metatag');
+  $old_tag = 'twitter:image:src';
+  $new_tag = 'twitter:image';
+  return metatag_update_replace_entity_tag($sandbox, $old_tag, $new_tag);
+}
+
+/**
+ * Rename the 'twitter:image:src' meta tag back to 'twitter:image', part 2.
+ */
+function metatag_twitter_cards_update_7101() {
+  module_load_include('install', 'metatag');
+  $old_tag = 'twitter:image:src';
+  $new_tag = 'twitter:image';
+  return metatag_update_replace_config_tag($old_tag, $new_tag);
+}
+
+/**
+ * Clear the Metatag cache.
+ */
+function metatag_twitter_cards_update_7102() {
+  cache_clear_all('*', 'cache_metatag', TRUE);
+  return t('All Metatag caches cleared.');
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..10f962ea3c4519639d1860fe6ec049ebaf6c9f68
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.metatag.inc
@@ -0,0 +1,430 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag Twitter Cards module.
+ */
+
+/**
+ * Implements hook_metatag_bundled_config_alter().
+ */
+function metatag_twitter_cards_metatag_bundled_config_alter(array &$configs) {
+  foreach ($configs as &$config) {
+    switch ($config->instance) {
+      case 'global':
+        $config->config += array(
+          'twitter:card' => array('value' => 'summary'),
+          'twitter:title' => array('value' => '[current-page:title]'),
+          'twitter:url' => array('value' => '[current-page:url:absolute]'),
+        );
+        break;
+
+      case 'global:frontpage':
+        $config->config += array(
+          'twitter:description' => array('value' => '[site:slogan]'),
+          'twitter:title' => array('value' => '[site:name]'),
+          'twitter:url' => array('value' => '[site:url]'),
+        );
+        break;
+
+      // On error pages point everything to the homepage.
+      case 'global:403':
+      case 'global:404':
+        $config->config += array(
+          'twitter:title' => array('value' => '[site:name]'),
+          'twitter:url' => array('value' => '[site:url]'),
+        );
+        break;
+
+      case 'node':
+        $config->config += array(
+          'twitter:description' => array('value' => '[node:summary]'),
+          'twitter:title' => array('value' => '[node:title]'),
+        );
+        break;
+
+      case 'taxonomy_term':
+        $config->config += array(
+          'twitter:description' => array('value' => '[term:description]'),
+          'twitter:title' => array('value' => '[term:name]'),
+        );
+        break;
+
+      case 'user':
+        $config->config += array(
+          'twitter:title' => array('value' => '[user:name]'),
+        );
+        if (variable_get('user_pictures')) {
+          $config->config += array(
+            'twitter:image' => array('value' => '[user:picture:url]'),
+          );
+        }
+        break;
+    }
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_twitter_cards_metatag_info() {
+  $info['groups']['twitter-cards'] = array(
+    'label' => t('Twitter card'),
+    'description' => t('A set of meta tags specially for controlling the summaries displayed when content is shared on <a href="!url">Twitter</a>.', array('!url' => 'https://twitter.com/')),
+    'form' => array(
+      '#weight' => 60,
+    ),
+  );
+
+  // Twitter Cards meta tags stack after the Open Graph tags.
+  $weight = 40;
+
+  // Defaults used for all cards.
+  $defaults = array(
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'twitter-cards',
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards',
+    ),
+  );
+
+  $info['tags']['twitter:card'] = array(
+    'label' => t('Twitter card type'),
+    'description' => t('Notes: no other fields are required for a <em>Summary</em> card, a <em>Photo</em> card requires the \'image\' field, a <em>Media player</em> card requires the \'title\', \'description\', \'media player URL\', \'media player width\', \'media player height\' and \'image\' fields, a <em>Summary Card with Large Image</em> card requires the \'Summary\' field and the \'image\' field, a <em>Gallery Card</em> requires all the \'Gallery Image\' fields, an <em>App Card</em> requires the \'iPhone app ID\' field, the \'iPad app ID\' field and the \'Google Play app ID\' field, a <em>Product Card</em> requires the \'description\' field, the \'image\' field, the \'Label 1\' field, the \'Data 1\' field, the \'Label 2\' field and the \'Data 2\' field.'),
+    'weight' => ++$weight,
+    'form' => array(
+      '#type' => 'select',
+      '#options' => array(
+        'summary' => t('Summary (default)'),
+        'summary_large_image' => t('Summary with large image'),
+        'photo' => t('Photo'),
+        'player' => t('Media player'),
+        'gallery' => t('Gallery'),
+        'app' => t('App'),
+        'product' => t('Product'),
+      ),
+      '#empty_option' => t('- None -'),
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:site'] = array(
+    'label' => t('Site\'s Twitter account'),
+    'description' => t('The @username for the website, which will be displayed in the Card\'s footer; must include the @ symbol.'),
+    'context' => array('global'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'twitter',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:site:id'] = array(
+    'label' => t('Site\'s Twitter account ID'),
+    'description' => t('The numerical Twitter account ID for the website, which will be displayed in the Card\'s footer.'),
+    'context' => array('global'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:creator'] = array(
+    'label' => t('Creator\'s Twitter account'),
+    'description' => t('The @username for the content creator / author for this page, including the @ symbol.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'twitter',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:creator:id'] = array(
+    'label' => t('Creator\'s Twitter account ID'),
+    'description' => t('The numerical Twitter account ID for the content creator / author for this page.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:url'] = array(
+    'label' => t('Page URL'),
+    'description' => t('The permalink / canonical URL of the current page.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'canonical',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:title'] = array(
+    'label' => t('Title'),
+    'description' => t('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".'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['twitter:description'] = array(
+    'label' => t('Description'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+  ) + $defaults;
+  $info['tags']['twitter:image'] = array(
+    'label' => t('Image URL'),
+    'description' => t('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 <em>Photo</em> then the image must be at least 280x150px.'),
+    'image' => TRUE,
+    'weight' => ++$weight,
+    'replaces' => array(
+      'twitter:image:src',
+    ),
+    'devel_generate' => array(
+      'type' => 'image',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:image:width'] = array(
+    'label' => t('Image width'),
+    'description' => t('The width of the image being linked to, in pixels.'),
+    'weight' => ++$weight,
+    'dependencies' => array(
+      array(
+        'dependency' => 'twitter:image',
+        'attribute' => 'value',
+        'condition' => 'filled',
+        'value' => TRUE,
+      ),
+    ),
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:image:height'] = array(
+    'label' => t('Image height'),
+    'description' => t('The height of the image being linked to, in pixels.'),
+    'weight' => ++$weight,
+    'dependencies' => array(
+      array(
+        'dependency' => 'twitter:image',
+        'attribute' => 'value',
+        'condition' => 'filled',
+        'value' => TRUE,
+      ),
+    ),
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:image:alt'] = array(
+    'label' => 'Image alternative text',
+    'description' => 'The alternative text of the image being linked to. Limited to 420 characters.',
+    'weight' => ++$weight,
+    'dependencies' => array(
+      array(
+        'dependency' => 'twitter:image',
+        'attribute' => 'value',
+        'condition' => 'filled',
+        'value' => TRUE,
+      ),
+    ),
+  ) + $defaults;
+
+  // 'gallery' cards.
+  $gallery_defaults = array(
+    'image' => TRUE,
+    'dependencies' => array(
+      array(
+        'dependency' => 'twitter:card',
+        'attribute' => 'value',
+        'condition' => 'value',
+        'value' => 'gallery',
+      ),
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:image0'] = array(
+    'label' => t('1st Gallery Image'),
+    'description' => t('A URL to the image representing the first photo in your gallery.'),
+    'weight' => ++$weight,
+  ) + $gallery_defaults;
+  $info['tags']['twitter:image1'] = array(
+    'label' => t('2nd Gallery Image'),
+    'description' => t('A URL to the image representing the second photo in your gallery.'),
+    'weight' => ++$weight,
+  ) + $gallery_defaults;
+  $info['tags']['twitter:image2'] = array(
+    'label' => t('3rd Gallery Image'),
+    'description' => t('A URL to the image representing the third photo in your gallery.'),
+    'weight' => ++$weight,
+  ) + $gallery_defaults;
+  $info['tags']['twitter:image3'] = array(
+    'label' => t('4th Gallery Image'),
+    'description' => t('A URL to the image representing the fourth photo in your gallery.'),
+    'weight' => ++$weight,
+  ) + $gallery_defaults;
+
+  // 'player' cards.
+  $player_defaults = array(
+    'dependencies' => array(
+      array(
+        'dependency' => 'twitter:card',
+        'attribute' => 'value',
+        'condition' => 'value',
+        'value' => 'player',
+      ),
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:player'] = array(
+    'label' => t('Media player URL'),
+    'description' => t('The full URL for loading a media player. Required when using a <em>Media player</em> card.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $player_defaults;
+  $info['tags']['twitter:player:width'] = array(
+    'label' => t('Media player width'),
+    'description' => t('The width of the media player iframe, in pixels. Required when using a <em>Media player</em> card.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $player_defaults;
+  $info['tags']['twitter:player:height'] = array(
+    'label' => t('Media player height'),
+    'description' => t('The height of the media player iframe, in pixels. Required when using a <em>Media player</em> card.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'integer',
+    ),
+  ) + $player_defaults;
+  $info['tags']['twitter:player:stream'] = array(
+    'label' => t('MP4 media stream URL'),
+    'description' => t('The full URL for an MP4 video (h.264) or audio (AAC) stream, takes precidence over the other media player field.'),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'type' => 'url',
+    ),
+  ) + $player_defaults;
+  $info['tags']['twitter:player:stream:content_type'] = array(
+    'label' => t('MP4 media stream MIME type'),
+    'description' => t('The MIME type for the media contained in the stream URL, as defined by <a href="!url">RFC 4337</a>.', array('!url' => 'http://tools.ietf.org/rfc/rfc4337.txt')),
+    'weight' => ++$weight,
+    'devel_generate' => array(
+      'maxlength' => 1,
+    ),
+  ) + $player_defaults;
+
+  // 'app' cards.
+  $info['tags']['twitter:app:country'] = array(
+    'label' => t('App Store Country'),
+    'description' => t('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.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:name:iphone'] = array(
+    'label' => t('iPhone app name'),
+    'description' => t("The name of the iPhone app."),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:id:iphone'] = array(
+    'label' => t('iPhone app ID'),
+    'description' => t("String value, should be the numeric representation of your iPhone app's ID in the App Store."),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:url:iphone'] = array(
+    'label' => t('iPhone app\'s custom URL scheme'),
+    'description' => t('The iPhone app\'s custom URL scheme (must include "://" after the scheme name).'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:name:ipad'] = array(
+    'label' => t('iPad app name'),
+    'description' => t("The name of the iPad app."),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:id:ipad'] = array(
+    'label' => t('iPad app ID'),
+    'description' => t("String value, should be the numeric representation of your iPad app's ID in the App Store."),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:url:ipad'] = array(
+    'label' => t('iPad app\'s custom URL scheme'),
+    'description' => t('The iPad app\'s custom URL scheme (must include "://" after the scheme name).'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:name:googleplay'] = array(
+    'label' => t('Google Play app name'),
+    'description' => t("The name of the app in the Google Play app store."),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:id:googleplay'] = array(
+    'label' => t('Google Play app ID'),
+    'description' => t("Your app ID in the Google Play Store (i.e. \"com.android.app\")."),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:app:url:googleplay'] = array(
+    'label' => t('Google Play app\'s custom URL scheme'),
+    'description' => t('The Google Play app\'s custom URL scheme (must include "://" after the scheme name).'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $defaults;
+
+  // 'product' cards.
+  $product_defaults = array(
+    'dependencies' => array(
+      array(
+        'dependency' => 'twitter:card',
+        'attribute' => 'value',
+        'condition' => 'value',
+        'value' => 'product',
+      ),
+    ),
+  ) + $defaults;
+  $info['tags']['twitter:label1'] = array(
+    'label' => t('Label 1'),
+    'description' => t('This field expects a string, and you can specify values for labels such as price, items in stock, sizes, etc.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $product_defaults;
+  $info['tags']['twitter:data1'] = array(
+    'label' => t('Data 1'),
+    'description' => t('This field expects a string, and allows you to specify the types of data you want to offer (price, country, etc.).'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $product_defaults;
+  $info['tags']['twitter:label2'] = array(
+    'label' => t('Label 2'),
+    'description' => t('This field expects a string, and you can specify values for labels such as price, items in stock, sizes, etc.'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $product_defaults;
+  $info['tags']['twitter:data2'] = array(
+    'label' => t('Data 2'),
+    'description' => t('This field expects a string, and allows you to specify the types of data you want to offer (price, country, etc.).'),
+    'weight' => ++$weight,
+    'element' => array(
+      '#theme' => 'metatag_twitter_cards'
+    ),
+  ) + $product_defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.module b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.module
new file mode 100644
index 0000000000000000000000000000000000000000..b26823623a83385e1dc2e2d4c9df36702a56c882
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/metatag_twitter_cards.module
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag: Twitter Cards.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_twitter_cards_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function metatag_twitter_cards_theme() {
+  $info['metatag_twitter_cards'] = array(
+    'render element' => 'element',
+  );
+
+  return $info;
+}
+
+/**
+ * Theme callback for an twittercard meta tag.
+ */
+function theme_metatag_twitter_cards($variables) {
+  $element = &$variables['element'];
+  $args = array(
+    '#name' => 'name',
+    '#value' => 'content',
+  );
+  element_set_attributes($element, $args);
+  unset($element['#value']);
+  return theme('html_tag', $variables);
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/tests/metatag_twitter_cards.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/tests/metatag_twitter_cards.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..f6a4fc2a2c79dad54ccae9516014bc3587f910e0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/tests/metatag_twitter_cards.tags.test
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Twitter Cards tags work correctly.
+ */
+class MetatagTwitterCardsTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Twitter Cards',
+      'description' => 'Test the Twitter Cards meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'twitter:app:country',
+    'twitter:app:id:googleplay',
+    'twitter:app:id:ipad',
+    'twitter:app:id:iphone',
+    'twitter:app:name:googleplay',
+    'twitter:app:name:ipad',
+    'twitter:app:name:iphone',
+    'twitter:app:url:googleplay',
+    'twitter:app:url:ipad',
+    'twitter:app:url:iphone',
+    'twitter:card',
+    'twitter:creator',
+    'twitter:creator:id',
+    'twitter:data1',
+    'twitter:data2',
+    'twitter:description',
+    'twitter:image',
+    'twitter:image0',
+    'twitter:image1',
+    'twitter:image2',
+    'twitter:image3',
+    'twitter:image:alt',
+    'twitter:image:height',
+    'twitter:image:width',
+    'twitter:label1',
+    'twitter:label2',
+    'twitter:player',
+    'twitter:player:height',
+    'twitter:player:stream',
+    'twitter:player:stream:content_type',
+    'twitter:player:width',
+    'twitter:site',
+    'twitter:site:id',
+    'twitter:title',
+    'twitter:url',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_twitter_cards';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    // All OG tags use colons to separate levels.
+    $tag_name = str_replace('_', ':', $tag_name);
+
+    // Fix a few specific tags.
+    $tag_name = str_replace('content:type', 'content_type', $tag_name);
+
+    return $tag_name;
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_key() for 'twitter:card'.
+   */
+  public function twitter_card_test_key() {
+    return 'metatags[und][twitter:card][value]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'twitter:card'.
+   */
+  public function twitter_card_test_value() {
+    return 'summary';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'twitter:card'.
+   */
+  public function twitter_card_test_field_xpath() {
+    return "//select[@name='metatags[und][twitter:card][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'twitter:image'.
+   */
+  public function twitter_image_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'twitter:image0'.
+   */
+  public function twitter_image0_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'twitter:image1'.
+   */
+  public function twitter_image1_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'twitter:image2'.
+   */
+  public function twitter_image2_test_value() {
+    return $this->randomImageUrl();
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'twitter:image3'.
+   */
+  public function twitter_image3_test_value() {
+    return $this->randomImageUrl();
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/tests/metatag_twitter_cards.test b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/tests/metatag_twitter_cards.test
new file mode 100644
index 0000000000000000000000000000000000000000..0125dd70780bac0b44e055b7b69674d692ef188d
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_twitter_cards/tests/metatag_twitter_cards.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag Twitter Cards module.
+ */
+class MetatagTwitterCardsTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Twitter Cards tests',
+      'description' => 'Test the Metatag:Twitter Cards module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_twitter_cards';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_verification/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f1cd79876c037800b3da0b29f28e9537bc2ce07f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/README.txt
@@ -0,0 +1,16 @@
+Metatag: Verification
+---------------------
+This module adds meta tags used to confirm ownership of the site with various
+search engines and online services.
+
+
+Usage
+------------------------------------------------------------------------------
+These tags are only available on the Global configuration section of the main
+settings interface at admin/config/search/metatag as they affect the site as a
+whole rather than portions of it.
+
+
+Credits
+------------------------------------------------------------------------------
+Development and maintenance by Damien McKenna.
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.info b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.info
new file mode 100644
index 0000000000000000000000000000000000000000..6cf49efd7bd03ee4ee9af29fda9697909e65b617
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.info
@@ -0,0 +1,16 @@
+name = Metatag: Verification
+description = "Various meta tags for verifying ownership of a site."
+package = SEO
+core = 7.x
+dependencies[] = metatag:metatag
+
+; Tests.
+files[] = tests/metatag_verification.test
+files[] = tests/metatag_verification.tags.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.install b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.install
new file mode 100644
index 0000000000000000000000000000000000000000..0a87ec19ebbd819bb91fe47307aeeac8f68910bd
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.install
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @file
+ * Update scripts for the Metatag:Verification submodule.
+ */
+
+/**
+ * Implementations of hook_update_N().
+ */
+
+/**
+ * Remove the Alexa verification tag.
+ */
+function metatag_verification_update_7100() {
+  module_load_include('install', 'metatag');
+  metatag_update_delete_config('alexaVerifyID');
+}
+
+/**
+ * Remove the Yahoo verification tag.
+ */
+function metatag_verification_update_7101() {
+  module_load_include('install', 'metatag');
+  metatag_update_delete_config('y_key');
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..eeab04d862f65de7d8bfa5703ffcfb90aab8e217
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.metatag.inc
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the Metatag: Verification module.
+ */
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_verification_metatag_info() {
+  $info['groups']['verification'] = array(
+    'label' => t('Site verification'),
+    'description' => t('These meta tags are used to confirm site ownership with search engines and other services.'),
+    'form' => array(
+      '#weight' => 110,
+    ),
+  );
+
+  // Stack the verification codes after most others.
+  $weight = 100;
+
+  // Defaults used for all meta tags.
+  $defaults = array(
+    'class' => 'DrupalTextMetaTag',
+    'context' => array('global'),
+    'group' => 'verification',
+  );
+
+  $info['tags']['msvalidate.01'] = array(
+    'label' => t('Bing'),
+    'description' => t('A string provided by <a href="@bing">Bing</a>, full details are available from the <a href="@verify_url">Bing online help</a>.', array('@bing' => 'http://www.bing.com/', '@verify_url' => 'http://www.bing.com/webmaster/help/how-to-verify-ownership-of-your-site-afcfefc6')),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['baidu-site-verification'] = array(
+    'label' => t('Baidu'),
+    'description' => t('A string provided by <a href="@baidu">Baidu</a>.', array('@baidu' => 'http://www.baidu.com/')),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['google-site-verification'] = array(
+    'label' => t('Google'),
+    'description' => t('A string provided by <a href="@google">Google</a>, full details are available from the <a href="@verify_url">Google online help</a>.', array('@google' => 'https://www.google.com/', '@verify_url' => 'https://support.google.com/webmasters/answer/35179?hl=en')),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['norton-safeweb-site-verification'] = array(
+    'label' => t('Norton Safe Web'),
+    'description' => t('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>.', array('@norton' => 'https://safeweb.norton.com/', '@verify_url' => 'https://safeweb.norton.com/help/site_owners')),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['p:domain_verify'] = array(
+    'label' => t('Pinterest'),
+    'description' => t('A string provided by <a href="@pinterest">Pinterest</a>, full details are available from the <a href="@verify_url">Pinterest online help</a>.', array('@pinterest' => 'https://www.pinterest.com/', '@verify_url' => 'https://help.pinterest.com/en/articles/verify-your-website')),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  $info['tags']['yandex-verification'] = array(
+    'label' => t('Yandex'),
+    'description' => t('A string provided by <a href="@yandex">Yandex</a>, full details are available from the <a href="@verify_url">Yandex online help</a>.', array('@yandex' => 'http://www.yandex.com/', '@verify_url' => 'http://api.yandex.com/webmaster/doc/dg/reference/hosts-type.xml')),
+    'weight' => ++$weight,
+  ) + $defaults;
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.module b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.module
new file mode 100644
index 0000000000000000000000000000000000000000..87f93d3a4140e94d25b30b216421311338924a4f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/metatag_verification.module
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for Metatag: Verification.
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_verification_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_verification/tests/metatag_verification.tags.test b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/tests/metatag_verification.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..ca8fb9492d3378b85ceea1a64d36148145926ffe
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/tests/metatag_verification.tags.test
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Tests that each of the Metatag Verification tags work correctly.
+ */
+class MetatagVerificationTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Verification',
+      'description' => 'Test the Verification meta tags.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'baidu-site-verification',
+    'google-site-verification',
+    'msvalidate.01',
+    'norton-safeweb-site-verification',
+    'p:domain_verify',
+    'yandex-verification',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_verification';
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTestTagName($tag_name) {
+    $tag_name = str_replace('_', '-', $tag_name);
+    $tag_name = str_replace('msvalidate-01', 'msvalidate.01', $tag_name);
+    $tag_name = str_replace('p-domain-verify', 'p:domain_verify', $tag_name);
+    return $tag_name;
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_verification/tests/metatag_verification.test b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/tests/metatag_verification.test
new file mode 100644
index 0000000000000000000000000000000000000000..447155857e6db54fd325a8c6c358ef3ffa425574
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_verification/tests/metatag_verification.test
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Tests for the Metatag Verification module.
+ */
+class MetatagVerificationTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Verification tests',
+      'description' => 'Test the Metatag:Verification module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_verification';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Confirm that it's possible to load the main admin page.
+   */
+  public function testAdminPage() {
+    $this->drupalGet('admin/config/search/metatags');
+    $this->assertResponse(200);
+
+    // Confirm the page is correct.
+    $this->assertText(t('To view a summary of the default meta tags and the inheritance, click on a meta tag type.'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/README.txt b/profiles/wcm_base/modules/contrib/metatag/metatag_views/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4398edc3813c0879c27f39a660772afb6008a8c9
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/README.txt
@@ -0,0 +1,16 @@
+Metatag: Views
+----------------
+This module adds support for meta tag configuration for Views pages.
+
+Configuration is done within the "Metatag" section of the Page Settings in
+the Views UI configuration page.
+
+
+Credits / Contact
+--------------------------------------------------------------------------------
+Originally developed by Dave Reid [1].
+
+
+References
+--------------------------------------------------------------------------------
+1: https://www.drupal.org/u/dave-reid
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.i18n.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.i18n.inc
new file mode 100644
index 0000000000000000000000000000000000000000..752753ac4f3647f8c8be3ed58f650f5765de3cfc
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.i18n.inc
@@ -0,0 +1,97 @@
+<?php
+/**
+ * @file
+ * Internationalization (i18n) hooks.
+ */
+
+/**
+ * Implements hook_i18n_object_info().
+ */
+function metatag_views_i18n_object_info() {
+  $info['metatag_views'] = array(
+    'title' => t('Metatag:Views configurations'),
+    // Callback to load all config objects.
+    'list callback' => 'metatag_views_i18n_list_displays',
+    // The object load callback.
+    // 'load callback' => 'metatag_views_i18n_load',
+    // Custom i18n object overrides. Right now this avoids problems with the
+    // object ID as defined by get_string_context().
+    'class' => 'metatag_views_i18n_metatag',
+    // @todo Is this needed? What does it do?
+    // 'translation set' => TRUE,
+
+    // The object key field; multiple values will be concatenated with ":" as
+    // the separator.
+    'key' => array('vid', 'id'),
+    // Placeholders for automatic paths. This connects the 'key' to strings in
+    // the paths listed below.
+    // 'placeholders' => array(
+    //   '%did' => 'did',
+    // ),
+    // To produce edit links automatically.
+    // 'edit path' => 'admin/config/search/metatags/config/%instance',
+    // Auto-generate a 'translate' tab.
+    // 'translate tab' => 'admin/config/search/metatags/config/%instance/translate',
+
+    // Properties for string translation.
+    'string translation' => array(
+      // The textgroup, type and (below) name will be concatenated into a single
+      // string as the {locales_source} context.
+      'textgroup' => 'metatag',
+      'type' => 'metatag_views',
+      // Table where the object is stored, to automate string lists.
+      // 'table' => 'views_display',
+      // Translatable properties of these objects, this will be added later.
+      'properties' => array(),
+      // The path to translate individual strings.
+      // 'translate path' => 'admin/config/search/metatags/config/%instance/translate/%i18n_language',
+    ),
+  );
+
+  // Compile all of the tags to add to the translation stack.
+  $meta_tag_info = metatag_get_info();
+  $groups = $meta_tag_info['groups'];
+  foreach ($meta_tag_info['tags'] as $tag_info) {
+    // Ignore certain field types that aren't translatable, mostly fields that
+    // list predetermined options in various forms.
+    if (!empty($tag_info['class']) && $tag_info['class'] == 'DrupalListMetaTag') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#type']) && $tag_info['form']['#type'] == 'select') {
+      continue;
+    }
+    elseif (!empty($tag_info['form']['#options'])) {
+      continue;
+    }
+
+    // Build a suitable structure for this meta tag.
+    $tag_name = $tag_info['name'];
+    $tag_group = $tag_info['group'];
+    $group_label = isset($groups[$tag_group]['label']) ? $groups[$tag_group]['label'] : $tag_group;
+    $info['metatag_views']['string translation']['properties'][$tag_name] = array(
+      'title' => $group_label . ': ' . $tag_info['label'],
+      'field' => "display_options.metatags.und.{$tag_name}.value",
+    );
+  }
+
+  return $info;
+}
+
+/**
+ * List callback.
+ */
+function metatag_views_i18n_list_displays() {
+  $displays = array();
+
+  foreach (views_get_all_views() as $view_id => $view) {
+    foreach ($view->display as $display) {
+      if (!empty($display->display_options['metatags'][LANGUAGE_NONE])) {
+        // Need to rig i18n_string's ability to find the record.
+        $display->view_id = $view_id;
+        $displays[$display->view_id . METATAG_VIEWS_CONTEXT_SEPARATOR . $display->id] = $display;
+      }
+    }
+  }
+
+  return $displays;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..55cb8465c20abea9fc5b39c6276873796d270585
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.inc
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @file
+ * Custom classes used with the Metatag:Views module.
+ */
+
+if (class_exists('i18n_string_object_wrapper')) {
+
+  /**
+   * i18n object overrides.
+   */
+  class metatag_views_i18n_metatag extends i18n_string_object_wrapper {
+
+    /**
+     * Get base keys for translating this object.
+     */
+    public function get_string_context() {
+      // This will result in a context like
+      // 'metatag_views:view_name__page:description' for the 'description' tag
+      // on the 'page' display of the 'view_name' view.
+      return array('metatag_views', $this->object->view_id . METATAG_VIEWS_CONTEXT_SEPARATOR . $this->object->id);
+    }
+
+  }
+}
\ No newline at end of file
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.info b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.info
new file mode 100644
index 0000000000000000000000000000000000000000..5a8f70d357e2a469fea2a0f5e656efe3d2ee0b78
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.info
@@ -0,0 +1,21 @@
+name = Metatag: Views
+description = Provides Metatag integration within the Views interface.
+package = SEO
+core = 7.x
+
+dependencies[] = metatag:metatag
+dependencies[] = views:views
+
+files[] = metatag_views.inc
+files[] = metatag_views_plugin_display_extender_metatags.inc
+
+; Tests.
+files[] = tests/metatag_views.test
+files[] = tests/metatag_views.i18n.test
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b293fe1d126ef1c19332d08ed38b68ca63f7b4a5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.metatag.inc
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @file
+ * Metatag integration for the metatag_views module.
+ */
+
+/**
+ * Implements hook_metatag_config_instance_info().
+ */
+function metatag_views_metatag_config_instance_info() {
+  $info['view'] = array('label' => t('Views'));
+  return $info;
+}
+
+/**
+ * Implements hook_metatag_config_default().
+ */
+function metatag_views_metatag_config_default() {
+  $configs = array();
+
+  $config = new stdClass();
+  $config->instance = 'view';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => '[view:title] | [current-page:pager][site:name]'),
+    'description' => array('value' => '[view:description]'),
+    'canonical' => array('value' => '[view:url]'),
+  );
+  $configs[$config->instance] = $config;
+
+  return $configs;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.module b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.module
new file mode 100644
index 0000000000000000000000000000000000000000..f3afe72fead4711d1df76a4ecbbf069bc6752280
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.module
@@ -0,0 +1,130 @@
+<?php
+/**
+ * @file
+ * Provides native meta tag integration with Views.
+ */
+
+// This is used to join the view name and the display name when building the
+// context string.
+define('METATAG_VIEWS_CONTEXT_SEPARATOR', '__');
+
+/**
+ * Implements hook_views_api().
+ */
+function metatag_views_views_api() {
+  return array('api' => 3.0);
+}
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_views_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_view_preview_info_alter().
+ */
+function metatag_views_views_preview_info_alter(&$rows, $view) {
+  $metatags = $view->display_handler->get_option('metatags');
+  if (!is_array($metatags) || empty($metatags)) {
+    return;
+  }
+
+  // If meta tags were found but they're not nested for the language, fix it.
+  // This leaves some possibility for future versions to support translation.
+  if (!empty($metatags) && !isset($metatags[LANGUAGE_NONE])) {
+    $metatags = array(LANGUAGE_NONE => $metatags);
+  }
+
+  // Set the page title to be the previewed views title before fetching meta
+  // tag values.
+  $title = drupal_set_title();
+  if ($view_title = $view->get_title()) {
+    drupal_set_title($view_title);
+  }
+
+  $instance = 'view:' . $view->name;
+  $options['token data']['view'] = $view;
+  $values = metatag_metatags_values($instance, $metatags, $options);
+  foreach ($values as $metatag => $value) {
+    $metatag_info = metatag_get_info('tags', $metatag);
+    $values[$metatag] = $metatag_info['label'] . ': ' . check_plain($value);
+  }
+  if (!empty($values)) {
+    $rows['query'][] = array(
+      '<strong>' . t('Meta tags') . '</strong>',
+      implode('<br />', $values),
+    );
+  }
+
+  // Restore the page title.
+  drupal_set_title($title);
+}
+
+/**
+ * Implements hook_page_alter().
+ */
+function metatag_views_page_alter(&$page) {
+  // By default do not add meta tags to admin pages. To enable meta tags on
+  // admin pages set the 'metatag_tag_admin_pages' variable to TRUE.
+  if (path_is_admin(current_path()) && !variable_get('metatag_tag_admin_pages', FALSE)) {
+    return;
+  }
+
+  $view = views_get_page_view();
+
+  // Check if Views metatags are enabled.
+  if (!empty($view) && metatag_config_is_enabled('view')) {
+    global $language;
+
+    // The following is taken from views_get_page_view().
+    // If a module is still putting in the display like we used to, catch that.
+    if (is_subclass_of($view, 'views_plugin_display')) {
+      $view = $view->view;
+    }
+
+    // Prevent Views settings from overwriting global:frontpage.
+    if (drupal_is_front_page() && metatag_config_is_enabled('global:frontpage')) {
+      return;
+    }
+
+    // Include only view name by default.
+    $instance = 'view:' . $view->name;
+
+    // Include display name if option is overridden.
+    if (!$view->display_handler->is_defaulted('metatags')) {
+      $instance = 'view:' . $view->name . ':' . $view->current_display;
+    }
+
+    // Load the meta tags for this view.
+    $metatags = $view->display_handler->get_option('metatags');
+
+    // Only proceed if there's something to work with.
+    if (!empty($metatags) && is_array($metatags)) {
+      // If meta tags were found but they're not nested for the language, fix
+      // it. This leaves some possibility for future versions to support
+      // translation.
+      if (!isset($metatags[LANGUAGE_NONE])) {
+        $metatags = array(LANGUAGE_NONE => $metatags);
+      }
+
+      // Translate all of the meta tags using i18n, but don't update the
+      // strings.
+      metatag_translate_metatags($metatags[LANGUAGE_NONE], 'metatag_views:' . $view->name . METATAG_VIEWS_CONTEXT_SEPARATOR . $view->current_display, NULL, FALSE);
+
+      // Build options for meta tag rendering.
+      $options = array();
+      $options['token data']['view'] = $view;
+      $options['language'] = $language->language;
+
+      // The page region can be changed.
+      $region = variable_get('metatag_page_region', 'content');
+
+      // Add the metatags.
+      $page[$region]['metatags'][$instance] = metatag_metatags_view($instance, $metatags, $options);
+    }
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.tokens.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.tokens.inc
new file mode 100644
index 0000000000000000000000000000000000000000..2db1deb69fa3ea61db8c235f59ef3eb0c5c0640a
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.tokens.inc
@@ -0,0 +1,101 @@
+<?php
+/**
+ * @file
+ * Token integration for the metatag_views module.
+ */
+
+/**
+ * Implements hook_token_info().
+ */
+function metatag_views_token_info() {
+  if (module_hook('views', 'token_info')) {
+    return array();
+  }
+
+  $info['types']['view'] = array(
+    'name' => t('View'),
+    'description' => t('Tokens related to views.'),
+    'needs-data' => 'view',
+  );
+  $info['tokens']['view']['name'] = array(
+    'name' => t('Name'),
+    'description' => t('The human-readable name of the view.'),
+  );
+  $info['tokens']['view']['description'] = array(
+    'name' => t('Description'),
+    'description' => t('The description of the view.'),
+  );
+  $info['tokens']['view']['machine-name'] = array(
+    'name' => t('Machine name'),
+    'description' => t('The machine-readable name of the view.'),
+  );
+  $info['tokens']['view']['title'] = array(
+    'name' => t('Title'),
+    'description' => t('The title of current display of the view.'),
+  );
+  $info['tokens']['view']['url'] = array(
+    'name' => t('URL'),
+    'description' => t('The URL of the view.'),
+    'type' => 'url',
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function metatag_views_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  if (module_hook('views', 'tokens')) {
+    return array();
+  }
+
+  $url_options = array('absolute' => TRUE);
+  if (isset($options['language'])) {
+    $url_options['language'] = $options['language'];
+  }
+  $sanitize = !empty($options['sanitize']);
+  $langcode = isset($options['language']) ? $options['language']->language : NULL;
+
+  $replacements = array();
+
+  if ($type == 'view' && !empty($data['view'])) {
+    $view = $data['view'];
+
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'name':
+          $replacements[$original] = $sanitize ? check_plain($view->human_name) : $view->human_name;
+          break;
+
+        case 'description':
+          $replacements[$original] = $sanitize ? check_plain($view->description) : $view->description;
+          break;
+
+        case 'machine-name':
+          $replacements[$original] = $view->name;
+          break;
+
+        case 'title':
+          $title = $view->get_title();
+          $replacements[$original] = $sanitize ? check_plain($title) : $title;
+          break;
+
+        case 'url':
+          if ($path = $view->get_url()) {
+            $replacements[$original] = url($path, $url_options);
+          }
+          break;
+      }
+    }
+
+    // [view:url:*] nested tokens. This only works if Token module is installed.
+    if ($url_tokens = token_find_with_prefix($tokens, 'url')) {
+      if ($path = $view->get_url()) {
+        $replacements += token_generate('url', $url_tokens, array('path' => $path), $options);
+      }
+    }
+  }
+
+  return $replacements;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.views.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..54f00c091c2c336024907749c02ba30ce839eb03
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views.views.inc
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @file
+ * Views integration for the metatag module.
+ */
+
+/**
+ * Implements hook_views_plugins().
+ */
+function metatag_views_views_plugins() {
+  $plugins = array();
+  $plugins['display_extender']['metatags'] = array(
+    'title' => t('Meta tags'),
+    'help' => t('Provides meta tags for views.'),
+    'handler' => 'metatag_views_plugin_display_extender_metatags',
+    'enabled' => TRUE,
+    'path' => drupal_get_path('module', 'metatag_views'),
+  );
+
+  return $plugins;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views_plugin_display_extender_metatags.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views_plugin_display_extender_metatags.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bb6762b956780f4ca2252b8affb62e95e54a8c13
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/metatag_views_plugin_display_extender_metatags.inc
@@ -0,0 +1,109 @@
+<?php
+/**
+ * @file
+ * Custom display extender plugin for Views.
+ */
+
+class metatag_views_plugin_display_extender_metatags extends views_plugin_display_extender {
+
+  /**
+   * Default values.
+   */
+  function options_definition() {
+    $options = parent::option_definition();
+    $options['metatags'] = array('default' => '');
+    return $options;
+  }
+  function options_definition_alter(&$options) {
+    $options['metatags'] = array('default' => array());
+  }
+
+  /**
+   * Defines where within the Views admin UI the new settings will be visible.
+   */
+  function options_summary(&$categories, &$options) {
+    $categories['metatags'] = array(
+      'title' => t('Meta tags'),
+      'column' => 'second',
+    );
+    $options['metatags'] = array(
+      'category' => 'metatags',
+      'title' => t('Meta tags'),
+      'value' => $this->has_metatags() ? t('Overridden') : t('Using defaults'),
+    );
+  }
+
+  /**
+   * Defines the form.
+   */
+  function options_form(&$form, &$form_state) {
+    if ($form_state['section'] == 'metatags') {
+      $form['#title'] .= t('The meta tags for this display');
+      $metatags = $this->get_metatags();
+
+      // Build/inject the Metatag form.
+      $instance = 'view:' . $form_state['view']->name;
+      $options['token types'] = array('view');
+      $options['context'] = 'view';
+      metatag_metatags_form($form, $instance, $metatags[LANGUAGE_NONE], $options);
+
+      $form['metatags']['#type'] = 'container';
+
+      // Basic tags fieldset should not collapse to display in a larger popup.
+      // @see https://www.drupal.org/node/1294478
+      // @see https://www.drupal.org/node/2624020
+      $form['metatags'][LANGUAGE_NONE]['basic']['#collapsible'] = FALSE;
+    }
+  }
+
+  /**
+   * Saves the form values.
+   */
+  function options_submit(&$form, &$form_state) {
+    if ($form_state['section'] == 'metatags') {
+      $metatags = $form_state['values']['metatags'];
+
+      // Leave some possibility for future versions to support translation.
+      foreach ($metatags as $langcode => $values) {
+        if (!empty($form['metatags'][$langcode]['#metatag_defaults'])) {
+          metatag_filter_values_from_defaults($form_state['values']['metatags'][$langcode], $form['metatags'][$langcode]['#metatag_defaults']);
+        }
+      }
+
+      $this->display->set_option('metatags', $metatags);
+
+      // Update the i18n strings.
+      if (!empty($metatags[LANGUAGE_NONE]) && $this->definition['enabled'] && module_exists('i18n_string') && !variable_get('metatag_i18n_disabled', FALSE)) {
+        metatag_translations_update($metatags[LANGUAGE_NONE], 'metatag_views:' . $this->view->name . '_' . $this->display->plugin_name);
+      }
+    }
+  }
+
+  /**
+   * Identify whether or not the current display has custom meta tags defined.
+   */
+  protected function has_metatags() {
+    $metatags = $this->get_metatags();
+    return !empty($metatags[LANGUAGE_NONE]);
+  }
+
+  /**
+   * Get the Metatag configuration for this display.
+   *
+   * @return array
+   *   The meta tag values, keys by language (default LANGUAGE_NONE).
+   */
+  private function get_metatags() {
+    $metatags = $this->display->get_option('metatags');
+
+    // Leave some possibility for future versions to support translation.
+    if (empty($metatags)) {
+      $metatags = array(LANGUAGE_NONE => array());
+    }
+    if (!isset($metatags[LANGUAGE_NONE])) {
+      $metatags = array(LANGUAGE_NONE => $metatags);
+    }
+
+    return $metatags;
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views.i18n.test b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views.i18n.test
new file mode 100644
index 0000000000000000000000000000000000000000..99b0bfd93a94b04c5a379ae28c977b1e32b40dca
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views.i18n.test
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * Tests for the Metatag module for the direct Views integration.
+ */
+class MetatagViewsI18nTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag:Views i18n tests',
+      'description' => 'Test Metatag integration via the Metatag:Views module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'views';
+    $modules[] = 'metatag_views';
+
+    // Needed for translations.
+    $modules[] = 'locale';
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable the hidden submodule to manage some default configs.
+    $modules[] = 'metatag_views_tests';
+
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      // From i18n.
+      'translate admin strings',
+      'translate user-defined strings',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+  /**
+   * Test the Metatag:Views translations.
+   */
+  public function testExportedPage() {
+    // Plan out the different translation string tests.
+    $string_en = 'Testing Metatag:Views.';
+    $string_fr = 'French page description.';
+    $config_name = 'metatag_views:metatag_views_test' . METATAG_VIEWS_CONTEXT_SEPARATOR . 'page:description';
+    $path = 'metatag-views-test';
+
+    // Confirm the string is present as it has been grabbed by the string-
+    // refresh triggered in $this->setUp().
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the generator tag.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the description tag.');
+
+    // Save the translation string.
+    $this->saveTranslationString($lid, $config_name, 'fr', $string_en, $string_fr);
+
+    // Load the English page again.
+    $this->drupalGet($path);
+    $this->assertResponse(200, 'Loaded the default test page again.');
+
+    // Confirm the page's description is what we set it to.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_en);
+    $this->assertNotEqual($xpath[0]['content'], $string_fr);
+
+    // Load the French page.
+    $this->drupalGet('fr/' . $path);
+    $this->assertResponse(200, 'Loaded the French test page.');
+
+    // Confirm the generator string was translated.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_fr);
+    $this->assertNotEqual($xpath[0]['content'], $string_en);
+  }
+
+  // @todo Test translations on an in-db display.
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views.test b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views.test
new file mode 100644
index 0000000000000000000000000000000000000000..9417821a563942ee26153f3f84cf5b93b64d67dd
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views.test
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * Tests for the Metatag module for the direct Views integration.
+ */
+class MetatagViewsTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag:Views tests',
+      'description' => 'Test Metatag integration via the Metatag:Views module.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'views';
+
+    // Enable the hidden submodule to manage some default configs.
+    $modules[] = 'metatag_views_tests';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Test the Metatag:Views translations on an exported page.
+   */
+  public function testExportedPage() {
+    $this->drupalGet('metatag-views-test');
+    $this->assertResponse(200);
+
+    // Test the page title.
+    $this->assertTitle('Test Views page title');
+
+    // Test the description meta tag.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Testing Metatag:Views.');
+
+    // Test the keywords meta tag.
+    $xpath = $this->xpath("//meta[@name='keywords']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one keywords meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Test, page, keywords');
+  }
+
+  // @todo Test an in-db display.
+  // @todo Test the master display.
+  // @todo Test separate displays.
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.info b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.info
new file mode 100644
index 0000000000000000000000000000000000000000..ada79e23ad9b03cacacb7fee82366ebd28c3bc70
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.info
@@ -0,0 +1,17 @@
+name = Metatag:Views Tests
+description = Helper module for testing metatag_views.module.
+core = 7.x
+
+; Don't show this on the modules admin page.
+hidden = TRUE
+
+dependencies[] = metatag:metatag
+dependencies[] = metatag:metatag_views
+dependencies[] = views:views
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.module b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.module
new file mode 100644
index 0000000000000000000000000000000000000000..8801269aff4ae0a3f44b0a4770250e608c6d4367
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.module
@@ -0,0 +1,12 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations.
+ */
+
+/**
+ * Implements hook_views_api().
+ */
+function metatag_views_tests_views_api($module = NULL, $api = NULL) {
+  return array('api' => '3.0');
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.views_default.inc b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.views_default.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ac6672b6e847d3352e6a78c47416247ecb3ff231
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/metatag_views/tests/metatag_views_tests.views_default.inc
@@ -0,0 +1,452 @@
+<?php
+/**
+ * @file
+ * metatag_views_tests.views_default.inc
+ */
+
+/**
+ * Implements hook_views_default_views().
+ */
+function metatag_views_tests_views_default_views() {
+  $export = array();
+
+  $view = new view();
+  $view->name = 'metatag_views_test';
+  $view->description = '';
+  $view->tag = 'default';
+  $view->base_table = 'node';
+  $view->human_name = 'Metatag Views test';
+  $view->core = 7;
+  $view->api_version = '3.0';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Master */
+  $handler = $view->new_display('default', 'Master', 'default');
+  $handler->display->display_options['title'] = 'Metatag Views test';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '5';
+  $handler->display->display_options['style_plugin'] = 'default';
+  $handler->display->display_options['row_plugin'] = 'node';
+  $handler->display->display_options['row_options']['links'] = FALSE;
+  /* Field: Content: Title */
+  $handler->display->display_options['fields']['title']['id'] = 'title';
+  $handler->display->display_options['fields']['title']['table'] = 'node';
+  $handler->display->display_options['fields']['title']['field'] = 'title';
+  $handler->display->display_options['fields']['title']['label'] = '';
+  $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
+  $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
+  /* Sort criterion: Content: Post date */
+  $handler->display->display_options['sorts']['created']['id'] = 'created';
+  $handler->display->display_options['sorts']['created']['table'] = 'node';
+  $handler->display->display_options['sorts']['created']['field'] = 'created';
+  $handler->display->display_options['sorts']['created']['order'] = 'DESC';
+  /* Filter criterion: Content: Published */
+  $handler->display->display_options['filters']['status']['id'] = 'status';
+  $handler->display->display_options['filters']['status']['table'] = 'node';
+  $handler->display->display_options['filters']['status']['field'] = 'status';
+  $handler->display->display_options['filters']['status']['value'] = 1;
+  $handler->display->display_options['filters']['status']['group'] = 1;
+  $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+
+  /* Display: Page */
+  $handler = $view->new_display('page', 'Page', 'page');
+  $handler->display->display_options['metatags'] = array(
+    'und' => array(
+      'title' => array(
+        'value' => 'Test Views page title',
+        'default' => '[view:title] | [current-page:pager][site:name]',
+      ),
+      'description' => array(
+        'value' => 'Testing Metatag:Views.',
+        'default' => '[view:description]',
+      ),
+      'abstract' => array(
+        'value' => '',
+      ),
+      'keywords' => array(
+        'value' => 'Test, page, keywords',
+      ),
+      'robots' => array(
+        'value' => array(
+          'index' => 0,
+          'follow' => 0,
+          'noindex' => 0,
+          'nofollow' => 0,
+          'noarchive' => 0,
+          'nosnippet' => 0,
+          'noodp' => 0,
+          'noydir' => 0,
+          'noimageindex' => 0,
+          'notranslate' => 0,
+        ),
+      ),
+      'news_keywords' => array(
+        'value' => '',
+      ),
+      'standout' => array(
+        'value' => '',
+      ),
+      'rating' => array(
+        'value' => '',
+      ),
+      'referrer' => array(
+        'value' => '',
+      ),
+      'rights' => array(
+        'value' => '',
+      ),
+      'image_src' => array(
+        'value' => '',
+      ),
+      'canonical' => array(
+        'value' => '[view:url]',
+        'default' => '[view:url]',
+      ),
+      'shortlink' => array(
+        'value' => '[current-page:url:unaliased]',
+        'default' => '[current-page:url:unaliased]',
+      ),
+      'publisher' => array(
+        'value' => '',
+      ),
+      'author' => array(
+        'value' => '',
+      ),
+      'original-source' => array(
+        'value' => '',
+      ),
+      'prev' => array(
+        'value' => '',
+      ),
+      'next' => array(
+        'value' => '',
+      ),
+      'revisit-after' => array(
+        'value' => '',
+        'period' => '',
+      ),
+      'content-language' => array(
+        'value' => '',
+      ),
+      'geo.position' => array(
+        'value' => '',
+      ),
+      'geo.placename' => array(
+        'value' => '',
+      ),
+      'geo.region' => array(
+        'value' => '',
+      ),
+      'icbm' => array(
+        'value' => '',
+      ),
+      'refresh' => array(
+        'value' => '',
+      ),
+      'itemtype' => array(
+        'value' => '',
+      ),
+      'itemprop:name' => array(
+        'value' => '[current-page:title]',
+        'default' => '[current-page:title]',
+      ),
+      'itemprop:description' => array(
+        'value' => '',
+      ),
+      'itemprop:image' => array(
+        'value' => '',
+      ),
+      'theme-color' => array(
+        'value' => '',
+      ),
+      'MobileOptimized' => array(
+        'value' => '',
+      ),
+      'HandheldFriendly' => array(
+        'value' => '',
+      ),
+      'viewport' => array(
+        'value' => '',
+      ),
+      'cleartype' => array(
+        'value' => '',
+      ),
+      'apple-itunes-app' => array(
+        'value' => '',
+      ),
+      'apple-mobile-web-app-capable' => array(
+        'value' => '',
+      ),
+      'apple-mobile-web-app-status-bar-style' => array(
+        'value' => '',
+      ),
+      'format-detection' => array(
+        'value' => '',
+      ),
+      'ios-app-link-alternative' => array(
+        'value' => '',
+      ),
+      'android-app-link-alternative' => array(
+        'value' => '',
+      ),
+      'android-manifest' => array(
+        'value' => '',
+      ),
+      'x-ua-compatible' => array(
+        'value' => '',
+      ),
+      'application-name' => array(
+        'value' => '',
+      ),
+      'msapplication-allowDomainApiCalls' => array(
+        'value' => '',
+      ),
+      'msapplication-allowDomainMetaTags' => array(
+        'value' => '',
+      ),
+      'msapplication-badge' => array(
+        'value' => '',
+      ),
+      'msapplication-config' => array(
+        'value' => '',
+      ),
+      'msapplication-navbutton-color' => array(
+        'value' => '',
+      ),
+      'msapplication-notification' => array(
+        'value' => '',
+      ),
+      'msapplication-square150x150logo' => array(
+        'value' => '',
+      ),
+      'msapplication-square310x310logo' => array(
+        'value' => '',
+      ),
+      'msapplication-square70x70logo' => array(
+        'value' => '',
+      ),
+      'msapplication-wide310x150logo' => array(
+        'value' => '',
+      ),
+      'msapplication-starturl' => array(
+        'value' => '',
+      ),
+      'msapplication-task' => array(
+        'value' => '',
+      ),
+      'msapplication-task-separator' => array(
+        'value' => '',
+      ),
+      'msapplication-tilecolor' => array(
+        'value' => '',
+      ),
+      'msapplication-tileimage' => array(
+        'value' => '',
+      ),
+      'msapplication-tooltip' => array(
+        'value' => '',
+      ),
+      'msapplication-window' => array(
+        'value' => '',
+      ),
+      'og:type' => array(
+        'value' => 'article',
+        'default' => 'article',
+      ),
+      'og:url' => array(
+        'value' => '[current-page:url:absolute]',
+        'default' => '[current-page:url:absolute]',
+      ),
+      'og:title' => array(
+        'value' => '[current-page:title]',
+        'default' => '[current-page:title]',
+      ),
+      'og:determiner' => array(
+        'value' => '',
+      ),
+      'og:description' => array(
+        'value' => '',
+      ),
+      'og:updated_time' => array(
+        'value' => '',
+      ),
+      'og:see_also' => array(
+        'value' => '',
+      ),
+      'og:image' => array(
+        'value' => '',
+      ),
+      'og:image:url' => array(
+        'value' => '',
+      ),
+      'og:image:secure_url' => array(
+        'value' => '',
+      ),
+      'og:image:type' => array(
+        'value' => '',
+      ),
+      'og:image:width' => array(
+        'value' => '',
+      ),
+      'og:image:height' => array(
+        'value' => '',
+      ),
+      'og:latitude' => array(
+        'value' => '',
+      ),
+      'og:longitude' => array(
+        'value' => '',
+      ),
+      'og:street_address' => array(
+        'value' => '',
+      ),
+      'og:locality' => array(
+        'value' => '',
+      ),
+      'og:region' => array(
+        'value' => '',
+      ),
+      'og:postal_code' => array(
+        'value' => '',
+      ),
+      'og:country_name' => array(
+        'value' => '',
+      ),
+      'og:email' => array(
+        'value' => '',
+      ),
+      'og:phone_number' => array(
+        'value' => '',
+      ),
+      'og:fax_number' => array(
+        'value' => '',
+      ),
+      'og:locale' => array(
+        'value' => '',
+      ),
+      'og:locale:alternate' => array(
+        'value' => '',
+      ),
+      'article:author' => array(
+        'value' => '',
+      ),
+      'article:publisher' => array(
+        'value' => '',
+      ),
+      'article:section' => array(
+        'value' => '',
+      ),
+      'article:tag' => array(
+        'value' => '',
+      ),
+      'article:published_time' => array(
+        'value' => '',
+      ),
+      'article:modified_time' => array(
+        'value' => '',
+      ),
+      'article:expiration_time' => array(
+        'value' => '',
+      ),
+      'profile:first_name' => array(
+        'value' => '',
+      ),
+      'profile:last_name' => array(
+        'value' => '',
+      ),
+      'profile:username' => array(
+        'value' => '',
+      ),
+      'profile:gender' => array(
+        'value' => '',
+      ),
+      'og:audio' => array(
+        'value' => '',
+      ),
+      'og:audio:secure_url' => array(
+        'value' => '',
+      ),
+      'og:audio:type' => array(
+        'value' => '',
+      ),
+      'book:author' => array(
+        'value' => '',
+      ),
+      'book:isbn' => array(
+        'value' => '',
+      ),
+      'book:release_date' => array(
+        'value' => '',
+      ),
+      'book:tag' => array(
+        'value' => '',
+      ),
+      'og:video:url' => array(
+        'value' => '',
+      ),
+      'og:video:secure_url' => array(
+        'value' => '',
+      ),
+      'og:video:width' => array(
+        'value' => '',
+      ),
+      'og:video:height' => array(
+        'value' => '',
+      ),
+      'og:video:type' => array(
+        'value' => '',
+      ),
+      'video:actor' => array(
+        'value' => '',
+      ),
+      'video:actor:role' => array(
+        'value' => '',
+      ),
+      'video:director' => array(
+        'value' => '',
+      ),
+      'video:writer' => array(
+        'value' => '',
+      ),
+      'video:duration' => array(
+        'value' => '',
+      ),
+      'video:release_date' => array(
+        'value' => '',
+      ),
+      'video:tag' => array(
+        'value' => '',
+      ),
+      'video:series' => array(
+        'value' => '',
+      ),
+    ),
+  );
+  $handler->display->display_options['path'] = 'metatag-views-test';
+  $translatables['metatag_views_test'] = array(
+    t('Master'),
+    t('Metatag Views i18n test'),
+    t('more'),
+    t('Apply'),
+    t('Reset'),
+    t('Sort by'),
+    t('Asc'),
+    t('Desc'),
+    t('Items per page'),
+    t('- All -'),
+    t('Offset'),
+    t('« first'),
+    t('‹ previous'),
+    t('next ›'),
+    t('last »'),
+    t('Page'),
+  );
+  $export['metatag_views_test'] = $view;
+
+  return $export;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/plugins/content_types/node_form_metatags.inc b/profiles/wcm_base/modules/contrib/metatag/plugins/content_types/node_form_metatags.inc
new file mode 100644
index 0000000000000000000000000000000000000000..fb76c4d4604fed7e0603aff3cb8ee1bfda0f96e3
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/plugins/content_types/node_form_metatags.inc
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @file
+ * Display the node form's Metatag fieldset in a pane.
+ */
+
+$plugin = array(
+  'single' => TRUE,
+  'title' => t('Node form meta tags'),
+  'icon' => 'icon_node_form.png',
+  'description' => t('Meta tags on the node form.'),
+  'required context' => new ctools_context_required(t('Form'), 'node_form'),
+  'category' => t('Form'),
+);
+
+/**
+ * CTools content type callback to output this pane.
+ */
+function metatag_node_form_metatags_content_type_render($subtype, $conf, $panel_args, &$context) {
+  $block = new stdClass();
+
+  $block->title = t('Meta tags');
+  $block->module = 'metatag';
+  $block->delta = 'metatag';
+
+  if (isset($context->form)) {
+    if (isset($context->form['metatags'])) {
+      $block->content['metatags'] = $context->form['metatags'];
+      unset($block->content['metatags']['#pre_render']);
+      unset($block->content['metatags']['#theme_wrappers']);
+      $block->content['metatags']['#type'] = '';
+
+      // Set access to false on the original rather than removing so that
+      // vertical tabs doesn't clone it. I think this is due to references.
+      $context->form['metatags']['#access'] = FALSE;
+    }
+  }
+  else {
+    $block->content = t('Meta tags options.');
+  }
+  return $block;
+}
+
+/**
+ * CTools content type callback to get the title of this pane.
+ */
+function metatag_node_form_metatags_content_type_admin_title($subtype, $conf, $context) {
+  if (isset($context->identifier)) {
+    $message = t('"@s" node form meta tags', array('@s' => $context->identifier));
+  }
+  else {
+    $message = t('Node form meta tags');
+  }
+  return $message;
+}
+
+/**
+ * CTools content type callback to display an edit form for this pane.
+ */
+function metatag_node_form_metatags_content_type_edit_form($form, &$form_state) {
+  // Provide a blank form so we have a place to have context setting.
+  return $form;
+}
+
+/**
+ * CTools content type callback to provide extra information about this pane.
+ */
+function metatag_node_form_metatags_content_type_admin_info($type, $subtype, $conf, $context = NULL) {
+  $output = new stdClass();
+  $output->title = t('Metatag form');
+  $output->content = t('Shows the meta tag fields on this node form if the user has the appropriate permissions.');
+
+  return $output;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.bulk_revert.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.bulk_revert.test
new file mode 100644
index 0000000000000000000000000000000000000000..4e4c4c3eaf1353807328688209394402891a74d1
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.bulk_revert.test
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Tests for the Metatag module to ensure the bulk revert functionality works
+ */
+class MetatagBulkRevertTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag bulk revert',
+      'description' => 'Test the Metatag bulk revert functionality.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * Test the Bulk Revert functionality works.
+   */
+  function testBulkRevertPageLoads() {
+    $this->adminUser = $this->createAdminUser();
+    $this->drupalLogin($this->adminUser);
+
+    $this->drupalGet('admin/config/search/metatags/bulk-revert');
+    $this->assertResponse(200);
+
+    // Confirm each of the entity checkboxes is present.
+    foreach (entity_get_info() as $entity_type => $entity_info) {
+      foreach (array_keys($entity_info['bundles']) as $bundle) {
+        if (metatag_entity_supports_metatags($entity_type, $bundle)) {
+          $this->assertFieldByName("update[{$entity_type}:{$bundle}]");
+        }
+      }
+    }
+
+    // Confirm each of the meta tags is available as a checkbox.
+    foreach (metatag_get_info('tags') as $tag_name => $tag) {
+      $this->assertFieldByName("tags[{$tag_name}]");
+    }
+
+    // Confirm each of the languages has a checkbox.
+    $this->assertFieldByName("languages[" . LANGUAGE_NONE . "]");
+    foreach (language_list() as $language) {
+      $this->assertFieldByName("languages[{$language->language}]");
+    }
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.core_tag_removal.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.core_tag_removal.test
new file mode 100644
index 0000000000000000000000000000000000000000..ff9c057e0e9e303d068572b2efd917eeeeea9d9b
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.core_tag_removal.test
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Tests for the Metatag module to ensure removal of core tags works correctly.
+ */
+class MetatagCoreTagRemovalTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tag handling',
+      'description' => 'Test Metatag integration with the locale module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * Test that the core meta tags work correctly.
+   */
+  function testCoreTagRemoval() {
+    // The default generator string that both Metatag and Drupal core use.
+    $generator_default = 'Drupal 7 (http://drupal.org)';
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the Generator tag is the default.
+    $xpath = $this->xpath("//meta[@name='generator']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one generator meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $generator_default);
+
+    // Update the global config to remove the 'generator' value.
+    $config = metatag_config_load('global');
+    unset($config->config['generator']);
+    metatag_config_save($config);
+    // Dump out the current config, to aid with debugging.
+    $this->verbose($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the Generator tag no longer exists.
+    $xpath = $this->xpath("//meta[@name='generator']");
+    $this->assertEqual(count($xpath), 0, 'No generator meta tag found.');
+
+    // Tell Metatag to leave core's meta tags in place.
+    variable_set('metatag_leave_core_tags', TRUE);
+
+    // Clear the Metatag caches.
+    metatag_flush_caches();
+
+    // Clear the page caches.
+    drupal_flush_all_caches();
+
+    // Load the front page again.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the Generator tag is the default again, i.e. core is
+    // responsible for adding it. Also, core uses the meta tag name "Generator"
+    // instead of 'generator' like Metatag uses.
+    $xpath = $this->xpath("//meta[@name='Generator']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one generator meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $generator_default);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.helper.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.helper.test
new file mode 100644
index 0000000000000000000000000000000000000000..db1d1032b378da871b49cfe5bb8d45d82c8cabc6
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.helper.test
@@ -0,0 +1,764 @@
+<?php
+
+/**
+ * A base class for the Metatag tests, provides shared methods.
+ */
+abstract class MetatagTestHelper extends DrupalWebTestCase {
+
+  /**
+   * Admin user.
+   *
+   * @var \StdClass
+   */
+  protected $adminUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Make sure these modules are enabled so that we can use their entity
+    // types later.
+    $modules[] = 'node';
+    $modules[] = 'taxonomy';
+
+    // Requirements.
+    $modules[] = 'ctools';
+    $modules[] = 'token';
+
+    // Metatag modules. Only enable the main module, submodules will be tested
+    // separately.
+    $modules[] = 'metatag';
+
+    // Adds some functionality for testing the entity handling.
+    $modules[] = 'metatag_test';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * {@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>' . check_plain($title) . "</h2>\n";
+    }
+
+    parent::verbose($title . $message);
+  }
+
+  /**
+   * Load the Performance admin page and clear all caches.
+   */
+  function clearAllCaches() {
+    $this->drupalGet('admin/config/development/performance');
+    $this->assertResponse(200);
+    $this->assertText(t('Performance'));
+    $this->assertText(t('Clear cache'));
+    $this->drupalPost(NULL, array(), t('Clear all caches'));
+    $this->assertResponse(200);
+    $this->assertText(t('Caches cleared'));
+  }
+
+  /**
+   * Create a content type for the tests.
+   */
+  function createContentType($machine_name, $label) {
+    // Create a content type.
+    $content_type = $this->drupalCreateContentType(array(
+      'type' => $machine_name,
+      'name' => $label,
+    ));
+
+    // Enable meta tags for this new content type.
+    metatag_entity_type_enable('node', $machine_name, TRUE);
+
+    return $content_type;
+  }
+
+  /**
+   * Create an admin user for the tests.
+   *
+   * @param array $extra_permissions
+   *   An array of permission strings to be added to the user.
+   *
+   * @return object
+   *   A user object.
+   */
+  function createAdminUser($extra_permissions = array()) {
+    $permissions = array(
+      // Basic permissions for the module.
+      'administer meta tags',
+      'edit meta tags',
+
+      // General admin access.
+      'access administration pages',
+    );
+
+    // Reset the static variable used to identify permissions, otherwise it's
+    // possible the permissions check in drupalCreateUser will fail.
+    $this->checkPermissions(array(), TRUE);
+    cache_clear_all();
+
+    return $this->drupalCreateUser(array_merge($permissions, $extra_permissions));
+  }
+
+  /**
+   * Create a normal user for the tests.
+   *
+   * @param array $extra_permissions
+   *   An array of permission strings to be added to the user.
+   *
+   * @return object
+   *   A user object.
+   */
+  function createUser($extra_permissions) {
+    // Basic permissions for the module.
+    $permissions = array(
+      'edit meta tags',
+    );
+
+    // Reset the static variable used to identify permissions, otherwise it's
+    // possible the permissions check in drupalCreateUser will fail.
+    $this->checkPermissions(array(), TRUE);
+    cache_clear_all();
+
+    return $this->drupalCreateUser(array_merge($permissions, $extra_permissions));
+  }
+
+  /**
+   * Returns a new vocabulary with random properties.
+   *
+   * @param $vocab_name
+   *   If empty a random string will be used.
+   * @param $content_type
+   *   Any content types listed will have a Taxonomy Term reference field added
+   *   that points to the new vocabulary.
+   *
+   * @return object
+   *   A vocabulary object.
+   */
+  function createVocabulary($vocab_name = NULL, $content_type = NULL) {
+    if (empty($vocab_name)) {
+      $vocab_name = $this->randomName();
+    }
+
+    // Create a vocabulary.
+    $vocabulary = new stdClass();
+    $vocabulary->name = $vocab_name;
+    $vocabulary->description = $vocab_name;
+    $vocabulary->machine_name = drupal_strtolower($vocab_name);
+    $vocabulary->help = '';
+    $vocabulary->weight = mt_rand(0, 10);
+    if (!empty($content_type)) {
+      $vocabulary->nodes = array($content_type => $content_type);
+    }
+    taxonomy_vocabulary_save($vocabulary);
+
+    // Enable meta tags for this new vocabulary.
+    metatag_entity_type_enable('taxonomy_term', $vocab_name, TRUE);
+
+    return $vocabulary;
+  }
+
+  /**
+   * Returns a new taxonomy term in a specific vocabulary.
+   *
+   * @param object $vocabulary
+   *   The vocabulary to add the term to.
+   * @param string $term_name
+   *   The name to use for the new vocabulary. If none is provided one will be
+   *   generated randomly.
+   *
+   * @return object
+   *   A taxonomy term object.
+   */
+  function createTerm($vocabulary, $term_name = NULL) {
+    if (empty($term_name)) {
+      $term_name = $this->randomName();
+    }
+
+    // Create an object to save.
+    $term = new stdClass();
+    $term->name = $term_name;
+    $term->description = $term_name;
+    // Use the first available text format.
+    $term->format = db_query_range('SELECT format FROM {filter_format}', 0, 1)->fetchField();
+    $term->vid = $vocabulary->vid;
+
+    // Save the term.
+    taxonomy_term_save($term);
+
+    return $term;
+  }
+
+  /**
+   * Return an list of default values.
+   *
+   * This should cover all of the default meta tags provided for a test:foo
+   * entity.
+   *
+   * @todo Expand to cover more meta tags.
+   *
+   * @see metatag_test_metatag_config_default()
+   */
+  function getTestDefaults() {
+    return array(
+      // Basic meta tags.
+      'title' => array('value' => 'Test altered title'),
+      'description' => array('value' => 'Test foo description'),
+      'abstract' => array('value' => 'Test foo abstract'),
+      // 'keywords' => array('value' => ''),
+
+      // Advanced meta tags.
+      // 'robots' => array('value' => ''),
+      // 'news_keywords' => array('value' => ''),
+      // 'standout' => array('value' => ''),
+      // 'robots' => array('value' => ''),
+      // 'standout' => array('value' => ''),
+      'generator' => array('value' => 'Drupal 7 (http://drupal.org)'),
+      // 'standout' => array('value' => ''),
+      // 'image_src' => array('value' => ''),
+      'canonical' => array('value' => '[current-page:url:absolute]'),
+      'shortlink' => array('value' => '[current-page:url:unaliased]'),
+      // 'publisher' => array('value' => ''),
+      // 'author' => array('value' => ''),
+      // 'original-source' => array('value' => ''),
+      // 'revisit-after' => array('value' => ''),
+      // 'content-language' => array('value' => ''),'
+    );
+  }
+
+  /**
+   * Add a locale to the site.
+   *
+   * This assumes the Locale module is enabled.
+   */
+  public function addSiteLanguage($langcode) {
+    // Load the language-add page.
+    $this->drupalGet('admin/config/regional/language/add');
+    $this->assertResponse(200, 'Loaded the language-add admin page.');
+
+    // Submit the language-add form.
+    $args = array(
+      'langcode' => $langcode,
+    );
+    $this->drupalPost(NULL, $args, t('Add language'));
+    $this->assertResponse(200);
+
+    // Verify that the browser was returned to the main languages admin page.
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), 'Redirected back to the main languages admin page.');
+
+    // Clear the language list cache so it can be reloaded.
+    drupal_static_reset('language_list');
+
+    // Get all language definitions.
+    $languages = language_list();
+    $language = $languages[$langcode]->name;
+    $this->assertText(strip_tags(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => t($language), '@locale-help' => url('admin/help/locale')))), 'A new language has been added.');
+  }
+
+  /**
+   * Set up a basic starting point for the locales.
+   *
+   * This assumes the Locale module is enabled. This also must be done before
+   * other user accounts are logged in.
+   *
+   * @param array $locales
+   *   A list of locales to be enabled, in langcode format.
+   */
+  public function setupLocales(array $locales = array()) {
+    // If no locales were requested, add Spanish and French.
+    if (empty($locales)) {
+      $locales[] = 'es';
+      $locales[] = 'fr';
+    }
+
+    // Log in as an admin user with privs to just set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      'access administration pages',
+    );
+    $admin_user = $this->drupalCreateUser($perms);
+    $this->drupalLogin($admin_user);
+
+    // Load the admin page, just to have a point of reference.
+    $this->drupalGet('admin');
+    $this->assertResponse(200, 'Loaded the main admin page.');
+
+    // Identify the site's default language.
+    $default_language = language_default('language');
+
+    // Add the locales.
+    foreach ($locales as $langcode) {
+      // Don't create the default language, it's already present.
+      if ($langcode != $default_language) {
+        $this->addSiteLanguage($langcode);
+      }
+    }
+
+    // Enable URL language detection and selection.
+    $this->drupalGet('admin/config/regional/language/configure');
+    $this->assertResponse(200);
+    $edit = array(
+      'language[enabled][locale-url]' => TRUE,
+    );
+    // Also enable path handling for Entity Translation if it is installed.
+    if (module_exists('entity_translation')) {
+      $edit['language_content[enabled][locale-url]'] = TRUE;
+    }
+    $this->drupalPost(NULL, $edit, t('Save settings'));
+    $this->assertResponse(200);
+
+    // Once all the setup is done, log out the user.
+    $this->drupalLogout();
+  }
+
+  /**
+   * Get the {locales_source} lid value for a specific context.
+   *
+   * @param string $context
+   *   The context string to search for.
+   * @param string $textgroup
+   *   This string's textgroup; defaults to 'metatag'.
+   *
+   * @return integer
+   *   The {locales_source}.lid value for this string.
+   */
+  function getTranslationLidByContext($context, $textgroup = 'metatag') {
+    // Extra debug output.
+    $this->debugLocalesSourcesByContext($context);
+
+    // Look for the string that's actually being requested.
+    return (int) db_query("SELECT lid
+      FROM {locales_source}
+      WHERE textgroup = :textgroup
+      AND context = :context",
+      array(
+        ':textgroup' => $textgroup,
+        ':context' => $context,
+      ))
+      ->fetchField();
+  }
+
+  /**
+   * Get the {locales_source} lid value for a specific source.
+   *
+   * @param string $string
+   *   The translation string to search for.
+   * @param string $textgroup
+   *   This string's textgroup; defaults to 'metatag'.
+   *
+   * @return integer
+   *   The {locales_source}.lid value for this string.
+   */
+  function getTranslationLidBySource($string, $textgroup = 'metatag') {
+    // Extra debug output.
+    $this->debugLocalesSourcesByContext('', $textgroup);
+
+    // Look for the string that's actually being requested.
+    return (int) db_query("SELECT lid
+      FROM {locales_source}
+      WHERE textgroup = :textgroup
+      AND source = :source",
+      array(
+        ':textgroup' => $textgroup,
+        ':source' => $string,
+      ))
+      ->fetchField();
+  }
+
+  /**
+   * Get the {locales_source} lid values for a specific context.
+   *
+   * @param string $context
+   *   The context string to search for.
+   * @param string $textgroup
+   *   This string's textgroup; defaults to 'metatag'.
+   *
+   * @return integer
+   *   The {locales_source}.lid value for this string.
+   */
+  function getTranslationsByContext($context, $textgroup = 'metatag') {
+    return db_query("SELECT lid
+      FROM {locales_source}
+      WHERE textgroup = :textgroup
+      AND context = :context",
+      array(
+        ':textgroup' => $textgroup,
+        ':context' => $context,
+      ))
+      ->fetchCol();
+  }
+
+  /**
+   * Generate a debug dump of the {locales_source} records for a specific context.
+   *
+   * @param string $context
+   *   The translation context to search against.
+   * @param string $textgroup
+   *   This string's textgroup; defaults to 'metatag'.
+   */
+  function debugLocalesSourcesByContext($context, $textgroup = 'metatag') {
+    // Get a dump of all i18n strings for Metatag.
+    $records = db_query("SELECT lid, location, textgroup, source, context, version
+      FROM {locales_source}
+      WHERE textgroup = :textgroup",
+      array(
+        ':textgroup' => $textgroup,
+      ))
+      ->fetchAllAssoc('lid');
+    foreach ($records as $key => $record) {
+      $records[$key] = (array) $record;
+    }
+    $args = array(
+      'caption' => 'i18n source check for . ' . $context,
+      'header' => array(
+        'lid',
+        'location',
+        'textgroup',
+        'source',
+        'context',
+        'version',
+      ),
+      'rows' => $records,
+    );
+    $this->verbose(theme('table', $args));
+  }
+
+  /**
+   * Save a {locales_target} translation string to the database.
+   *
+   * @param int $lid
+   *   The {locales_source}.lid primary key.
+   * @param string $context
+   *   The {locales_source}.context value for this string.
+   * @param string $langcode
+   *   The language the string is being translated into.
+   * @param string $string_source
+   *   The string that is being translated.
+   * @param string $string_target
+   *   The destination string.
+   */
+  function saveTranslationString($lid, $context, $langcode, $string_source, $string_target) {
+    // Load the translation page for the front page's title tag.
+    $this->drupalGet('admin/config/regional/translate/edit/' . $lid);
+    $this->assertResponse(200, 'Loaded the front page title tag string translation page.');
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/edit/' . $lid, array('absolute' => TRUE)));
+
+    // Confirm that the permission-check text is not found.
+    $this->assertNoText(t('This is a user-defined string. You are not allowed to translate these strings.'));
+
+    // Look for the existing string. The string gets mungled by the Locale
+    // module, so need to replicate its behaviour.
+    $this->assertText(check_plain(wordwrap($string_source, 0)));
+
+    // Look for the context value; the context value is empty for all default
+    // i.e. interface strings, so don't test this when the context is empty.
+    if (!empty($context)) {
+      $this->assertText($context);
+    }
+
+    // Confirm that the destination strings exist.
+    $source_locale = language_default('language');
+    if (function_exists('i18n_string_source_language')) {
+      $source_locale = i18n_string_source_language();
+    }
+    if ($source_locale != 'en') {
+      $this->assertField('translations[en]', 'Found the English translation string field.');
+    }
+    if ($source_locale != 'fr') {
+      $this->assertField('translations[fr]', 'Found the French translation string field.');
+    }
+    if ($source_locale != 'es') {
+      $this->assertField('translations[es]', 'Found the Spanish translation string field.');
+    }
+
+    // Translate the string.
+    $edit = array(
+      "translations[{$langcode}]" => $string_target,
+    );
+    $this->drupalPost(NULL, $edit, t('Save translations'));
+    $this->assertResponse(200);
+
+    // Confirm the save worked.
+    $this->assertText(t('The string has been saved.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)));
+
+    // Debug output.
+    $this->debugLocalesTargetsByContext($context);
+
+    // Clear the Metatag caches.
+    metatag_flush_caches();
+  }
+
+  /**
+   * Generate a debug dump of the {locales_target} records for a specific context.
+   *
+   * @param string $context
+   *   The translation context to search against.
+   */
+  function debugLocalesTargetsByContext($context) {
+    // , lt.i18n_status
+    $records = db_query("SELECT lt.lid, lt.translation, lt.language, lt.plid, lt.plural
+      FROM {locales_target} lt
+        INNER JOIN {locales_source} ls
+          ON lt.lid = ls.lid
+      WHERE ls.textgroup = 'metatag'
+        AND ls.context = :context",
+      array(':context' => $context))
+      ->fetchAllAssoc('lid');
+    foreach ($records as $key => $record) {
+      $records[$key] = (array) $record;
+    }
+    $args = array(
+      'caption' => 'Locale target check for . ' . $context,
+      'header' => array(
+        'lid',
+        'translation',
+        'language',
+        'plid',
+        'plural',
+        // 'i18n_status',
+      ),
+      'rows' => $records,
+    );
+    $this->verbose(theme('table', $args));
+  }
+
+  /**
+   * Creates an object which can be used for generating and checking behavior.
+   *
+   * @param string $identifier
+   *   The machine name to identify this object in source code.
+   * @param string $path
+   *   Path where generate metatags.
+   *
+   * @return object
+   *   A mapping object.
+   */
+  function createTestObject($identifier, $path) {
+    $test_object = new stdClass();
+    $test_object->name = $identifier;
+    $test_object->path = $path;
+    $test_object->title = "My $identifier title";
+    $test_object->description = "My $identifier description";
+    $test_object->abstract = "My $identifier abstract";
+    $test_object->keywords = "My $identifier keywords";
+
+    return $test_object;
+  }
+
+  /**
+   * Generates meta tags by path from a test_object.
+   *
+   * @return $test_object
+   *   Metatag mapping object.
+   */
+  function generateByPathConfig($test_object) {
+    // Verify the "add context" page works.
+    $this->drupalGet('admin/config/search/metatags/context');
+    $this->assertResponse(200);
+    $this->assertText(t('Add a meta tag by path'));
+
+    // Verify the "add context" page works.
+    $this->drupalGet('admin/config/search/metatags/context/add');
+    $this->assertResponse(200);
+    $this->assertText(t('The unique ID for this metatag path context rule. This must contain only lower case letters, numbers and underscores.'));
+
+    // Add new Metatag object for this configuration.
+    $values = array(
+      'name' => $test_object->name,
+    );
+
+    $this->drupalPost('admin/config/search/metatags/context/add', $values, t('Add and configure'));
+    $this->assertResponse(200);
+  }
+
+  /**
+   * Edits meta tags by path from a test_object.
+   *
+   * @return $test_object
+   *   Metatag mapping object.
+   */
+  function editByPathConfig($test_object) {
+    $edit = array(
+      'paths' => $test_object->path,
+      'metatags[und][title][value]' => $test_object->title,
+      'metatags[und][description][value]' => $test_object->description,
+      'metatags[und][abstract][value]' => $test_object->abstract,
+      'metatags[und][keywords][value]' => $test_object->keywords,
+    );
+    $this->drupalPost('admin/config/search/metatags/context/' . $test_object->name, $edit, t('Save'));
+    $this->assertResponse(200);
+  }
+
+  /**
+   * Checks if meta tags have been added correctly from a test_object.
+   *
+   * @return $test_object
+   *   Metatag mapping object.
+   */
+  function checkByPathConfig($test_object) {
+    $this->drupalGet($test_object->path);
+    $this->assertResponse(200);
+
+    // Manually test the page title.
+    if (!empty($test_object->title)) {
+      $this->assertTitle($test_object->title, 'Title found in ' . $test_object->path);
+    }
+
+    // Test the other meta tags.
+    $tags = array('description', 'abstract', 'keywords');
+    foreach ($tags as $tag) {
+      if (!empty($test_object->{$tag})) {
+        $this->assertRaw($test_object->{$tag}, $tag . ' found in ' . $test_object->path);
+      }
+      else {
+        $this->assertNoRaw('<meta name="' . $tag, $tag . ' not found in ' . $test_object->path);
+      }
+    }
+  }
+
+
+  /**
+   * Check the translation page for a specific string.
+   *
+   * @param string $string
+   *   The source string to search for.
+   * @param string $context
+   *   The i18n string context to check for.
+   * @param boolean $assert_true
+   *   By default strings are expeted to be found. If the string is not expected
+   *   to be translatable yet then pass in FALSE.
+   */
+  function searchTranslationPage($string, $context, $assert_true = TRUE) {
+    // Load the translation page.
+    $search = array(
+      'string' => $string,
+      'language' => 'all',
+      'translation' => 'all',
+      'group' => 'metatag',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertResponse(200, 'Loaded the translation admin page.');
+
+    // Confirm there are strings to translate.
+    $xpath = $this->xpath("//body//div[@class='content']//table//tbody//tr");
+    $count = count($xpath);
+
+    // If the string is expected, then confirm that there are strings to be
+    // found.
+    if ($assert_true) {
+      $this->assertTrue($count >= 1, 'Found Metatag strings to translate.');
+      $this->assertNoText(t('No strings available.'));
+      $xpath = $this->xpath("//body//div[@class='content']//table//tbody//tr");
+      $this->verbose("Found {$count} items to translate.");
+      if (!empty($string)) {
+        $this->assertText($context);
+        $this->assertText('metatag:' . $context);
+      }
+    }
+    // If the string is not supposed to be found, then confirm the context is
+    // not available.
+    else {
+      $this->assertNoText($context);
+      $this->assertNoText('metatag:' . $context);
+    }
+  }
+
+  /**
+   * Create an image of a specific size & type.
+   *
+   * @param string $image_size
+   *   The size of the requested image in 'XxY' format; defaults to '200x200'.
+   * @param string $format
+   *   The image format to use, defaults to 'png'.
+   *
+   * @return string
+   *   The URL to a public file.
+   */
+  function generateImage($image_size = '200x200', $format = 'png') {
+    // Only proceed if the Devel Generate module is installed.
+    if (module_exists('devel_generate')) {
+      // Load the Devel Generate image generator logic.
+      module_load_include('inc', 'devel_generate', 'image.devel_generate');
+
+      $image_format = 'png';
+      $image_size = '200x200';
+      $temp_image = devel_generate_image($image_format, $image_size, $image_size);
+
+      return file_unmanaged_move($temp_image, 'public://');
+    }
+    else {
+      $this->error('The Devel Generate module is not enabled, it must be added to the $modules array in the setUp() method for this test class.');
+    }
+  }
+
+  /**
+   * Create an image file object of a specific size & type.
+   *
+   * @param string
+   *   The size of the requested image in 'XxY' format; defaults to '200x200'.
+   * @param string
+   *   The image format to use, defaults to 'png'.
+   *
+   * @return object
+   *   The file object for the generated image.
+   */
+  function generateImageFile($image_size = '200x200', $format = 'png') {
+    // Generate a test image.
+    $image_uri = $this->generateImage();
+
+    // Create a file object for this image.
+    $file = new StdClass();
+    $file->fid = NULL;
+    $file->uid = 1;
+    $file->uri = $image_uri;
+    $file->filemime = file_get_mimetype($image_uri);
+    $file->filesize = filesize($image_uri);
+    $file->status = 1;
+    $file->timestamp = filemtime($image_uri);
+    $saved_file = file_save($file);
+
+    return $saved_file;
+  }
+
+  /**
+   * Verify a user entity's meta tags load correctly.
+   *
+   * @param object $user
+   *   A user object that is to be tested.
+   */
+  function assertUserEntityTags($user) {
+    // Load the user's profile page.
+    $this->drupalGet('user/' . $user->uid);
+    $this->assertResponse(200);
+
+    // Verify the title is using the custom default for this vocabulary.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $user->name . " ponies");
+  }
+
+  /**
+   * Generate a string that is allowable as a machine name.
+   *
+   * @param int $length
+   *   How long the machine name will be, defaults to eight characters.
+   *
+   * @return string
+   *   A string that contains lowercase letters and numbers, with a letter as
+   *   the first character.
+   */
+  function randomMachineName($length = 8) {
+    return strtolower($this->randomName($length));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.image.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.image.test
new file mode 100644
index 0000000000000000000000000000000000000000..1a2b0915531921b94a6e086db4b0f9ade663022b
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.image.test
@@ -0,0 +1,487 @@
+<?php
+
+/**
+ * Tests for the Metatag module to ensure image handling doesn't break.
+ */
+class MetatagCoreImageTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for images',
+      'description' => 'Test Metatag integration with image files.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'devel_generate'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Needs the OpenGraph submodule because of testNodeFieldValueMultiple().
+    $modules[] = 'metatag_opengraph';
+
+    // Need image handling.
+    $modules[] = 'image';
+
+    // Need the Devel Generate image generator.
+    $modules[] = 'devel_generate';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Confirm that an image can be added to a global configuration using the
+   * image's absolute URL.
+   */
+  function testConfigAbsoluteURL() {
+    // Generate a test image.
+    $image_uri = $this->generateImage();
+    $this->verbose($image_uri);
+
+    // Work out the web-accessible URL for this image.
+    $image_url = file_create_url($image_uri);
+
+    // Update the global config to add an image meta tag.
+    $config = metatag_config_load('global');
+    $config->config['image_src']['value'] = $image_url;
+    metatag_config_save($config);
+
+    // Dump out the current config, to aid with debugging.
+    $this->verbose($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $image_url, 'The image_src meta tag with an absolute URL is being output correctly.');
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that an image can be added to a global configuration using the
+   * image's relative URL.
+   */
+  function testConfigDrupalRelativeURL() {
+    // Generate a test image.
+    $image_uri = $this->generateImage();
+    $this->verbose($image_uri);
+
+    // Work out the web-accessible URL for this image.
+    $image_url = file_create_url($image_uri);
+
+    // Extract the relative URL version of the absolute URL.
+    $url_length = strlen($GLOBALS['base_url']);
+
+    // Need to increase the length by 1 as the base_url does not include a
+    // trailing slash.
+    $relative_url = substr($image_url, $url_length + 1);
+
+    // Update the global config to add an image meta tag.
+    $config = metatag_config_load('global');
+    $config->config['image_src']['value'] = $relative_url;
+    metatag_config_save($config);
+
+    // Dump out the current config, to aid with debugging.
+    $this->verbose($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual((string)$xpath[0]['href'], $image_url);//, 'The image_src meta tag with a URL relative to the Drupal root is being output as an absolute URL.');
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that an image can be added to a global configuration using the
+   * image's relative URL.
+   */
+  function testConfigRelativeURL() {
+    // Generate a test image.
+    $image_uri = $this->generateImage();
+    $this->verbose($image_uri);
+
+    // Work out the web-accessible URL for this image.
+    $image_url = file_create_url($image_uri);
+
+    // Extract the relative URL version of the absolute URL.
+    $url_length = drupal_strlen($GLOBALS['base_url']);
+
+    // Need to increase the length by 1 as the base_url does not include a
+    // trailing slash.
+    $relative_url = drupal_substr($image_url, $url_length + 1);
+
+    // Update the global config to add an image meta tag.
+    $config = metatag_config_load('global');
+    $config->config['image_src']['value'] = $relative_url;
+    metatag_config_save($config);
+
+    // Dump out the current config, to aid with debugging.
+    $this->verbose($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual((string)$xpath[0]['href'], $image_url);//, 'The image_src meta tag with an internal URI is being output as an absolute URL.');
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that an image can be added to a global configuration using the
+   * image's protocol-relative URL.
+   */
+  function testConfigProtocolRelativeURL() {
+    // Generate a test image.
+    $image_uri = $this->generateImage();
+    $this->verbose($image_uri);
+
+    // Work out the web-accessible URL for this image.
+    $image_url = file_create_url($image_uri);
+
+    // Make the URL protocol-relative.
+    $relative_url = str_replace('http://', '//', $image_url);
+
+    // Update the global config to add an image meta tag.
+    $config = metatag_config_load('global');
+    $config->config['image_src']['value'] = $relative_url;
+    metatag_config_save($config);
+
+    // Dump out the current config, to aid with debugging.
+    $this->verbose($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $relative_url, 'The image_src meta tag with a protocol-relative URL is being output correctly.');
+    $this->assertNotEqual($xpath[0]['href'], $image_url, 'The image_src meta tag does not contain the absolute URL.');
+  }
+
+  /**
+   * Confirm that an image can be added to a global configuration using the
+   * image's internal URI.
+   */
+  function testConfigInternalURL() {
+    // Generate a test image.
+    $image_uri = $this->generateImage();
+    $this->verbose($image_uri);
+
+    // Work out the web-accessible URL for this image.
+    $image_url = file_create_url($image_uri);
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($image_url);
+    $this->assertResponse(200, 'The image could be loaded.');
+
+    // Update the global config to add an image meta tag.
+    $config = metatag_config_load('global');
+    $config->config['image_src']['value'] = $image_uri;
+    metatag_config_save($config);
+
+    // Dump out the current config, to aid with debugging.
+    $this->verbose($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the image URL can be found in the raw HTML.
+    $this->assertRaw($image_url, 'Found the image URL in the raw HTML.');
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $image_url, 'The image_src meta tag with an internal URI is being output correctly.');
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that an image with a space in its URL will be handled properly.
+   */
+  function testConfigImageWithSpaceInURL() {
+    // Generate a test image.
+    $image_uri = $this->generateImage();
+    $this->verbose($image_uri);
+
+    // Rename the file so it has a space in the filename.
+    $image_uri = file_unmanaged_move($image_uri, str_replace('_', ' ', $image_uri));
+    $this->verbose($image_uri);
+
+    // Work out the web-accessible URL for this image.
+    $image_url = file_create_url($image_uri);
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($image_url);
+    $this->assertResponse(200, 'The image could be loaded.');
+
+    // After processing the image's URL will have "%20" instead of spaces.
+    $image_url_friendly = str_replace(' ', '%20', $image_url);
+
+    // Confirm the file's friendly URL could be loaded.
+    $this->drupalGet($image_url_friendly);
+    $this->assertResponse(200, 'The friendly image could be loaded.');
+
+    // Update the global config to add an image meta tag.
+    $config = metatag_config_load('global');
+    $config->config['image_src']['value'] = $image_uri;
+    metatag_config_save($config);
+
+    // Dump out the current config, to aid with debugging.
+    $this->verbose($config);
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // Confirm that the image's friendly URL can be found in the raw HTML.
+    $this->assertRaw($image_url_friendly, 'Found the friendly image URL in the raw HTML.');
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $image_url_friendly, 'The image had its spaces replaces with "%20".');
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that a default value on an image field will be output correctly.
+   */
+  function testNodeFieldDefault() {
+    // Generate a test image file object.
+    $image = $this->generateImageFile();
+    $image_url = file_create_url($image->uri);
+
+    // Dump out the file object, to aid with debugging.
+    $this->verbose($image);
+
+    // Update the article-image default settings to use the new image field.
+    $entity_type = 'node';
+    $bundle = 'article';
+    $field_name = 'field_image';
+    $instance = field_info_instance($entity_type, $field_name, $bundle);
+    $instance['settings']['default_image'] = $image->fid;
+    field_update_instance($instance);
+
+    // Create an example node.
+    $args = array(
+      'type' => 'article',
+    );
+    $node = $this->drupalCreateNode($args);
+
+    // Update the config.
+    $config = metatag_config_load('node');
+    $config->config['image_src']['value'] = '[node:field_image]';
+    metatag_config_save($config);
+
+    // Load the node page.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $image_url, "The image_src meta tag was found with the field's default image.");
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that a file on an image field will be output correctly.
+   */
+  function testNodeFieldValue() {
+    // Update the 'content' config to use the field_image field as the
+    // image_src meta tag.
+    $config = metatag_config_load('node');
+    $config->config['image_src']['value'] = '[node:field_image]';
+    metatag_config_save($config);
+
+    // Generate a test image file object.
+    $image = $this->generateImageFile();
+    $image_url = file_create_url($image->uri);
+
+    // Dump out the file object, to aid with debugging.
+    $this->verbose($image);
+
+    // Create an example node.
+    $args = array(
+      'type' => 'article',
+      'field_image' => array(
+        LANGUAGE_NONE => array(
+          array('fid' => $image->fid),
+        ),
+      ),
+    );
+    $node = $this->drupalCreateNode($args);
+
+    // Forcibly reload the node, to avoid working with a cached version.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->verbose($node, 'Node');
+
+    // Load the node page.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Confirm that the image_src meta tag has the expected values.
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'One image_src meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $image_url, "The image_src meta tag was found with the node's image field's value.");
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that when using a file field that allows multiple values, only the
+   * first item will be used when outputting a single meta tag.
+   */
+  function testNodeFieldValueNotMultiple() {
+    // Update the 'content' config to use the field_image field as the
+    // image_src meta tag.
+    $config = metatag_config_load('node');
+    $config->config['image_src']['value'] = '[node:field_image]';
+    metatag_config_save($config);
+
+    // Update the image field to allow unlimited items.
+    $field_name = 'field_image';
+    $field = field_info_field($field_name);
+    $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
+    field_update_field($field);
+
+    // Generate a test image file object.
+    $image1 = $this->generateImageFile();
+    $image1_url = file_create_url($image1->uri);
+    $image2 = $this->generateImageFile();
+    $image2_url = file_create_url($image2->uri);
+
+    // Dump out the file objects, to aid with debugging.
+    $this->verbose($image1, 'Image #1');
+    $this->verbose($image2, 'Image #2');
+
+    // Create an example node.
+    $args = array(
+      'type' => 'article',
+      'field_image' => array(
+        LANGUAGE_NONE => array(
+          array('fid' => $image1->fid),
+          array('fid' => $image2->fid),
+        ),
+      ),
+    );
+    $node = $this->drupalCreateNode($args);
+
+    // Forcibly reload the node, to avoid working with a cached version.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->verbose($node, 'Node');
+
+    // Load the node page.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Confirm that the image_src meta tag has the expected values.
+
+    $xpath = $this->xpath("//link[@rel='image_src']");
+    $this->assertEqual(count($xpath), 1, 'Only one image_src meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $image1_url, "The image_src meta tag was found with the node's image field's first value.");
+    $this->assertNotEqual($xpath[0]['href'], $image2_url, "The image_src meta tag does not contain the node's image field's second value.");
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['href']);
+    $this->assertResponse(200, "The image_src meta tag's value could be loaded.");
+  }
+
+  /**
+   * Confirm that when using a file field that allows multiple values, that
+   * multiple images can be used and then it will result in multiple meta tags.
+   */
+  function testNodeFieldValueMultiple() {
+    // Update the 'content' config to use the field_image field as the
+    // image_src meta tag.
+    $config = metatag_config_load('node');
+    $config->config['og:image']['value'] = '[node:field_image]';
+    metatag_config_save($config);
+
+    // Update the image field to allow unlimited items.
+    $field_name = 'field_image';
+    $field = field_info_field($field_name);
+    $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
+    field_update_field($field);
+
+    // Generate a test image file object.
+    $image1 = $this->generateImageFile();
+    $image1_url = file_create_url($image1->uri);
+    $image2 = $this->generateImageFile();
+    $image2_url = file_create_url($image2->uri);
+
+    // Dump out the file objects, to aid with debugging.
+    $this->verbose($image1, 'Image #1');
+    $this->verbose($image2, 'Image #2');
+
+    // Create an example node.
+    $args = array(
+      'type' => 'article',
+      'field_image' => array(
+        LANGUAGE_NONE => array(
+          array('fid' => $image1->fid),
+          array('fid' => $image2->fid),
+        ),
+      ),
+    );
+    $node = $this->drupalCreateNode($args);
+
+    // Forcibly reload the node, to avoid working with a cached version.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->verbose($node, 'Node');
+
+    // Load the node page.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Confirm that the og:image meta tags have the expected values.
+    $xpath = $this->xpath("//meta[@property='og:image']");
+    $this->assertEqual(count($xpath), 2, 'Two og:image meta tags were found.');
+    $this->assertEqual($xpath[0]['content'], $image1_url, "The first og:image meta tag has the correct image.");
+    $this->assertEqual($xpath[1]['content'], $image2_url, "The second og:image meta tag has the correct image.");
+
+    // Confirm the file could be loaded.
+    $this->drupalGet($xpath[0]['content']);
+    $this->assertResponse(200, "The first og:image meta tag's value could be loaded.");
+    $this->drupalGet($xpath[1]['content']);
+    $this->assertResponse(200, "The second og:image meta tag's value could be loaded.");
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.locale.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.locale.test
new file mode 100644
index 0000000000000000000000000000000000000000..0b2a8a836e1acc9e4be45d563a712ce7ac443fd8
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.locale.test
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * Tests for the Metatag module to ensure Locale integration doesn't break.
+ */
+class MetatagCoreLocaleTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for Locale',
+      'description' => 'Test Metatag integration with the locale module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need Locale for the multiple languages.
+    $modules[] = 'locale';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Test that the node form meta tag fields are translated correctly.
+   */
+  function testNodeFormTranslations() {
+    $content_type = 'metatag_test';
+    $content_type_path = str_replace('_', '-', $content_type);
+    $label = 'Test';
+
+    // Create a content type.
+    $this->createContentType($content_type, $label);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'create ' . $content_type . ' content',
+      'delete any ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+
+      // Locale items.
+      'administer languages',
+      'translate interface',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Load the node form in each locale, confirm it has the fields. This also
+    // preloads the field labels into the locale system.
+    foreach (array('French' => 'fr', 'English' => '') as $lang => $langcode) {
+      $path = 'node/add/' . $content_type_path;
+      if (!empty($langcode)) {
+        $path = $langcode . '/' . $path;
+      }
+
+      // Load the node form in French to prep the translation strings.
+      $this->drupalGet($path);
+      $this->assertResponse(200);
+
+      // Verify the page loaded correctly.
+      // @todo Update this to extract the page title.
+      $this->assertText(strip_tags(t('Create @name', array('@name' => $label))));
+
+      // Confirm the Metatag fields are present.
+      $this->assertField('edit-metatags-und-title-value', 'Found the page title meta tag');
+      $xpath = $this->xpath("//label[@for='edit-metatags-und-title-value']");
+      $this->assertEqual(count($xpath), 1, 'Exactly one page title field found.');
+      // Need to trim() the xpath results because Field API adds a space after
+      // every field's label.
+      $this->assertEqual(trim((string)$xpath[0]), 'Page title');
+
+      $this->assertField('edit-metatags-und-description-value', 'Found the description meta tag');
+      $xpath = $this->xpath("//label[@for='edit-metatags-und-description-value']");
+      $this->assertEqual(count($xpath), 1, 'Exactly one description field found.');
+      // Need to trim() the xpath results because Field API adds a space after
+      // every field's label.
+      $this->assertEqual(trim((string)$xpath[0]), 'Description');
+    }
+
+    // Translate the page title and description fields.
+    $textgroup = 'default';
+    $context = '';
+    $langcode = 'fr';
+    $title_source = 'Page title';
+    $title_target = 'Le page title';
+    $lid = $this->getTranslationLidBySource($title_source, $textgroup);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the page title tag.');
+    $this->saveTranslationString($lid, $context, $langcode, $title_source, $title_target);
+    $desc_source= 'Description';
+    $desc_target = 'Le description';
+    $lid = $this->getTranslationLidBySource($desc_source, $textgroup);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the description tag.');
+    $this->saveTranslationString($lid, $context, $langcode, $desc_source, $desc_target);
+
+    // Clear the metatag_get_info() cache since translated strings have changed.
+    metatag_config_cache_clear();
+
+    // Load the French node form again.
+    $this->drupalGet('fr/node/add/' . $content_type_path);
+    $this->assertResponse(200);
+
+    // Verify the title field's label was translated.
+    $xpath = $this->xpath("//label[@for='edit-metatags-und-title-value']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one page title field found.');
+    // Need to trim() the xpath results because Field API adds a space after
+    // every field's label.
+    $this->assertEqual(trim((string)$xpath[0]), $title_target);
+
+    // Verify the description field's label was translated.
+    $xpath = $this->xpath("//label[@for='edit-metatags-und-description-value']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one description field found.');
+    // Need to trim() the xpath results because Field API adds a space after
+    // every field's label.
+    $this->assertEqual(trim((string)$xpath[0]), $desc_target);
+  }
+
+  /**
+   * Verify language meta tags don't output LANGUAGE_NONE / 'und'.
+   */
+  function testLanguageNone() {
+    // Set the global node defaults to set "content-language" to the node's
+    // language.
+    $config = metatag_config_load('node');
+    $config->config['content-language']['value'] = '[node:language]';
+    metatag_config_save($config);
+
+    // Create a test node.
+    $node = $this->drupalCreateNode();
+    $this->assertEqual($node->language, LANGUAGE_NONE);
+
+    // Load the node page, confirm that the "content-language" meta tag is not
+    // output.
+    $this->drupalGet('node/' . $node->nid);
+    $xpath = $this->xpath("//meta[@http-equiv='content-language']");
+    $this->assertEqual(count($xpath), 0, 'The content-language meta tag was not found.');
+  }
+
+  // @todo Make sure the meta tag fields are displayed in the correct locale.
+  // @todo Make sure the node records are stored with the correct language.
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.node.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.node.test
new file mode 100644
index 0000000000000000000000000000000000000000..6c3bb184ee79359e8168f6ea0fcc9eae448195f6
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.node.test
@@ -0,0 +1,427 @@
+<?php
+
+/**
+ * Tests for the Metatag module and node entities.
+ */
+class MetatagCoreNodeTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for nodes',
+      'description' => 'Test Metatag edit functionality for nodes.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * Tests creation of a standard entity.
+   */
+  public function testEntityCreationWorkflow() {
+    $content_type = 'metatag_test';
+    $content_type_path = str_replace('_', '-', $content_type);
+    $label = 'Test';
+
+    // Create a content type.
+    $this->createContentType($content_type, $label);
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'create ' . $content_type . ' content',
+      'delete any ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+
+      // Used later for revision handling.
+      'view revisions',
+      'revert revisions',
+      'delete revisions',
+
+      // This permission is required in order to create new revisions.
+      'administer nodes',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Assign default values for the new content type.
+
+    // Load the "add default configuration" page.
+    $this->drupalGet('admin/config/search/metatags/config/add');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText(t('Select the type of default meta tags you would like to add.'));
+
+    // Submit the initial form to select an entity bundle.
+    $this->drupalPost(NULL, array(
+      'instance' => 'node:' . $content_type,
+    ), t('Add and configure'));
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText('Node: ' . $label);
+
+    // Submit the form with some values.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[node:title]',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText(strip_tags(t('The meta tag defaults for @label have been saved.', array('@label' => 'Node: ' . $label))));
+
+    // Verify that the user was redirected to the settings page again.
+    $this->assertEqual($this->getUrl(), url('admin/config/search/metatags', array('absolute' => TRUE)));
+
+    // Create a test node.
+
+    // Load the node form.
+    $this->drupalGet('node/add/' . $content_type_path);
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly.
+    // @todo Update this to extract the page title.
+    $this->assertText(strip_tags(t('Create @name', array('@name' => $label))));
+
+    // Verify that it's possible to submit values to the form.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[node:title] ponies',
+      'title' => 'Who likes magic',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // The meta tags that will be checked for.
+    $expected = array(
+      'und' => array(
+        'abstract' => array(
+          'value' => '[node:title] ponies',
+        ),
+      ),
+    );
+
+    // Verify that the node saved correctly.
+    // $xpath = $this->xpath("//h1");
+    $t_args = array('@type' => 'Test', '%title' => 'Who likes magic');
+    // This doesn't work for some reason, it seems the HTML is stripped off
+    // during output so the %title's standard Drupal wrappers don't match.
+    // $this->assertText(t('@type %title has been created.', $t_args));
+    // .. so this has to be done instead.
+    $this->assertText(strip_tags(t('@type %title has been created.', $t_args)));
+
+    // Verify the node data saved correctly.
+    $matches = array();
+    $nid = 0;
+    if (preg_match('@node/(\d+)$@', $this->getUrl(), $matches)) {
+      $nid = end($matches);
+      $node = node_load($nid);
+      $this->verbose($node, 'node_load(' . $nid . ')');
+
+      // Only the non-default values are stored.
+      $this->assertEqual($expected, $node->metatags);
+
+      // Confirm the APIs can load the data for this node.
+      $metatags = metatag_metatags_load('node', $node->nid);
+      $this->verbose($metatags, 'metatag_metatags_load("node", ' . $node->nid . ')');
+      $this->assertEqual($expected, $metatags);
+      $metatags = metatag_metatags_load_multiple('node', array($node->nid));
+      $this->verbose($metatags, 'metatag_metatags_load_multiple("node", array(' . $node->nid . '))');
+      $this->assertEqual(array($node->nid => array($node->vid => $expected)), $metatags);
+
+      // Confirm the APIs can load the data for this node revision.
+      $metatags = metatag_metatags_load('node', $node->nid, $node->vid);
+      $this->verbose($metatags, 'metatag_metatags_load("node", ' . $node->nid . ', ' . $node->vid . ')');
+      $this->assertEqual($expected, $metatags);
+      $metatags = metatag_metatags_load_multiple('node', array($node->nid), array($node->vid));
+      $this->verbose($metatags, 'metatag_metatags_load_multiple("node", array(' . $node->nid . '), array(' . $node->vid . '))');
+      $this->assertEqual(array($node->nid => array($node->vid => $expected)), $metatags);
+    }
+
+    // This shouldn't happen, it indicates a problem.
+    else {
+      $this->fail(t('Could not determine the ID for the created node.'));
+    }
+
+    // Verify the title is using the custom default for this content type.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Who likes magic ponies');
+
+    // Core's canonical tag is a relative URL, whereas Metatag outputs an
+    // absolute URL.
+    $old_canonical = url('node/' . $node->nid);
+    $new_canonical = url('node/' . $node->nid, array('absolute' => TRUE));
+
+    // Confirm that the canonical tag is in the correct format.
+    $xpath = $this->xpath("//link[@rel='canonical']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one canonical meta tag found.');
+    $this->assertEqual($xpath[0]['href'], $new_canonical);
+    $this->assertNotEqual($xpath[0]['href'], $old_canonical);
+
+    // Try loading the node revisions page.
+    $this->drupalGet('node/' . $node->nid . '/revisions');
+    // Verify the page did not load correctly. This is because the revisions
+    // page can't be loaded if there's only one revision.
+    $this->assertResponse(403);
+
+    // Try creating a revision of the node.
+    $old_title = $node->title;
+    $old_vid = $node->vid;
+    $new_title = 'Who still likes magic';
+    // Load the node-edit page.
+    $this->drupalGet('node/' . $node->nid . '/edit');
+    // Verify the page loaded correctly.
+    $this->assertResponse(200);
+    // Try submitting text to the page.
+    $args = array(
+      'metatags[und][abstract][value]' => '[node:title] kittens',
+      'title' => $new_title,
+      'revision' => 1,
+      'log' => 'Creating a new revision',
+    );
+    $this->drupalPost(NULL, $args, t('Save'));
+    // Verify the page submission loaded correctly.
+    $this->assertResponse(200);
+
+    // A new version of the expected results
+    $expected_updated = array(
+      'und' => array(
+        'abstract' => array(
+          'value' => '[node:title] kittens',
+        ),
+      ),
+    );
+
+    // Verify that the node saved correctly.
+    // $xpath = $this->xpath("//h1");
+    $t_args = array('@type' => 'Test', '%title' => $new_title);
+    // This doesn't work for some reason, it seems the HTML is stripped off
+    // during output so the %title's standard Drupal wrappers don't match.
+    // $this->assertText(t('@type %title has been updated.', $t_args));
+    // .. so this has to be done instead.
+    $this->assertText(strip_tags(t('@type %title has been updated.', $t_args)));
+
+    // Verify the title is still using the custom default for this content type.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertNotEqual($xpath[0]['content'], $old_title . ' ponies', 'Did not find the new abstract meta tag.');
+    $this->assertEqual($xpath[0]['content'], $new_title . ' kittens', 'Found the old abstract meta tag.');
+
+    // Load the node revisions page.
+    $this->drupalGet('node/' . $node->nid . '/revisions');
+    // Verify the page loaded correctly.
+    $this->assertResponse(200, 'Loaded the revisions page for this node.');
+
+    // Confirm there are two revisions.
+    $xpath = $this->xpath("//body//div[@class='content']//table//tbody//tr");
+    $this->assertEqual(count($xpath), 2, 'There are two revisions of this node.');
+
+    // Load the previous revision.
+    $this->drupalGet('node/' . $node->nid . '/revisions/' . $old_vid . '/view');
+    // Verify the page loaded correctly.
+    $this->assertResponse(200, 'Loaded the original revision of this node.');
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertNotEqual($xpath[0]['content'], $new_title . ' kittens', 'Did not find the new abstract meta tag.');
+    $this->assertEqual($xpath[0]['content'], $old_title . ' ponies', 'Found the old abstract meta tag.');
+
+    // Load the updated node; force-load it to make sure it's loaded properly.
+    $updated_node = node_load($node->nid, NULL, TRUE);
+    $updated_vid = $updated_node->vid;
+    $this->verbose($updated_node, 'node_load(' . $node->nid . ', NULL, TRUE)');
+
+    // Confirm the APIs can load the data for this node.
+    $metatags = metatag_metatags_load('node', $updated_node->nid);
+    $this->verbose($metatags, 'metatag_metatags_load("node", ' . $updated_node->nid . ')');
+    $this->assertEqual($expected_updated, $metatags);
+    $this->assertNotEqual($expected, $metatags);
+    // This one is complicated. If only the entity id is passed in it will load
+    // the {metatag} records for *all* of the entity's revisions.
+    $metatags = metatag_metatags_load_multiple('node', array($updated_node->nid));
+    $this->verbose($metatags, 'metatag_metatags_load_multiple("node", array(' . $updated_node->nid . '))');
+    $this->assertEqual(array($updated_node->nid => array($node->vid => $expected, $updated_node->vid => $expected_updated)), $metatags);
+
+    // Confirm the APIs can load the data for this node revision.
+    $metatags = metatag_metatags_load('node', $updated_node->nid, $updated_vid);
+    $this->verbose($metatags, 'metatag_metatags_load("node", ' . $updated_node->nid . ', ' . $updated_node->vid . ')');
+    $this->assertEqual($expected_updated, $metatags);
+    $this->assertNotEqual($expected, $metatags);
+    $metatags = metatag_metatags_load_multiple('node', array($updated_node->nid), array($updated_node->vid));
+    $this->verbose($metatags, 'metatag_metatags_load_multiple("node", array(' . $updated_node->nid . '), array(' . $updated_node->vid . '))');
+    $this->assertEqual(array($updated_node->nid => array($updated_node->vid => $expected_updated)), $metatags);
+
+    // Load the current revision again.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200, 'Loaded the current revision of this node.');
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertNotEqual($xpath[0]['content'], $old_title . ' ponies', 'Did not find the old abstract meta tag.');
+    $this->assertEqual($xpath[0]['content'], $new_title . ' kittens', 'Found the new abstract meta tag.');
+
+    // Revert to the original revision.
+    $this->drupalGet('node/' . $node->nid . '/revisions/' . $old_vid . '/revert');
+    // Verify the page loaded correctly.
+    $this->assertResponse(200, 'Loaded the form to revert to the original revision of this node.');
+    // Try submitting the form.
+    $this->drupalPost(NULL, array(), t('Revert'));
+    // Verify the page submission loaded correctly.
+    $this->assertResponse(200);
+    // Confirm there are now three revisions.
+    $xpath = $this->xpath("//body//div[@class='content']//table//tbody//tr");
+    $this->assertEqual(count($xpath), 3, 'There are now three revisions of this node.');
+
+    // Load the current revision, which will now have the old meta tags.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200, 'Loaded the current revision of this node.');
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertNotEqual($xpath[0]['content'], $new_title . ' kittens', 'Did not find the new abstract meta tag.');
+    $this->assertEqual($xpath[0]['content'], $old_title . ' ponies', 'Found the old abstract meta tag again.');
+
+    // Delete the original revision.
+    $this->drupalGet('node/' . $node->nid . '/revisions/' . $old_vid . '/delete');
+    // Verify the page loaded correctly.
+    $this->assertResponse(200, 'Loaded the form to delete the original revision of this node.');
+    // Try submitting the form.
+    $this->drupalPost(NULL, array(), t('Delete'));
+    // Verify the page submission loaded correctly.
+    $this->assertResponse(200);
+    // Confirm there are now two revisions again.
+    $xpath = $this->xpath("//body//div[@class='content']//table//tbody//tr");
+    $this->assertEqual(count($xpath), 2, 'There are two revisions of this node again.');
+
+    // Clear the caches and then load the current revision, just to confirm
+    // that the page is still loading correctly.
+    metatag_config_cache_clear();
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200, 'Loaded the current revision of this node again.');
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertNotEqual($xpath[0]['content'], $new_title . ' kittens', 'Did not find the new abstract meta tag.');
+    $this->assertEqual($xpath[0]['content'], $old_title . ' ponies', 'Found the old abstract meta tag again.');
+
+    // Delete the second revision.
+    $this->drupalGet('node/' . $node->nid . '/revisions/' . $updated_vid . '/delete');
+    // Verify the page loaded correctly.
+    $this->assertResponse(200, 'Loaded the form to delete the second revision of this node.');
+    // Try submitting the form.
+    $this->drupalPost(NULL, array(), t('Delete'));
+    $this->assertResponse(200);
+    // Verify that the revisions page no longer loads because there's only one
+    // revision now.
+    $this->drupalGet('node/' . $node->nid . '/revisions');
+    $this->assertResponse(403, 'No longer able to load the node revisions page.');
+
+    // Clear the caches and then load the current revision, just to confirm
+    // that the page is still loading correctly.
+    metatag_config_cache_clear();
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200, 'Loaded the current revision of this node again.');
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertNotEqual($xpath[0]['content'], $new_title . ' kittens', 'Did not find the new abstract meta tag.');
+    $this->assertEqual($xpath[0]['content'], $old_title . ' ponies', 'Found the old abstract meta tag again.');
+  }
+
+  /**
+   * Tests different 'preview' options. #1: Disabled.
+   */
+  public function testNodePreviewOption0() {
+    $this->checkNodePreviewOption(0);
+  }
+
+  /**
+   * Tests different 'preview' options. #2: Optional, without preview.
+   */
+  public function testNodePreviewOption1NoPreview() {
+    $this->checkNodePreviewOption(1, FALSE);
+  }
+
+  /**
+   * Tests different 'preview' options. #2: Optional, with preview.
+   */
+  public function testNodePreviewOption1Preview() {
+    $this->checkNodePreviewOption(1, TRUE);
+  }
+
+  /**
+   * Tests different 'preview' options. #3: Preview required.
+   */
+  public function testNodePreviewOption2() {
+    $this->checkNodePreviewOption(2);
+  }
+
+  /**
+   * Change the node preview option at the content type level, confirm meta tags
+   * still save correctly.
+   *
+   * @param int $option
+   *   A suitable value for the 'node_preview' option for a content type, must
+   *   be either 0, 1 or 2.
+   * @param bool $preview
+   *   Whether to perform a preview. Has the following implications:
+   *   - if $option === 0, $preview is ignored, no preview is performed.
+   *   - if $option === 1, $preview is considered, a preview may be performed.
+   *   - if $option === 2, $preview is ignored, a preview is performed.
+   */
+  function checkNodePreviewOption($option, $preview = FALSE) {
+    $content_type = 'article';
+    $label = 'Test';
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'create ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+
+      // Required for customizing the node preview option.
+      'administer content types',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Set the node preview mode.
+    $this->drupalGet('admin/structure/types/manage/' . $content_type);
+    $this->assertResponse(200);
+    $edit = array(
+      'node_preview' => $option,
+    );
+    $this->drupalPost(NULL, $edit, t('Save content type'));
+    $this->assertText(strip_tags(t('The content type %name has been updated.', array('%name' => t('Article')))));
+
+    // Create a test node.
+    $this->drupalGet('node/add/' . $content_type);
+    $this->assertResponse(200);
+
+    // Save a custom meta tag.
+    $edit = array(
+      'metatags[und][abstract][value]' => '[node:title] ponies',
+      'title' => 'Who likes magic',
+    );
+
+    // A preview may be optionally performed. Core allows three combinations:
+    // * 0 = Disallowed.
+    // * 1 = Optional.
+    // * 2 = Required.
+    if (($option === 1 && $preview) || $option === 2) {
+      $this->drupalPost(NULL, $edit, t('Preview'));
+      $this->drupalPost(NULL, array(), t('Save'));
+    }
+    else {
+      $this->drupalPost(NULL, $edit, t('Save'));
+    }
+    $this->assertResponse(200);
+
+    // Verify the title is using the custom default for this content type.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Who likes magic ponies');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.node.with_i18n.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.node.with_i18n.test
new file mode 100644
index 0000000000000000000000000000000000000000..424013c8d9bc4453e8ba7f6b64bc79bbb32e8cf0
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.node.with_i18n.test
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Tests for the Metatag module to ensure i18n integration doesn't break.
+ */
+class MetatagCoreNodeWithI18nTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core node tests with i18n',
+      'description' => 'Test Metatag node config integration with the i18n module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need the i18n and i18n_strings modules.
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable all of the modules that are needed.
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      // From i18n.
+      'translate admin strings',
+      'translate user-defined strings',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+  /**
+   * Test translations of the main node configuration.
+   */
+  public function testI18nNodeConfig() {
+    // Plan out the different translation string tests.
+    $string_en = 'It is a node page!';
+    $config_name = 'metatag_config:node:title';
+
+    // Confirm the translation page exists and has some Metatag strings.
+    $this->searchTranslationPage('', $config_name);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Load the meta tags.
+    $instance = 'node';
+    $config = metatag_config_load($instance);
+
+    // Set something specific as the homepage.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the node's title.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the node title tag.');
+  }
+
+  /**
+   * Test translations of the 'page' content type configuration.
+   */
+  public function testI18nNodePageConfig() {
+    // Plan out the different translation string tests.
+    $string_en = 'It is a node page page!';
+    $config_name = 'metatag_config:node:page:title';
+
+    // Confirm the translation page exists and has some Metatag strings.
+    $this->searchTranslationPage('', $config_name);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Create a new config object for the node:page structure.
+    $config = new StdClass();
+    $config->instance = 'node:page';
+
+    // Set an example tag.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the node's title.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the node title tag.');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.output_caching.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.output_caching.test
new file mode 100644
index 0000000000000000000000000000000000000000..dc637b6fac1dd11f206bfdedc87f3a05bd53e885
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.output_caching.test
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * Tests for the Metatag module's output caching
+ */
+class MetatagCoreOutputCachingTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag: output caching',
+      'description' => 'Test the output caching functionality in Metatag.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * Test how user tokens are handled when cache is enabled.
+   */
+  public function testUserTokensCacheEnabled() {
+    // Enable output caching.
+    variable_set('metatag_cache_output', TRUE);
+
+    // Create two user accounts.
+    $account1 = $this->drupalCreateUser();
+    $account2 = $this->drupalCreateUser();
+
+    // Log in the first account.
+    $this->drupalLogin($account1);
+
+    // Load the test page.
+    $this->drupalGet('account-test-page');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly and has the correct title.
+    $this->assertText('Test page for user tokens.');
+    $this->assertText('Hello ' . $account1->name);
+    $xpath = $this->xpath("//h1");
+    $this->verbose($xpath);
+    $this->assertEqual(trim((string)$xpath[0]), 'Hello ' . $account1->name);
+
+    // Confirm the page title itself.
+    $this->assertTitle('Hello ' . $account1->name . ' | Drupal');
+
+    // Log out the user.
+    $this->drupalLogout().
+
+    // Log in the second account.
+    $this->drupalLogin($account2);
+
+    // Load the test page.
+    $this->drupalGet('account-test-page');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly and now shows the second user account's
+    // name on the page.
+    $this->assertText('Test page for user tokens.');
+    $this->assertText('Hello ' . $account2->name);
+    $xpath = $this->xpath("//h1");
+    $this->verbose($xpath);
+    $this->assertEqual(trim((string)$xpath[0]), 'Hello ' . $account2->name);
+
+    // Confirm the page title has not been updated, which is as designed.
+    $this->assertTitle('Hello ' . $account1->name . ' | Drupal');
+    $this->assertNoTitle('Hello ' . $account2->name . ' | Drupal');
+  }
+
+  /**
+   * Test how user tokens are handled when cache is Disabled.
+   */
+  public function testUserTokensCacheDisabled() {
+    // Disable output caching.
+    variable_set('metatag_cache_output', FALSE);
+
+    // Create two user accounts.
+    $account1 = $this->drupalCreateUser();
+    $account2 = $this->drupalCreateUser();
+
+    // Log in the first account.
+    $this->drupalLogin($account1);
+
+    // Load the test page.
+    $this->drupalGet('account-test-page');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly and has the correct title.
+    $this->assertText('Test page for user tokens.');
+    $this->assertText('Hello ' . $account1->name);
+    $xpath = $this->xpath("//h1");
+    $this->verbose($xpath);
+    $this->assertEqual(trim((string)$xpath[0]), 'Hello ' . $account1->name);
+
+    // Confirm the page title itself.
+    $this->assertTitle('Hello ' . $account1->name . ' | Drupal');
+
+    // Log out the user.
+    $this->drupalLogout().
+
+    // Log in the second account.
+    $this->drupalLogin($account2);
+
+    // Load the test page.
+    $this->drupalGet('account-test-page');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly and now shows the second user account's
+    // name on the page.
+    $this->assertText('Test page for user tokens.');
+    $this->assertText('Hello ' . $account2->name);
+    $xpath = $this->xpath("//h1");
+    $this->verbose($xpath);
+    $this->assertEqual(trim((string)$xpath[0]), 'Hello ' . $account2->name);
+
+    // Confirm the page title has changed, i.e. it shows the second account name
+    // rather than the first.
+    $this->assertNoTitle('Hello ' . $account1->name . ' | Drupal');
+    $this->assertTitle('Hello ' . $account2->name . ' | Drupal');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.string_handling.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.string_handling.test
new file mode 100644
index 0000000000000000000000000000000000000000..37933acbade544cc6ed1e5250ba7b32407610270
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.string_handling.test
@@ -0,0 +1,271 @@
+<?php
+
+/**
+ * Tests for Metatag's string handling.
+ */
+class MetatagCoreStringHandlingTest extends MetatagTestHelper {
+
+  /**
+   * @var $admin_user
+   *   An admin user.
+   */
+  protected $admin_user;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for string handling',
+      'description' => "Tests Metatag's string handling.",
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules);
+
+    $content_type = 'page';
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'create ' . $content_type . ' content',
+      'delete any ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+
+      // This permission is required in order to create new revisions.
+      'administer nodes',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Tests that a meta tag with single quote is not double escaped.
+   */
+  function testSingleQuote() {
+    $this->_testAString("bla'bleblu");
+  }
+
+  /**
+   * Tests that a meta tag with a double quote is not double escaped.
+   */
+  function testDoubleQuote() {
+    $this->_testAString('bla"bleblu');
+  }
+
+  /**
+   * Tests that a meta tag with an ampersand is not double escaped.
+   */
+  function testAmpersand() {
+    $this->_testAString("blable&blu");
+  }
+
+  /**
+   * Tests that specific strings are not double escaped.
+   */
+  function _testAString($string) {
+    $this->_testConfig($string);
+    $this->_testNode($string);
+    $this->_testEncodedField($string);
+  }
+
+  /**
+   * Tests that a specific config string is not double encoded.
+   */
+  function _testConfig($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);
+
+    // Test the front page.
+    $instance = 'global:frontpage';
+
+    // Save the main node configuration form to assign the description tag.
+    $edit = array(
+      // Just use [node:title] to avoid problems with the default suffix.
+      'metatags[und][title][value]' => $title_original,
+      // Save the original string.
+      'metatags[und][description][value]' => $desc_original,
+    );
+    $this->drupalPost('admin/config/search/metatags/config/' . $instance, $edit, 'Save');
+    $this->assertResponse(200);
+
+    // Load the configuration object.
+    $result = db_select('metatag_config', 'mc')
+      ->fields('mc', array('config'))
+      ->condition('mc.instance', $instance)
+      ->execute()
+      ->fetchAssoc();
+
+    // Unserialize the configuration.
+    $config = unserialize($result['config']);
+
+    // Make sure the title tag is stored correctly.
+    $this->assertEqual($title_original, $config['title']['value'], 'The title tag was stored in its original format.');
+    $this->assertNotEqual($title_encoded, $config['title']['value'], 'The title tag was not stored in an encoded format.');
+    $this->assertNotEqual($title_encodeded, $config['title']['value'], 'The title tag was not stored in a double-encoded format.');
+
+    // Make sure the description tag is stored correctly.
+    $this->assertEqual($desc_original, $config['description']['value'], 'The description tag was stored in its original format.');
+    $this->assertNotEqual($desc_encoded, $config['description']['value'], 'The description tag was not stored in an encoded format.');
+    $this->assertNotEqual($desc_encodeded, $config['description']['value'], 'The description tag was not stored in a double-encoded format.');
+
+    // Load the front page.
+    $this->drupalGet('<front>');
+    $this->assertResponse(200);
+
+    // assertTitle() uses xpath, which parses the HTML, so all of the HTML
+    // entities will be converted automagically.
+    $this->assertTitle($title_original, 'Confirmed the node title tag is available in its original format.');
+    $this->assertNoTitle($title_encoded, 'Confirmed the node title tag is not double-encoded.');
+    $this->assertNoTitle($title_encodeded, 'Confirmed the node title tag is not double-double-encoded?');
+
+    // 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_original . '</title>', 'Confirmed the node title tag is available in its original format.');
+    $this->assertNoRaw('<title>' . $title_encoded . '</title>', 'Confirmed the node title tag is not double-encoded.');
+    $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.
+   */
+  function _testNode($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);
+
+    // Create a node and check how the meta tag is displayed.
+    $node = $this->drupalCreateNode(array(
+      'title' => $title_original,
+      'body' => array(
+        LANGUAGE_NONE => array(
+          array(
+            'value' => $desc_original,
+            'format' => filter_default_format(),
+          ),
+        ),
+      ),
+      'metatags' => array(
+        LANGUAGE_NONE => array(
+          'abstract' => array('value' => '[node:title]'),
+        ),
+      ),
+    ));
+
+    // Page titles have a suffix added automatically.
+    $suffix = ' | ' . variable_get('site_name', 'Drupal');
+
+    // Load the node page.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // assertTitle() uses xpath, which parses the HTML, so all of the HTML
+    // entities will be converted automagically.
+    $this->assertTitle($title_original . $suffix, 'Confirmed the node title tag is available in its original format.');
+    $this->assertNoTitle($title_encoded . $suffix, 'Confirmed the node title tag is not double-encoded.');
+    $this->assertNoTitle($title_encodeded . $suffix, 'Confirmed the node title tag is not double-double-encoded?');
+
+    // 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_original . $suffix . '</title>', 'Confirmed the node title tag is encoded.');
+
+    // Test a few other versions of the title, to ensure it isn't broken
+    // on another tag.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual($xpath[0]['content'], $title_original);
+    $this->assertNotEqual($xpath[0]['content'], $title_encoded);
+    $this->assertNotEqual($xpath[0]['content'], $title_encodeded);
+
+    // 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);
+
+    // 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.
+   */
+  function _testEncodedField($string) {
+    // 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);
+
+    // Create a node and check how the meta tag is displayed.
+    $node = $this->drupalCreateNode(array(
+      'title' => $title_original,
+      'body' => array(
+        LANGUAGE_NONE => array(
+          array(
+            'value' => $desc_encoded,
+            'format' => filter_default_format(),
+          ),
+        ),
+      ),
+    ));
+
+    // Load the node page.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // 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);
+
+    // 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/profiles/wcm_base/modules/contrib/metatag/tests/metatag.string_handling_with_i18n.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.string_handling_with_i18n.test
new file mode 100644
index 0000000000000000000000000000000000000000..f2cdd02ddd8e5535971fef6e4e08ebe8d6388826
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.string_handling_with_i18n.test
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * Tests for Metatag's string handling when the i18n module is enabled.
+ */
+class MetatagCoreStringHandlingWithI18nTest extends MetatagCoreStringHandlingTest {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for string handling w i18n',
+      'description' => "Tests Metatag's string handling when i18n is enabled.",
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp(array('i18n', 'i18n_string'));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.tags.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.tags.test
new file mode 100644
index 0000000000000000000000000000000000000000..3c4dc860110cf90251bbfa0267aa1df1ba2661c1
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.tags.test
@@ -0,0 +1,291 @@
+<?php
+
+/**
+ * Tests that each of the Metatag base tags work correctly.
+ */
+class MetatagTagsTest extends MetatagTagsTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag tags: Basic',
+      'description' => 'Test the basic meta tags.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public $tags = array(
+    'abstract',
+    'cache-control',
+    'canonical',
+    'content-language',
+    'description',
+    'expires',
+    'generator',
+    'geo.placename',
+    'geo.position',
+    'geo.region',
+    'icbm',
+    'image_src',
+    'keywords',
+    'news_keywords',
+    'next',
+    'original-source',
+    'pragma',
+    'prev',
+    'rating',
+    'referrer',
+    'refresh',
+    // @todo 'revisit-after',
+    'rights',
+    'robots',
+    'shortlink',
+    'standout',
+    'title',
+  );
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'abstract'.
+   */
+  public function abstract_test_field_xpath() {
+    return "//textarea[@name='metatags[und][abstract][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'cache_control'.
+   */
+  public function cache_control_test_output_xpath() {
+    return "//meta[@http-equiv='cache-control']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'canonical'.
+   */
+  public function canonical_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'canonical'.
+   */
+  public function canonical_test_output_xpath() {
+    return "//link[@rel='canonical']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_name_attribute() for 'content_language'.
+   */
+  public function content_language_test_name_attribute() {
+    return 'http-equiv';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_tag_name() for 'content_language'.
+   */
+  public function content_language_test_tag_name() {
+    return 'content-language';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'description'.
+   */
+  public function description_test_field_xpath() {
+    return "//textarea[@name='metatags[und][description][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_tag_name() for 'geo_placename'.
+   */
+  public function geo_placename_test_tag_name() {
+    return 'geo.placename';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_tag_name() for 'geo_position'.
+   */
+  public function geo_position_test_tag_name() {
+    return 'geo.position';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_tag_name() for 'geo_region'.
+   */
+  public function geo_region_test_tag_name() {
+    return 'geo.region';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'image_src'.
+   */
+  public function image_src_test_output_xpath() {
+    return "//link[@rel='image_src']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'image_src'.
+   */
+  public function image_src_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'image_src'.
+   */
+  public function image_src_test_value() {
+    return 'http://example.com/images/test-image.gif';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'next'.
+   */
+  public function next_test_output_xpath() {
+    return "//link[@rel='next']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'next'.
+   */
+  public function next_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_tag_name() for 'original-source'.
+   */
+  public function original_source_test_tag_name() {
+    return 'original-source';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_name_attribute() for 'pragma'.
+   */
+  public function pragma_test_name_attribute() {
+    return 'http-equiv';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'prev'.
+   */
+  public function prev_test_output_xpath() {
+    return "//link[@rel='prev']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'prev'.
+   */
+  public function prev_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_key() for 'rating'.
+   */
+  public function rating_test_key() {
+    return 'metatags[und][rating][value]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'general'.
+   */
+  public function rating_test_value() {
+    return 'general';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'rating'.
+   */
+  public function rating_test_field_xpath() {
+    return "//select[@name='metatags[und][rating][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_key() for 'referrer'.
+   */
+  public function referrer_test_key() {
+    return 'metatags[und][referrer][value]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'referrer'.
+   */
+  public function referrer_test_value() {
+    return 'origin';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'referrer'.
+   */
+  public function referrer_test_field_xpath() {
+    return "//select[@name='metatags[und][referrer][value]']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_name_attribute() for 'refresh'.
+   */
+  public function refresh_test_name_attribute() {
+    return 'http-equiv';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'robots'.
+   */
+  public function robots_test_key() {
+    return 'metatags[und][robots][value][index]';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'robots'.
+   */
+  public function robots_test_value() {
+    return TRUE;
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_field_xpath() for 'robots'.
+   */
+  public function robots_test_field_xpath() {
+    return "//input[@name='metatags[und][robots][value][index]' and @type='checkbox']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value() for 'revisit-after'.
+   */
+  public function revisit_after_test_value() {
+    return 2;
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'shortlink'.
+   */
+  public function shortlink_test_output_xpath() {
+    return "//link[@rel='shortlink']";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'shortlink'.
+   */
+  public function shortlink_test_value_attribute() {
+    return 'href';
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_output_xpath() for 'title'.
+   */
+  public function title_test_output_xpath() {
+    return "//title";
+  }
+
+  /**
+   * Implements {meta_tag_name}_test_value_attribute() for 'title';
+   */
+  public function title_test_value_attribute() {
+    return '';
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.tags_helper.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.tags_helper.test
new file mode 100644
index 0000000000000000000000000000000000000000..832e88cef768d854b01366f533f3d311cdc765d8
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.tags_helper.test
@@ -0,0 +1,261 @@
+<?php
+
+/**
+ * Base class for testing a module's custom tags.
+ */
+abstract class MetatagTagsTestBase extends MetatagTestHelper {
+
+  /**
+   * All of the meta tags defined by this module which will be tested.
+   */
+  public $tags = array();
+
+  /**
+   * The tag to look for when testing the output.
+   */
+  public $test_tag = 'meta';
+
+  /**
+   * The attribute to look for to indicate which tag.
+   */
+  public $test_name_attribute = 'name';
+
+  /**
+   * The attribute to look for when testing the output.
+   */
+  public $test_value_attribute = 'content';
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'metatag_test';
+    parent::setUp($modules);
+
+    // Create an admin user that can manage meta tags.
+    $account = $this->createAdminUser();
+    $this->drupalLogin($account);
+  }
+
+  /**
+   * Tests that this module's tags are available.
+   */
+  function testTagsArePresent() {
+    // Load the global config.
+    $this->drupalGet('admin/config/search/metatags/config/global');
+    $this->assertResponse(200);
+
+    // Confirm the various meta tags are available.
+    foreach ($this->tags as $tag) {
+      // Convert tag names to something more suitable for a function name.
+      $tag_name = str_replace(array('.', '-', ':'), '_', $tag);
+
+      // Look for a custom method named "{$tag_name}_test_field_xpath", 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 = "{$tag_name}_test_field_xpath";
+      if (method_exists($this, $method)) {
+        $xpath = $this->$method();
+      }
+      else {
+        $xpath = "//input[@name='metatags[und][{$tag}][value]' and @type='text']";
+      }
+      $this->assertFieldByXPath($xpath, NULL, format_string('The "%tag" tag field was found.', array('%tag' => $tag)));
+    }
+  }
+
+  /**
+   * Confirm that each tag can be saved and that the output of each tag is
+   * correct.
+   */
+  function testTagsInputOutput() {
+    // Load the global config.
+    $this->drupalGet('admin/config/search/metatags/config/global');
+    $this->assertResponse(200);
+
+    // Update the Global defaults and test them.
+    $all_values = $values = array();
+    foreach ($this->tags as $tag_raw) {
+      // Convert tag names to something more suitable for a function name.
+      $tag_name = str_replace(array('.', '-', ':', ' '), '_', $tag_raw);
+
+      // Look for a custom method named "{$tag_name}_test_key", if found use
+      // that method to get the test string for this meta tag, otherwise it
+      // defaults to the meta tag's name.
+      $method = "{$tag_name}_test_key";
+      if (method_exists($this, $method)) {
+        $test_key = $this->$method();
+      }
+      else {
+        $test_key = "metatags[und][{$tag_raw}][value]";
+      }
+
+      // Look for a custom method named "{$tag_name}_test_value", if found use
+      // that method to get the test string for this meta tag, otherwise it
+      // defaults to just generating a random string.
+      $method = "{$tag_name}_test_value";
+      if (method_exists($this, $method)) {
+        $test_value = $this->$method();
+      }
+      else {
+        // Generate a random string.
+        $test_value = $this->getTestTagValue();
+      }
+
+      $values[$test_key] = $test_value;
+
+      // Look for a custom method named "{$tag_name}_test_preprocess_output", if
+      // found use that method provide any additional processing on the value
+      // e.g. adding a prefix.
+      $method = "{$tag_name}_test_preprocess_output";
+      if (method_exists($this, $method)) {
+        $test_value = $this->$method($test_value);
+      }
+
+      $all_values[$tag_name] = $test_value;
+    }
+    $this->drupalPost(NULL, $values, 'Save');
+    $this->assertText(strip_tags(t('The meta tag defaults for @label have been saved.', array('@label' => 'Global'))));
+
+    // Load the test page.
+    $this->drupalGet('moosqueakoinkmeow');
+    $this->assertResponse(200);
+    $this->assertText(t('Test page.'));
+
+    // Look for the values.
+    foreach ($this->tags as $tag_raw) {
+      // Convert tag names to something more suitable for a function name.
+      $tag_name = str_replace(array('.', '-', ':', ' '), '_', $tag_raw);
+
+      // Verify this meta tag was output.
+      $this->assertTrue(!empty($all_values[$tag_name]));
+
+      // Look for a custom method named "{$tag_name}_test_output_xpath", 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:
+      // <$test_tag $test_name_attribute=$tag_name $test_value_attribute=$value />
+      $method = "{$tag_name}_test_output_xpath";
+      if (method_exists($this, $method)) {
+        $xpath_string = $this->$method();
+      }
+      else {
+        // Look for a custom method named "{$tag_name}_test_tag", if
+        // found use that method to get the xpath definition for this meta tag,
+        // otherwise it defaults to $this->test_tag.
+        $method = "{$tag_name}_test_tag";
+        if (method_exists($this, $method)) {
+          $xpath_tag = $this->$method();
+        }
+        else {
+          $xpath_tag = $this->test_tag;
+        }
+
+        // Look for a custom method named "{$tag_name}_test_name_attribute", if
+        // found use that method to get the xpath definition for this meta tag,
+        // otherwise it defaults to $this->test_name_attribute.
+        $method = "{$tag_name}_test_name_attribute";
+        if (method_exists($this, $method)) {
+          $xpath_name_attribute = $this->$method();
+        }
+        else {
+          $xpath_name_attribute = $this->test_name_attribute;
+        }
+
+        // Look for a custom method named "{$tag_name}_test_tag_name", if
+        // found use that method to get the xpath definition for this meta tag,
+        // otherwise it defaults to $tag_name.
+        $method = "{$tag_name}_test_tag_name";
+        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}']";
+      }
+
+      // Something should have been found.
+      $this->assertTrue(!empty($xpath_string));
+
+      // Look for a custom method named "{$tag_name}_test_value_attribute", if
+      // found use that method to get the xpath definition for this meta tag,
+      // otherwise it defaults to $this->test_value_attribute.
+      $method = "{$tag_name}_test_value_attribute";
+      if (method_exists($this, $method)) {
+        $xpath_value_attribute = $this->$method();
+      }
+      else {
+        $xpath_value_attribute = $this->test_value_attribute;
+      }
+
+      // Extract the meta tag from the HTML.
+      $xpath = $this->xpath($xpath_string);
+      $this->assertEqual(count($xpath), 1, format_string('One @name tag found.', array('@name' => $tag_name)));
+
+      // 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.");
+      }
+    }
+  }
+
+  /**
+   * 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.
+   */
+  public 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.
+   */
+  public function getTestTagValue() {
+    return $this->randomMachineName() . ' ' . $this->randomMachineName();
+  }
+
+  /**
+   * Generate a URL for an image.
+   *
+   * @return string
+   *   An absolute URL to a non-existant image.
+   */
+  public function randomImageUrl() {
+    return 'http://www.example.com/images/'  . $this->randomMachineName() . '.png';
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.term.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.term.test
new file mode 100644
index 0000000000000000000000000000000000000000..460eb232a055ebf328e9e970dec46588bb98258f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.term.test
@@ -0,0 +1,166 @@
+<?php
+
+/**
+ * Tests for the Metatag module and taxonomy term entities.
+ */
+class MetatagCoreTermTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for terms',
+      'description' => 'Test Metatag edit functionality for terms.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need the Path module to set a alias which can then be loaded.
+    $modules[] = 'path';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Tests creation of a standard entity.
+   */
+  public function testEntityCreationWorkflow() {
+    $content_type = 'metatag_test';
+    $content_type_path = str_replace('_', '-', $content_type);
+    $content_type_label = 'Test';
+    $vocab_name = 'test_vocab';
+    $term_name = 'Who likes magic';
+    $term_path = 'term-test';
+
+    // Create a content type.
+    $this->createContentType($content_type, $content_type_label);
+
+    // Create a vocabulary.
+    $vocabulary = $this->createVocabulary($vocab_name, $content_type);
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'create ' . $content_type . ' content',
+      'delete any ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+
+      // Needed for the vocabulary.
+      'administer taxonomy',
+      'edit terms in ' . $vocabulary->vid,
+      'delete terms in ' . $vocabulary->vid,
+
+      // Needed for the Path module.
+      'create url aliases',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Assign default values for the new vocabulary.
+
+    // Load the "add default configuration" page.
+    $this->drupalGet('admin/config/search/metatags/config/add');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText(t('Select the type of default meta tags you would like to add.'));
+
+    // Submit the initial form to select an entity bundle.
+    $this->drupalPost(NULL, array(
+      'instance' => 'taxonomy_term:' . $vocabulary->name,
+    ), t('Add and configure'));
+    $this->assertResponse(200);
+
+    // @todo Update this to extract the H1 tag.
+    $this->assertText(strip_tags('Taxonomy term: ' . $vocabulary->name));
+
+    // Submit the form with some values.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[term:name]',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText(strip_tags(t('The meta tag defaults for @label have been saved.', array('@label' => 'Taxonomy term: ' . $vocabulary->name))));
+
+    // Verify that the user was redirected to the settings page again.
+    $this->assertEqual($this->getUrl(), url('admin/config/search/metatags', array('absolute' => TRUE)));
+
+    // Create a test term.
+
+    // Load the term form.
+    $this->drupalGet('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly.
+    // @todo Update this to extract the H1 tag.
+    // $this->assertText(strip_tags(t('Create @name', array('@name' => $vocabulary->name))));
+
+    // Verify that it's possible to submit values to the form.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[term:name] ponies',
+      'name' => $term_name,
+      'path[alias]' => $term_path,
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify that the node saved correctly.
+    $t_args = array('%name' => $term_name);
+    // This doesn't work for some reason, it seems the HTML is stripped off
+    // during output so the %name's standard Drupal wrappers don't match.
+    // $this->assertText(t('Created new term %name.', $t_args));
+    // .. so this has to be done instead.
+    $this->assertText(strip_tags(t('Created new term %name.', $t_args)));
+
+    // Verify the term data saved correctly.
+    $this->drupalGet($term_path);
+    $this->assertResponse(200);
+
+    // Try to extract the 'edit' link.
+    $xpaths = $this->xpath("//ul/li/a");
+    $matches = array();
+    $tid = 0;
+    if (!empty($xpaths)) {
+      foreach ($xpaths as $xpath) {
+        $attributes = $xpath->attributes();
+        if (!empty($attributes['href'])) {
+          if (preg_match('@taxonomy/term/(\d+)/edit$@', $attributes['href'], $matches)) {
+            $tid = $matches[1];
+          }
+        }
+      }
+    }
+
+    // Presuing a term ID was found, load the term.
+    if (!empty($tid)) {
+      $term = taxonomy_term_load($tid);
+
+      // Only the non-default values are stored.
+      $expected = array(
+        'und' => array(
+          'abstract' => array(
+            'value' => '[term:name] ponies',
+          ),
+        ),
+      );
+      $this->assertEqual($expected, $term->metatags);
+    }
+
+    // This shouldn't happen, it indicates a problem.
+    else {
+      $this->fail(t('Could not determine the ID for created term.'));
+    }
+
+    // Verify the title is using the custom default for this vocabulary.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], "Who likes magic ponies");
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.term.with_i18n.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.term.with_i18n.test
new file mode 100644
index 0000000000000000000000000000000000000000..91070c91eb20845502de2ff0e318497a9f2f1b83
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.term.with_i18n.test
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Tests for the Metatag module to ensure i18n integration doesn't break.
+ */
+class MetatagCoreTermWithI18nTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core term tests with i18n',
+      'description' => 'Test Metatag taxonomy config integration with the i18n module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need the i18n and i18n_strings modules.
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable all of the modules that are needed.
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      // From i18n.
+      'translate admin strings',
+      'translate user-defined strings',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+  /**
+   * Test translations of the main taxonomy term configuration.
+   */
+  public function testI18nTermConfig() {
+    // Plan out the different translation string tests.
+    $string_en = 'It is a term page!';
+    $config_name = 'metatag_config:taxonomy_term:title';
+
+    // Confirm the translation page exists and has some Metatag strings.
+    $this->searchTranslationPage('', $config_name);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Load the meta tags.
+    $instance = 'taxonomy_term';
+    $config = metatag_config_load($instance);
+
+    // Set something specific as the homepage.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the term's title.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the taxonomy term title tag.');
+  }
+
+  /**
+   * Test translations of the 'tags' vocabulary configuration.
+   */
+  public function testI18nTermTagsConfig() {
+    // Plan out the different translation string tests.
+    $string_en = 'It is a taxonomy term Tags page!';
+    $config_name = 'metatag_config:taxonomy_term:tags:title';
+
+    // Confirm the translation page exists and has some Metatag strings.
+    $this->searchTranslationPage('', $config_name);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Create a new config object for the taxonomy_term:tags structure.
+    $config = new StdClass();
+    $config->instance = 'taxonomy_term:tags';
+
+    // Set an example tag.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the term's title.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the taxonomy term title tag.');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.unit.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.unit.test
new file mode 100644
index 0000000000000000000000000000000000000000..ec2d6fce63dadf998166363760a6e3b66ae80958
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.unit.test
@@ -0,0 +1,142 @@
+<?php
+
+/**
+ * Unit tests for the Metatag module.
+ *
+ * @todo These aren't really unit tests, we might need to fix that.
+ */
+class MetatagCoreUnitTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag unit tests',
+      'description' => 'Test basic meta tag functionality for entities.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * Test the metatag_config_load_with_defaults() function.
+   */
+  public function testConfigLoadDefaults() {
+    // Load the global defaults, inc the fake entity.
+    $defaults = metatag_config_load_with_defaults('test:foo');
+
+    // Load the example values and verify they're the same as the globals.
+    $extra_tags = array(
+      // Fake meta tag.
+      'test:foo' => array('value' => 'foobar'),
+    );
+    $new_values = array_merge($extra_tags, $this->getTestDefaults());
+
+    // Confirm that the values are equal.
+    $this->assertEqual($defaults, $new_values);
+  }
+
+  /**
+   * Test the basic entity handling.
+   */
+  public function testEntitySupport() {
+    $test_cases[1] = array('type' => 'node', 'bundle' => 'article', 'expected' => TRUE);
+    $test_cases[2] = array('type' => 'node', 'bundle' => 'page', 'expected' => TRUE);
+    $test_cases[3] = array('type' => 'node', 'bundle' => 'invalid-bundle', 'expected' => FALSE);
+    $test_cases[4] = array('type' => 'user', 'expected' => TRUE);
+    $test_cases[5] = array('type' => 'taxonomy_term', 'bundle' => 'tags', 'expected' => TRUE);
+    $test_cases[6] = array('type' => 'taxonomy_term', 'bundle' => 'invalid-bundle', 'expected' => FALSE);
+    foreach ($test_cases as $test_case) {
+      $test_case += array('bundle' => NULL);
+      $this->assertMetatagEntitySupportsMetatags($test_case['type'], $test_case['bundle'], $test_case['expected']);
+    }
+
+    // Disable meta tags for these.
+    metatag_entity_type_disable('node', 'page');
+    metatag_entity_type_disable('user');
+
+    $test_cases[2]['expected'] = FALSE;
+    $test_cases[4]['expected'] = FALSE;
+    $test_cases[6]['expected'] = FALSE;
+    foreach ($test_cases as $test_case) {
+      $test_case += array('bundle' => NULL);
+      $this->assertMetatagEntitySupportsMetatags($test_case['type'], $test_case['bundle'], $test_case['expected']);
+    }
+  }
+
+  /**
+   * Confirm an entity supports meta tags.
+   *
+   * @param string $entity_type
+   *   The name of the entity type to test.
+   * @param string $bundle
+   *   The name of the entity bundle to test.
+   * @param array $expected
+   *   The expected results.
+   *
+   * @return object
+   *   An assertion.
+   */
+  function assertMetatagEntitySupportsMetatags($entity_type, $bundle, $expected) {
+    $entity = entity_create_stub_entity($entity_type, array(0, NULL, $bundle));
+    return $this->assertEqual(
+      metatag_entity_supports_metatags($entity_type, $bundle),
+      $expected,
+      t("metatag_entity_supports_metatags(:type, :bundle) is :expected", array(
+        ':type' => var_export($entity_type, TRUE),
+        ':bundle' => var_export($bundle, TRUE),
+        ':expected' => var_export($expected, TRUE),
+      ))
+    );
+  }
+
+  /**
+   * Test the metatag_config_instance_label() function.
+   */
+  public function testConfigLabels() {
+    $test_cases = array(
+      'node' => 'Node',
+      'node:article' => 'Node: Article',
+      'node:article:c' => 'Node: Article: Unknown (c)',
+      'node:b' => 'Node: Unknown (b)',
+      'node:b:c' => 'Node: Unknown (b): Unknown (c)',
+      'a' => 'Unknown (a)',
+      'a:b' => 'Unknown (a): Unknown (b)',
+      'a:b:c' => 'Unknown (a): Unknown (b): Unknown (c)',
+      'a:b:c:d' => 'Unknown (a): Unknown (b): Unknown (c): Unknown (d)',
+    );
+
+    foreach ($test_cases as $input => $expected_output) {
+      drupal_static_reset('metatag_config_instance_label');
+      $actual_output = metatag_config_instance_label($input);
+      $this->assertEqual($actual_output, $expected_output);
+    }
+  }
+
+  /**
+   * Test the _metatag_config_instance_sort() function.
+   */
+  public function testConfigInstanceSort() {
+    $input = array(
+      'node:article',
+      'global:frontpage',
+      'file',
+      'node:page',
+      'global',
+      'node',
+      'global:404',
+    );
+    usort($input, '_metatag_config_instance_sort');
+    $this->assertIdentical($input, array(
+      'global',
+      'global:404',
+      'global:frontpage',
+      'file',
+      'node',
+      'node:article',
+      'node:page',
+    ));
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.user.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.user.test
new file mode 100644
index 0000000000000000000000000000000000000000..ea083a3cef57dbc888e5d376466870c50c1c9812
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.user.test
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * Tests for the Metatag module of user entities.
+ */
+class MetatagCoreUserTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for users',
+      'description' => 'Test Metatag edit functionality for users.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token'),
+    );
+  }
+
+  /**
+   * Tests creation of a standard entity.
+   */
+  public function testEntityCreationWorkflow() {
+    // Create an admin user and log them in.
+    if (!isset($this->adminUser)) {
+      $this->adminUser = $this->createAdminUser();
+    }
+    $this->drupalLogin($this->adminUser);
+
+    // Assign default values for the new vocabulary.
+
+    // Load the page for overriding the User configuration.
+    $this->drupalGet('admin/config/search/metatags/config/user');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    // @todo Update this to extract the H1 tag.
+    $this->assertText(strip_tags('User'));
+
+    // Submit the form with some values.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[user:name]',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText(strip_tags(t('The meta tag defaults for @label have been saved.', array('@label' => 'User'))));
+
+    // Verify that the user was redirected to the settings page again.
+    $this->assertEqual($this->getUrl(), url('admin/config/search/metatags', array('absolute' => TRUE)));
+
+    // Load the user's edit form.
+    $this->drupalGet('user/' . $this->adminUser->uid . '/edit');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly.
+    // @todo Update this to extract the H1 tag.
+    // $this->assertText(strip_tags(t('Create @name', array('@name' => $vocabulary->name))));
+
+    // Verify that it's possible to submit values to the form.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[user:name] ponies',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify that the user object saved correctly.
+    // $t_args = array('%name' => $this->adminUser->name);
+    // This doesn't work for some reason, it seems the HTML is stripped off
+    // during output so the %name's standard Drupal wrappers don't match.
+    // $this->assertText(t('The changes have been saved.'));
+    // .. so this has to be done instead.
+    $this->assertText(strip_tags(t('The changes have been saved.')));
+
+    // Manually load the admin account.
+    $account = user_load($this->adminUser->uid);
+
+    // Only the non-default values are stored.
+    $expected = array(
+      'und' => array(
+        'abstract' => array(
+          'value' => '[user:name] ponies',
+        ),
+      ),
+    );
+    $this->assertEqual($expected, $account->metatags);
+
+    // Confirm the user profile tags work correctly.
+    $this->assertUserEntityTags($this->adminUser);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_config.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_config.test
new file mode 100644
index 0000000000000000000000000000000000000000..dcf7cf70dfd38520b8064bf35dbca737ef5bfcb4
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_config.test
@@ -0,0 +1,326 @@
+<?php
+
+/**
+ * Tests for Metatag's i18n integration for the configurations.
+ */
+class MetatagCoreWithI18nConfigTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with i18n: configs',
+      'description' => 'Test Metatag configuration integration with the i18n module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need the i18n and i18n_strings modules.
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable all of the modules that are needed.
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      // From i18n.
+      'translate admin strings',
+      'translate user-defined strings',
+      // Needed for content type management.
+      'bypass node access',
+      'administer content types',
+      'administer nodes',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+  /**
+   * Test translation functionality with i18n on config defaults.
+   */
+  public function testI18nDefaultConfig() {
+    // Plan out the different translation string tests.
+    $string_en = 'Drupal 7 (http://drupal.org)';
+    $string_fr = 'French Drupal';
+    $config_name = 'metatag_config:global:generator';
+
+    // Confirm the translation page exists and has some Metatag strings.
+    $this->searchTranslationPage('', $config_name);
+
+    // Load the front page.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $xpath = $this->xpath("//meta[@name='generator']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one generator meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_en);
+
+    // Confirm the string is present.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Get the translation string lid for the generator tag.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the generator tag.');
+
+    // Save the translation string.
+    $this->saveTranslationString($lid, $config_name, 'fr', $string_en, $string_fr);
+
+    // Load the English front page again.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the default homepage.');
+
+    // Confirm the page's generator tag is what we set it to.
+    $xpath = $this->xpath("//meta[@name='generator']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one generator meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_en);
+
+    // Load the French front page.
+    $this->drupalGet('fr');
+    $this->assertResponse(200, 'Loaded the French homepage.');
+
+    // Confirm the generator string was translated.
+    $xpath = $this->xpath("//meta[@name='generator']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one generator meta tag found.');
+    $this->assertEqual($xpath[0]['content'], $string_fr);
+  }
+
+  /**
+   * Test translations of the custom configurations.
+   */
+  public function testI18nCustomConfig() {
+    // Plan out the different translation string tests.
+    $string_en = 'Welcome to the homepage!';
+    $string_fr = 'Bonjour pour le homepage!';
+    $config_name = 'metatag_config:global:frontpage:title';
+
+    // Confirm the translation page exists and has some Metatag strings.
+    $this->searchTranslationPage('', $config_name);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Load the front page's meta tags.
+    $instance = 'global:frontpage';
+    $config = metatag_config_load($instance);
+
+    // Set something specific as the homepage.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Load the front page.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+
+    // Get the translation string lid for the front page's title.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the front page title tag.');
+
+    // Save the translation string.
+    $this->saveTranslationString($lid, $config_name, 'fr', $string_en, $string_fr);
+
+    // Load the English front page again.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the default homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+
+    // Load the French front page.
+    $this->drupalGet('fr');
+    $this->assertResponse(200, 'Loaded the French homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_fr);
+  }
+
+  /**
+   * Confirm that translations will be deleted when configs are deleted.
+   */
+  public function testI18nDeleteConfig() {
+    // Plan out the different translation string tests.
+    $string_en = 'Hey, an article!';
+    $string_fr = 'Alors! Un article!';
+    $config_name = 'metatag_config:node:article:title';
+
+    // Create a config for the 'article' content type's meta tags.
+    $instance = 'node:article';
+    $label = t('Node: Article');
+    $config = new StdClass();
+    $config->instance = $instance;
+    $config->api_version = 1;
+    $config->disabled = FALSE;
+    $config->export_module = 'metatag';
+    $config->config = array();
+
+    // Set something specific as the page title.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Load the 'delete' page.
+    $this->drupalGet('admin/config/search/metatags/config/' . $instance . '/delete');
+    $this->assertResponse(200);
+
+    // Confirm this is the correct page.
+    $this->assertText(t('Are you sure you want to delete the meta tag defaults for @label?', array('@label' => $label)));
+    $this->assertText(t('This action cannot be undone.'));
+    $this->assertFieldByName('op');
+    $this->assertFieldByName('op', t('Confirm'));
+
+    // Submit the form.
+    $this->drupalPost(NULL, array(), t('Confirm'));
+    $this->assertResponse(200);
+    $this->assertText(t('The meta tag defaults for @label have been deleted.', array('@label' => $label)));
+
+    // Confirm the string has been removed.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+  }
+
+  /**
+   * Confirm that translations will be deleted when entity bundles are deleted.
+   */
+  public function testI18nDeleteEntityBundle() {
+    // Plan out the different translation string tests.
+    $string_en = 'Hey, an article!';
+    $string_fr = 'Alors! Un article!';
+    $config_name = 'metatag_config:node:article:title';
+
+    // Create a config for the 'article' content type's meta tags.
+    $content_type = 'article';
+    $content_type_label = t('Article');
+    $instance = 'node:article';
+    $instance_label = t('Node: Article');
+    $config = new StdClass();
+    $config->instance = $instance;
+    $config->api_version = 1;
+    $config->disabled = FALSE;
+    $config->export_module = 'metatag';
+    $config->config = array();
+
+    // Set something specific as the page title.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_en, $config_name);
+
+    // Load the 'delete' page.
+    $this->drupalGet('admin/structure/types/manage/' . $content_type);
+    $this->assertResponse(200);
+
+    // Confirm this is the correct page.
+    $this->assertFieldByName('op', t('Delete content type'));
+
+    // Submit the form.
+    $this->drupalPost(NULL, array(), t('Delete content type'));
+    $this->assertResponse(200);
+
+    // Confirm this is the correct page.
+    $this->assertText(t('Are you sure you want to delete the content type @label?', array('@label' => $content_type_label)));
+    $this->assertText(t('This action cannot be undone.'));
+    $this->assertFieldByName('op');
+    $this->assertFieldByName('op', t('Delete'));
+
+    // Submit the form.
+    $this->drupalPost(NULL, array(), t('Delete'));
+    $this->assertResponse(200);
+    $this->assertText(t('The content type @label has been deleted.', array('@label' => $content_type_label)));
+
+    // Confirm the config was deleted.
+    $config = metatag_config_load($instance);
+    $this->assertEqual($config, array());
+
+    // Confirm the string has been removed.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+  }
+
+  /**
+   * Test translations of the custom configurations.
+   */
+  public function testI18nDifferentSourceLanguage() {
+    // Make French the default source locale.
+    variable_set('i18n_string_source_language', 'fr');
+
+    // Verify that the default language and source language are different.
+    $this->assertNotEqual(i18n_string_source_language(), language_default('language'));
+
+    // Plan out the different translation string tests.
+    $string_en = 'Welcome to the homepage!';
+    $string_fr = 'Bonjour pour le homepage!';
+    $config_name = 'metatag_config:global:frontpage:title';
+
+    // Confirm the translation page exists and has some Metatag strings.
+    $this->searchTranslationPage('', $config_name);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Load the front page's meta tags.
+    $instance = 'global:frontpage';
+    $config = metatag_config_load($instance);
+
+    // Set something specific as the homepage.
+    $config->config['title']['value'] = $string_fr;
+    metatag_config_save($config);
+
+    // Confirm the string is present now.
+    $this->searchTranslationPage($string_fr, $config_name);
+
+    // Load the front page.
+    $this->drupalGet('fr');
+    $this->assertResponse(200, 'Loaded the homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_fr);
+
+    // Get the translation string lid for the front page's title.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the front page title tag.');
+
+    // Save the translation string.
+    $this->saveTranslationString($lid, $config_name, 'en', $string_fr, $string_en);
+
+    // Load the English front page again.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the default homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+
+    // Load the French front page.
+    $this->drupalGet('fr');
+    $this->assertResponse(200, 'Loaded the French homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_fr);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_disabled.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_disabled.test
new file mode 100644
index 0000000000000000000000000000000000000000..060f4783b062915e30b8b0c70aa548cf9033bdc1
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_disabled.test
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Tests for Metatag for when i18n is enabled but not actually configured.
+ */
+class MetatagCoreWithI18nDisabledTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with i18n disabled',
+      'description' => 'Test Metatag integration with the i18n module enabled but the integration disabled.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need the i18n and i18n_strings modules.
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable all of the modules that are needed.
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      // From i18n.
+      'translate admin strings',
+      'translate user-defined strings',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Turn off i18n integration.
+    variable_set('metatag_i18n_disabled', TRUE);
+
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+  /**
+   * Test translations of the output tags.
+   */
+  public function testI18nOutput() {
+    // Plan out the different translation string tests.
+    $string_en = 'Welcome to the homepage!';
+    $string_fr = 'Bonjour pour le homepage!';
+    $config_name = 'metatag:frontpage:title';
+
+    $this->searchTranslationPage('', $config_name);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Load the front page's meta tags.
+    $instance = 'global:frontpage';
+    $config = metatag_config_load($instance);
+
+    // Set something specific as the homepage.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+
+    // Confirm the string is still not translatable.
+    $this->searchTranslationPage($string_en, $config_name, FALSE);
+
+    // Get the translation string lid for the front page's title.
+    $lid = $this->getTranslationLidByContext($config_name);
+    $this->assertEqual($lid, 0, 'Did not find a locales_source string for the front page output title tag.');
+
+    // Load the French front page.
+    $this->drupalGet('fr');
+    $this->assertResponse(200, 'Loaded the French homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_output.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_output.test
new file mode 100644
index 0000000000000000000000000000000000000000..73922fb2ba0cb19322f7076538e167a6367383d5
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_i18n_output.test
@@ -0,0 +1,180 @@
+<?php
+
+/**
+ * Tests for Metatag for when i18n is enabled and actively being used.
+ */
+class MetatagCoreWithI18nOutputTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with i18n: output',
+      'description' => 'Test Metatag integration with the i18n module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'i18n'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Need the i18n and i18n_strings modules.
+    $modules[] = 'i18n';
+    $modules[] = 'i18n_string';
+
+    // Enable all of the modules that are needed.
+    parent::setUp($modules);
+
+    // Add more locales.
+    $this->setupLocales();
+
+    // Set up the locales.
+    $perms = array(
+      'administer languages',
+      'translate interface',
+      // From i18n.
+      'translate admin strings',
+      'translate user-defined strings',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Test translations of the output tags.
+   */
+  public function testI18nOutputTranslationsEnabled() {
+    // Enable output translations.
+    $this->toggleOutputTranslations(TRUE);
+
+    // Plan out the different translation string tests.
+    $string_en = 'Welcome to the homepage!';
+    $string_fr = 'Bonjour pour le homepage!';
+    $string_context = 'output:frontpage:title';
+
+    $this->searchTranslationPage('', $string_context);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $string_context, FALSE);
+
+    // Load the front page's meta tags.
+    $instance = 'global:frontpage';
+    $config = metatag_config_load($instance);
+
+    // Set something specific as the homepage.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+
+    // Confirm the string is translatable.
+    $this->searchTranslationPage($string_en, $string_context);
+
+    // Get the translation string lid for the front page's title.
+    $lid = $this->getTranslationLidByContext($string_context);
+    $this->assertNotEqual($lid, 0, 'Found the locales_source string for the front page output title tag.');
+
+    // Save the translation string.
+    $this->saveTranslationString($lid, $string_context, 'fr', $string_en, $string_fr);
+
+    // Load the English front page again.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the default homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+
+    // Load the French front page.
+    $this->drupalGet('fr');
+    $this->assertResponse(200, 'Loaded the French homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_fr);
+
+    // Make doubly sure there are output translations.
+    $lids = $this->getTranslationsByContext($string_context);
+    $this->assertNotEqual($lids, array());
+  }
+
+  /**
+   * Verify that no output translation records are generated when it's disabled.
+   */
+  public function testI18nOutputTranslationsDisabled() {
+    // Make sure output translations are disabled.
+    $this->toggleOutputTranslations(FALSE);
+
+    // Plan out the different translation string tests.
+    $string_en = 'Welcome to the homepage!';
+    $string_fr = 'Bonjour pour le homepage!';
+    $string_context = 'output:frontpage:title';
+
+    $this->searchTranslationPage('', $string_context);
+
+    // Confirm the string is not present yet.
+    $this->searchTranslationPage($string_en, $string_context, FALSE);
+
+    // Load the front page's meta tags.
+    $instance = 'global:frontpage';
+    $config = metatag_config_load($instance);
+
+    // Set something specific as the homepage.
+    $config->config['title']['value'] = $string_en;
+    metatag_config_save($config);
+
+    // Load the front page.
+    $this->drupalGet('');
+    $this->assertResponse(200, 'Loaded the homepage.');
+
+    // Confirm the page's title is what we set it to.
+    $this->assertTitle($string_en);
+
+    // Confirm the string is still not translatable.
+    $this->searchTranslationPage($string_en, $string_context, FALSE);
+
+    // Make doubly sure there are no output translations.
+    $lids = $this->getTranslationsByContext($string_context);
+    $this->assertEqual($lids, array());
+  }
+
+  /**
+   *
+   */
+  public function testMenuPaths() {
+    $paths = metatag_test_menu();
+    $test_string = 'read-more-books-every-day';
+    foreach ($paths as $path => $menu_item) {
+      if (substr($path, -1) == '%') {
+        $path = substr($path, 0, -1) . $test_string;
+      }
+      $this->drupalGet($path);
+      $this->assertResponse(200, 'Loaded a page: ' . $path);
+    }
+  }
+
+  /**
+   * Enable or disable output translations.
+   *
+   * @param bool $enable
+   *   Whether or not to enable translations; defaults to TRUE.
+   */
+  private function toggleOutputTranslations($enable = TRUE) {
+    // Enable output translation.
+    variable_set('metatag_i18n_translate_output', $enable);
+
+    // Reload the translations.
+    drupal_flush_all_caches();
+    module_load_include('admin.inc', 'i18n_string');
+    i18n_string_refresh_group('metatag');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_me.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_me.test
new file mode 100644
index 0000000000000000000000000000000000000000..a04ed2fd22669f6d70d1905eb437288c78ef5d4a
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_me.test
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * Tests for the Metatag module for Me module integration.
+ */
+class MetatagCoreWithMeTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with Me',
+      'description' => 'Test Metatag integration with the Me module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'me'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'me';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Make sure the /user/me path doesn't load any meta tags.
+   */
+  public function testMePath() {
+    // Create an admin user and log them in.
+    if (!isset($this->adminUser)) {
+      $this->adminUser = $this->createAdminUser();
+    }
+    $this->drupalLogin($this->adminUser);
+
+    // Load the user's profile page.
+    // Load the 'me' page.
+    $this->drupalGet('user/' . $this->adminUser->uid);
+    $this->assertResponse(200);
+
+    // Look for some meta tags that should exist.
+    $xpath = $this->xpath("//meta[@name='generator']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one generator meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Drupal 7 (http://drupal.org)');
+    $xpath = $this->xpath("//link[@rel='canonical']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one canonical meta tag found.');
+    $this->assertEqual($xpath[0]['href'], url('user/' . $this->adminUser->uid, array('absolute' => TRUE)));
+    $xpath = $this->xpath("//link[@rel='shortlink']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one shortlink meta tag found.');
+    $this->assertEqual($xpath[0]['href'], url('user/' . $this->adminUser->uid, array('absolute' => TRUE)));
+
+    // Load the 'me' page.
+    $this->drupalGet('user/me');
+    $this->assertResponse(200);
+
+    // Confirm the meta tags defined above don't exist.
+    $xpath = $this->xpath("//meta[@name='generator']");
+    $this->assertEqual(count($xpath), 0, 'Did not find the generator meta tag.');
+    $xpath = $this->xpath("//link[@rel='canonical']");
+    $this->assertEqual(count($xpath), 0, 'Did not find the canonical meta tag.');
+    $xpath = $this->xpath("//link[@rel='shortlink']");
+    $this->assertEqual(count($xpath), 0, 'Did not find the shortlink meta tag.');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_media.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_media.test
new file mode 100644
index 0000000000000000000000000000000000000000..41db779d258863d9b7c6788eb75f1b4ec4fc7ebf
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_media.test
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * Tests for the Metatag module for Media integration.
+ */
+class MetatagCoreWithMediaTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with Media',
+      'description' => 'Test Metatag integration with the Media module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'file_entity', 'media'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'file_entity';
+    $modules[] = 'media';
+    // The filter is in the WYSIWYG submodule.
+    $modules[] = 'media_wysiwyg';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Make sure the media filter is enabled.
+   */
+  public function testMediaFilter() {
+    $desc = 'The description.';
+
+    // Create a node and check how the meta tag is displayed.
+    $node = $this->drupalCreateNode(array(
+      'body' => array(
+        LANGUAGE_NONE => array(
+          array(
+            'value' => $desc . '[[{"fid":"1","view_mode":"default","type":"media","attributes":{"height":"100","width":"100","class":"media-element file-default"}}]]',
+            'format' => filter_default_format(),
+          ),
+        ),
+      ),
+    ));
+
+    // Load the node page.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Check the 'description' tag to make sure the Media string was filtered.
+    $xpath = $this->xpath("//meta[@name='description']");
+    $this->assertEqual($xpath[0]['content'], $desc);
+  }
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_panels.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_panels.test
new file mode 100644
index 0000000000000000000000000000000000000000..5c923d27677ce1a0593cce8166f81d7096138e92
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_panels.test
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * Tests for the Metatag module for Panels integration, outside of
+ * Metatag:Panels.
+ */
+class MetatagCoreWithPanelsTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with Panels',
+      'description' => 'Test Metatag integration with the Panels module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'panels', 'page_manager'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // We'll be using Panels but most of the work is actually in Page Manager.
+    $modules[] = 'page_manager';
+    $modules[] = 'panels';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Test out a node_view Panels display with Metatag.
+   */
+  public function testPanelsNodeView() {
+    $content_type = 'metatag_test';
+    $content_type_path = str_replace('_', '-', $content_type);
+    $label = 'Test';
+
+    // Create a content type.
+    $this->createContentType($content_type, $label);
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'create ' . $content_type . ' content',
+      'delete any ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+
+      // Needed for Panels et al.
+      'use page manager',
+      'administer page manager',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Create a test node.
+
+    // Load the node form.
+    $this->drupalGet('node/add/' . $content_type_path);
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly.
+    // @todo Update this to extract the page title.
+    $this->assertText(strip_tags(t('Create @name', array('@name' => $label))));
+
+    // Verify that it's possible to submit values to the form.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[node:title] ponies',
+      'title' => 'Who likes magic',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify that the node saved correctly.
+    // $xpath = $this->xpath("//h1");
+    $t_args = array('@type' => 'Test', '%title' => 'Who likes magic');
+    // This doesn't work for some reason, it seems the HTML is stripped off
+    // during output so the %title's standard Drupal wrappers don't match.
+    // $this->assertText(t('@type %title has been created.', $t_args));
+    // .. so this has to be done instead.
+    $this->assertText(strip_tags(t('@type %title has been created.', $t_args)));
+
+    // Save the node URL for later.
+    $node_url = $this->getUrl();
+
+    // Confirm the tags load correctly.
+    $this->confirmNodeTags();
+
+    // Enable the Page Manager display for nodes.
+    variable_set('page_manager_node_view_disabled', FALSE);
+
+    // Confirm that the main Panels page loads correctly.
+    $this->drupalGet('admin/structure/pages');
+    $this->assertResponse(200);
+
+    // Confirm that the Panels node_view page loads.
+    $this->drupalGet('admin/structure/pages/edit/node_view');
+    $this->assertResponse(200);
+
+    // Confirm that a new variant can be added.
+    $this->drupalGet('admin/structure/pages/nojs/operation/node_view/actions/add');
+    $this->assertResponse(200);
+
+    // Create a variant. This is done as a series of form submissions.
+    $args = array(
+      'title' => 'Test',
+      'name' => 'test',
+      'handler' => 'panel_context',
+    );
+    $this->drupalPost('admin/structure/pages/nojs/operation/node_view/actions/add', $args, t('Create variant'));
+    $this->assertResponse(200);
+    $args = array(
+      'layout' => 'flexible',
+    );
+    $this->drupalPost(NULL, $args, t('Continue'));
+    $this->assertResponse(200);
+    $args = array();
+    $this->drupalPost(NULL, $args, t('Continue'));
+    $this->assertResponse(200);
+    $args = array();
+    $this->drupalPost(NULL, $args, t('Create variant'));
+    $this->assertResponse(200);
+    $this->assertText(t('The page has been updated. Changes will not be permanent until you save.'));
+    $args = array();
+    $this->drupalPost(NULL, $args, t('Save'));
+    $this->assertResponse(200);
+
+    // Confirm the process completed successfully.
+    $this->assertEqual($this->getUrl(), url('admin/structure/pages/edit/node_view', array('absolute' => TRUE)));
+    $this->assertText(t('Panel') . ': Test');
+
+    // Clear all caches, so we can start off properly.
+    drupal_flush_all_caches();
+
+    // Load the node page again.
+    $this->confirmNodeTags($node_url);
+  }
+
+  /**
+   * Confirm that the meta tags for the requested node load properly.
+   *
+   * @param string $path
+   *   Optional path to load, if not present the current path will be used.
+   */
+  function confirmNodeTags($path = NULL) {
+    if (!empty($path)) {
+      $this->drupalGet($path);
+      $this->assertResponse(200);
+    }
+
+    // Verify the title is using the custom default for this content type.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Who likes magic ponies');
+  }
+
+  /**
+   * Test out a term_view Panels display with Metatag.
+   *
+   * @todo Write this.
+   */
+  // public function testPanelsTermView() {
+  //   // Enable the Page Manager display for terms.
+  //   variable_set('page_manager_term_view_disabled', FALSE);
+  // }
+
+  /**
+   * Test out a user_view Panels display with Metatag.
+   *
+   * @todo Write this.
+   */
+  // public function testPanelsUserView() {
+  //   // Enable the Page Manager display for users.
+  //   variable_set('page_manager_user_view_disabled', FALSE);
+  // }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_profile2.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_profile2.test
new file mode 100644
index 0000000000000000000000000000000000000000..4ff7d3c5d7fa401e4e292cf071d56d59b8f5eb8b
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_profile2.test
@@ -0,0 +1,128 @@
+<?php
+
+/**
+ * Tests for the Metatag module for Profile2 integration.
+ *
+ * Inherit from the User test so that its tests can be confirmed to still work
+ * when the Profile2 module is enabled.
+ */
+class MetatagCoreWithProfile2Test extends MetatagCoreUserTest {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with Profile2',
+      'description' => 'Test Metatag integration with the Profile2 module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'profile2'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'profile2';
+
+    parent::setUp($modules);
+
+    // Add extra permissions for the admin user, this way it can be ready for
+    // use by the other user tests.
+    $perms = array(
+      // Let the user edit & view their own profile.
+      'edit own main profile',
+      'view own main profile',
+      // Manage profile entity definitions.
+      'administer profile types',
+      // Need this permission to access the Field UI pages for Profile2.
+      'administer site configuration',
+      'administer fields',
+      'administer profiles',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Make sure that the Profile2 entity doesn't interfere with the user entity.
+   */
+  public function testUserProfilePage() {
+    // Add a custom meta tag to the user's profile.
+    $this->drupalGet('user/' . $this->adminUser->uid . '/edit');
+    $this->assertResponse(200);
+
+    // Verify that it's possible to submit values to the form.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[user:name] ponies',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify that the user object saved correctly.
+    $this->assertText(strip_tags(t('The changes have been saved.')));
+
+    // Confirm the user profile tags work correctly.
+    $this->assertUserEntityTags($this->adminUser);
+
+    // Load the 'main' Profile2 fields admin page.
+    $this->drupalGet('admin/structure/profiles');
+    $this->assertResponse(200);
+    // Load the 'main' Profile2 fields admin page.
+    $this->drupalGet('admin/structure/profiles/manage/main');
+    $this->assertResponse(200);
+    // Load the 'main' Profile2 fields admin page.
+    $this->drupalGet('admin/structure/profiles/manage/main/fields');
+    $this->assertResponse(200);
+
+    // Verify that the page loaded correctly.
+    $this->assertFieldByName('fields[_add_new_field][label]');
+    $this->assertFieldByName('fields[_add_new_field][field_name]');
+    $this->assertFieldByName('fields[_add_new_field][type]');
+    $this->assertFieldByName('fields[_add_new_field][widget_type]');
+
+    // Add a text field to the Main profile.
+    $edit = array(
+      'fields[_add_new_field][label]' => 'Test field',
+      'fields[_add_new_field][field_name]' => 'test',
+      'fields[_add_new_field][type]' => 'text',
+      'fields[_add_new_field][widget_type]' => 'text_textfield',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+    $this->assertText(strip_tags(t('Saved %label configuration.', array('%label' => 'Test field'))));
+
+    // Edit the user's Profile2 entity.
+    $this->drupalGet('user/' . $this->adminUser->uid . '/edit/main');
+    $this->assertResponse(200);
+    $this->assertFieldByName('profile_main[field_test][und][0][value]');
+    $edit = array(
+      'profile_main[field_test][und][0][value]' => 'test string',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Add a custom meta tag to the user's profile.
+    $this->drupalGet('user/' . $this->adminUser->uid . '/edit');
+    $this->assertResponse(200);
+
+    // Verify that it's possible to submit values to the form.
+    $edit = array(
+      'metatags[und][abstract][value]' => '[user:name] ponies',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertResponse(200);
+
+    // Verify that the user object saved correctly.
+    $this->assertText(strip_tags(t('The changes have been saved.')));
+
+    // Clear all caches.
+    drupal_flush_all_caches();
+
+    // Confirm the user profile tags still work correctly.
+    $this->assertUserEntityTags($this->adminUser);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_search_api.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_search_api.test
new file mode 100644
index 0000000000000000000000000000000000000000..6c8ada29dea9eeb065716ca175ac392e63b37f03
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_search_api.test
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * Tests for the Search API integration.
+ */
+class MetatagCoreWithSearchAPITest extends MetatagTestHelper {
+
+  /**
+   * The index used by these tests.
+   *
+   * @var SearchApIindex
+   */
+  protected $index;
+
+  /**
+   * The ID of the index used by these tests.
+   *
+   * @var string
+   */
+  protected $indexId;
+
+  /**
+   * The machine name of the created test server.
+   *
+   * @var string
+   */
+  protected $serverId;
+
+  /**
+   * @inheritdoc
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag Search API tests',
+      'description' => 'Tests the Metatag Search API integration.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'entity', 'search_api'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Needed for Search API.
+    $modules[] = 'entity';
+    // The module.
+    $modules[] = 'search_api';
+    // Used to help test the integration.
+    $modules[] = 'metatag_search_test';
+
+    parent::setUp($modules);
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'edit any page content',
+
+      // Needed for Search API.
+      'administer search_api',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Create an index.
+    $this->indexId = 'test_index';
+    $this->index = entity_create('search_api_index', array(
+      'id' => $this->indexId,
+      'name' => 'test',
+      'machine_name' => 'test_index',
+      'enabled' => 1,
+      'item_type' => 'node',
+      'options' => array(
+        'data_alter_callbacks' => array(
+          'search_api_metatag_alter_callback' => array(
+            'status' => 1,
+          ),
+        ),
+        'fields' => array(
+          'metatag_keywords' => array(
+            'type' => 'text',
+          ),
+        ),
+      ),
+    ));
+    $this->index->save();
+
+    // Set up a Search API server.
+    $this->serverId = 'test_server';
+    $values = array(
+      'name' => 'Search API test server',
+      'machine_name' => $this->serverId,
+      'enabled' => 1,
+      'description' => 'A server used for testing.',
+      'class' => 'metatag_search_test_service',
+    );
+    $this->drupalPost('admin/config/search/search_api/add_server', $values, 'Create server');
+
+    // Configure the server.
+    $this->drupalPost(NULL, array(), 'Create server');
+    $this->assertText(t('The server was successfully created.'));
+    $this->drupalGet('admin/config/search/search_api');
+    $values = array(
+      'server' => $this->serverId,
+    );
+    $this->drupalPost("admin/config/search/search_api/index/{$this->indexId}/edit", $values, 'Save settings');
+    $this->clickLink(t('enable'));
+
+    // Enable meta tags for the 'page' content type.
+    metatag_entity_type_enable('node', 'page');
+  }
+
+  /**
+   * Test that the alter callback indexes the keywords.
+   */
+  public function testAlter() {
+    // Add a node with keywords.
+    $node = $this->drupalCreateNode();
+    $keywords = 'puppies, rainbows';
+    $values = array(
+      'metatags[' . LANGUAGE_NONE . '][keywords][value]' => $keywords,
+    );
+    $this->drupalPost('node/' . $node->nid . '/edit', $values, 'Save');
+
+    // Index the node.
+    $this->drupalPost("admin/config/search/search_api/index/{$this->indexId}", array(), 'Index now');
+
+    // Check whether the keywords have been indexed.
+    $this->assertIdentical(variable_get('metatag_search_test_keywords', FALSE), $keywords);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_views.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_views.test
new file mode 100644
index 0000000000000000000000000000000000000000..b02a8f25590ee89ea727c46977557ce6e1497462
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_views.test
@@ -0,0 +1,189 @@
+<?php
+
+/**
+ * Tests for the Metatag module for Views integration, outside of
+ * Metatag:Views.
+ */
+class MetatagCoreWithViewsTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with Views',
+      'description' => 'Test Metatag integration with the Views module.',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'views'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'views';
+    $modules[] = 'views_ui';
+
+    // Need the Path module to set a alias which can then be loaded.
+    $modules[] = 'path';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Test the taxonomy term page still works when displayed via Views.
+   */
+  public function testTermViews() {
+    $vocab_name = 'test_vocab';
+    $term_name = 'Who likes magic';
+    $term_path = 'term-test';
+
+    // Create a vocabulary.
+    $vocabulary = $this->createVocabulary($vocab_name);
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Global admin access.
+      'administer site configuration',
+
+      // Needed for the vocabulary.
+      'administer taxonomy',
+      'edit terms in ' . $vocabulary->vid,
+      'delete terms in ' . $vocabulary->vid,
+
+      // Needed for the Path module.
+      'create url aliases',
+
+      // Needed for Views.
+      'administer views',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+
+    // Log in the admin user.
+    $this->drupalLogin($this->adminUser);
+
+    // Load the "add default configuration" page.
+    $this->drupalGet('admin/config/search/metatags/config/add');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText(t('Select the type of default meta tags you would like to add.'));
+
+    // Submit the initial form to select an entity bundle.
+    $this->drupalPost(NULL, array(
+      'instance' => 'taxonomy_term:' . $vocabulary->name,
+    ), t('Add and configure'));
+    $this->assertResponse(200);
+
+    // @todo Update this to extract the H1 tag.
+    $this->assertText(strip_tags('Taxonomy term: ' . $vocabulary->name));
+
+    // Submit the form with some values.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[term:name]',
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify the page loaded correct.
+    $this->assertText(strip_tags(t('The meta tag defaults for @label have been saved.', array('@label' => 'Taxonomy term: ' . $vocabulary->name))));
+
+    // Verify that the user was redirected to the settings page again.
+    $this->assertEqual($this->getUrl(), url('admin/config/search/metatags', array('absolute' => TRUE)));
+
+    // Create a test term.
+
+    // Load the term form.
+    $this->drupalGet('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add');
+    $this->assertResponse(200);
+
+    // Verify the page loaded correctly.
+    // @todo Update this to extract the H1 tag.
+    // $this->assertText(strip_tags(t('Create @name', array('@name' => $vocabulary->name))));
+
+    // Verify that it's possible to submit values to the form.
+    $this->drupalPost(NULL, array(
+      'metatags[und][abstract][value]' => '[term:name] ponies',
+      'name' => $term_name,
+      'path[alias]' => $term_path,
+    ), t('Save'));
+    $this->assertResponse(200);
+
+    // Verify that the node saved correctly.
+    $t_args = array('%name' => $term_name);
+    // This doesn't work for some reason, it seems the HTML is stripped off
+    // during output so the %name's standard Drupal wrappers don't match.
+    // $this->assertText(t('Created new term %name.', $t_args));
+    // .. so this has to be done instead.
+    $this->assertText(strip_tags(t('Created new term %name.', $t_args)));
+
+    // Verify the term data saved correctly.
+    $this->drupalGet($term_path);
+    $this->assertResponse(200);
+
+    // Confirm the page is managed by the default taxonomy term page.
+    $this->assertText(t('There is currently no content classified with this term.'));
+
+    // Enable the taxonomy_term default display.
+    $view = views_get_view('taxonomy_term');
+    ctools_include('export');
+    ctools_export_set_object_status($view, 0);
+    $this->clearAllCaches();
+
+    $this->drupalGet('admin/structure/views');
+    $this->assertResponse(200);
+
+    $vars = variable_get('views_defaults');
+    $this->verbose($vars);
+    $this->assertFalse($vars['taxonomy_term'], 'Taxonomy term page is enabled.');
+
+    // Load the page again.
+    $this->drupalGet($term_path);
+    $this->assertResponse(200);
+
+    // Confirm this page is managed by Views - if it's managed by the default
+    // taxonomy term page this text will show.
+    $this->assertNoText(t('There is currently no content classified with this term.'));
+
+    // Try to extract the 'edit' link.
+    $xpaths = $this->xpath("//ul/li/a");
+    $matches = array();
+    $tid = 0;
+    if (!empty($xpaths)) {
+      foreach ($xpaths as $xpath) {
+        $attributes = $xpath->attributes();
+        if (!empty($attributes['href'])) {
+          if (preg_match('@taxonomy/term/(\d+)/edit$@', $attributes['href'], $matches)) {
+            $tid = $matches[1];
+          }
+        }
+      }
+    }
+
+    // Presuing a term ID was found, load the term.
+    if (!empty($tid)) {
+      $term = taxonomy_term_load($tid);
+
+      // Only the non-default values are stored.
+      $expected = array(
+        'und' => array(
+          'abstract' => array(
+            'value' => '[term:name] ponies',
+          ),
+        ),
+      );
+      $this->assertEqual($expected, $term->metatags);
+    }
+
+    // This shouldn't happen, it indicates a problem.
+    else {
+      $this->fail(t('Could not determine the ID for created term.'));
+    }
+
+    // Verify the title is using the custom default for this vocabulary.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], "Who likes magic ponies");
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_workbench_moderation.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_workbench_moderation.test
new file mode 100644
index 0000000000000000000000000000000000000000..98007d550f350749beb2573d84b08537f6e8877a
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.with_workbench_moderation.test
@@ -0,0 +1,113 @@
+<?php
+/**
+ * @file
+ * Tests for the Metatag module for Workbench Moderation integration.
+ */
+
+class MetatagCoreWithWorkbenchModerationTest extends MetatagTestHelper {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests with Workbench Moderation v3',
+      'description' => 'Test Metatag integration with the Workbench Moderation module (v3).',
+      'group' => 'Metatag',
+      'dependencies' => array('ctools', 'token', 'workbench_moderation'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    $modules[] = 'workbench_moderation';
+
+    parent::setUp($modules);
+  }
+
+  /**
+   * Confirm that WM-based node edit workflows work properly.
+   */
+  public function testNodeEdit() {
+    // Create a new content type and enable moderation on it.
+    $content_type = 'metatag_test';
+    $content_type_path = str_replace('_', '-', $content_type);
+    $label = 'Test';
+    $this->createContentType($content_type, $label);
+    variable_set('node_options_' . $content_type, array('revision', 'moderation'));
+
+    // Create a brand new unpublished node programmatically.
+    $settings = array(
+      'title' => 'Who likes magic',
+      'type' => $content_type,
+      'metatags' => array(
+        LANGUAGE_NONE => array(
+          'abstract' => array('value' => '[node:title] ponies'),
+        ),
+      ),
+      'status' => NODE_NOT_PUBLISHED,
+    );
+    $node = $this->drupalCreateNode($settings);
+
+    // Check that page is not published.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(403);
+
+    // Create and login user.
+    $moderator_user = $this->drupalCreateUser(array(
+      'access content',
+      'view revisions',
+      'view all unpublished content',
+      'view moderation history',
+      'view moderation messages',
+      'bypass workbench moderation',
+      "create {$content_type} content",
+      "edit any {$content_type} content",
+    ));
+    $this->drupalLogin($moderator_user);
+
+    // Publish the node via the moderation form.
+    $moderate = array('state' => workbench_moderation_state_published());
+    $this->drupalPost("node/{$node->nid}/moderation", $moderate, t('Apply'));
+
+    // Create draft with different node title.
+    $edit = array(
+      'title' => 'I like magic',
+    );
+    $this->drupalPost("node/{$node->nid}/edit", $edit, t('Save'));
+
+    // Logout user.
+    $this->drupalLogout();
+
+    // Check that page is already published.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Verify the title is using the custom default for this content type.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'Who likes magic ponies');
+
+    // Login user again.
+    $this->drupalLogin($moderator_user);
+
+    // Publish draft via the moderation form.
+    $moderate = array('state' => workbench_moderation_state_published());
+    $this->drupalPost("node/{$node->nid}/moderation", $moderate, t('Apply'));
+
+    // Logout user.
+    $this->drupalLogout();
+
+    // Check that page is already published.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertResponse(200);
+
+    // Verify the title is using the custom default for this content type.
+    $xpath = $this->xpath("//meta[@name='abstract']");
+    $this->assertEqual(count($xpath), 1, 'Exactly one abstract meta tag found.');
+    $this->assertEqual($xpath[0]['content'], 'I like magic ponies');
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag.xss.test b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.xss.test
new file mode 100644
index 0000000000000000000000000000000000000000..9d2deb0c89b3e5d61f8f057d229b75a36d21fd75
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag.xss.test
@@ -0,0 +1,190 @@
+<?php
+
+/**
+ * Tests Metatag module to ensure there are no XSS scripting vulnerabilities.
+ */
+class MetatagCoreXSSTest extends MetatagTestHelper {
+
+  /**
+   * 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 metatags 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="&quot;&gt;alert(&quot;xss&quot;);" />';
+
+  /**
+   * String that causes an alert when metatags 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="/&quot;&gt;alert(&quot;image%20xss&quot;);" />';
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Metatag core tests for XSS.',
+      'description' => 'Test Metatag for XSS vulnerabilities.',
+      'group' => 'Metatag',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    parent::setUp($modules);
+
+    $content_type = 'page';
+
+    // Create an admin user and log them in.
+    $perms = array(
+      // Needed for the content type.
+      'create ' . $content_type . ' content',
+      'delete any ' . $content_type . ' content',
+      'edit any ' . $content_type . ' content',
+
+      // This permission is required in order to create new revisions.
+      'administer nodes',
+    );
+    $this->adminUser = $this->createAdminUser($perms);
+    $this->drupalLogin($this->adminUser);
+  }
+
+  /**
+   * Verify XSS injected in global Node config is not rendered.
+   */
+  function testXssMetatagConfig() {
+    // Submit the form with some example XSS values.
+    $this->drupalGet('admin/config/search/metatags/config/global');
+    $this->assertResponse(200);
+    $edit = array(
+      'metatags[und][title][value]' => $this->xssTitleString,
+      'metatags[und][abstract][value]' => $this->xssString,
+      'metatags[und][image_src][value]' => $this->xssImageString,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertResponse(200);
+
+    // Use front page to test.
+    $this->drupalGet('<front>');
+
+    // Verify title is clean.
+    $this->assertNoTitle($this->xssTitleString);
+    $this->assertNoRaw($this->xssTitleString);
+
+    // Verify the abstract is clean.
+    $this->assertRaw($this->escapedXssTag);
+    $this->assertNoRaw($this->xssString);
+
+    // Verify the image_src is clean.
+    $this->assertRaw($this->escapedXssImageTag);
+    $this->assertNoRaw($this->xssImageString);
+  }
+
+  /**
+   * Verify XSS injected in the entity metatag override field is not rendered.
+   */
+  public function testXssEntityOverride() {
+    $title = 'Test Page';
+
+    // Load a page node.
+    $this->drupalGet('node/add/page');
+    $this->assertResponse(200);
+
+    // Submit the node with some example XSS values.
+    $edit = array(
+      'title' => $title,
+      'metatags[und][title][value]' => $this->xssTitleString,
+      'metatags[und][description][value]' => $this->xssString,
+      'metatags[und][abstract][value]' => $this->xssString,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Verify the page saved.
+    $this->assertResponse(200);
+    $this->assertText(t('Basic page @title has been created.', array('@title' => $title)));
+
+    // Verify title is not the injected string and thus cleaned.
+    $this->assertNoTitle($this->xssTitleString);
+    $this->assertNoRaw($this->xssTitleString);
+
+    // Verify the description and abstract are clean.
+    $this->assertRaw($this->escapedXssTag);
+    $this->assertNoRaw($this->xssString);
+  }
+
+  /**
+   * Verify XSS injected in the entity titles are not rendered.
+   */
+  public function testXssEntityTitle() {
+    // Load a page node.
+    $this->drupalGet('node/add/page');
+    $this->assertResponse(200);
+
+    // Submit the node with some example XSS values.
+    $edit = array(
+      'title' => $this->xssTitleString,
+      'body[und][0][value]' => 'hello world',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Verify the page saved.
+    $this->assertResponse(200);
+    $this->assertText(t('has been created.'));
+
+    // Verify title is not the injected string and thus cleaned.
+    $this->assertNoRaw($this->xssTitleString);
+  }
+
+  /**
+   * Verify XSS injected in the body field is not rendered.
+   */
+  public function testXssEntityBody() {
+    $title = 'Hello World';
+
+    // Load a page node.
+    $this->drupalGet('node/add/page');
+    $this->assertResponse(200);
+
+    // Submit the node with a test body value.
+    $edit = array(
+      'title' => $title,
+      'body[und][0][value]' => $this->xssString,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Verify the page saved.
+    $this->assertResponse(200);
+    $this->assertText(t('Basic page @title has been created.', array('@title' => $title)));
+
+    // Verify body field is clean.
+    $this->assertNoRaw($this->xssString);
+  }
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag_search_test.info b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_search_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..b3b36b5b3525554367e1e2b3cabb276ca7e273fb
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_search_test.info
@@ -0,0 +1,16 @@
+name = Metatag Search API test
+description = "Test module for the Metatag Search API integration."
+core = 7.x
+package = Metatag
+
+dependencies[] = metatag:metatag
+dependencies[] = search_api:search_api
+
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag_search_test.module b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_search_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..33fc772d8255d753ceac656ca5d28d8e4fe336d9
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_search_test.module
@@ -0,0 +1,47 @@
+<?php
+/**
+ * @file
+ * Metatag: Search API test helper module.
+ */
+
+/**
+ * Implements hook_search_api_service_info().
+ */
+function metatag_search_test_search_api_service_info() {
+  $services['metatag_search_test_service'] = array(
+    'name' => 'metatag_search_test_service',
+    'description' => 'metatag_search_test_service description',
+    'class' => 'MetatagSearchTestSearchApiService',
+  );
+  return $services;
+}
+
+/**
+ * Dummy Search API service class.
+ */
+class MetatagSearchTestSearchApiService extends SearchApiAbstractService {
+
+  /**
+   * @inheritdoc
+   */
+  public function indexItems(SearchApiIndex $index, array $items) {
+    variable_set('metatag_search_test_keywords', FALSE);
+    foreach (array_values($items) as $item) {
+      if (isset($item['metatag_keywords']['value'])) {
+        variable_set('metatag_search_test_keywords', $item['metatag_keywords']['value']);
+      }
+    }
+    return array_keys($items);
+  }
+
+  /**
+   * @inheritdoc
+   */
+  public function deleteItems($ids = 'all', SearchApiIndex $index = NULL) {}
+
+  /**
+   * @inheritdoc
+   */
+  public function search(SearchApiQueryInterface $query) {}
+
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.info b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..b2bdcbd9b63e9c2a5b9631cd033734dd98c6310f
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.info
@@ -0,0 +1,15 @@
+name = Meta Tag Test
+description = Helper module for testing metatag.module.
+core = 7.x
+
+; Don't show this on the modules admin page.
+hidden = TRUE
+
+dependencies[] = metatag:metatag
+
+; Information added by Drupal.org packaging script on 2017-02-15
+version = "7.x-1.21"
+core = "7.x"
+project = "metatag"
+datestamp = "1487171290"
+
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.metatag.inc b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.metatag.inc
new file mode 100644
index 0000000000000000000000000000000000000000..98f79937dfea0b60b01b45fce86a8eb3080e720e
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.metatag.inc
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * Implements hook_metatag_config_default().
+ *
+ * @todo Expand to cover more meta tags.
+ *
+ * @see MetatagTestHelper::getTestDefaults()
+ */
+function metatag_test_metatag_config_default() {
+  $configs = array();
+
+  $config = new stdClass();
+  $config->instance = 'test';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'description' => array('value' => 'Test description'),
+  );
+  $configs[$config->instance] = $config;
+
+  $config = new stdClass();
+  $config->instance = 'test:foo';
+  $config->api_version = 1;
+  $config->disabled = FALSE;
+  $config->config = array(
+    'title' => array('value' => 'Test title'),
+    'abstract' => array('value' => 'Test foo abstract'),
+    'description' => array('value' => 'Test foo description'),
+    'test:foo' => array('value' => 'foobar'),
+  );
+  $configs[$config->instance] = $config;
+
+  return $configs;
+}
+
+/**
+ * Implements hook_metatag_config_default_alter().
+ */
+function metatag_test_metatag_config_default_alter(array &$configs) {
+  if (isset($configs['test:foo'])) {
+    $configs['test:foo']->config['title']['value'] = 'Test altered title';
+  }
+}
+
+/**
+ * Implements hook_metatag_info().
+ */
+function metatag_test_metatag_info() {
+  $info['groups']['testing'] = array(
+    'label' => t('Testing'),
+    'form' => array(
+      '#weight' => 100,
+    ),
+  );
+
+  $info['test:foo'] = array(
+    'label' => t('Foo meta tag'),
+    'description' => t('Testing metatag.'),
+    'class' => 'DrupalTextMetaTag',
+    'group' => 'testing',
+  );
+
+  return $info;
+}
diff --git a/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.module b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..9008c956441f6998d1bb5fc1d7ea1145ed735756
--- /dev/null
+++ b/profiles/wcm_base/modules/contrib/metatag/tests/metatag_test.module
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function metatag_test_ctools_plugin_api($owner, $api) {
+  if ($owner == 'metatag' && $api == 'metatag') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * Provides simple pages to test against.
+ */
+function metatag_test_menu() {
+  $string = 'moosqueakoinkmeow';
+  $defaults = array(
+    'page callback' => 'metatag_test_page_callback',
+    'access callback' => TRUE,
+    'type' => MENU_NORMAL_ITEM,
+  );
+
+  $items[$string] = array(
+    'title' => 'Test page',
+    'description' => 'An average page.',
+  ) + $defaults;
+
+  // 255 / 19 chars = 13.
+  $long_path = implode('/', array_pad(array(), 13, $string));
+  $items[$long_path . '/%'] = array(
+    'title' => 'Test page with really long URL',
+    'description' => 'The URL is really, really, really long.',
+    'page arguments' => array(13),
+  ) + $defaults;
+
+  // User-specific meta tags.
+  $items['account-test-page'] = array(
+    'title' => 'User test page',
+    'description' => 'Test how user tokens are handled.',
+    'page callback' => 'metatag_test_user_page_callback',
+  ) + $defaults;
+
+  return $items;
+}
+
+/**
+ * Simple page callback for test pages.
+ */
+function metatag_test_page_callback() {
+  return t('Test page.');
+}
+
+/**
+ * Simple page callback for the user test page.
+ */
+function metatag_test_user_page_callback() {
+  global $user;
+
+  $username = 'Anonymous visitor';
+  if (isset($user->name)) {
+    $username = $user->name;
+  }
+  drupal_set_title('Hello ' . $username);
+
+  return t('Test page for user tokens.');
+}
diff --git a/profiles/wcm_base/modules/custom/wcm_metatags/README.md b/profiles/wcm_base/modules/custom/wcm_metatags/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..dab8c5c4f47fe374f33753965c1f3decec904e91
--- /dev/null
+++ b/profiles/wcm_base/modules/custom/wcm_metatags/README.md
@@ -0,0 +1,3 @@
+##WCM Metatags
+
+Right now just including the metatag module, as many questions remain about how to best utilize global metatags for SEO. Stay tuned.
diff --git a/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.info b/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.info
new file mode 100644
index 0000000000000000000000000000000000000000..4ec92397987efcf9f912f52ed47008d2f606f127
--- /dev/null
+++ b/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.info
@@ -0,0 +1,7 @@
+name = WCM Metatags
+description = Configuration of side-wide and content-specific metatags for SEO and social media.
+core = 7.x
+package = WCM Configuration
+version = 7.x-1.0
+dependencies[] = metatag
+features[features_api][] = api:2
diff --git a/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.make b/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.make
new file mode 100644
index 0000000000000000000000000000000000000000..051519e032343cfde8b441ee457bc629adb30f04
--- /dev/null
+++ b/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.make
@@ -0,0 +1,6 @@
+; WCM Metatags Makefile 
+api = 2
+core = 7.x
+;modules
+projects[metatag][version] = 1.21
+projects[metatag][subdir] = contrib
\ No newline at end of file
diff --git a/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.module b/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.module
new file mode 100644
index 0000000000000000000000000000000000000000..44788b071e42418f461724a48cea5cd1f0b6e429
--- /dev/null
+++ b/profiles/wcm_base/modules/custom/wcm_metatags/wcm_metatags.module
@@ -0,0 +1,5 @@
+<?php
+/**
+ * @file
+ * Drupal needs this blank file.
+ */
diff --git a/profiles/wcm_base/modules/custom/wcm_search/wcm_search.module b/profiles/wcm_base/modules/custom/wcm_search/wcm_search.module
index a3f7203d8a35db77da958daf71c0a2d9bbe852cb..125075cb3e05f17921ba9b803f593d32860b6ce0 100644
--- a/profiles/wcm_base/modules/custom/wcm_search/wcm_search.module
+++ b/profiles/wcm_base/modules/custom/wcm_search/wcm_search.module
@@ -51,7 +51,7 @@ function wcm_search_solr_post_schema($posted, $env = '') {
  * Implements hook_form_FORM_ID_alter().
  */
 function wcm_search_form_search_block_form_alter(&$form, &$form_state) {
-  $form['#prefix'] = '<div id="wcm-search"><span id="search-block-toggle" class="fa fa-search" title="Toggle Search" tabindex="0"></span>';
+  $form['#prefix'] = '<div id="wcm-search"><span id="search-block-toggle" class="fa fa-search" title="Toggle Search" tabindex="0" aria-expanded="false" aria-controls="block-search-form"></span>';
   $form['search_block_form']['#attributes']['placeholder'] = t('Search');
   $form['actions']['submit']['#value'] = t('Go');
   $form['#suffix'] = '</div>';
diff --git a/profiles/wcm_base/modules/custom/wcm_user_config/theme/user-login.tpl.php b/profiles/wcm_base/modules/custom/wcm_user_config/theme/user-login.tpl.php
index 59eed063928c19cd62636c516243d18f4edd3513..f4c495b06a9ff6b107b50499489b6f3144c4c1b3 100644
--- a/profiles/wcm_base/modules/custom/wcm_user_config/theme/user-login.tpl.php
+++ b/profiles/wcm_base/modules/custom/wcm_user_config/theme/user-login.tpl.php
@@ -1,30 +1,30 @@
-<?php 
-	$handle_non_osu = '<h2> Non-OSU Users</h2>';
-	$non_osu_login = drupal_render($form['name']); 
+<?php
+	$handle_non_osu = '<h2> Non-Ohio State Users</h2>';
+	$non_osu_login = drupal_render($form['name']);
 	$non_osu_login .= drupal_render($form['pass']);
 	$non_osu_login .= '<p><a href="/user/password">Forgot your password?</a></p>';
 	$non_osu_login .= drupal_render($form['form_build_id']);
 	$non_osu_login .= drupal_render($form['form_id']);
-	$non_osu_login .= drupal_render($form['actions']);	
+	$non_osu_login .= drupal_render($form['actions']);
 ?>
 
 
 <div class="login-box osu">
-  <h2>OSU Users</h2>
-  <p><a href="<?php print $https_base_url; ?>/saml_login<?php if ($has_destination) : ?>?ReturnTo=<?php print $return_to; ?><?php endif; ?>">Log in with your OSU credentials</a></p>
+  <h2>Ohio State Users</h2>
+  <p><a href="<?php print $https_base_url; ?>/saml_login<?php if ($has_destination) : ?>?ReturnTo=<?php print $return_to; ?><?php endif; ?>">Log in with your Ohio State credentials</a></p>
 </div>
 
 <div class="login-box non-osu">
-	
-	<?php 
+
+	<?php
 		print theme(
 	  'ctools_collapsible',
 	  array(
-	    'handle' => $handle_non_osu, 
-	    'content' => $non_osu_login, 
+	    'handle' => $handle_non_osu,
+	    'content' => $non_osu_login,
 	    'collapsed' => TRUE
 	  )
 	);
 	?>
-	
-</div>
\ No newline at end of file
+
+</div>
diff --git a/profiles/wcm_base/modules/custom/wcm_user_profile/wcm_user_profile.module b/profiles/wcm_base/modules/custom/wcm_user_profile/wcm_user_profile.module
index d85af6b0ef55a524a84d17cec9d5825ac1c58741..bf87dc2dcd04623c457476f4074e8605888ab4bb 100644
--- a/profiles/wcm_base/modules/custom/wcm_user_profile/wcm_user_profile.module
+++ b/profiles/wcm_base/modules/custom/wcm_user_profile/wcm_user_profile.module
@@ -20,7 +20,7 @@ function wcm_user_profile_user_view_alter(&$build) {
   $access = $dir || $lead;
 
   global $user;
-  if (!($access || $user->uid == $account->uid || user_access('view user profiles'))) {
+  if (!($access || $user->uid == $account->uid || user_access('access user profiles'))) {
     drupal_set_breadcrumb('');
     drupal_access_denied();
     module_invoke_all('exit');
diff --git a/profiles/wcm_base/themes/ocio_omega_1/layouts/ocio-full/ocio-full-layout.tpl.php b/profiles/wcm_base/themes/ocio_omega_1/layouts/ocio-full/ocio-full-layout.tpl.php
index 0c9a7dc8c74d4606b4752d6c2ba1b1b65b76ee3a..19574448fe8f09134c2d12c0832226024e642169 100755
--- a/profiles/wcm_base/themes/ocio_omega_1/layouts/ocio-full/ocio-full-layout.tpl.php
+++ b/profiles/wcm_base/themes/ocio_omega_1/layouts/ocio-full/ocio-full-layout.tpl.php
@@ -36,7 +36,7 @@
         <?php print $messages; ?>
         <?php print render($page['help']); ?>
         <?php print render($page['workbench']); ?>
-        <?php if (!$is_front && !empty($title)): ?>
+        <?php if (!empty($title)): ?>
           <?php print render($title_prefix); ?>
           <h1 <?php print $title_attributes; ?>><?php print $title; ?></h1>
           <?php print render($title_suffix); ?>
diff --git a/profiles/wcm_base/themes/ocio_omega_2/layouts/ocio-2/ocio-2-layout.tpl.php b/profiles/wcm_base/themes/ocio_omega_2/layouts/ocio-2/ocio-2-layout.tpl.php
index 0c98b0f12e508f380319398514235cee6569f3e7..12b252460b72354c0c49f5361fb5b7d14dbead62 100644
--- a/profiles/wcm_base/themes/ocio_omega_2/layouts/ocio-2/ocio-2-layout.tpl.php
+++ b/profiles/wcm_base/themes/ocio_omega_2/layouts/ocio-2/ocio-2-layout.tpl.php
@@ -32,7 +32,7 @@
     <div>
     <?php endif; ?>
       <div class="l-content" role="main">
-        <?php if (!$is_front && !empty($title)): ?>
+        <?php if (!empty($title)): ?>
           <?php print render($title_prefix); ?>
           <h1 <?php print $title_attributes; ?>><?php print $title; ?></h1>
           <?php print render($title_suffix); ?>
diff --git a/profiles/wcm_base/themes/ocio_omega_3/layouts/ocio-3/ocio-3-layout.tpl.php b/profiles/wcm_base/themes/ocio_omega_3/layouts/ocio-3/ocio-3-layout.tpl.php
index be69c31a07c819e54b4b8b70db2bd9de0a780331..768ce78114909ac34a5689c20b49833f0d5e775f 100644
--- a/profiles/wcm_base/themes/ocio_omega_3/layouts/ocio-3/ocio-3-layout.tpl.php
+++ b/profiles/wcm_base/themes/ocio_omega_3/layouts/ocio-3/ocio-3-layout.tpl.php
@@ -30,7 +30,7 @@
         <?php print render($page['workbench']); ?>
 
         <div class="l-content" role="main">
-          <?php if (!$is_front && !empty($title)): ?>
+          <?php if (!empty($title)): ?>
             <?php print render($title_prefix); ?>
             <h1 <?php print $title_attributes; ?>><?php print $title; ?></h1>
             <?php print render($title_suffix); ?>
@@ -46,11 +46,11 @@
         <?php print render($page['sidebar_1']); ?>
         <?php print render($page['sidebar_2']); ?>
       </div>
-      
+
       <div class="l-region--pre-footer-wrapper <?php print $main_classes; ?>">
 				<?php print render($page['pre_footer']); ?>
   		</div>
-      
+
       <footer class="l-footer-wrapper" role="contentinfo">
         <?php print render($page['footer_1']); ?>
         <?php print render($page['footer_2']); ?>
diff --git a/profiles/wcm_base/themes/ocio_omega_4/layouts/ocio-4/ocio-4-layout.tpl.php b/profiles/wcm_base/themes/ocio_omega_4/layouts/ocio-4/ocio-4-layout.tpl.php
index 0ad99efc70614e90f7d9f9cca68c91a23a2a9823..13ec8b57b906003c26f9c8357542605501aaa11e 100644
--- a/profiles/wcm_base/themes/ocio_omega_4/layouts/ocio-4/ocio-4-layout.tpl.php
+++ b/profiles/wcm_base/themes/ocio_omega_4/layouts/ocio-4/ocio-4-layout.tpl.php
@@ -33,7 +33,7 @@
     <?php endif; ?>
 
       <div class="l-content" role="main">
-        <?php if (!$is_front && !empty($title)): ?>
+        <?php if (!empty($title)): ?>
           <?php print render($title_prefix); ?>
           <h1 <?php print $title_attributes; ?>><?php print $title; ?></h1>
           <?php print render($title_suffix); ?>
diff --git a/profiles/wcm_base/themes/ocio_omega_base/js/ocio-omega-base.behaviors.js b/profiles/wcm_base/themes/ocio_omega_base/js/ocio-omega-base.behaviors.js
index 0c2fb75873098e74d8e10d6316ebb20c6418b12d..59965d52489c6afa20d5b7a82b5c494e634b6fe2 100644
--- a/profiles/wcm_base/themes/ocio_omega_base/js/ocio-omega-base.behaviors.js
+++ b/profiles/wcm_base/themes/ocio_omega_base/js/ocio-omega-base.behaviors.js
@@ -215,7 +215,7 @@
        */
       function showHoverSearchBox() {
         searchBox.stop(true, true).clearQueue().fadeIn('fast');
-        toggleButton.addClass('fa-search-minus');
+        toggleButton.attr('aria-expanded', 'true').addClass('fa-search-minus');
       }
 
       /*
@@ -243,7 +243,7 @@
       function hideHoverSearchBox_do() {
         // Handles the actual hiding, without any logical operations.
         searchBox.stop(true, true).fadeOut('fast')
-        toggleButton.removeClass('fa-search-minus');
+        toggleButton.attr('aria-expanded', 'false').removeClass('fa-search-minus');
       }
     }
   };
@@ -299,7 +299,7 @@
 
 		}
   };
-  
+
   //adds classes to news client article nodes based on sidebar being empty or not
   Drupal.behaviors.ocioOmegaNewsArticle = {
     attach: function (context, settings) {
diff --git a/profiles/wcm_base/themes/ocio_omega_base/layouts/ocio-default/ocio-default-layout.tpl.php b/profiles/wcm_base/themes/ocio_omega_base/layouts/ocio-default/ocio-default-layout.tpl.php
index 1b8553e53d27c6e74dc144263c611dd32c485513..45214cd39936b684ba0e37fc473cf31b771b6046 100644
--- a/profiles/wcm_base/themes/ocio_omega_base/layouts/ocio-default/ocio-default-layout.tpl.php
+++ b/profiles/wcm_base/themes/ocio_omega_base/layouts/ocio-default/ocio-default-layout.tpl.php
@@ -33,7 +33,7 @@
     <?php endif; ?>
 
     <div class="l-content" role="main">
-      <?php if (!$is_front && !empty($title)): ?>
+      <?php if (!empty($title)): ?>
       <?php print render($title_prefix); ?>
         <h1 <?php print $title_attributes; ?>><?php print $title; ?></h1>
         <?php print render($title_suffix); ?>
@@ -46,13 +46,13 @@
       <?php print render($page['content']); ?>
         <?php print $feed_icons; ?>
       </div>
-      
+
       <?php print render($page['sidebar_1']); ?>
       <?php print render($page['sidebar_2']); ?>
-      
+
     </div>
   </div>
-  
+
   <div class="l-region--pre-footer-wrapper <?php print $main_classes; ?>">
 	<?php print render($page['pre_footer']); ?>
   </div>
@@ -64,4 +64,4 @@
       <?php print render($page['footer_3']); ?>
     </div>
   </footer>
-</div>
\ No newline at end of file
+</div>
diff --git a/profiles/wcm_base/themes/wcm_omega/js/wcm-omega-menu.behaviors.js b/profiles/wcm_base/themes/wcm_omega/js/wcm-omega-menu.behaviors.js
index 54881db1e74dec314e64f06f80fcf303508db44c..6e784d9c50c7a3980eecc81bae9b631d92b88f48 100644
--- a/profiles/wcm_base/themes/wcm_omega/js/wcm-omega-menu.behaviors.js
+++ b/profiles/wcm_base/themes/wcm_omega/js/wcm-omega-menu.behaviors.js
@@ -1,43 +1,43 @@
 (function ($) {
-  
+
 /*** This document contains theme functions specific to menus and the main menu region ***/
-  
+
   /*****************************************************
   *** main menu behavior
   *****************************************************/
   Drupal.behaviors.wcmOmegaMainMenu = {
     attach: function (context, settings) {
-      
-      //adds classes to main menu elements by level 
+
+      //adds classes to main menu elements by level
       //to standardlize classes across superfish and menu-block modules
       $('ul#superfish-1 > li').addClass('main-menu-top-li');
       $('.main-menu-top-li > ul').addClass('main-menu-second-ul');
       $('#block-menu-block-custom-1 ul.menu').addClass('main-menu-second-ul');
       $('.main-menu-second-ul > li').addClass('main-menu-second-li');
-      
-      //behavior for second-level menu      
+
+      //behavior for second-level menu
       if($('body').hasClass('menu-style-2')) {
 
         //shifts and adjusts menu based on window size and content
-        var menuShift = function() {  
-          
+        var menuShift = function() {
+
           //menu width
           $('.main-menu-top-li > .main-menu-second-ul').each(function(){
             var ul2 = $(this);
             var ul2_width = ul2.css('width');
             var l_width = $('.l-constrained').css('width');
-            
+
             //set width of hovered second level ul based on width of l-consrained
             ul2.css('width',l_width);
           })
-          
+
           //determine height after width is applied above
           // applies menu height classes to parents
           $('li[class*="sf-item-"] > ul').each(function(){
             var hgt = $(this).css('height');
             $(this).parent().addClass('hgt-'+ hgt);
           })
-          
+
           //changes height of second menu wrapper based on "hgt-"class on hover of main-menu-top-li
           $('.menuparent.main-menu-top-li').each(function(){
             //extracts height from "hgt-" class
@@ -59,18 +59,18 @@
 
           //position of first menu item
           var ul1_left = $('ul#superfish-1 .sf-item-1').position().left;
-          
+
           //finds the position of each second level ul hover and shifts it to left align with first item
           $('.main-menu-top-li').each(function(){
             var ulx = $(this);
             var ulx_left = ulx.position().left;
             var shift = -(ulx_left - ul1_left);
-            
+
             $(this).find('.main-menu-second-ul').css('margin-left', shift);
           })
-          
+
         }//end menuShift
-        
+
         $(window).on('load resize', menuShift);
       };
     }
@@ -84,8 +84,8 @@
   		$(".mean-container .mean-nav ul li span").addClass("nolink");
 		}
   };
-  
-  
+
+
   /*****************************************************
   *** adds functionality for search box in the menu bar
   *****************************************************/
@@ -164,7 +164,7 @@
        */
       function showHoverSearchBox() {
         searchBox.stop(true, true).clearQueue().fadeIn('fast');
-        toggleButton.addClass('fa-search-minus');
+        toggleButton.attr('aria-expanded', 'true').addClass('fa-search-minus');
       }
 
       /*
@@ -192,11 +192,11 @@
       function hideHoverSearchBox_do() {
         // Handles the actual hiding, without any logical operations.
         searchBox.stop(true, true).fadeOut('fast')
-        toggleButton.removeClass('fa-search-minus');
+        toggleButton.attr('aria-expanded', 'false').removeClass('fa-search-minus');
       }
 
     }
   };
-  
 
-})(jQuery);
\ No newline at end of file
+
+})(jQuery);
diff --git a/profiles/wcm_base/themes/wcm_omega/layouts/wcm-standard/wcm-standard-layout.tpl.php b/profiles/wcm_base/themes/wcm_omega/layouts/wcm-standard/wcm-standard-layout.tpl.php
index 03c1f2d53df1881b140a80f3e98c989216b1bc95..b6960f1d9c2704f908d6cfa2854af80fa1c08824 100644
--- a/profiles/wcm_base/themes/wcm_omega/layouts/wcm-standard/wcm-standard-layout.tpl.php
+++ b/profiles/wcm_base/themes/wcm_omega/layouts/wcm-standard/wcm-standard-layout.tpl.php
@@ -1,5 +1,5 @@
 <div<?php print $attributes; ?>>
-  
+
   <header class="l-header" role="banner">
     <?php print render($page['osu_navbar']); ?>
     <?php print render($page['masthead']); ?>
@@ -24,11 +24,11 @@
     <?php if (!$landing_page) :?>
       <div class="l-constrained max-width">
     <?php else: ?>
-      <div>
+      <div class="panelized-area">
     <?php endif; ?>
 
       <div class="l-content" role="main">
-        <?php if (!$is_front && !empty($title)): ?>
+        <?php if (!empty($title)): ?>
           <?php print render($title_prefix); ?>
           <h1 <?php print $title_attributes; ?>><?php print $title; ?></h1>
           <?php print render($title_suffix); ?>
@@ -41,16 +41,16 @@
         <?php print render($page['content']); ?>
         <?php print $feed_icons; ?>
       </div>
-      
+
       <!-- only print sidebars if not a landing page -->
       <?php if (!$landing_page) :?>
         <?php print render($page['sidebar_1']); ?>
         <?php print render($page['sidebar_2']); ?>
       <?php endif; ?>
-      
+
     </div>
-  </div>
-  
+  </div><!-- end l-main -->
+
   <div class="l-region--pre-footer-wrapper <?php print $main_classes; ?>">
     <?php print render($page['pre_footer']); ?>
   </div>
@@ -62,5 +62,5 @@
       <?php print render($page['footer_3']); ?>
     </div>
   </footer>
-  
+
 </div> <!-- end layout -->
diff --git a/profiles/wcm_base/wcm_base.make b/profiles/wcm_base/wcm_base.make
index 5afff176d071f07cc5bf3e0c8bd181d5c2b5dcb4..a3c3920fb6292727ea4553354603c954b9110664 100644
--- a/profiles/wcm_base/wcm_base.make
+++ b/profiles/wcm_base/wcm_base.make
@@ -282,6 +282,12 @@ projects[ocio_omega_settings][download][type] = "git"
 projects[ocio_omega_settings][download][url] = git@code.osu.edu:ocio_odee_web/ocio_omega_settings.git
 projects[ocio_omega_settings][download][branch] = 7.x-1.x
 
+projects[wcm_metatags][type] = module
+projects[wcm_metatags][subdir] = custom
+projects[wcm_metatags][download][type] = "git"
+projects[wcm_metatags][download][url] = git@code.osu.edu:ocio_odee_web/wcm_metatags.git
+projects[wcm_metatags][download][branch] = 7.x-1.x
+
 projects[wcm_panels_settings][type] = module
 projects[wcm_panels_settings][subdir] = custom
 projects[wcm_panels_settings][download][type] = "git"