PluginProbe
Visual Composer Website Builder / 45.3.0
Visual Composer Website Builder v45.3.0
45.16.4 45.16.3 45.16.2 45.16.1 45.2-beta.1 45.2-beta.2 45.2.0 45.3-beta.1 45.3.0 45.4-beta.1 45.4.0 45.4.1 45.4.1-beta.2 45.5-beta.1 45.5.0 45.6-beta.1 45.6.0 45.7-beta.1 45.7.0 45.8-beta.1 45.8.0 45.9.0 trunk 45.0 45.0-beta.1 All 42 releases
visualcomposer / visualcomposer / Modules / Editors / DataUsage / Controller.php

Controller.php in Visual Composer Website Builder 45.3.0, at visualcomposer/Modules/Editors/DataUsage/Controller.php

547 lines 18.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace VisualComposer\Modules\Editors\DataUsage;
4
5 if (!defined('ABSPATH')) {
6 header('Status: 403 Forbidden');
7 header('HTTP/1.1 403 Forbidden');
8 exit;
9 }
10
11 use VisualComposer\Framework\Illuminate\Support\Module;
12 use VisualComposer\Framework\Container;
13 use VisualComposer\Helpers\License;
14 use VisualComposer\Helpers\Options;
15 use VisualComposer\Helpers\Request;
16 use VisualComposer\Helpers\Traits\EventsFilters;
17 use VisualComposer\Helpers\Traits\WpFiltersActions;
18
19 /**
20 * Class Controller.
21 */
22 class Controller extends Container implements Module
23 {
24 use EventsFilters;
25 use WpFiltersActions;
26
27 public function __construct()
28 {
29 /** @see \VisualComposer\Modules\Editors\DataUsage\Controller::updateInitialUsage */
30 $this->addFilter('vcv:editors:frontend:render', 'updateInitialUsage', 1);
31 /** @see \VisualComposer\Modules\Editors\DataUsage\Controller::sendUsageData */
32 $this->addEvent('vcv:admin:inited vcv:system:activation:hook vcv:hub:checkForUpdate', 'sendUsageData');
33 $this->addFilter('vcv:editor:variables', 'addDataCollectionVariables');
34 $this->addFilter('vcv:ajax:dataCollection:submit:adminNonce', 'submitDataCollection');
35 $this->addEvent('vcv:saveUsageStats', 'saveUsageStats');
36 $this->addEvent('vcv:saveTemplateUsage', 'saveTemplateUsage');
37 $this->addEvent('vcv:saveTeaserDownload', 'saveTeaserDownload');
38 }
39
40 protected function updateInitialUsage($response, $payload)
41 {
42 global $post;
43 if (!isset($post, $post->ID)) {
44 return false;
45 }
46 $optionsHelper = vchelper('Options');
47
48 $sourceId = $post->ID;
49
50 $editorStartDate = time();
51 update_post_meta($sourceId, '_' . VCV_PREFIX . 'editorStartedAt', $editorStartDate);
52
53 $initialUsages = (int)$optionsHelper->get('initialEditorUsage');
54 if ($initialUsages) {
55 $initialUsages++;
56 } else {
57 $initialUsages = 1;
58 }
59 $optionsHelper->set('initialEditorUsage', $initialUsages);
60
61 return $response;
62 }
63
64 /**
65 * Send user usage data statistic to VC data collection server.
66 *
67 * @param \VisualComposer\Helpers\License $licenseHelper
68 * @param \VisualComposer\Helpers\Options $optionsHelper
69 */
70 protected function sendUsageData(License $licenseHelper, Options $optionsHelper)
71 {
72 if (!$this->isNeedUserData()) {
73 return;
74 }
75
76 $updatedPostsList = $optionsHelper->get('updatedPostsList');
77 $usageStats = $this->getUsageStats($updatedPostsList);
78
79 if (!$usageStats) {
80 return;
81 }
82
83 $data = [
84 'vcv-send-usage-statistics' => 'sendUsageStatistics',
85 'vcv-statistics' => $usageStats,
86 'vcv-hashed-url' => $licenseHelper->getHashedKey(get_site_url()),
87 ];
88
89 $json = wp_json_encode($data);
90 $zip = zlib_encode($json, ZLIB_ENCODING_DEFLATE);
91 // Base64 is safe to send through the network
92 // @codingStandardsIgnoreLine
93 $encodedData = base64_encode($zip);
94
95 $response = wp_remote_post(
96 vcvenv('VCV_HUB_URL'),
97 [
98 'body' => [
99 'vcv-send-usage-statistics' => $encodedData,
100 ],
101 'timeout' => 30,
102 ]
103 );
104
105 $this->afterDataSendProcess($response, $updatedPostsList);
106 }
107
108 /**
109 * Check if we need user data right now.
110 * We send user data once a day.
111 *
112 * @return bool
113 */
114 public function isNeedUserData()
115 {
116 $optionsHelper = vchelper('Options');
117 $isAllowed = $optionsHelper->get('settings-itemdatacollection-enabled', false);
118
119 if (!$isAllowed) {
120 return false;
121 }
122
123 // Once in a day transient.
124 $isAlreadySend = $optionsHelper->getTransient('lastUsageSend');
125
126 if ($isAlreadySend) {
127 return false;
128 }
129
130 return true;
131 }
132
133 /**
134 * Collect user usage statistics.
135 *
136 * @note If you change anything in the data,
137 * you also need to change the information table
138 * here visualcomposer/resources/views/settings/fields/dataCollectionTable.php
139 *
140 * @param array $updatedPostsList
141 *
142 * @return array
143 */
144 protected function getUsageStats($updatedPostsList)
145 {
146 $optionsHelper = vchelper('Options');
147 $usageStats = [];
148 $teaserDownloads = $optionsHelper->get('downloadedContent');
149 if (maybe_unserialize($teaserDownloads)) {
150 $usageStats['downloadedContent'] = maybe_unserialize($teaserDownloads);
151 }
152
153 $licenseHelper = vchelper('License');
154 if ($updatedPostsList && is_array($updatedPostsList)) {
155 foreach ($updatedPostsList as $postId) {
156 $hashedId = $licenseHelper->getHashedKey($postId);
157 $editorUsage = get_post_meta($postId, '_' . VCV_PREFIX . 'editorUsage', true);
158 $elementUsage = get_post_meta($postId, '_' . VCV_PREFIX . 'elementDiffs', true);
159 $templateUsage = get_post_meta($postId, '_' . VCV_PREFIX . 'templates', true);
160
161 if (maybe_unserialize($editorUsage)) {
162 $editorUsageData = $this->getEditorUsageData($editorUsage);
163
164 $usageStats[ $hashedId ]['editorUsage'] = $editorUsageData;
165 }
166 if (maybe_unserialize($elementUsage)) {
167 $usageStats[ $hashedId ]['elementUsage'] = maybe_unserialize($elementUsage);
168 }
169 if (maybe_unserialize($templateUsage)) {
170 $usageStats[ $hashedId ]['templateUsage'] = maybe_unserialize($templateUsage);
171 }
172 }
173 }
174
175 return $usageStats;
176 }
177
178 /**
179 * Get editor usage data.
180 *
181 * @param string $editorUsage
182 *
183 * @return array|mixed
184 */
185 protected function getEditorUsageData($editorUsage)
186 {
187 // @codingStandardsIgnoreLine
188 global $wp_version;
189 $editorUsageData = maybe_unserialize($editorUsage);
190 if (is_array($editorUsageData)) {
191 $activeTheme = wp_get_theme();
192 foreach ($editorUsageData as $key => $value) {
193 $editorUsageData[ $key ]['phpVersion'] = phpversion();
194 // @codingStandardsIgnoreLine
195 $editorUsageData[ $key ]['wpVersion'] = $wp_version;
196 $editorUsageData[ $key ]['vcvVersion'] = VCV_VERSION;
197 $editorUsageData[ $key ]['activeTheme'] = $activeTheme->get('Name');
198 }
199 } else {
200 $editorUsageData = [];
201 }
202
203 return $editorUsageData;
204 }
205
206 /**
207 * Action after send statistic.
208 *
209 * @param array|\WP_Error $response
210 * @param array $updatedPostsList
211 */
212 protected function afterDataSendProcess($response, $updatedPostsList)
213 {
214 $optionsHelper = vchelper('Options');
215 $isResponseSuccess = wp_remote_retrieve_response_code($response) === 200;
216
217 if ($isResponseSuccess) {
218 // Set transient that expires in 1 day
219 $optionsHelper->setTransient('lastUsageSend', 1, 12 * 3600);
220 $optionsHelper->set('lastSentDate', time());
221
222 // Prevent multiple same template sending
223 if ($updatedPostsList && is_array($updatedPostsList)) {
224 foreach ($updatedPostsList as $postId) {
225 delete_post_meta($postId, '_' . VCV_PREFIX . 'templates');
226 delete_post_meta($postId, '_' . VCV_PREFIX . 'elementDiffs');
227 $allElements = get_post_meta($postId, '_' . VCV_PREFIX . 'allElements', true);
228 update_post_meta($postId, '_' . VCV_PREFIX . 'elements', $allElements);
229 }
230 }
231 $optionsHelper->delete('updatedPostsList');
232 $optionsHelper->delete('downloadedContent');
233 } else {
234 // If failed try one more time after one hour
235 $optionsHelper->setTransient('lastUsageSend', 1, 3600);
236 }
237 }
238
239 /**
240 * @param $variables
241 * @param $payload
242 *
243 * @return array
244 */
245 protected function addDataCollectionVariables($variables, $payload)
246 {
247 $optionsHelper = vchelper('Options');
248 $isEnabled = $optionsHelper->get('settings-itemdatacollection-enabled', null);
249 // Have at least 10 initial usages
250 $initialUsages = (int)$optionsHelper->get('initialEditorUsage');
251 // @codingStandardsIgnoreLine
252 $dataCollectionPopupOk = $initialUsages >= 10;
253
254 $variables[] = [
255 'key' => 'VCV_SHOW_DATA_COLLECTION_POPUP',
256 'value' => is_null($isEnabled) && $dataCollectionPopupOk,
257 'type' => 'constant',
258 ];
259 $variables[] = [
260 'key' => 'vcvIsDataCollectionEnabled',
261 'value' => $isEnabled,
262 'type' => 'variable',
263 ];
264
265 return $variables;
266 }
267
268 /**
269 * Send anonymous usage data collection permit
270 *
271 * @param $response
272 * @param \VisualComposer\Helpers\Request $requestHelper
273 * @param \VisualComposer\Helpers\Options $optionsHelper
274 *
275 * @return array
276 */
277 protected function submitDataCollection(
278 $response,
279 Request $requestHelper,
280 Options $optionsHelper
281 ) {
282 $isChecked = $requestHelper->input('vcv-dataCollection');
283 $isChecked = filter_var($isChecked, FILTER_VALIDATE_BOOLEAN);
284 $value = $isChecked ? 'itemDataCollectionEnabled' : '';
285
286 $optionsHelper->set('settings-itemdatacollection-enabled', $value);
287
288 return ['status' => true];
289 }
290
291 protected function saveUsageStats($response, $payload, License $licenseHelper)
292 {
293 $sourceId = $payload['sourceId'];
294 $elements = $payload['elements'];
295 $date = time();
296
297 $optionsHelper = vchelper('Options');
298 $updatedPostsList = $optionsHelper->get('updatedPostsList', []);
299 if (!in_array($sourceId, $updatedPostsList)) {
300 $updatedPostsList[] = $sourceId;
301 }
302
303 $optionsHelper->set('updatedPostsList', $updatedPostsList);
304
305 $this->saveEditorUsage($sourceId, $payload, $date);
306 $this->saveElementsUsage($sourceId, $elements, $date);
307
308 // Update editor start time field for multiple save without page refresh
309 update_post_meta($sourceId, '_' . VCV_PREFIX . 'editorStartedAt', $date);
310
311 return false;
312 }
313
314 /**
315 * Save editor usage data.
316 *
317 * @param int $sourceId
318 * @param array $payload
319 * @param int $date
320 */
321 protected function saveEditorUsage($sourceId, $payload, $date)
322 {
323 $licenseHelper = vchelper('License');
324 $hashedId = $licenseHelper->getHashedKey($sourceId);
325
326 $licenseType = $payload['licenseType'];
327 if (!$licenseType) {
328 $licenseType = 'Not Activated';
329 }
330
331 $editorStartDate = get_post_meta($sourceId, '_' . VCV_PREFIX . 'editorStartedAt', true);
332 $editorEndDate = $date;
333
334 $optionsHelper = vchelper('Options');
335
336 $editorUsage = get_post_meta($sourceId, '_' . VCV_PREFIX . 'editorUsage', true);
337 $editorUsage = maybe_unserialize($editorUsage);
338
339 if (!is_array($editorUsage)) {
340 $editorUsage = [];
341 }
342
343 // Remove previous usage if data was sent before
344 $lastSentDate = $optionsHelper->get('lastSentDate');
345 foreach ($editorUsage as $key => $value) {
346 if ($value['timestamp'] < $lastSentDate) {
347 unset($editorUsage[ $key ]);
348 }
349 }
350 $editorUsage[] = [
351 'pageId' => $hashedId,
352 'license' => ucfirst($licenseType),
353 'startDate' => $editorStartDate,
354 'endDate' => $editorEndDate,
355 'timestamp' => time(),
356 ];
357
358 $editorUsage = maybe_unserialize($editorUsage);
359
360 update_post_meta($sourceId, '_' . VCV_PREFIX . 'editorUsage', $editorUsage);
361 }
362
363 /**
364 * Save editor elements usage data.
365 *
366 * @param int $sourceId
367 * @param string $elements
368 * @param string $date
369 */
370 protected function saveElementsUsage($sourceId, $elements, $date)
371 {
372 $licenseHelper = vchelper('License');
373
374 $elements = json_decode($elements, true);
375 if ($elements) {
376 foreach ($elements as $key => $value) {
377 $elements[ $key ]['pageId'] = $licenseHelper->getHashedKey($elements[ $key ]['pageId']);
378 $elements[ $key ]['date'] = $date;
379 }
380 }
381
382 $previousElements = get_post_meta($sourceId, '_' . VCV_PREFIX . 'elements', true);
383 $previousElements = maybe_unserialize($previousElements);
384
385 $newElements = $this->getNewElements($previousElements, $elements);
386 $newElements = maybe_serialize($newElements);
387 update_post_meta($sourceId, '_' . VCV_PREFIX . 'elementDiffs', $newElements);
388
389 $elements = maybe_serialize($elements);
390 update_post_meta($sourceId, '_' . VCV_PREFIX . 'allElements', $elements);
391 }
392
393 protected function getNewElements($previousElements, $elements)
394 {
395 $newElements = [];
396 if ($previousElements && is_array($previousElements) && is_array($elements)) {
397 $mergedElements = array_merge($previousElements, $elements);
398 foreach ($mergedElements as $key => $value) {
399 if (!isset($elements[ $key ])) {
400 $newElements[ $key ] = [
401 'pageId' => $value['pageId'],
402 'name' => $value['name'],
403 'count' => $value['count'],
404 'type' => $value['type'],
405 'action' => 'Deleted',
406 'license' => $value['license'],
407 'date' => time(),
408 ];
409 }
410 if (!isset($previousElements[ $key ])) {
411 $newElements[ $key ] = [
412 'pageId' => $value['pageId'],
413 'name' => $value['name'],
414 'count' => $value['count'],
415 'type' => $value['type'],
416 'action' => 'Added',
417 'license' => $value['license'],
418 'date' => time(),
419 ];
420 }
421 if (isset($elements[ $key ]) && isset($previousElements[ $key ])) {
422 $diff = $elements[ $key ]['count'] - $previousElements[ $key ]['count'];
423 if ($diff !== 0) {
424 $newElements[ $key ] = [
425 'pageId' => $value['pageId'],
426 'name' => $value['name'],
427 'count' => abs($diff),
428 'type' => $value['type'],
429 'action' => $diff > 0 ? 'Added' : 'Deleted',
430 'license' => $value['license'],
431 'date' => time(),
432 ];
433 }
434 }
435 }
436 } else {
437 $newElements = $elements;
438 }
439
440 return $newElements;
441 }
442
443 protected function saveTemplateUsage($response, $payload, License $licenseHelper)
444 {
445 $sourceId = $payload['sourceId'];
446 $hashedId = $licenseHelper->getHashedKey($sourceId);
447 $id = $payload['templateId'];
448 $editorTemplatesHelper = vchelper('EditorTemplates');
449 $optionsHelper = vchelper('Options');
450 $template = $editorTemplatesHelper->read($id);
451 $templateGroupKey = $template['allData']['templatesGroupsSorted'][0];
452 $licenseType = $optionsHelper->get('license-type');
453 if (!$licenseType) {
454 $licenseType = 'Not Activated';
455 }
456 $templateType = $editorTemplatesHelper->getGroupName($templateGroupKey);
457
458 $templates = get_post_meta($sourceId, '_' . VCV_PREFIX . 'templates', true);
459 $templates = maybe_unserialize($templates);
460 if (empty($templates)) {
461 $templates = [];
462 }
463 $templates[ $id ] = [
464 'pageId' => $hashedId,
465 'name' => $template['allData']['pageTitle']['current'],
466 'license' => ucfirst($licenseType),
467 'action' => 'Added',
468 'date' => time(),
469 'type' => $templateType,
470 ];
471 $templates = maybe_serialize($templates);
472 update_post_meta($sourceId, '_' . VCV_PREFIX . 'templates', $templates);
473
474 return false;
475 }
476
477 protected function saveTeaserDownload($response, $payload, License $licenseHelper)
478 {
479 $sourceId = $payload['sourceId'];
480 if (!$sourceId) {
481 $hashedId = 'dashboard';
482 } else {
483 $hashedId = $licenseHelper->getHashedKey($sourceId);
484 }
485 $teaser = isset($payload['template']) ? $payload['template'] : $payload['element'];
486 $optionsHelper = vchelper('Options');
487 $licenseType = $optionsHelper->get('license-type');
488 if (!$licenseType) {
489 $licenseType = 'Not Activated';
490 }
491 $downloadedContent = $optionsHelper->get('downloadedContent', []);
492 if (!empty($downloadedContent)) {
493 $downloadedContent = maybe_unserialize($downloadedContent);
494 }
495
496 $teaserId = isset($teaser['id']) ? $teaser['id'] : $teaser['key'];
497
498 if (isset($payload['element'])) {
499 $elementData = array_values(
500 (array)$optionsHelper->get(
501 'hubTeaserElements',
502 [
503 'All Elements' => [
504 'id' => 'AllElements0',
505 'index' => 0,
506 'title' => 'All Elements',
507 'elements' => [],
508 ],
509 ]
510 )
511 );
512 $allElements = $elementData[0]['elements'];
513
514 foreach ($allElements as $value) {
515 if ($value['tag'] === $teaser['tag']) {
516 $teaser['type'] = in_array('free', $value['bundleType']) ? 'Free' : 'Premium';
517 }
518 }
519 }
520
521 if (isset($payload['template'])) {
522 $downloadedContent['templateUsage'][ $teaserId ] = [
523 'pageId' => $hashedId,
524 'name' => $teaser['name'],
525 'license' => ucfirst($licenseType),
526 'action' => 'Downloaded',
527 'date' => time(),
528 'type' => $teaser['type'] === 'hub' ? 'Premium' : 'Free',
529 ];
530 } else {
531 $downloadedContent['elementUsage'][ $teaserId ] = [
532 'pageId' => $hashedId,
533 'name' => isset($teaser['name']) ? $teaser['name'] : $teaser['tag'],
534 'license' => ucfirst($licenseType),
535 'action' => 'Downloaded',
536 'date' => time(),
537 'type' => $teaser['type'],
538 ];
539 }
540
541 $downloadedContent = maybe_serialize($downloadedContent);
542 $optionsHelper->set('downloadedContent', $downloadedContent);
543
544 return false;
545 }
546 }
547