Skip to content

Commit

Permalink
Merge pull request #3224 from alphagov/ga4-refactor
Browse files Browse the repository at this point in the history
Refactor GA4 code
  • Loading branch information
andysellick authored Dec 13, 2023
2 parents 4bf4a87 + 5952026 commit 8ccdaf6
Show file tree
Hide file tree
Showing 24 changed files with 213 additions and 133 deletions.
5 changes: 3 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,15 @@ GEM
govuk_personalisation (0.15.0)
plek (>= 1.9.0)
rails (>= 6, < 8)
govuk_publishing_components (36.1.0)
govuk_publishing_components (37.0.0)
govuk_app_config
govuk_personalisation (>= 0.7.0)
kramdown
plek
rails (>= 6)
rouge
sprockets (>= 3)
sprockets-rails
govuk_schemas (4.7.0)
json-schema (>= 2.8, < 4.2)
govuk_test (4.0.1)
Expand Down Expand Up @@ -241,7 +242,7 @@ GEM
msgpack (1.7.2)
multi_test (1.1.0)
mutex_m (0.2.0)
net-imap (0.4.7)
net-imap (0.4.8)
date
net-protocol
net-pop (0.1.2)
Expand Down
43 changes: 0 additions & 43 deletions app/assets/javascripts/analytics-ga4/ga4-finder-tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,6 @@
GOVUK.analyticsGa4 = GOVUK.analyticsGa4 || {}

GOVUK.analyticsGa4.Ga4FinderTracker = {

// Finds the parent div containing the filters. Loops through each child div that has data-ga4-filter-parent on it . Sets an index on each of these child divs.
setFilterIndexes: function () {
var filterContainer = document.querySelector('[data-ga4-filter-container]')

if (!filterContainer) {
return
}

var filterParents = filterContainer.querySelectorAll('[data-ga4-filter-parent]')

for (var i = 0; i < filterParents.length; i++) {
filterParents[i].setAttribute('data-ga4-index', JSON.stringify({ index_section: i + 1, index_section_count: filterParents.length }))
}

window.GOVUK.triggerEvent(window, 'ga4-filter-indexes-added')
},

// Called when the search results updates. Takes the event target, and a string containing the type of change and element type. Creates the GTM schema and pushes it.
// changeEventMetadata is a string referring to the type of form change and the element type that triggered it. For example 'update-filter checkbox'.
trackChangeEvent: function (eventTarget, changeEventMetadata) {
Expand Down Expand Up @@ -157,31 +139,6 @@
} catch (e) {
console.error('GA4 configuration error: ' + e.message, window.location)
}
},

addFilterButtonTracking: function (button, section) {
button.setAttribute('data-ga4-expandable', '')
var ga4JSON = { event_name: 'select_content', type: 'finder', section: section }

try {
var index = button.closest('[data-ga4-index]') || undefined
if (index) {
var indexData = JSON.parse(index.getAttribute('data-ga4-index'))
// flatten the attributes in index into the main data
for (var prop in indexData) {
ga4JSON[prop] = indexData[prop]
}
} else {
console.warn('No data-ga4-index found on the following element or its parents:')
console.warn(button)
}
} catch (e) {
// if there's a problem with the index object, don't add the attribute
console.error('GA4 configuration error: ' + e.message, window.location)
return
}

button.setAttribute('data-ga4-event', JSON.stringify(ga4JSON))
}
}

Expand Down
20 changes: 12 additions & 8 deletions app/assets/javascripts/components/expander.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,21 @@ window.GOVUK.Modules = window.GOVUK.Modules || {}; // if this ; is omitted, none
$button.setAttribute('aria-expanded', expanded)
$button.setAttribute('aria-controls', this.$content.getAttribute('id'))

// GA4 Accordion tracking. Relies on the ga4-finder-tracker setting the index first, so we wrap this in a custom event.
window.addEventListener('ga4-filter-indexes-added', function () {
if (window.GOVUK.analyticsGa4) {
if (window.GOVUK.analyticsGa4.Ga4FinderTracker) {
window.GOVUK.analyticsGa4.Ga4FinderTracker.addFilterButtonTracking($button, this.$toggle.innerHTML)
var buttonAttributes = this.$module.getAttribute('data-button-data-attributes')
if (buttonAttributes) {
try {
buttonAttributes = JSON.parse(buttonAttributes)
for (var rawKey in buttonAttributes) {
var key = rawKey.replace(/_/g, '-').toLowerCase()
var rawValue = buttonAttributes[rawKey]
var value = typeof rawValue === 'object' ? JSON.stringify(rawValue) : rawValue
$button.setAttribute('data-' + key, value)
}
} catch (e) {
console.error('Error with expander button data attributes, invalid JSON passed' + e.message, window.location)
}
}.bind(this))

}
$button.innerHTML = toggleHtml

this.$toggle.parentNode.replaceChild($button, this.$toggle)
}

Expand Down
16 changes: 0 additions & 16 deletions app/assets/javascripts/live_search.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@

if (document.readyState === 'complete') {
this.Ga4EcommerceTracking()
this.ga4SetFilterIndexes()
} else {
window.addEventListener('DOMContentLoaded', function () {
this.Ga4EcommerceTracking()
this.ga4SetFilterIndexes()
}.bind(this))
}

Expand Down Expand Up @@ -634,19 +632,5 @@
}
}

