From 4654cb55dcf3e7db25976f5e245bc52313b316ba Mon Sep 17 00:00:00 2001 From: Eflyax Date: Thu, 2 Nov 2017 01:33:46 +0100 Subject: [PATCH 1/3] Changed API, invoke rendering events from backend --- src/DI/FacebookPixelExtension.php | 1 - src/FacebookPixel/FacebookPixel.php | 103 ++++++++++-------- src/FacebookPixel/FacebookPixelService.php | 26 ++--- src/FacebookPixel/templates/commonEvent.latte | 5 +- .../templates/facebookPixel.latte | 21 +++- 5 files changed, 83 insertions(+), 73 deletions(-) diff --git a/src/DI/FacebookPixelExtension.php b/src/DI/FacebookPixelExtension.php index 4303bcc..af409de 100755 --- a/src/DI/FacebookPixelExtension.php +++ b/src/DI/FacebookPixelExtension.php @@ -38,4 +38,3 @@ public function loadConfiguration() } } - diff --git a/src/FacebookPixel/FacebookPixel.php b/src/FacebookPixel/FacebookPixel.php index 9fcaf65..7dddb46 100755 --- a/src/FacebookPixel/FacebookPixel.php +++ b/src/FacebookPixel/FacebookPixel.php @@ -7,6 +7,16 @@ class FacebookPixel extends Control { + const EVENT_VIEW_CONTENT = 'ViewContent', + EVENT_PURCHASE = 'Purchase', + EVENT_ADD_TO_CART = 'AddToCart'; + + private $sessionEvents = [ + self::EVENT_ADD_TO_CART, + self::EVENT_VIEW_CONTENT, + self::EVENT_PURCHASE, + ]; + /** @var string */ private $facebookId; @@ -33,11 +43,17 @@ public function __construct($id, FacebookPixelService $facebookPixelService, $pr public function render() { $this->template->id = $this->facebookId; + $events = []; + foreach ($this->sessionEvents as $sessionEvent) { + $events[] = $this->facebookPixelService->getEventContent($sessionEvent); + } + $this->template->specialEvents = $events; $this->template->setFile(__DIR__ . '/templates/facebookPixel.latte'); $this->template->render(); + $this->clearEventsFromSession(); } - public function renderViewContent( + public function viewContent( $contentIds, $contentName = null, $contentCategory = null, @@ -45,63 +61,49 @@ public function renderViewContent( $currency = null ) { - $this->template->parameters = - $this->prepareProductsToParameters($contentIds, $contentName, $contentCategory, $value, $currency); - $this->template->event = FacebookPixelService::EVENT_VIEW_CONTENT; - $this->template->id = $this->facebookId; - $this->template->render(__DIR__ . '/templates/commonEvent.latte'); + $this->sendEventToOutput( + self::EVENT_VIEW_CONTENT, + $this->prepareProductsToParameters( + $contentIds, + $contentName, + $contentCategory, + $value, + $currency + ) + ); } - public function renderAddToCart( + public function addToCart( $contentIds, $contentName = null, $contentCategory = null, $value = null, - $currency = null, - $selector = null + $currency = null ) { - if (!$this->facebookPixelService->eventStatus(FacebookPixelService::EVENT_ADD_TO_CART) && !$selector) { - - return; - } - $this->template->selector = $selector; - $this->template->id = $this->facebookId; - $this->template->event = FacebookPixelService::EVENT_ADD_TO_CART; - $this->template->parameters = - $this->prepareProductsToParameters($contentIds, $contentName, $contentCategory, $value, $currency); - $this->template->render(__DIR__ . '/templates/addToCart.latte'); - if (!$selector) { - $this->facebookPixelService->eventEnd(FacebookPixelService::EVENT_ADD_TO_CART); - } + $this->sendEventToOutput( + $this->template->event = self::EVENT_ADD_TO_CART, + $this->prepareProductsToParameters($contentIds, $contentName, $contentCategory, $value, $currency) + ); } - public function renderPurchase($value, $currency, $contentIds = null) + public function purchase($value, $currency, $contentIds = null) { - if (!$this->facebookPixelService->eventStatus(FacebookPixelService::EVENT_PURCHASE)) { + $this->sendEventToOutput( + $this->template->event = self::EVENT_PURCHASE, + $this->prepareProductsToParameters($contentIds, null, null, $value, $currency) + ); + } - return; - } - if ($value) { - $parameters['value'] = $this->formatPrice($value); - } - if ($currency) { - $parameters['currency'] = "'{$currency}'"; - } - if (!is_array($contentIds)) { - $contentIds = [$contentIds]; - } - $idsWithPrefix = []; - foreach ($contentIds as $id) { - $idsWithPrefix[] = $this->productIdPrefix . $id; + private function sendEventToOutput($event, $eventParameters) + { + $output = "fbq('track', '" . $event . "'"; + if (isset($eventParameters)) { + $output .= ', ' . $eventParameters; } - $idsWithPrefix = array_map('strval', $idsWithPrefix); - $parameters['content_type'] = count($idsWithPrefix) > 1 ? 'product_group' : 'product'; - $parameters['content_ids'] = $idsWithPrefix; - $this->template->parameters = json_encode($parameters); - $this->template->event = FacebookPixelService::EVENT_PURCHASE; - $this->template->render(__DIR__ . '/templates/commonEvent.latte'); - $this->facebookPixelService->eventEnd(FacebookPixelService::EVENT_PURCHASE); + $output .= ");"; + $output = str_replace('"', "'", $output); + $this->facebookPixelService->saveEvent($event, $output); } /** @@ -132,7 +134,7 @@ private function prepareProductsToParameters( $parameters['content_name'] = $contentName; $parameters['content_category'] = $contentCategory ? $contentCategory : null; $parameters['value'] = $value ? $this->formatPrice($value) : null; - $parameters['currency'] = $currency ? "'{$currency}'" : null; + $parameters['currency'] = $currency ?: null; foreach ($parameters as $key => $value) { if (!$value) { @@ -151,4 +153,11 @@ private function formatPrice($value) return number_format($value, 2, '.', ''); } -} \ No newline at end of file + private function clearEventsFromSession() + { + foreach ($this->sessionEvents as $sessionEvent) { + $this->facebookPixelService->removeEvent($sessionEvent); + } + } + +} diff --git a/src/FacebookPixel/FacebookPixelService.php b/src/FacebookPixel/FacebookPixelService.php index 11edae1..c1290f1 100755 --- a/src/FacebookPixel/FacebookPixelService.php +++ b/src/FacebookPixel/FacebookPixelService.php @@ -13,10 +13,6 @@ class FacebookPixelService { - const EVENT_VIEW_CONTENT = 'ViewContent', - EVENT_PURCHASE = 'Purchase', - EVENT_ADD_TO_CART = 'AddToCart'; - /** @var SessionSection */ private $sessionSection; @@ -30,31 +26,31 @@ public function __construct(Session $session) } /** - * Activates given event - * @param String $eventName + * Save special events to session + * @param String[] $eventName + * @param String[] $eventContent */ - public function eventStart($eventName) + public function saveEvent($eventName, $eventContent) { - $this->sessionSection->$eventName = true; + $this->sessionSection->$eventName = serialize($eventContent); + } /** - * Deactivates given event * @param String $eventName + * @return String */ - public function eventEnd($eventName) + public function getEventContent($eventName) { - unset($this->sessionSection->$eventName); + return unserialize($this->sessionSection->$eventName); } /** - * Gets status of given event * @param String $eventName - * @return String */ - public function eventStatus($eventName) + public function removeEvent($eventName) { - return $this->sessionSection->$eventName; + $this->sessionSection->$eventName = null; } } \ No newline at end of file diff --git a/src/FacebookPixel/templates/commonEvent.latte b/src/FacebookPixel/templates/commonEvent.latte index ccaa463..1930192 100755 --- a/src/FacebookPixel/templates/commonEvent.latte +++ b/src/FacebookPixel/templates/commonEvent.latte @@ -1,4 +1 @@ - - +fbq('track', '{$event}'{ifset $parameters}, {$parameters|noescape}{/ifset}); \ No newline at end of file diff --git a/src/FacebookPixel/templates/facebookPixel.latte b/src/FacebookPixel/templates/facebookPixel.latte index d5fab2e..8eb7cf4 100755 --- a/src/FacebookPixel/templates/facebookPixel.latte +++ b/src/FacebookPixel/templates/facebookPixel.latte @@ -1,12 +1,21 @@ \ No newline at end of file + + +{if count($specialEvents)} + +{/if} From b7c708d328b2660905b0e4edcc9c8056bec5f6df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Z=C3=A1ruba?= Date: Thu, 2 Nov 2017 03:02:42 +0100 Subject: [PATCH 2/3] Updated tests --- src/FacebookPixel/FacebookPixel.php | 4 +- .../templates/facebookPixel.latte | 22 +++---- tests/.gitignore | 3 +- tests/app/presenters/HomepagePresenter.php | 58 ++++++++++++++++--- tests/app/templates/@layout.latte | 9 +-- .../Homepage/addToCartAndPurchase.latte | 1 + .../templates/Homepage/productDetail.latte | 16 ----- tests/app/templates/Homepage/purchase.latte | 6 -- tests/tests/functional/src/EventTest.php | 37 +++++++----- 9 files changed, 93 insertions(+), 63 deletions(-) create mode 100755 tests/app/templates/Homepage/addToCartAndPurchase.latte diff --git a/src/FacebookPixel/FacebookPixel.php b/src/FacebookPixel/FacebookPixel.php index 7dddb46..e37a549 100755 --- a/src/FacebookPixel/FacebookPixel.php +++ b/src/FacebookPixel/FacebookPixel.php @@ -82,7 +82,7 @@ public function addToCart( ) { $this->sendEventToOutput( - $this->template->event = self::EVENT_ADD_TO_CART, + self::EVENT_ADD_TO_CART, $this->prepareProductsToParameters($contentIds, $contentName, $contentCategory, $value, $currency) ); } @@ -90,7 +90,7 @@ public function addToCart( public function purchase($value, $currency, $contentIds = null) { $this->sendEventToOutput( - $this->template->event = self::EVENT_PURCHASE, + self::EVENT_PURCHASE, $this->prepareProductsToParameters($contentIds, null, null, $value, $currency) ); } diff --git a/src/FacebookPixel/templates/facebookPixel.latte b/src/FacebookPixel/templates/facebookPixel.latte index 8eb7cf4..81c5341 100755 --- a/src/FacebookPixel/templates/facebookPixel.latte +++ b/src/FacebookPixel/templates/facebookPixel.latte @@ -1,21 +1,17 @@ - {if count($specialEvents)} - + {/if} diff --git a/tests/.gitignore b/tests/.gitignore index e7d2149..8b94733 100755 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,8 +1,9 @@ vendor composer.lock temp -!temp/.gitignore +!temp/cache/.htaccess log +!log/.htaccess tests/_temp tests/_log tests/_helpers \ No newline at end of file diff --git a/tests/app/presenters/HomepagePresenter.php b/tests/app/presenters/HomepagePresenter.php index 10485ad..816cf88 100644 --- a/tests/app/presenters/HomepagePresenter.php +++ b/tests/app/presenters/HomepagePresenter.php @@ -2,6 +2,7 @@ namespace App\Presenters; +use Eflyax\FacebookPixel\FacebookPixel; use Eflyax\FacebookPixel\FacebookPixelService; use Eflyax\FacebookPixel\IFacebookPixelFactory; use Nette\Application\UI\Presenter; @@ -17,41 +18,82 @@ class HomepagePresenter extends Presenter /** @var FacebookPixelService @inject */ public $facebookPixelService; + /** @var FacebookPixel */ + public $facebookPixel; + private $product; + private $currencyCode = 'CZK'; + protected function startup() { parent::startup(); + $this->facebookPixel = $this['facebookPixel']; $product = new \stdClass(); $product->id = 1; $product->price = 42; $product->title = 'Product title'; $product->description = 'Product description'; - $this->product = $product; } public function actionProductDetail() { - $this->template->product = $this->product; - $this->template->currencyCode = 'CZK'; + $this->facebookPixel->viewContent( + $this->product->id, + $this->product->title, + null, + $this->product->price, + $this->currencyCode + ); } public function actionPurchase() { - $this->template->totalPrice = $this->product->price + self::SHIPPING_PRICE; - $this->template->currencyCode = 'CZK'; - $this->template->productIds = [$this->product->id]; - $this->facebookPixelService->eventStart(FacebookPixelService::EVENT_PURCHASE); + $totalPrice = $this->product->price + self::SHIPPING_PRICE; + $this->facebookPixel->purchase($totalPrice, $this->currencyCode); } public function actionAddToCart() { // ..add product to shopping cart - $this->facebookPixelService->eventStart(FacebookPixelService::EVENT_ADD_TO_CART); + $this->facebookPixel->addToCart( + $this->product->id, + $this->product->title, + null, + $this->product->price, + $this->currencyCode + ); $this->redirect('ProductDetail'); } + public function actionAddToCartAndPurchase() + { + $totalPrice = $this->product->price + self::SHIPPING_PRICE; + $this->facebookPixel->addToCart( + $this->product->id, + $this->product->title, + null, + $this->product->price, + $this->currencyCode + ); + $this->facebookPixel->purchase($totalPrice, $this->currencyCode); + } + + public function actionAddToCartAndPurchaseWithRedirect() + { + $totalPrice = $this->product->price + self::SHIPPING_PRICE; + $this->facebookPixel->addToCart( + $this->product->id, + $this->product->title, + null, + $this->product->price, + $this->currencyCode + ); + $this->facebookPixel->purchase($totalPrice, $this->currencyCode); + $this->redirect('Homepage:'); + } + protected function createComponentFacebookPixel() { return $this->IFacebookPixelFactory->create(); diff --git a/tests/app/templates/@layout.latte b/tests/app/templates/@layout.latte index 8961386..7715ff4 100755 --- a/tests/app/templates/@layout.latte +++ b/tests/app/templates/@layout.latte @@ -1,17 +1,18 @@ - + + -{control facebookPixel} -
- {block content} + {block content}{/block}
+{control facebookPixel} + \ No newline at end of file diff --git a/tests/app/templates/Homepage/addToCartAndPurchase.latte b/tests/app/templates/Homepage/addToCartAndPurchase.latte new file mode 100755 index 0000000..e3484e6 --- /dev/null +++ b/tests/app/templates/Homepage/addToCartAndPurchase.latte @@ -0,0 +1 @@ +{block content} diff --git a/tests/app/templates/Homepage/productDetail.latte b/tests/app/templates/Homepage/productDetail.latte index b1b2ad8..58d34f8 100755 --- a/tests/app/templates/Homepage/productDetail.latte +++ b/tests/app/templates/Homepage/productDetail.latte @@ -1,19 +1,3 @@ {block content} -{control facebookPixel:viewContent, - $product->id, - $product->title, - $product->description, - $product->price, - $currencyCode -} - -{control facebookPixel:addToCart, - $product->id, - $product->title, - $product->description, - $product->price, - $currencyCode -} - Add to cart diff --git a/tests/app/templates/Homepage/purchase.latte b/tests/app/templates/Homepage/purchase.latte index 08b8664..e3484e6 100755 --- a/tests/app/templates/Homepage/purchase.latte +++ b/tests/app/templates/Homepage/purchase.latte @@ -1,7 +1 @@ {block content} - -{control facebookPixel:purchase, - $totalPrice, - $currencyCode, - $productIds -} \ No newline at end of file diff --git a/tests/tests/functional/src/EventTest.php b/tests/tests/functional/src/EventTest.php index a9cfb4e..54d7014 100644 --- a/tests/tests/functional/src/EventTest.php +++ b/tests/tests/functional/src/EventTest.php @@ -8,8 +8,8 @@ class EventTest extends BasePresenterTest public function testPageView() { $this->checkUrlAndResponse($this->generateLink('Homepage:')); - $this->tester->see('fbq(\'init\', ' . self::FB_PIXEL_ID . ')'); - $this->tester->see('fbq(\'track\', \'PageView\')'); + $this->tester->see("'init', '" . self::FB_PIXEL_ID . "'"); + $this->tester->see("'track', 'PageView'"); $this->tester->seeElement('img', [ 'src' => 'https://www.facebook.com/tr?id=' . self::FB_PIXEL_ID . '&ev=PageView&noscript=1' ]); @@ -18,10 +18,10 @@ public function testPageView() public function testViewContent() { $this->checkUrlAndResponse($this->generateLink('Homepage:productDetail')); - $this->tester->see('\'track\', "ViewContent"'); + $this->tester->see("'track', 'ViewContent'"); $this->checkProduct(); - // we didn't call start event AddToCart before - $this->tester->dontSee('\'track\', "AddToCart"'); +// // we didn't call start event AddToCart before + $this->tester->dontSee("'track', 'AddToCart'"); } public function testAddToCart() @@ -30,24 +30,35 @@ public function testAddToCart() $this->generateLink('Homepage:addToCart'), $this->generateLink('Homepage:productDetail') ); - $this->tester->see('\'track\', "AddToCart"'); + $this->tester->see("'track', 'AddToCart'"); $this->checkProduct(); } public function testPurchase() { $this->checkUrlAndResponse($this->generateLink('Homepage:purchase')); - $this->tester->see('\'track\', "Purchase"'); + $this->tester->see("'track', 'Purchase'"); + } + + public function testMultipleEvents() + { + $this->checkUrlAndResponse($this->generateLink('Homepage:addToCartAndPurchase')); + } + + public function testMultipleEventsWithRedirect() + { + $this->checkUrlAndResponse( + $this->generateLink('Homepage:addToCartAndPurchaseWithRedirect'), + $this->generateLink('Homepage:') + ); } private function checkProduct() { - $this->tester->see('"content_type":"product"'); - $this->tester->see('"content_ids":["1"]'); - $this->tester->see('"content_name":"Product title"'); - $this->tester->see('"content_category":"Product description"'); - $this->tester->see('"value":"42.00"'); - $this->tester->see('"currency":"\'CZK\'"'); + $this->tester->see("'content_type':'product'"); + $this->tester->see("'content_ids':['1']"); + $this->tester->see("'content_name':'Product title'"); + $this->tester->see("'currency':'CZK'"); } } From cdf084e9286b48d5eafd7da562eb971dcab92597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Z=C3=A1ruba?= Date: Thu, 2 Nov 2017 03:38:10 +0100 Subject: [PATCH 3/3] Updated readme --- README.md | 115 ++++++++++++++++++++++++------------------------------ 1 file changed, 51 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index fed8c2e..dbd936f 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -#Nette extension for Facebook Pixel. +# Nette extension for Facebook Pixel. + +TODO +* implement missing events (search, addToWishList, etc..) +* support for ajax ## Requirements @@ -8,8 +12,8 @@ The best way to install Eflyax/Facebook-pixel is using [Composer](http://getcomposer.org/): -```sh -$ composer require eflyax/facebook-pixel +```bash +$ composer require eflyax/facebook-pixel ``` ## Usage @@ -25,7 +29,7 @@ and configuration with you FB pixel ID: ``` facebookPixel: id: '111122223333444' - productIdPrefix: '42' // optional + productIdPrefix: '42' # optional ``` Be careful you add FB pixel ID as string, there was issues with integer @@ -35,29 +39,37 @@ Be careful you add FB pixel ID as string, there was issues with integer Inject FB pixel factory and service to your module where you want to render FB pixel. FB pixel service will help you to render specific events. -``` +```php abstract class BaseFrontPresenter extends BasePresenter { /** @var IFacebookPixelFactory @inject */ - public $facebookPixelFactory; + public $IFacebookPixelFactory; + + /** @var FacebookPixel */ + public $facebookPixel; + - /** @var FacebookPixelService @inject */ - public $facebookPixelService; + protected function startup() + { + parent::startup(); + $this->facebookPixel = $this['facebookPixel']; + } + . . protected function createComponentFacebookPixel() { - return $this->facebookPixelFactory->create(); + return $this->IFacebookPixelFactory->create(); } } ``` #### Frontend -Now you are ready to render basic FB pixel for event PageView. Render control faceboobPixel in layout +Now you are ready to render FB pixel in layout `{control facebookPixel}` @@ -66,82 +78,57 @@ Now you are ready to render basic FB pixel for event PageView. Render control fa #### AddToCart -##### Backend In method where you add product to cart call eventStart like this: -```` - public function actionAddProduct($idProduct, $quantity = 1) - { - ... - $this->facebookPixelService->eventStart(FacebookPixelService::EVENT_ADD_TO_CART); - } +````php + $this->facebookPixel->addToCart( + $productId, + $productTitle, + $productCategory, + $productPrice, + $currencyCode + ); ```` -##### Frontend -This control is rendered only if you call eventStart addToCart on backend. When you render this control event is automatically deactivated - -``` -{control facebookPixel:addToCart, - $product->getId(), - $product->getTitle(), - $product->getDescription(), - $product->getPrice(), - $currency->getCode() -} -``` - #### Purchase -##### Backend -Before you redirect customer on thank you page call startEvent: - -`$this->facebookPixelService->eventStart(FacebookPixelService::EVENT_PURCHASE);` - -##### Frontend - ``` -{control facebookPixel:purchase, - $totalPrice, - $currency->getCode(), - $itemIds -} + $this->facebookPixel->purchase($totalPrice, $currencyCode); ``` - -`$itemIds` can contains id for one or more products - - #### ViewContent -##### Frontend + For one product: -``` -{control facebookPixel:viewContent, - $product->getId(), - $product->getTitle(), - $product->getDescription(), - $product->getPrice(), - $currency->getCode() -} +```php +$this->facebookPixel->viewContent( + $productId, + $productTitle, + $productCategory, + $productPrice, + $currencyCode +); ``` For more products (category): -``` -{control facebookPixel:viewContent, + +```php +$this->facebookPixel->viewContent( $productIds -} +); ``` ## Events validation -If you want to validate events sended to facebook I can recommend this browser plugin: +If you want to validate events which you send to facebook I can recommend this browser plugin: [Facebook Pixel Helper](https://chrome.google.com/webstore/detail/FacebookPixel-helper/fdgfkebogiimcoedlicjlajpkdmockpc) ## How to run tests -``` -$ cd tests -$ composer install -$ ./vendor/bin/codecept build -$ ./vendor/bin/codecept run +```bash +$ cd tests +$ composer install +$ mkdir temp +$ ./vendor/bin/codecept build +$ ./vendor/bin/codecept run ```