Is there a way in GTM to create a variable tracking the product category of a checkout conversion without duplicate categories? - google-tag-manager

I currently have a custom variable that pulls ecommerce information out of the data layer and returns with the product categories for that purchase. I did this through two custom variables - the first being "PurchaseProducts", which has the data layer variable of "ecommerce.purchase.products", and then making a second Custom JavaScript variable with the code
function () { return {{PurchaseProducts}}.map(function(a) {return a.category;}); }
This does work on returning the categories for that purchase, however it seems to be returning the category of each item. (For example, "Produce, Produce, Pantry, Health and Beauty, Specialty Cheese, Pantry")
Is there a way to adjust the code to have the different categories be pulled but not have the duplicates? Or should I look into having separate variables for each of the categories?

You just need something like remove duplicate in JavaScript array.
Here is a way:
var arr = ["apple", "mango", "apple", "orange", "mango", "mango"];
var unique = arr.reduce(function (acc, curr) {
if (!acc.includes(curr))
acc.push(curr);
return acc;
}, []);
console.log(unique);
If you search about it. Make sure you are not using JS ES6 since Google Tag Manager not support it. If you are not familiar, when you see const, let, => in the code. It is ES6 and paste it in GTM will show error when previewing.

Related

Populating Array Data from Data Layer into GTM

I have a Data Layer that is giving me information like this from Drupal
dataLayer = [{
"entityType":"node",
"entityBundle":"article",
"entityTaxonomy":
{"funnel_path":{"2":"Find a Park"},
"byline":{"4":"Name1","5":"Name2"}},"drupalLanguage":"en",
"userUid":"1"}
];
</script>
I can easily use GTM's Data Layer variable to pull in entityBundle. How do I set it to pull in the information in byline? I tried entityTaxonomy.byline, but that give me an array. I can set to do entityTaxonomy.byline.4 to get Name1, but that would be silly since the editors would be regularly adding things.
I am planning to add the byline, ultimately, into Custom Dimension 2 in Google Analytics.
I am looking to have the data that goes to Custom Dimension 2 to be Name1, Name2 . Sometimes this will be just one value. Sometimes it can be up to 20 values.
What do I need to do in GTM to get it to register that information?
entityTaxonomy.byline actually gives you an object. You would need to do a bit of processing to get an array that you can join into a string. One possible way would be
temp = [];
Object.keys(test.entityTaxonomy.byline).map(function(key, index) {
temp.push(test.entityTaxonomy.byline[key]);
});
bylines = temp.join(",")
(I'm sure that could be done much more concise). In GTM you would need to create a variable that contains the objects with the bylines, then you could do the processing in a custom javascript variable (which is by definition an anonymous function with a return value)
function() {
var byLineObject = {{bylines}} // created as datalayer var beforehand
temp = [];
Object.keys(byLineObject).map(function(key, index) {
temp.push(byLineObject[key]);
});
return temp.join(",")
}

Meteor template exclusive subscription

I have two different templates in one route. Both return a number of items from a uniform collection however, when I do
Template.stepOneSelect.onCreated(function() {
var instance = this;
instance.autorun(function() {
var subsciption = instance.subscribe('stepOne');
});
instance.occupations = function() {
return Occupations.find();
}
});
it returns Occupations from the whole route. There isn't a way for me to query the ones I need in one template because I query them on the server with other Collection that I am not subscribed to in that template.
So I need
Template.stepOneSelect.helpers({
stepOneTitles: function () {
return Template.instance().occupations();
}
});
to only return the Occupations from that template and I am getting all the occupations from the route
// MORE INFO
I have two collections, CareerPaths and Occupations.
CareerPaths has fields like occupationOneId which is an _id of the Occupation. It would be easy if I had a field in each Occupation that states which step of the CareerPath it is but one Occupation can be in different steps of a CareerPath. So I need to be returning Occupations based on CareerPaths. The route has two sections, one with a list of CareerPaths with a limit (only 10 at a time) and the other section should have ALL the Occupations from the first step of a career path, etc. I haven't found anything in publishComposite to only return the Children of a publication.
If I am getting this right, you are trying to display only the data published by a particular subscription. The easy way to do this would be to move the query used in the publication into client/server code, then call the query from both the publication and the client-side query.

Google Places API: How to use multiple types?

I need a POI API that returns ratings, photos, opening/closing times, etc and I thought Google Places API seemed to do what I want, but I am having some trouble with filtering: I want to use the autocomplete feature with multiple types for filtering.
Here is what I have:
var map;
var selectAttractionAutocomplete;
var selectCityAutocompleteOptions = {
types: ['(cities)']
};
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(-33.8665433, 151.1956316),
zoom: 15
});
var inputsearchedCity = document.getElementById('input-searched-city');
selectCityAutocomplete = new google.maps.places.Autocomplete(inputsearchedCity, selectCityAutocompleteOptions);
selectCityAutocomplete.bindTo('bounds', map);
google.maps.event.addListener(selectCityAutocomplete, 'place_changed', function () {
console.log(selectCityAutocomplete.getPlace());
});
How can I use multiple types?
I have tried pipes, commas, brackets... nothing works:
var selectCityAutocompleteOptions = {
types: ['cities|point_of_interest']
};
If your are using in a query string, use the | separator. Remember that only 'geocode|establishment' is currently valid as a collection type, which is the same than not specifying any combined type.
See:
https://developers.google.com/places/web-service/autocomplete#place_types
You may restrict results from a Place Autocomplete request to be of a certain type by passing a types parameter. The parameter specifies a type or a type collection, as listed in the supported types below. If nothing is specified, all types are returned. In general only a single type is allowed. The exception is that you can safely mix the geocode and establishment types, but note that this will have the same effect as specifying no types.
According to Google Documentation, point_of_interestis of type 2, which are not supported in the types filter of a place search, or in the types property when adding a place.
This question is partly answered in this thread.
First, the place type of "cities" it not supported. You can find a list of supported place types here.
There is no way to use multiple types at once. However, you can call the API twice in order to get similar results. For example:
var selectCityAutocompleteOptions1 = {
types: ['zoo']
};
var selectCityAutocompleteOptions2 = {
types: ['museum']
};
Based off of your description, though, it sounds like you want all points of interest results, without filtering by type. In that case you might want to use a Find Place Requests Place Search instead.
Encountered this recently. Answer is here Google Places Auto-Complete
types, which can either specify one of two explicit types or one of two type collections.
var request = {
bounds: map.getBounds(),
types: ['bar','park']
//keyword: 'best view'
};

