Adding parameters to Shopify purchase event - events

In order to better better match purchase events to Meta accounts - and therein improving ad delivery - I need to add Phone Number, email, first name and last name to purchase events in Shopify.
How would one go about this?

You need to add your script in the checkout (and thank you) page.
To do that you have a section under Settings -> Checkout -> Additional Scripts
In that part you can use the liquid variables. For example something like
window.dataLayer.push({
...
page_type: "purchase",
page_currency: "{{ shop.currency }}",
{% if customer %}
user_type: "member",
user_id: "{{ customer.id | remove: "'" | remove: '"' }}",
user_r: "{{ customer.last_order.created_at | date: "%B %d, %Y %I:%M%p" }}",
user_f: "{{ customer.orders_count }}",
user_m: "{{ customer.total_spent | times: 0.01 }}",
user_eh: "{{ customer.email | sha1 }}"
{% else %}
user_type: "visitor"
{% endif %}
});

Related

Ansible - best method to copy results of json_query to file

Below is an excerpt from a playbook that queries a REST service, stores the results, and displays to the screen via the debug module. What is the best way to write the result to a file with the desired format?
vars:
jquery: "json[].{File: filename, Path: filepath, Size: size}"
uri:
url: "https://somewhere.com/subscriptions"
register: "subscriptions"
debug:
msg: "{{ subscriptions | json_query(jquery) }}"
copy:
content: "{{ subscriptions | json_query(jquery) }}"
dest: "./subscriptions.txt"
The debug output looks like the below:
{ File: "afile",
Path: "somepath/afile",
Size: "9999.0"
},
{ File: "bfile",
Path: "somepath/bfile",
Size: "9999.0"
}
Using the copy module the results are all ran together. What is the best way to preserve the formatting of the debug ouput? Bonus points if the "{}," characters can be removed.
I'm assuming the correct answer involves the use of templating?
Thank you.
The shortest answer is probably:
copy:
content: "{{ subscriptions | json_query(jquery) | to_nice_json }}"
dest: "./subscriptions.txt"
This will produce nicely formatted JSON output. Because your result is a list, the output file will look like:
[
{
"File": "afile",
"Path": "somepath/afile",
"Size": "9999.0"
},
{
"File": "bfile",
"Path": "somepath/bfile",
"Size": "9999.0"
}
]
If you want output that isn't valid JSON, you'll probably have to use
the template module to produce it yourself.
If you want your output to look like this:
File: afile,
Path: somepath/afile
Size: 9999.0
File: bfile,
Path: somepath/bfile
Size: 9999.0
You might write:
copy:
content: |
{% for item in items %}
File: {{ item.File }}
Path: {{ item.Path }}
Size: {{ item.Size }}
{% endfor %}
dest: "./subscriptions.txt"
vars:
items: "{{ subscriptions | json_query(jquery) }}"
...but ideally you would use the template module instead of
embedding the template in the copy module like this (that's just a matter of moving the content of the content key in this example into a file, and using that as the src of the template task).

Jinja2: Add new key/value items inside a for loop statement

I want to append new key/value item to a hash inside a jinja2 for loop. Until now i have only been able to append a static entry, but i would like to add a test depending on the current element.
My data set looks like:
people:
- forename: John
name: Doe
gender: M
- forename: Jane
name: Doe
gender: F
I want to dump something like:
Hello Mr John Doe
Hello Ms Jane Doe
I can do something like :
{% for person in people -%}
Hello {{ 'Ms' if person.gender=='F' else 'Mr' }} {{ person.forename }} {{ person.name }}
{% endfor -%}
but i find this syntax awkward, especially if i have to repeat the test many times.
My idea is to add a title key to my data and i am trying to do it inside the for statement.
Jinja accept the combine filter for that:
{% for person in people | map ('combine', { "title": 'M.'} ) -%}
Hello {{ person.title ~ ' ' ~ person.forename ~ ' ' ~ person.name }}
{% endfor -%}
And i can also add a test to choose the correct title:
{% for person in people | map ('combine', { "title": 'Mr'} if 1==1 else { "title": 'Ms'}) -%}
Hello {{ person.title ~ ' ' ~ person.forename ~ ' ' ~ person.name }}
{% endfor -%}
But i have been unable to acces to the current person, i have tried thinks like person.gender=='M', self.gender=='M', this.gender=='M', but without success.
Is there any way to do it ?
Thanks !
I am answering my question since i finally have found a way to do it.
The key is to filter the people array with selectattr, then to apply the combine and do it again for the rest of the array.
{% for person in people | selectattr("gender", "equalto", "F") | map('combine', { 'title': 'Ms' }) +
people | selectattr("gender", "equalto", "M") | map('combine', { 'title': 'Mr' }) -%}
Hello {{ person.title }} {{ person.forename }} {{ person.name }}
{% endfor -%}
The for statement is of course more complex, but the loop body is straightforward.

How can I loop over a list of dicts and their content lists

I have the following var
---
- hosts: all
vars:
new_service:
name: test
Unit:
- option: Description
value: "Testname"
Service:
- option: ExecStart
value: "/usr/bin/python3 -m http.server 8080"
- option: WorkingDirectory
value: /home/test/testservice/html
I want to be able to use the ini_file module to create a service template so that the above var is converted into the following ini file
[Unit]
Description=Testname
[Service]
ExecStart=/usr/bin/python3 -m http.server 8080
WorkingDirectory=/home/test/testservice/html
I cannot figure out how to loop over this. I was thinking to use the product() so as to loop over nested lists, maybe something like this?
- name: "Create new unit section of service file"
ini_file:
path: "~{{ USERNAME }}/.config/systemd/user/{{ new_service[name] }}"
section: "{{ item.0 }}"
option: "{{ item.1.option }}"
value: "{{ item.1.value }}"
loop: "{{ ['unit', 'service'] | product({{ new_service[item.0] }})"
But I do not believe item is defined in the loop definition itself
(The reason I'm going with ini_file rather than template is because I want the service file creation to be able to handle any number of fields on demand)
You can still use a template to have a variable number of sections and options. Using loop with ini_file here is not efficient IMO. The only real use case would be if you need to keep the original contents of the file only adding new ones. But performance will be dramatically lower than a single template, especially if your have a lot of elements.
The only difficulty I see is that you have a name attribute in your dict which is not a section title. But it can be easily ruled out.
template.j2
{% for section in new_service %}
{% if section != 'name' %}
[{{ section }}]
{% for option in new_service[section] %}
{{ option.option }}={{ option.value }}
{% endfor %}
{% endif %}
{% endfor %}
Back to original question
If you really want to go through the loop route, it is still possible but will require quite a bit of effort with your actual data structure (loop/set_fact/... to finally get a single loopable structure).
If possible, I would change it to the following:
new_service:
name: test
sections:
- section: Unit
options:
- option: Description
value: "Testname"
- section: Service
options:
- option: ExecStart
value: "/usr/bin/python3 -m http.server 8080"
- option: WorkingDirectory
value: /home/test/testservice/html
And you can then directly loop through this structure using the subelements lookup. Note that "name" (on top level) is not a var but a string identifier for your service name value and should be used as such (fixed in my below example):
- name: "Create new unit section of service file"
ini_file:
path: "~{{ USERNAME }}/.config/systemd/user/{{ new_service.name }}"
section: "{{ item.0.section }}"
option: "{{ item.1.option }}"
value: "{{ item.1.value }}"
loop: "{{ lookup('subelements', new_service.sections, 'options') }}"
You can easily adapt my first example template to this new data structure as well if needed.

Problems with Jinja2 and ansible making a sub dict

I need to read a csv file with diferent IPs and make a dictionary with a jinja2 filter for modificate the IP depending the IPNumber value. The yml file is like:
- read_csv:
path: vms.csv
key: Number
fieldnames: Name,IP1,IP2,IP3,IP4,IPNumber
delimiter: ';'
register: vms
- name: vms to dict
debug:
msg:
- {{'Name':{{ item.value.Name }},
{% if item.value.IPNumber == "1" %}
'IP':{{ item.value.IP1 }},
{% endif %}
{% if item.value.IPNumber == "2"%}
'IP':{{ item.value.IP2 }},
{% endif %}
{% if item.value.IPNumber == "3"%}
'IP':{{ item.value.IP3 }},
{% endif %}
{% if item.value.IPNumber == "4"%}
'IP':{{ item.value.IP4 }},
{% endif %}}}
loop: "{{ vms.dict | dict2items }}"
register: vms2
But I get the error:
The error appears to be in '/etc/ansible/roles/vms.yml': line 17, column 16, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
'Name':{{ item.value.Name}},
{% if item.value.IPNumber == "1" %}
^ here
I know is a syntax problem but I dont guess where the problem is.
I need some help.
The following task should create your dictionary as per your requirement inside a var you can reuse elsewhere. Rename my_ip_dict to whatever suits your project better.
- name: Create my IP dictionary
set_fact:
my_ip_dict: >-
{{
my_ip_dict | default({})
| combine({item.value.Name: item.value['IP' + item.value.IPNumber]})
}}
loop: "{{ vms.dict | dict2items }}"
- name: Check the result:
debug:
var: my_ip_dict
Note that I have dropped all the if/else structures by calling directly the correct field depending on IPNumber. I took for granted it always has a value in the valid scope or the other existing IP* fields. If this is not the case, you can always default that value e.g. item.value['IP' + item.value.IPNumber] | default('N/A')
You should put only variables/expressions within {{ or {%. To me 'Name' looks like normal text and should be outside.
Example:
# Notice the quotes `"` symbol at the beginning and end of debug message
- debug:
msg:
- "Name: {{ item.value.Name }},
{% if item.value.IPNumber == "1" %}
IP: {{ item.value.IP1 }}
# and so on...
{% endif %}"
This at least should address the error message.

Filter data from list of dicts using condition in Jinja2 filter

data:
- { name: foo, app: foo, isweb: true }
- { name: bar, app: bar, isweb: true }
- { name: foobar, app: foobar, isweb: false }
- { name: baz, app: baz, isweb: false }
Desired result is list as:
{% set list= [] %}
{% for item in data %}
{% if item.isweb == true %}
{{list.append(item.app)}}
{% endif %}
{% endfor %}
Can this be implemented using filters :
{{ data | map(attribute='app') | list | join(' ') }}
Basically the question is how to implement the above for loop using a single line filter (as above) but only get data which have a value of isweb true.
There can be several ways to do this (working with ansible 2.7. Not sure about lower versions):
Pure Filter way(using selectattr and map):
- set_fact: app_list="{{ data | selectattr("isweb", "equalto", true) | map(attribute='app') | list }}"
Using ansible loop with condition in filter:
- set_fact: app_list="{{ (app_list | default([])) + ([ item.app ] if (item.isweb == True) else []) }}"
loop: "{{ data }}"
Using Ansible loop with when statement:
- set_fact: app_list="{{ (app_list | default([])) + [ item.app ] }}"
loop: "{{ data }}"
when: item.app is defined and item.app == true
You're very close to solving it, just need to add another filter:
{{ data | selectattr('isweb', 'equalto', true) | map(attribute='app') | list | join(' ') }}

Resources