AgilOne_Recommendations_CE - Version 1.0.0.0

Version Notes

All required page templates and layout files are located in the default theme directory (app/design/frontend/base/default). You will need to copy these files into your site's installed theme directory to install this module. See installation instructions for more details.

Download this release

Release Info

Developer Joe Mancini
Extension AgilOne_Recommendations_CE
Version 1.0.0.0
Comparing to
See all releases


Version 1.0.0.0

Files changed (30) hide show
  1. app/code/community/AgilOne/Recommendations/Block/Catalog/Product/List/Upsell.php +77 -0
  2. app/code/community/AgilOne/Recommendations/Block/Catalog/Product/List/Upsell/Item.php +31 -0
  3. app/code/community/AgilOne/Recommendations/Block/Iframe.php +18 -0
  4. app/code/community/AgilOne/Recommendations/Block/Webtag.php +113 -0
  5. app/code/community/AgilOne/Recommendations/Block/Widget/U2p.php +16 -0
  6. app/code/community/AgilOne/Recommendations/Block/Widget/U2p/Items.php +74 -0
  7. app/code/community/AgilOne/Recommendations/Block/Widget/U2p/Items/Item.php +38 -0
  8. app/code/community/AgilOne/Recommendations/Helper/Data.php +16 -0
  9. app/code/community/AgilOne/Recommendations/Model/Abstract.php +316 -0
  10. app/code/community/AgilOne/Recommendations/Model/Adminhtml/System/Config/Source/Brand.php +32 -0
  11. app/code/community/AgilOne/Recommendations/Model/Adminhtml/System/Config/Source/Log.php +28 -0
  12. app/code/community/AgilOne/Recommendations/Model/Feed.php +225 -0
  13. app/code/community/AgilOne/Recommendations/Model/Observer.php +37 -0
  14. app/code/community/AgilOne/Recommendations/Model/Webtag.php +132 -0
  15. app/code/community/AgilOne/Recommendations/controllers/AjaxController.php +23 -0
  16. app/code/community/AgilOne/Recommendations/etc/adminhtml.xml +23 -0
  17. app/code/community/AgilOne/Recommendations/etc/config.xml +125 -0
  18. app/code/community/AgilOne/Recommendations/etc/system.xml +204 -0
  19. app/code/community/AgilOne/Recommendations/etc/widget.xml +7 -0
  20. app/design/frontend/base/default/layout/recommendations.xml +30 -0
  21. app/design/frontend/base/default/template/recommendations/catalog/product/list/upsell.phtml +24 -0
  22. app/design/frontend/base/default/template/recommendations/catalog/product/list/upsell/item.phtml +14 -0
  23. app/design/frontend/base/default/template/recommendations/iframe.phtml +10 -0
  24. app/design/frontend/base/default/template/recommendations/webtag.phtml +53 -0
  25. app/design/frontend/base/default/template/recommendations/widget/u2p/items.phtml +23 -0
  26. app/design/frontend/base/default/template/recommendations/widget/u2p/items/item.phtml +13 -0
  27. app/etc/modules/AgilOne_Recommendations.xml +17 -0
  28. app/locale/en_US/AgileOne_Recommendations.csv +0 -0
  29. package.xml +33 -0
  30. skin/frontend/base/default/css/recommendations.css +21 -0
