* @copyright 2007-2013 PrestaShop SA * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ class Mobile_Theme extends Module { public $_errors = array(); public $_html = ''; public function __construct() { $this->name = 'mobile_theme'; $this->tab = (version_compare(_PS_VERSION_, 1.4) >= 0 ? 'administration' : 'Theme'); $this->version = '0.5.2'; parent::__construct(); $this->displayName = $this->l('Mobile Template'); $this->description = $this->l('Provides a mobile template compatible with iPhone, Android, etc.'); $this->confirmUninstall = $this->l('Uninstalling this module will delete your mobile template and all the custom modifications that you may have done on it, are you sure?'); /* Compatibility with old versions of PrestaShop */ if (!defined('_PS_ROOT_DIR_')) define('_PS_ROOT_DIR_', dirname(__FILE__).'/../../'); } public function install() { if (_PS_VERSION_ >= '1.5') { $this->_errors[] = $this->l('This module cannot be installed on this version of PrestaShop.'); return false; } return Configuration::updateValue('PS_MOBILE_THEME_HEADINGS', 'b') && Configuration::updateValue('PS_MOBILE_THEME_FILTERING_BAR', 'a') && Configuration::updateValue('PS_MOBILE_THEME_PROCESS_BAR', 'a') && Configuration::updateValue('PS_MOBILE_THEME_CONF_MSG', 'e') && Configuration::updateValue('PS_MOBILE_THEME_ERROR_MSG', 'a') && Configuration::updateValue('PS_MOBILE_THEME_LIST_HEADERS', 'b') && Configuration::updateValue('PS_MOBILE_THEME_BUTTONS', 'e') && Configuration::updateValue('PS_MOBILE_THEME_HEADER_FOOTER', 'a') && Configuration::updateValue('PS_MOBILE_DOMAIN', 'm.'.Configuration::get('PS_SHOP_DOMAIN')) && Configuration::updateValue('PS_MOBILE_DEVICE', 0) && Configuration::updateValue('PS_REDIRECT_MOBILE_DOMAIN', 0) && Configuration::updateValue('PS_MOBILE_MODULE_ENABLED', 1) && $this->modifySettingsFile(true) && /*$this->installTheme(true) &&*/ parent::install() && $this->registerHook('header') && $this->registerHook('home') /*&& $this->registerHook('footer')*/ && $this->registerHook('backOfficeTop') && $this->installHook(); } public function uninstall() { return Configuration::deleteByName('PS_MOBILE_THEME_HEADINGS') && Configuration::deleteByName('PS_MOBILE_THEME_FILTERING_BAR') && Configuration::deleteByName('PS_MOBILE_THEME_PROCESS_BAR') && Configuration::deleteByName('PS_MOBILE_THEME_CONF_MSG') && Configuration::deleteByName('PS_MOBILE_THEME_ERROR_MSG') && Configuration::deleteByName('PS_MOBILE_THEME_LIST_HEADERS') && Configuration::deleteByName('PS_MOBILE_THEME_BUTTONS') && Configuration::deleteByName('PS_MOBILE_THEME_HEADER_FOOTER') && Configuration::deleteByName('PS_MOBILE_DOMAIN') && Configuration::deleteByName('PS_MOBILE_DEVICE') && Configuration::deleteByName('PS_REDIRECT_MOBILE_DOMAIN') && Configuration::deleteByName('PS_MOBILE_MODULE_ENABLED') && Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'hook` WHERE `id_hook` = '.(int)Configuration::get('PS_MOBILE_HOOK_HEADER_ID')) && Configuration::deleteByName('PS_MOBILE_HOOK_HEADER_ID') && $this->modifySettingsFile(false) && $this->installTheme(false) && parent::uninstall(); } public function installHook() { return Db::getInstance()->Execute('INSERT INTO `'._DB_PREFIX_.'hook` (`name`, `title`, `description`) VALUE (\'displayMobileHeader\', \''.pSQL($this->l('Header of mobile pages')).'\', \''.pSQL($this->l('A hook which allow you to do things in the header of each pages of the Mobile version')).'\')') && Configuration::updateValue('PS_MOBILE_HOOK_HEADER_ID', Hook::get('displayMobileHeader')); } /** * @brief Edit the Settings file * * @param boolean $install Whether we are installing or uninstalling * @param array $params Array fof parameters, allowed value: 'mobile_domain' => string, 'device' => {0:'phone', 1:'tablet', 2:'both'} * * @return boolean Success/Failure */ public function editSettings($install = true, $params = array()) { return true; } /** * @brief Modify the PrestaShop core file for the Mobile * * @param boolean $install Whether we install or uninstall * * @return boolean Success/Failure */ protected function modifySettingsFile($install = true) { return true; } /** * @brief Copy the mobile theme into the PrestaShop theme directory * * @param string $install Flag whether we install or uninstall. * * @return boolean Success or Failure */ function installTheme($install = true) { return true; } /** * @brief Check if user should be redirected to a specific site. * * @param array params Params array from hookHeader() * @param string site_type Type of site to be redirected (allowed value: 'ps_full_site' and 'ps_mobile_site' * @param boolean addjs_exists whether Tools::addJS() exists or not * */ protected function _redirectSite($params, $site_type, $addjs_exists = true) { if ($site_type != 'ps_full_site' && $site_type != 'ps_mobile_site') return ; global $js_files; // Make sure order-opc is well redirected to order if (_THEME_NAME_ == 'prestashop_mobile' && $site_type == 'ps_mobile_site' && strpos($_SERVER['PHP_SELF'], 'order-opc.php') !== false) { global $link; $dest = $link->getPageLink('order.php', true); header('HTTP/1.0 302 Moved'); header('Location: '.$dest.(strpos($dest, '?') !== false ? '&' : '?').'ps_mobile_site=1'.(isset($_GET['mobile_iframe']) ? '&mobile_iframe=1' : '')); exit; } $site_type_cookie = (int)($site_type == 'ps_full_site'); if (isset($params['cookie']->full_site) && $params['cookie']->full_site == $site_type_cookie && !isset($_GET['ps_mobile_site']) && !isset($_GET['ps_full_site'])) { $dest = $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; header('HTTP/1.0 302 Moved'); header('Location: http://'.$dest.(strpos($dest, '?') !== false ? '&' : '?').$site_type.'=1'.(isset($_GET['mobile_iframe']) ? '&mobile_iframe=1' : '')); exit; } if (isset($_GET['mobile_iframe'])) unset($params['cookie']->full_site); /*if ($site_type == 'ps_mobile_site' && !isset($_GET['ps_mobile_site']) && !isset($_GET['ps_full_site'])) { if ($addjs_exists) Tools::addJS(__PS_BASE_URI__.'modules/mobile_theme/iframe_redirect.js'); else array_push($js_files, __PS_BASE_URI__.'modules/mobile_theme/mobile_iframe.js'); } if ($site_type == 'ps_full_site' && isset($_GET['mobile_iframe'])) { if ($addjs_exists) Tools::addJS(__PS_BASE_URI__.'modules/mobile_theme/mobile_iframe.js'); else array_push($js_files, __PS_BASE_URI__.'modules/mobile_theme/mobile_iframe.js'); }*/ } /** * @brief Init the Cookie for scpecific site and rewrite all links. * * @param array $params params of the HookHeader() * @param boolean $addjs_exists whether Tools::addJS() exists or not * */ protected static function _initForceSite($params, $addjs_exists = true) { global $js_files, $smarty; if (!isset($js_files)) $js_files = array(); if (isset($_GET['ps_full_site']) && $_GET['ps_full_site'] == 1) { if ($addjs_exists) Tools::addJS(__PS_BASE_URI__.'modules/mobile_theme/full_site.js'); else { array_push($js_files, __PS_BASE_URI__.'modules/mobile_theme/full_site.js'); $smarty->assign('js_files_mobile', $js_files); } $params['cookie']->full_site = 1; } elseif (isset($_GET['ps_mobile_site']) && $_GET['ps_mobile_site'] == 1) { if ($addjs_exists) Tools::addJS(__PS_BASE_URI__.'modules/mobile_theme/mobile_site.js'); else { array_push($js_files, __PS_BASE_URI__.'modules/mobile_theme/mobile_site.js'); $smarty->assign('js_files_mobile', $js_files); } $params['cookie']->full_site = 0; } } /** * @brief Remove former verison of JQuery * * Search for former version of JQuery and unset them in order to include the last one. * */ protected static function _removeJQuery() { global $js_files; // Remove Jquery from the js list file, will be included in the template (also remove thickbox in 1.3) $jquery_names = array('jquery.js', 'jquery.pack.js', 'jquery.min.js', 'jquery-1.2.6.pack.js', 'jquery-1.4.4.min.js', 'jquery-1.6.2.min.js', 'jquery-1.7.2.min.js', 'thickbox-modified.js'); foreach ($js_files as $k => $f) if (in_array(basename($f), $jquery_names)) unset($js_files[$k]); } /** * @brief Disable the module * * When disabling the module, we need to edit the settings to also disable the theme swtich. * When enabling it, the settings will be rewritten automatically with the performances system. * */ public function disable() { Configuration::updateValue('PS_MOBILE_MODULE_ENABLED', 0); $this->editSettings(false); return parent::disable(); } public function hookBackOfficeTop($params) { // If the module as been disabled (manually or via performances update) rewrite the settings /*if (!Configuration::get('PS_MOBILE_MODULE_ENABLED')) { $this->editSettings(false); $this->editSettings(true, array('mobile_domain' => Configuration::get('PS_MOBILE_DOMAIN'), 'device' => (int)Configuration::get('PS_MOBILE_DEVICE'))); }*/ if (!defined('_PS_MOBILE_')) Configuration::updateValue('PS_MOBILE_MODULE_ENABLED', 0); // Helper function for the performance/db tab $this->_html .= ''."\n"; // Make sure we have JQuery if (version_compare(_PS_VERSION_, '1.0', '<')) $this->_html .= ''; // Display warning message if the module is disabled (This occurs only in case of failure) /*if (!Configuration::get('PS_MOBILE_MODULE_ENABLED')) $this->_html .= '';*/ // If a form has been submitted with the 'ps_disable_mobile' param, revert the settings if (Tools::isSubmit('ps_disable_mobile')) { Configuration::updateValue('PS_MOBILE_MODULE_ENABLED', 0); $this->editSettings(false); } // Make sure to uninstall the module before deleting it if (Tools::isSubmit('ps_delete_mobile') && Tools::getValue('token') == Tools::getAdminTokenLite('AdminModules')) { $this->uninstall(); $this->_html .= ''; } $this->_html .= ''; // Make sure to rewrite the settings with performaces and database tab. (add ps_disable_mobile params to the forms) if (isset($_GET['tab']) && $_GET['tab'] == 'AdminDb') $this->_html .= ''; elseif (isset($_GET['tab']) && $_GET['tab'] == 'AdminMeta') $this->_html .= ''; elseif (isset($_GET['tab']) && $_GET['tab'] == 'AdminPerformance') $this->_html .= ''; return $this->_html; } public function hookHeader($params) { global $js_files, $css_files, $smarty; $addjs_exists = method_exists('Tools', 'addJS'); // Check if URL contain specific site data and change the site if needed self::_initForceSite($params, $addjs_exists); // If forced mobile site, need to make sure PrestaShop redirect well on mobile site $this->_redirectSite($params, 'ps_mobile_site', $addjs_exists); // If the theme is not the mobile one, we just stop here. if (_THEME_NAME_ != 'prestashop_mobile') return; // Load the hookMobileHeader for the registered modules $modules = Db::getInstance()->ExecuteS(' SELECT `name` FROM `'._DB_PREFIX_.'module` m LEFT JOIN `'._DB_PREFIX_.'hook_module` hm ON (hm.id_module = m.id_module) WHERE hm.`id_hook` = '.(int)Configuration::get('PS_MOBILE_HOOK_HEADER_ID')); foreach ($modules as $m) { $tmp = Module::getInstanceByName($m['name']); $this->_html .= $tmp->hookDisplayMobileHeader(); } // If forced full site, need to make sure PrestaShop redirect well on full site $this->_redirectSite($params, 'ps_full_site', $addjs_exists); self::_removeJQuery(); if (strpos($_SERVER['PHP_SELF'], 'order.php') !== false) { $addr = new Address((int)$params['cart']->id_address_invoice); if (Validate::isLoadedObject($addr)) if (in_array(Country::getIsoById((int)$addr->id_country), array('FR', 'PL', 'IT', 'ES'))) array_push($js_files, _THEME_DIR_.'js/payment.js'); } // Create a new Array of all JS and append the old one to it (Important for JQuery) $js_files_mobile = array_unique(array_merge(array(_THEME_DIR_.'js/jquery.min.js', _THEME_DIR_.'js/jquery.mobile.min.js', _THEME_DIR_.'js/global.js', _THEME_DIR_.'js/swipe.js', _THEME_DIR_.'js/product.js', _THEME_DIR_.'js/tools.js', _THEME_DIR_.'js/order-address.js', _THEME_DIR_.'js/statesManagement.js'), $js_files)); // Empty the former js files $js_files = array(); if ($addjs_exists) // Consider that if Tools::addJS() exists, then Tools::addCSS() too. { Tools::addJS($js_files_mobile); Tools::addCSS(_THEME_DIR_.'css/jquery.mobile.min.css'); } else $css_files[_THEME_DIR_.'css/jquery.mobile.min.css'] = 'all'; $smarty->assign(array('mobile_theme_phone' => _PS_MOBILE_PHONE_, 'mobile_theme_tablet' => _PS_MOBILE_TABLET_, 'js_files_mobile' => $js_files_mobile, 'css_files_mobile' => $css_files)); /* Template Styles */ $smarty->assign('ps_mobile_styles', Configuration::getMultiple(array('PS_MOBILE_THEME_HEADINGS', 'PS_MOBILE_THEME_FILTERING_BAR', 'PS_MOBILE_THEME_PROCESS_BAR', 'PS_MOBILE_THEME_CONF_MSG', 'PS_MOBILE_THEME_ERROR_MSG', 'PS_MOBILE_THEME_LIST_HEADERS', 'PS_MOBILE_THEME_BUTTONS', 'PS_MOBILE_THEME_HEADER_FOOTER'))); $paypal = Module::getInstanceByName('paypal'); if ($paypal && $paypal->active && version_compare($paypal->version, '3.2.0', '>=')) { if (strpos($_SERVER['PHP_SELF'], 'product.php') !== false) $smarty->assign('paypal_product', $paypal->renderExpressCheckoutButton('product').$paypal->renderExpressCheckoutForm('product')); if (strpos($_SERVER['PHP_SELF'], 'order.php') !== false || strpos($_SERVER['PHP_SELF'], '.php') !== false) $smarty->assign('paypal_cart', $paypal->renderExpressCheckoutButton('cart').$paypal->renderExpressCheckoutForm('cart')); } // Display/assign specific content for pages self::_pageStore($params); // Add translation of JS message for the payment page if (strpos($_SERVER['PHP_SELF'], 'order.php') !== false) $smarty->assign('translate_nopayment', ''); // The hookHeader is not called from the mobile template. Affect $smarty->HOOK_HEADER_MOBILE instead $smarty->assign('HOOK_HEADER_MOBILE', $this->_html); } /** * @brief Assign missing smarty templates for Store page * * @param array $params params array from hookHeader * */ protected static function _pageStore($params) { if (strpos($_SERVER['PHP_SELF'], 'stores.php') !== false) { global $smarty; Configuration::set('PS_STORES_SIMPLIFIED', 1); $stores = Db::getInstance()->ExecuteS(' SELECT s.*, cl.`name` country, st.`iso_code` state FROM `'._DB_PREFIX_.'store` s LEFT JOIN `'._DB_PREFIX_.'country_lang` cl ON (cl.`id_country` = s.`id_country`) LEFT JOIN `'._DB_PREFIX_.'state` st ON (st.`id_state` = s.`id_state`) WHERE s.`active` = 1 AND cl.`id_lang` = '.(int)$params['cookie']->id_lang); foreach ($stores as &$store) $store['has_picture'] = file_exists(_PS_STORE_IMG_DIR_.(int)$store['id_store'].'.jpg'); $smarty->assign('stores', $stores); } } public function hookFooter($params) { if ($params['cookie']->full_site == 1) return '
'.$this->l('View mobile site').'
'; } public function hookHome($params) { if (_THEME_NAME_ != 'prestashop_mobile') return; global $smarty, $link; $id_customer = (int)($params['cookie']->id_customer); $id_lang = (int)$params['cookie']->id_lang; $groups = $id_customer ? implode(', ', Customer::getGroupsStatic($id_customer)) : (int)_PS_DEFAULT_CUSTOMER_GROUP_; $maxdepth = Configuration::get('BLOCK_CATEG_MAX_DEPTH'); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS(' SELECT c.`id_parent`, c.`id_category`, cl.`name`, cl.`description` as `desc`, cl.`link_rewrite` FROM `'._DB_PREFIX_.'category` c LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` AND `id_lang` = '.(int)$id_lang.') LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = c.`id_category`) WHERE (c.`active` = 1 AND c.`id_parent` = 1) '.((int)($maxdepth) != 0 ? ' AND `level_depth` <= '.(int)($maxdepth) : '').' AND cg.`id_group` IN ('.pSQL($groups).') GROUP BY id_category ORDER BY `level_depth` ASC, '.(Configuration::get('BLOCK_CATEG_SORT') ? 'cl.`name`' : 'c.`position`').' '.(Configuration::get('BLOCK_CATEG_SORT_WAY') ? 'DESC' : 'ASC')); if ($result) { foreach ($result as &$r) $r['link'] = $link->getCategoryLink((int)$r['id_category'], $r['link_rewrite']); $smarty->assign('block_category_mobile', $result); } $smarty->assign('meta_title', Configuration::get('PS_SHOP_NAME')); } public function displayConf() { echo '