Implement Google remarketing

This commit is contained in:
Björn Fromme
2019-05-06 11:21:19 +02:00
parent d0f0557aeb
commit 6fea91ae26
6 changed files with 156 additions and 49 deletions
@@ -27,6 +27,8 @@ namespace EP\EpProducts\Controller;
* This copyright notice MUST APPEAR in all copies of the script! * This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/ ***************************************************************/
use EP\EpProducts\CsvFormatter\FacebookCatalogCsvFormatter;
use EP\EpProducts\CsvFormatter\GoogleBusinessFeedCsvFormatter;
use EP\EpProducts\Domain\Model\Product; use EP\EpProducts\Domain\Model\Product;
use EP\EpProducts\Domain\Model\Reseller; use EP\EpProducts\Domain\Model\Reseller;
use EP\EpProducts\Service\ResellerDataService; use EP\EpProducts\Service\ResellerDataService;
@@ -154,46 +156,14 @@ class ResellerController extends ActionController
$fileHandle = fopen('php://output', 'wb'); $fileHandle = fopen('php://output', 'wb');
fputcsv($fileHandle, [ if ($type === 'google') {
'id', $csv = GoogleBusinessFeedCsvFormatter::format($data);
'availability', } else {
'condition', $csv = FacebookCatalogCsvFormatter::format($data);
'description', }
'image_link',
'link',
'title',
'price',
'brand',
]);
foreach ($data['product'] as $product) { foreach ($csv as $row) {
$minPrice = 0; fputcsv($fileHandle, $row);
$available = 0;
foreach ($product['hotels']['hotel'] as $hotel) {
foreach ($hotel['dates']['date'] as $date) {
if ($minPrice === 0 || $date['minprice'] < $minPrice) {
$minPrice = $date['minprice'];
}
$available++;
}
}
$description = preg_replace( "/\r|\n/", ' ', $product['description']);
$description = strip_tags($description);
$description = htmlspecialchars_decode($description);
fputcsv($fileHandle, [
$product['@id'],
$available > 0 ? 'in stock' : 'out of stock',
'new',
$description,
$product['images']['image'][0],
$product['link'],
$product['name'],
$minPrice . ' EUR',
'brand-epreisen'
]);
} }
fclose($fileHandle); fclose($fileHandle);
@@ -0,0 +1,59 @@
<?php
namespace EP\EpProducts\CsvFormatter;
class FacebookCatalogCsvFormatter
{
/**
* @param array $data
* @return array
*/
public static function format(array $data)
{
$csv = [];
$csv[] = [
'id',
'availability',
'condition',
'description',
'image_link',
'link',
'title',
'price',
'brand',
];
foreach ($data['product'] as $product) {
$minPrice = 0;
$available = 0;
foreach ($product['hotels']['hotel'] as $hotel) {
foreach ($hotel['dates']['date'] as $date) {
if ($minPrice === 0 || $date['minprice'] < $minPrice) {
$minPrice = $date['minprice'];
}
$available++;
}
}
$description = preg_replace( "/\r|\n/", ' ', $product['description']);
$description = strip_tags($description);
$description = htmlspecialchars_decode($description);
$csv[] = [
$product['@id'],
$available > 0 ? 'in stock' : 'out of stock',
'new',
$description,
$product['images']['image'][0],
$product['link'],
$product['name'],
$minPrice . ' EUR',
'brand-epreisen'
];
}
return $csv;
}
}
@@ -0,0 +1,47 @@
<?php
namespace EP\EpProducts\CsvFormatter;
class GoogleBusinessFeedCsvFormatter
{
/**
* @param array $data
* @return array
*/
public static function format(array $data)
{
$csv = [];
$csv[] = [
'Destination ID',
'OriginID',
'Title',
'Final URL',
'Image URL',
'Price',
];
foreach ($data['product'] as $product) {
$minPrice = 0;
foreach ($product['hotels']['hotel'] as $hotel) {
foreach ($hotel['dates']['date'] as $date) {
if ($minPrice === 0 || $date['minprice'] < $minPrice) {
$minPrice = $date['minprice'];
}
}
}
$csv[] = [
$product['@id'],
$product['@id'],
$product['name'],
$product['link'],
$product['images']['image'][0],
$minPrice . '.00 EUR',
];
}
return $csv;
}
}
@@ -66,11 +66,13 @@
type: Boolean, type: Boolean,
default: false default: false
}, },
fbPixelData: { busProId: {
type: Object, type: Number,
default () { default: 0
return {} },
} nameInternal: {
type: String,
default: ''
}, },
daytrip: { daytrip: {
type: Number, type: Number,
@@ -93,7 +95,7 @@
this.detailShow = false; this.detailShow = false;
let query = {}; let query = {};
query[this.argumentPrefix + '[filterSettings]'] = this.filterSettings; query[this.argumentPrefix + '[filterSettings]'] = this.filterSettings;
$.post(this.uris['dates'], query, (json) => { $.post(this.uris['dates'], query, json => {
if (json.dates.length === 1) { if (json.dates.length === 1) {
this.singleDate = true; this.singleDate = true;
let dateRow = json.dates[0]; let dateRow = json.dates[0];
@@ -116,7 +118,7 @@
this.detailShow = false; this.detailShow = false;
let query = {}; let query = {};
query[this.argumentPrefix + '[product]'] = this.filterSettings; query[this.argumentPrefix + '[product]'] = this.filterSettings;
$.post(this.uris['dateslist'], query, (json) => { $.post(this.uris['dateslist'], query, json => {
if (json.dates.length === 1) { if (json.dates.length === 1) {
this.singleDate = true; this.singleDate = true;
let dateRow = json.dates[0]; let dateRow = json.dates[0];
@@ -151,12 +153,13 @@
let query = {}; let query = {};
query[this.argumentPrefix + '[filterSettings]'] = this.filterSettings; query[this.argumentPrefix + '[filterSettings]'] = this.filterSettings;
query[this.argumentPrefix + '[date]'] = dateUid; query[this.argumentPrefix + '[date]'] = dateUid;
$.post(this.uris['pricetable'], query, (json) => { $.post(this.uris['pricetable'], query, json => {
this.priceTableRows = json.priceTable; this.priceTableRows = json.priceTable;
this.dateStart = dayjs(json.dateStart).format('DD.MM.YYYY'); this.dateStart = dayjs(json.dateStart).format('DD.MM.YYYY');
this.dateEnd = dayjs(json.dateEnd).format('DD.MM.YYYY'); this.dateEnd = dayjs(json.dateEnd).format('DD.MM.YYYY');
this.servicesIncluded = json.servicesIncluded; this.servicesIncluded = json.servicesIncluded;
this.loading = false; this.loading = false;
this.trackConversion();
EventBus.$emit('tableLoaded'); EventBus.$emit('tableLoaded');
}, 'json'); }, 'json');
}, },
@@ -179,6 +182,31 @@
}, },
scrollToMain () { scrollToMain () {
EventBus.$emit('scrollTo', '#main'); EventBus.$emit('scrollTo', '#main');
},
trackConversion () {
const dataLayer = window.dataLayer || [];
dataLayer.push({
'google_tag_params': {
'travel_destid': this.busProId,
'travel_originid': this.busProId,
'travel_pagetype': 'offerdetails',
'travel_startdate': this.dateStart,
'travel_enddate': this.dateEnd,
'travel_totalvalue': this.calculateMinPriceFromPriceTable() + '.00 EUR'
}
});
},
calculateMinPriceFromPriceTable () {
let minPrice = 0;
for (let index in this.priceTableRows) {
if (!this.priceTableRows.hasOwnProperty(index)) {
continue;
}
if (minPrice === 0 || this.priceTableRows[index].roomPrice < minPrice) {
minPrice = this.priceTableRows[index].roomPrice;
}
}
return minPrice;
} }
}, },
created () { created () {
@@ -17,7 +17,8 @@
}' }'
argument-prefix='<ep:argumentPrefix pluginName="Ajax" />' argument-prefix='<ep:argumentPrefix pluginName="Ajax" />'
:hotel-first="{f:if(condition: settings.hotelOnTop, then: 'true', else: 'false')}" :hotel-first="{f:if(condition: settings.hotelOnTop, then: 'true', else: 'false')}"
:fb-pixel-data="{ productUid: <f:format.raw>{product.busProId}</f:format.raw>, nameInternal: '<f:format.raw>{product.nameInternal}</f:format.raw>' }" :bus-pro-id="{product.busProId -> f:format.raw()}"
name-internal="{product.nameInternal -> f:format.raw()}"
:daytrip="{product.daytrip -> v:variable.convert(type: 'int')}" :daytrip="{product.daytrip -> v:variable.convert(type: 'int')}"
inline-template> inline-template>
<article> <article>
@@ -235,7 +236,7 @@
</div> </div>
</div> </div>
</div> </div>
<facebook-pixel :values="{ content_ids: [ fbPixelData.productUid ], content_name: fbPixelData.nameInternal, content_type: 'product' }"></facebook-pixel> <facebook-pixel :values="{ content_ids: [ busProId ], content_name: nameInternal, content_type: 'product' }"></facebook-pixel>
</div> </div>
</div> </div>
</article> </article>
@@ -14,6 +14,8 @@
<f:link.action action="xml" arguments="{reseller: reseller}" target="_blank">Export XML</f:link.action> <f:link.action action="xml" arguments="{reseller: reseller}" target="_blank">Export XML</f:link.action>
<h2>Gesamtexport CSV (Facebook)</h2> <h2>Gesamtexport CSV (Facebook)</h2>
<f:link.action action="csv" arguments="{reseller: reseller}" target="_blank">Export CSV</f:link.action> <f:link.action action="csv" arguments="{reseller: reseller}" target="_blank">Export CSV</f:link.action>
<h2>Gesamtexport CSV (Google)</h2>
<f:link.action action="csv" arguments="{reseller: reseller, type: 'google'}" target="_blank">Export CSV</f:link.action>
<h2>Einzelexport für Copy&amp;Paste</h2> <h2>Einzelexport für Copy&amp;Paste</h2>
<ul> <ul>
<f:for each="{products}" as="product"> <f:for each="{products}" as="product">