app/code/community/AgilOne/Recommendations/Block/Catalog/Product/List/Upsell.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Block_Catalog_Product_List_Upsell extends Mage_Catalog_Block_Product_Abstract
10
+ {
11
+
12
+ protected $_items = null;
13
+
14
+ protected $_title = null;
15
+
16
+ protected $_columnCount = null;
17
+
18
+ protected function _construct()
19
+ {
20
+ parent::_construct();
21
+
22
+ $this->setTemplate('recommendations/catalog/product/list/upsell.phtml');
23
+
24
+ if (!$this->_items = Mage::getModel('recommendations/feed')->getP2PItems($this->getProduct()->getId())) {
25
+ $this->_items = new Varien_Data_Collection();
26
+ }
27
+
28
+ $this->_title = Mage::getStoreConfig('agilone/pdp/title');
29
+
30
+ $this->_columnCount = Mage::getStoreConfig('agilone/pdp/limit');
31
+
32
+ $product = Mage::registry('product');
33
+ }
34
+
35
+ public function getTitle()
36
+ {
37
+ return $this->__($this->_title);
38
+ }
39
+
40
+ public function hasItems()
41
+ {
42
+ return $this->getItemsCount() > 0;
43
+ }
44
+
45
+ public function getItems()
46
+ {
47
+ return $this->getItemCollection();
48
+ }
49
+
50
+ public function getItemCollection()
51
+ {
52
+ return $this->_items;
53
+ }
54
+
55
+ public function getItemsCount()
56
+ {
57
+ return count($this->getItemCollection());
58
+ }
59
+
60
+ public function getRowCount()
61
+ {
62
+ return ceil($this->getItemsCount()/$this->getColumnCount());
63
+ }
64
+
65
+ public function setColumnCount($columns)
66
+ {
67
+ if (intval($columns) > 0) {
68
+ $this->_columnCount = intval($columns);
69
+ }
70
+ return $this;
71
+ }
72
+
73
+ public function getColumnCount()
74
+ {
75
+ return $this->_columnCount;
76
+ }
77
+ }
app/code/community/AgilOne/Recommendations/Block/Catalog/Product/List/Upsell/Item.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Block_Catalog_Product_List_Upsell_Item extends Mage_Catalog_Block_Product_Abstract
10
+ {
11
+ protected $_item = null;
12
+
13
+ protected $_position = null;
14
+
15
+ public function getItem()
16
+ {
17
+ return $this->_item;
18
+ }
19
+
20
+ public function setItem($item)
21
+ {
22
+ $this->_item = $item;
23
+ return $this;
24
+ }
25
+
26
+ public function setPosition($position)
27
+ {
28
+ $this->_position = $position;
29
+ return $this;
30
+ }
31
+ }
app/code/community/AgilOne/Recommendations/Block/Iframe.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Iframe Block
4
+ *
5
+ * @category AgilOne
6
+ * @package AgilOne_Recommendations
7
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
8
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
9
+ */
10
+
11
+ class AgilOne_Recommendations_Block_Iframe extends Mage_Core_Block_Template
12
+ {
13
+
14
+ protected function _getUrl()
15
+ {
16
+ return Mage::getUrl('recommendations/ajax/webtag',array('_secure'=> Mage::app()->getStore()->isCurrentlySecure()));
17
+ }
18
+ }
app/code/community/AgilOne/Recommendations/Block/Webtag.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WebTab Block: Provides data for a1as.push javascript variables
4
+ *
5
+ * var _a1as = _a1as || [];
6
+ * _a1as.push(["init","1234567"]);
7
+ * _a1as.push(["setvar","userid","142"]);
8
+ * _a1as.push(["setvar","email","rloerzel@lyonscg.com"]);
9
+ * _a1as.push(["track"]);
10
+ *
11
+ * @category AgilOne
12
+ * @package AgilOne_Recommendations
13
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
14
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
15
+ */
16
+
17
+ class AgilOne_Recommendations_Block_Webtag extends Mage_Core_Block_Template
18
+ {
19
+
20
+ protected $_webtagModel;
21
+
22
+
23
+
24
+ protected function _construct()
25
+ {
26
+ parent::_construct();
27
+
28
+ $this->_webtagModel = Mage::getModel('recommendations/webtag');
29
+
30
+ }
31
+
32
+ public function isEnabled()
33
+ {
34
+ return $this->_webtagModel->isEnabled();
35
+ }
36
+
37
+ public function getHandle()
38
+ {
39
+ return $this->_webtagModel->getHandle();
40
+ }
41
+ /**
42
+ * Get Website's WebTagId
43
+ *@return string|boolean
44
+ */
45
+ public function getWebTagId()
46
+ {
47
+ return $this->_webtagModel->getWebTagId();
48
+ }
49
+
50
+ /**
51
+ * Get Logged-In User's Magento ID
52
+ * @return string
53
+ */
54
+ public function getUserId()
55
+ {
56
+ return $this->_webtagModel->getUserId();
57
+ }
58
+
59
+ /**
60
+ * Get Logged-In User's Email Address
61
+ * @return string|boolean
62
+ */
63
+ public function getEmail()
64
+ {
65
+ return $this->_webtagModel->getEmail();
66
+ }
67
+
68
+ /**
69
+ * Get SKU and brand of product viewed
70
+ * @return string|boolean
71
+ */
72
+ public function getProductView()
73
+ {
74
+ return $this->_webtagModel->getProductView();
75
+ }
76
+
77
+ /**
78
+ * Get URL-Key of category viewed
79
+ * @return string|boolean
80
+ */
81
+ public function getCategoryIdView()
82
+ {
83
+ return $this->_webtagModel->getCategoryIdView();
84
+ }
85
+
86
+ /**
87
+ * Get contents of cart if item is added or removed
88
+ * @return string|boolean
89
+ */
90
+ public function getProductIdCart()
91
+ {
92
+ return $this->_webtagModel->getProductIdCart();
93
+ }
94
+
95
+ /**
96
+ * Get order information on success page
97
+ * @return Varien_Object|boolean
98
+ */
99
+ public function getOrder()
100
+ {
101
+ return $this->_webtagModel->getOrder();
102
+ }
103
+
104
+ /**
105
+ * Get search keywords
106
+ * @return string|boolean
107
+ */
108
+ public function getOnsiteSearch()
109
+ {
110
+ return $this->_webtagModel->getOnsiteSearch();
111
+ }
112
+
113
+ }
app/code/community/AgilOne/Recommendations/Block/Widget/U2p.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Block_Widget_U2p extends Mage_Core_Block_Template implements Mage_Widget_Block_Interface
10
+ {
11
+
12
+ protected function _toHtml()
13
+ {
14
+ return $this->getLayout()->createBlock('recommendations/widget_u2p_items')->toHtml();
15
+ }
16
+ }
app/code/community/AgilOne/Recommendations/Block/Widget/U2p/Items.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Block_Widget_U2p_Items extends Mage_Core_Block_Template
10
+ {
11
+ protected $_items = null;
12
+
13
+ protected $_title = null;
14
+
15
+ protected $_columnCount = null;
16
+
17
+ protected function _construct()
18
+ {
19
+ parent::_construct();
20
+
21
+ $this->setLayout(Mage::getModel('core/layout'));
22
+
23
+ $this->setTemplate('recommendations/widget/u2p/items.phtml');
24
+
25
+ $this->setChild('widget.u2p.item',$this->getLayout()->createBlock('recommendations/widget_u2p_items_item'));
26
+
27
+ if (!$this->_items = Mage::getModel('recommendations/feed')->getU2PItems()) {
28
+ $this->_items = new Varien_Data_Collection();
29
+ }
30
+
31
+ $this->_title = Mage::getStoreConfig('agilone/widget/title');
32
+
33
+ $this->_columnCount = Mage::getStoreConfig('agilone/widget/limit');
34
+ }
35
+
36
+ public function getTitle()
37
+ {
38
+ return $this->__($this->_title);
39
+ }
40
+
41
+ public function hasItems()
42
+ {
43
+ return $this->getItemsCount() > 0;
44
+ }
45
+
46
+ public function getItemCollection()
47
+ {
48
+ return $this->_items;
49
+ }
50
+
51
+ public function getItemsCount()
52
+ {
53
+ return count($this->getItemCollection());
54
+ }
55
+
56
+ public function getRowCount()
57
+ {
58
+ return ceil($this->getItemsCount()/$this->getColumnCount());
59
+ }
60
+
61
+ public function setColumnCount($columns)
62
+ {
63
+ if (intval($columns) > 0) {
64
+ $this->_columnCount = intval($columns);
65
+ }
66
+ return $this;
67
+ }
68
+
69
+ public function getColumnCount()
70
+ {
71
+ return $this->_columnCount;
72
+ }
73
+
74
+ }
app/code/community/AgilOne/Recommendations/Block/Widget/U2p/Items/Item.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Block_Widget_U2p_Items_Item extends Mage_Catalog_Block_Product_Abstract
10
+ {
11
+ protected $_item = null;
12
+
13
+ protected $_position = null;
14
+
15
+ protected function _construct()
16
+ {
17
+ parent::_construct();
18
+
19
+ $this->setTemplate('recommendations/widget/u2p/items/item.phtml');
20
+ }
21
+
22
+ public function getItem()
23
+ {
24
+ return $this->_item;
25
+ }
26
+
27
+ public function setItem($item)
28
+ {
29
+ $this->_item = $item;
30
+ return $this;
31
+ }
32
+
33
+ public function setPosition($position)
34
+ {
35
+ $this->_position = $position;
36
+ return $this;
37
+ }
38
+ }
app/code/community/AgilOne/Recommendations/Helper/Data.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Helper_Data extends Mage_Core_Helper_Abstract
10
+ {
11
+ const LOG_LEVEL_NONE = 0;
12
+
13
+ const LOG_LEVEL_ERRORS = 1;
14
+
15
+ const LOG_LEVEL_ALL = 2;
16
+ }
app/code/community/AgilOne/Recommendations/Model/Abstract.php ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Abstract Model
4
+ *
5
+ * @category AgilOne
6
+ * @package AgilOne_Recommendations
7
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
8
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
9
+ *
10
+ * https://agilone.zendesk.com/hc/en-us/articles/201534597-OpenAPI-Recommendations
11
+ */
12
+
13
+ abstract class AgilOne_Recommendations_Model_Abstract extends Mage_Core_Model_Abstract
14
+ {
15
+ /**
16
+ * @var string $_storeId
17
+ *
18
+ * Id of current active store
19
+ */
20
+ protected $_storeId = null;
21
+
22
+ /**
23
+ * @var Mage_Core_Model_Store $_store
24
+ *
25
+ * Current active store object
26
+ */
27
+ protected $_store = null;
28
+
29
+ /**
30
+ * @var boolean $_isEnabled
31
+ *
32
+ * Is module enabled?
33
+ */
34
+ protected $_isEnabled = null;
35
+
36
+ /**
37
+ * @var Mage_Checkout_Model_Session $_checkoutSession
38
+ *
39
+ * Checkout session singleton object
40
+ */
41
+ protected $_checkoutSession = null;
42
+
43
+ /**
44
+ * @var Mage_Customer_Model_Session $_customerSession
45
+ *
46
+ * Customer session singleton object
47
+ */
48
+ protected $_customerSession = null;
49
+
50
+ /**
51
+ * @var string $_sourceId
52
+ *
53
+ * The SourceID is an ID specific to your data sources. You may have several of them if
54
+ * AgilOne manage different customer or product databases for you. The {sourceid} parameter
55
+ * makes sure that the {customerkey} or {productkey} you're supplying is unique.
56
+ */
57
+ protected $_sourceId = null;
58
+
59
+ /**
60
+ * @var string $_tenantId
61
+ *
62
+ * The TenantID is an ID specific to your workspace. If on app.agilone.com, you only have
63
+ * access to one workspace (the most common case) the tenant value is optional in API calls.
64
+ */
65
+ protected $_tenantId = null;
66
+
67
+ /**
68
+ * @var string $_webtagId
69
+ *
70
+ * ID provided with AgilOne WebTag account
71
+ */
72
+ protected $_webtagId = null;
73
+
74
+ /**
75
+ * @var string $_brandAttribute
76
+ *
77
+ * Magento product attribute to represent the AgilOne 'brand' attribute in API calls
78
+ */
79
+ protected $_brandAttribute = null;
80
+
81
+ /**
82
+ * @var string $_logLevel
83
+ *
84
+ * Debug Logging Level
85
+ *
86
+ * 0: None
87
+ * 1: Errors Only
88
+ * 2: All Traffic
89
+ */
90
+ protected $_logLevel = null;
91
+
92
+ /**
93
+ * @var string $_baseUrl
94
+ *
95
+ * Base AgilOne API URL (i.e. "api.agilone.com")
96
+ */
97
+ protected $_baseUrl = null;
98
+
99
+ /**
100
+ * @var string $_handle
101
+ *
102
+ * Layout Handle Identifier (i.e. "catalog_product_view")
103
+ */
104
+ protected $_handle = null;
105
+
106
+ /**
107
+ * @var string $_action
108
+ *
109
+ * Controller action
110
+ */
111
+ protected $_action = null;
112
+
113
+ /**
114
+ * @var string $_userId
115
+ *
116
+ * Logged-in customer user id
117
+ */
118
+ protected $_userId = null;
119
+
120
+ /**
121
+ * @var string $_email
122
+ *
123
+ * Logged-in customer user email address
124
+ */
125
+ protected $_email = null;
126
+
127
+ /**
128
+ * Constructor. Set variables.
129
+ */
130
+ protected function _construct()
131
+ {
132
+ parent::_construct();
133
+
134
+ try {
135
+ $this->_storeId = Mage::app()->getStore()->getId();
136
+
137
+ $this->_store = $store = Mage::app()->getStore();
138
+
139
+ $this->_checkoutSession = Mage::getSingleton('checkout/session');
140
+
141
+ $this->_customerSession = Mage::getSingleton('customer/session');
142
+
143
+ $this->_isEnabled = Mage::getStoreConfig('agilone/general/enabled',$this->_storeId);
144
+
145
+ $this->_sourceId = Mage::getStoreConfig('agilone/general/source_id',$this->_storeId);
146
+
147
+ $this->_tenantId = Mage::getStoreConfig('agilone/general/tenant_id',$this->_storeId);
148
+
149
+ $this->_webtagId = Mage::getStoreConfig('agilone/general/webtag_id',$this->_storeId);
150
+
151
+ $this->_brandAttribute = Mage::getStoreConfig('agilone/general/brand_attribute',$this->_storeId);
152
+
153
+ $this->_logLevel = Mage::getStoreConfig('agilone/general/log_level',$this->_storeId);
154
+
155
+ if (Mage::getStoreConfig('agilone/general/force_https',$this->_storeId)) {
156
+ $protocol = 'https';
157
+ } else {
158
+ $protocol = 'http';
159
+ }
160
+
161
+ $this->_baseUrl = $protocol . '://' . Mage::getStoreConfig('agilone/general/base_url',$this->_storeId);
162
+
163
+ $req = Mage::app()->getRequest();
164
+
165
+ $this->_handle = $req->getRequestedRouteName() . '_' . $req->getRequestedControllerName() . '_' . $req->getRequestedActionName();
166
+
167
+ $this->_action = $req->getRequestedActionName();
168
+
169
+ if($this->_customerSession->isLoggedIn()){
170
+ $customer = $this->_customerSession->getCustomer();
171
+ $this->_userId = $customer->getId();
172
+ $this->_email = $customer->getEmail();
173
+ } else {
174
+ $this->_userId = null;
175
+ $this->_email = $this->_checkoutSession->getQuote()->getCustomerEmail();
176
+ }
177
+
178
+ } catch (Exception $e) {
179
+ Mage::logException($e);
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Is module enabled?
185
+ *
186
+ * @return boolean
187
+ */
188
+ public function isEnabled()
189
+ {
190
+ return (boolean) $this->_isEnabled;
191
+ }
192
+
193
+ /**
194
+ * Get A1 Api Key
195
+ *
196
+ *@return string
197
+ */
198
+ protected function _getApiKey()
199
+ {
200
+ return $this->_apiKey;
201
+ }
202
+
203
+ /**
204
+ * Get A1 Api Secret Key
205
+ *
206
+ *@return string
207
+ */
208
+ protected function _getApiSecret()
209
+ {
210
+ return $this->_apiSecret;
211
+ }
212
+
213
+ /**
214
+ * Get layout handle for current page
215
+ *
216
+ * @return string
217
+ */
218
+ public function getHandle()
219
+ {
220
+ return $this->_handle;
221
+ }
222
+
223
+ /**
224
+ * Get Website's WebTagId
225
+ *
226
+ *@return string|boolean
227
+ */
228
+ public function getWebTagId()
229
+ {
230
+ return $this->_webtagId;
231
+ }
232
+
233
+ /**
234
+ * Get Logged-In User's Magento ID
235
+ *
236
+ * @return string
237
+ */
238
+ public function getUserId()
239
+ {
240
+ return $this->_userId;
241
+ }
242
+
243
+ /**
244
+ * Get Logged-In User's Email Address
245
+ *
246
+ * @return string|boolean
247
+ */
248
+ public function getEmail()
249
+ {
250
+ return $this->_email;
251
+ }
252
+
253
+ /**
254
+ * Get product viewed
255
+ *
256
+ * @return string|boolean
257
+ */
258
+ public function getProduct()
259
+ {
260
+ try {
261
+ if ($this->_handle === 'catalog_product_view') {
262
+ if ($productId = Mage::registry('current_product')->getId()) {
263
+ return Mage::getModel('catalog/product')->load($productId);
264
+ }
265
+ }
266
+ } catch (Exception $e) {
267
+ Mage::logException($e);
268
+ }
269
+
270
+ return false;
271
+ }
272
+
273
+ /**
274
+ * Get cache lifetime for P2P data
275
+ *
276
+ * @return string
277
+ */
278
+ protected function _getCacheP2P()
279
+ {
280
+ return $this->_cacheP2P;
281
+ }
282
+
283
+ /**
284
+ * Get cache lifetime for U2P data
285
+ *
286
+ * @return string
287
+ */
288
+ protected function _getCacheU2P()
289
+ {
290
+ return $this->_cacheU2P;
291
+ }
292
+
293
+ /**
294
+ * Log debug information and errors
295
+ *
296
+ * @param string $message
297
+ * @param number $level
298
+ */
299
+
300
+ public function log($message = '',$level = 7)
301
+ {
302
+ switch ($this->_logLevel) {
303
+ case AgilOne_Recommendations_Helper_Data::LOG_LEVEL_ALL:
304
+ Mage::log($message,$level,'agilone_recommendations.log');
305
+ break;
306
+
307
+ case AgilOne_Recommendations_Helper_Data::LOG_LEVEL_ERRORS:
308
+ case $level > 5:
309
+ Mage::log($message,$level,'agilone_recommendations.log');
310
+
311
+ break;
312
+ default:
313
+ break;
314
+ }
315
+ }
316
+ }
app/code/community/AgilOne/Recommendations/Model/Adminhtml/System/Config/Source/Brand.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Model_Adminhtml_System_Config_Source_Brand
10
+ {
11
+ protected $_options;
12
+
13
+ public function toOptionArray()
14
+ {
15
+ if (!$this->_options) {
16
+ $this->_options = array();
17
+ $attributes = Mage::getResourceModel('catalog/product_attribute_collection')
18
+ ->addVisibleFilter()
19
+ ->getSelect()
20
+ ->order(array('frontend_label ASC'))
21
+ ->query();
22
+
23
+ foreach($attributes as $attribute) {
24
+ $this->_options[] = array(
25
+ 'value'=> $attribute['attribute_code'],
26
+ 'label'=> $attribute['frontend_label'] . ' (' . $attribute['attribute_code'] . ')'
27
+ );
28
+ }
29
+ }
30
+ return $this->_options;
31
+ }
32
+ }
app/code/community/AgilOne/Recommendations/Model/Adminhtml/System/Config/Source/Log.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @category AgilOne
4
+ * @package AgilOne_Recommendations
5
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
6
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
7
+ */
8
+
9
+ class AgilOne_Recommendations_Model_Adminhtml_System_Config_Source_Log
10
+ {
11
+ public function toOptionArray()
12
+ {
13
+ return array(
14
+ array(
15
+ 'value' => AgilOne_Recommendations_Helper_Data::LOG_LEVEL_NONE,
16
+ 'label' => Mage::helper('recommendations')->__('None')
17
+ ),
18
+ array(
19
+ 'value' => AgilOne_Recommendations_Helper_Data::LOG_LEVEL_ERRORS,
20
+ 'label' => Mage::helper('recommendations')->__('Errors Only')
21
+ ),
22
+ array(
23
+ 'value' => AgilOne_Recommendations_Helper_Data::LOG_LEVEL_ALL,
24
+ 'label' => Mage::helper('recommendations')->__('All Traffic')
25
+ ),
26
+ );
27
+ }
28
+ }
app/code/community/AgilOne/Recommendations/Model/Feed.php ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Recommendation Feed Model
4
+ *
5
+ * @category AgilOne
6
+ * @package AgilOne_Recommendations
7
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
8
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
9
+ *
10
+ * https://agilone.zendesk.com/hc/en-us/articles/201534597-OpenAPI-Recommendations
11
+ */
12
+
13
+ class AgilOne_Recommendations_Model_Feed extends AgilOne_Recommendations_Model_Abstract
14
+ {
15
+ /**
16
+ * @var string $_apiKey
17
+ *
18
+ * SHA256 (AES) Public Key
19
+ */
20
+ protected $_apiKey = null;
21
+
22
+ /**
23
+ * @var string $_apiSecret
24
+ *
25
+ * SHA256 (AES) Secret Key
26
+ */
27
+ protected $_apiSecret = null;
28
+
29
+ /**
30
+ * @var string $_limitP2P
31
+ *
32
+ * Number of product recommendations to return
33
+ */
34
+ protected $_limitP2P = null;
35
+
36
+ /**
37
+ * @var string $_cacheP2P
38
+ *
39
+ * Caching expiration seconds from current timestamp for product recommendations
40
+ */
41
+ protected $_cacheP2P = null;
42
+
43
+ /**
44
+ * @var string $_limitU2P
45
+ *
46
+ * Number of customer recommendations to return
47
+ */
48
+ protected $_limitU2P = null;
49
+
50
+ /**
51
+ * @var string $_cacheU2P
52
+ *
53
+ * Caching expiration seconds from current timestamp for customer recommendations
54
+ */
55
+ protected $_cacheU2P = null;
56
+
57
+ /**
58
+ * @var string $_defaultEmail
59
+ *
60
+ * Default email address to use for customers who aren't logged in.
61
+ */
62
+ protected $_defaultEmail = null;
63
+
64
+
65
+ /**
66
+ * Constructor. Set variables.
67
+ */
68
+ protected function _construct()
69
+ {
70
+ parent::_construct();
71
+
72
+ try {
73
+ $this->_apiKey = Mage::getStoreConfig('agilone/general/api_key',$this->_storeId);
74
+
75
+ /**
76
+ * Secret key encoding for query string authentication
77
+ * https://agilone.zendesk.com/hc/en-us/articles/201534547-OpenAPI-Query-String-Authentication
78
+ */
79
+ $this->_apiSecret = base64_decode(mb_convert_encoding(Mage::getStoreConfig('agilone/general/api_secret',$this->_storeId), "auto", "ASCII"));
80
+
81
+ $this->_limitP2P = Mage::getStoreConfig('agilone/pdp/limit',$this->_storeId);
82
+
83
+ $this->_cacheP2P = Mage::getStoreConfig('agilone/pdp/cache_lifetime',$this->_storeId);
84
+
85
+ $this->_limitU2P = Mage::getStoreConfig('agilone/widget/limit',$this->_storeId);
86
+
87
+ $this->_cacheU2P = Mage::getStoreConfig('agilone/widget/cache_lifetime',$this->_storeId);
88
+
89
+ /**
90
+ * if guest checkout use email from quote
91
+ */
92
+ if (!$this->_defaultEmail = Mage::getSingleton('checkout/session')->getQuote()->getCustomerEmail()) {
93
+ $this->_defaultEmail = Mage::getStoreConfig('agilone/widget/default_email',$this->_storeId);
94
+ }
95
+
96
+ } catch (Exception $e) {
97
+ Mage::logException($e);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Convert JSON from API into array for template page
103
+ *
104
+ * @param string $json
105
+ * @return multitype:array
106
+ */
107
+ protected function _convertItemJson($json = null)
108
+ {
109
+ try {
110
+ $items = new Varien_Data_Collection();
111
+
112
+ if ($json) {
113
+
114
+ $obj = json_decode($json);
115
+
116
+ if ($obj && $obj->result && $obj->result->resultSet && $rows = $obj->result->resultSet->resultSetitem) {
117
+
118
+ foreach($rows as $row) {
119
+ $product = new Varien_Object();
120
+ $product->setName(htmlentities($row->product->name, ENT_QUOTES, 'UTF-8'));
121
+ $product->setDescription(htmlentities($row->product->name, ENT_QUOTES, 'UTF-8'));
122
+ $product->setBrand(htmlentities($row->product->brand, ENT_QUOTES, 'UTF-8'));
123
+ $product->setSku($row->product->id);
124
+ $product->setRank($row->rank);
125
+ $product->setImageUrl($row->product->imageUrl);
126
+ $product->setProductUrl($row->product->productUrl);
127
+ $product->setPrice($row->product->price);
128
+ $product->setSpecialPrice($row->product->salePrice);
129
+ $product->setAvailability($row->product->availability);
130
+ $product->setSaleCondition($row->product->saleCondition);
131
+ $product->setGtin($row->product->gtin);
132
+ $product->setMpn($row->product->mpn);
133
+ $items->addItem($product);
134
+ }
135
+ }
136
+ }
137
+
138
+ return $items;
139
+ } catch (Exception $e) {
140
+ Mage::logException($e);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Send request for recommendations to AgilOne API
146
+ *
147
+ * @param string $path The URL-encoded path including the leading slash. E.g. '/1.0/account/1/2'.
148
+ * @param string $expires The time in seconds from the Epoch when the signature expires.
149
+ * @param string $limit Number of recommendations to return
150
+ */
151
+ protected function _request($path,$expires,$limit = 4)
152
+ {
153
+ try {
154
+ $canonical = mb_convert_encoding("GET\n\n\n" . $expires . "\n" . $path, "auto", 'UTF-8');
155
+ $signature = urlencode(base64_encode(hash_hmac("sha256", $canonical, $this->_apiSecret, true)));
156
+ $url = $this->_baseUrl . $path . '?limit=' . $limit . '&a1accesskeyid=' . $this->_apiKey . '&expires=' . $expires . '&signature=' . $signature;
157
+
158
+ if ($data = @file_get_contents($url)) {
159
+ $items = $this->_convertItemJson($data);
160
+ $this->log(count($items) . " RECOMMENDATIONS: $url",Zend_Log::INFO);
161
+ return $items;
162
+ } else {
163
+ $this->log("NO RECOMMENDATIONS: $url",Zend_Log::WARN);
164
+ return false;
165
+ }
166
+ } catch (Exception $e) {
167
+ Mage::logException($e);
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Get JSON-formatted object of product recommendations
173
+ *
174
+ * @return string
175
+ */
176
+ public function getU2PItems()
177
+ {
178
+ try {
179
+
180
+ if ($email = $this->_email ? $this->_email : $this->_defaultEmail) {
181
+ if (is_numeric($this->_tenantId)) {
182
+ $path = '/1.0/tenant/' . $this->_tenantId . '/customer/' . $email . '/recommendations/product';
183
+ } else {
184
+ $path = '/1.0/user/' . $email . '/recommendations/product';
185
+ }
186
+
187
+ $expires = time() + intval($this->_getCacheU2P());
188
+ return $this->_request($path,$expires,$this->_limitU2P);
189
+ } else {
190
+ throw new Exception("U2P default email not set.");
191
+ }
192
+
193
+ } catch (Exception $e) {
194
+ Mage::logException($e);
195
+ }
196
+ return false;
197
+ }
198
+
199
+ /**
200
+ * Get JSON-formatted object of user product recommendations
201
+ *
202
+ * @param string $productId
203
+ * @return string
204
+ */
205
+ public function getP2PItems($productId = null)
206
+ {
207
+ try {
208
+ if (is_numeric($productId)) {
209
+ if (is_numeric($this->_tenantId)) {
210
+ $path = '/1.0/tenant/' . $this->_tenantId . '/product/' . $this->_sourceId . '/' . $productId . '/recommendations/product';
211
+ } else {
212
+ $path = '/1.0/product/' . $this->_sourceId . '/' . $productId. '/recommendations/product';
213
+ }
214
+
215
+ $expires = time() + intval($this->_getCacheP2P());
216
+ return $this->_request($path,$expires,$this->_limitP2P);
217
+ } else {
218
+ return;
219
+ }
220
+ } catch (Exception $e) {
221
+ Mage::logException($e);
222
+ return false;
223
+ }
224
+ }
225
+ }
app/code/community/AgilOne/Recommendations/Model/Observer.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Observer Model
4
+ *
5
+ * @category AgilOne
6
+ * @package AgilOne_Recommendations
7
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
8
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
9
+ */
10
+
11
+ class AgilOne_Recommendations_Model_Observer extends Mage_Core_Model_Abstract
12
+ {
13
+
14
+ /**
15
+ * Capture Add To Cart/Remove From Cart events as a session
16
+ * variable to limit output of cart contents in Webtag.php
17
+ */
18
+ public function updateProductIdCart()
19
+ {
20
+ Mage::getSingleton('checkout/session')->setA1Cart(true);
21
+ }
22
+
23
+
24
+ /**
25
+ * Capture search keywords
26
+ * @param Varien_Event_Observer $event
27
+ */
28
+ public function captureSearch(Varien_Event_Observer $event)
29
+ {
30
+ try {
31
+ Mage::getSingleton('checkout/session')->setA1Search($event->getData('catalogsearch_query')->getData('query_text'));
32
+ } catch (Mage_Core_Exception $e) {
33
+ Mage::logException($e);
34
+ }
35
+ }
36
+
37
+ }
app/code/community/AgilOne/Recommendations/Model/Webtag.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WebTab Model: Provides data for a1as.push javascript variables
4
+ *
5
+ * var _a1as = _a1as || [];
6
+ * _a1as.push(["init","1234567"]);
7
+ * _a1as.push(["setvar","userid","142"]);
8
+ * _a1as.push(["setvar","email","rloerzel@lyonscg.com"]);
9
+ * _a1as.push(["track"]);
10
+ *
11
+ * @category AgilOne
12
+ * @package AgilOne_Recommendations
13
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
14
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
15
+ */
16
+
17
+ class AgilOne_Recommendations_Model_Webtag extends AgilOne_Recommendations_Model_Abstract
18
+ {
19
+ /**
20
+ * Get SKU and brand of product viewed
21
+ * @return string|boolean
22
+ */
23
+ public function getProductView()
24
+ {
25
+ try {
26
+ if ($product = $this->getProduct()) {
27
+ $a1Product = new Varien_Object();
28
+ $a1Product->setProductId($product->getId());
29
+ $a1Product->setBrandId($product->getAttributeText($this->_brandAttribute));
30
+ return $a1Product;
31
+ }
32
+ } catch (Exception $e) {
33
+ Mage::logException($e);
34
+ }
35
+
36
+ return false;
37
+ }
38
+
39
+ /**
40
+ * Get URL-Key of category viewed
41
+ * @return string|boolean
42
+ */
43
+ public function getCategoryIdView()
44
+ {
45
+ try {
46
+ if ($this->_handle === 'catalog_category_view') {
47
+ return Mage::registry('current_category')->getId();
48
+ }
49
+ } catch (Exception $e) {
50
+ Mage::logException($e);
51
+ }
52
+
53
+ return false;
54
+ }
55
+
56
+ /**
57
+ * Get contents of cart if item is added or removed
58
+ * @return string|boolean
59
+ */
60
+ public function getProductIdCart()
61
+ {
62
+ try {
63
+ if ( $this->_checkoutSession->getA1Cart()) {
64
+ $ids = array();
65
+ $quote = $this->_checkoutSession->getQuote();
66
+
67
+ foreach($quote->getAllVisibleItems() as $item) {
68
+ $ids[] = $item->getProductId();
69
+ }
70
+
71
+ $this->_checkoutSession->setA1Cart(false);
72
+
73
+ /**
74
+ * Return " " if cart has been emptied.
75
+ * Trim on webtag.phtml will result in:
76
+ * _a1as.push(["setvar","productid_cart",""]);
77
+ */
78
+ return $ids ? implode(',',$ids) : ' ';
79
+ }
80
+ } catch (Exception $e) {
81
+ Mage::logException($e);
82
+ }
83
+
84
+ return false;
85
+ }
86
+
87
+ /**
88
+ * Get order information on success page
89
+ * @return Varien_Object|boolean
90
+ */
91
+ public function getOrder()
92
+ {
93
+ try {
94
+ $a1Order = new Varien_Object();
95
+ if ($this->_action == 'success') {
96
+ $_lastOrderId = Mage::getSingleton('checkout/session')->getLastOrderId();
97
+ if (is_numeric($_lastOrderId) && $order = Mage::getModel('sales/order')->load($_lastOrderId)) {
98
+ $a1Order->setOrderId($order->getIncrementId());
99
+ $a1Order->setOrderTotal($order->getGrandTotal());
100
+ $ids = array();
101
+ foreach($order->getAllVisibleItems() as $item) {
102
+ $ids[] = $item->getProductId();
103
+ }
104
+ $a1Order->setProductIdOrder(implode(',',$ids));
105
+ $a1Order->setCustomerEmail($order->getCustomerEmail());
106
+ $a1Order->setCustomerId($order->getCustomerId() ? $order->getCustomerId() : 0);
107
+ }
108
+ return $a1Order;
109
+ }
110
+
111
+ } catch (Exception $e) {
112
+ Mage::logException($e);
113
+ }
114
+ return false;
115
+ }
116
+
117
+ /**
118
+ * Get search keywords
119
+ * @return string|boolean
120
+ */
121
+ public function getOnsiteSearch()
122
+ {
123
+ try {
124
+ $a1Search = Mage::getSingleton('checkout/session')->getA1Search();
125
+ Mage::getSingleton('checkout/session')->setA1Search();
126
+ return $a1Search;
127
+ } catch (Exception $e) {
128
+ Mage::logException($e);
129
+ }
130
+ return false;
131
+ }
132
+ }
app/code/community/AgilOne/Recommendations/controllers/AjaxController.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Ajax Controller
4
+ *
5
+ * @category AgilOne
6
+ * @package AgilOne_Recommendations
7
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
8
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
9
+ */
10
+
11
+ class AgilOne_Recommendations_AjaxController extends Mage_Core_Controller_Front_Action
12
+ {
13
+ public function webtagAction()
14
+ {
15
+ $this->loadLayout();
16
+ $webtags = $this->getLayout()->createBlock('recommendations/webtag')->setTemplate('recommendations/webtag.phtml')->toHtml();
17
+ $content = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
18
+ $content .= '<html xmlns="http://www.w3.org/1999/xhtml">';
19
+ $content .= '<head><title>' . html_entity_decode(Mage::getStoreConfig('design/head/default_description')) . '</title>';
20
+ $content .= '</head><body>' . $webtags . '</body></html>';
21
+ $this->getResponse()->setBody($content);
22
+ }
23
+ }
app/code/community/AgilOne/Recommendations/etc/adminhtml.xml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <system>
8
+ <children>
9
+ <config>
10
+ <children>
11
+ <agilone translate="title" module="agilone">
12
+ <title>AgilOne Configuration</title>
13
+ <sort_order>10</sort_order>
14
+ </agilone>
15
+ </children>
16
+ </config>
17
+ </children>
18
+ </system>
19
+ </children>
20
+ </admin>
21
+ </resources>
22
+ </acl>
23
+ </config>
app/code/community/AgilOne/Recommendations/etc/config.xml ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * @category AgilOne
5
+ * @package AgilOne_Recommendations
6
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
7
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
8
+ */
9
+ -->
10
+ <config>
11
+ <modules>
12
+ <AgilOne_Recommendations>
13
+ <version>1.0.0</version>
14
+ </AgilOne_Recommendations>
15
+ </modules>
16
+ <global>
17
+ <models>
18
+ <recommendations>
19
+ <class>AgilOne_Recommendations_Model</class>
20
+ </recommendations>
21
+ </models>
22
+ <helpers>
23
+ <recommendations>
24
+ <class>AgilOne_Recommendations_Helper</class>
25
+ </recommendations>
26
+ </helpers>
27
+ <resources>
28
+ <recommendations_setup>
29
+ <setup>
30
+ <module>AgilOne_Recommendations</module>
31
+ </setup>
32
+ </recommendations_setup>
33
+ </resources>
34
+ <blocks>
35
+ <recommendations>
36
+ <class>AgilOne_Recommendations_Block</class>
37
+ </recommendations>
38
+ </blocks>
39
+ </global>
40
+ <frontend>
41
+ <routers>
42
+ <recommendations>
43
+ <use>standard</use>
44
+ <args>
45
+ <module>AgilOne_Recommendations</module>
46
+ <frontName>recommendations</frontName>
47
+ </args>
48
+ </recommendations>
49
+ </routers>
50
+ <events>
51
+ <sales_quote_add_item>
52
+ <observers>
53
+ <recommendations_sales_quote_add_item>
54
+ <type>singleton</type>
55
+ <class>recommendations/observer</class>
56
+ <method>updateProductIdCart</method>
57
+ </recommendations_sales_quote_add_item>
58
+ </observers>
59
+ </sales_quote_add_item>
60
+ <sales_quote_item_delete_after>
61
+ <observers>
62
+ <recommendations_sales_quote_item_delete_after>
63
+ <type>singleton</type>
64
+ <class>recommendations/observer</class>
65
+ <method>updateProductIdCart</method>
66
+ </recommendations_sales_quote_item_delete_after>
67
+ </observers>
68
+ </sales_quote_item_delete_after>
69
+ <catalogsearch_query_save_after>
70
+ <observers>
71
+ <recommendations_catalogsearch_query_save_after>
72
+ <type>singleton</type>
73
+ <class>recommendations/observer</class>
74
+ <method>captureSearch</method>
75
+ </recommendations_catalogsearch_query_save_after>
76
+ </observers>
77
+ </catalogsearch_query_save_after>
78
+ </events>
79
+ <translate>
80
+ <modules>
81
+ <AgilOne_Recommendations>
82
+ <files>
83
+ <default>AgilOne_Recommendations.csv</default>
84
+ </files>
85
+ </AgilOne_Recommendations>
86
+ </modules>
87
+ </translate>
88
+ <layout>
89
+ <updates>
90
+ <recommendations>
91
+ <file>recommendations.xml</file>
92
+ </recommendations>
93
+ </updates>
94
+ </layout>
95
+ </frontend>
96
+ <default>
97
+ <agilone>
98
+ <general>
99
+ <enabled>1</enabled>
100
+ <base_url>api.agilone.com</base_url>
101
+ <api_key></api_key>
102
+ <api_secret></api_secret>
103
+ <tenant_id></tenant_id>
104
+ <source_id></source_id>
105
+ <webtag_id></webtag_id>
106
+ <force_https>1</force_https>
107
+ <brand_attribute>manufacturer</brand_attribute>
108
+ <log_level>0</log_level>
109
+ </general>
110
+ <pdp>
111
+ <title>You may also like . . .</title>
112
+ <limit>4</limit>
113
+ <cache_lifetime>3800</cache_lifetime>
114
+ <error_message>There are no recommendations to display.</error_message>
115
+ </pdp>
116
+ <widget>
117
+ <title>You may also like . . .</title>
118
+ <limit>4</limit>
119
+ <cache_lifetime>3800</cache_lifetime>
120
+ <error_message>There are no recommendations to display.</error_message>
121
+ <default_email>dummy@example.com</default_email>
122
+ </widget>
123
+ </agilone>
124
+ </default>
125
+ </config>
app/code/community/AgilOne/Recommendations/etc/system.xml ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <agilone translate="label" module="recommendations">
5
+ <label><![CDATA[<img src="https://app.agilone.com/images/logo-a1-60x60.png" alt="AgilOne Logo" style="width:20px;height:20px;padding-right:3px;position:relative;top:+4px;" />AgilOne Recommendations]]></label>
6
+ <tab>customer</tab>
7
+ <sort_order>1</sort_order>
8
+ <show_in_default>1</show_in_default>
9
+ <show_in_website>1</show_in_website>
10
+ <show_in_store>1</show_in_store>
11
+ <groups>
12
+ <general>
13
+ <label>Account Settings</label>
14
+ <comment><![CDATA[<h3>How does AgilOne work?</h3><p><strong>Now marketers, large and small, can boost revenues, improve marketing returns and transform their businesses without the need for in-house data scientists or ongoing IT involvement. AgilOne has been described as the perfect marriage between Machine Learning and Human Intelligence. When you sign up for AgilOne, you will also be supported by the best data scientists and marketing experts in the business. We are here to help!</strong><br/><br/><a href="https://app.agilone.com/metrics" target="_blank">Customer Login</a></span> | <a href="https://agilone.zendesk.com/hc/en-us" target="_blank">Knowledge Base</a></p><br/><br/>]]></comment>
15
+ <frontend_type>text</frontend_type>
16
+ <sort_order>10</sort_order>
17
+ <show_in_default>1</show_in_default>
18
+ <show_in_website>1</show_in_website>
19
+ <show_in_store>1</show_in_store>
20
+ <fields>
21
+ <enabled translate="label">
22
+ <label>Enable Module</label>
23
+ <frontend_type>select</frontend_type>
24
+ <source_model>adminhtml/system_config_source_yesno</source_model>
25
+ <sort_order>10</sort_order>
26
+ <show_in_default>1</show_in_default>
27
+ <show_in_website>1</show_in_website>
28
+ <show_in_store>1</show_in_store>
29
+ </enabled>
30
+ <base_url translate="label">
31
+ <label>Base URL</label>
32
+ <comment><![CDATA[Base URL for API (i.e. "api.agilone.com")]]></comment>
33
+ <frontend_type>text</frontend_type>
34
+ <sort_order>20</sort_order>
35
+ <show_in_default>1</show_in_default>
36
+ <show_in_website>1</show_in_website>
37
+ <show_in_store>1</show_in_store>
38
+ </base_url>
39
+ <api_key translate="label">
40
+ <label>A1 Access Key Id</label>
41
+ <comment><![CDATA[SHA256 (AES) Public Key.]]></comment>
42
+ <frontend_type>text</frontend_type>
43
+ <sort_order>30</sort_order>
44
+ <show_in_default>1</show_in_default>
45
+ <show_in_website>1</show_in_website>
46
+ <show_in_store>1</show_in_store>
47
+ </api_key>
48
+ <api_secret translate="label">
49
+ <label>A1 Secret Access Key</label>
50
+ <comment><![CDATA[SHA256 (AES) Secret Key.]]></comment>
51
+ <frontend_type>text</frontend_type>
52
+ <sort_order>40</sort_order>
53
+ <show_in_default>1</show_in_default>
54
+ <show_in_website>1</show_in_website>
55
+ <show_in_store>1</show_in_store>
56
+ </api_secret>
57
+ <tenant_id translate="label">
58
+ <label>Tenant ID (OPTIONAL)</label>
59
+ <comment><![CDATA[The TenantID is an ID specific to your workspace. If on app.agilone.com, you only have access to one workspace (the most common case) the tenant value is optional in API calls.]]></comment>
60
+ <frontend_type>text</frontend_type>
61
+ <sort_order>50</sort_order>
62
+ <show_in_default>1</show_in_default>
63
+ <show_in_website>1</show_in_website>
64
+ <show_in_store>1</show_in_store>
65
+ </tenant_id>
66
+ <source_id translate="label">
67
+ <label>Source ID</label>
68
+ <comment><![CDATA[The SourceID is an ID specific to your data sources. You may have several of them if AgilOne manage different customer or product databases for you. The {sourceid} parameter makes sure that the {customerkey} or {productkey} you're supplying is unique.]]></comment>
69
+ <frontend_type>text</frontend_type>
70
+ <sort_order>60</sort_order>
71
+ <show_in_default>1</show_in_default>
72
+ <show_in_website>1</show_in_website>
73
+ <show_in_store>1</show_in_store>
74
+ </source_id>
75
+ <webtag_id translate="label">
76
+ <label>WebTag ID</label>
77
+ <comment><![CDATA[ID provided with AgilOne WebTag account]]></comment>
78
+ <frontend_type>text</frontend_type>
79
+ <sort_order>70</sort_order>
80
+ <show_in_default>1</show_in_default>
81
+ <show_in_website>1</show_in_website>
82
+ <show_in_store>1</show_in_store>
83
+ </webtag_id>
84
+ <force_https translate="label">
85
+ <label>Force HTTPS</label>
86
+ <comment><![CDATA[Use HTTP or HTTPS for API access. NOTE: AgilOne's API enforces SSL on all connections by default. ]]></comment>
87
+ <frontend_type>select</frontend_type>
88
+ <source_model>adminhtml/system_config_source_yesno</source_model>
89
+ <sort_order>80</sort_order>
90
+ <show_in_default>1</show_in_default>
91
+ <show_in_website>1</show_in_website>
92
+ <show_in_store>1</show_in_store>
93
+ </force_https>
94
+ <brand_attribute translate="label">
95
+ <label>Brand Attribute</label>
96
+ <comment><![CDATA[Magento product attribute to represent the AgilOne 'brand' attribute in API calls.]]></comment>
97
+ <frontend_type>select</frontend_type>
98
+ <source_model>recommendations/adminhtml_system_config_source_brand</source_model>
99
+ <sort_order>90</sort_order>
100
+ <show_in_default>1</show_in_default>
101
+ <show_in_website>1</show_in_website>
102
+ <show_in_store>1</show_in_store>
103
+ </brand_attribute>
104
+ <log_level>
105
+ <label>Log Level</label>
106
+ <comment><![CDATA[Debug Logging Level.]]></comment>
107
+ <frontend_type>select</frontend_type>
108
+ <source_model>recommendations/adminhtml_system_config_source_log</source_model>
109
+ <sort_order>100</sort_order>
110
+ <show_in_default>1</show_in_default>
111
+ <show_in_website>1</show_in_website>
112
+ <show_in_store>1</show_in_store>
113
+ </log_level>
114
+ </fields>
115
+ </general>
116
+ <pdp>
117
+ <label>P2P Product Detail Page Recommendations</label>
118
+ <comment><![CDATA[<p><strong>Settings for P2P product recommendations block on PDP page (i.e. "catalog_product_view"). Replaces product upsell content block.</strong><br/><br/></p>]]></comment>
119
+ <frontend_type>text</frontend_type>
120
+ <sort_order>20</sort_order>
121
+ <show_in_default>1</show_in_default>
122
+ <show_in_website>1</show_in_website>
123
+ <show_in_store>1</show_in_store>
124
+ <fields>
125
+ <title translate="label">
126
+ <label>Title</label>
127
+ <comment><![CDATA[P2P block header title.]]></comment>
128
+ <frontend_type>text</frontend_type>
129
+ <sort_order>10</sort_order>
130
+ <show_in_default>1</show_in_default>
131
+ <show_in_website>1</show_in_website>
132
+ <show_in_store>1</show_in_store>
133
+ </title>
134
+ <limit translate="label">
135
+ <label>Number of Recommendations Returned</label>
136
+ <comment><![CDATA[Maximum number of P2P recommendations to return from API.]]></comment>
137
+ <frontend_type>text</frontend_type>
138
+ <sort_order>20</sort_order>
139
+ <show_in_default>1</show_in_default>
140
+ <show_in_website>1</show_in_website>
141
+ <show_in_store>1</show_in_store>
142
+ </limit>
143
+ <cache_lifetime translate="label">
144
+ <label>Cache Lifetime (seconds)</label>
145
+ <comment><![CDATA[Caching expiration seconds from current timestamp for P2P recommendations]]></comment>
146
+ <frontend_type>text</frontend_type>
147
+ <sort_order>30</sort_order>
148
+ <show_in_default>1</show_in_default>
149
+ <show_in_website>1</show_in_website>
150
+ <show_in_store>1</show_in_store>
151
+ </cache_lifetime>
152
+ </fields>
153
+ </pdp>
154
+ <widget>
155
+ <label>U2P Widget Recommendations</label>
156
+ <comment><![CDATA[<p><strong>Settings for the U2P user product recommendation widget.</strong><br/><br/></p>]]></comment>
157
+ <frontend_type>text</frontend_type>
158
+ <sort_order>30</sort_order>
159
+ <show_in_default>1</show_in_default>
160
+ <show_in_website>1</show_in_website>
161
+ <show_in_store>1</show_in_store>
162
+ <fields>
163
+ <title translate="label">
164
+ <label>Title</label>
165
+ <comment><![CDATA[U2P block header title.]]></comment>
166
+ <frontend_type>text</frontend_type>
167
+ <sort_order>10</sort_order>
168
+ <show_in_default>1</show_in_default>
169
+ <show_in_website>1</show_in_website>
170
+ <show_in_store>1</show_in_store>
171
+ </title>
172
+ <limit translate="label">
173
+ <label>Number of Recommendations Returned</label>
174
+ <comment><![CDATA[Maximum number of U2P recommendations to return from API.]]></comment>
175
+ <frontend_type>text</frontend_type>
176
+ <sort_order>20</sort_order>
177
+ <show_in_default>1</show_in_default>
178
+ <show_in_website>1</show_in_website>
179
+ <show_in_store>1</show_in_store>
180
+ </limit>
181
+ <cache_lifetime translate="label">
182
+ <label>Cache Lifetime (seconds)</label>
183
+ <comment><![CDATA[Caching expiration seconds from current timestamp for U2P recommendations]]></comment>
184
+ <frontend_type>text</frontend_type>
185
+ <sort_order>30</sort_order>
186
+ <show_in_default>1</show_in_default>
187
+ <show_in_website>1</show_in_website>
188
+ <show_in_store>1</show_in_store>
189
+ </cache_lifetime>
190
+ <default_email translate="label">
191
+ <label>Default Email for Guests</label>
192
+ <comment><![CDATA[Default email address to use for customers who aren't logged in.]]></comment>
193
+ <frontend_type>text</frontend_type>
194
+ <sort_order>40</sort_order>
195
+ <show_in_default>1</show_in_default>
196
+ <show_in_website>1</show_in_website>
197
+ <show_in_store>1</show_in_store>
198
+ </default_email>
199
+ </fields>
200
+ </widget>
201
+ </groups>
202
+ </agilone>
203
+ </sections>
204
+ </config>
app/code/community/AgilOne/Recommendations/etc/widget.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <widgets>
3
+ <recommendations_u2p type="recommendations/widget_u2p">
4
+ <name>AgilOne U2P Recommendations</name>
5
+ <description type="desc">Customer product recommendations provided by AgilOne.</description>
6
+ </recommendations_u2p>
7
+ </widgets>
app/design/frontend/base/default/layout/recommendations.xml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * @category AgileOne
5
+ * @package AgileOne_Recommendations
6
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
7
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
8
+ */
9
+ -->
10
+ <layout version="1.0.0">
11
+ <default>
12
+ <reference name="head">
13
+ <action method="addItem">
14
+ <type>skin_css</type>
15
+ <name>css/recommendations.css</name>
16
+ </action>
17
+ </reference>
18
+ <reference name="before_body_end">
19
+ <block type="recommendations/webtag" name="agilone.recommendations.webtag" as="agilone.recommendations.webtag" template="recommendations/webtag.phtml" />
20
+ <block type="recommendations/iframe" name="agilone.recommendations.iframe" as="agilone.recommendations.iframe" template="recommendations/iframe.phtml" />
21
+ </reference>
22
+ </default>
23
+ <catalog_product_view>
24
+ <reference name="product.info">
25
+ <block type="recommendations/catalog_product_list_upsell" name="product.info.upsell" as="upsell_products" template="recommendations/catalog/product/list/upsell.phtml">
26
+ <action method="setColumnCount"><columns>4</columns></action>
27
+ <block type="recommendations/catalog_product_list_upsell_item" name="catalog.product.upsell.item" template="recommendations/catalog/product/list/upsell/item.phtml" />
28
+ </block>
29
+ </reference>
30
+ </catalog_product_view></layout>
app/design/frontend/base/default/template/recommendations/catalog/product/list/upsell.phtml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($this->hasItems()): ?>
2
+ <div id="ordergroove-upsell">
3
+ <div class="widget-box">
4
+ <div class="box-title">
5
+ <h2><?php echo $this->getTitle() ?></h2>
6
+ </div>
7
+ <?php $i=0; foreach ($this->getItemCollection() as $_item): ?>
8
+ <?php if ($i++ % $this->getColumnCount() == 0): ?>
9
+ <ul class="widget-grid">
10
+ <?php endif ?>
11
+ <li class="item<?php if (($i - 1) % $this->getColumnCount() == 0):?> first<?php elseif ($i % $this->getColumnCount() == 0):?> last<?php endif;?>">
12
+ <?php
13
+ $itemBlock = $this->getChild('catalog.product.upsell.item')->setItem($_item)->setPosition($i);
14
+ echo $itemBlock->toHtml();
15
+ ?>
16
+ </li>
17
+ <?php if ($i % $this->getColumnCount() == 0 || $i == $this->getItemsCount()): ?>
18
+ </ul>
19
+ <?php endif ?>
20
+ <?php endforeach; ?>
21
+
22
+ </div>
23
+ </div>
24
+ <?php endif ?>
app/design/frontend/base/default/template/recommendations/catalog/product/list/upsell/item.phtml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $_item = $this->getItem();
2
+ if ($_item = $this->getItem()): ?>
3
+ <div class="item-info">
4
+ <a href="<?php echo $_item->getProductUrl() ?>" class="product-image"><img src="<?php echo $_item->getImageUrl() ?>" width="100" height="100" alt="<?php echo $this->escapeHtml($_item->getName()) ?>" title="<?php echo $this->escapeHtml($_item->getName()) ?>" /></a>
5
+ <div class="product-details">
6
+ <h3 class="product-name"><a href="<?php echo $_item->getProductUrl() ?>"><?php echo $this->escapeHtml($_item->getName()) ?></a></h3>
7
+ <div class="price-box">
8
+ <span class="regular-price">
9
+ <span class="price"><?php echo Mage::helper('core')->currency($_item->getSpecialPrice() ? $_item->getSpecialPrice() : $_item->getPrice(), true, false) ?></span>
10
+ </span>
11
+ </div>
12
+ </div>
13
+ </div>
14
+ <?php endif;?>
app/design/frontend/base/default/template/recommendations/iframe.phtml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <iframe src="" id="a1iframe" width="1" height="1" frameborder="0" ></iframe>
2
+ <script type='text/javascript'>
3
+ document.observe("dom:loaded", function() {
4
+ if ($("billing-buttons-container") != undefined) {
5
+ $("billing-buttons-container").on("click", "button.validation-passed", function() {
6
+ $('a1iframe').src = "<?php echo $this->_getUrl() ?>";
7
+ });
8
+ }
9
+ });
10
+ </script>
app/design/frontend/base/default/template/recommendations/webtag.phtml ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($this->isEnabled()): ?>
2
+ <script type='text/javascript'>
3
+ var _a1as = _a1as || [];
4
+ _a1as.push(["init","<?php echo $this->getWebTagId() ?>"]);
5
+ <?php $userId = $this->getUserId() ?>
6
+ <?php if (is_numeric($userId)):?>
7
+ _a1as.push(["setvar","userid","<?php echo $userId ?>"]);
8
+ <?php endif?>
9
+ <?php if ($email = $this->getEmail()):?>
10
+ _a1as.push(["setvar","email","<?php echo $email ?>"]);
11
+ <?php endif?>
12
+ <?php if ($product = $this->getProductView()):?>
13
+ _a1as.push(["setvar","productid_view","<?php echo $product->getProductId() ?>"]);
14
+ <?php if ($brandId = $product->getBrandId()): ?>
15
+ _a1as.push(["setvar","brandid_view","<?php echo $brandId ?>"]);
16
+ <?php endif?>
17
+ <?php endif?>
18
+ <?php if ($categoryId = $this->getCategoryIdView()):?>
19
+ _a1as.push(["setvar","categoryid_view","<?php echo $categoryId ?>"]);
20
+ <?php endif?>
21
+ <?php if ($productIds = $this->getProductIdCart()):?>
22
+ _a1as.push(["setvar","productid_cart","<?php echo trim($productIds) ?>"]);
23
+ <?php endif ?>
24
+ <?php if ($keyword = $this->getOnsiteSearch()):?>
25
+ _a1as.push(["setvar","onsitesearch","<?php echo $keyword ?>"]);
26
+ <?php endif ?>
27
+ <?php
28
+ if ($order = $this->getOrder()) {
29
+ if (!is_numeric($userId)) { ?>
30
+ _a1as.push(["setvar","userid","<?php echo $order->getCustomerId() ?>"]);
31
+ <?php }
32
+ if (!$email = $this->getEmail()) {?>
33
+ _a1as.push(["setvar","email","<?php echo $order->getCustomerEmail() ?>"]);
34
+ <?php }?>
35
+ _a1as.push(["setvar","orderid","<?php echo $order->getOrderId() ?>"]);
36
+ _a1as.push(["setvar","productid_order","<?php echo $order->getProductIdOrder() ?>"]);
37
+ _a1as.push(["setvar","ordertotal","<?php echo $order->getOrderTotal() ?>"]);
38
+ <?php } ?>
39
+ _a1as.push(["track"]);
40
+ </script>
41
+ <script type='text/javascript'>
42
+ (function() {
43
+ var a1s = document.createElement('script');
44
+ a1s.type = 'text/javascript';
45
+ a1s.async = true;
46
+ a1s.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'tr-1.agilone.com/tr-as.js';
47
+ var a1ss = document.getElementsByTagName('script')[0];
48
+ a1ss.parentNode.insertBefore(a1s, a1ss);
49
+ })();
50
+ </script>
51
+ <?php else:?>
52
+ <!-- AgilOne_Recommendations module has been disabled in the Magento admin -->
53
+ <?php endif?>
app/design/frontend/base/default/template/recommendations/widget/u2p/items.phtml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($this->hasItems()): ?>
2
+ <div id="ordergroove-widget">
3
+ <div class="widget-box">
4
+ <div class="box-title">
5
+ <h2><?php echo $this->getTitle() ?></h2>
6
+ </div>
7
+ <?php $i=0; foreach ($this->getItemCollection() as $_item): ?>
8
+ <?php if ($i++ % $this->getColumnCount() == 0): ?>
9
+ <ul class="widget-grid">
10
+ <?php endif ?>
11
+ <li class="item<?php if (($i - 1) % $this->getColumnCount() == 0):?> first<?php elseif ($i % $this->getColumnCount() == 0):?> last<?php endif;?>">
12
+ <?php
13
+ $itemBlock = $this->getChild('widget.u2p.item')->setItem($_item)->setPosition($i);
14
+ echo $itemBlock->toHtml();
15
+ ?>
16
+ </li>
17
+ <?php if ($i % $this->getColumnCount() == 0 || $i == $this->getItemsCount()): ?>
18
+ </ul>
19
+ <?php endif ?>
20
+ <?php endforeach; ?>
21
+ </div>
22
+ </div>
23
+ <?php endif ?>
app/design/frontend/base/default/template/recommendations/widget/u2p/items/item.phtml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ($_item = $this->getItem()): ?>
2
+ <div class="item-info">
3
+ <a href="<?php echo $_item->getProductUrl() ?>" class="product-image"><img src="<?php echo $_item->getImageUrl() ?>" width="100" height="100" alt="<?php echo $this->escapeHtml($_item->getName()) ?>" title="<?php echo $this->escapeHtml($_item->getName()) ?>" /></a>
4
+ <div class="product-details">
5
+ <h3 class="product-name"><a href="<?php echo $_item->getProductUrl() ?>"><?php echo $this->escapeHtml($_item->getName()) ?></a></h3>
6
+ <div class="price-box">
7
+ <span class="regular-price">
8
+ <span class="price"><?php echo Mage::helper('core')->currency($_item->getSpecialPrice() ? $_item->getSpecialPrice() : $_item->getPrice(), true, false) ?></span>
9
+ </span>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ <?php endif;?>
app/etc/modules/AgilOne_Recommendations.xml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * @category AgilOne
5
+ * @package AgilOne_Recommendations
6
+ * @copyright Copyright (c) 2014 AgilOne (http://www.agilone.com/)
7
+ * @author Richard Loerzel (rloerzel@lyonscg.com)
8
+ */
9
+ -->
10
+ <config>
11
+ <modules>
12
+ <AgilOne_Recommendations>
13
+ <active>true</active>
14
+ <codePool>community</codePool>
15
+ </AgilOne_Recommendations>
16
+ </modules>
17
+ </config>
app/locale/en_US/AgileOne_Recommendations.csv ADDED
File without changes
package.xml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>AgilOne_Recommendations_CE</name>
4
+ <version>1.0.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>AgilOne Predictive Marketing Module for Magento Community Edition</summary>
10
+ <description>AgilOne provides out of the box predictive marketing programs that increase conversions and customer lifetime value. Whether you are looking to convert more browsers into buyers, grow one time buyers into repeat buyers or retain valuable customers, AgilOne Turnkey Actions can deliver. For each program hyper-target content and offers using likelihood to buy, lifetime value, behavioral, product and brand clusters. Add one-on-one upsell, cross-sell and next-sell recommendations to boost impact. Whichever AgilOne program you start with, you will see immediate lift. Start with one program today, then continue to add new programs, all powered by the same Predictive Marketing Cloud. &#xD;
11
+ &#xD;
12
+ What Gives AgilOne The Leading Edge?&#xD;
13
+ &#xD;
14
+ Predictive Cart Recovery- Recover up to 45% of carts by providing the right incentive for each customer, taking into account likelihood to buy, lifetime value or cluster personas. Coordinate cart campaigns across channels to ensure you don&#x2019;t remind customers who already bought.&#xD;
15
+ &#xD;
16
+ Predictive Email Retargeting- Double site conversions by reminding customers to come back. Use one-on-one content such as abandoned search terms, items browsed, and recommendations. Then add the right incentive for each person based on likelihood to buy and lifetime value.&#xD;
17
+ &#xD;
18
+ Repeat Purchase Program- Get customers to repeat buy and double sales with post-purchase offers and recommendations or by sending replenishment reminders for consumables. Use likelihood to buy predictions to add the right level of discount or incentive.&#xD;
19
+ &#xD;
20
+ Cluster-Based Targeting- Triple conversions and increase lifetime value by targeted content using predictive product, brand or behavioral clusters. Also add personalized product recommendations to any of your programs &#x2013; online and offline.&#xD;
21
+ &#xD;
22
+ Loyalty Appreciation- Increase retention by showering your best customers with attention. Increase lifetime value by rewarding each customer with personalized loyalty rewards if they buy just a little more, or a little more often, than they usually would.&#xD;
23
+ &#xD;
24
+ Customer Reactivation- Reactivate customers with content based on cluster personas, a personal recommendation and an incentive that is right-sized using likelihood to buy and lifetime value. Also reduce email opt-outs 40% by adjusting email frequency by segment.</description>
25
+ <notes>All required page templates and layout files are located in the default theme directory (app/design/frontend/base/default). You will need to copy these files into your site's installed theme directory to install this module. See installation instructions for more details.&#xD;
26
+ </notes>
27
+ <authors><author><name>Joe Mancini</name><user>jmancini</user><email>joe.mancini@agilone.com</email></author></authors>
28
+ <date>2015-01-27</date>
29
+ <time>16:55:06</time>
30
+ <contents><target name="magecommunity"><dir><dir name="AgilOne"><dir name="Recommendations"><dir name="Block"><dir name="Catalog"><dir name="Product"><dir name="List"><dir name="Upsell"><file name="Item.php" hash="e4c027773238928af9785420dc5d0e7f"/></dir><file name="Upsell.php" hash="2417b4ef08b896c4644bf237df5d63b2"/></dir></dir></dir><file name="Iframe.php" hash="617872f6f4246bb4c2630c4960377864"/><file name="Webtag.php" hash="86805274691e6ef41686746bbb9f3945"/><dir name="Widget"><dir name="U2p"><dir name="Items"><file name="Item.php" hash="3e3cb709eea726ea7ddc436d71949c6d"/></dir><file name="Items.php" hash="706ab4ade9b7ab7c82311fb5e4a73df2"/></dir><file name="U2p.php" hash="94a58e321fcbe289238c7cc86a3e7c67"/></dir></dir><dir name="Helper"><file name="Data.php" hash="2d8cd6135b38e854755dc575b5b1df6b"/></dir><dir name="Model"><file name="Abstract.php" hash="7210e4b1c533da85ec86b58f37c3f2bb"/><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Source"><file name="Brand.php" hash="298072061fe5725ce6ff3636cecc7f02"/><file name="Log.php" hash="81841ae9aac08ee561e7f95f3f4e254c"/></dir></dir></dir></dir><file name="Feed.php" hash="9492859a2c00da4b5c330e442ca0f314"/><file name="Observer.php" hash="adcfae4929499f950dab60fad9129216"/><file name="Webtag.php" hash="11a8461f56a3b0b19794022121a65b4e"/></dir><dir name="controllers"><file name="AjaxController.php" hash="2919d6acab2a89459c9f0547316e59d2"/></dir><dir name="etc"><file name="adminhtml.xml" hash="b7ade3730ef0a58c10bbb504f7d59753"/><file name="config.xml" hash="1ed5137d00b1a638af221ebee18775aa"/><file name="system.xml" hash="d5eb10c4ebd05f04f8c380b081873fa9"/><file name="widget.xml" hash="1146942200e7eb109c683308f6eae7df"/></dir></dir></dir></dir></target><target name="magedesign"><dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="recommendations.xml" hash="49fb21c6005cf28d00ca3ff3e7dcd956"/></dir><dir name="template"><dir name="recommendations"><dir name="catalog"><dir name="product"><dir name="list"><dir name="upsell"><file name="item.phtml" hash="af1973e8a7e24ae3bcdbea2cad4a3348"/></dir><file name="upsell.phtml" hash="3f305c35bbb95aed702062b340965d22"/></dir></dir></dir><file name="iframe.phtml" hash="56b2e5cf2b01588910a91efa6ac5150e"/><file name="webtag.phtml" hash="95d86170a07bed708173f9e455dc6280"/><dir name="widget"><dir name="u2p"><dir name="items"><file name="item.phtml" hash="ef06bc8d5875ca4baa1d28fcd67ff255"/></dir><file name="items.phtml" hash="b01af5a56e889306eef45bbc1318f452"/></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir><dir name="modules"><file name="AgilOne_Recommendations.xml" hash="0c1e21985b9226bc310a56d249963212"/></dir></dir></target><target name="magelocale"><dir><dir name="en_US"><file name="AgileOne_Recommendations.csv" hash="d41d8cd98f00b204e9800998ecf8427e"/></dir></dir></target><target name="mageskin"><dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><file name="recommendations.css" hash="ef5656b647a3afd22d636c3a8b68af5c"/></dir></dir></dir></dir></dir></target></contents>
31
+ <compatible/>
32
+ <dependencies><required><php><min>5.3.3</min><max>5.3.29</max></php><package><name/><channel>connect.magentocommerce.com/core</channel><min/><max/></package><extension><name>mbstring</name><min/><max/></extension><extension><name>mcrypt</name><min/><max/></extension></required></dependencies>
33
+ </package>
skin/frontend/base/default/css/recommendations.css ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ordergroove-upsell { background-color:#faf7ee; padding:0; margin:0; }
2
+ #ordergroove-upsell .widget-box .box-title h2 { font-weight:bold; font-size:15px; color:#e26703; padding:0 0 1px; margin:0 0 8px; }
3
+ #ordergroove-upsell .widget-box { min-height:260px; margin:0; }
4
+ #ordergroove-upsell .widget-box .widget-grid .item { background-color:#ffffff;float:left; width:138px;padding:4px;margin:4px;border: 1px solid #e5dcc3;}
5
+ #ordergroove-upsell .widget-box .widget-grid .product-image {width:100px;height:135px;display:block; margin-left:auto;margin-right:auto;margin-bottom:10px;}
6
+ #ordergroove-upsell .widget-box .widget-grid .product-name { /*min-height:2.7em;*/ margin:0 0 5px; font-weight:bold; font-size:13px; color:#203548; text-align:center;}
7
+ #ordergroove-upsell .widget-box .widget-grid .product-name a { color:#203548; }
8
+ #ordergroove-upsell .widget-box .widget-grid .price-box { margin:5px 0; text-align:center;}
9
+ #ordergroove-upsell .widget-box .widget-grid .availability { line-height:21px; }
10
+ #ordergroove-upsell .widget-box .widget-grid .actions { position:absolute; bottom:12px; }
11
+
12
+ #ordergroove-widget { display:inline-block; padding:25px;}
13
+ #ordergroove-widget .widget-box .box-title h2 { font-weight:bold; font-size:15px; color:#e26703; padding:0 0 1px; margin:0 0 8px; border-bottom: 1px solid #e5dcc3; }
14
+ #ordergroove-widget .widget-box { min-height:240px; margin:0; }
15
+ #ordergroove-widget .widget-box .widget-grid .item { background-color:#ffffff;float:left; width:138px;padding:4px;margin:4px;border: 1px solid #e5dcc3; }
16
+ #ordergroove-widget .widget-box .widget-grid .product-image {width:100px;height:135px;display:block; margin-left:auto;margin-right:auto;margin-bottom:10px;}
17
+ #ordergroove-widget .widget-box .widget-grid .product-name { /*min-height:2.7em;*/ margin:0 0 5px; font-weight:bold; font-size:13px; color:#203548; text-align:center;}
18
+ #ordergroove-widget .widget-box .widget-grid .product-name a { color:#203548; }
19
+ #ordergroove-widget .widget-box .widget-grid .price-box { margin:5px 0; text-align:center;}
20
+ #ordergroove-widget .widget-box .widget-grid .availability { line-height:21px; }
21
+ #ordergroove-widget .widget-box .widget-grid .actions { position:absolute; bottom:12px; }