├── .github └── workflows │ └── release.yml ├── Block ├── Adminhtml │ └── SelectWidgetBlock.php └── Embed.php ├── Controller └── Adminhtml │ ├── GoToDashboard │ └── Index.php │ ├── RemoveWidget │ └── Index.php │ ├── SaveWidget │ └── Index.php │ ├── SelectWidget │ └── Index.php │ └── StoreWidget │ └── Index.php ├── Helper └── StringUtil.php ├── Model ├── ResourceModel │ ├── Widget.php │ └── Widget │ │ └── Collection.php └── Widget.php ├── README.md ├── Setup ├── InstallSchema.php ├── UpgradeData.php └── UpgradeSchema.php ├── composer.json ├── composer.lock ├── etc ├── acl.xml ├── adminhtml │ ├── menu.xml │ └── routes.xml ├── csp_whitelist.xml └── module.xml ├── registration.php └── view ├── adminhtml ├── layout │ └── widget_selectwidget_index.xml ├── requirejs-config.js ├── templates │ └── selectwidget.phtml └── web │ ├── css │ └── tawk-widget-select.css │ └── js │ └── tawk-widget-select.js └── frontend ├── layout └── default.xml ├── requirejs-config.js ├── templates └── embed.phtml └── web └── js └── tawk-embed.js /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: create-release-artifact 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | create-release-artifact: 9 | name: Creating release artifact 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: checkout 13 | uses: actions/checkout@v2 14 | 15 | - name: build artifact 16 | run: composer run package && mv ./tmp/tawkmagento2.zip tawkmagento2.zip 17 | 18 | - name: upload artifact 19 | uses: actions/upload-release-asset@v1 20 | env: 21 | GITHUB_TOKEN: ${{ github.token }} 22 | with: 23 | upload_url: ${{ github.event.release.upload_url }} 24 | asset_path: ./tawkmagento2.zip 25 | asset_name: tawkmagento2.zip 26 | asset_content_type: application/zip -------------------------------------------------------------------------------- /Block/Adminhtml/SelectWidgetBlock.php: -------------------------------------------------------------------------------- 1 | logger = $context->getLogger(); 65 | $this->modelWidgetFactory = $modelFactory; 66 | $this->request = $context->getRequest(); 67 | } 68 | 69 | /** 70 | * Retrieves current base url 71 | * 72 | * @return string Base url 73 | */ 74 | public function mainurl() 75 | { 76 | $protocol = 'http'; 77 | if ($this->request->isSecure()) { 78 | $protocol = 'https'; 79 | } 80 | return $protocol . "://" . $this->request->getServer('HTTP_HOST'); 81 | } 82 | 83 | /** 84 | * Retrieves list of stores and creates option DOM elements 85 | * 86 | * @return string Option DOM elements 87 | */ 88 | public function getWebSiteoptions() 89 | { 90 | $sdstr = ''; 91 | 92 | $websites = $this->_storeManager->getWebsites(); 93 | foreach ($websites as $website) { 94 | $sdstr .= ''.$website->getName().''; 95 | } 96 | return $sdstr; 97 | } 98 | 99 | /** 100 | * Retrieves iframe url for widget selection. 101 | * 102 | * @return string Iframe Url 103 | */ 104 | public function getIframeUrl() 105 | { 106 | return $this->getBaseUrl().'/generic/widgets' 107 | .'?currentWidgetId=¤tPageId=&transparentBackground=1' 108 | .'&pltf=magento&pltfv=2&parentDomain='.$this->mainurl(); 109 | } 110 | 111 | /** 112 | * Retrieves base tawk.to plugin url. 113 | * 114 | * @return string base tawk.to plugin url. 115 | */ 116 | public function getBaseUrl() 117 | { 118 | return 'https://plugins.tawk.to'; 119 | } 120 | 121 | /** 122 | * Generates list of stores available with their hierarchy 123 | * 124 | * @return array list of stores available 125 | */ 126 | public function getHierarchy() 127 | { 128 | $websites = $this->_storeManager->getWebsites(); 129 | 130 | $h = []; 131 | 132 | $h[] = [ 133 | 'id' => 'global', 134 | 'name' => 'Global', 135 | 'childs' => [], 136 | 'current' => $this->getCurrentValuesFor('global') 137 | ]; 138 | 139 | foreach ($websites as $website) { 140 | $parsed = []; 141 | 142 | $parsed['id'] = $website->getId(); 143 | $parsed['name'] = $website->getName(); 144 | $parsed['childs'] = $this->parseGroups($website->getGroups()); 145 | $parsed['current'] = $this->getCurrentValuesFor($website->getId()); 146 | 147 | $h[] = $parsed; 148 | } 149 | 150 | return $h; 151 | } 152 | 153 | /** 154 | * Retrieves list of widget settings. 155 | * 156 | * @return array list of widget settings 157 | */ 158 | public function getCollection() 159 | { 160 | return $this->modelWidgetFactory->create()->getCollection(); 161 | } 162 | 163 | /** 164 | * Save widget action 165 | */ 166 | public function getFormAction() 167 | { 168 | return $this->getUrl('widget/savewidget', ['_secure' => true]); 169 | } 170 | 171 | /** 172 | * Remove widget action 173 | */ 174 | public function getRemoveUrl() 175 | { 176 | return $this->getUrl('widget/removewidget', ['_secure' => true]); 177 | } 178 | 179 | /** 180 | * Retrieve store widget action 181 | */ 182 | public function getStoreWidget() 183 | { 184 | return $this->getUrl('widget/storewidget', ['_secure' => true]); 185 | } 186 | 187 | /** 188 | * Parses group details and its widget settings. 189 | * 190 | * @param object[] $groups list of groups. 191 | * @return object[] list of groups with parsed details. 192 | */ 193 | private function parseGroups($groups) 194 | { 195 | $return = []; 196 | 197 | foreach ($groups as $group) { 198 | $parsed = []; 199 | 200 | $parsed['id'] = $group->getWebsiteId().'_'.$group->getId(); 201 | $parsed['name'] = $group->getName(); 202 | $parsed['childs'] = $this->parseStores($group->getStores()); 203 | $parsed['current'] = $this->getCurrentValuesFor($parsed['id']); 204 | 205 | $return[] = $parsed; 206 | } 207 | 208 | return $return; 209 | } 210 | 211 | /** 212 | * Parses store details and its widget settings. 213 | * 214 | * @param object[] $stores List of stores. 215 | * @return object[] List of groups with parsed details. 216 | */ 217 | private function parseStores($stores) 218 | { 219 | $return = []; 220 | 221 | foreach ($stores as $store) { 222 | $parsed = []; 223 | 224 | $parsed['id'] = $store->getWebsiteId().'_'.$store->getGroupId().'_'.$store->getId(); 225 | $parsed['name'] = $store->getName(); 226 | $parsed['childs'] = []; 227 | $parsed['current'] = $this->getCurrentValuesFor($parsed['id']); 228 | 229 | $return[] = $parsed; 230 | } 231 | 232 | return $return; 233 | } 234 | 235 | /** 236 | * Retrieves property and widget id for provided store/group id 237 | * 238 | * @param string $id Store/group id. 239 | * @return array { 240 | * pageId: string, 241 | * widgetId: string 242 | * } 243 | */ 244 | private function getCurrentValuesFor($id) 245 | { 246 | $widgets = $this->getCollection(); 247 | 248 | foreach ($widgets as $widget) { 249 | if ($widget->getForStoreId() === $id) { 250 | return [ 251 | 'pageId' => $widget->getPageId(), 252 | 'widgetId' => $widget->getWidgetId() 253 | ]; 254 | } 255 | } 256 | 257 | return []; 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /Block/Embed.php: -------------------------------------------------------------------------------- 1 | modelWidgetFactory = $modelFactory->create(); 87 | $this->storeManager = $context->getStoreManager(); 88 | $this->logger = $context->getLogger(); 89 | $this->model = $this->getWidgetModel(); 90 | $this->request = $context->getRequest(); 91 | $this->modelSessionFactory = $sessionFactory->create(); 92 | } 93 | 94 | /** 95 | * Retrieves embed url. 96 | * 97 | * @return string Embed Url. 98 | */ 99 | public function getEmbedUrl() 100 | { 101 | return 'https://embed.tawk.to'. 102 | '/'.htmlspecialchars($this->model->getPageId()). 103 | '/'.htmlspecialchars($this->model->getWidgetId()); 104 | } 105 | 106 | /** 107 | * Instantiate widget model data object 108 | * 109 | * @return \Magento\Framework\DataObject|null Returns `DataObject` if model is found. Otherwise, returns `null`. 110 | */ 111 | private function getWidgetModel() 112 | { 113 | $store = $this->storeManager->getStore(); 114 | 115 | $storeId = $store->getId(); 116 | $groupId = $store->getGroup()->getId(); 117 | $websiteId = $store->getWebsite()->getId(); 118 | 119 | //order in which we select widget 120 | $ids = [$websiteId.'_'.$groupId.'_'.$storeId, $websiteId.'_'.$groupId, $websiteId, 'global']; 121 | 122 | foreach ($ids as $id) { 123 | $tmpModel = $this->modelWidgetFactory->loadByForStoreId($id); 124 | 125 | if ($tmpModel->hasId()) { 126 | return $tmpModel; 127 | } 128 | } 129 | 130 | return null; 131 | } 132 | 133 | /** 134 | * Retrieves current customer details. 135 | * 136 | * @return array { 137 | * name: string, 138 | * email: string 139 | * } 140 | */ 141 | public function getCurrentCustomerDetails() 142 | { 143 | if ($this->model->getEnableVisitorRecognition() != 1) { 144 | return null; 145 | } 146 | 147 | if (!$this->modelSessionFactory->isLoggedIn()) { 148 | return null; 149 | } 150 | 151 | $customerSession = $this->modelSessionFactory->getCustomer(); 152 | return [ 153 | 'name' => $customerSession->getName(), 154 | 'email' => $customerSession->getEmail() 155 | ]; 156 | } 157 | 158 | /** 159 | * To or to not display the selected widget. 160 | */ 161 | protected function _toHtml() 162 | { 163 | if ($this->model === null) { 164 | return ''; 165 | } 166 | 167 | $alwaysdisplay = $this->model->getAlwaysDisplay(); 168 | $donotdisplay = $this->model->getDoNotDisplay(); 169 | $display = true; 170 | 171 | $httpHost = $this->request->getServer('HTTP_HOST'); 172 | $requestUri = $this->request->getServer('REQUEST_URI'); 173 | $httpsServer = $this->request->getServer('HTTPS'); 174 | $serverProtocol = $this->request->getServer('SERVER_PROTOCOL'); 175 | 176 | if ($alwaysdisplay == 1) { 177 | $display = true; 178 | 179 | $excluded_url_list = $this->model->getExcludeUrl(); 180 | if ($excluded_url_list !== null && strlen($excluded_url_list) > 0) { 181 | $current_url = $httpHost . $requestUri; 182 | $current_url = urldecode($current_url); 183 | 184 | $ssl = !empty($httpsServer) && $httpsServer == 'on'; 185 | $sp = strtolower($serverProtocol); 186 | $protocol = substr($sp, 0, strpos($sp, '/')) . ($ssl ? 's' : ''); 187 | 188 | $current_url = $protocol.'://'.$current_url; 189 | $current_url = strtolower($current_url); 190 | $current_url = trim(strtolower($current_url)); 191 | 192 | $excluded_url_list = preg_split("/,/", $excluded_url_list); 193 | if (UrlPatternMatcher::match($current_url, $excluded_url_list)) { 194 | $display = false; 195 | } 196 | } 197 | } else { 198 | $display = false; 199 | } 200 | 201 | if ($donotdisplay == 1) { 202 | $display = false; 203 | 204 | $included_url_list = $this->model->getIncludeUrl(); 205 | if ($included_url_list !== null && strlen($included_url_list) > 0) { 206 | $current_url = $httpHost . $requestUri; 207 | $current_url = urldecode($current_url); 208 | 209 | $ssl = (!empty($httpsServer) && $httpsServer == 'on'); 210 | $sp = strtolower($serverProtocol); 211 | $protocol = substr($sp, 0, strpos($sp, '/')) . ($ssl ? 's' : ''); 212 | 213 | $current_url = $protocol.'://'.$current_url; 214 | $current_url = strtolower($current_url); 215 | $current_url = trim(strtolower($current_url)); 216 | 217 | $included_url_list = preg_split("/,/", $included_url_list); 218 | if (UrlPatternMatcher::match($current_url, $included_url_list)) { 219 | $display = true; 220 | } 221 | } 222 | } 223 | 224 | if ($display == true) { 225 | return parent::_toHtml(); 226 | } else { 227 | return ''; 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /Controller/Adminhtml/GoToDashboard/Index.php: -------------------------------------------------------------------------------- 1 | _authorization->isAllowed('Tawk_Widget::tawk_go_to_dashboard'); 33 | } 34 | 35 | /** 36 | * Executes a redirect to the tawk.to dashboard 37 | */ 38 | public function execute() 39 | { 40 | $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); 41 | return $resultRedirect->setUrl('https://dashboard.tawk.to/'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Controller/Adminhtml/RemoveWidget/Index.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 82 | $this->logger = $logger; 83 | $this->modelWidgetFactory = $modelFactory->create(); 84 | $this->request = $this->getRequest(); 85 | $this->helper = $helper; 86 | } 87 | 88 | /** 89 | * Removes the store's property, widget, and its visibility options 90 | * 91 | * @return array { 92 | * success: bool 93 | * } 94 | */ 95 | public function execute() 96 | { 97 | $response = $this->resultJsonFactory->create(); 98 | $response->setHeader('Content-type', 'application/json'); 99 | 100 | $storeId = $this->helper->stripTagsandQuotes($this->request->getParam('id')); 101 | if (!$storeId) { 102 | return $response->setData(['success' => false]); 103 | } 104 | 105 | $this->modelWidgetFactory->loadByForStoreId($storeId)->delete(); 106 | 107 | return $response->setData(['success' => true]); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Controller/Adminhtml/SaveWidget/Index.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 82 | $this->logger = $logger; 83 | $this->modelWidgetFactory = $modelFactory->create(); 84 | $this->request = $this->getRequest(); 85 | $this->helper = $helper; 86 | } 87 | 88 | /** 89 | * Saves selected property, widget, and its visibility options. 90 | * 91 | * @return array { 92 | * success: bool 93 | * } 94 | */ 95 | public function execute() 96 | { 97 | $response = $this->resultJsonFactory->create(); 98 | $response->setHeader('Content-type', 'application/json'); 99 | 100 | $pageId = $this->helper->stripTagsandQuotes($this->request->getParam('pageId')); 101 | $widgetId = $this->helper->stripTagsandQuotes($this->request->getParam('widgetId')); 102 | $storeId = $this->helper->stripTagsandQuotes($this->request->getParam('id')); 103 | 104 | if (!$pageId || !$widgetId || !$storeId) { 105 | return $response->setData(['success' => false]); 106 | } 107 | 108 | $alwaysdisplay = filter_var($this->request->getParam('alwaysdisplay'), FILTER_SANITIZE_NUMBER_INT); 109 | $excludeurl = $this->request->getParam('excludeurl'); 110 | $donotdisplay = filter_var($this->request->getParam('donotdisplay'), FILTER_SANITIZE_NUMBER_INT); 111 | $includeurl = $this->request->getParam('includeurl'); 112 | $enableVisitorRecognition = filter_var( 113 | $this->request->getParam('enableVisitorRecognition'), 114 | FILTER_SANITIZE_NUMBER_INT 115 | ); 116 | 117 | $model = $this->modelWidgetFactory->loadByForStoreId($storeId); 118 | 119 | if ($pageId != '-1') { 120 | $model->setPageId($pageId); 121 | } 122 | 123 | if ($widgetId != '-1') { 124 | $model->setWidgetId($widgetId); 125 | } 126 | 127 | $model->setForStoreId($storeId); 128 | 129 | $model->setAlwaysDisplay($alwaysdisplay); 130 | $model->setExcludeUrl($excludeurl); 131 | 132 | $model->setDoNotDisplay($donotdisplay); 133 | $model->setIncludeUrl($includeurl); 134 | 135 | $model->setEnableVisitorRecognition($enableVisitorRecognition); 136 | 137 | $model->save(); 138 | 139 | return $response->setData(['success' => true]); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Controller/Adminhtml/SelectWidget/Index.php: -------------------------------------------------------------------------------- 1 | resultPageFactory = $resultPageFactory; 43 | } 44 | 45 | /** 46 | * Checks current session if authorized to choose widget. 47 | * 48 | * @return boolean Returns `true` if current user is allowed to choose widget. 49 | */ 50 | protected function _isAllowed() 51 | { 52 | return $this->_authorization->isAllowed('Tawk_Widget::tawk_choose_widget'); 53 | } 54 | 55 | /** 56 | * Creates the widget selection page 57 | */ 58 | public function execute() 59 | { 60 | return $this->resultPageFactory->create(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Controller/Adminhtml/StoreWidget/Index.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 82 | $this->logger = $logger; 83 | $this->modelWidgetFactory = $modelWidgetFactory->create(); 84 | $this->request = $this->getRequest(); 85 | $this->helper = $helper; 86 | } 87 | 88 | /** 89 | * Retrieves the store property, widget, and its visibility options. 90 | * 91 | * @return array { 92 | * success: bool, 93 | * pageid: string, 94 | * widgetid: string, 95 | * alwaysdisplay: int, 96 | * excludeurl: string, 97 | * donotdisplay: int, 98 | * includeurl: string, 99 | * enableVisitorRecognition: int 100 | * } 101 | */ 102 | public function execute() 103 | { 104 | $response = $this->resultJsonFactory->create(); 105 | $response->setHeader('Content-type', 'application/json'); 106 | 107 | $storeId = $this->helper->stripTagsandQuotes($this->request->getParam('id')); 108 | if (!$storeId) { 109 | return $response->setData(['success' => false]); 110 | } 111 | 112 | $model = $this->modelWidgetFactory->loadByForStoreId($storeId); 113 | 114 | if (!$model->hasId()) { 115 | $model = $this->modelWidgetFactory; 116 | } 117 | 118 | $pageId = $model->getPageId(); 119 | $widgetId = $model->getWidgetId(); 120 | 121 | $alwaysdisplay = $model->getAlwaysDisplay(); 122 | $excludeurl = $model->getExcludeUrl(); 123 | 124 | $donotdisplay = $model->getDoNotDisplay(); 125 | $includeurl = $model->getIncludeUrl(); 126 | 127 | $enableVisitorRecognition = $model->getEnableVisitorRecognition(); 128 | 129 | return $response->setData([ 130 | 'success' => true, 131 | 'pageid' => $pageId, 132 | 'widgetid' => $widgetId, 133 | 'alwaysdisplay' => $alwaysdisplay, 134 | 'excludeurl' => $excludeurl, 135 | 'donotdisplay' => $donotdisplay, 136 | 'includeurl' => $includeurl, 137 | 'enableVisitorRecognition' => $enableVisitorRecognition 138 | ]); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Helper/StringUtil.php: -------------------------------------------------------------------------------- 1 | _init('tawk_widget', 'id'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Model/ResourceModel/Widget/Collection.php: -------------------------------------------------------------------------------- 1 | _init(WidgetModel::class, Widget::class); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Model/Widget.php: -------------------------------------------------------------------------------- 1 | _init(WidgetResourceModel::class); 32 | } 33 | 34 | /** 35 | * Retrieves widget settings by store id. 36 | * 37 | * @param string $id 38 | * @return array Store widget settings 39 | */ 40 | public function loadByForStoreId($id) 41 | { 42 | return $this->getCollection() 43 | ->addFieldToFilter('for_store_id', $id) 44 | ->getFirstItem(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tawk.to Live Chat 2 | 3 | Free live chat widget for your site 4 | 5 | *** 6 | **Development and releases have been moved to this [fork](https://github.com/tawk/tawk-magento-2-package) because the package has been published on Packagist under a new module name. To maintain support for previous installations, we have decided to archive this repository. Please visit the fork for the latest releases and support.** 7 | *** 8 | 9 | ## Description 10 | 11 | The tawk.to Live Chat app makes it easy to monitor and chat with visitors on your website. Be there when they need you with unlimited messaging, ticketing and your own Knowledge Base — all 100% FREE. 12 | 13 | Compatible with all modern browsers, tawk.to was created in response to the growing need for businesses to respond in real time, with real people. 14 | 15 | Never lose another lead or sale again — tawk.to offers iOS, Android, Windows and Mac OSX apps to keep you connected wherever you go. 16 | 17 | Don’t have a tawk.to account yet? [Create one here.](https://tawk.to/?utm_source=zencart&utm_medium=link&utm_campaign=signup) 18 | 19 | ## Installation 20 | 21 | ### Pre-requisites 22 | - Be sure Composer is installed. You can install it by entering in your website root directory and executing this command: `curl -sS https://getcomposer.org/installer | php` 23 | 24 | ### Standard Installation (Recommended) 25 | 1. Add these repositories to your Composer repositories by executing the following commands: 26 | - `php composer.phar config repositories.tawk-url-utils vcs "https://github.com/tawk/tawk-url-utils.git"` 27 | - `php composer.phar config repositories.tawk vcs "https://github.com/tawk/tawk-magento-2.git"` 28 | 2. Install the extension by executing `php composer.phar require tawk/widget`. 29 | 30 | ### Composer Artifact Installation 31 | 1. Download the latest zip file [here](https://github.com/tawk/tawk-magento-2/releases). 32 | 2. Create a folder in `` called `artifacts`. 33 | 3. Copy the zip file to `/artifacts`. 34 | 4. Add the repositories to your Composer repositories by executing the following commands 35 | - `php composer.phar config repositories.tawk-url-utils vcs "https://github.com/tawk/tawk-url-utils.git"` 36 | - `php composer.phar config repositories.tawk artifact "/artifacts"` 37 | 5. Install the extension by executing `php composer.phar require tawk/widget`. 38 | 39 | ### Manual Installation 40 | 1. Download the latest zip file [here](https://github.com/tawk/tawk-magento-2/releases). 41 | 2. Extract the package. 42 | 3. Copy the contents to `/app/code/Tawk/Widget` folder of your website (create a new folder if necessary). 43 | 4. Add the dependency repository to your Composer repositories by executing `php composer.phar config repositories.tawk-url-utils vcs "https://github.com/tawk/tawk-url-utils.git"`. 44 | 5. Install the dependency `tawk-url-util` by executing `php composer.phar require tawk/url-utils`. 45 | 46 | ## Updating to v1.6.0 47 | For users using previous versions than v1.6.0, there are additional setups that needs to be made before running the `php bin/magento setup:upgrade` command. 48 | 49 | ### Standard Installation 50 | 1. Add this new repository by running `php composer.phar config repositories.tawk-url-utils vcs "https://github.com/tawk/tawk-url-utils.git"`. 51 | 2. Run `php composer.phar require tawk/widget` to update the extension and install the new dependencies. 52 | 3. Then run the following magento commands to upgrade the extension. 53 | ``` 54 | php bin/magento setup:upgrade 55 | php bin/magento setup:static-content:deploy 56 | php bin/magento cache:clean 57 | ``` 58 | 59 | ### Manual Installation 60 | 1. Download the latest zip file [here](https://github.com/tawk/tawk-magento-2/releases). 61 | 2. Extract the package. 62 | 3. Copy the contents to `/app/code/Tawk/Widget` folder of your website (create a new folder if necessary). 63 | 4. Add the dependency repository to your Composer repositories by executing `php composer.phar config repositories.tawk-url-utils vcs "https://github.com/tawk/tawk-url-utils.git"`. 64 | 5. Install the dependency `tawk-url-util` by executing `php composer.phar require tawk/url-utils`. 65 | 3. Then run the following magento commands to upgrade the extension. 66 | ``` 67 | php bin/magento setup:upgrade 68 | php bin/magento setup:static-content:deploy 69 | php bin/magento cache:clean 70 | ``` 71 | 72 | ## Enabling the Extension 73 | Once the extension is installed, you will need to execute the following command lines from your website root directory: 74 | ``` 75 | php bin/magento module:enable Tawk_Widget 76 | php bin/magento setup:upgrade 77 | php bin/magento setup:static-content:deploy 78 | php bin/magento cache:clean 79 | ``` 80 | 81 | ## Widget Configuration 82 | 1. Go to `Dashboard` -> `System` -> `tawk.to widget` -> `Select your widget`. 83 | 2. Log in to your tawk.to account. 84 | 3. Select the property and the widget you want to place on your store and click `Use selected widget`. 85 | 4. The widget will now appear on your store. 86 | 87 | ## Frequently Asked Questions 88 | Visit our [Help Center](https://help.tawk.to/) for answers to FAQs 89 | -------------------------------------------------------------------------------- /Setup/InstallSchema.php: -------------------------------------------------------------------------------- 1 | startSetup(); 37 | 38 | $table = $setup->getConnection()->newTable($setup->getTable('tawk_widget'))->addColumn( 39 | 'id', 40 | Table::TYPE_INTEGER, 41 | 10, 42 | ['identity' => true, 'unsigned' => false, 'nullable' => false, 'primary' => true], 43 | 'Id' 44 | )->addColumn( 45 | 'for_store_id', 46 | Table::TYPE_TEXT, 47 | 50, 48 | [], 49 | 'For store Id' 50 | )->addColumn( 51 | 'page_id', 52 | Table::TYPE_TEXT, 53 | 50, 54 | [], 55 | 'Page Id' 56 | )->addColumn( 57 | 'widget_id', 58 | Table::TYPE_TEXT, 59 | 50, 60 | [], 61 | 'Widget Id' 62 | )->addColumn( 63 | 'always_display', 64 | Table::TYPE_INTEGER, 65 | 1, 66 | [], 67 | 'always_display' 68 | )->addColumn( 69 | 'exclude_url', 70 | Table::TYPE_TEXT, 71 | 255, 72 | [], 73 | 'exclude_url' 74 | )->addColumn( 75 | 'do_not_display', 76 | Table::TYPE_INTEGER, 77 | 1, 78 | [], 79 | 'do_not_display' 80 | )->addColumn( 81 | 'include_url', 82 | Table::TYPE_TEXT, 83 | 255, 84 | [], 85 | 'include_url' 86 | )->addColumn( 87 | 'enable_visitor_recognition', 88 | Table::TYPE_INTEGER, 89 | 1, 90 | [ 91 | 'nullable' => false, 92 | 'default' => 1 93 | ], 94 | 'Enable visitor recognition feature' 95 | )->setComment( 96 | 'Tawk Widget table that makes connection between stores and widgets' 97 | ); 98 | 99 | $setup->getConnection()->createTable($table); 100 | 101 | $setup->endSetup(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Setup/UpgradeData.php: -------------------------------------------------------------------------------- 1 | _modelWidgetFactory = $modelWidgetFactory; 40 | $this->_modelStoreManager = $modelStoreManager; 41 | } 42 | 43 | /** 44 | * Upgrade runner 45 | * 46 | * @param ModuleDataSetupInterface $setup Module Data Setup instance 47 | * @param ModuleContextInterface $context Module Context Setup instance 48 | * @return void 49 | */ 50 | public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) 51 | { 52 | $setup->startSetup(); 53 | $this->versionUpdate160($setup, $context); 54 | $setup->endSetup(); 55 | } 56 | 57 | /** 58 | * Upgrade script for version 1.6.0 59 | * 60 | * Add new records with wildcards that are derived from the existing patterns. 61 | * 62 | * @param [type] $setup 63 | * @param [type] $context 64 | * @return void 65 | */ 66 | private function versionUpdate160($setup, $context) 67 | { 68 | if (version_compare($context->getVersion(), '1.6.0', '<')) { 69 | // get all stores and groups 70 | $collection = $this->_modelWidgetFactory->create()->getCollection(); 71 | 72 | foreach ($collection as $item) { 73 | $storeId = $item->getForStoreId(); 74 | $storeHost = $this->getStoreHost($storeId); 75 | $excludePatternList = $this->addWildcardToPatternList($item->getExcludeUrl(), $storeHost); 76 | $includePatternList = $this->addWildcardToPatternList($item->getIncludeUrl(), $storeHost); 77 | 78 | $item->setExcludeUrl($excludePatternList); 79 | $item->setIncludeUrl($includePatternList); 80 | $item->save(); 81 | } 82 | } 83 | } 84 | 85 | /** 86 | * Retrieves store url host 87 | * 88 | * @param int $storeId Store Id 89 | * @return string Store Url Host 90 | */ 91 | private function getStoreHost($storeId) 92 | { 93 | $storeHost = ''; 94 | 95 | $storeUrl = $this->_modelStoreManager->getStore($storeId)->getBaseUrl(); 96 | //phpcs:ignore Magento2.Functions.DiscouragedFunction.Discouraged 97 | $parsedUrl = parse_url($storeUrl); 98 | 99 | if (!empty($parsedUrl['host'])) { 100 | $storeHost = $parsedUrl['host']; 101 | } 102 | 103 | if (!empty($parsedUrl['port'])) { 104 | $storeHost .= ':' . $parsedUrl['port']; 105 | } 106 | 107 | return $storeHost; 108 | } 109 | 110 | /** 111 | * Processes the pattern list and adds a wildcard at the end of the pattern. 112 | * 113 | * @param string $patternList Pattern list separated with comma. 114 | * @param string $storeHost Store Host. 115 | * @return string Pattern list with wildcards. 116 | */ 117 | private function addWildcardToPatternList($patternList, $storeHost) 118 | { 119 | if (empty($patternList)) { 120 | return ''; 121 | } 122 | $splittedPatternList = preg_split("/,/", (string)$patternList); 123 | $wildcard = PathHelper::get_wildcard(); 124 | 125 | $newPatternList = []; 126 | $addedPatterns = []; 127 | 128 | foreach ($splittedPatternList as $pattern) { 129 | if (empty($pattern)) { 130 | continue; 131 | } 132 | 133 | $pattern = ltrim($pattern, PHP_EOL); 134 | $pattern = trim($pattern); 135 | 136 | if (strpos($pattern, 'http://') !== 0 && 137 | strpos($pattern, 'https://') !== 0 && 138 | strpos($pattern, '/') !== 0 139 | ) { 140 | // Check if the first part of the string is a host. 141 | // If not, add a leading / so that the pattern 142 | // matcher treats is as a path. 143 | $firstPatternChunk = explode('/', $pattern)[0]; 144 | if ($firstPatternChunk !== $storeHost) { 145 | $pattern = '/' . $pattern; 146 | } 147 | } 148 | 149 | $newPatternList[] = $pattern; 150 | $newPattern = $pattern . '/' . $wildcard; 151 | if (in_array($newPattern, $splittedPatternList, true)) { 152 | continue; 153 | } 154 | 155 | if (true === isset($addedPatterns[$newPattern])) { 156 | continue; 157 | } 158 | 159 | $newPatternList[] = $newPattern; 160 | $addedPatterns[$newPattern] = true; 161 | } 162 | 163 | // EOL for display purposes 164 | return join(',' . PHP_EOL, $newPatternList); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /Setup/UpgradeSchema.php: -------------------------------------------------------------------------------- 1 | startSetup(); 44 | $this->versionUpdate150($setup, $context); 45 | 46 | $setup->endSetup(); 47 | } 48 | 49 | /** 50 | * Upgrade script for version 1.5.0 51 | * 52 | * Adds Enable Visitor Recognition field. 53 | * 54 | * @param [type] $setup 55 | * @param [type] $context 56 | * @return void 57 | */ 58 | private function versionUpdate150($setup, $context) 59 | { 60 | if (version_compare($context->getVersion(), '1.5.0', '<')) { 61 | $setup->getConnection()->addColumn( 62 | $setup->getTable('tawk_widget'), 63 | 'enable_visitor_recognition', 64 | [ 65 | 'type' => Table::TYPE_INTEGER, 66 | 'length' => 1, 67 | 'nullable' => false, 68 | 'default' => 1, 69 | 'comment' => 'Enable visitor recognition feature' 70 | ] 71 | ); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tawk/widget", 3 | "description": "tawk.to - free live chat software for your website", 4 | "type": "magento2-module", 5 | "keywords": [ 6 | "magento 2", 7 | "tawk", 8 | "tawkto", 9 | "live chat", 10 | "messaging", 11 | "b2c communication tool", 12 | "support tool", 13 | "helpdesk", 14 | "agents" 15 | ], 16 | "homepage": "https://www.tawk.to/", 17 | "support": { 18 | "email": "support@tawk.to", 19 | "issues": "https://github.com/tawk/tawk-magento-2/issues" 20 | }, 21 | "version": "1.6.1", 22 | "license": [ 23 | "OSL-3.0" 24 | ], 25 | "require": { 26 | "php": ">=5.6.0", 27 | "tawk/url-utils": "^2.0" 28 | }, 29 | "autoload": { 30 | "files": [ 31 | "registration.php" 32 | ], 33 | "psr-4": { 34 | "Tawk\\Widget\\": "" 35 | } 36 | }, 37 | "require-dev": { 38 | "squizlabs/php_codesniffer": "^3.6", 39 | "magento/magento-coding-standard": "^17.0", 40 | "phpcompatibility/php-compatibility": "^9.3", 41 | "magento/framework": "^103.0", 42 | "magento/module-backend": "^102.0", 43 | "magento/module-customer": "^103.0" 44 | }, 45 | "scripts": { 46 | "post-install-cmd": [ 47 | "([ $COMPOSER_DEV_MODE -eq 0 ] || vendor/bin/phpcs --config-set installed_paths vendor/magento/magento-coding-standard/,vendor/phpcompatibility/php-compatibility)" 48 | ], 49 | "post-update-cmd": [ 50 | "([ $COMPOSER_DEV_MODE -eq 0 ] || vendor/bin/phpcs --config-set installed_paths vendor/magento/magento-coding-standard/,vendor/phpcompatibility/php-compatibility)" 51 | ], 52 | "build:dev": "composer install", 53 | "build:prod": "composer install --no-dev", 54 | "lint": "phpcs -p -s -v --runtime-set ignore_warnings_on_exit true .", 55 | "lint:fix": "phpcbf -p -s -v .; err=$?; if [ $err -eq 1 ]; then exit 0; else exit $err; fi;", 56 | "package": "composer run clean && mkdir -p ./tmp/tawkmagento2 && cp -r ./view ./tmp/tawkmagento2 && cp -r ./etc ./tmp/tawkmagento2 && cp -r ./Setup ./tmp/tawkmagento2 && cp -r ./Model ./tmp/tawkmagento2 && cp -r ./Controller ./tmp/tawkmagento2 && cp -r ./Block ./tmp/tawkmagento2 && cp -r ./Helper ./tmp/tawkmagento2 && cp ./registration.php ./tmp/tawkmagento2 && cp ./composer.json ./tmp/tawkmagento2 && cp README.md ./tmp/tawkmagento2 && (cd ./tmp && zip -9 -rq ./tawkmagento2.zip ./tawkmagento2)", 57 | "clean": "rm -rf ./tmp" 58 | }, 59 | "repositories": { 60 | "magento": { 61 | "type": "composer", 62 | "url": "https://repo.magento.com/" 63 | }, 64 | "tawk-url-utils": { 65 | "type": "vcs", 66 | "url": "https://github.com/tawk/tawk-url-utils.git" 67 | } 68 | }, 69 | "config": { 70 | "allow-plugins": { 71 | "magento/composer-dependency-version-audit-plugin": true 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /etc/csp_whitelist.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | *.tawk.to 26 | fonts.googleapis.com 27 | cdn.jsdelivr.net 28 | 29 | 30 | 31 | 32 | *.tawk.to 33 | cdn.jsdelivr.net 34 | 35 | 36 | 37 | 38 | *.tawk.to 39 | 40 | 41 | 42 | 43 | *.tawk.to 44 | fonts.gstatic.com 45 | 46 | 47 | 48 | 49 | *.tawk.to 50 | tawk.link 51 | cdn.jsdelivr.net 52 | s3.amazonaws.com/ 53 | 54 | 55 | 56 | 57 | *.tawk.to 58 | tawk.link 59 | 60 | 61 | 62 | 63 | *.tawk.to 64 | wss://*.tawk.to 65 | 66 | 67 | 68 | 69 | *.tawk.to 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | 26 | Select your widget 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /view/adminhtml/requirejs-config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | map: { 3 | '*': { 4 | 'tawk-widget-select': 'Tawk_Widget/js/tawk-widget-select' 5 | } 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /view/adminhtml/templates/selectwidget.phtml: -------------------------------------------------------------------------------- 1 | 19 | 35 | 36 | Select Store 37 | 38 | = /* @noEscape */ $block->getWebSiteoptions(); ?> 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | Visibility Options 50 | 51 | Always Display widget 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | (Exception) hide tawk.to widget to the following URLs or paths. Separate each entry with a comma(,). 60 | 61 | 62 | Examples of accepted patterns 63 | 64 | * 65 | */to/somewhere 66 | /*/to/somewhere 67 | /path/*/somewhere 68 | /path/*/lead/*/somewhere 69 | /path/*/*/somewhere 70 | /path/to/* 71 | /path/to/*/ 72 | */to/*/page 73 | /*/to/*/page 74 | /path/*/other/* 75 | /path/*/other/*/ 76 | http://www.example.com/ 77 | http://www.example.com/* 78 | http://www.example.com/*/to/somewhere 79 | http://www.example.com/path/*/somewhere 80 | http://www.example.com/path/*/lead/*/somewhere 81 | http://www.example.com/path/*/*/somewhere 82 | http://www.example.com/path/to/* 83 | http://www.example.com/path/to/*/ 84 | http://www.example.com/*/to/*/page 85 | http://www.example.com/path/*/other/* 86 | http://www.example.com/path/*/other/*/ 87 | 88 | 89 | 90 | 91 | 92 | 93 | Do not Display widget 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | (Exception) display tawk.to widget to the following URLs or paths. Separate each entry with a comma(,). 102 | 103 | 104 | Examples of accepted patterns 105 | 106 | * 107 | */to/somewhere 108 | /*/to/somewhere 109 | /path/*/somewhere 110 | /path/*/lead/*/somewhere 111 | /path/*/*/somewhere 112 | /path/to/* 113 | /path/to/*/ 114 | */to/*/page 115 | /*/to/*/page 116 | /path/*/other/* 117 | /path/*/other/*/ 118 | http://www.example.com/ 119 | http://www.example.com/* 120 | http://www.example.com/*/to/somewhere 121 | http://www.example.com/path/*/somewhere 122 | http://www.example.com/path/*/lead/*/somewhere 123 | http://www.example.com/path/*/*/somewhere 124 | http://www.example.com/path/to/* 125 | http://www.example.com/path/to/*/ 126 | http://www.example.com/*/to/*/page 127 | http://www.example.com/path/*/other/* 128 | http://www.example.com/path/*/other/*/ 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | Privacy Options 140 | 141 | Enable Visitor Recognition 142 | 143 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | Save Settings 152 | 153 | 154 | -------------------------------------------------------------------------------- /view/adminhtml/web/css/tawk-widget-select.css: -------------------------------------------------------------------------------- 1 | .websiteids:focus { 2 | box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset, 0 0 8px rgba(102, 175, 233, .6); 3 | border-color: #66afe9; 4 | outline: 0 none; 5 | } 6 | 7 | .websiteids { 8 | width: 350px; 9 | background-color: #fff; 10 | background-image: none; 11 | border: 1px solid #ccc; 12 | border-radius: 4px; 13 | box-shadow: 0 1px 1px rgba(0, 0, 0, .075) inset; 14 | color: #555; 15 | font-size: 14px; 16 | height: 34px; 17 | line-height: 1.42857; 18 | padding: 6px 12px; 19 | transition: border-color .15s ease-in-out 0s, box-shadow .15s ease-in-out 0s; 20 | 21 | } 22 | 23 | .websiteids-label { 24 | display: inline-block; 25 | font-size: 15px; 26 | font-weight: bold; 27 | width: 200px; 28 | } 29 | 30 | .tawk-fields { 31 | margin: 15px 0; 32 | } 33 | 34 | .switch { 35 | position: relative; 36 | display: inline-block; 37 | width: 60px; 38 | height: 34px; 39 | } 40 | 41 | /* Hide default HTML checkbox */ 42 | .switch input { 43 | display: none; 44 | } 45 | 46 | /* The slider */ 47 | .slider { 48 | position: absolute; 49 | cursor: pointer; 50 | top: 0; 51 | left: 0; 52 | right: 0; 53 | bottom: 0; 54 | background-color: #ccc; 55 | -webkit-transition: .4s; 56 | transition: .4s; 57 | } 58 | 59 | .slider:before { 60 | position: absolute; 61 | content: ''; 62 | height: 26px; 63 | width: 26px; 64 | left: 4px; 65 | bottom: 4px; 66 | background-color: white; 67 | -webkit-transition: .4s; 68 | transition: .4s; 69 | } 70 | 71 | input:checked + .slider { 72 | background-color: #2196f3; 73 | } 74 | 75 | input:focus + .slider { 76 | box-shadow: 0 0 1px #2196f3; 77 | } 78 | 79 | input:checked + .slider:before { 80 | -webkit-transform: translateX(26px); 81 | -ms-transform: translateX(26px); 82 | transform: translateX(26px); 83 | } 84 | 85 | /* Rounded sliders */ 86 | .slider.round { 87 | border-radius: 34px; 88 | } 89 | 90 | .slider.round:before { 91 | border-radius: 50%; 92 | } 93 | 94 | .savesettingsbtn { 95 | background-color: #5cb85c; 96 | border-color: #4cae4c; 97 | color: #fff; 98 | -moz-user-select: none; 99 | user-select: none; 100 | background-image: none; 101 | border: 1px solid transparent; 102 | border-radius: 4px; 103 | cursor: pointer; 104 | display: inline-block; 105 | font-size: 14px; 106 | font-weight: normal; 107 | line-height: 1.42857; 108 | margin-bottom: 0; 109 | padding: 6px 12px; 110 | text-align: center; 111 | vertical-align: middle; 112 | white-space: nowrap; 113 | text-decoration: none; 114 | } 115 | 116 | .savesettingsbtn:hover { 117 | text-decoration: none; 118 | color: #fff; 119 | } 120 | 121 | /* Tooltip */ 122 | .tawk-tooltip { 123 | position: relative; 124 | display: inline; 125 | color: #03a84e; 126 | } 127 | 128 | .tawk-tooltip .tawk-tooltiptext { 129 | visibility: hidden; 130 | background-color: #545454; 131 | color: #fff; 132 | text-align: center; 133 | padding: .5rem; 134 | max-width: 300px; 135 | border-radius: .5rem; 136 | font-size: 1rem; 137 | font-weight: 600; 138 | line-height: 1.2; 139 | position: absolute; 140 | z-index: 1000; 141 | left: 0; 142 | } 143 | 144 | .tawk-tooltip .tawk-tooltiptext::before { 145 | content: ''; 146 | display: block; 147 | width: 0; 148 | height: 0; 149 | position: absolute; 150 | 151 | border-left: 5px solid transparent; 152 | border-right: 5px solid transparent; 153 | border-bottom: 5px solid #545454; 154 | top: -5px; 155 | left: 5px; 156 | } 157 | 158 | .tawk-tooltip:hover .tawk-tooltiptext { 159 | visibility: visible; 160 | } 161 | -------------------------------------------------------------------------------- /view/adminhtml/web/js/tawk-widget-select.js: -------------------------------------------------------------------------------- 1 | define(['jquery', 'jquery/ui'], function ($) { 2 | 'use strict'; 3 | 4 | $.noConflict(); 5 | 6 | return function (config) { 7 | var domain = config.domain, 8 | baseUrl = config.baseUrl, 9 | removeWidgetUrl = config.removeWidgetUrl, 10 | storedWidgetUrl = config.storedWidgetUrl, 11 | formAction = config.form.action, 12 | formKey = config.form.key; 13 | 14 | function displayWidget(websiteId) { 15 | jQuery.get(storedWidgetUrl + '?id=' + websiteId, function (response) { 16 | var src = baseUrl + '/generic/widgets?'; 17 | 18 | if (response.widgetid) { 19 | src = src + '¤tWidgetId=' + response.widgetid; 20 | } 21 | if (response.pageid) { 22 | src = src + '¤tPageId=' + response.pageid; 23 | } 24 | src = src + '&transparentBackground=1&pltf=magento&pltfv=2&parentDomain=' + domain; 25 | document.getElementById('tawk_widget_customization').src = src; 26 | 27 | jQuery('#excludeurl').val(response.excludeurl); 28 | jQuery('#includeurl').val(response.includeurl); 29 | if (response.alwaysdisplay === '1') { 30 | jQuery('#alwaysdisplay').prop('checked', true); 31 | jQuery('#exlucded_urls_container').show(); 32 | } else { 33 | jQuery('#alwaysdisplay').prop('checked', false); 34 | jQuery('#exlucded_urls_container').hide(); 35 | } 36 | 37 | if (response.donotdisplay === '1') { 38 | jQuery('#donotdisplay').prop('checked', true); 39 | jQuery('#included_urls_container').show(); 40 | } else { 41 | jQuery('#donotdisplay').prop('checked', false); 42 | jQuery('#included_urls_container').hide(); 43 | } 44 | 45 | jQuery('#enable_visitor_recognition').prop('checked', response.enableVisitorRecognition === '1'); 46 | }); 47 | } 48 | 49 | function setWidget(e) { 50 | var alwaysdisplay = jQuery('#alwaysdisplay').is(':checked'), 51 | alwaysdisplayvalue = alwaysdisplay ? 1 : 0, 52 | 53 | donotdisplay = jQuery('#donotdisplay').is(':checked'), 54 | donotdisplayvalue = donotdisplay ? 1 : 0; 55 | 56 | jQuery.post(formAction, { 57 | pageId : e.data.pageId, 58 | widgetId : e.data.widgetId, 59 | id : jQuery('#websiteids').val(), 60 | excludeurl : jQuery('#excludeurl').val(), 61 | includeurl : jQuery('#includeurl').val(), 62 | alwaysdisplay : alwaysdisplayvalue, 63 | donotdisplay: donotdisplayvalue, 64 | enableVisitorRecognition : jQuery('#enable_visitor_recognition').is(':checked') ? 1 : 0, 65 | form_key : formKey 66 | }, function () { 67 | e.source.postMessage({action : 'setDone'}, baseUrl); 68 | }); 69 | } 70 | 71 | function removeWidget(e) { 72 | jQuery.get(removeWidgetUrl + '?id=' + jQuery('#websiteids').val(), function () { 73 | e.source.postMessage({action : 'removeDone'}, baseUrl); 74 | }); 75 | } 76 | 77 | function saveVisibilityOptions(e) { 78 | var alwaysdisplay = jQuery('#alwaysdisplay').is(':checked'), 79 | alwaysdisplayvalue = alwaysdisplay ? 1 : 0, 80 | donotdisplay = jQuery('#donotdisplay').is(':checked'), 81 | donotdisplayvalue = donotdisplay ? 1 : 0; 82 | 83 | e.preventDefault(); 84 | 85 | jQuery.post(formAction, { 86 | pageId : '-1', 87 | widgetId : '-1', 88 | id : jQuery('#websiteids').val(), 89 | excludeurl : jQuery('#excludeurl').val(), 90 | includeurl : jQuery('#includeurl').val(), 91 | alwaysdisplay : alwaysdisplayvalue, 92 | donotdisplay: donotdisplayvalue, 93 | enableVisitorRecognition : jQuery('#enable_visitor_recognition').is(':checked') ? 1 : 0, 94 | form_key : formKey 95 | }, function () { 96 | /* TODO: convert this to a different type of alert that doesn't use the browser alert func */ 97 | /* eslint-disable-next-line no-alert */ 98 | alert('Visibility options Saved'); 99 | }); 100 | } 101 | 102 | function reloadIframeHeight(height) { 103 | var iframe = jQuery('#tawkIframe'); 104 | 105 | if (!height) { 106 | return; 107 | } 108 | 109 | if (height === iframe.height()) { 110 | return; 111 | } 112 | 113 | iframe.height(height); 114 | } 115 | 116 | jQuery(function () { 117 | displayWidget(jQuery('#websiteids').val()); 118 | 119 | if (jQuery('#alwaysdisplay').prop('checked')) { 120 | jQuery('#exlucded_urls_container').show(); 121 | } else { 122 | jQuery('#exlucded_urls_container').hide(); 123 | } 124 | 125 | if (jQuery('#donotdisplay').prop('checked')) { 126 | jQuery('#included_urls_container').show(); 127 | } else { 128 | jQuery('#included_urls_container').hide(); 129 | } 130 | 131 | window.addEventListener('message', function (e) { 132 | if (e.origin === baseUrl) { 133 | if (e.data.action === 'setWidget') { 134 | setWidget(e); 135 | } 136 | if (e.data.action === 'removeWidget') { 137 | removeWidget(e); 138 | } 139 | if (e.data.action === 'reloadHeight') { 140 | reloadIframeHeight(e.data.height); 141 | } 142 | } 143 | }); 144 | 145 | jQuery('.savesettingsbtn').click(saveVisibilityOptions); 146 | 147 | jQuery('#websiteids').on('change', function () { 148 | if (this.value === 0) { 149 | document.getElementById('tawk_widget_customization').src = ''; 150 | jQuery('#visibility_options').hide(); 151 | } else { 152 | displayWidget(this.value); 153 | jQuery('#visibility_options').show(); 154 | } 155 | }); 156 | 157 | jQuery('#alwaysdisplay').change(function () { 158 | if (this.checked) { 159 | jQuery('#exlucded_urls_container').show(); 160 | jQuery('#donotdisplay').prop('checked', false); 161 | jQuery('#included_urls_container').hide(); 162 | } else { 163 | jQuery('#exlucded_urls_container').hide(); 164 | jQuery('#donotdisplay').prop('checked', true); 165 | jQuery('#included_urls_container').show(); 166 | } 167 | }); 168 | 169 | jQuery('#donotdisplay').change(function () { 170 | if (this.checked) { 171 | jQuery('#included_urls_container').show(); 172 | jQuery('#alwaysdisplay').prop('checked', false); 173 | jQuery('#exlucded_urls_container').hide(); 174 | } else { 175 | jQuery('#included_urls_container').hide(); 176 | jQuery('#alwaysdisplay').prop('checked', true); 177 | jQuery('#exlucded_urls_container').show(); 178 | } 179 | }); 180 | }); 181 | }; 182 | }); 183 | -------------------------------------------------------------------------------- /view/frontend/layout/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /view/frontend/requirejs-config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | map: { 3 | '*': { 4 | 'tawk-embed': 'Tawk_Widget/js/tawk-embed' 5 | } 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /view/frontend/templates/embed.phtml: -------------------------------------------------------------------------------- 1 | 19 | 20 | getCurrentCustomerDetails(); ?> 21 | 44 | -------------------------------------------------------------------------------- /view/frontend/web/js/tawk-embed.js: -------------------------------------------------------------------------------- 1 | define([], function () { 2 | 'use strict'; 3 | 4 | return function (config) { 5 | var visitor = config.visitor, 6 | embedUrl = config.embedUrl, 7 | /* eslint-disable-next-line no-unused-vars */ 8 | Tawk_LoadStart = new Date(); 9 | 10 | window.Tawk_API = window.Tawk_API || {}; 11 | 12 | if (visitor) { 13 | window.Tawk_API.visitor = { 14 | name : visitor.name, 15 | email : visitor.email 16 | }; 17 | } 18 | 19 | (function () { 20 | var s1 = document.createElement('script'),s0 = document.getElementsByTagName('script')[0]; 21 | 22 | s1.async = true; 23 | s1.src = embedUrl; 24 | s1.charset = 'UTF-8'; 25 | s1.setAttribute('crossorigin','*'); 26 | s0.parentNode.insertBefore(s1,s0); 27 | })(); 28 | }; 29 | }); 30 | 31 | --------------------------------------------------------------------------------