Social Media Share Buttons & Social Sharing Icons - Version 2.2.5

Version Description

  • Integrated feedback system
Download this release

Release Info

Developer socialdude
Plugin Icon 128x128 Social Media Share Buttons & Social Sharing Icons
Version 2.2.5
Comparing to
See all releases

Code changes from version 2.2.4 to 2.2.5

Files changed (47) hide show
  1. analyst/assets/css/customize.css +280 -0
  2. analyst/assets/img/pencil.png +0 -0
  3. analyst/assets/img/shield_question.png +0 -0
  4. analyst/assets/img/shield_success.png +0 -0
  5. analyst/assets/img/smile.png +0 -0
  6. analyst/assets/index.php +2 -0
  7. analyst/assets/js/customize.js +29 -0
  8. analyst/autoload.php +38 -0
  9. analyst/index.php +2 -0
  10. analyst/main.php +36 -0
  11. analyst/sdk_resolver.php +79 -0
  12. analyst/src/Account/Account.php +602 -0
  13. analyst/src/Account/AccountData.php +176 -0
  14. analyst/src/Account/AccountDataFactory.php +121 -0
  15. analyst/src/Analyst.php +167 -0
  16. analyst/src/ApiRequestor.php +257 -0
  17. analyst/src/ApiResponse.php +44 -0
  18. analyst/src/Cache/DatabaseCache.php +118 -0
  19. analyst/src/Collector.php +217 -0
  20. analyst/src/Contracts/AnalystContract.php +12 -0
  21. analyst/src/Contracts/CacheContract.php +47 -0
  22. analyst/src/Contracts/HttpClientContract.php +25 -0
  23. analyst/src/Contracts/RequestContract.php +22 -0
  24. analyst/src/Contracts/RequestorContract.php +44 -0
  25. analyst/src/Contracts/TrackerContract.php +69 -0
  26. analyst/src/Http/CurlHttpClient.php +102 -0
  27. analyst/src/Http/DummyHttpClient.php +33 -0
  28. analyst/src/Http/Requests/AbstractLoggerRequest.php +64 -0
  29. analyst/src/Http/Requests/ActivateRequest.php +42 -0
  30. analyst/src/Http/Requests/DeactivateRequest.php +64 -0
  31. analyst/src/Http/Requests/InstallRequest.php +38 -0
  32. analyst/src/Http/Requests/OptInRequest.php +42 -0
  33. analyst/src/Http/Requests/OptOutRequest.php +40 -0
  34. analyst/src/Http/Requests/UninstallRequest.php +36 -0
  35. analyst/src/Http/WordPressHttpClient.php +61 -0
  36. analyst/src/Mutator.php +103 -0
  37. analyst/src/Notices/Notice.php +121 -0
  38. analyst/src/Notices/NoticeFactory.php +126 -0
  39. analyst/src/helpers.php +79 -0
  40. analyst/templates/forms/deactivate.php +157 -0
  41. analyst/templates/forms/install.php +110 -0
  42. analyst/templates/notice.php +10 -0
  43. analyst/templates/optin.php +60 -0
  44. analyst/templates/optout.php +109 -0
  45. analyst/version.php +15 -0
  46. readme.txt +7 -3
  47. ultimate_social_media_icons.php +9 -1