LiveSearch.prototype.ga4SetFilterIndexes = function () {
if (GOVUK.analyticsGa4 && GOVUK.analyticsGa4.Ga4FinderTracker) {
var consentCookie = GOVUK.getConsentCookie()

if (consentCookie && consentCookie.settings) {
GOVUK.analyticsGa4.Ga4FinderTracker.setFilterIndexes()
} else {
window.addEventListener('cookie-consent', function () {
GOVUK.analyticsGa4.Ga4FinderTracker.setFilterIndexes()
})
}
}
}

GOVUK.LiveSearch = LiveSearch
}())
14 changes: 10 additions & 4 deletions app/controllers/finders_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def render_component(partial, locals)
def result_set_presenter
@result_set_presenter ||= ResultSetPresenter.new(
content_item,
facets,
all_facets,
results,
filter_params,
sort_presenter,
Expand All @@ -106,12 +106,18 @@ def results
@results ||= ResultSetParser.parse(search_results)
end

def all_facets
return @facets if defined?(@facets)

FacetsBuilder.new(content_item:, search_results:, value_hash: filter_params).facets
end

def facets
@facets ||= FacetsBuilder.new(content_item:, search_results:, value_hash: filter_params).facets
FacetsIterator.new(all_facets.select(&:filterable?))
end

def signup_links
@signup_links ||= SignupLinksPresenter.new(content_item, facets, keywords).signup_links
@signup_links ||= SignupLinksPresenter.new(content_item, all_facets, keywords).signup_links
end

def initialize_search_query(is_for_feed: false)
Expand Down Expand Up @@ -174,7 +180,7 @@ def keywords

def facet_tags
@facet_tags ||= FacetTagsPresenter.new(
facets.select(&:filterable?),
facets,
sort_presenter,
i_am_a_topic_page_finder:,
)
Expand Down
14 changes: 14 additions & 0 deletions app/lib/facets_iterator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class FacetsIterator
delegate :select, :any?, to: :@facets

def initialize(facets)
@facets = facets
@facets_with_ga4_section = @facets.select(&:has_ga4_section?)
end

def each_with_index_and_count
@facets.each do |facet|
yield facet, @facets_with_ga4_section.index(facet), @facets_with_ga4_section.count
end
end
end
4 changes: 4 additions & 0 deletions app/models/date_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def query_params
{ key => date_values }
end

def ga4_section
name
end

private

def value_fragments
Expand Down
8 changes: 8 additions & 0 deletions app/models/facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ def query_params
{}
end

def ga4_section
nil
end

def has_ga4_section?
!ga4_section.nil?
end

private

def and_word_connectors
Expand Down
4 changes: 4 additions & 0 deletions app/models/option_select_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ def closed_on_load_mobile?
open_on_load?
end

def ga4_section
name
end

private

def value_fragments
Expand Down
4 changes: 4 additions & 0 deletions app/models/radio_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def query_params
{ key => selected_value["value"] }
end

def ga4_section
""
end

private

def selected_value
Expand Down
4 changes: 4 additions & 0 deletions app/models/radio_facet_for_multiple_filters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def allowed_values
@filter_hashes
end

def ga4_section
""
end

private

attr_reader :filter_hashes
Expand Down
4 changes: 4 additions & 0 deletions app/models/taxon_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def query_params
}
end

def ga4_section
"Topic"
end

private

def value_fragments
Expand Down
4 changes: 4 additions & 0 deletions app/models/topical_facet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ def allowed_values
def to_partial_path
"option_select_facet"
end

