PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/yotpo/yotpo.php

https://github.com/DaveBenNoah/PrestaShop-modules
PHP | 801 lines | 741 code | 57 blank | 3 comment | 98 complexity | 573d7abc305004bf162f4e714d0e0d72 MD5 | raw file
Possible License(s): Apache-2.0, CC-BY-SA-3.0
  1. <?php
  2. if (!defined('_PS_VERSION_'))
  3. exit;
  4. class Yotpo extends Module
  5. {
  6. const PAST_ORDERS_DAYS_BACK = 90;
  7. const PAST_ORDERS_LIMIT = 10000;
  8. const BULK_SIZE = 1000;
  9. private $_html = '';
  10. private $_httpClient = null;
  11. private $_yotpo_module_path = '';
  12. private static $_MAP_STATUS = null;
  13. private $_required_files = array('/YotpoHttpClient.php', '/YotpoSnippetCache.php');
  14. private $_is_smarty_product_vars_assigned = false;
  15. public function __construct()
  16. {
  17. $version_mask = explode('.', _PS_VERSION_, 3);
  18. $version_test = $version_mask[0] > 0 && $version_mask[1] > 4;
  19. $this->name = 'yotpo';
  20. $this->tab = $version_test ? 'advertising_marketing' : 'Reviews';
  21. $this->version = '1.4';
  22. if ($version_test)
  23. $this->author = 'Yotpo';
  24. $this->need_instance = 1;
  25. parent::__construct();
  26. $this->displayName = $this->l('Yotpo - Social Reviews and Testimonials');
  27. $this->description = $this->l('The #1 reviews add-on for SMBs. Generate beautiful, trusted reviews for your shop.');
  28. $this->_yotpo_module_path = _PS_MODULE_DIR_.$this->name;
  29. if (!Configuration::get('yotpo_app_key'))
  30. $this->warning = $this->l('Set your API key in order the Yotpo module to work correctly');
  31. if (!defined('_PS_BASE_URL_'))
  32. define('_PS_BASE_URL_', 'http://'.(isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST']));
  33. if(file_exists($this->_yotpo_module_path . '/YotpoSnippetCache.php')) {
  34. include_once($this->_yotpo_module_path.'/YotpoSnippetCache.php');
  35. }
  36. /* Backward compatibility */
  37. if (version_compare(_PS_VERSION_, '1.5') < 0) {
  38. require(_PS_MODULE_DIR_.$this->name.'/backward_compatibility/backward.php');
  39. }
  40. }
  41. public function getAcceptedMapStatuses()
  42. {
  43. if(method_exists('Tools', "unSerialize")) {
  44. $selected_statuses = Tools::unSerialize(Configuration::get('yotpo_map_status'));
  45. }
  46. else {
  47. $selected_statuses = @unserialize(Configuration::get('yotpo_map_status'));
  48. }
  49. if(!is_null($selected_statuses) && !empty($selected_statuses)) {
  50. return $selected_statuses;
  51. }
  52. if (is_null(self::$_MAP_STATUS))
  53. {
  54. self::$_MAP_STATUS = array();
  55. $statuses = array('PS_OS_WS_PAYMENT', 'PS_OS_PAYMENT', 'PS_OS_DELIVERED', 'PS_OS_SHIPPING');
  56. foreach ($statuses as $status)
  57. {
  58. if (defined($status))
  59. self::$_MAP_STATUS[] = (int)Configuration::get($status);
  60. elseif (defined('_'.$status.'_'))
  61. self::$_MAP_STATUS[] = constant('_'.$status.'_');
  62. }
  63. }
  64. return self::$_MAP_STATUS;
  65. }
  66. public function install()
  67. {
  68. if (!function_exists('curl_init'))
  69. $this->setError($this->l('Yotpo needs the PHP Curl extension, please ask your hosting provider to enable it prior to install this module.'));
  70. if(version_compare(_PS_VERSION_, '1.3') < 0)
  71. $this->setError($this->l('Minimum version required for Yotpo module is Prestashop 1.3'));
  72. foreach ($this->_required_files as $file)
  73. if(!file_exists($this->_yotpo_module_path .$file))
  74. $this->setError($this->l('Can\'t include file '.$this->_yotpo_module_path .$file));
  75. if ((is_array($this->_errors) && count($this->_errors) > 0) || parent::install() == false ||
  76. !$this->registerHook('productfooter') || !$this->registerHook('postUpdateOrderStatus')||
  77. !$this->registerHook('extraLeft') || !$this->registerHook('extraRight') ||
  78. !$this->registerHook('productTab') || !$this->registerHook('productTabContent') ||
  79. !$this->registerHook('header') || !$this->registerHook('orderConfirmation') || !YotpoSnippetCache::createDB())
  80. return false;
  81. /* Default language: English; Default widget location: Product page Footer; Default widget tab name: "Reviews"
  82. * Default bottom line location: product page left column Default bottom line enabled : true*/
  83. Configuration::updateValue('yotpo_language', 'en', false);
  84. Configuration::updateValue('yotpo_widget_location', 'footer', false);
  85. Configuration::updateValue('yotpo_widget_tab_name', 'Reviews', false);
  86. Configuration::updateValue('yotpo_bottom_line_enabled', 1, false);
  87. Configuration::updateValue('yotpo_bottom_line_location', 'left_column', false);
  88. Configuration::updateValue('yotpo_widget_language_code', 'en', false);
  89. Configuration::updateValue('yotpo_language_as_site', 0, false);
  90. Configuration::updateValue('yotpo_rich_snippets', 1, false);
  91. Configuration::updateValue('yotpo_rich_snippet_cache_created', 1, true);
  92. Configuration::updateValue('yotpo_map_status', serialize($this->getAcceptedMapStatuses()), false);
  93. return true;
  94. }
  95. public function hookheader()
  96. {
  97. $smarty = $this->context->smarty;
  98. $smarty->assign(array('yotpoAppkey' => Configuration::get('yotpo_app_key'),
  99. 'yotpoDomain' => $this->getShopDomain(),
  100. 'yotpoLanguage' => $this->getLanguage()));
  101. if(isset($this->context->controller)) {
  102. $this->context->controller->addJS(($this->_path).'/js/headerScript.js');
  103. }
  104. else {
  105. return '<script type="text/javascript" src="'.$this->_path.'/js/headerScript.js"></script>';
  106. }
  107. }
  108. public function hookproductfooter($params)
  109. {
  110. $widgetLocation = Configuration::get('yotpo_widget_location');
  111. return ($widgetLocation == 'footer' || $widgetLocation == 'other') ? $this->showWidget($params['product']) : null;
  112. }
  113. public function hookpostUpdateOrderStatus($params)
  114. {
  115. if (in_array($params['newOrderStatus']->id, $this->getAcceptedMapStatuses()))
  116. {
  117. $data = $this->prepareMapData($params);
  118. if (Configuration::get('yotpo_app_key') != '' && Configuration::get('yotpo_oauth_token') != '' && !is_null($data))
  119. $this->httpClient()->makeMapRequest($data, Configuration::get('yotpo_app_key'), Configuration::get('yotpo_oauth_token'));
  120. }
  121. }
  122. public function hookProductTab()
  123. {
  124. if ($this->parseProductId() != null && Configuration::get('yotpo_widget_location') == 'tab') {
  125. if (version_compare(_PS_VERSION_, '1.6') >= 0) {
  126. return '<h3 class="page-product-heading"><a href="#idTab-yotpo">'.Configuration::get('yotpo_widget_tab_name').'</a></h3>';
  127. }
  128. return '<li><a href="#idTab-yotpo">'.Configuration::get('yotpo_widget_tab_name').'</a></li>';
  129. }
  130. return null;
  131. }
  132. public function hookProductTabContent()
  133. {
  134. $product = $this->getPageProduct(null);
  135. if ($product != null && Configuration::get('yotpo_widget_location') == 'tab')
  136. return '<div id="idTab-yotpo">'.$this->showWidget($product).'</div>';
  137. }
  138. public function hookextraLeft()
  139. {
  140. return $this->showBottomLine('left_column');
  141. }
  142. public function hookextraRight()
  143. {
  144. return $this->showBottomLine('right_column');
  145. }
  146. public function hookorderConfirmation($params)
  147. {
  148. $app_key = Configuration::get('yotpo_app_key');
  149. $order_id = !empty($params['objOrder']) && !empty($params['objOrder']->id) ? $params['objOrder']->id : null;
  150. $order_amount = !empty($params['total_to_pay']) ? $params['total_to_pay'] : '';
  151. $order_currency = !empty($params['currencyObj']) && !empty($params['currencyObj']->iso_code) ? $params['currencyObj']->iso_code : '';
  152. if(!empty($app_key) && !is_null($order_id)) {
  153. $smarty = $this->context->smarty;
  154. $conversion_params = "app_key=" .$app_key.
  155. "&order_id=" .$order_id.
  156. "&order_amount=".$order_amount.
  157. "&order_currency=" .$order_currency;
  158. $conversion_url = "https://api.yotpo.com/conversion_tracking.gif?$conversion_params";
  159. $smarty->assign('yotpoConversionUrl', $conversion_url);
  160. return $this->display(__FILE__,'views/templates/front/conversionImage.tpl');
  161. }
  162. }
  163. public function uninstall()
  164. {
  165. Configuration::deleteByName('yotpo_app_key');
  166. Configuration::deleteByName('yotpo_oauth_token');
  167. Configuration::deleteByName('yotpo_widget_location');
  168. Configuration::deleteByName('yotpo_widget_tab_name');
  169. Configuration::deleteByName('yotpo_past_orders');
  170. Configuration::deleteByName('yotpo_language');
  171. Configuration::deleteByName('yotpo_language_as_site');
  172. Configuration::deleteByName('yotpo_rich_snippets');
  173. Configuration::deleteByName('yotpo_rich_snippet_cache_created');
  174. Configuration::deleteByName('yotpo_map_status');
  175. YotpoSnippetCache::dropDB();
  176. return parent::uninstall();
  177. }
  178. public function getContent()
  179. {
  180. if (isset($this->context->controller))
  181. $this->context->controller->addCSS($this->_path.'/css/form.css', 'all');
  182. else
  183. echo '<link rel="stylesheet" type="text/css" href="../modules/yotpo/css/form.css" />';
  184. $force_settings = $this->processRegistrationForm() == 'b2c';
  185. $this->processSettingsForm();
  186. $this->displayForm($force_settings);
  187. return '<img src="http://www.prestashop.com/modules/yotpo.png?url_site='.Tools::safeOutput($_SERVER['SERVER_NAME']).'" alt="" style="display: none;" />'.$this->_html;
  188. }
  189. private function getProductImageUrl($id_product)
  190. {
  191. $id_image = Product::getCover($id_product);
  192. if (count($id_image) > 0)
  193. {
  194. $image = new Image($id_image['id_image']);
  195. return method_exists($image, 'getExistingImgPath') ? _PS_BASE_URL_._THEME_PROD_DIR_.$image->getExistingImgPath().".jpg" : $this->getExistingImgPath($image);
  196. }
  197. return null;
  198. }
  199. private function getExistingImgPath($image)
  200. {
  201. if (!$image->id)
  202. return null;
  203. if (file_exists(_PS_PROD_IMG_DIR_.(int)$image->id_product.'-'.(int)$image->id.'.jpg'))
  204. return _PS_BASE_URL_._THEME_PROD_DIR_.(int)$image->id_product.'-'.(int)$image->id.'.'.'jpg';
  205. }
  206. private function getProductLink($product_id)
  207. {
  208. $link = $this->context->link;
  209. if (isset($link) && method_exists($link, 'getProductLink'))
  210. return $link->getProductLink((int)$product_id);
  211. else
  212. {
  213. $link = new Link();
  214. return $link->getProductLink((int)$product_id);
  215. }
  216. }
  217. private function getDescritpion($product,$lang_id)
  218. {
  219. if (!empty($product['description_short']))
  220. return strip_tags($product['description_short']);
  221. $full_product = new Product((int)$product['id_product'], false, (int)$lang_id);
  222. return strip_tags($full_product->description);
  223. }
  224. private function setError($error)
  225. {
  226. if (!$this->_errors)
  227. $this->_errors = array();
  228. $this->_errors[] = $error;
  229. }
  230. private function httpClient()
  231. {
  232. if (is_null($this->_httpClient))
  233. {
  234. include_once($this->_yotpo_module_path.'/YotpoHttpClient.php');
  235. $this->_httpClient = new YotpoHttpClient($this->name);
  236. }
  237. return $this->_httpClient;
  238. }
  239. private function parseProductId()
  240. {
  241. $product_id = (int)Tools::getValue('id_product');
  242. if (!empty($product_id))
  243. return (int)$product_id;
  244. else
  245. {
  246. parse_str($_SERVER['QUERY_STRING'], $query);
  247. if (!empty($query['id_product']))
  248. return (int)$query['id_product'];
  249. }
  250. return null;
  251. }
  252. private function showWidget($product)
  253. {
  254. $rich_snippets = '';
  255. if(Configuration::get('yotpo_rich_snippets') == true) {
  256. $rich_snippets .= $this->getRichSnippet($this->parseProductId());
  257. }
  258. $smarty = $this->context->smarty;
  259. $smarty->assign('richSnippetsCode', $rich_snippets);
  260. $this->assignProductVars($product);
  261. if (Configuration::get('yotpo_widget_location') != 'other')
  262. return $this->display(__FILE__, 'views/templates/front/widgetDiv.tpl');
  263. return null;
  264. }
  265. private function assignProductVars($product = null)
  266. {
  267. if(!$this->_is_smarty_product_vars_assigned)
  268. {
  269. if (is_null($product))
  270. $product = $this->getPageProduct();
  271. $this->_is_smarty_product_vars_assigned = true;
  272. $smarty = $this->context->smarty;
  273. $smarty->assign(array('yotpoProductId' => (int)$product->id,
  274. 'yotpoProductName' => strip_tags($product->name),
  275. 'yotpoProductDescription' => strip_tags($product->description),
  276. 'yotpoProductModel' => $this->getProductModel($product),
  277. 'yotpoProductImageUrl' => $this->getProductImageUrl($product->id),
  278. 'yotpoProductBreadCrumbs' => $this->getBreadCrumbs($product),
  279. 'yotpoProductLink' => $this->getProductLink((int)$product->id),
  280. 'yotpoLanguage' => $this->getLanguage()));
  281. }
  282. }
  283. private function showBottomLine($bottom_line_location)
  284. {
  285. if(Configuration::get('yotpo_bottom_line_enabled') == true && Configuration::get('yotpo_bottom_line_location') === $bottom_line_location
  286. && Configuration::get('yotpo_bottom_line_location') != 'other')
  287. {
  288. $this->assignProductVars(null);
  289. return $this->display(__FILE__,'views/templates/front/bottomLineDiv.tpl');
  290. }
  291. }
  292. private function getShopDomain()
  293. {
  294. return method_exists('Tools', 'getShopDomain') ? Tools::getShopDomain(false,false) : str_replace('www.', '', $_SERVER['HTTP_HOST']);
  295. }
  296. private function processRegistrationForm()
  297. {
  298. if (Tools::isSubmit('yotpo_register'))
  299. {
  300. $email = Tools::getValue('yotpo_user_email');
  301. $name = Tools::getValue('yotpo_user_name');
  302. $password = Tools::getValue('yotpo_user_password');
  303. $confirm = Tools::getValue('yotpo_user_confirm_password');
  304. if ($email === false || $email === '')
  305. return $this->prepareError($this->l('Provide valid email address'));
  306. if (Tools::strlen($password) < 6 || Tools::strlen($password) > 128)
  307. return $this->prepareError($this->l('Password must be at least 6 characters'));
  308. if ($password != $confirm)
  309. return $this->prepareError($this->l('Passwords are not identical'));
  310. if ($name === false || $name === '')
  311. return $this->prepareError($this->l('Name is missing'));
  312. $is_mail_valid = $this->httpClient()->checkeMailAvailability($email);
  313. if ($is_mail_valid['status_code'] == 200 &&
  314. ($is_mail_valid['json'] == true && $is_mail_valid['response']['available'] == true) ||
  315. ($is_mail_valid['json'] == false && preg_match("/available[\W]*(true)/",$is_mail_valid['response']) == 1))
  316. {
  317. $response = $this->httpClient()->check_if_b2c_user($email);
  318. if (empty($response['response']['data']))
  319. {
  320. $registerResponse = $this->httpClient()->register($email, $name, $password, _PS_BASE_URL_);
  321. if ($registerResponse['status_code'] == 200)
  322. {
  323. $app_key ='';
  324. $secret = '';
  325. if ($registerResponse['json'] == true)
  326. $app_key = $registerResponse['response']['app_key'];
  327. else
  328. {
  329. preg_match("/app_key[\W]*[\"'](.*?)[\"']/",$registerResponse['response'], $matches);
  330. $app_key = $matches[1];
  331. unset($matches);
  332. }
  333. $secret ='';
  334. if ($registerResponse['json'] == true)
  335. $secret = $registerResponse['response']['secret'];
  336. else
  337. {
  338. preg_match("/secret[\W]*[\"'](.*?)[\"']/",$registerResponse['response'], $matches);
  339. $secret = $matches[1];
  340. }
  341. $accountPlatformResponse = $this->httpClient()->createAcountPlatform($app_key, $secret, _PS_BASE_URL_);
  342. if ($accountPlatformResponse['status_code'] == 200)
  343. {
  344. Configuration::updateValue('yotpo_app_key', $app_key, false);
  345. Configuration::updateValue('yotpo_oauth_token', $secret, false);
  346. return $this->prepareSuccess($this->l('Account successfully created'));
  347. }
  348. else
  349. return $this->prepareError($accountPlatformResponse['status_message']);
  350. }
  351. else
  352. return $this->prepareError($registerResponse['status_message']);
  353. }
  354. else
  355. {
  356. $id = $response['response']['data']['id'];
  357. $data = array(
  358. 'password'=> $password,
  359. 'display_name'=> $name,
  360. 'account' => array(
  361. 'url' => _PS_BASE_URL_,
  362. 'custom_platform_name'=>null,
  363. 'install_step'=>8,
  364. 'account_platform' => array(
  365. 'shop_domain'=> _PS_BASE_URL_,
  366. 'platform_type_id'=>8,
  367. )
  368. )
  369. );
  370. $this->httpClient()->create_user_migration($id,$data);
  371. $this->httpClient()->notify_user_migration($id);
  372. $this->prepareError($this->l('We have sent you a confirmation email. Please check and click on the link to get your app key and secret token to fill out below.'));
  373. return 'b2c';
  374. }
  375. }
  376. else
  377. return $is_mail_valid['status_code'] == 200 ? $this->prepareError($this->l('This e-mail address is already taken.')) : $this->prepareError();
  378. }
  379. }
  380. private function processSettingsForm()
  381. {
  382. if (Tools::isSubmit('yotpo_settings'))
  383. {
  384. $api_key = Tools::getValue('yotpo_app_key');
  385. $secret_token = Tools::getValue('yotpo_oauth_token');
  386. $location = Tools::getValue('yotpo_widget_location');
  387. $tabName = Tools::getValue('yotpo_widget_tab_name');
  388. $bottomLineEnabled = Tools::getValue('yotpo_bottom_line_enabled');
  389. $bottomLineLocation = Tools::getValue('yotpo_bottom_line_location');
  390. $language_as_site = Tools::getValue('yotpo_language_as_site');
  391. $widget_language_code = Tools::getValue('yotpo_widget_language_code');
  392. $rich_snippet = Tools::getValue('yotpo_rich_snippets');
  393. $map_statuses = Tools::getValue('yotpo_map_status');
  394. if ($api_key == '')
  395. return $this->prepareError($this->l('Api key is missing'));
  396. if ($secret_token == '')
  397. return $this->prepareError($this->l('Please fill out the secret token'));
  398. Configuration::updateValue('yotpo_app_key', Tools::getValue('yotpo_app_key'), false);
  399. Configuration::updateValue('yotpo_oauth_token', Tools::getValue('yotpo_oauth_token'), false);
  400. Configuration::updateValue('yotpo_widget_location', $location, false);
  401. Configuration::updateValue('yotpo_widget_tab_name', $tabName, false);
  402. Configuration::updateValue('yotpo_bottom_line_enabled', $bottomLineEnabled, false);
  403. Configuration::updateValue('yotpo_bottom_line_location', $bottomLineLocation, false);
  404. Configuration::updateValue('yotpo_language', $widget_language_code, false);
  405. Configuration::updateValue('yotpo_language_as_site', $language_as_site, false);
  406. Configuration::updateValue('yotpo_rich_snippets', $rich_snippet, false);
  407. Configuration::updateValue('yotpo_map_status', serialize($map_statuses), false);
  408. return $this->prepareSuccess();
  409. }
  410. elseif (Tools::isSubmit('yotpo_past_orders'))
  411. {
  412. $api_key = Tools::getValue('yotpo_app_key');
  413. $secret_token = Tools::getValue('yotpo_oauth_token');
  414. if ($api_key != '' && $secret_token != '')
  415. {
  416. $past_orders = $this->getPastOrders();
  417. $is_success = true;
  418. foreach ($past_orders as $post_bulk)
  419. if (!is_null($post_bulk))
  420. {
  421. $response = $this->httpClient()->makePastOrdersRequest($post_bulk, $api_key, $secret_token);
  422. if ($response['status_code'] != 200 && $is_success)
  423. {
  424. $is_success = false;
  425. $this->prepareError($this->l($response['status_message']));
  426. }
  427. }
  428. if ($is_success)
  429. {
  430. Configuration::updateValue('yotpo_past_orders', 1, false);
  431. Configuration::updateValue('YOTPO_CONFIGURATION_OK', true);
  432. $this->prepareSuccess('Past orders sent successfully');
  433. }
  434. }
  435. else
  436. $this->prepareError($this->l('You need to set your app key and secret token to post past orders'));
  437. }
  438. }
  439. private function displayForm($force_settings = false)
  440. {
  441. $smarty = $this->context->smarty;
  442. $smarty->assign(array('yotpo_finishedRegistration' => false, 'yotpo_allreadyUsingYotpo' => false));
  443. if (Tools::isSubmit('log_in_button'))
  444. {
  445. $smarty->assign('yotpo_allreadyUsingYotpo', true);
  446. return $this->displaySettingsForm();
  447. }
  448. if (Tools::isSubmit('yotpo_register'))
  449. $smarty->assign('yotpo_finishedRegistration', true);
  450. return Configuration::get('yotpo_app_key') != '' || $force_settings ? $this->displaySettingsForm() : $this->displayRegistrationForm();
  451. }
  452. private function displayRegistrationForm()
  453. {
  454. $smarty = $this->context->smarty;
  455. $smarty->assign(array('yotpo_action' => $_SERVER['REQUEST_URI'], 'yotpo_email' => Tools::getValue('yotpo_user_email'),
  456. 'yotpo_userName' => Tools::getValue('yotpo_user_name')));
  457. $this->_html .= $this->display(__FILE__, 'views/templates/admin/registrationForm.tpl');
  458. return $this->_html;
  459. }
  460. private function displaySettingsForm()
  461. {
  462. if(!Configuration::get('yotpo_rich_snippet_cache_created')) {
  463. $created = YotpoSnippetCache::createDB();
  464. Configuration::updateValue('yotpo_rich_snippet_cache_created', 1, $created);
  465. }
  466. $smarty = $this->context->smarty;
  467. $all_statuses = OrderState::getOrderStates($this->getLanguageId());
  468. //no configuration found -- use default
  469. if(Configuration::get('yotpo_map_status') == false) {
  470. Configuration::updateValue('yotpo_map_status', serialize($this->getAcceptedMapStatuses()), false);
  471. }
  472. if(method_exists('Tools', "unSerialize")) {
  473. $selected_statuses = Tools::unSerialize(Configuration::get('yotpo_map_status'));
  474. }
  475. else {
  476. $selected_statuses = @unserialize(Configuration::get('yotpo_map_status'));
  477. }
  478. foreach ($all_statuses as &$status) {
  479. $status['selected'] = in_array($status['id_order_state'], $selected_statuses) ? '1' : '0';
  480. }
  481. $smarty->assign(array(
  482. 'yotpo_action' => $_SERVER['REQUEST_URI'],
  483. 'yotpo_appKey' => Tools::getValue('yotpo_app_key',Configuration::get('yotpo_app_key')),
  484. 'yotpo_oauthToken' => Tools::getValue('yotpo_oauth_token',Configuration::get('yotpo_oauth_token')),
  485. 'yotpo_widgetLocation' => Configuration::get('yotpo_widget_location'),
  486. 'yotpo_showPastOrdersButton' => Configuration::get('yotpo_past_orders') != 1 ? true : false,
  487. 'yotpo_tabName' => Configuration::get('yotpo_widget_tab_name'),
  488. 'yotpo_bottomLineEnabled' => Configuration::get('yotpo_bottom_line_enabled'),
  489. 'yotpo_bottomLineLocation' => Configuration::get('yotpo_bottom_line_location'),
  490. 'yotpo_widget_language_code' => Configuration::get('yotpo_language'),
  491. 'yotpo_language_as_site' => Configuration::get('yotpo_language_as_site'),
  492. 'yotpo_rich_snippets' => Configuration::get('yotpo_rich_snippets'),
  493. 'yotpo_all_statuses' => $all_statuses));
  494. $settings_template = $this->display(__FILE__, 'views/templates/admin/settingsForm.tpl');
  495. if (strpos($settings_template, 'yotpo_map_enabled') != false || strpos($settings_template, 'yotpo_language_as_site') == false || strpos($settings_template, 'yotpo_rich_snippets') == false)
  496. {
  497. if(method_exists($smarty, 'clearCompiledTemplate'))
  498. {
  499. $smarty->clearCompiledTemplate(_PS_MODULE_DIR_ . $this->name .'/views/templates/admin/settingsForm.tpl');
  500. $settings_template = $this->display(__FILE__, 'views/templates/admin/settingsForm.tpl');
  501. }
  502. elseif (method_exists($smarty, 'clear_compiled_tpl'))
  503. {
  504. $smarty->clear_compiled_tpl(_PS_MODULE_DIR_ . $this->name .'/views/templates/admin/settingsForm.tpl');
  505. $settings_template = $this->display(__FILE__, 'views/templates/admin/settingsForm.tpl');
  506. }
  507. elseif (isset($smarty->force_compile)) {
  508. $value = $smarty->force_compile;
  509. $smarty->force_compile = true;
  510. $settings_template = $this->display(__FILE__, 'views/templates/admin/settingsForm.tpl');
  511. $smarty->force_compile = $value;
  512. }
  513. }
  514. $this->_html .= $settings_template;
  515. }
  516. private function getProductModel($product)
  517. {
  518. if (Validate::isEan13($product->ean13))
  519. return $product->ean13;
  520. elseif (Validate::isUpc($product->upc))
  521. return $product->upc;
  522. return null;
  523. }
  524. private function getBreadCrumbs($product)
  525. {
  526. if (!method_exists('Product', 'getProductCategoriesFull'))
  527. return '';
  528. $result = array();
  529. $lang_id = $this->getLanguageId();
  530. $all_product_subs = Product::getProductCategoriesFull((int)$product->id, (int)$lang_id);
  531. if (isset($all_product_subs) && count($all_product_subs) > 0)
  532. foreach($all_product_subs as $subcat)
  533. {
  534. $sub_category = new Category((int)$subcat['id_category'], (int)$lang_id);
  535. $sub_category_path = $sub_category->getParentsCategories();
  536. foreach ($sub_category_path as $key)
  537. $result[] = $key['name'];
  538. }
  539. return implode(';', $result);
  540. }
  541. private function prepareError($message = '')
  542. {
  543. $this->_html .= sprintf('<div class="bootstrap"><div class="alert">%s</div></div>', $message == '' ? $this->l('Error occured') : $message);
  544. }
  545. private function prepareSuccess($message = '')
  546. {
  547. $this->_html .= sprintf('<div class="conf confirm">%s</div>', $message == '' ? $this->l('Settings updated') : $message);
  548. }
  549. private function prepareMapData($params)
  550. {
  551. $order = new Order((int)$params['id_order']);
  552. $customer = new Customer((int)$order->id_customer);
  553. $id_lang = !is_null($params['cookie']) && !is_null($params['cookie']->id_lang) ? (int)$params['cookie']->id_lang : (int)Configuration::get('PS_LANG_DEFAULT');
  554. if (Validate::isLoadedObject($order) && Validate::isLoadedObject($customer))
  555. {
  556. $singleMapParams = array('id_order' => (int)$params['id_order'], 'date_add' => $order->date_add,
  557. 'email' => $customer->email, 'firstname'=> $customer->firstname, 'lastname' => $customer->lastname,
  558. 'id_lang' => $id_lang);
  559. $result = $this->getSingleMapData($singleMapParams);
  560. if (!is_null($result) && is_array($result))
  561. {
  562. $result['platform'] = 'prestashop';
  563. return $result;
  564. }
  565. }
  566. return null;
  567. }
  568. private function getSingleMapData($params)
  569. {
  570. $cart = Cart::getCartByOrderId((int)$params['id_order']);
  571. if(Validate::isLoadedObject($cart))
  572. {
  573. $products = $cart->getProducts();
  574. if(count($products) == 0 && method_exists('Shop','getContextShopID') && Shop::getContextShopID() != (int)$cart->id_shop)
  575. {
  576. Shop::initialize();
  577. $products = $cart->getProducts(true);
  578. }
  579. $currency = Currency::getCurrencyInstance((int)$cart->id_currency);
  580. if (!is_null($products) && is_array($products) && Validate::isLoadedObject($currency))
  581. {
  582. $data = array();
  583. $data['order_date'] = $params['date_add'];
  584. $data['email'] = $params['email'];
  585. $data['customer_name'] = $params['firstname'].' '.$params['lastname'];
  586. $data['order_id'] = (int)$params['id_order'];
  587. $data['currency_iso'] = $currency->iso_code;
  588. $products_arr = array();
  589. foreach ($products as $product)
  590. {
  591. $product_data = array();
  592. $product_data['url'] = $this->getProductLink($product['id_product']);
  593. $product_data['name'] = $product['name'];
  594. $product_data['image'] = $this->getProductImageUrl((int)$product['id_product']);
  595. $product_data['description'] = $this->getDescritpion($product, (int)$params['id_lang']);
  596. $product_data['price'] = $product['price'];
  597. $products_arr[(int)$product['id_product']] = $product_data;
  598. }
  599. $data['products'] = $products_arr;
  600. return $data;
  601. }
  602. }
  603. return null;
  604. }
  605. private function getPastOrders()
  606. {
  607. $result = Db::getInstance()->ExecuteS('SELECT o.`id_order`,o.`id_lang`, o.`date_add`, c.`firstname`, c.`lastname`, c.`email`
  608. FROM `'._DB_PREFIX_.'order_history` oh
  609. LEFT JOIN `'._DB_PREFIX_.'orders` o ON (o.`id_order` = oh.`id_order`)
  610. LEFT JOIN `'._DB_PREFIX_.'customer` c ON (c.`id_customer` = o.`id_customer`)
  611. WHERE oh.`id_order_history` IN (SELECT MAX(`id_order_history`) FROM `'._DB_PREFIX_.'order_history` GROUP BY `id_order`) AND
  612. o.`date_add` < NOW() AND
  613. DATE_SUB(NOW(), INTERVAL '.self::PAST_ORDERS_DAYS_BACK.' day) < o.`date_add` AND
  614. oh.`id_order_state` IN ('.join(',', $this->getAcceptedMapStatuses()).')
  615. LIMIT 0,'.self::PAST_ORDERS_LIMIT.'');
  616. if (is_array($result))
  617. {
  618. $orders = array();
  619. foreach ($result as $singleMap)
  620. {
  621. $res = $this->getSingleMapData($singleMap);
  622. if (!is_null($res))
  623. $orders[] = $res;
  624. }
  625. $post_bulk_orders = array_chunk($orders, self::BULK_SIZE);
  626. $data = array();
  627. foreach ($post_bulk_orders as $index => $bulk)
  628. {
  629. $data[$index] = array();
  630. $data[$index]['orders'] = $bulk;
  631. $data[$index]['platform'] = 'prestashop';
  632. }
  633. return $data;
  634. }
  635. return null;
  636. }
  637. private function getPageProduct($product_id = null)
  638. {
  639. if($product_id == null)
  640. $product_id = $this->parseProductId();
  641. $product = new Product((int)($product_id), false, Configuration::get('PS_LANG_DEFAULT'));
  642. if(Validate::isLoadedObject($product))
  643. return $product;
  644. return null;
  645. }
  646. private function getLanguage() {
  647. $language = Configuration::get('yotpo_language');
  648. if (Configuration::get('yotpo_language_as_site') == true) {
  649. if (isset($this->context->language) && isset($this->context->language->iso_code)) {
  650. $language = $this->context->language->iso_code;
  651. }
  652. else {
  653. $language = Language::getIsoById( (int)$this->context->cookie->id_lang );
  654. }
  655. }
  656. return $language;
  657. }
  658. private function getRichSnippet($product_id) {
  659. $result = '';
  660. if (Configuration::get('yotpo_app_key') != '' && Configuration::get('yotpo_oauth_token') != '' && is_int($product_id)) {
  661. try {
  662. $result = YotpoSnippetCache::getRichSnippet($product_id);
  663. $should_update_row = is_array($result) && !YotpoSnippetCache::isValidCache($result);
  664. if($result == false || $should_update_row) {
  665. $result = '';
  666. $expiration_time = null;
  667. $request_result = $this->httpClient()->makeRichSnippetRequest(Configuration::get('yotpo_app_key'), $product_id);
  668. if($request_result['status_code'] == 200) {
  669. if ($request_result['json'] == true) {
  670. $result .= $request_result['response']['rich_snippet']['html_code'];
  671. $expiration_time = $request_result['response']['rich_snippet']['ttl'];
  672. }
  673. else
  674. {
  675. preg_match("/html_code[\"']:[\"'](.*)[\"'],[\"']ttl/",$request_result['response'], $matches);
  676. $result = $matches[1];
  677. unset($matches);
  678. $result = str_replace('\"','"',$result);
  679. $result = str_replace('\n','',$result);
  680. preg_match("/ttl[\"']:(.*)}/",$request_result['response'], $matches);
  681. $expiration_time = $matches[1];
  682. unset($matches);
  683. }
  684. if(Tools::strlen($result) > 0 && Tools::strlen($expiration_time) > 0 && is_numeric($expiration_time)) {
  685. if($should_update_row) {
  686. YotpoSnippetCache::updateCahce($product_id, $result, $expiration_time);
  687. }
  688. else {
  689. YotpoSnippetCache::addRichSnippetToCahce($product_id, $result, $expiration_time);
  690. }
  691. }
  692. }
  693. }
  694. elseif (is_array($result) && !$should_update_row) {
  695. $result = $result['rich_snippet_code'];
  696. }
  697. }
  698. catch (Exception $e) {
  699. error_log($e->getMessage());
  700. }
  701. }
  702. return $result;
  703. }
  704. private function getLanguageId(){
  705. if (isset($this->context->language) && isset($this->context->language->id)) {
  706. return $this->context->language->id;
  707. }
  708. else {
  709. return $this->context->cookie->id_lang;
  710. }
  711. }
  712. }