Tidio Live Chat - Version 5.0.0

Version Description

  • New integration flow based on OAuth
Download this release

Release Info

Developer kkopaczyktidio
Plugin Icon 128x128 Tidio Live Chat
Version 5.0.0
Comparing to
See all releases

Code changes from version 4.5.1 to 5.0.0

Files changed (62) hide show
  1. TidioDotEnv.php +5 -6
  2. config.php +1 -1
  3. languages/js/.gitkeep +0 -0
  4. languages/js/tidio-live-chat-es_ES-tidio-chat-admin.json +0 -45
  5. languages/js/tidio-live-chat-es_MX-tidio-chat-admin.json +0 -45
  6. languages/js/tidio-live-chat-fr_BE-tidio-chat-admin.json +0 -45
  7. languages/js/tidio-live-chat-fr_CA-tidio-chat-admin.json +0 -45
  8. languages/js/tidio-live-chat-fr_FR-tidio-chat-admin.json +0 -45
  9. languages/js/tidio-live-chat-pl_PL-tidio-chat-admin.json +0 -45
  10. languages/js/tidio-live-chat-ru_RU-tidio-chat-admin.json +0 -45
  11. languages/tidio-live-chat-es_ES.mo +0 -0
  12. languages/tidio-live-chat-es_MX.mo +0 -0
  13. languages/tidio-live-chat-fr_BE.mo +0 -0
  14. languages/tidio-live-chat-fr_CA.mo +0 -0
  15. languages/tidio-live-chat-fr_FR.mo +0 -0
  16. languages/tidio-live-chat-pl_PL.mo +0 -0
  17. languages/tidio-live-chat-ru_RU.mo +0 -0
  18. media/css/options.css +0 -393
  19. media/img/16.svg +0 -3
  20. media/img/27.svg +0 -3
  21. media/img/28.svg +0 -3
  22. media/img/29.svg +0 -3
  23. media/img/34.svg +0 -3
  24. media/img/4.svg +0 -3
  25. media/img/8.svg +0 -3
  26. media/img/a-center.png +0 -0
  27. media/img/ajax-loader.gif +0 -0
  28. media/img/chevron.svg +0 -4
  29. media/img/plus.svg +0 -3
  30. media/img/tidio-logo.svg +0 -8
  31. media/img/wp-logo.svg +0 -7
  32. media/js/options.js +0 -341
  33. options.php +0 -61
  34. readme.txt +24 -7
  35. src/Admin/TidioAdminActionLink.php +84 -0
  36. src/Admin/TidioAdminController.php +104 -0
  37. src/Admin/TidioAdminDashboard.php +51 -0
  38. src/Admin/TidioAdminNotice.php +30 -0
  39. src/Admin/TidioAdminRouting.php +55 -0
  40. src/Admin/TidioIframeSetup.php +99 -0
  41. src/Sdk/Api/Client/CurlTidioApiClient.php +108 -0
  42. src/Sdk/Api/Client/FileGetContentsTidioApiClient.php +137 -0
  43. src/Sdk/Api/Client/TidioApiClientFactory.php +30 -0
  44. src/Sdk/Api/Exception/TidioApiException.php +32 -0
  45. src/Sdk/Api/TidioApiClient.php +19 -0
  46. src/Sdk/Encryption/Exception/TidioDecryptionFailedException.php +14 -0
  47. src/Sdk/Encryption/Service/OpenSslTidioEncryptionService.php +54 -0
  48. src/Sdk/Encryption/Service/PlainTextTidioEncryptionService.php +20 -0
  49. src/Sdk/Encryption/Service/TidioEncryptionServiceFactory.php +26 -0
  50. src/Sdk/Encryption/TidioEncryptionService.php +17 -0
  51. src/Sdk/TidioIntegrationFacade.php +43 -0
  52. src/TidioIntegrationState.php +92 -0
  53. src/TidioLiveChat.php +30 -0
  54. src/TidioLiveChatConfig.php +45 -0
  55. src/Translation/TidioErrorTranslator.php +15 -0
  56. src/Translation/TidioTranslationLoader.php +28 -0
  57. src/Translation/i18n.php +20 -0
  58. src/Utils/QueryParameters.php +26 -0
  59. src/Widget/TidioWidgetLoader.php +70 -0
  60. tidio-elements.php +38 -462
  61. views/ajax-tidio-chat-redirect.php +0 -55
  62. views/iframe.php +6 -0
TidioDotEnv.php CHANGED
@@ -9,6 +9,9 @@ class TidioDotEnv
9
  */
10
  private $envDirectoryPath;
11
 
 
 
 
12
  public function __construct($envDirectoryPath)