def ga4_section
name
end
end
4 changes: 3 additions & 1 deletion app/views/components/_date_filter.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
aria_controls_id ||= false
date_errors_from ||= nil
date_errors_to ||= nil
data_attributes ||= nil
button_data_attributes ||= nil
%>
<% if key && name %>
<%= render "components/expander", { title: name } do %>
<%= render "components/expander", { title: name, data_attributes:, button_data_attributes: } do %>
<div class="govuk-!-margin-bottom-0" id="<%= key %>">
<%= render "govuk_publishing_components/components/input", {
label: {
Expand Down
10 changes: 7 additions & 3 deletions app/views/components/_expander.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
content_id = "expander-content-#{SecureRandom.hex(4)}"
shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)

css_classes = %w( app-c-expander )
css_classes << (shared_helper.get_margin_bottom) unless margin_bottom == 0
component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
component_helper.add_data_attribute({ module: "expander" })
component_helper.add_data_attribute({ "open-on-load": open_on_load })
component_helper.add_class("app-c-expander")
component_helper.add_class(shared_helper.get_margin_bottom) unless margin_bottom == 0
component_helper.add_data_attribute({ "button-data-attributes": button_data_attributes }) if local_assigns.include?(:button_data_attributes)
%>
<% if title %>
<%= tag.div class: css_classes, data: { module: "expander", 'open-on-load': open_on_load, 'ga4-filter-parent': '' } do %>
<%= tag.div(**component_helper.all_attributes) do %>
<h3 class="app-c-expander__heading">
<span class="app-c-expander__title js-toggle"><%= title %></span>
<svg version="1.1" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="0" height="0" class="app-c-expander__icon app-c-expander__icon--up" aria-hidden="true" focusable="false"><path d="m798.16 609.84l-256-256c-16.683-16.683-43.691-16.683-60.331 0l-256 256c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0l225.84-225.84 225.84 225.84c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331z"/></svg>
Expand Down
40 changes: 40 additions & 0 deletions app/views/components/docs/expander.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,43 @@ examples:
margin_bottom: 9
block: |
This is some content that is passed to the component. It should be distinct from the component, in that the component should not style or interact with it, other than to show and hide it.
with_counter:
description: If there are form elements within the expander it can display a count of the number of form elements with a selected or input value. This is to make it appear the same as the option select component when appearing with it in search pages. Note that if any form elements are selected on page load, the component will expand by default.
data:
title: Things
block: |
<div class="govuk-form-group gem-c-select">
<label class="govuk-label" for="level_one_taxon">Topic</label>
<select name="level_one_taxon" id="level_one_taxon" class="govuk-select gem-c-select__select--full-width">
<option value="">All topics</option>
<option value="1" selected>Business and industry</option>
<option value="2">COVID-19</option>
<option value="3">Corporate information</option>
</select>
</div>
<div class="govuk-form-group" data-ga4-section="Sub-topic">
<div class="govuk-form-group gem-c-select">
<label class="govuk-label" for="level_two_taxon">Sub-topic</label>
<select name="level_two_taxon" id="level_two_taxon" class="govuk-select gem-c-select__select--full-width">
<option value="">All sub-topics</option>
<option value="2">Business and the environment</option>
<option value="3">Business regulation</option>
<option value="4">Charities and social enterprises</option>
</select>
</div>
</div>
<div class="govuk-form-group">
<label for="public_timestamp[from]" class="gem-c-label govuk-label">Updated after</label>
<input aria-describedby="hint-fe643477" class="gem-c-input govuk-input" id="public_timestamp[from]" name="public_timestamp[from]" spellcheck="false" type="text" value="2023">
</div>
with_button_data_attributes:
description: Allows data attributes to be passed to the component to be added to the expand/collapse button. The attributes are written to the parent element then read by the JavaScript and applied to the button. This is used for tracking purposes.
data:
title: Organisation
button_data_attributes:
ga4_expandable: ""
ga4_event:
event_name: "select_content"
type: "finder"
block: |
Sssh I'm hiding
15 changes: 12 additions & 3 deletions app/views/finders/_date_facet.html.erb
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
<span data-ga4-change-category="update-filter text">
<%=
render "components/date_filter", {
<%= render "components/date_filter", {
name: date_facet.name,
key: date_facet.key,
from_value: date_facet.user_supplied_from_date,
to_value: date_facet.user_supplied_to_date,
aria_controls_id: "js-search-results-info",
date_errors_to: date_facet.error_message_to(@search_query),
date_errors_from: date_facet.error_message_from(@search_query)
date_errors_from: date_facet.error_message_from(@search_query),
data_attributes: { "ga4-filter-parent": date_facet.ga4_section, "ga4-index": { index_section: index + 1, index_section_count: count } },
button_data_attributes: {
ga4_expandable: "",
ga4_event: {
event_name: 'select_content',
type: 'finder',
section: date_facet.name,
index: { index_section: index + 1, index_section_count: count }
}
}
} %>
</span>
Loading

0 comments on commit 8ccdaf6

Please sign in to comment.