How to get statistics of where visitors come from via URL params

There are many QR codes that contains URL of website such as:(it just demos link)
http://www.popupstore.com/index.php?qrcode_type=magazine&location=Singapore
http://www.popupstore.com/index.php?qrcode_type=banner&location=Vietnam
I need a way can summary to know that where customer come from (nearly same as source/channel in Google Analytics):
Type: Mazazine, banner, etc.
Location: Vietnam, Singapore, etc.
Can anyone help me please :)
You could create two Custom Dimensions, each for Type and another for Country
As per your need define the appropriate Scope of the dimension, a Hit level or Session level scope would be appropriate.
You need to push custom dimensions into Google Analytics i.e. additonal JS code in your site.
ga('send', 'pageview', {
'dimension1': 'Magzine',
'dimension2': 'Singapore'
});
How this works
User scans the code and visits the store
Site has a JS code snippet that would get the query parameters from the URL and sets a custom dimension for each parameter
Setting the custom dimension would let Google Analytics know the value of the Type and Country
It is your JS code that tells Google Analytics what value to take for custom dimension. Google Analytics would not know that the value came from the URL.
To get a query parameter value via javascript you can refer to this answer, If you take the function provided there by Jan Turon (head over and give him an upvote of this helps you):
function getJsonFromUrl() {
var query = location.search.substr(1);
var result = {};
query.split("&").forEach(function(part) {
var item = part.split("=");
result[item[0]] = decodeURIComponent(item[1]);
});
return result;
}
You can use this to dynamically set the dimensions based on the url. You first call the function to return an JSON object that has the key/value pairs from the query parameters, then you insert the needed values to set the dimensions:
result = getJsonFromUrl();
ga('send', 'pageview', {
'dimension1': result.qrcode_type,
'dimension2': result.location
});

Meteor: Remove collection attributes when another collection is deleted

I have two collections: one for Posts and one for Categories. Posts have one or more categories. I'd like for the Posts collection to be updated if a category is deleted, so that posts do contain any non-existent categories. I've got this to work, but I'm not sure it is the most efficient way to do it.
This code is what fires when a category delete button is pressed. This both removes the category from the collection, and goes through each post that contains the category and updates the category array to exclude the deleted category.
Template.listCategories.events({
'click .delete-category': function(e){
e.preventDefault();
var category = this.name;
Categories.remove(this._id);
var posts = Posts.find({categories: category}).fetch();
for (var i=0;i<posts.length;i++){
var cats = _.without(posts[i].categories, category);
Posts.update(posts[i]._id, {$set: {categories: cats}});
}
}
});
First I set the a 'category' variable to equal the name of the category being deleted.
Second, I actually remove the category from the collection.
Lastly, I set a 'posts' variable equal to a fetch of all posts that contain the category name, which returns an object of posts. I iterate through the posts, and, with the help of underscore, I use the '_.without' function to return an array of categories that excludes the deleted category. I then call Posts.update to update the categories with the new array.
My concern, though, is that I'm calling Posts.update each time in the For loop. It's a client side call, so maybe that doesn't matter as much? I still feel like there is a better way to do this. Any help?
I think you are looking for the $pull operator (docs):
The $pull operator removes all instances of a value from an existing
array.
With this your code can be simplified to this:
Template.listCategories.events({
'click .delete-category': function(e){
e.preventDefault();
var category = this.name;
Categories.remove(this._id);
Posts.update({categories: category}, {$pull: {categories: category}}, {multi:true});
}
});
NB:
It's a client side call, so maybe that doesn't matter as much?
Your assertion is wrong, Posts.update is not just a client-side call. Actually, a stub that using minimongo simulates the effect of the update operation is executed on the client while in parallel the update is also remotely executed on the server.

Resources