diff --git a/app/javascript/dashboard/components-next/HelpCenter/Pages/PortalSettingsPage/PortalIntegrationsSettings.vue b/app/javascript/dashboard/components-next/HelpCenter/Pages/PortalSettingsPage/PortalIntegrationsSettings.vue index f35d470c3..cab5c7ad1 100644 --- a/app/javascript/dashboard/components-next/HelpCenter/Pages/PortalSettingsPage/PortalIntegrationsSettings.vue +++ b/app/javascript/dashboard/components-next/HelpCenter/Pages/PortalSettingsPage/PortalIntegrationsSettings.vue @@ -26,12 +26,6 @@ const { replaceInstallationName } = useBranding(); // Provider keys and formats, mirroring Portal::ANALYTICS_CONFIG_FORMATS. Admin-only // (also enforced on the backend) since these inject tracking scripts into public pages. const ANALYTICS_PROVIDERS = [ - { - key: 'gtm_container_id', - i18nKey: 'GTM', - icon: 'i-logos-google-tag-manager', - format: /^GTM-[A-Z0-9]+$/, - }, { key: 'ga4_measurement_id', i18nKey: 'GA4', diff --git a/app/models/concerns/portal_config_schema.rb b/app/models/concerns/portal_config_schema.rb index f403f428d..27b6709b0 100644 --- a/app/models/concerns/portal_config_schema.rb +++ b/app/models/concerns/portal_config_schema.rb @@ -48,7 +48,6 @@ module PortalConfigSchema 'analytics' => { 'type' => %w[object null], 'properties' => { - 'gtm_container_id' => { 'type' => %w[string null] }, 'ga4_measurement_id' => { 'type' => %w[string null] }, 'hotjar_site_id' => { 'type' => %w[string null] }, 'plausible_domain' => { 'type' => %w[string null] }, diff --git a/app/models/portal.rb b/app/models/portal.rb index 57132b2f0..fc066bf51 100644 --- a/app/models/portal.rb +++ b/app/models/portal.rb @@ -56,7 +56,6 @@ class Portal < ApplicationRecord # Analytics id fields and the format each must match. Formats keep values safe to # interpolate into markup. Add a provider here and its snippet in _portal_analytics.html.erb. ANALYTICS_CONFIG_FORMATS = { - 'gtm_container_id' => /\AGTM-[A-Z0-9]+\z/, 'ga4_measurement_id' => /\AG-[A-Z0-9]+\z/, 'hotjar_site_id' => /\A\d+\z/, 'plausible_domain' => /\A[a-z0-9]([a-z0-9.-]*[a-z0-9])?\z/i, @@ -71,7 +70,9 @@ class Portal < ApplicationRecord def analytics value = config_value('analytics') - value.is_a?(Hash) ? value : {} + return {} unless value.is_a?(Hash) + + value.deep_stringify_keys.slice(*ANALYTICS_CONFIG_FORMATS.keys) end # Reader per analytics id (e.g. portal.ga4_measurement_id) so the snippet partials stay simple. @@ -159,11 +160,18 @@ class Portal < ApplicationRecord def normalize_config self.config = persisted_config.merge((config || {}).deep_stringify_keys) + normalize_analytics_config config['allowed_locales'] = allowed_locale_codes config['default_locale'] = default_locale config['draft_locales'] = draft_locale_codes end + def normalize_analytics_config + return unless config['analytics'].is_a?(Hash) + + config['analytics'] = config['analytics'].deep_stringify_keys.slice(*ANALYTICS_CONFIG_FORMATS.keys) + end + def validate_config denied_keys = config.keys - CONFIG_JSON_KEYS errors.add(:config, "in portal on #{denied_keys.join(',')} is not supported.") if denied_keys.any? diff --git a/app/views/layouts/_portal_analytics.html.erb b/app/views/layouts/_portal_analytics.html.erb index 277c66d55..30f1e6e82 100644 --- a/app/views/layouts/_portal_analytics.html.erb +++ b/app/views/layouts/_portal_analytics.html.erb @@ -1,16 +1,3 @@ -<%# Analytics tags. Every value below is validated against Portal::ANALYTICS_CONFIG_FORMATS, %> -<%# so it is restricted to a safe shape (no quotes/angle brackets) before interpolation. %> -<% if @portal.gtm_container_id.present? %> - - - -<% end %> <% if @portal.ga4_measurement_id.present? %> diff --git a/app/views/layouts/_portal_analytics_noscript.html.erb b/app/views/layouts/_portal_analytics_noscript.html.erb index cda3667a3..733524276 100644 --- a/app/views/layouts/_portal_analytics_noscript.html.erb +++ b/app/views/layouts/_portal_analytics_noscript.html.erb @@ -1,9 +1,3 @@ -<% if @portal.gtm_container_id.present? %> - - - -<% end %> <% if @portal.meta_pixel_id.present? %>