analyst/assets/css/customize.css ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .analyst-action-opt {
2
+ cursor: pointer;
3
+ }
4
+
5
+ .analyst-modal {
6
+ color: #000000;
7
+ display: none;
8
+ position: fixed;
9
+ z-index: 1000;
10
+ padding-top: 100px;
11
+ left: 0;
12
+ top: 0;
13
+ width: 100%;
14
+ height: 100%;
15
+ overflow: auto;
16
+ background-color: rgb(0,0,0);
17
+ background-color: rgba(0,0,0,0.4);
18
+ }
19
+
20
+ .analyst-modal-content {
21
+ font-family: Helvetica, serif;
22
+ position: relative;
23
+ background-color: #fefefe;
24
+ margin: auto;
25
+ padding: 35px 35px 20px;
26
+ border: 1px solid #F2F2F2;
27
+ width: 40%;
28
+ box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
29
+ -webkit-animation-name: analyst-animatetop;
30
+ -webkit-animation-duration: 0.4s;
31
+ animation-name: analyst-animatetop;
32
+ animation-duration: 0.4s
33
+ }
34
+
35
+ .analyst-btn-success {
36
+ cursor: pointer;
37
+ color: #ffffff;
38
+ background-color: #00AF5E;
39
+ border: none;
40
+ width: 100%;
41
+ font-size: 18px;
42
+ padding: 8px;
43
+ font-weight: bold;
44
+ }
45
+
46
+ .analyst-btn-grey {
47
+ cursor: pointer;
48
+ color: #2D2D2D;
49
+ background-color: #D8D8D8;
50
+ border: none;
51
+ width: 100%;
52
+ font-size: 18px;
53
+ padding: 8px;
54
+ font-weight: bold;
55
+ }
56
+
57
+ .analyst-btn-secondary-ghost {
58
+ cursor: pointer;
59
+ background: transparent;
60
+ border: none;
61
+ color: #898686;
62
+ font-size: 18px;
63
+ }
64
+
65
+ .analyst-modal-def-top-padding {
66
+ padding-top: 20px;
67
+ }
68
+
69
+ .analyst-modal-header {
70
+ font-size: 20px;
71
+ font-weight: bold;
72
+ }
73
+
74
+ /*INSTALL STYLES*/
75
+ .analyst-install-footer {
76
+ padding-top: 10px;
77
+ text-align: center;
78
+ }
79
+
80
+ .analyst-install-image-block {
81
+ width: 140px;
82
+ }
83
+
84
+ .analyst-install-image-block img {
85
+ width: inherit;
86
+ }
87
+
88
+ .analyst-install-description-block {
89
+ padding-left: 40px;
90
+ padding-top: 5px
91
+ }
92
+
93
+ .analyst-install-description-text {
94
+ font-size: 16px;
95
+ color: #000000;
96
+ }
97
+
98
+ .analyst-install-permissions-list {
99
+ list-style: disc inside;
100
+ }
101
+
102
+ .analyst-install-permissions-list li {
103
+ padding-left: 15px;
104
+ margin-bottom: 2px;
105
+ }
106
+
107
+ .analyst-install-footer span {
108
+ color: #8a8787;
109
+ padding-right: 10px;
110
+ padding-left: 10px;
111
+ }
112
+
113
+ .analyst-install-footer span:not(:last-child) {
114
+ border-right: 1px solid #8a8787;
115
+ }
116
+
117
+ /*INSTALL STYLES*/
118
+
119
+ .reason-answer {
120
+ padding: 7px;
121
+ margin-left: 23px;
122
+ border: 1px solid #F2F2F2;
123
+ }
124
+
125
+ .analyst-link {
126
+ color: #00AF5E;
127
+ text-decoration: none;
128
+ }
129
+
130
+ .analyst-action-text {
131
+ cursor: pointer;
132
+ }
133
+
134
+ .analyst-action-text:hover {
135
+ color: #9d9a9a;
136
+ }
137
+
138
+ .analyst-disable-modal-mask {
139
+ width: 100%;
140
+ height: 100%;
141
+ opacity: 0.5;
142
+ position: absolute;
143
+ background: white;
144
+ top: 0;
145
+ left: 0;
146
+ }
147
+
148
+ .analyst-smile-image {
149
+ vertical-align: middle;
150
+ padding-bottom: 3px;
151
+ width: 24px;
152
+ }
153
+
154
+ #analyst-deactivation-reasons li {
155
+ padding-bottom: 3px;
156
+ font-size: 16px;
157
+ color: #000000;
158
+ }
159
+
160
+ @-webkit-keyframes analyst-animatetop {
161
+ from {top:-300px; opacity:0}
162
+ to {top:0; opacity:1}
163
+ }
164
+
165
+ @keyframes analyst-animatetop {
166
+ from {top:-300px; opacity:0}
167
+ to {top:0; opacity:1}
168
+ }
169
+
170
+ .analyst-modal-close {
171
+ color: #48036F;
172
+ font-size: 28px;
173
+ font-weight: bold;
174
+ top: 12px;
175
+ position: absolute;
176
+ right: 15px;
177
+ }
178
+
179
+ .analyst-modal-close:hover,
180
+ .analyst-modal-close:focus {
181
+ color: #000;
182
+ text-decoration: none;
183
+ cursor: pointer;
184
+ }
185
+
186
+ .analyst-modal-body {padding: 2px 16px;}
187
+
188
+ .analyst-modal-footer {
189
+ padding: 6px 16px;
190
+ background-color: #FFE773;
191
+ color: white;
192
+ }
193
+
194
+ #analyst-deactivate-modal .question-answer input, textarea {
195
+ margin-top: 5px;
196
+ width: 100%;
197
+ }
198
+
199
+ .analyst-btn-primary {
200
+ cursor: pointer;
201
+ border: none;
202
+ display:inline-block;
203
+ padding:0.7em 1.4em;
204
+ margin:0 0.3em 0.3em 0;
205
+ border-radius:0.15em;
206
+ box-sizing: border-box;
207
+ text-decoration:none;
208
+ font-family:'Roboto',sans-serif;
209
+ text-transform:uppercase;
210
+ font-weight:400;
211
+ color:#FFFFFF;
212
+ background-color:#9F3ED5;
213
+ box-shadow:inset 0 -0.6em 0 -0.35em rgba(0,0,0,0.17);
214
+ text-align:center;
215
+ position:relative;
216
+ }
217
+
218
+ .analyst-btn-primary:disabled {
219
+ background-color: #AD66D5;
220
+ cursor: not-allowed;
221
+ }
222
+
223
+ .analyst-btn-primary:active{
224
+ top:0.1em;
225
+ }
226
+ @media all and (max-width:30em){
227
+ .analyst-btn-primary {
228
+ display:block;
229
+ margin:0.4em auto;
230
+ }
231
+ }
232
+
233
+ .analyst-btn-secondary {
234
+ cursor: pointer;
235
+ border: none;
236
+ display:inline-block;
237
+ padding:0.7em 1.4em;
238
+ margin:0 0.3em 0.3em 0;
239
+ border-radius:0.15em;
240
+ box-sizing: border-box;
241
+ text-decoration:none;
242
+ font-family:'Roboto',sans-serif;
243
+ text-transform:uppercase;
244
+ font-weight:400;
245
+ color:#FFFFFF;
246
+ background-color:#6C8CD5;
247
+ box-shadow:inset 0 -0.6em 0 -0.35em rgba(0,0,0,0.17);
248
+ text-align:center;
249
+ position:relative;
250
+ }
251
+
252
+ .analyst-btn-secondary:disabled {
253
+ background-color: #6C8CD5;
254
+ cursor: not-allowed;
255
+ }
256
+
257
+ .analyst-btn-secondary:active{
258
+ top:0.1em;
259
+ }
260
+ @media all and (max-width:30em){
261
+ .analyst-btn-secondary {
262
+ display:block;
263
+ margin:0.4em auto;
264
+ }
265
+ }
266
+
267
+ .analyst-notice {
268
+ padding-right: 38px;
269
+ position: relative;
270
+ margin-bottom: 30px !important;
271
+ }
272
+
273
+ .analyst-notice .analyst-plugin-name {
274
+ background-color: #00000024;
275
+ padding-left: 7px;
276
+ padding-right: 7px;
277
+ position: absolute;
278
+ top: 100%;
279
+ border-radius: 0 0 5px 5px;
280
+ }
analyst/assets/img/pencil.png ADDED
Binary file
analyst/assets/img/shield_question.png ADDED
Binary file
analyst/assets/img/shield_success.png ADDED
Binary file
analyst/assets/img/smile.png ADDED
Binary file
analyst/assets/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
analyst/assets/js/customize.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($) {
2
+ $(document).on('click', '.analyst-notice-dismiss', function () {
3
+ var id = $(this).attr('analyst-notice-id');
4
+ var self = this;
5
+
6
+ $.post(ajaxurl, {action: 'analyst_notification_dismiss', id: id})
7
+ .done(function () {
8
+ $(self).parent().fadeOut()
9
+ })
10
+ })
11
+
12
+ var url = new URL(window.location.href)
13
+
14
+ if (url.searchParams.has('verify')) {
15
+ var pluginId = url.searchParams.get('plugin_id')
16
+
17
+ $.ajax({
18
+ url: ajaxurl,
19
+ method: 'POST',
20
+ data: {
21
+ action: 'analyst_install_verified_' + pluginId,
22
+ },
23
+ success: function () {
24
+ // Refresh page without query params
25
+ window.location.href = window.location.origin + window.location.pathname
26
+ }
27
+ })
28
+ }
29
+ })(jQuery)
analyst/autoload.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once __DIR__ . '/src/helpers.php';
4
+
5
+ require_once __DIR__ . '/src/Contracts/HttpClientContract.php';
6
+ require_once __DIR__ . '/src/Contracts/RequestContract.php';
7
+ require_once __DIR__ . '/src/Contracts/RequestorContract.php';
8
+ require_once __DIR__ . '/src/Contracts/TrackerContract.php';
9
+ require_once __DIR__ . '/src/Contracts/CacheContract.php';
10
+
11
+ require_once __DIR__ . '/src/Cache/DatabaseCache.php';
12
+
13
+ require_once __DIR__ . '/src/Account/Account.php';
14
+ require_once __DIR__ . '/src/Account/AccountData.php';
15
+ require_once __DIR__ . '/src/Account/AccountDataFactory.php';
16
+ require_once __DIR__ . '/src/Contracts/AnalystContract.php';
17
+
18
+ require_once __DIR__ . '/src/Http/Requests/AbstractLoggerRequest.php';
19
+ require_once __DIR__ . '/src/Http/Requests/ActivateRequest.php';
20
+ require_once __DIR__ . '/src/Http/Requests/DeactivateRequest.php';
21
+ require_once __DIR__ . '/src/Http/Requests/InstallRequest.php';
22
+ require_once __DIR__ . '/src/Http/Requests/OptInRequest.php';
23
+ require_once __DIR__ . '/src/Http/Requests/OptOutRequest.php';
24
+ require_once __DIR__ . '/src/Http/Requests/UninstallRequest.php';
25
+
26
+ require_once __DIR__ . '/src/Http/CurlHttpClient.php';
27
+ require_once __DIR__ . '/src/Http/DummyHttpClient.php';
28
+ require_once __DIR__ . '/src/Http/WordPressHttpClient.php';
29
+
30
+ require_once __DIR__ . '/src/Notices/Notice.php';
31
+ require_once __DIR__ . '/src/Notices/NoticeFactory.php';
32
+
33
+ require_once __DIR__ . '/src/Analyst.php';
34
+ require_once __DIR__ . '/src/ApiRequestor.php';
35
+ require_once __DIR__ . '/src/ApiResponse.php';
36
+ require_once __DIR__ . '/src/Collector.php';
37
+ require_once __DIR__ . '/src/Mutator.php';
38
+
analyst/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence
analyst/main.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once 'sdk_resolver.php';
4
+
5
+
6
+ if (!function_exists('analyst_init')) {
7
+ /**
8
+ * Initialize analyst
9
+ *
10
+ * @param array $options
11
+ */
12
+ function analyst_init ($options) {
13
+ // Try resolve latest supported SDK
14
+ // In case resolving is failed exit the execution
15
+ try {
16
+ analyst_resolve_sdk($options['base-dir']);
17
+ } catch (Exception $exception) {
18
+ error_log('[ANALYST] Cannot resolve any supported SDK');
19
+ return;
20
+ }
21
+
22
+ try {
23
+ global /** @var Analyst\Analyst $analyst */
24
+ $analyst;
25
+
26
+ // Set global instance of analyst
27
+ if (!$analyst) {
28
+ $analyst = Analyst\Analyst::getInstance();
29
+ }
30
+
31
+ $analyst->registerAccount(new Account\Account($options['client-id'], $options['client-secret'], $options['base-dir']));
32
+ } catch (Exception $e) {
33
+ error_log('Analyst SDK receive an error: [' . $e->getMessage() . '] Please contact our support at support@analyst.com');
34
+ }
35
+ }
36
+ }
analyst/sdk_resolver.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!function_exists('analyst_resolve_sdk')) {
4
+
5
+ /**
6
+ * Resolve supported sdk versions and load latest supported one
7
+ * also bootstrap sdk with autoloader
8
+ *
9
+ * @since 1.1.3
10
+ *
11
+ * @param null $thisPluginPath
12
+ * @return void
13
+ * @throws Exception
14
+ */
15
+ function analyst_resolve_sdk($thisPluginPath = null) {
16
+ static $loaded = false;
17
+
18
+ // Exit if we already resolved SDK
19
+ if ($loaded) return;
20
+
21
+ $plugins = get_option('active_plugins');
22
+
23
+ if ($thisPluginPath) {
24
+ array_push($plugins, plugin_basename($thisPluginPath));
25
+ }
26
+
27
+ $pluginsFolder = ABSPATH . 'wp-content/plugins';
28
+
29
+ $possibleSDKs = array_map(function ($path) use ($pluginsFolder) {
30
+ $sdkFolder = sprintf('%s/%s/analyst/', $pluginsFolder, dirname($path));
31
+
32
+ $sdkFolder = str_replace('\\', '/', $sdkFolder);
33
+
34
+ $versionPath = $sdkFolder . 'version.php';
35
+
36
+ if (file_exists($versionPath)) {
37
+ return require $versionPath;
38
+ }
39
+
40
+ return false;
41
+ }, $plugins);
42
+
43
+ global $wp_version;
44
+
45
+ // Filter out plugins which has no SDK
46
+ $SDKs = array_filter($possibleSDKs, function ($s) {return is_array($s);});
47
+
48
+ // Filter SDKs which is supported by PHP and WP
49
+ $supported = array_values(array_filter($SDKs, function ($sdk) use($wp_version) {
50
+ $phpSupported = version_compare(PHP_VERSION, $sdk['php']) >= 0;
51
+ $wpSupported = version_compare($wp_version, $sdk['wp']) >= 0;
52
+
53
+ return $phpSupported && $wpSupported;
54
+ }));
55
+
56
+ // Sort SDK by version in descending order
57
+ uasort($supported, function ($x, $y) {
58
+ return version_compare($y['sdk'], $x['sdk']);
59
+ });
60
+
61
+ // Reset sorted values keys
62
+ $supported = array_values($supported);
63
+
64
+ if (!isset($supported[0])) {
65
+ throw new Exception('There is no SDK which is support current PHP version and WP version');
66
+ }
67
+
68
+ // Autoload files for supported SDK
69
+ $autoloaderPath = str_replace(
70
+ '\\',
71
+ '/',
72
+ sprintf('%s/autoload.php', $supported[0]['path'])
73
+ );
74
+
75
+ require_once $autoloaderPath;
76
+
77
+ $loaded = true;
78
+ }
79
+ }
analyst/src/Account/Account.php ADDED
@@ -0,0 +1,602 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Account;
4
+
5
+ use Analyst\Analyst;
6
+ use Analyst\ApiRequestor;
7
+ use Analyst\Cache\DatabaseCache;
8
+ use Analyst\Collector;
9
+ use Analyst\Http\Requests\ActivateRequest;
10
+ use Analyst\Http\Requests\DeactivateRequest;
11
+ use Analyst\Http\Requests\InstallRequest;
12
+ use Analyst\Http\Requests\OptInRequest;
13
+ use Analyst\Http\Requests\OptOutRequest;
14
+ use Analyst\Http\Requests\UninstallRequest;
15
+ use Analyst\Notices\Notice;
16
+ use Analyst\Notices\NoticeFactory;
17
+ use Analyst\Contracts\TrackerContract;
18
+ use Analyst\Contracts\RequestorContract;
19
+
20
+ /**
21
+ * Class Account
22
+ *
23
+ * This is plugin's account object
24
+ */
25
+ class Account implements TrackerContract
26
+ {
27
+ /**
28
+ * Account id
29
+ *
30
+ * @var string
31
+ */
32
+ protected $id;
33
+
34
+ /**
35
+ * Basename of plugin
36
+ *
37
+ * @var string
38
+ */
39
+ protected $path;
40
+
41
+ /**
42
+ * Whether plugin is active or not
43
+ *
44
+ * @var bool
45
+ */
46
+ protected $isInstalled = false;
47
+
48
+ /**
49
+ * Is user sign in for data tracking
50
+ *
51
+ * @var bool
52
+ */
53
+ protected $isOptedIn = false;
54
+
55
+ /**
56
+ * Is user accepted permissions grant
57
+ * for collection site data
58
+ *
59
+ * @var bool
60
+ */
61
+ protected $isSigned = false;
62
+
63
+ /**
64
+ * Is user ever resolved install modal window?
65
+ *
66
+ * @var bool
67
+ */
68
+ protected $isInstallResolved = false;
69
+
70
+ /**
71
+ * Public secret code
72
+ *
73
+ * @var string
74
+ */
75
+ protected $clientSecret;
76
+
77
+ /**
78
+ * @var AccountData
79
+ */
80
+ protected $data;
81
+
82
+ /**
83
+ * Base plugin path
84
+ *
85
+ * @var string
86
+ */
87
+ protected $basePluginPath;
88
+
89
+ /**
90
+ * @var RequestorContract
91
+ */
92
+ protected $requestor;
93
+
94
+ /**
95
+ * @var Collector
96
+ */
97
+ protected $collector;
98
+
99
+ /**
100
+ * Account constructor.
101
+ * @param $id
102
+ * @param $secret
103
+ * @param $baseDir
104
+ */
105
+ public function __construct($id, $secret, $baseDir)
106
+ {
107
+ $this->id = $id;
108
+ $this->clientSecret = $secret;
109
+
110
+ $this->path = $baseDir;
111
+
112
+ $this->basePluginPath = plugin_basename($baseDir);
113
+ }
114
+
115
+ /**
116
+ * @return string
117
+ */
118
+ public function getPath()
119
+ {
120
+ return $this->path;
121
+ }
122
+
123
+ /**
124
+ * @param string $path
125
+ */
126
+ public function setPath($path)
127
+ {
128
+ $this->data->setPath($path);
129
+
130
+ $this->path = $path;
131
+ }
132
+
133
+ /**
134
+ * @return bool
135
+ */
136
+ public function isOptedIn()
137
+ {
138
+ return $this->isOptedIn;
139
+ }
140
+
141
+ /**
142
+ * @param bool $isOptedIn
143
+ */
144
+ public function setIsOptedIn($isOptedIn)
145
+ {
146
+ $this->data->setIsOptedIn($isOptedIn);
147
+
148
+ $this->isOptedIn = $isOptedIn;
149
+ }
150
+
151
+ /**
152
+ * Whether plugin is active
153
+ *
154
+ * @return bool
155
+ */
156
+ public function isActive()
157
+ {
158
+ return is_plugin_active($this->path);
159
+ }
160
+
161
+ /**
162
+ * @param string $id
163
+ */
164
+ public function setId($id)
165
+ {
166
+ $this->id = $id;
167
+ }
168
+
169
+ /**
170
+ * @return string
171
+ */
172
+ public function getId()
173
+ {
174
+ return $this->id;
175
+ }
176
+
177
+ /**
178
+ * @return bool
179
+ */
180
+ public function isInstalled()
181
+ {
182
+ return $this->isInstalled;
183
+ }
184
+
185
+ /**
186
+ * @param bool $isInstalled
187
+ */
188
+ public function setIsInstalled($isInstalled)
189
+ {
190
+ $this->data->setIsInstalled($isInstalled);
191
+
192
+ $this->isInstalled = $isInstalled;
193
+ }
194
+
195
+ /**
196
+ * Should register activation and deactivation
197
+ * event hooks
198
+ *
199
+ * @return void
200
+ */
201
+ public function registerHooks()
202
+ {
203
+ register_activation_hook($this->basePluginPath, [&$this, 'onActivePluginListener']);
204
+ register_uninstall_hook($this->basePluginPath, ['Account\Account', 'onUninstallPluginListener']);
205
+
206
+ $this->addFilter('plugin_action_links', [&$this, 'onRenderActionLinksHook']);
207
+
208
+ $this->addAjax('analyst_opt_in', [&$this, 'onOptInListener']);
209
+ $this->addAjax('analyst_opt_out', [&$this, 'onOptOutListener']);
210
+ $this->addAjax('analyst_plugin_deactivate', [&$this, 'onDeactivatePluginListener']);
211
+ $this->addAjax('analyst_install', [&$this, 'onInstallListener']);
212
+ $this->addAjax('analyst_skip_install', [&$this, 'onSkipInstallListener']);
213
+ $this->addAjax('analyst_install_verified', [&$this, 'onInstallVerifiedListener']);
214
+ }
215
+
216
+ /**
217
+ * Will fire when admin activates plugin
218
+ *
219
+ * @return void
220
+ */
221
+ public function onActivePluginListener()
222
+ {
223
+ if (!$this->isInstallResolved()) {
224
+ DatabaseCache::getInstance()->put('plugin_to_install', $this->id);
225
+ }
226
+
227
+ if (!$this->isAllowingLogging()) return;
228
+
229
+ ActivateRequest::make($this->collector, $this->id, $this->path)
230
+ ->execute($this->requestor);
231
+
232
+ $this->setIsInstalled(true);
233
+
234
+ AccountDataFactory::syncData();
235
+ }
236
+
237
+ /**
238
+ * Will fire when admin deactivates plugin
239
+ *
240
+ * @return void
241
+ */
242
+ public function onDeactivatePluginListener()
243
+ {
244
+ if (!$this->isAllowingLogging()) return;
245
+
246
+ $question = isset($_POST['question']) ? stripslashes($_POST['question']) : null;
247
+ $reason = isset($_POST['reason']) ? stripslashes($_POST['reason']) : null;
248
+
249
+ $response = DeactivateRequest::make($this->collector, $this->id, $this->path, $question, $reason)
250
+ ->execute($this->requestor);
251
+
252
+ // Exit if request failed
253
+ if (!$response->isSuccess()) {
254
+ wp_send_json_error($response->body);
255
+ }
256
+
257
+ $this->setIsInstalled(false);
258
+
259
+ AccountDataFactory::syncData();
260
+
261
+ wp_die();
262
+ }
263
+
264
+ /**
265
+ * Will fire when user opted in
266
+ *
267
+ * @return void
268
+ */
269
+ public function onOptInListener()
270
+ {
271
+ $response = OptInRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
272
+
273
+ // Exit if request failed
274
+ if (!$response->isSuccess()) {
275
+ wp_send_json_error($response->body);
276
+ }
277
+
278
+ $this->setIsOptedIn(true);
279
+
280
+ AccountDataFactory::syncData();
281
+
282
+ wp_die();
283
+ }
284
+
285
+ /**
286
+ * Will fire when user opted out
287
+ *
288
+ * @return void
289
+ */
290
+ public function onOptOutListener()
291
+ {
292
+ $response = OptOutRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
293
+
294
+ // Exit if request failed
295
+ if (!$response->isSuccess()) {
296
+ wp_send_json_error($response->body);
297
+ }
298
+
299
+ $this->setIsOptedIn(false);
300
+
301
+ AccountDataFactory::syncData();
302
+
303
+ wp_die();
304
+ }
305
+
306
+ /**
307
+ * Will fire when user accept opt-in
308
+ * at first time
309
+ *
310
+ * @return void
311
+ */
312
+ public function onInstallListener()
313
+ {
314
+ $cache = DatabaseCache::getInstance();
315
+
316
+ // Set flag to true which indicates that install is resolved
317
+ // also remove install plugin id from cache
318
+ $this->setIsInstallResolved(true);
319
+ $cache->delete('plugin_to_install');
320
+
321
+ $response = InstallRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
322
+
323
+ // Exit if request failed
324
+ if (!$response->isSuccess()) {
325
+ wp_send_json_error($response->body);
326
+ }
327
+
328
+ $this->setIsSigned(true);
329
+
330
+ $this->setIsOptedIn(true);
331
+
332
+ $factory = NoticeFactory::instance();
333
+
334
+ $message = sprintf('Please confirm your email by clicking on the link we sent to %s. This makes sure you’re not a bot.', $this->collector->getGeneralEmailAddress());
335
+
336
+ $notificationId = uniqid();
337
+
338
+ $notice = Notice::make(
339
+ $notificationId,
340
+ $this->getId(),
341
+ $message,
342
+ $this->collector->getPluginName($this->path)
343
+ );
344
+
345
+ $factory->addNotice($notice);
346
+
347
+ AccountDataFactory::syncData();
348
+
349
+ // Set email confirmation notification id to cache
350
+ // se we can extract and remove it when user confirmed email
351
+ $cache->put(
352
+ sprintf('account_email_confirmation_%s', $this->getId()),
353
+ $notificationId
354
+ );
355
+
356
+ wp_die();
357
+ }
358
+
359
+ /**
360
+ * Will fire when user skipped installation
361
+ *
362
+ * @return void
363
+ */
364
+ public function onSkipInstallListener()
365
+ {
366
+ // Set flag to true which indicates that install is resolved
367
+ // also remove install plugin id from cache
368
+ $this->setIsInstallResolved(true);
369
+ DatabaseCache::getInstance()->delete('plugin_to_install');
370
+ }
371
+
372
+ /**
373
+ * Will fire when user delete plugin through admin panel.
374
+ * This action will happen if admin at least once
375
+ * activated the plugin.
376
+ *
377
+ * @return void
378
+ * @throws \Exception
379
+ */
380
+ public static function onUninstallPluginListener()
381
+ {
382
+ $factory = AccountDataFactory::instance();
383
+
384
+ $pluginFile = substr(current_filter(), strlen( 'uninstall_' ));
385
+
386
+ $account = $factory->getAccountDataByBasePath($pluginFile);
387
+
388
+ // If account somehow is not found, exit the execution
389
+ if (!$account) return;
390
+
391
+ $analyst = Analyst::getInstance();
392
+
393
+ $collector = new Collector($analyst);
394
+
395
+ $requestor = new ApiRequestor($account->getId(), $account->getSecret(), $analyst->getApiBase());
396
+
397
+ // Just send request to log uninstall event not caring about response
398
+ UninstallRequest::make($collector, $account->getId(), $account->getPath())->execute($requestor);
399
+
400
+ $factory->sync();
401
+ }
402
+
403
+ /**
404
+ * Fires when used verified his account
405
+ */
406
+ public function onInstallVerifiedListener()
407
+ {
408
+ $factory = NoticeFactory::instance();
409
+
410
+ $notice = Notice::make(
411
+ uniqid(),
412
+ $this->getId(),
413
+ 'Thank you for confirming your email.',
414
+ $this->collector->getPluginName($this->path)
415
+ );
416
+
417
+ $factory->addNotice($notice);
418
+
419
+ // Remove confirmation notification
420
+ $confirmationNotificationId = DatabaseCache::getInstance()->pop(sprintf('account_email_confirmation_%s', $this->getId()));
421
+ $factory->remove($confirmationNotificationId);
422
+
423
+ AccountDataFactory::syncData();
424
+ }
425
+
426
+ /**
427
+ * Will fire when wp renders plugin
428
+ * action buttons
429
+ *
430
+ * @param $defaultLinks
431
+ * @return array
432
+ */
433
+ public function onRenderActionLinksHook($defaultLinks)
434
+ {
435
+ $customLinks = [];
436
+
437
+ $customLinks[] = $this->isOptedIn()
438
+ ? '<a class="analyst-action-opt analyst-opt-out" analyst-plugin-id="' . $this->getId() . '" analyst-plugin-signed="' . (int) $this->isSigned() . '">Opt Out</a>'
439
+ : '<a class="analyst-action-opt analyst-opt-in" analyst-plugin-id="' . $this->getId() . '" analyst-plugin-signed="' . (int) $this->isSigned() . '">Opt In</a>';
440
+
441
+ // Append anchor to find specific deactivation link
442
+ if (isset($defaultLinks['deactivate'])) {
443
+ $defaultLinks['deactivate'] .= '<span analyst-plugin-id="' . $this->getId() . '" analyst-plugin-opted-in="' . (int) $this->isOptedIn() . '"></span>';
444
+ }
445
+
446
+ return array_merge($customLinks, $defaultLinks);
447
+ }
448
+
449
+ /**
450
+ * @return AccountData
451
+ */
452
+ public function getData()
453
+ {
454
+ return $this->data;
455
+ }
456
+
457
+ /**
458
+ * @param AccountData $data
459
+ */
460
+ public function setData(AccountData $data)
461
+ {
462
+ $this->data = $data;
463
+
464
+ $this->setIsOptedIn($data->isOptedIn());
465
+ $this->setIsInstalled($data->isInstalled());
466
+ $this->setIsSigned($data->isSigned());
467
+ $this->setIsInstallResolved($data->isInstallResolved());
468
+ }
469
+
470
+ /**
471
+ * Resolves valid action name
472
+ * based on client id
473
+ *
474
+ * @param $action
475
+ * @return string
476
+ */
477
+ private function resolveActionName($action)
478
+ {
479
+ return sprintf('%s_%s', $action, $this->id);
480
+ }
481
+
482
+ /**
483
+ * Register action for current plugin
484
+ *
485
+ * @param $action
486
+ * @param $callback
487
+ */
488
+ private function addFilter($action, $callback)
489
+ {
490
+ $validAction = sprintf('%s_%s', $action, $this->basePluginPath);
491
+
492
+ add_filter($validAction, $callback, 10);
493
+ }
494
+
495
+ /**
496
+ * Add ajax action for current plugin
497
+ *
498
+ * @param $action
499
+ * @param $callback
500
+ * @param bool $raw Format action ??
501
+ */
502
+ private function addAjax($action, $callback, $raw = false)
503
+ {
504
+ $validAction = $raw ? $action : sprintf('%s%s', 'wp_ajax_', $this->resolveActionName($action));
505
+
506
+ add_action($validAction, $callback);
507
+ }
508
+
509
+ /**
510
+ * @return bool
511
+ */
512
+ public function isSigned()
513
+ {
514
+ return $this->isSigned;
515
+ }
516
+
517
+ /**
518
+ * @param bool $isSigned
519
+ */
520
+ public function setIsSigned($isSigned)
521
+ {
522
+ $this->data->setIsSigned($isSigned);
523
+
524
+ $this->isSigned = $isSigned;
525
+ }
526
+
527
+ /**
528
+ * @return RequestorContract
529
+ */
530
+ public function getRequestor()
531
+ {
532
+ return $this->requestor;
533
+ }
534
+
535
+ /**
536
+ * @param RequestorContract $requestor
537
+ */
538
+ public function setRequestor(RequestorContract $requestor)
539
+ {
540
+ $this->requestor = $requestor;
541
+ }
542
+
543
+ /**
544
+ * @return string
545
+ */
546
+ public function getClientSecret()
547
+ {
548
+ return $this->clientSecret;
549
+ }
550
+
551
+ /**
552
+ * @return Collector
553
+ */
554
+ public function getCollector()
555
+ {
556
+ return $this->collector;
557
+ }
558
+
559
+ /**
560
+ * @param Collector $collector
561
+ */
562
+ public function setCollector(Collector $collector)
563
+ {
564
+ $this->collector = $collector;
565
+ }
566
+
567
+ /**
568
+ * Do we allowing logging
569
+ *
570
+ * @return bool
571
+ */
572
+ public function isAllowingLogging()
573
+ {
574
+ return $this->isOptedIn;
575
+ }
576
+
577
+ /**
578
+ * @return string
579
+ */
580
+ public function getBasePluginPath()
581
+ {
582
+ return $this->basePluginPath;
583
+ }
584
+
585
+ /**
586
+ * @return bool
587
+ */
588
+ public function isInstallResolved()
589
+ {
590
+ return $this->isInstallResolved;
591
+ }
592
+
593
+ /**
594
+ * @param bool $isInstallResolved
595
+ */
596
+ public function setIsInstallResolved($isInstallResolved)
597
+ {
598
+ $this->data->setIsInstallResolved($isInstallResolved);
599
+
600
+ $this->isInstallResolved = $isInstallResolved;
601
+ }
602
+ }
analyst/src/Account/AccountData.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Account;
4
+
5
+ /**
6
+ * Class AccountData is the data holder
7
+ * for Analyst\Account\Account class
8
+ * which is unserialized from database
9
+ */
10
+ class AccountData
11
+ {
12
+ /**
13
+ * Account id
14
+ *
15
+ * @var string
16
+ */
17
+ protected $id;
18
+
19
+ /**
20
+ * Account secret key
21
+ *
22
+ * @var string
23
+ */
24
+ protected $secret;
25
+
26
+ /**
27
+ * Basename of plugin
28
+ *
29
+ * @var string
30
+ */
31
+ protected $path;
32
+
33
+ /**
34
+ * Whether admin accepted opt in
35
+ * terms and permissions
36
+ *
37
+ * @var bool
38
+ */
39
+ protected $isInstalled = false;
40
+
41
+ /**
42
+ * Is user sign in for data tracking
43
+ *
44
+ * @var bool
45
+ */
46
+ protected $isOptedIn = false;
47
+
48
+ /**
49
+ * Is user accepted permissions grant
50
+ * for collection site data
51
+ *
52
+ * @var bool
53
+ */
54
+ protected $isSigned = false;
55
+
56
+ /**
57
+ * Is user ever resolved install modal window?
58
+ *
59
+ * @var bool
60
+ */
61
+ protected $isInstallResolved;
62
+
63
+ /**
64
+ * @return string
65
+ */
66
+ public function getId()
67
+ {
68
+ return $this->id;
69
+ }
70
+
71
+ /**
72
+ * @param string $id
73
+ */
74
+ public function setId($id)
75
+ {
76
+ $this->id = $id;
77
+ }
78
+
79
+ /**
80
+ * @param string $path
81
+ * @return AccountData
82
+ */
83
+ public function setPath($path)
84
+ {
85
+ $this->path = $path;
86
+ return $this;
87
+ }
88
+
89
+ /**
90
+ * @return bool
91
+ */
92
+ public function isInstalled()
93
+ {
94
+ return $this->isInstalled;
95
+ }
96
+
97
+ /**
98
+ * @param bool $isInstalled
99
+ */
100
+ public function setIsInstalled($isInstalled)
101
+ {
102
+ $this->isInstalled = $isInstalled;
103
+ }
104
+
105
+ /**
106
+ * @return bool
107
+ */
108
+ public function isOptedIn()
109
+ {
110
+ return $this->isOptedIn;
111
+ }
112
+
113
+ /**
114
+ * @param bool $isOptedIn
115
+ */
116
+ public function setIsOptedIn($isOptedIn)
117
+ {
118
+ $this->isOptedIn = $isOptedIn;
119
+ }
120
+
121
+ /**
122
+ * @return bool
123
+ */
124
+ public function isSigned()
125
+ {
126
+ return $this->isSigned;
127
+ }
128
+
129
+ /**
130
+ * @param bool $isSigned
131
+ */
132
+ public function setIsSigned($isSigned)
133
+ {
134
+ $this->isSigned = $isSigned;
135
+ }
136
+
137
+ /**
138
+ * @return string
139
+ */
140
+ public function getPath()
141
+ {
142
+ return $this->path;
143
+ }
144
+
145
+ /**
146
+ * @return string
147
+ */
148
+ public function getSecret()
149
+ {
150
+ return $this->secret;
151
+ }
152
+
153
+ /**
154
+ * @param string $secret
155
+ */
156
+ public function setSecret($secret)
157
+ {
158
+ $this->secret = $secret;
159
+ }
160
+
161
+ /**
162
+ * @return bool
163
+ */
164
+ public function isInstallResolved()
165
+ {
166
+ return $this->isInstallResolved;
167
+ }
168
+
169
+ /**
170
+ * @param bool $isInstallResolved
171
+ */
172
+ public function setIsInstallResolved($isInstallResolved)
173
+ {
174
+ $this->isInstallResolved = $isInstallResolved;
175
+ }
176
+ }
analyst/src/Account/AccountDataFactory.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Account;
4
+
5
+ /**
6
+ * Class AccountDataFactory
7
+ *
8
+ * Holds information about this
9
+ * wordpress project plugins accounts
10
+ *
11
+ */
12
+ class AccountDataFactory
13
+ {
14
+ private static $instance;
15
+
16
+ CONST OPTIONS_KEY = 'analyst_accounts_data';
17
+
18
+ /**
19
+ * @var AccountData[]
20
+ */
21
+ protected $accounts = [];
22
+
23
+ /**
24
+ * Read factory from options or make fresh instance
25
+ *
26
+ * @return static
27
+ */
28
+ public static function instance()
29
+ {
30
+ if (!static::$instance) {
31
+ $raw = get_option(self::OPTIONS_KEY);
32
+
33
+ // In case this object is not serialized
34
+ // we instantiate new object
35
+ if (!$raw) {
36
+ static::$instance = new self();
37
+ } else {
38
+ static::$instance = unserialize($raw);
39
+ }
40
+
41
+ }
42
+
43
+ return static::$instance;
44
+ }
45
+
46
+ /**
47
+ * Sync this object data with cache
48
+ */
49
+ public function sync()
50
+ {
51
+ update_option(self::OPTIONS_KEY, serialize($this));
52
+ }
53
+
54
+ /**
55
+ * Sync this instance data with cache
56
+ */
57
+ public static function syncData()
58
+ {
59
+ static::instance()->sync();
60
+ }
61
+
62
+ /**
63
+ * Find plugin account data or create fresh one
64
+ *
65
+ * @param Account $account