13
  {
14
  if (!is_dir($envDirectoryPath)) {
@@ -18,9 +21,6 @@ class TidioDotEnv
18
  $this->envDirectoryPath = $envDirectoryPath;
19
  }
20
 
21
- /**
22
- * @return void
23
- */
24
  public function load()
25
  {
26
  $file = sprintf('%s/%s', $this->envDirectoryPath, self::ENV_FILENAME);
@@ -38,7 +38,7 @@ class TidioDotEnv
38
 
39
  /**
40
  * @param string $file
41
- * @return array
42
  */
43
  private function parseEnvFile($file)
44
  {
@@ -57,8 +57,7 @@ class TidioDotEnv
57
  }
58
 
59
  /**
60
- * @param array $envs
61
- * @return void
62
  */
63
  private function setEnvs($envs)
64
  {
9
  */
10
  private $envDirectoryPath;
11
 
12
+ /**
13
+ * @param string $envDirectoryPath
14
+ */
15
  public function __construct($envDirectoryPath)
16
  {
17
  if (!is_dir($envDirectoryPath)) {
21
  $this->envDirectoryPath = $envDirectoryPath;
22
  }
23
 
 
 
 
24
  public function load()
25
  {
26
  $file = sprintf('%s/%s', $this->envDirectoryPath, self::ENV_FILENAME);
38
 
39
  /**
40
  * @param string $file
41
+ * @return array<string, string>
42
  */
43
  private function parseEnvFile($file)
44
  {
57
  }
58
 
59
  /**
60
+ * @param array<string, string> $envs
 
61
  */
62
  private function setEnvs($envs)
63
  {
config.php CHANGED
@@ -6,6 +6,6 @@ require_once __DIR__ . '/TidioDotEnv.php';
6
 
7
  return [
8
  'tidio_api_url' => getenv('TIDIO_API_URL') ?: 'https://api-v2.tidio.co',
9
- 'tidio_panel_url' => getenv('TIDIO_PANEL_URL') ?: 'https://www.tidio.com',
10
  'tidio_widget_url' => getenv('TIDIO_WIDGET_URL') ?: '//code.tidio.co',
11
  ];
6
 
7
  return [
8
  'tidio_api_url' => getenv('TIDIO_API_URL') ?: 'https://api-v2.tidio.co',
9
+ 'tidio_panel_url' => getenv('TIDIO_PANEL_URL') ?: 'https://www.tidio.com/panel',
10
  'tidio_widget_url' => getenv('TIDIO_WIDGET_URL') ?: '//code.tidio.co',
11
  ];
languages/js/.gitkeep DELETED
File without changes
languages/js/tidio-live-chat-es_ES-tidio-chat-admin.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "domain": "tidio-live-chat",
3
- "locale_data": {
4
- "tidio-live-chat": {
5
- "": {
6
- "domain": "tidio-live-chat",
7
- "plural_forms": "nplurals=2; plural=(n != 1);",
8
- "lang": "es"
9
- },
10
- "Loading...": [
11
- "Cargando..."
12
- ],
13
- "Can’t be empty!": [
14
- "¡No puede dejarse en blanco!"
15
- ],
16
- "Email can’t be empty!": [
17
- "¡El email no puede dejarse en blanco!"
18
- ],
19
- "Email is invalid!": [
20
- "¡El email no es válido!"
21
- ],
22
- "Start using Tidio": [
23
- "Comienza a usar Tidio"
24
- ],
25
- "Something went wrong.": [
26
- "Algo ha salido mal."
27
- ],
28
- "You have been blocked for too many attempts. Please try again in an hour.": [
29
- "Como ha habido demasiados intentos, se te ha bloqueado. Vuelve a intentarlo en una hora."
30
- ],
31
- "Password can’t be empty!": [
32
- "¡La contraseña no puede dejarse en blanco!"
33
- ],
34
- "Wrong email or password": [
35
- "Email o contraseña no válidos"
36
- ],
37
- "Go to Tidio panel": [
38
- "Ir al panel de Tidio"
39
- ],
40
- "Error occured while creating, please try again!": [
41
- "Se ha producido un error durante la creación, ¡vuelve a intentarlo!"
42
- ]
43
- }
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/js/tidio-live-chat-es_MX-tidio-chat-admin.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "domain": "tidio-live-chat",
3
- "locale_data": {
4
- "tidio-live-chat": {
5
- "": {
6
- "domain": "tidio-live-chat",
7
- "plural_forms": "nplurals=2; plural=(n != 1);",
8
- "lang": "es_MX"
9
- },
10
- "Loading...": [
11
- "Cargando..."
12
- ],
13
- "Can’t be empty!": [
14
- "No puede quedar en blanco."
15
- ],
16
- "Email can’t be empty!": [
17
- "El email no puede quedar en blanco."
18
- ],
19
- "Email is invalid!": [
20
- "El email no es válido."
21
- ],
22
- "Start using Tidio": [
23
- "Comienza a usar Tidio"
24
- ],
25
- "Something went wrong.": [
26
- "Algo salió mal."
27
- ],
28
- "You have been blocked for too many attempts. Please try again in an hour.": [
29
- "Como hubo demasiados intentos, fuiste bloqueado. Vuelve a intentar en una hora."
30
- ],
31
- "Password can’t be empty!": [
32
- "La contraseña no puede quedar en blanco."
33
- ],
34
- "Wrong email or password": [
35
- "Email o contraseña no válidos"
36
- ],
37
- "Go to Tidio panel": [
38
- "Ir al panel de Tidio"
39
- ],
40
- "Error occured while creating, please try again!": [
41
- "Ocurrió un error durante la creación, ¡vuelve a intentarlo!"
42
- ]
43
- }
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/js/tidio-live-chat-fr_BE-tidio-chat-admin.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "domain": "tidio-live-chat",
3
- "locale_data": {
4
- "tidio-live-chat": {
5
- "": {
6
- "domain": "tidio-live-chat",
7
- "plural_forms": "nplurals=2; plural=(n > 1);",
8
- "lang": "fr"
9
- },
10
- "Loading...": [
11
- "Chargement..."
12
- ],
13
- "Can’t be empty!": [
14
- "Ce champ ne peut pas être vide !"
15
- ],
16
- "Email can’t be empty!": [
17
- "L'e-mail ne peut pas être vide !"
18
- ],
19
- "Email is invalid!": [
20
- "L'adresse e-mail est invalide !"
21
- ],
22
- "Start using Tidio": [
23
- "Commencez à utiliser Tidio"
24
- ],
25
- "Something went wrong.": [
26
- "Une erreur s'est produite."
27
- ],
28
- "You have been blocked for too many attempts. Please try again in an hour.": [
29
- "Vous avez été bloqué en raison d'un nombre trop élevé de tentatives. Veuillez réessayer dans une heure"
30
- ],
31
- "Password can’t be empty!": [
32
- "Le mot de passe ne peut pas être vide !"
33
- ],
34
- "Wrong email or password": [
35
- "Adresse e-mail ou mot de passe erroné"
36
- ],
37
- "Go to Tidio panel": [
38
- "Accéder au panneau Tidio"
39
- ],
40
- "Error occured while creating, please try again!": [
41
- "Une erreur s'est produite lors de la création, veuillez réessayer !"
42
- ]
43
- }
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/js/tidio-live-chat-fr_CA-tidio-chat-admin.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "domain": "tidio-live-chat",
3
- "locale_data": {
4
- "tidio-live-chat": {
5
- "": {
6
- "domain": "tidio-live-chat",
7
- "plural_forms": "nplurals=2; plural=(n > 1);",
8
- "lang": "fr"
9
- },
10
- "Loading...": [
11
- "Chargement..."
12
- ],
13
- "Can’t be empty!": [
14
- "Ce champ ne peut pas être vide !"
15
- ],
16
- "Email can’t be empty!": [
17
- "L'e-mail ne peut pas être vide !"
18
- ],
19
- "Email is invalid!": [
20
- "L'adresse e-mail est invalide !"
21
- ],
22
- "Start using Tidio": [
23
- "Commencez à utiliser Tidio"
24
- ],
25
- "Something went wrong.": [
26
- "Une erreur s'est produite."
27
- ],
28
- "You have been blocked for too many attempts. Please try again in an hour.": [
29
- "Vous avez été bloqué en raison d'un nombre trop élevé de tentatives. Veuillez réessayer dans une heure."
30
- ],
31
- "Password can’t be empty!": [
32
- "Le mot de passe ne peut pas être vide !"
33
- ],
34
- "Wrong email or password": [
35
- "Adresse e-mail ou mot de passe erroné"
36
- ],
37
- "Go to Tidio panel": [
38
- "Accéder au panneau Tidio"
39
- ],
40
- "Error occured while creating, please try again!": [
41
- "Une erreur s'est produite lors de la création, veuillez réessayer !"
42
- ]
43
- }
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/js/tidio-live-chat-fr_FR-tidio-chat-admin.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "domain": "tidio-live-chat",
3
- "locale_data": {
4
- "tidio-live-chat": {
5
- "": {
6
- "domain": "tidio-live-chat",
7
- "plural_forms": "nplurals=2; plural=(n > 1);",
8
- "lang": "fr"
9
- },
10
- "Loading...": [
11
- "Chargement..."
12
- ],
13
- "Can’t be empty!": [
14
- "Ce champ ne peut pas être vide !"
15
- ],
16
- "Email can’t be empty!": [
17
- "L'e-mail ne peut pas être vide !"
18
- ],
19
- "Email is invalid!": [
20
- "L'adresse e-mail est invalide !"
21
- ],
22
- "Start using Tidio": [
23
- "Commencez à utiliser Tidio"
24
- ],
25
- "Something went wrong.": [
26
- "Une erreur s'est produite."
27
- ],
28
- "You have been blocked for too many attempts. Please try again in an hour.": [
29
- "Vous avez été bloqué en raison d'un nombre trop élevé de tentatives. Veuillez réessayer dans une heure."
30
- ],
31
- "Password can’t be empty!": [
32
- "Le mot de passe ne peut pas être vide !"
33
- ],
34
- "Wrong email or password": [
35
- "Adresse e-mail ou mot de passe erroné"
36
- ],
37
- "Go to Tidio panel": [
38
- "Accéder au panneau Tidio"
39
- ],
40
- "Error occured while creating, please try again!": [
41
- "Une erreur s'est produite lors de la création, veuillez réessayer !"
42
- ]
43
- }
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/js/tidio-live-chat-pl_PL-tidio-chat-admin.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "domain": "tidio-live-chat",
3
- "locale_data": {
4
- "tidio-live-chat": {
5
- "": {
6
- "domain": "tidio-live-chat",
7
- "plural_forms": "nplurals=2; plural=(n != 1);",
8
- "lang": "es_MX"
9
- },
10
- "Loading...": [
11
- "Ładowanie..."
12
- ],
13
- "Can’t be empty!": [
14
- "Nie może być puste."
15
- ],
16
- "Email can’t be empty!": [
17
- "E-mail musi zostać podany."
18
- ],
19
- "Email is invalid!": [
20
- "Podany e-mail jest nieprawidłowy."
21
- ],
22
- "Start using Tidio": [
23
- "Rozpocznij korzystanie z Tidio"
24
- ],
25
- "Something went wrong.": [
26
- "Coś poszło nie tak."
27
- ],
28
- "You have been blocked for too many attempts. Please try again in an hour.": [
29
- "Zostałeś zablokowany z powodu zbyt wielu prób. Spróbuj ponownie za 1 godzinę."
30
- ],
31
- "Password can’t be empty!": [
32
- "Hasło nie może być puste!"
33
- ],
34
- "Wrong email or password": [
35
- "Nieprawidłowy email lub hasło"
36
- ],
37
- "Go to Tidio panel": [
38
- "Przejdź do panelu Tidio"
39
- ],
40
- "Error occured while creating, please try again!": [
41
- "Wystąpił błąd podczas tworzenia, proszę spróbować ponownie!"
42
- ]
43
- }
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/js/tidio-live-chat-ru_RU-tidio-chat-admin.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "domain": "tidio-live-chat",
3
- "locale_data": {
4
- "tidio-live-chat": {
5
- "": {
6
- "domain": "tidio-live-chat",
7
- "plural_forms": "nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));",
8
- "lang": "ru"
9
- },
10
- "Loading...": [
11
- "Загрузка..."
12
- ],
13
- "Can’t be empty!": [
14
- "Не может оставаться пустым!"
15
- ],
16
- "Email can’t be empty!": [
17
- "Содержимое эл. письма не может быть пустым!"
18
- ],
19
- "Email is invalid!": [
20
- "Недействительный адрес эл. почты!"
21
- ],
22
- "Start using Tidio": [
23
- "Начать использовать Tidio"
24
- ],
25
- "Something went wrong.": [
26
- "Что-то пошло не так."
27
- ],
28
- "You have been blocked for too many attempts. Please try again in an hour.": [
29
- "Ваш аккаунт заблокирован из-за слишком большого количества попыток. Пожалуйста, повторите попытку через час."
30
- ],
31
- "Password can’t be empty!": [
32
- "Поле Пароль не может оставаться пустым!"
33
- ],
34
- "Wrong email or password": [
35
- "Неверный адрес эл. почты или пароль"
36
- ],
37
- "Go to Tidio panel": [
38
- "Перейти на панель Tidio"
39
- ],
40
- "Error occured while creating, please try again!": [
41
- "При создании произошла ошибка, пожалуйста, повторите попытку!"
42
- ]
43
- }
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
languages/tidio-live-chat-es_ES.mo CHANGED
Binary file
languages/tidio-live-chat-es_MX.mo CHANGED
Binary file
languages/tidio-live-chat-fr_BE.mo CHANGED
Binary file
languages/tidio-live-chat-fr_CA.mo CHANGED
Binary file
languages/tidio-live-chat-fr_FR.mo CHANGED
Binary file
languages/tidio-live-chat-pl_PL.mo CHANGED
Binary file
languages/tidio-live-chat-ru_RU.mo CHANGED
Binary file
media/css/options.css DELETED
@@ -1,393 +0,0 @@
1
- @import url(https://fonts.googleapis.com/css?family=Muli:300,400,700&subset=latin);
2
-
3
- #tidio-wrapper,
4
- #tidio-wrapper *,
5
- #tidio-wrapper *:before,
6
- #tidio-wrapper *:after {
7
- -webkit-box-sizing: border-box;
8
- -moz-box-sizing: border-box;
9
- box-sizing: border-box;
10
- }
11
-
12
- #tidio-wrapper {
13
- background: #f1f1f1;
14
- color: #080f1a;
15
- font-family: 'Muli', sans-serif;
16
- height: 100%;
17
- font-size: 16px;
18
- max-width: 1234px;
19
- z-index: 1;
20
- position: relative;
21
- padding: 66px 24px 0 0;
22
- }
23
-
24
- .tidio-box-wrapper {
25
- display: flex;
26
- flex-direction: column;
27
- align-items: stretch;
28
- justify-content: center;
29
- margin: -12px
30
- }
31
-
32
- .tidio-box {
33
- background-color: #fff;
34
- flex-grow: 0;
35
- flex-shrink: 1;
36
- margin: 12px;
37
- padding: 40px 24px;
38
- display: flex;
39
- flex-direction: column;
40
- align-items: center;
41
- }
42
-
43
- .tidio-box-actions {
44
- display: flex;
45
- flex-direction: row;
46
- align-items: flex-start;
47
- justify-content: center;
48
- position: relative;
49
- }
50
-
51
- .tidio-box-actions form {
52
- display: none;
53
- flex-direction: column;
54
- align-items: center;
55
- width: 100%;
56
- max-width: 360px;
57
- }
58
-
59
- .tidio-box-george {
60
- text-align: center;
61
- position: relative;
62
- padding-bottom: 324px;
63
-
64
- background: url(../img/a-center.png) bottom center,
65
- url(../img/4.svg) calc(50% + 223px) calc(100% - 82px),
66
- url(../img/8.svg) calc(50% - 109px) calc(100% - 149px),
67
- url(../img/16.svg) calc(50% + 234px) calc(100% - 183px),
68
- url(../img/27.svg) calc(50% + 143px) calc(100% - 248px),
69
- url(../img/28.svg) calc(50% - 214px) calc(100% - 55px),
70
- url(../img/29.svg) calc(50% - 223px) calc(100% - 148px),
71
- url(../img/34.svg) calc(50% - 159px) calc(100% - 226px),
72
- #fff;
73
- background-size: 314px 293px, 21px 15px, 23px 15px, 18px 19px, 16px 16px, 14px 22px, 43px 21px, 22px 20px;
74
- background-repeat: no-repeat;
75
- }
76
-
77
- .tidio-box-george h2, .tidio-box-actions h1 {
78
- font-size: 24px;
79
- line-height: 34px;
80
- font-weight: bold;
81
- max-width: 400px;
82
- margin-top: 0;
83
- margin-bottom: 16px;
84
- }
85
-
86
- .tidio-box-actions h1 {
87
- margin: 32px 0;
88
- padding-top: 48px;
89
- }
90
-
91
- .tidio-box p {
92
- font-size: 16px;
93
- line-height: 25px;
94
- font-weight: 300;
95
- max-width: 350px;
96
- margin: 0;
97
- }
98
-
99
- .tidio-box-george-image {
100
- position: absolute;
101
- left: 0;
102
- right: 0;
103
- bottom: 0;
104
- height: 300px;
105
- background-repeat: no-repeat;
106
-
107
- background-position: bottom left;
108
- }
109
-
110
- .tidio-box-actions form label,
111
- .tidio-box-actions form input,
112
- .tidio-box-actions form select,
113
- .tidio-box-actions form button,
114
- .tidio-box-actions form .button {
115
- width: 100%;
116
- }
117
-
118
- .tidio-box-actions form label {
119
- font-size: 14px;
120
- }
121
-
122
- .tidio-box-actions form label + label {
123
- margin-top: 16px;
124
- }
125
-
126
- .tidio-box-actions form input,
127
- .tidio-box-actions .select-selected {
128
- margin-top: 8px;
129
- height: 48px;
130
- padding: 12px 16px 11px;
131
- border-radius: 3px;
132
- font-size: 16px;
133
- line-height: 24px;
134
- box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.06);
135
- border: solid 1px #bcc5d7;
136
- display: flex;
137
- align-items: center;
138
- justify-content: flex-start;
139
- color: #080f1a;
140
- }
141
-
142
- .tidio-box-actions form input:focus,
143
- .tidio-box-actions form select:focus {
144
- border-color: #0566ff;
145
- box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.06);
146
- outline: none;
147
- }
148
-
149
- .tidio-box-actions input::placeholder {
150
- font-style: normal;
151
- color: #8894ab;
152
- }
153
-
154
- .tidio-box-actions form button,
155
- .tidio-box-actions form .button {
156
- font-size: 16px;
157
- color: #fff;
158
- background-color: #0566ff;
159
- border-color: #0566ff;
160
- border-radius: 3px;
161
- height: 48px;
162
- display: flex;
163
- align-items: center;
164
- justify-content: center;
165
- font-weight: 300;
166
- cursor: pointer;
167
- transition: all .3s;
168
- }
169
-
170
- .tidio-box-actions form * + button,
171
- .tidio-box-actions form * + .button {
172
- margin-top: 24px;
173
- }
174
-
175
- .tidio-box-actions form button:hover,
176
- .tidio-box-actions form button:focus,
177
- .tidio-box-actions form .button:hover,
178
- .tidio-box-actions form .button:focus {
179
- color: #fff;
180
- background-color: #0b5bda;
181
- border-color: #0b5bda;
182
- }
183
-
184
- .tidio-box-actions form .btn-link {
185
- background-color: transparent;
186
- border-color: transparent;
187
- color: #0566ff;
188
- margin-top: 8px;
189
- box-shadow: none;
190
- }
191
-
192
- .tidio-box-actions form .btn-link:hover,
193
- .tidio-box-actions form .btn-link:active,
194
- .tidio-box-actions form .btn-link:focus {
195
- text-decoration: underline;
196
- outline: none;
197
- background-color: transparent;
198
- border-color: transparent;
199
- color: #0566ff;
200
- box-shadow: none;
201
- }
202
-
203
- @media only screen and (min-width: 480px) {
204
- .tidio-box-actions {
205
- padding-top: 64px;
206
- }
207
-
208
- .tidio-box-actions h1 {
209
- margin-top: 44px;
210
- }
211
-
212
- .tidio-box-george h2 {
213
- margin-top: 24px;
214
- }
215
- }
216
-
217
- @media only screen and (min-width: 1280px) {
218
- .tidio-box-wrapper {
219
- flex-direction: row;
220
- }
221
-
222
- .tidio-box-actions {
223
- flex-basis: 530px;
224
- align-items: flex-start;
225
- }
226
-
227
- .tidio-box-actions h1 {
228
- background-position: top left;
229
- }
230
-
231
- .tidio-box-george h2 {
232
- margin-top: 32px;
233
- }
234
-
235
- .tidio-box-actions form {
236
- align-items: flex-start;
237
- }
238
-
239
- .tidio-box-george {
240
- flex-basis: 680px;
241
- }
242
- }
243
-
244
- #after-install-text {
245
- display: none;
246
- }
247
-
248
- .tidio-button {
249
- font-family: 'Muli', sans-serif;
250
- margin-top: 20px !important;
251
- height: 40px !important;
252
- line-height: 38px !important;
253
- text-align: center;
254
- width: 170px;
255
- }
256
-
257
- /* error */
258
- #tidio-wrapper .error {
259
- display: none;
260
- margin: 12px 0 -12px;
261
- padding: 0;
262
- border: none;
263
- box-shadow: none;
264
- color: #e81332;
265
- font-size: 14px;
266
- line-height: 20px;
267
- }
268
-
269
- #tidio-wrapper .error:before {
270
- content: '!';
271
- display: inline-flex;
272
- align-items: center;
273
- justify-content: center;
274
- width: 16px;
275
- height: 16px;
276
- background-color: #e81332;
277
- color: #fff;
278
- font-size: 13px;
279
- border-radius: 10px;
280
- margin-right: 8px;
281
- }
282
-
283
- .custom-select {
284
- position: relative;
285
- font-family: 'Muli', sans-serif;
286
- }
287
-
288
- .custom-select select {
289
- display: none; /*hide original SELECT element: */
290
- }
291
-
292
- .select-selected {
293
- background-color: #fff;
294
- }
295
-
296
- .select-selected.disabled {
297
- color: #8894ab;
298
- }
299
-
300
- /* Style the arrow inside the select element: */
301
- .select-selected:after {
302
- position: absolute;
303
- content: "";
304
- top: 14px;
305
- right: 14px;
306
- width: 20px;
307
- height: 20px;
308
- background: url(../img/chevron.svg) center center;
309
- }
310
-
311
- /* Point the arrow upwards when the select box is open (active): */
312
- .select-selected.select-arrow-active {
313
- border-color: #0566ff;
314
- }
315
-
316
- .select-selected.select-arrow-active:after {
317
- transform: rotate(180deg);
318
- }
319
-
320
- /* style the items (options), including the selected item: */
321
- .select-items div, .select-selected {
322
- color: #080f1a;
323
- padding: 8px 15px;
324
- line-height: 24px;
325
- border: none;
326
- cursor: pointer;
327
- }
328
-
329
- /* Style items (options): */
330
- .select-items {
331
- position: absolute;
332
- background-color: #fff;
333
- top: calc(100% + 8px);
334
- left: 0;
335
- right: 0;
336
- z-index: 99;
337
- max-height: 212px;
338
- overflow-y: auto;
339
- border: 1px solid #bcc5d7;
340
- border-radius: 3px;
341
- padding-top: 4px;
342
- padding-bottom: 4px;
343
- font-size: 16px;
344
- line-height: 24px;
345
- }
346
-
347
- /* Hide the items when the select box is closed: */
348
- .select-hide {
349
- display: none;
350
- }
351
-
352
- .select-items div:hover, .same-as-selected {
353
- background-color: rgba(5, 102, 255, 0.08);
354
- color: #0566ff;
355
- }
356
-
357
- .logos {
358
- position: absolute;
359
- width: 100%;
360
- max-width: 128px;
361
- display: inline-flex;
362
- background: url(../img/plus.svg) no-repeat;
363
- background-position: 68px 18px;
364
- }
365
-
366
- @media only screen and (min-width: 480px) {
367
- .logos {
368
- max-width: 360px;
369
- }
370
- }
371
-
372
- .logo {
373
- position: relative;
374
- display: inline-flex;
375
- width: 48px;
376
- height: 48px;
377
- border-radius: 20px;
378
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.08);
379
- }
380
-
381
- .logo + .logo {
382
- margin-left: 53px;
383
- }
384
-
385
- .tidio-logo {
386
- background: url(../img/tidio-logo.svg) no-repeat center center;
387
- background-color: #fff;
388
- }
389
-
390
- .wp-logo {
391
- background: url(../img/wp-logo.svg) no-repeat center center;
392
- background-color: #fff;
393
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
media/img/16.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="19" viewBox="0 0 18 19">
2
- <path fill="#D6D9E3" fill-rule="evenodd" d="M8.575 0C3.94.226.229 4.163.01 9.085c-.219 4.922 3.126 9.212 7.72 9.902.317.05.64-.046.883-.267.243-.22.385-.543.387-.883v-.062c-.009-.59-.426-1.081-.976-1.152-3.45-.533-5.948-3.77-5.762-7.466.185-3.696 2.992-6.633 6.475-6.773m.42.123c3.318-.15 6.2 2.612 6.684 6.407.065.614.513 1.078 1.048 1.086h.057c.308-.002.6-.16.8-.43.2-.27.288-.628.242-.98C17.354 3.48 13.462-.234 9 .012"/>
3
- </svg>
 
 
 
media/img/27.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
2
- <path fill="#F54586" fill-rule="evenodd" d="M4 1.474c.002.841.686 1.521 1.53 1.521L10.823 3l-5.63 5.633a1.503 1.503 0 0 0 .02 2.112c.584.58 1.526.588 2.12.017L13 5.188v5.296c0 .403.162.789.448 1.073.286.284.673.444 1.077.443a1.487 1.487 0 0 0 1.056-.45c.277-.285.427-.669.418-1.066V1.542a1.442 1.442 0 0 0-.467-1.046l.016-.017a1.465 1.465 0 0 0-1.055-.466L5.526.001A1.475 1.475 0 0 0 4 1.475zM.393 15.608a1.34 1.34 0 0 1 0-1.898l1.316-1.316a1.34 1.34 0 0 1 1.897-.001c.525.524.525 1.374.002 1.899l-1.316 1.316a1.343 1.343 0 0 1-1.899-.002v.002z"/>
3
- </svg>
 
 
 
media/img/28.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="22" viewBox="0 0 14 22">
2
- <path fill="#D6D9E3" fill-rule="evenodd" d="M12.698 2.673L5.814 9.634h4.607c.365-.027.724.107.985.366a1.308 1.308 0 0 1 0 1.84l-9.098 9.196a1.277 1.277 0 0 1-1.243.337c-.444-.12-.79-.471-.91-.92a1.31 1.31 0 0 1 .334-1.256l6.887-6.962H2.769a1.26 1.26 0 0 1-.985-.366 1.308 1.308 0 0 1 0-1.84L10.882.834c.32-.35.804-.493 1.261-.376.457.118.814.48.93.941a1.31 1.31 0 0 1-.375 1.275z"/>
3
- </svg>
 
 
 
media/img/29.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="43" height="21" viewBox="0 0 43 21">
2
- <path fill="#303CA5" fill-rule="evenodd" d="M42.671 19.304c-.144.498-.53.89-1.027 1.044a1.552 1.552 0 0 1-1.44-.281c-1.472-1.166-2.08-2.957-2.599-4.477-.675-1.985-1.122-3.125-2.46-3.482-1.337-.357-2.296.406-3.879 1.79-1.652 1.445-3.71 3.244-6.72 2.44-3.012-.803-3.889-3.385-4.595-5.46-.674-1.985-1.12-3.125-2.456-3.481-1.336-.357-2.295.406-3.877 1.79-1.652 1.446-3.709 3.245-6.72 2.441-3.01-.803-3.887-3.386-4.593-5.46C1.8 4.678 1.421 3.663.698 3.099A1.497 1.497 0 0 1 .16 1.53 1.552 1.552 0 0 1 2.63.767C4.1 1.933 4.71 3.724 5.224 5.243c.675 1.984 1.122 3.124 2.458 3.48 1.336.358 2.295-.405 3.876-1.79 1.653-1.445 3.71-3.244 6.72-2.44 3.01.803 3.888 3.385 4.593 5.46.674 1.985 1.121 3.124 2.457 3.481 1.337.357 2.298-.405 3.88-1.79 1.652-1.446 3.709-3.244 6.72-2.44 3.012.804 3.89 3.386 4.596 5.46.508 1.492.886 2.507 1.61 3.07.48.369.691.987.537 1.57z"/>
3
- </svg>
 
 
 
media/img/34.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="22" height="20" viewBox="0 0 22 20">
2
- <path fill="#D6D9E3" fill-rule="evenodd" d="M20.374 11.944l-2.57 1.457-1.94 5.075c-.155.361-.506.603-.905.624a1.048 1.048 0 0 1-.968-.527l-1.33-2.26-5.141 2.914a1.523 1.523 0 0 1-1.138.136 1.494 1.494 0 0 1-.903-.692L.32 9.904A1.445 1.445 0 0 1 .159 8.79c.1-.378.348-.702.69-.9L13.705.608c.72-.4 1.633-.151 2.04.555l5.159 8.766c.203.336.26.737.162 1.115-.1.378-.348.702-.69.9z"/>
3
- </svg>
 
 
 
media/img/4.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="21" height="15" viewBox="0 0 21 15">
2
- <path fill="#F8AA09" fill-rule="evenodd" d="M18.769 6.63l-3.68-3.562-3.582 3.463c-.026.03-.037.068-.065.097a1.385 1.385 0 0 1-1.882 0 1.05 1.05 0 0 1-.066-.097L5.911 3.068 2.21 6.648a1.34 1.34 0 0 1-1.827-.022A1.235 1.235 0 0 1 .36 4.86L4.904.466c.026-.03.036-.067.065-.096A1.33 1.33 0 0 1 5.893 0c.347 0 .68.133.925.37l3.68 3.56L14.08.466c.026-.03.037-.067.066-.096a1.385 1.385 0 0 1 1.882 0c.029.029.04.064.065.096l4.523 4.374c.33.32.46.785.34 1.221-.12.437-.473.778-.924.896a1.338 1.338 0 0 1-1.263-.326zM4.92 8.466c.026-.03.037-.068.066-.096A1.33 1.33 0 0 1 5.91 8c.346 0 .678.133.923.37l3.677 3.552 3.578-3.457c.026-.03.037-.068.066-.096a1.385 1.385 0 0 1 1.88 0c.03.029.04.064.065.096l4.519 4.365c.33.319.458.783.337 1.218-.12.436-.472.776-.923.892a1.337 1.337 0 0 1-1.261-.326l-3.676-3.555-3.577 3.456c-.026.03-.037.067-.066.096a1.384 1.384 0 0 1-1.88 0 1.053 1.053 0 0 1-.065-.096l-3.58-3.456L2.23 14.63a1.339 1.339 0 0 1-1.847 0 1.232 1.232 0 0 1 0-1.784L4.92 8.465z"/>
3
- </svg>
 
 
 
media/img/8.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="23" height="15" viewBox="0 0 23 15">
2
- <path fill="#D6D9E3" fill-rule="evenodd" d="M18.099 8.113c-.201 1.937-1.297 3.692-2.995 4.795a7.331 7.331 0 0 1-6.831.579c-3.852 1.26-7.01 1.282-7.91-.196-.902-1.477.69-4.046 3.762-6.57.218-2.116 1.503-4.003 3.452-5.069a7.35 7.35 0 0 1 6.373-.304c3.854-1.262 7.01-1.283 7.911.195.901 1.478-.69 4.047-3.762 6.57zM2.771 11.965c.332.542 1.564.527 3.287.062a6.584 6.584 0 0 1-1.7-2.78c-1.289 1.178-1.919 2.175-1.587 2.718zM19.453 2.87c-.332-.543-1.564-.527-3.287-.063a6.583 6.583 0 0 1 1.699 2.78c1.29-1.177 1.92-2.174 1.588-2.717z"/>
3
- </svg>
 
 
 
media/img/a-center.png DELETED
Binary file
media/img/ajax-loader.gif DELETED
Binary file
media/img/chevron.svg DELETED
@@ -1,4 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
2
- <path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" fill="#bcc5d7"/>
3
- <path d="M0 0h24v24H0z" fill="none"/>
4
- </svg>
 
 
 
 
media/img/plus.svg DELETED
@@ -1,3 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="13" height="12" viewBox="0 0 13 12">
2
- <path fill="#D6D9E3" fill-rule="evenodd" d="M8 0v4.5h4.5v3H8V12H5V7.499L.5 7.5v-3L5 4.499V0h3z"/>
3
- </svg>
 
 
 
media/img/tidio-logo.svg DELETED
@@ -1,8 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
2
- <g fill="none" fill-rule="nonzero">
3
- <path fill="#135EEB" d="M15.2.554c-4.062 0-7.508 2.892-8.246 6.892.492-.061.984-.123 1.477-.123-.493 0-.985.062-1.477.123-4 .739-6.892 4.185-6.892 8.246V24H8.43c4 0 7.446-2.83 8.184-6.77H14.77 23.57V8.924c-.062-4.615-3.755-8.37-8.37-8.37zm-8.37 8.37z"/>
4
- <path fill="#0A60EA" d="M8.43 7.323c-.492 0-.984.062-1.476.123-.062.492-.123.985-.123 1.477 0 4.615 3.754 8.37 8.369 8.308h1.415c.123-.493.123-1.046.123-1.6.062-4.554-3.692-8.246-8.307-8.308z"/>
5
- <path fill="#15C2FF" d="M15.2 17.292c-4.615 0-8.37-3.692-8.37-8.307 0-.493.062-.985.124-1.477a8.266 8.266 0 0 0-6.892 8.184V24H8.43c4 0 7.446-2.83 8.184-6.77H15.2v.062z"/>
6
- <path fill="#2C82FF" d="M15.2.554c-4.062 0-7.508 2.892-8.246 6.892.492-.061.984-.123 1.477-.123 4.615 0 8.369 3.692 8.369 8.308 0 .554-.062 1.046-.123 1.6h6.892V8.923C23.508 4.308 19.815.553 15.2.553z"/>
7
- </g>
8
- </svg>
 
 
 
 
 
 
 
 
media/img/wp-logo.svg DELETED
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="28px" height="28px" viewBox="0 0 28 28" version="1.1">
3
- <g id="surface1">
4
- <path style=" stroke:none;fill-rule:evenodd;fill:rgb(19.607843%,21.568627%,23.529412%);fill-opacity:1;" d="M 14.035156 0.078125 C 6.324219 0.078125 0.078125 6.324219 0.078125 14.035156 C 0.078125 21.742188 6.324219 27.992188 14.035156 27.992188 C 21.742188 27.992188 27.992188 21.742188 27.992188 14.035156 C 27.992188 6.324219 21.742188 0.078125 14.035156 0.078125 M 14.035156 0.914062 C 16.648438 0.90625 19.203125 1.6875 21.367188 3.152344 C 22.765625 4.097656 23.96875 5.300781 24.914062 6.699219 C 26.378906 8.863281 27.160156 11.417969 27.152344 14.03125 C 27.160156 16.648438 26.378906 19.203125 24.914062 21.367188 C 23.96875 22.765625 22.765625 23.96875 21.367188 24.914062 C 19.203125 26.378906 16.648438 27.160156 14.035156 27.152344 C 11.417969 27.160156 8.863281 26.378906 6.699219 24.914062 C 5.300781 23.96875 4.097656 22.765625 3.152344 21.367188 C 1.6875 19.203125 0.90625 16.648438 0.914062 14.035156 C 0.90625 11.417969 1.6875 8.863281 3.152344 6.699219 C 4.097656 5.300781 5.300781 4.097656 6.699219 3.152344 C 8.863281 1.6875 11.417969 0.90625 14.03125 0.914062 "/>
5
- <path style=" stroke:none;fill-rule:evenodd;fill:rgb(19.607843%,21.568627%,23.529412%);fill-opacity:1;" d="M 24.242188 8.453125 C 24.292969 8.824219 24.320312 9.222656 24.320312 9.648438 C 24.320312 10.828125 24.097656 12.15625 23.433594 13.816406 L 19.882812 24.085938 C 23.464844 22.003906 25.667969 18.175781 25.664062 14.03125 C 25.667969 12.082031 25.179688 10.164062 24.242188 8.453125 Z M 14.238281 15.050781 L 10.75 25.191406 C 13.089844 25.882812 15.59375 25.816406 17.898438 25.007812 C 17.863281 24.957031 17.835938 24.902344 17.8125 24.847656 Z M 21.886719 13.449219 C 21.886719 12.007812 21.371094 11.015625 20.925781 10.238281 C 20.339844 9.28125 19.785156 8.46875 19.785156 7.511719 C 19.785156 6.441406 20.59375 5.445312 21.738281 5.445312 C 21.789062 5.445312 21.839844 5.453125 21.886719 5.457031 C 19.746094 3.488281 16.941406 2.398438 14.035156 2.402344 C 10.117188 2.398438 6.464844 4.371094 4.316406 7.644531 C 4.589844 7.652344 4.84375 7.65625 5.0625 7.65625 C 6.28125 7.65625 8.164062 7.511719 8.164062 7.511719 C 8.789062 7.476562 8.863281 8.394531 8.238281 8.46875 C 8.238281 8.46875 7.609375 8.542969 6.90625 8.578125 L 11.144531 21.179688 L 13.6875 13.546875 L 11.878906 8.578125 C 11.46875 8.554688 11.0625 8.515625 10.65625 8.46875 C 10.027344 8.429688 10.101562 7.472656 10.730469 7.507812 C 10.730469 7.507812 12.652344 7.65625 13.792969 7.65625 C 15.011719 7.65625 16.894531 7.507812 16.894531 7.507812 C 17.523438 7.472656 17.59375 8.394531 16.96875 8.46875 C 16.96875 8.46875 16.335938 8.542969 15.636719 8.578125 L 19.839844 21.082031 L 21.039062 17.28125 C 21.574219 15.617188 21.886719 14.441406 21.886719 13.445312 Z M 2.402344 14.03125 C 2.402344 18.492188 4.945312 22.554688 8.957031 24.5 L 3.410156 9.300781 C 2.742188 10.789062 2.402344 12.402344 2.402344 14.035156 Z M 2.402344 14.03125 "/>
6
- </g>
7
- </svg>
 
 
 
 
 
 
 
media/js/options.js DELETED
@@ -1,341 +0,0 @@
1
- /* global jQuery */
2
- jQuery(function ($) {
3
- const { __ } = wp.i18n;
4
-
5
- var TidioChatWP = {
6
- nonce: tidioConfig.nonce,
7
- apiUrl: tidioConfig.apiUrl,
8
- panelUrl: tidioConfig.panelUrl,
9
- token: null,
10
- email: '',
11
- translate: message => __(message, 'tidio-live-chat'),
12
- init: function () {
13
- this.error = $('.error');
14
- this.form = $('#tidio-start');
15
- this.form.show();
16
- var emailField = this.form.find('#email');
17
- emailField.val('');
18
- this.form.off().submit(this.onStartSubmit.bind(this));
19
- },
20
- onStartSubmit: function () {
21
- var emailField = this.form.find('#email');
22
- var submitButton = this.form.find('button');
23
- if (emailField.val() === '') {
24
- this.showError(this.translate('Can’t be empty!'));
25
- return false;
26
- }
27
- if (emailField.is(':invalid')) {
28
- this.showError(this.translate('Email is invalid!'));
29
- return false;
30
- }
31
- this.hideError();
32
- this.email = emailField.val();
33
- submitButton.prop('disabled', true).text(this.translate('Loading...'));
34
-
35
- $.get(TidioChatWP.apiUrl + '/access/checkIfEmailIsRegistered', {
36
- email: emailField.val(),
37
- }).done(function (data) {
38
- if (data.status === true && data.value &&
39
- data.value.registered === true) {
40
- this.form.hide();
41
- submitButton.prop('disabled', false).text(this.translate('Start using Tidio'));
42
- this.showLoginForm(emailField.val());
43
- } else {
44
- this.redirectToPanel();
45
- }
46
- }.bind(this)).fail((function(error) {
47
- submitButton.prop('disabled', false).text(this.translate('Start using Tidio'));
48
- if (error && error.status === 429) {
49
- this.showError(this.translate('You have been blocked for too many attempts. Please try again in an hour.'));
50
- } else {
51
- this.showError(this.translate('Something went wrong.'));
52
- }
53
-
54
- }).bind(this));
55
- return false;
56
- },
57
- showError: function (message) {
58
- this.error.text(message).fadeIn();
59
- },
60
- hideError: function () {
61
- this.error.hide();
62
- },
63
- showLoginForm: function (emailValue) {
64
- this.form = $('#tidio-login');
65
- this.form.css('display', 'flex');
66
- var emailField = this.form.find('#email');
67
- emailField.val(emailValue);
68
- var passwordField = this.form.find('#password');
69
- passwordField.val('');
70
-
71
- this.form.off().submit(this.onLoginSubmit.bind(this));
72
- },
73
- onLoginSubmit: function () {
74
- var emailField = this.form.find('#email');
75
- var passwordField = this.form.find('#password');
76
- var submitButton = this.form.find('button');
77
- if (emailField.val() === '') {
78
- this.showError(this.translate('Email can’t be empty!'));
79
- return false;
80
- }
81
- if (emailField.is(':invalid')) {
82
- this.showError(this.translate('Email is invalid!'));
83
- return false;
84
- }
85
- if (passwordField.val() === '') {
86
- this.showError(this.translate('Password can’t be empty!'));
87
- return false;
88
- }
89
- this.hideError();
90
- submitButton.prop('disabled', true).text(this.translate('Loading...'));
91
-
92
- var email = emailField.val();
93
- var password = document.querySelector(
94
- '#tidio-login #password').value;
95
-
96
- $.get(TidioChatWP.apiUrl + '/access/getUserToken', {
97
- email: email,
98
- password: password,
99
- })
100
- .done(function (data) {
101
- TidioChatWP.token = data.value;
102
- this.getProjects(TidioChatWP.token);
103
- }.bind(this))
104
- .fail(function (error) {
105
- const statusCode = error?.status;
106
- if (statusCode === 401) {
107
- this.showError(this.translate('Wrong email or password'));
108
- } else if (statusCode === 429) {
109
- this.showError(this.translate('You have been blocked for too many attempts. Please try again in an hour.'));
110
- } else {
111
- this.showError(this.translate('Something went wrong.'));
112
- }
113
- }.bind(this))
114
- .always(function() {
115
- submitButton.prop('disabled', false).text(this.translate('Go to Tidio panel'));
116
- }.bind(this));
117
-
118
- return false;
119
- },
120
- addEmailToRedirectLink: function(url) {
121
- return url + '&tour_default_email=' + encodeURIComponent(this.email);
122
- },
123
- redirectToPanel: function () {
124
- var redirect = function (response) {
125
- var url = this.addEmailToRedirectLink(response);
126
- window.open(url, '_blank');
127
- TidioChatWP.setRedirectLink(url);
128
- this.form.fadeOut('fast', function () {
129
- $('#after-install-text').fadeIn('fast');
130
- });
131
- }.bind(this);
132
-
133
- $.post(ajaxurl, {
134
- 'action': 'get_private_key',
135
- '_wpnonce': TidioChatWP.nonce,
136
- },
137
- function (response) {
138
- if (response === 'error') {
139
- // load through ajax url
140
- TidioChatWP.accessThroughXHR(redirect);
141
- return false;
142
- }
143
- redirect(response);
144
- });
145
- },
146
- setRedirectLink: function (url) {
147
- $('a[href="admin.php?page=tidio-chat"]').
148
- attr('href', url).
149
- attr('target', '_blank');
150
- $('#open-panel-link').attr('href', url);
151
- },
152
- renderProjects: function (data) {
153
- var select_project = $('#select-tidio-project');
154
- var defaultOption = select_project.children()[0];
155
- select_project.children().remove();
156
- select_project.append(defaultOption);
157
- var selected = false;
158
- if (data.value.length === 1) {
159
- selected = true;
160
- }
161
- for (var i in data.value) {
162
- var project = data.value[i];
163
- var value = {
164
- project_id: project.id,
165
- private_key: project.private_key,
166
- public_key: project.public_key,
167
- };
168
-
169
- var option = $(
170
- '<option value="' + project.id + '" ' + (selected ? 'selected="selected"' : '') + '>' + project.name +
171
- '</option>');
172
- option.data('value', value);
173
- select_project.append(option);
174
- }
175
- this.renderCustomSelect();
176
-
177
- },
178
- getProjects: function (token) {
179
- $.get(TidioChatWP.apiUrl + '/project', {
180
- api_token: token,
181
- }, (function (response) {
182
- if (response.value.length === 1) {
183
- this.renderProjects(response);
184
- this.onProjectSubmit();
185
- } else {
186
- this.form.hide();
187
- this.form = $('#tidio-project');
188
- this.form.show();
189
- this.renderProjects(response);
190
- this.form.off().submit(this.onProjectSubmit.bind(this));
191
- var startOver = $('#start-over');
192
- startOver.click(this.startOver.bind(this));
193
- }
194
- }).bind(this), 'json');
195
- },
196
- onProjectSubmit: function () {
197
- var details = $('#select-tidio-project option:selected').data('value');
198
- $.extend(details, {
199
- 'action': 'set_project_keys',
200
- 'api_token': TidioChatWP.token,
201
- '_wpnonce': TidioChatWP.nonce,
202
- });
203
-
204
- $.post(ajaxurl, details, (function (response) {
205
- var url = this.addEmailToRedirectLink(response);
206
- window.open(url, '_blank');
207
- TidioChatWP.setRedirectLink(url);
208
- this.form.fadeOut('fast', function () {
209
- $('#after-install-text').fadeIn('fast');
210
- });
211
- }).bind(this));
212
- return false;
213
- },
214
- startOver: function () {
215
- this.deleteCustomSelect();
216
- this.form.hide();
217
- this.init();
218
- },
219
- deleteCustomSelect: function() {
220
- var selectSelected = this.form.find('.custom-select .select-selected');
221
- if (selectSelected.length) {
222
- selectSelected.off().remove();
223
- }
224
- var selectItems = this.form.find('.custom-select .select-items');
225
- if (selectItems.length) {
226
- selectItems.off().remove();
227
- }
228
- },
229
- renderCustomSelect: function () {
230
-
231
- var customSelect, i, j, select, selectedItem, options, option;
232
- /* Look for any elements with the class "custom-select": */
233
- customSelect = document.getElementsByClassName('custom-select');
234
- for (i = 0; i < customSelect.length; i++) {
235
- select = customSelect[i].getElementsByTagName('select')[0];
236
- /* For each element, create a new DIV that will act as the selected item: */
237
- selectedItem = document.createElement('DIV');
238
- selectedItem.setAttribute('class', 'select-selected disabled');
239
- selectedItem.innerHTML = select.options[select.selectedIndex].innerHTML;
240
- customSelect[i].appendChild(selectedItem);
241
- /* For each element, create a new DIV that will contain the option list: */
242
- options = document.createElement('DIV');
243
- options.setAttribute('class', 'select-items select-hide');
244
- for (j = 1; j < select.length; j++) {
245
- /* For each option in the original select element,
246
- create a new DIV that will act as an option item: */
247
- option = document.createElement('DIV');
248
- option.innerHTML = select.options[j].innerHTML;
249
- option.addEventListener('click', function () {
250
- /* When an item is clicked, update the original select box,
251
- and the selected item: */
252
- var y, i, k, s, h;
253
- s = this.parentNode.parentNode.getElementsByTagName(
254
- 'select')[0];
255
- h = this.parentNode.previousSibling;
256
- for (i = 0; i < s.length; i++) {
257
- if (s.options[i].innerHTML === this.innerHTML) {
258
- s.selectedIndex = i;
259
- h.innerHTML = this.innerHTML;
260
- y = this.parentNode.getElementsByClassName(
261
- 'same-as-selected');
262
- for (k = 0; k < y.length; k++) {
263
- y[k].removeAttribute('class');
264
- }
265
- this.setAttribute('class', 'same-as-selected');
266
- break;
267
- }
268
- }
269
- h.click();
270
- });
271
- options.appendChild(option);
272
- }
273
- customSelect[i].appendChild(options);
274
- selectedItem.addEventListener('click', function (event) {
275
- /* When the select box is clicked, close any other select boxes,
276
- and open/close the current select box: */
277
- event.stopPropagation();
278
- event.preventDefault();
279
- closeAllSelect(this);
280
- this.nextSibling.classList.toggle('select-hide');
281
- this.classList.toggle('select-arrow-active');
282
- if (!this.classList.contains('select-arrow-active')) {
283
- this.classList.remove('disabled');
284
- }
285
- });
286
- }
287
-
288
- function closeAllSelect(element) {
289
- /* A function that will close all select boxes in the document,
290
- except the current select box: */
291
- var items, selected, i, arrNo = [];
292
- items = document.getElementsByClassName('select-items');
293
- selected = document.getElementsByClassName('select-selected');
294
- for (i = 0; i < selected.length; i++) {
295
- if (element == selected[i]) {
296
- arrNo.push(i);
297
- } else {
298
- selected[i].classList.remove('select-arrow-active');
299
- }
300
- }
301
- for (i = 0; i < items.length; i++) {
302
- if (arrNo.indexOf(i)) {
303
- items[i].classList.add('select-hide');
304
- }
305
- }
306
- }
307
-
308
- /* If the user clicks anywhere outside the select box,
309
- then close all select boxes: */
310
- document.addEventListener('click', closeAllSelect);
311
- },
312
- accessThroughXHR: function (_func) {
313
-
314
- var xhr_url = TidioChatWP.apiUrl + '/access/external/create?url=' +
315
- location.protocol + '//' + location.host +
316
- '&platform=wordpress';
317
- $.getJSON(xhr_url, {}, function (r) {
318
- if (!r || !r.value) {
319
- alert(this.translate('Error occured while creating, please try again!'));
320
- return false;
321
- }
322
- _func(TidioChatWP.panelUrl + '/access?privateKey=' +
323
- r.value.private_key +
324
- '&app=chat&utm_source=platform&utm_medium=wordpress');
325
-
326
- // save this in wordpress database
327
- $.post(ajaxurl, {
328
- 'action': 'tidio_chat_save_keys',
329
- 'public_key': r.value.public_key,
330
- 'private_key': r.value.private_key,
331
- '_wpnonce': TidioChatWP.nonce,
332
- });
333
- }).fail(function () {
334
- alert(this.translate('Error occured while creating, please try again!'));
335
- });
336
-
337
- },
338
- };
339
-
340
- TidioChatWP.init();
341
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
options.php DELETED
@@ -1,61 +0,0 @@
1
- <div id="tidio-wrapper">
2
- <div class="tidio-box-wrapper">
3
- <div class="tidio-box tidio-box-actions">
4
- <div class="logos">
5
- <div class="logo tidio-logo"></div>
6
- <div class="logo wp-logo"></div>
7
- </div>
8
- <form novalidate id="tidio-start">
9
- <h1><?php i18n::_e('Start using Tidio');?></h1>
10
- <label>
11
- <?php i18n::_e('Email Address');?>
12
- <input type="email" id="email" placeholder="e.g. tidius@tidio.com" required/>
13
- </label>
14
-
15
- <div class="error"></div>
16
- <button><?php i18n::_e('Let’s go');?></button>
17
- </form>
18
- <form novalidate id="tidio-login">
19
- <h1><?php i18n::_e('Log into your account');?></h1>
20
- <label>
21
- <?php i18n::_e('Email Address');?>
22
- <input type="email" id="email" placeholder="e.g. tidius@tidio.com" required/>
23
- </label>
24
-
25
- <label>
26
- <?php i18n::_e('Password');?>
27
- <input type="password" id="password" placeholder="<?php i18n::_e('Type your password');?>&hellip;" required/>
28
- </label>
29
-
30
- <div class="error"></div>
31
- <button><?php i18n::_e('Go to Tidio panel');?></button>
32
- <a class="button btn-link" href="https://www.tidio.com/panel/forgot-password" target="_blank"><?php i18n::_e('Forgot password?');?></a>
33
- </form>
34
- <form novalidate id="tidio-project">
35
- <h1><?php i18n::_e('Choose your project');?></h1>
36
- <label>
37
- <?php i18n::_e('Choose your project');?>
38
- <div class="custom-select">
39
- <select name="select-tidio-project" id="select-tidio-project">
40
- <option selected="selected" disabled><?php i18n::_e('Pick one from the list');?>&hellip;</option>
41
- </select>
42
- </div>
43
- </label>
44
-
45
- <div class="error"></div>
46
- <button><?php i18n::_e('Go to Tidio panel');?></button>
47
- <button type="button" id="start-over" class="btn-link"><?php i18n::_e('Start all over again');?></button>
48
- </form>
49
- <form id="after-install-text">
50
- <h1><?php i18n::_e('Your site is already integrated with Tidio Chat');?></h1>
51
- <p><?php i18n::_e('All you need to do now is select the “Tidio Chat” tab on the left - that will take you to your Tidio panel. You can also open the panel by using the link below.');?></p>
52
- <a href="#" id="open-panel-link" class="button" target="_blank"><?php i18n::_e('Go to Panel');?></a>
53
- </form>
54
- </div>
55
- <div class="tidio-box tidio-box-george">
56
- <h2><?php i18n::_e('Join 300 000+ websites using Tidio - Live Chat boosted with Bots');?></h2>
57
- <p><?php i18n::_e('Increase sales by skyrocketing communication with customers.');?></p>
58
- <div class="tidio-box-george-image"></div>
59
- </div>
60
- </div>
61
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -1,9 +1,10 @@
1
  === Tidio – Live Chat, Chatbots & Email Integration ===
2
- Contributors: tytus-tytus, lucastidio, marcingwizdala, kkopaczyktidio
3
  Tags: free live chat, live chat, chat, chatbot, livechat, tidio, widget, zendesk, mailchimp, messenger
4
- Requires at least: 3.0
5
- Tested up to: 5.8
6
- Stable tag: 4.5.1
 
7
  License: GPLv2
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -13,7 +14,7 @@ Add Tidio Live Chat to your WordPress for free to answer customers’ questions,
13
 
14
  Looking for an easy-to-use live chat plugin for your WordPress website? **Tidio offers this and plenty more.**
15
 
16
- It’s a multifunctional customer service platform that enables you to offer world-class customer support and actively generate more leads and sales. Tidio offers [live chat](https://www.tidio.com/live-chat/) and [chatbots](https://www.tidio.com/chatbots/) as well as [messenger](https://help.tidio.com/docs/messenger-integration-with-tidio) and [email](https://help.tidio.com/docs/external-mailbox-integration) integration so **you can manage all these channels in one panel**.
17
 
18
  But don't take our word for it—experience it yourself! Our plugin is completely free, and the installation takes under 5 minutes.
19
 
@@ -55,6 +56,12 @@ See how live chat can boost your sales
55
  Never used chatbots before? Check our video guide
56
  [youtube https://www.youtube.com/watch?v=-LUChIx9UW8]
57
 
 
 
 
 
 
 
58
  ## Selected Tidio features:
59
 
60
  - A lightweight and customizable widget that will work great with your branding and is 100% mobile-friendly
@@ -74,6 +81,12 @@ Never used chatbots before? Check our video guide
74
  - Tidio Live Chat and Chatbot is the **highest rated plugin of this type for WordPress**
75
  - The solution is actively used by **275,000 users … and growing**
76
 
 
 
 
 
 
 
77
  Hard to believe it? Read the testimonials, because our users say it best:
78
 
79
  ## TESTIMONIALS
@@ -137,7 +150,7 @@ After activating the plugin, create your account and start the product tour. Fol
137
 
138
  == Frequently Asked Questions ==
139
  = How much does Tidio Live Chat cost? =
140
- Tidio is free and we don’t need your card details. Later on, you can unlock additional premium features for a small price starting from USD 18 per month.
141
  = I’ve installed the WordPress chat plugin—what happens next? =
142
  Click on the new Tidio live chat icon that appeared on your WP-admin menu on the left. You'll be able to create your Tidio account connected to the plugin. Finish the initial configuration and you can start using the best live chat plugin for WordPress.
143
  = Do I need a Tidio account to use this WordPress live chat plugin? =
@@ -160,7 +173,7 @@ Yes. Apart from the tips available inside the tool itself, you can learn more ab
160
  - [Case Studies](https://www.tidio.com/case-studies/)
161
 
162
  = Can several support agents use the free chat at the same time? =
163
- Yes. You can also transfer conversations between operators. The free plan has 3 operator seats. It means that 3 operators (and an unlimited number of customers) can use the live chat at once for free. You can also buy extra seats if your support team grows.
164
  = Can visitors start chatting without providing their email address? =
165
  Yes, but you need to switch off the pre-chat survey. By default, Tidio shows a survey that visitors have to fill in before joining a live chat conversation.
166
  = Can I check if I missed any messages from my visitors? =
@@ -185,6 +198,10 @@ Currently, Tidio is available in English and French. Other languages are in deve
185
 
186
  == Changelog ==
187
 
 
 
 
 
188
  = 4.5.1 =
189
 
190
  - Add missing "tidioApiUrl" value in options.js file
1
  === Tidio – Live Chat, Chatbots & Email Integration ===
2
+ Contributors: tytus-tytus, lucastidio, marcingwizdala, kkopaczyktidio, ksladek, adrianmtidio
3
  Tags: free live chat, live chat, chat, chatbot, livechat, tidio, widget, zendesk, mailchimp, messenger
4
+ Requires at least: 4.7
5
+ Tested up to: 6.0
6
+ Requires PHP: 5.6
7
+ Stable tag: 5.0.0
8
  License: GPLv2
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
14
 
15
  Looking for an easy-to-use live chat plugin for your WordPress website? **Tidio offers this and plenty more.**
16
 
17
+ It’s a multifunctional customer service platform that enables you to offer world-class customer support and actively generate more leads and sales. Tidio offers [live chat](https://www.tidio.com/live-chat/) and [chatbots](https://www.tidio.com/chatbots/) as well as [Messenger](https://help.tidio.com/docs/messenger-integration-with-tidio), [Instagram](https://help.tidio.com/docs/integration-with-instagram) and [email](https://help.tidio.com/docs/external-mailbox-integration) integration so **you can manage all these channels in one panel**.
18
 
19
  But don't take our word for it—experience it yourself! Our plugin is completely free, and the installation takes under 5 minutes.
20
 
56
  Never used chatbots before? Check our video guide
57
  [youtube https://www.youtube.com/watch?v=-LUChIx9UW8]
58
 
59
+ ## Automated customer support - for even better experience.
60
+ Built-in chatbots can automatically answer most common customer questions about order status, product availability and delivery time. This kind of virtual assistant will not only support your customers 24/7, but save your time!
61
+
62
+ ## Smart Pop ups that improve conversion without irritating your customers
63
+ We all know that pop ups can boost sales, but they can also be frustrating for visitors. Ready-made Tidio chatbot scenarios can turn the live chat widget into smart pop ups. They can be triggered by defined action and fully customized. You can edit all the conditions, text and images using our drag&drop chatbot editor.
64
+
65
  ## Selected Tidio features:
66
 
67
  - A lightweight and customizable widget that will work great with your branding and is 100% mobile-friendly
81
  - Tidio Live Chat and Chatbot is the **highest rated plugin of this type for WordPress**
82
  - The solution is actively used by **275,000 users … and growing**
83
 
84
+
85
+ ## To run Tidio plugin for WordPress we recommend your host supports:
86
+
87
+ - **OpenSSL** (to increase security by encrypting your access tokens)
88
+ - **cURL**
89
+
90
  Hard to believe it? Read the testimonials, because our users say it best:
91
 
92
  ## TESTIMONIALS
150
 
151
  == Frequently Asked Questions ==
152
  = How much does Tidio Live Chat cost? =
153
+ Tidio is free and we don’t need your card details. Later on, you can unlock additional premium features for a small price starting from $33 per month.
154
  = I’ve installed the WordPress chat plugin—what happens next? =
155
  Click on the new Tidio live chat icon that appeared on your WP-admin menu on the left. You'll be able to create your Tidio account connected to the plugin. Finish the initial configuration and you can start using the best live chat plugin for WordPress.
156
  = Do I need a Tidio account to use this WordPress live chat plugin? =
173
  - [Case Studies](https://www.tidio.com/case-studies/)
174
 
175
  = Can several support agents use the free chat at the same time? =
176
+ Yes. You can also transfer conversations between operators. The free plan has 2 operator seats. It means that 2 operators (and an unlimited number of customers) can use the live chat at once for free. You can also buy extra seats if your support team grows.
177
  = Can visitors start chatting without providing their email address? =
178
  Yes, but you need to switch off the pre-chat survey. By default, Tidio shows a survey that visitors have to fill in before joining a live chat conversation.
179
  = Can I check if I missed any messages from my visitors? =
198
 
199
  == Changelog ==
200
 
201
+ = 5.0.0 =
202
+
203
+ - New integration flow based on OAuth
204
+
205
  = 4.5.1 =
206
 
207
  - Add missing "tidioApiUrl" value in options.js file
src/Admin/TidioAdminActionLink.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioAdminActionLink
4
+ {
5
+ /**
6
+ * @var TidioIntegrationState
7
+ */
8
+ private $integrationState;
9
+
10
+ /**
11
+ * @param TidioIntegrationState $integrationsState
12
+ */
13
+ public function __construct($integrationsState)
14
+ {
15
+ $this->integrationState = $integrationsState;
16
+
17
+ add_filter('plugin_action_links', [$this, 'addPluginActionLinks'], 10, 2);
18
+ }
19
+
20
+ /**
21
+ * @param string[] $links
22
+ * @param string $file
23
+ * @return string[]
24
+ */
25
+ public function addPluginActionLinks($links, $file)
26
+ {
27
+ if (!$this->isPluginConfigurationFile($file) ||
28
+ !$this->integrationState->isPluginIntegrated()
29
+ ) {
30
+ return $links;
31
+ }
32
+
33
+ $links[] = $this->prepareClearAccountDataActionLink();
34
+ $links[] = $this->prepareToggleAsyncLoadingActionLink();
35
+
36
+ return $links;
37
+ }
38
+
39
+ /**
40
+ * @param string $file
41
+ * @return bool
42
+ */
43
+ private function isPluginConfigurationFile($file)
44
+ {
45
+ return strpos($file, TidioLiveChat::TIDIO_PLUGIN_NAME) !== false;
46
+ }
47
+
48
+ /**
49
+ * @return string
50
+ */
51
+ private function prepareClearAccountDataActionLink()
52
+ {
53
+ return sprintf(
54
+ '<a href="%s">%s</a>',
55
+ TidioAdminRouting::getEndpointForClearAccountDataAction(),
56
+ esc_html(i18n::_t('Clear Account Data'))
57
+ );
58
+ }
59
+
60
+ /**
61
+ * @return string
62
+ */
63
+ private function prepareToggleAsyncLoadingActionLink()
64
+ {
65
+ $toggleAsyncLabel = '✘';
66
+ $onclickPart = '';
67
+ if ($this->integrationState->isAsyncLoadingTurnedOn()) {
68
+ $toggleAsyncLabel = '✓';
69
+ $onclickPart = sprintf(
70
+ 'onclick="return confirm(\'%s\');"',
71
+ i18n::_t('Disabling asynchronous loading of the chat widget may affect the page loading time of your website. Are you sure you want to disable the asynchronous loading?')
72
+ );
73
+ }
74
+
75
+ return sprintf(
76
+ '<a href="%s" %s>%s</a>',
77
+ TidioAdminRouting::getEndpointForToggleAsyncLoadingAction(),
78
+ $onclickPart,
79
+ esc_html(
80
+ sprintf('%s %s', $toggleAsyncLabel, i18n::_t('Asynchronous loading'))
81
+ )
82
+ );
83
+ }
84
+ }
src/Admin/TidioAdminController.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioAdminController
4
+ {
5
+ /**
6
+ * @var TidioIntegrationFacade
7
+ */
8
+ private $integrationFacade;
9
+ /**
10
+ * @var TidioIntegrationState
11
+ */
12
+ private $integrationState;
13
+
14
+ /**
15
+ * @param TidioIntegrationFacade $integrationFacade
16
+ * @param TidioIntegrationState $integrationState
17
+ */
18
+ public function __construct($integrationFacade, $integrationState)
19
+ {
20
+ $this->integrationFacade = $integrationFacade;
21
+ $this->integrationState = $integrationState;
22
+ }
23
+
24
+ public function handleIntegrateProjectAction()
25
+ {
26
+ if (!$this->isRequestNonceValid(TidioAdminRouting::INTEGRATE_PROJECT_ACTION)) {
27
+ wp_die('', 403);
28
+ }
29
+
30
+ $refreshToken = QueryParameters::get('refreshToken');
31
+ try {
32
+ $data = $this->integrationFacade->integrateProject($refreshToken);
33
+ } catch (TidioApiException $exception) {
34
+ $errorCode = $exception->getMessage();
35
+ $this->redirectToPluginAdminDashboardWithError($errorCode);
36
+ }
37
+
38
+ $this->integrationState->integrate(
39
+ $data['projectPublicKey'],
40
+ $data['accessToken'],
41
+ $data['refreshToken']
42
+ );
43
+
44
+ $this->redirectToPluginAdminDashboard();
45
+ }
46
+
47
+ public function handleToggleAsyncLoadingAction()
48
+ {
49
+ if (!$this->isRequestNonceValid(TidioAdminRouting::TOGGLE_ASYNC_LOADING_ACTION)) {
50
+ wp_die('', 403);
51
+ }
52
+
53
+ $this->integrationState->toggleAsyncLoading();
54
+
55
+ $this->redirectToPluginsListDashboard();
56
+ }
57
+
58
+ public function handleClearAccountDataAction()
59
+ {
60
+ if (!$this->isRequestNonceValid(TidioAdminRouting::CLEAR_ACCOUNT_DATA_ACTION)) {
61
+ wp_die('', 403);
62
+ }
63
+
64
+ $this->integrationState->removeIntegration();
65
+
66
+ $this->redirectToPluginsListDashboard();
67
+ }
68
+
69
+ /**
70
+ * @param string $nonce
71
+ * @return bool
72
+ */
73
+ private function isRequestNonceValid($nonce)
74
+ {
75
+ if (!QueryParameters::has('_wpnonce')) {
76
+ return false;
77
+ }
78
+
79
+ return (bool) wp_verify_nonce(QueryParameters::get('_wpnonce'), $nonce);
80
+ }
81
+
82
+ private function redirectToPluginsListDashboard()
83
+ {
84
+ wp_redirect(admin_url('plugins.php'));
85
+ die();
86
+ }
87
+
88
+ private function redirectToPluginAdminDashboard()
89
+ {
90
+ $url = 'admin.php?page=' . TidioLiveChat::TIDIO_PLUGIN_NAME;
91
+ wp_redirect(admin_url($url));
92
+ die();
93
+ }
94
+
95
+ /**
96
+ * @param string $errorCode
97
+ */
98
+ private function redirectToPluginAdminDashboardWithError($errorCode)
99
+ {
100
+ $url = sprintf('admin.php?page=%s&error=%s', TidioLiveChat::TIDIO_PLUGIN_NAME, $errorCode);
101
+ wp_redirect(admin_url($url));
102
+ die();
103
+ }
104
+ }
src/Admin/TidioAdminDashboard.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioAdminDashboard
4
+ {
5
+ const TIDIO_ICON_BASE64 = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIzLjEuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IldhcnN0d2FfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgdmlld0JveD0iMCAwIDIwIDIwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMCAyMDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiNBMEE1QUE7fQo8L3N0eWxlPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMiwxOHYtNS45YzAtMi43LDEuNy01LDQuMy01LjdDNy4xLDMuNyw5LjQsMiwxMi4xLDJDMTUuNCwyLDE4LDQuNiwxOCw3Ljl2NS45aC00LjVsMCwwLjEKCWMtMC44LDIuNS0zLDQuMS01LjYsNC4xSDJ6IE02LjEsOC4xTDYuMSw4LjFjLTEuNiwwLjctMi42LDIuMy0yLjYsNC4xdjQuNGg0LjRjMS44LDAsMy4zLTEsNC4xLTIuNmwwLTAuMWwtMC4xLDAKCWMtMy4xLTAuMi01LjYtMi43LTUuNy01LjZsMC0wLjFMNi4xLDguMXogTTEyLjEsMy41Yy0xLjgsMC0zLjMsMS00LjEsMi42bDAsMC4xbDAuMSwwYzMuMiwwLjEsNS43LDIuNyw1LjcsNS45djAuMWwwLjEsMC4xaDIuN1Y3LjkKCUMxNi41LDUuNSwxNC41LDMuNSwxMi4xLDMuNXogTTcuNiw3LjhMNy42LDcuOGMwLDIuNSwyLDQuNSw0LjQsNC41aDAuMWwwLjEtMC4xYzAtMi41LTItNC41LTQuNC00LjVINy43TDcuNiw3Ljh6Ii8+Cjwvc3ZnPgo=';
6
+
7
+ /**
8
+ * @var TidioIntegrationState
9
+ */
10
+ private $integrationState;
11
+ /**
12
+ * @var TidioIframeSetup
13
+ */
14
+ private $iframeSetup;
15
+
16
+ /**
17
+ * @param TidioIntegrationState $integrationState
18
+ * @param TidioIframeSetup $iframeSetup
19
+ */
20
+ public function __construct($integrationState, $iframeSetup)
21
+ {
22
+ $this->integrationState = $integrationState;
23
+ $this->iframeSetup = $iframeSetup;
24
+
25
+ add_action('admin_menu', [$this, 'addAdminMenuLink']);
26
+ }
27
+
28
+ public function addAdminMenuLink()
29
+ {
30
+ add_menu_page(
31
+ 'Tidio Chat',
32
+ 'Tidio Chat',
33
+ 'manage_options',
34
+ TidioLiveChat::TIDIO_PLUGIN_NAME,
35
+ [$this, 'addAdminPage'],
36
+ 'data:image/svg+xml;base64,' . self::TIDIO_ICON_BASE64
37
+ );
38
+ }
39
+
40
+ public function addAdminPage()
41
+ {
42
+ $dir = plugin_dir_path(__FILE__);
43
+ if ($this->integrationState->isPluginIntegrated()) {
44
+ $iframeUrl = $this->iframeSetup->prepareIntegrationSuccessIframeUrl();
45
+ } else {
46
+ $iframeUrl = $this->iframeSetup->prepareAuthenticationIframeUrl();
47
+ }
48
+
49
+ include $dir . '../../views/iframe.php';
50
+ }
51
+ }
src/Admin/TidioAdminNotice.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioAdminNotice
4
+ {
5
+ /**
6
+ * @var TidioErrorTranslator
7
+ */
8
+ private $errorTranslator;
9
+
10
+ /**
11
+ * @param TidioErrorTranslator $errorTranslator
12
+ */
13
+ public function __construct($errorTranslator)
14
+ {
15
+ $this->errorTranslator = $errorTranslator;
16
+
17
+ add_action('admin_notices', [$this, 'addAdminErrorNotice']);
18
+ }
19
+
20
+ public function addAdminErrorNotice()
21
+ {
22
+ if (!QueryParameters::has('error')) {
23
+ return;
24
+ }
25
+
26
+ $errorCode = QueryParameters::get('error');
27
+ $errorMessage = $this->errorTranslator->translate($errorCode);
28
+ echo sprintf('<div class="notice notice-error is-dismissible"><p>%s</p></div>', $errorMessage);
29
+ }
30
+ }
src/Admin/TidioAdminRouting.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioAdminRouting
4
+ {
5
+ const CLEAR_ACCOUNT_DATA_ACTION = 'tidio-live-chat-clear-account-data';
6
+ const INTEGRATE_PROJECT_ACTION = 'tidio-live-chat-integrate-project';
7
+ const TOGGLE_ASYNC_LOADING_ACTION = 'tidio-live-chat-toggle-async-loading';
8
+
9
+ /**
10
+ * @param TidioAdminController $adminController
11
+ */
12
+ public function __construct($adminController)
13
+ {
14
+ add_action('admin_post_' . self::INTEGRATE_PROJECT_ACTION, [$adminController, 'handleIntegrateProjectAction']);
15
+ add_action('admin_post_' . self::TOGGLE_ASYNC_LOADING_ACTION, [$adminController, 'handleToggleAsyncLoadingAction']);
16
+ add_action('admin_post_' . self::CLEAR_ACCOUNT_DATA_ACTION, [$adminController, 'handleClearAccountDataAction']);
17
+ }
18
+
19
+ /**
20
+ * @return string
21
+ */
22
+ public static function getEndpointForIntegrateProjectAction()
23
+ {
24
+ return self::getEndpointForAction(self::INTEGRATE_PROJECT_ACTION);
25
+ }
26
+
27
+ /**
28
+ * @return string
29
+ */
30
+ public static function getEndpointForToggleAsyncLoadingAction()
31
+ {
32
+ return self::getEndpointForAction(self::TOGGLE_ASYNC_LOADING_ACTION);
33
+ }
34
+
35
+ /**
36
+ * @return string
37
+ */
38
+ public static function getEndpointForClearAccountDataAction()
39
+ {
40
+ return self::getEndpointForAction(self::CLEAR_ACCOUNT_DATA_ACTION);
41
+ }
42
+
43
+ /**
44
+ * @param string $action
45
+ * @return string
46
+ */
47
+ private static function getEndpointForAction($action)
48
+ {
49
+ $queryString = http_build_query([
50
+ 'action' => $action,
51
+ '_wpnonce' => wp_create_nonce($action),
52
+ ]);
53
+ return admin_url('admin-post.php?' . $queryString);
54
+ }
55
+ }
src/Admin/TidioIframeSetup.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioIframeSetup
4
+ {
5
+ /**
6
+ * @var TidioIntegrationState
7
+ */
8
+ private $integrationState;
9
+
10
+ /**
11
+ * @param TidioIntegrationState $integrationState
12
+ */
13
+ public function __construct($integrationState)
14
+ {
15
+ $this->integrationState = $integrationState;
16
+ }
17
+
18
+ /**
19
+ * @return string
20
+ */
21
+ public function prepareAuthenticationIframeUrl()
22
+ {
23
+ $userId = get_current_user_id();
24
+ $userName = get_user_meta($userId, 'first_name', true);
25
+
26
+ $queryParams = array_merge(
27
+ [
28
+ 'pluginUrl' => TidioAdminRouting::getEndpointForIntegrateProjectAction(),
29
+ 'name' => $userName,
30
+ 'refId' => $this->readRefIdFromFile()
31
+ ],
32
+ $this->getDefaultIframeQueryParams()
33
+ );
34
+
35
+ $iframeBaseUrl = TidioLiveChatConfig::getPanelUrl() . '/register-platforms';
36
+ return sprintf('%s?%s', $iframeBaseUrl, http_build_query($queryParams));
37
+ }
38
+
39
+ /**
40
+ * @return string
41
+ */
42
+ public function prepareIntegrationSuccessIframeUrl()
43
+ {
44
+ $queryParams = array_merge(
45
+ [
46
+ 'panelUrl' => $this->getPanelRedirectUrl()
47
+ ],
48
+ $this->getDefaultIframeQueryParams()
49
+ );
50
+
51
+ $iframeBaseUrl = TidioLiveChatConfig::getPanelUrl() . '/integration-success';
52
+ return sprintf('%s?%s', $iframeBaseUrl, http_build_query($queryParams));
53
+ }
54
+
55
+ /**
56
+ * @return array<string, string>
57
+ */
58
+ private function getDefaultIframeQueryParams()
59
+ {
60
+ $userId = get_current_user_id();
61
+ $localeCode = get_user_locale($userId);
62
+
63
+ return [
64
+ 'siteUrl' => get_home_url(),
65
+ 'localeCode' => $localeCode,
66
+ 'utm_source' => 'platform',
67
+ 'utm_medium' => 'wordpress',
68
+ ];
69
+ }
70
+
71
+ /**
72
+ * @return string|null
73
+ */
74
+ private function readRefIdFromFile() {
75
+ try {
76
+ $loadedRefIdFromFile = @file_get_contents(AFFILIATE_CONFIG_FILE_PATH);
77
+ return trim($loadedRefIdFromFile);
78
+ } catch (Exception $e) {
79
+ return null;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @return string
85
+ */
86
+ private function getPanelRedirectUrl()
87
+ {
88
+ $queryParams = [
89
+ 'utm_source' => 'platform',
90
+ 'utm_medium' => 'wordpress'
91
+ ];
92
+ if ($this->integrationState->hasProjectPrivateKey()) {
93
+ $queryParams['privateKey'] = $this->integrationState->getProjectPrivateKey();
94
+ return sprintf('%s/external-access?%s', TidioLiveChatConfig::getPanelUrl(), http_build_query($queryParams));
95
+ }
96
+
97
+ return sprintf('%s?%s', TidioLiveChatConfig::getPanelUrl(), http_build_query($queryParams));
98
+ }
99
+ }
src/Sdk/Api/Client/CurlTidioApiClient.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class CurlTidioApiClient implements TidioApiClient
4
+ {
5
+ /**
6
+ * @var string[]
7
+ */
8
+ private $headers;
9
+
10
+ /**
11
+ * @param string[] $additionalHeaders
12
+ */
13
+ public function __construct($additionalHeaders = [])
14
+ {
15
+ $this->headers = array_merge(
16
+ [
17
+ 'Content-Type: application/json',
18
+ 'Accept: application/json'
19
+ ],
20
+ $additionalHeaders
21
+ );
22
+ }
23
+
24
+ /**
25
+ * @inerhitDoc
26
+ */
27
+ public function sendPostRequest($path, $data = [])
28
+ {
29
+ $url = TidioLiveChatConfig::getApiUrl() . $path;
30
+ $ch = curl_init();
31
+
32
+ curl_setopt($ch, CURLOPT_HEADER, 1);
33
+ curl_setopt($ch, CURLOPT_POST, 1);
34
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
35
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
36
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
37
+ curl_setopt($ch, CURLOPT_URL, $url);
38
+
39
+ $response = curl_exec($ch);
40
+ $responseInfo = curl_getinfo($ch);
41
+ curl_close($ch);
42
+
43
+ $responseData = $this->parseResponseData($response, $responseInfo);
44
+ $this->validateResponse($responseData, $responseInfo);
45
+
46
+ return $responseData;
47
+ }
48
+
49
+ /**
50
+ * @inerhitDoc
51
+ */
52
+ public function sendGetRequest($path)
53
+ {
54
+ $url = TidioLiveChatConfig::getApiUrl() . $path;
55
+ $ch = curl_init();
56
+
57
+ curl_setopt($ch, CURLOPT_HEADER, 1);
58
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
59
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
60
+ curl_setopt($ch, CURLOPT_URL, $url);
61
+
62
+ $response = curl_exec($ch);
63
+ $responseInfo = curl_getinfo($ch);
64
+ curl_close($ch);
65
+
66
+ $responseData = $this->parseResponseData($response, $responseInfo);
67
+ $this->validateResponse($responseData, $responseInfo);
68
+
69
+ return $responseData;
70
+ }
71
+
72
+ /**
73
+ * @param string|false $response
74
+ * @param array<string, mixed> $responseInfo
75
+ * @return array<string, mixed>
76
+ */
77
+ private function parseResponseData($response, $responseInfo)
78
+ {
79
+ $headerSize = $responseInfo['header_size'];
80
+ $responseBody = substr($response, $headerSize);
81
+ $responseData = json_decode($responseBody, true);
82
+
83
+ if (false === $responseData) {
84
+ return [];
85
+ }
86
+
87
+ return $responseData;
88
+ }
89
+
90
+ /**
91
+ * @param array<string, mixed> $responseData
92
+ * @param array<string, mixed> $responseInfo
93
+ * @throws TidioApiException
94
+ */
95
+ private function validateResponse($responseData, $responseInfo)
96
+ {
97
+ $statusCode = $responseInfo['http_code'];
98
+ if ($statusCode === 401) {
99
+ throw TidioApiException::withUnauthorizedErrorCode();
100
+ } elseif ($statusCode < 200 || $statusCode >= 300) {
101
+ if (isset($responseData['error'])) {
102
+ throw TidioApiException::withErrorCode($responseData['error']);
103
+ }
104
+
105
+ throw TidioApiException::withUnknownErrorCode();
106
+ }
107
+ }
108
+ }
src/Sdk/Api/Client/FileGetContentsTidioApiClient.php ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class FileGetContentsTidioApiClient implements TidioApiClient
4
+ {
5
+ /**
6
+ * @var string[]
7
+ */
8
+ private $headers;
9
+
10
+ /**
11
+ * @param string[] $additionalHeaders
12
+ */
13
+ public function __construct($additionalHeaders = [])
14
+ {
15
+ $this->headers = array_merge(
16
+ ['Accept: application/json'],
17
+ $additionalHeaders
18
+ );
19
+ }
20
+
21
+ /**
22
+ * @inerhitDoc
23
+ */
24
+ public function sendPostRequest($path, $data = [])
25
+ {
26
+ $url = TidioLiveChatConfig::getApiUrl() . $path;
27
+ $content = http_build_query($data);
28
+ $headers = array_merge([
29
+ 'Content-Type: application/x-www-form-urlencoded',
30
+ 'Content-Length: ' . strlen($content)
31
+ ], $this->headers);
32
+ $options = [
33
+ 'http' => [
34
+ 'method' => 'POST',
35
+ 'header' => $this->prepareRequestHeaders($headers),
36
+ 'content' => http_build_query($data),
37
+ 'ignore_errors' => true
38
+ ]
39
+ ];
40
+
41
+ $context = stream_context_create($options);
42
+ $response = @file_get_contents($url, false, $context);
43
+
44
+ $responseData = $this->parseResponseData($response);
45
+ $this->validateResponse($responseData, $http_response_header);
46
+
47
+ return $responseData;
48
+ }
49
+
50
+ /**
51
+ * @inerhitDoc
52
+ */
53
+ public function sendGetRequest($path)
54
+ {
55
+ $url = TidioLiveChatConfig::getApiUrl() . $path;
56
+ $options = [
57
+ 'http' => [
58
+ 'method' => 'GET',
59
+ 'header' => $this->prepareRequestHeaders($this->headers),
60
+ 'ignore_errors' => true
61
+ ]
62
+ ];
63
+
64
+ $context = stream_context_create($options);
65
+ $response = @file_get_contents($url, false, $context);
66
+
67
+ $responseData = $this->parseResponseData($response);
68
+ $this->validateResponse($responseData, $http_response_header);
69
+
70
+ return $responseData;
71
+ }
72
+
73
+ /**
74
+ * @param string[] $headers
75
+ * @return string
76
+ */
77
+ private function prepareRequestHeaders($headers)
78
+ {
79
+ $headerString = '';
80
+ foreach ($headers as $header) {
81
+ $headerString .= $header . "\r\n";
82
+ }
83
+
84
+ return $headerString;
85
+ }
86
+
87
+ /**
88
+ * @param string|false $response
89
+ * @return array<string, mixed>
90
+ */
91
+ private function parseResponseData($response)
92
+ {
93
+ if (false === $response) {
94
+ return [];
95
+ }
96
+
97
+ return json_decode($response, true);
98
+ }
99
+
100
+ /**
101
+ * @param array<string, mixed> $responseData
102
+ * @param string[] $responseHeaders
103
+ * @throws TidioApiException
104
+ */
105
+ private function validateResponse($responseData, $responseHeaders)
106
+ {
107
+ $statusCode = $this->parseStatusCodeFromHeaders($responseHeaders);
108
+ if ($statusCode === 401) {
109
+ throw TidioApiException::withUnauthorizedErrorCode();
110
+ } elseif ($statusCode < 200 || $statusCode >= 300) {
111
+ if (isset($responseData['error'])) {
112
+ throw TidioApiException::withErrorCode($responseData['error']);
113
+ }
114
+
115
+ throw TidioApiException::withUnknownErrorCode();
116
+ }
117
+ }
118
+
119
+ /**
120
+ * @param string[] $responseHeaders
121
+ * @return int
122
+ */
123
+ private function parseStatusCodeFromHeaders($responseHeaders)
124
+ {
125
+ $statusCodeFallback = 500;
126
+ if (!isset($responseHeaders[0])) {
127
+ // cannot retrieve status code from headers, return 500 as fallback
128
+ return $statusCodeFallback;
129
+ }
130
+
131
+ $responseStatusHeader = $responseHeaders[0];
132
+ preg_match('/^HTTP\/\S*\s(\d{3})\s.+$/', $responseStatusHeader, $statusCodeResult);
133
+
134
+ $statusCode = end($statusCodeResult);
135
+ return $statusCode ? (int) $statusCode : $statusCodeFallback;
136
+ }
137
+ }
src/Sdk/Api/Client/TidioApiClientFactory.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioApiClientFactory
4
+ {
5
+ /**
6
+ * @return TidioApiClient
7
+ */
8
+ public function create()
9
+ {
10
+ if (function_exists('curl_version')) {
11
+ return new CurlTidioApiClient();
12
+ }
13
+
14
+ return new FileGetContentsTidioApiClient();
15
+ }
16
+
17
+ /**
18
+ * @param string $token
19
+ * @return TidioApiClient
20
+ */
21
+ public function createAuthenticated($token)
22
+ {
23
+ $authorizationHeader = ['Authorization: Bearer ' . $token];
24
+ if (function_exists('curl_version')) {
25
+ return new CurlTidioApiClient($authorizationHeader);
26
+ }
27
+
28
+ return new FileGetContentsTidioApiClient($authorizationHeader);
29
+ }
30
+ }
src/Sdk/Api/Exception/TidioApiException.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioApiException extends \Exception
4
+ {
5
+ const UNAUTHORIZED_ERROR_CODE = 'unauthorized';
6
+ const UNKNOWN_ERROR_CODE = 'unknown_error';
7
+
8
+ /**
9
+ * @param string $errorCode
10
+ * @return TidioApiException
11
+ */
12
+ public static function withErrorCode($errorCode)
13
+ {
14
+ return new self($errorCode);
15
+ }
16
+
17
+ /**
18
+ * @return TidioApiException
19
+ */
20
+ public static function withUnauthorizedErrorCode()
21
+ {
22
+ return new self(self::UNAUTHORIZED_ERROR_CODE);
23
+ }
24
+
25
+ /**
26
+ * @return TidioApiException
27
+ */
28
+ public static function withUnknownErrorCode()
29
+ {
30
+ return new self(self::UNKNOWN_ERROR_CODE);
31
+ }
32
+ }
src/Sdk/Api/TidioApiClient.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface TidioApiClient
4
+ {
5
+ /**
6
+ * @param string $path
7
+ * @param array<string, mixed> $data
8
+ * @return array<string, mixed>
9
+ * @throws TidioApiException
10
+ */
11
+ public function sendPostRequest($path, $data = []);
12
+
13
+ /**
14
+ * @param string $path
15
+ * @return array<string, mixed>
16
+ * @throws TidioApiException
17
+ */
18
+ public function sendGetRequest($path);
19
+ }
src/Sdk/Encryption/Exception/TidioDecryptionFailedException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioDecryptionFailedException extends \Exception
4
+ {
5
+ const INVALID_HASH_ERROR_CODE = 'invalid_hash';
6
+
7
+ /**
8
+ * @return TidioDecryptionFailedException
9
+ */
10
+ public static function withInvalidHashErrorCode()
11
+ {
12
+ return new self(self::INVALID_HASH_ERROR_CODE);
13
+ }
14
+ }
src/Sdk/Encryption/Service/OpenSslTidioEncryptionService.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class OpenSslTidioEncryptionService implements TidioEncryptionService
4
+ {
5
+ const CIPHER_ALGORITHM = 'aes-256-ctr';
6
+ const HASH_ALGORITHM = 'sha256';
7
+ const HASH_LENGTH = 32;
8
+
9
+ /**
10
+ * @var string
11
+ */
12
+ private $encryptionKey;
13
+ /**
14
+ * @var int
15
+ */
16
+ private $ivLength;
17
+
18
+ public function __construct($encryptionKey)
19
+ {
20
+ $this->encryptionKey = $encryptionKey;
21
+ $this->ivLength = openssl_cipher_iv_length(self::CIPHER_ALGORITHM);
22
+ }
23
+
24
+ /**
25
+ * @inerhitDoc
26
+ */
27
+ public function encrypt($value)
28
+ {
29
+ $iv = openssl_random_pseudo_bytes($this->ivLength);
30
+ $encryptedValue = openssl_encrypt($value, self::CIPHER_ALGORITHM, $this->encryptionKey, 0, $iv);
31
+ $hmac = hash_hmac(self::HASH_ALGORITHM, $encryptedValue, $this->encryptionKey, true);
32
+
33
+ return base64_encode($iv . $hmac . $encryptedValue);
34
+ }
35
+
36
+ /**
37
+ * @inerhitDoc
38
+ */
39
+ public function decrypt($encryptedString)
40
+ {
41
+ $encryptedString = base64_decode($encryptedString, true);
42
+
43
+ $iv = substr($encryptedString, 0, $this->ivLength);
44
+ $hmac = substr($encryptedString, $this->ivLength, self::HASH_LENGTH);
45
+ $encryptedValue = substr($encryptedString, $this->ivLength + self::HASH_LENGTH);
46
+
47
+ $hashToCompare = hash_hmac(self::HASH_ALGORITHM, $encryptedValue, $this->encryptionKey, true);
48
+ if (!hash_equals($hmac, $hashToCompare)) {
49
+ throw TidioDecryptionFailedException::withInvalidHashErrorCode();
50
+ }
51
+
52
+ return openssl_decrypt($encryptedValue, self::CIPHER_ALGORITHM, $this->encryptionKey, 0, $iv);
53
+ }
54
+ }
src/Sdk/Encryption/Service/PlainTextTidioEncryptionService.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class PlainTextTidioEncryptionService implements TidioEncryptionService
4
+ {
5
+ /**
6
+ * @inerhitDoc
7
+ */
8
+ public function encrypt($value)
9
+ {
10
+ return $value;
11
+ }
12
+
13
+ /**
14
+ * @inerhitDoc
15
+ */
16
+ public function decrypt($encryptedString)
17
+ {
18
+ return $encryptedString;
19
+ }
20
+ }
src/Sdk/Encryption/Service/TidioEncryptionServiceFactory.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioEncryptionServiceFactory
4
+ {
5
+ public function create()
6
+ {
7
+ $encryptionKey = $this->getEncryptionKey();
8
+ if (empty($encryptionKey) || !extension_loaded('openssl')) {
9
+ return new PlainTextTidioEncryptionService();
10
+ }
11
+
12
+ return new OpenSslTidioEncryptionService($encryptionKey);
13
+ }
14
+
15
+ /**
16
+ * @return string|null
17
+ */
18
+ private function getEncryptionKey()
19
+ {
20
+ if (!defined('LOGGED_IN_KEY')) {
21
+ return null;
22
+ }
23
+
24
+ return LOGGED_IN_KEY;
25
+ }
26
+ }
src/Sdk/Encryption/TidioEncryptionService.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface TidioEncryptionService
4
+ {
5
+ /**
6
+ * @param string $value
7
+ * @return string
8
+ */
9
+ public function encrypt($value);
10
+
11
+ /**
12
+ * @param string $encryptedString
13
+ * @return string
14
+ * @throws TidioDecryptionFailedException
15
+ */
16
+ public function decrypt($encryptedString);
17
+ }
src/Sdk/TidioIntegrationFacade.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioIntegrationFacade
4
+ {
5
+ const TIDIO_WORDPRESS_OAUTH_CLIENT_ID = '8ea883be-28c3-4bfd-9fe2-4091eb38fe08';
6
+
7
+ /**
8
+ * @var TidioApiClientFactory
9
+ */
10
+ private $apiClientFactory;
11
+
12
+ /**
13
+ * @param TidioApiClientFactory $apiClientFactory
14
+ */
15
+ public function __construct($apiClientFactory)
16
+ {
17
+ $this->apiClientFactory = $apiClientFactory;
18
+ }
19
+
20
+ /**
21
+ * @param string $refreshToken
22
+ * @return array<string, mixed>
23
+ * @throws TidioApiException
24
+ */
25
+ public function integrateProject($refreshToken)
26
+ {
27
+ $apiClient = $this->apiClientFactory->create();
28
+ $tokens = $apiClient->sendPostRequest('/platforms/oauth/access_token', [
29
+ 'grant_type' => 'refresh_token',
30
+ 'client_id' => self::TIDIO_WORDPRESS_OAUTH_CLIENT_ID,
31
+ 'refresh_token' => $refreshToken
32
+ ]);
33
+
34
+ $apiClient = $this->apiClientFactory->createAuthenticated($tokens['access_token']);
35
+ $data = $apiClient->sendPostRequest('/platforms/wordpress/integrate');
36
+
37
+ return [
38
+ 'projectPublicKey' => $data['projectPublicKey'],
39
+ 'accessToken' => $tokens['access_token'],
40
+ 'refreshToken' => $tokens['refresh_token']
41
+ ];
42
+ }
43
+ }
src/TidioIntegrationState.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioIntegrationState
4
+ {
5
+ const PUBLIC_KEY_OPTION = 'tidio-one-public-key';
6
+ const PRIVATE_KEY_OPTION = 'tidio-one-private-key';
7
+ const ASYNC_LOAD_OPTION = 'tidio-async-load';
8
+ const TIDIO_OAUTH_ACCESS_TOKEN_KEY = 'tidio-access-token';
9
+ const TIDIO_OAUTH_REFRESH_TOKEN_KEY = 'tidio-refresh-token';
10
+
11
+ /**
12
+ * @var OpenSslTidioEncryptionService
13
+ */
14
+ private $encryptionService;
15
+
16
+ /**
17
+ * @param OpenSslTidioEncryptionService $encryptionService
18
+ */
19
+ public function __construct($encryptionService)
20
+ {
21
+ $this->encryptionService = $encryptionService;
22
+ }
23
+
24
+ /**
25
+ * @return string|null
26
+ */
27
+ public function getProjectPublicKey()
28
+ {
29
+ return get_option(self::PUBLIC_KEY_OPTION, null);
30
+ }
31
+
32
+ /**
33
+ * @return string|null
34
+ */
35
+ public function getProjectPrivateKey()
36
+ {
37
+ return get_option(self::PRIVATE_KEY_OPTION, null);
38
+ }
39
+
40
+ /**
41
+ * @return bool
42
+ */
43
+ public function hasProjectPrivateKey()
44
+ {
45
+ return !empty(get_option(self::PRIVATE_KEY_OPTION));
46
+ }
47
+
48
+ /**
49
+ * @return bool
50
+ */
51
+ public function isPluginIntegrated()
52
+ {
53
+ return !empty(get_option(self::PUBLIC_KEY_OPTION));
54
+ }
55
+
56
+ /**
57
+ * @return bool
58
+ */
59
+ public function isAsyncLoadingTurnedOn()
60
+ {
61
+ return (bool) get_option(self::ASYNC_LOAD_OPTION);
62
+ }
63
+
64
+ public function integrate($projectPublicKey, $accessToken, $refreshToken)
65
+ {
66
+ $encryptedRefreshToken = $this->encryptionService->encrypt($refreshToken);
67
+
68
+ update_option(self::PUBLIC_KEY_OPTION, $projectPublicKey);
69
+ update_option(self::TIDIO_OAUTH_ACCESS_TOKEN_KEY, $accessToken);
70
+ update_option(self::TIDIO_OAUTH_REFRESH_TOKEN_KEY, $encryptedRefreshToken);
71
+ update_option(self::ASYNC_LOAD_OPTION, true);
72
+ }
73
+
74
+ public function removeIntegration()
75
+ {
76
+ delete_option(self::PUBLIC_KEY_OPTION);
77
+ delete_option(self::TIDIO_OAUTH_ACCESS_TOKEN_KEY);
78
+ delete_option(self::TIDIO_OAUTH_REFRESH_TOKEN_KEY);
79
+ delete_option(self::ASYNC_LOAD_OPTION);
80
+ delete_option(self::PRIVATE_KEY_OPTION);
81
+ }
82
+
83
+ public function turnOnAsyncLoading()
84
+ {
85
+ update_option(self::ASYNC_LOAD_OPTION, true);
86
+ }
87
+
88
+ public function toggleAsyncLoading()
89
+ {
90
+ update_option(self::ASYNC_LOAD_OPTION, !$this->isAsyncLoadingTurnedOn());
91
+ }
92
+ }
src/TidioLiveChat.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioLiveChat
4
+ {
5
+ const TIDIO_PLUGIN_NAME = 'tidio-live-chat';
6
+
7
+ public static function load()
8
+ {
9
+ $encryptionService = (new TidioEncryptionServiceFactory())->create();
10
+ $integrationState = new TidioIntegrationState($encryptionService);
11
+ if (!is_admin()) {
12
+ new TidioWidgetLoader($integrationState);
13
+ return;
14
+ }
15
+
16
+ if (current_user_can('activate_plugins')) {
17
+ new TidioTranslationLoader();
18
+ $apiClientFactory = new TidioApiClientFactory();
19
+ $integrationFacade = new TidioIntegrationFacade($apiClientFactory);
20
+ $adminController = new TidioAdminController($integrationFacade, $integrationState);
21
+ $iframeSetup = new TidioIframeSetup($integrationState);
22
+ $errorTranslator = new TidioErrorTranslator();
23
+
24
+ new TidioAdminRouting($adminController);
25
+ new TidioAdminActionLink($integrationState);
26
+ new TidioAdminDashboard($integrationState, $iframeSetup);
27
+ new TidioAdminNotice($errorTranslator);
28
+ }
29
+ }
30
+ }
src/TidioLiveChatConfig.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ final class TidioLiveChatConfig
4
+ {
5
+ /**
6
+ * @var array|null
7
+ */
8
+ private static $config = null;
9
+
10
+ /**
11
+ * @return string
12
+ */
13
+ public static function getApiUrl()
14
+ {
15
+ return self::getConfig()['tidio_api_url'];
16
+ }
17
+
18
+ /**
19
+ * @return string
20
+ */
21
+ public static function getPanelUrl()
22
+ {
23
+ return self::getConfig()['tidio_panel_url'];
24
+ }
25
+
26
+ /**
27
+ * @return string
28
+ */
29
+ public static function getWidgetUrl()
30
+ {
31
+ return self::getConfig()['tidio_widget_url'];
32
+ }
33
+
34
+ /**
35
+ * @return array<string, string>
36
+ */
37
+ private static function getConfig()
38
+ {
39
+ if (self::$config === null) {
40
+ self::$config = require __DIR__ . '/../config.php';
41
+ }
42
+
43
+ return self::$config;
44
+ }
45
+ }
src/Translation/TidioErrorTranslator.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioErrorTranslator
4
+ {
5
+ const ERROR_CODE_FALLBACK_MESSAGE = 'The integration process has been interrupted. An error has occurred (%s). Please try again later or contact our support team.';
6
+
7
+ /**
8
+ * @param string $errorCode
9
+ * @return string
10
+ */
11
+ public function translate($errorCode)
12
+ {
13
+ return sprintf(i18n::_t(self::ERROR_CODE_FALLBACK_MESSAGE), $errorCode);
14
+ }
15
+ }
src/Translation/TidioTranslationLoader.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioTranslationLoader
4
+ {
5
+ public function __construct()
6
+ {
7
+ add_filter('load_textdomain_mofile', [$this, 'loadTextDomain'], 10, 2);
8
+ load_plugin_textdomain(TidioLiveChat::TIDIO_PLUGIN_NAME);
9
+ }
10
+
11
+ /**
12
+ * @param string $mofile
13
+ * @param string $domain
14
+ * @return string
15
+ */
16
+ public function loadTextDomain($mofile, $domain)
17
+ {
18
+ if (TidioLiveChat::TIDIO_PLUGIN_NAME === $domain && false !== strpos($mofile, WP_LANG_DIR . '/plugins/')) {
19
+ $userId = get_current_user_id();
20
+ $userLocaleCode = get_user_locale($userId);
21
+
22
+ $locale = apply_filters('plugin_locale', $userLocaleCode, $domain);
23
+ $mofile = sprintf('%s/%s/../../languages/%s-%s.mo', WP_PLUGIN_DIR, dirname(plugin_basename(__FILE__)), $domain, $locale);
24
+ }
25
+
26
+ return $mofile;
27
+ }
28
+ }
src/Translation/i18n.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class i18n
4
+ {
5
+ /**
6
+ * echo translation
7
+ */
8
+ public static function _e($message)
9
+ {
10
+ _e($message, TidioLiveChat::TIDIO_PLUGIN_NAME);
11
+ }
12
+
13
+ /**
14
+ * returns translation
15
+ */
16
+ public static function _t($message)
17
+ {
18
+ return __($message, TidioLiveChat::TIDIO_PLUGIN_NAME);
19
+ }
20
+ }
src/Utils/QueryParameters.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class QueryParameters
4
+ {
5
+ /**
6
+ * @param string $key
7
+ * @return bool
8
+ */
9
+ public static function has($key)
10
+ {
11
+ return isset($_GET[$key]);
12
+ }
13
+
14
+ /**
15
+ * @param string $key
16
+ * @return string|null
17
+ */
18
+ public static function get($key)
19
+ {
20
+ if (!self::has($key)) {
21
+ return null;
22
+ }
23
+
24
+ return sanitize_text_field($_GET[$key]);
25
+ }
26
+ }
src/Widget/TidioWidgetLoader.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class TidioWidgetLoader
4
+ {
5
+ /**
6
+ * @var TidioIntegrationState
7
+ */
8
+ private $integrationState;
9
+
10
+ /**
11
+ * @param TidioIntegrationState $integrationState
12
+ */
13
+ public function __construct($integrationState)
14
+ {
15
+ $this->integrationState = $integrationState;
16
+
17
+ if (!$this->integrationState->isPluginIntegrated()) {
18
+ return;
19
+ }
20
+
21
+ add_action('wp_head', [$this,'addPreconnectLink']);
22
+ if ($this->integrationState->isAsyncLoadingTurnedOn()) {
23
+ add_action('wp_footer', [$this, 'enqueueScriptsAsync'], PHP_INT_MAX);
24
+ return;
25
+ }
26
+
27
+ add_action('wp_enqueue_scripts', [$this, 'enqueueScriptsSync'], 1000);
28
+ }
29
+
30
+ public function addPreconnectLink() {
31
+ echo '<link rel="preconnect" href="//code.tidio.co">';
32
+ }
33
+
34
+ public function enqueueScriptsAsync()
35
+ {
36
+ $publicKey = $this->integrationState->getProjectPublicKey();
37
+ $widgetUrl = sprintf('%s/%s.js', TidioLiveChatConfig::getWidgetUrl(), $publicKey);
38
+ $asyncScript = <<<SRC
39
+ <script type='text/javascript'>
40
+ document.tidioChatCode = "$publicKey";
41
+ (function() {
42
+ function asyncLoad() {
43
+ var tidioScript = document.createElement("script");
44
+ tidioScript.type = "text/javascript";
45
+ tidioScript.async = true;
46
+ tidioScript.src = "{$widgetUrl}";
47
+ document.body.appendChild(tidioScript);
48
+ }
49
+ if (window.attachEvent) {
50
+ window.attachEvent("onload", asyncLoad);
51
+ } else {
52
+ window.addEventListener("load", asyncLoad, false);
53
+ }
54
+ })();
55
+ </script>
56
+ SRC;
57
+ echo $asyncScript;
58
+ }
59
+
60
+ public function enqueueScriptsSync()
61
+ {
62
+ $projectPublicKey = $this->integrationState->getProjectPublicKey();
63
+
64
+ $widgetUrl = sprintf('%s/%s.js', TidioLiveChatConfig::getWidgetUrl(), $projectPublicKey);
65
+ wp_enqueue_script(TidioLiveChat::TIDIO_PLUGIN_NAME, $widgetUrl, [], TIDIOCHAT_VERSION, true);
66
+
67
+ $inlineScriptWithProjectPublicKeyVariable = sprintf('document.tidioChatCode = "%s";', $projectPublicKey);
68
+ wp_add_inline_script(TidioLiveChat::TIDIO_PLUGIN_NAME, $inlineScriptWithProjectPublicKeyVariable, 'before');
69
+ }
70
+ }
tidio-elements.php CHANGED
@@ -4,478 +4,54 @@
4
  * Plugin Name: Tidio Chat
5
  * Plugin URI: http://www.tidio.com
6
  * Description: Tidio Live Chat - live chat boosted with chatbots for your online business. Integrates with your website in less than 20 seconds.
7
- * Version: 4.5.1
8
  * Author: Tidio Ltd.
9
  * Author URI: http://www.tidio.com
10
  * Text Domain: tidio-live-chat
11
  * Domain Path: /languages/
12
  * License: GPL2
13
  */
14
- define('TIDIOCHAT_VERSION', '4.5.1');
15
- define('AFFILIATE_CONFIG_FILE_PATH', get_template_directory().'/tidio_affiliate_ref_id.txt');
16
-
17
- class TidioLiveChat
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  {
19
- const PUBLIC_KEY_OPTION = 'tidio-one-public-key';
20
- const PRIVATE_KEY_OPTION = 'tidio-one-private-key';
21
- const ASYNC_LOAD_OPTION = 'tidio-async-load';
22
- const CLEAR_ACCOUNT_DATA_ACTION = 'tidio-chat-reset';
23
- const TIDIO_PLUGIN_NAME = 'tidio-live-chat';
24
- const TOGGLE_ASYNC_ACTION = 'tidio-chat-toggle-async';
25
- const TIDIO_ICON_BASE64 = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIzLjEuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IldhcnN0d2FfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgdmlld0JveD0iMCAwIDIwIDIwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMCAyMDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiNBMEE1QUE7fQo8L3N0eWxlPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMiwxOHYtNS45YzAtMi43LDEuNy01LDQuMy01LjdDNy4xLDMuNyw5LjQsMiwxMi4xLDJDMTUuNCwyLDE4LDQuNiwxOCw3Ljl2NS45aC00LjVsMCwwLjEKCWMtMC44LDIuNS0zLDQuMS01LjYsNC4xSDJ6IE02LjEsOC4xTDYuMSw4LjFjLTEuNiwwLjctMi42LDIuMy0yLjYsNC4xdjQuNGg0LjRjMS44LDAsMy4zLTEsNC4xLTIuNmwwLTAuMWwtMC4xLDAKCWMtMy4xLTAuMi01LjYtMi43LTUuNy01LjZsMC0wLjFMNi4xLDguMXogTTEyLjEsMy41Yy0xLjgsMC0zLjMsMS00LjEsMi42bDAsMC4xbDAuMSwwYzMuMiwwLjEsNS43LDIuNyw1LjcsNS45djAuMWwwLjEsMC4xaDIuN1Y3LjkKCUMxNi41LDUuNSwxNC41LDMuNSwxMi4xLDMuNXogTTcuNiw3LjhMNy42LDcuOGMwLDIuNSwyLDQuNSw0LjQsNC41aDAuMWwwLjEtMC4xYzAtMi41LTItNC41LTQuNC00LjVINy43TDcuNiw3Ljh6Ii8+Cjwvc3ZnPgo=';
26
- const TIDIO_XHR_NONCE_NAME = 'tidio-xhr-nonce';
27
-
28
- public function __construct()
29
- {
30
- if (!empty($_GET['tidio_chat_version'])) {
31
- echo TIDIOCHAT_VERSION;
32
- exit;
33
- }
34
-
35
- /* load plugin translations*/
36
- add_filter('load_textdomain_mofile', [$this, 'loadTextDomain'], 10, 2);
37
- load_plugin_textdomain(self::TIDIO_PLUGIN_NAME);
38
-
39
- /* Before add link to menu - check is user trying to unninstal */
40
- if (is_admin() && current_user_can('activate_plugins') && !empty($_GET['tidio_one_clear_cache'])) {
41
- delete_option(TidioLiveChat::PUBLIC_KEY_OPTION);
42
- delete_option(TidioLiveChat::PRIVATE_KEY_OPTION);
43
- }
44
-
45
- if (get_option(TidioLiveChat::PUBLIC_KEY_OPTION)) {
46
- add_action('admin_footer', array($this, 'adminJS'));
47
- }
48
-
49
- if (!is_admin()) {
50
- add_action('wp_head', array($this,'addPreconnectLink'));
51
- if (get_option(TidioLiveChat::ASYNC_LOAD_OPTION)) {
52
- add_action('wp_footer', array($this, 'enqueueScriptsAsync'), PHP_INT_MAX);
53
- } else {
54
- add_action('wp_enqueue_scripts', array($this, 'enqueueScriptsSync'), 1000);
55
- }
56
- } else if (current_user_can('activate_plugins')) {
57
- add_action('admin_menu', array($this, 'addAdminMenuLink'));
58
- add_action('admin_enqueue_scripts', array($this, 'enqueueAdminScripts'));
59
- add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScriptTranslation']);
60
-
61
- add_action('wp_ajax_tidio_chat_save_keys', array($this, 'ajaxTidioChatSaveKeys'));
62
- add_action('wp_ajax_set_project_keys', array($this, 'ajaxSetProjectKeys'));
63
- add_action('wp_ajax_get_private_key', array($this, 'ajaxGetPrivateKey'));
64
-
65
- add_action('admin_post_' . TidioLiveChat::CLEAR_ACCOUNT_DATA_ACTION . '', array($this, 'uninstall'));
66
- add_action('admin_post_' . TidioLiveChat::TOGGLE_ASYNC_ACTION . '', array($this, 'toggleAsync'));
67
-
68
- add_filter('plugin_action_links', array($this, 'pluginActionLinks'), 10, 2);
69
- }
70
- }
71
-
72
- public function loadTextDomain($mofile, $domain)
73
- {
74
- if ('tidio-live-chat' === $domain && false !== strpos($mofile, WP_LANG_DIR . '/plugins/')) {
75
- $locale = apply_filters('plugin_locale', determine_locale(), $domain);
76
- $mofile = WP_PLUGIN_DIR . '/' . dirname(plugin_basename(__FILE__)) . '/languages/' . $domain . '-' . $locale . '.mo';
77
- }
78
-
79
- return $mofile;
80
- }
81
-
82
- public static function activate()
83
- {
84
- update_option(TidioLiveChat::ASYNC_LOAD_OPTION, true);
85
- }
86
-
87
- public static function ajaxGetPrivateKey()
88
- {
89
- check_ajax_referer(TidioLiveChat::TIDIO_XHR_NONCE_NAME);
90
-
91
- $privateKey = TidioLiveChat::getPrivateKey();
92
- if (!$privateKey || $privateKey == 'false') {
93
- echo 'error';
94
- exit();
95
- }
96
- echo TidioLiveChat::getRedirectUrl($privateKey);
97
- exit();
98
- }
99
-
100
- public static function getPrivateKey()
101
- {
102
- TidioLiveChat::syncPrivateKey();
103
-
104
- $privateKey = get_option(TidioLiveChat::PRIVATE_KEY_OPTION);
105
-
106
- if ($privateKey) {
107
- return $privateKey;
108
- }
109
-
110
- try {
111
- $data = TidioLiveChat::getContent(TidioLiveChat::getAccessUrl());
112
- } catch (Exception $e) {
113
- $data = null;
114
- }
115
- //
116
- if (!$data) {
117
- update_option(TidioLiveChat::PRIVATE_KEY_OPTION, 'false');
118
- return false;
119
- }
120
-
121
- @$data = json_decode($data, true);
122
- if (!$data || !$data['status']) {
123
- update_option(TidioLiveChat::PRIVATE_KEY_OPTION, 'false');
124
- return false;
125
- }
126
-
127
- update_option(TidioLiveChat::PRIVATE_KEY_OPTION, $data['value']['private_key']);
128
- update_option(TidioLiveChat::PUBLIC_KEY_OPTION, $data['value']['public_key']);
129
- update_option(TidioLiveChat::ASYNC_LOAD_OPTION, true);
130
-
131
- return $data['value']['private_key'];
132
- }
133
-
134
- public static function syncPrivateKey()
135
- {
136
- if (get_option(TidioLiveChat::PUBLIC_KEY_OPTION)) {
137
- return false;
138
- }
139
-
140
- $publicKey = get_option('tidio-chat-external-public-key');
141
- $privateKey = get_option('tidio-chat-external-private-key');
142
-
143
- if (!$publicKey || !$privateKey) {
144
- return false;
145
- }
146
-
147
- // sync old variables with new one
148
-
149
- update_option(TidioLiveChat::PUBLIC_KEY_OPTION, $publicKey);
150
- update_option(TidioLiveChat::PRIVATE_KEY_OPTION, $privateKey);
151
-
152
- return true;
153
- }
154
-
155
- public static function getContent($url)
156
- {
157
-
158
- if (function_exists('curl_version')) { // load through curl
159
- $ch = curl_init();
160
-
161
- curl_setopt($ch, CURLOPT_HEADER, 0);
162
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
163
- curl_setopt($ch, CURLOPT_URL, $url);
164
-
165
- $data = curl_exec($ch);
166
- curl_close($ch);
167
-
168
- return $data;
169
- } else { // load through file get contents
170
- return file_get_contents($url);
171
- }
172
- }
173
-
174
- public static function readRefIDFromFile() {
175
- try {
176
- $loadedRefIdFromFile = @file_get_contents(AFFILIATE_CONFIG_FILE_PATH);
177
- return trim($loadedRefIdFromFile);
178
- } catch (Exception $e){}
179
- return null;
180
- }
181
-
182
- public static function getAccessUrl()
183
- {
184
- $parameters = array(
185
- 'url' => site_url(),
186
- 'platform' => 'wordpress',
187
- 'email' => get_option('admin_email'),
188
- '_ip' => $_SERVER['REMOTE_ADDR'],
189
- );
190
- $refIdFromFile = TidioLiveChat::readRefIDFromFile();
191
- if (isset($refIdFromFile)) {
192
- $parameters['ref_id'] = $refIdFromFile;
193
- }
194
- $accessUrlParameters = http_build_query($parameters);
195
- return TidioLiveChatConfig::getApiUrl() . '/access/external/create?'.$accessUrlParameters;
196
- }
197
-
198
- public static function getRedirectUrl($privateKey)
199
- {
200
- return TidioLiveChatConfig::getPanelUrl() . '/panel/external-access?' . http_build_query(
201
- array(
202
- 'privateKey' => $privateKey,
203
- 'utm_source' => 'platform',
204
- 'utm_medium' => 'wordpress'
205
- )
206
- );
207
- }
208
-
209
- public function pluginActionLinks($links, $file)
210
- {
211
- if (strpos($file, basename(__FILE__)) !== false) {
212
- if (get_option(TidioLiveChat::PRIVATE_KEY_OPTION)) {
213
- $queryString = http_build_query(
214
- array(
215
- 'action' => TidioLiveChat::CLEAR_ACCOUNT_DATA_ACTION,
216
- '_wpnonce' => wp_create_nonce(TidioLiveChat::CLEAR_ACCOUNT_DATA_ACTION),
217
- )
218
- );
219
- $links[] = '<a href="' . admin_url('admin-post.php') . '?' . $queryString . '">' . esc_html(i18n::_t('Clear Account Data')) . '</a>';
220
-
221
- if (get_option(TidioLiveChat::ASYNC_LOAD_OPTION)) {
222
- $toggleAsyncLabel = '✓';
223
- $onclickPart = 'onclick="return confirm(\''.i18n::_t('Disabling asynchronous loading of the chat widget may affect the page loading time of your website. Are you sure you want to disable the asynchronous loading?').'\');"';
224
- } else {
225
- $toggleAsyncLabel = '✘';
226
- $onclickPart = '';
227
- }
228
- $queryString = http_build_query(
229
- array(
230
- 'action' => TidioLiveChat::TOGGLE_ASYNC_ACTION,
231
- '_wpnonce' => wp_create_nonce(TidioLiveChat::TOGGLE_ASYNC_ACTION),
232
- )
233
- );
234
- $links[] = '<a href="' . admin_url('admin-post.php') . '?' . $queryString . '" ' . $onclickPart . '>' . esc_html($toggleAsyncLabel . ' ' . i18n::_t('Asynchronous loading')) . '</a>';
235
- }
236
- }
237
-
238
- return $links;
239
- }
240
-
241
- public function toggleAsync()
242
- {
243
- if (wp_verify_nonce($_GET['_wpnonce'], TidioLiveChat::TOGGLE_ASYNC_ACTION) === false) {
244
- wp_die('', 403);
245
- }
246
-
247
- update_option(TidioLiveChat::ASYNC_LOAD_OPTION, !get_option(TidioLiveChat::ASYNC_LOAD_OPTION));
248
- wp_redirect(admin_url('plugins.php'));
249
- die();
250
- }
251
-
252
- public function ajaxSetProjectKeys()
253
- {
254
- check_ajax_referer(TidioLiveChat::TIDIO_XHR_NONCE_NAME);
255
-
256
- update_option(TidioLiveChat::PUBLIC_KEY_OPTION, $_POST['public_key']);
257
- update_option(TidioLiveChat::PRIVATE_KEY_OPTION, $_POST['private_key']);
258
-
259
- $query = http_build_query(array(
260
- 'api_token' => $_POST['api_token'],
261
- 'project_public_key' => $_POST['public_key']
262
- ));
263
-
264
- $options = array('http' => array('method' => 'POST'));
265
-
266
- $context = stream_context_create($options);
267
- @file_get_contents(TidioLiveChatConfig::getApiUrl() . '/access/connectWordpress?' . $query, false, $context);
268
-
269
- echo TidioLiveChat::getRedirectUrl($_POST['private_key']);
270
- exit();
271
- }
272
-
273
- public function ajaxTidioChatSaveKeys()
274
- {
275
- if (!is_admin()) {
276
- exit;
277
- }
278
-
279
- check_ajax_referer(TidioLiveChat::TIDIO_XHR_NONCE_NAME);
280
-
281
- if (empty($_POST['private_key']) || empty($_POST['public_key'])) {
282
- exit;
283
- }
284
-
285
- update_option(TidioLiveChat::PUBLIC_KEY_OPTION, $_POST['public_key']);
286
- update_option(TidioLiveChat::PRIVATE_KEY_OPTION, $_POST['private_key']);
287
-
288
- echo '1';
289
  exit;
290
  }
291
 
292
- public function addPreconnectLink() {
293
- echo '<link rel="preconnect" href="//code.tidio.co">';
294
- }
295
-
296
- public function enqueueScriptsAsync()
297
- {
298
- $publicKey = TidioLiveChat::getPublicKey();
299
- $widgetUrl = TidioLiveChatConfig::getWidgetUrl() . '/' . $publicKey . '.js';
300
- $asyncScript = <<<SRC
301
- <script type='text/javascript'>
302
- document.tidioChatCode = "$publicKey";
303
- (function() {
304
- function asyncLoad() {
305
- var tidioScript = document.createElement("script");
306
- tidioScript.type = "text/javascript";
307
- tidioScript.async = true;
308
- tidioScript.src = "{$widgetUrl}";
309
- document.body.appendChild(tidioScript);
310
- }
311
- if (window.attachEvent) {
312
- window.attachEvent("onload", asyncLoad);
313
- } else {
314
- window.addEventListener("load", asyncLoad, false);
315
- }
316
- })();
317
- </script>
318
- SRC;
319
- echo $asyncScript;
320
- }
321
-
322
- public static function getPublicKey()
323
- {
324
- $publicKey = get_option(TidioLiveChat::PUBLIC_KEY_OPTION);
325
-
326
- if ($publicKey) {
327
- return $publicKey;
328
- }
329
-
330
- TidioLiveChat::getPrivateKey();
331
-
332
- return get_option(TidioLiveChat::PUBLIC_KEY_OPTION);
333
- }
334
-
335
- public function enqueueScriptsSync()
336
- {
337
- wp_enqueue_script('tidio-chat', TidioLiveChatConfig::getWidgetUrl() . '/' . TidioLiveChat::getPublicKey() . '.js', array(),
338
- TIDIOCHAT_VERSION,
339
- true);
340
- wp_add_inline_script('tidio-chat', 'document.tidioChatCode = "' . TidioLiveChat::getPublicKey() . '";',
341
- 'before');
342
- }
343
-
344
- public function enqueueAdminScriptTranslation()
345
- {
346
- $langDir = plugin_dir_path(__FILE__) . 'languages/js/';
347
-
348
- wp_set_script_translations('tidio-chat-admin', 'tidio-live-chat', $langDir);
349
- }
350
-
351
- public function enqueueAdminScripts()
352
- {
353
- $tidioConfig = [
354
- 'nonce' => wp_create_nonce(self::TIDIO_XHR_NONCE_NAME),
355
- 'apiUrl' => TidioLiveChatConfig::getApiUrl(),
356
- 'panelUrl' => TidioLiveChatConfig::getPanelUrl()
357
- ];
358
-
359
- wp_enqueue_script('tidio-chat-admin', plugins_url('media/js/options.js', __FILE__), ['wp-i18n'], TIDIOCHAT_VERSION, true);
360
- wp_add_inline_script('tidio-chat-admin', sprintf('const tidioConfig = %s', json_encode($tidioConfig)), 'before');
361
- wp_enqueue_style('tidio-chat-admin-style', plugins_url('media/css/options.css', __FILE__), array(), TIDIOCHAT_VERSION);
362
- }
363
-
364
- public function adminJS()
365
- {
366
- $privateKey = TidioLiveChat::getPrivateKey();
367
- $redirectUrl = '';
368
-
369
- if ($privateKey && $privateKey != 'false') {
370
- $redirectUrl = TidioLiveChat::getRedirectUrl($privateKey);
371
- } else {
372
- $redirectUrl = admin_url('admin-ajax.php?action=tidio_chat_redirect');
373
- }
374
-
375
- echo "<script>jQuery('a[href=\"admin.php?page=tidio-chat\"]').attr('href', '" . $redirectUrl . "').attr('target', '_blank') </script>";
376
- }
377
-
378
- public function addAdminMenuLink()
379
- {
380
- add_menu_page(
381
- 'Tidio Chat',
382
- 'Tidio Chat',
383
- 'manage_options',
384
- 'tidio-chat',
385
- array($this, 'addAdminPage'),
386
- 'data:image/svg+xml;base64,' . self::TIDIO_ICON_BASE64
387
- );
388
- }
389
-
390
- public function addAdminPage()
391
- {
392
- // Set class property
393
- $dir = plugin_dir_path(__FILE__);
394
- include $dir . 'options.php';
395
- }
396
-
397
- public function uninstall()
398
- {
399
- if (wp_verify_nonce($_GET['_wpnonce'], TidioLiveChat::CLEAR_ACCOUNT_DATA_ACTION) === false) {
400
- wp_die('', 403);
401
- }
402
-
403
- delete_option(TidioLiveChat::PUBLIC_KEY_OPTION);
404
- delete_option(TidioLiveChat::PRIVATE_KEY_OPTION);
405
- delete_option(TidioLiveChat::ASYNC_LOAD_OPTION);
406
- wp_redirect(admin_url('plugins.php'));
407
- die();
408
- }
409
  }
410
 
411
- final class TidioLiveChatConfig
412
- {
413
- /**
414
- * @var array|null
415
- */
416
- private static $config = null;
417
-
418
- /**
419
- * @return string
420
- */
421
- public static function getApiUrl()
422
- {
423
- return self::getConfig()['tidio_api_url'];
424
- }
425
-
426
- /**
427
- * @return string
428
- */
429
- public static function getPanelUrl()
430
- {
431
- return self::getConfig()['tidio_panel_url'];
432
- }
433
-
434
- /**
435
- * @return string
436
- */
437
- public static function getWidgetUrl()
438
- {
439
- return self::getConfig()['tidio_widget_url'];
440
- }
441
-
442
- /**
443
- * @return array
444
- */
445
- private static function getConfig()
446
- {
447
- if (self::$config === null) {
448
- self::$config = require __DIR__ . '/config.php';
449
- }
450
 
451
- return self::$config;
452
- }
453
- }
454
-
455
- add_action('init', 'initialize_tidio');
456
-
457
- function initialize_tidio()
458
- {
459
- $tidioLiveChat = new TidioLiveChat();
460
- }
461
-
462
- register_activation_hook(__FILE__, array('TidioLiveChat', 'activate'));
463
-
464
- class i18n
465
- {
466
- /**
467
- * echo translation
468
- */
469
- public static function _e($message)
470
- {
471
- _e($message, TidioLiveChat::TIDIO_PLUGIN_NAME);
472
- }
473
-
474
- /**
475
- * returns translation
476
- */
477
- public static function _t($message)
478
- {
479
- return __($message, TidioLiveChat::TIDIO_PLUGIN_NAME);
480
- }
481
- }
4
  * Plugin Name: Tidio Chat
5
  * Plugin URI: http://www.tidio.com
6
  * Description: Tidio Live Chat - live chat boosted with chatbots for your online business. Integrates with your website in less than 20 seconds.
7
+ * Version: 5.0.0
8
  * Author: Tidio Ltd.
9
  * Author URI: http://www.tidio.com
10
  * Text Domain: tidio-live-chat
11
  * Domain Path: /languages/
12
  * License: GPL2
13
  */
14
+ define('TIDIOCHAT_VERSION', '5.0.0');
15
+ define('AFFILIATE_CONFIG_FILE_PATH', get_template_directory() . '/tidio_affiliate_ref_id.txt');
16
+
17
+ require_once __DIR__ . '/src/TidioLiveChatConfig.php';
18
+ require_once __DIR__ . '/src/Translation/TidioTranslationLoader.php';
19
+ require_once __DIR__ . '/src/Translation/TidioErrorTranslator.php';
20
+ require_once __DIR__ . '/src/Translation/i18n.php';
21
+ require_once __DIR__ . '/src/Widget/TidioWidgetLoader.php';
22
+ require_once __DIR__ . '/src/Admin/TidioAdminActionLink.php';
23
+ require_once __DIR__ . '/src/Admin/TidioAdminController.php';
24
+ require_once __DIR__ . '/src/Admin/TidioIframeSetup.php';
25
+ require_once __DIR__ . '/src/Admin/TidioAdminDashboard.php';
26
+ require_once __DIR__ . '/src/Admin/TidioAdminRouting.php';
27
+ require_once __DIR__ . '/src/Admin/TidioAdminNotice.php';
28
+ require_once __DIR__ . '/src/Admin/TidioIframeSetup.php';
29
+ require_once __DIR__ . '/src/Sdk/TidioIntegrationFacade.php';
30
+ require_once __DIR__ . '/src/Sdk/Encryption/TidioEncryptionService.php';
31
+ require_once __DIR__ . '/src/Sdk/Encryption/Exception/TidioDecryptionFailedException.php';
32
+ require_once __DIR__ . '/src/Sdk/Encryption/Service/PlainTextTidioEncryptionService.php';
33
+ require_once __DIR__ . '/src/Sdk/Encryption/Service/OpenSslTidioEncryptionService.php';
34
+ require_once __DIR__ . '/src/Sdk/Encryption/Service/TidioEncryptionServiceFactory.php';
35
+ require_once __DIR__ . '/src/Sdk/Api/TidioApiClient.php';
36
+ require_once __DIR__ . '/src/Sdk/Api/Client/TidioApiClientFactory.php';
37
+ require_once __DIR__ . '/src/Sdk/Api/Client/CurlTidioApiClient.php';
38
+ require_once __DIR__ . '/src/Sdk/Api/Client/FileGetContentsTidioApiClient.php';
39
+ require_once __DIR__ . '/src/Sdk/Api/Exception/TidioApiException.php';
40
+ require_once __DIR__ . '/src/Utils/QueryParameters.php';
41
+ require_once __DIR__ . '/src/TidioIntegrationState.php';
42
+ require_once __DIR__ . '/src/TidioLiveChat.php';
43
+
44
+ function initializeTidioLiveChat()
45
  {
46
+ if (!empty($_GET['tidio_chat_version'])) {
47
+ echo TIDIOCHAT_VERSION;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  exit;
49
  }
50
 
51
+ TidioLiveChat::load();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
 
54
+ add_action('init', 'initializeTidioLiveChat');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ $encryptionService = (new TidioEncryptionServiceFactory())->create();
57
+ register_activation_hook(__FILE__, [new TidioIntegrationState($encryptionService), 'turnOnAsyncLoading']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
views/ajax-tidio-chat-redirect.php DELETED
@@ -1,55 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <title>Redirect to Tidio Chat...</title>
6
- </head>
7
-
8
- <body>
9
-
10
- <script>
11
-
12
- var path = {
13
- admin_url: '<?php echo admin_url() ?>'
14
- };
15
-
16
- </script>
17
-
18
- <?php /* ACCESS REDIRECT */ ?>
19
-
20
- <?php if($view['mode']=='redirect'){ ?>
21
-
22
- <script> location.href = '<?php echo $view['redirect_url'] ?>'; </script>
23
-
24
- <?php } ?>
25
-
26
- <?php /* ACCESS REQUEST */ ?>
27
-
28
- <?php if($view['mode']=='access_request'){ ?>
29
-
30
- <img src="<?php echo admin_url() ?>../wp-content/plugins/tidio-live-chat/media/img/ajax-loader.gif" />
31
-
32
- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
33
- <script>
34
-
35
- $.getJSON('<?php echo $view['access_url'] ?>&remote=1', function(data){
36
-
37
- if(!data || !data['status']){
38
- alert('Error occurred, please refresh page and try again!');
39
- return false;
40
- }
41
-
42
- data = data['value'];
43
-
44
- location.href = path.admin_url + 'admin-ajax.php?action=tidio_chat_redirect&access_status=success&private_key=' + data.private_key + '&public_key=' + data.public_key;
45
-
46
- });
47
-
48
- </script>
49
-
50
- <?php } ?>
51
-
52
-
53
-
54
- </body>
55
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
views/iframe.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <iframe
2
+ id="tidio-panel-iframe"
3
+ style="overflow:hidden; height:calc(100vh - 32px); min-height: 620px; width:100%"
4
+ width="100%"
5
+ src="<?php echo isset($iframeUrl) ? $iframeUrl : ''; ?>">
6
+ </iframe>