PluginProbe
Vision – Interactive Image Map with Hotspots Builder / 1.9.2
Vision – Interactive Image Map with Hotspots Builder v1.9.2
1.12.2 1.12.1 1.12.0 1.11.0 1.6.0 1.6.1 1.6.2 1.7.1 1.7.2 1.7.3 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 All 33 releases
vision / includes / plugin.php

plugin.php in Vision – Interactive Image Map with Hotspots Builder 1.9.2, at includes/plugin.php

1,327 lines 51.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined('ABSPATH') || exit;
3
4 class Vision_Builder {
5 private $pluginBasename = NULL;
6
7 private $ajax_action_item_update = NULL;
8 private $ajax_action_item_update_status = NULL;
9 private $ajax_action_settings_update = NULL;
10 private $ajax_action_settings_get = NULL;
11 private $ajax_action_delete_data = NULL;
12 private $ajax_action_modal = NULL;
13
14 private $vision_map_id = null;
15 private $vision_map_version = null;
16 private $shortcodes = [];
17
18 function __construct($pluginBasename) {
19 $this->pluginBasename = $pluginBasename;
20 }
21
22 function run() {
23 $upload_dir = wp_upload_dir();
24 $plugin_url = plugin_dir_url(dirname(__FILE__));
25
26 define('VISION_PLUGIN_UPLOAD_DIR', wp_normalize_path($upload_dir['basedir'] . '/vision'));
27 define('VISION_PLUGIN_UPLOAD_URL', set_url_scheme($upload_dir['baseurl'] . '/vision/'));
28
29 define('VISION_PLUGIN_PLAN', 'lite');
30
31 $user = wp_get_current_user(); //is_super_admin()
32 $allowed_roles = $this->getAllowedRoles();
33 if((array_intersect($allowed_roles, $user->roles) || current_user_can('manage_options')) && is_admin()) {
34 $this->ajax_action_item_update = 'vision_ajax_item_update';
35 $this->ajax_action_item_update_status = 'vision_ajax_item_update_status';
36 $this->ajax_action_settings_update = 'vision_ajax_settings_update';
37 $this->ajax_action_settings_get = 'vision_ajax_settings_get';
38 $this->ajax_action_delete_data = 'vision_ajax_delete_data';
39 $this->ajax_action_modal = 'vision_ajax_modal';
40
41 load_plugin_textdomain('vision', false, dirname(dirname(plugin_basename(__FILE__))) . '/languages/');
42
43 add_action('admin_menu', [$this, 'admin_menu']);
44 add_filter('submenu_file', [$this, 'admin_menu_highlight'], 10, 2);
45 add_action('admin_footer', [$this, 'admin_footer']);
46 add_action('admin_notices', [$this, 'admin_notices']);
47 add_action('in_admin_header', [$this, 'in_admin_header']);
48 add_action('wp_loaded', [$this, 'page_redirects']);
49
50 // important, because ajax has another url
51 add_action('wp_ajax_' . $this->ajax_action_item_update, [$this, 'ajax_item_update']);
52 add_action('wp_ajax_' . $this->ajax_action_item_update_status, [$this, 'ajax_item_update_status']);
53 add_action('wp_ajax_' . $this->ajax_action_settings_update, [$this, 'ajax_settings_update']);
54 add_action('wp_ajax_' . $this->ajax_action_settings_get, [$this, 'ajax_settings_get']);
55 add_action('wp_ajax_' . $this->ajax_action_delete_data, [$this, 'ajax_delete_data']);
56 add_action('wp_ajax_' . $this->ajax_action_modal, [$this, 'ajax_modal']);
57 } else {
58 add_shortcode(VISION_SHORTCODE_NAME, [$this, 'shortcode']);
59 }
60
61 // only logged users with right roles can preview a vision map
62 if(array_intersect($allowed_roles, $user->roles) || current_user_can('manage_options')) {
63 add_filter('do_parse_request', [$this, 'do_parse_request'], 10, 3);
64 }
65
66 add_action('rest_api_init', array($this, 'rest_api_init'));
67 }
68
69 function rest_api_init() {
70 register_rest_route(
71 VISION_PLUGIN_REST_URL, '/item/(?P<id>\d+)',
72 [
73 'methods' => 'GET',
74 'callback' => [$this, 'rest_api_get_item'],
75 'permission_callback' => [$this, 'rest_api_permissions_check']
76 ]
77 );
78 }
79
80 function rest_api_get_item($request) {
81 $id = intval( $request->get_param('id') );
82 $preview = boolval( $request->get_param('preview') );
83
84 global $wpdb;
85 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
86
87 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
88 $sql = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%d AND NOT deleted", $id);
89 $item = $wpdb->get_row($sql, OBJECT);
90 // phpcs:enable
91
92 $config = null;
93 if($item->active) {
94 $config = unserialize($item->config);
95 } else if($preview) {
96 $user = wp_get_current_user();
97 $allowed_roles = $this->getAllowedRoles();
98
99 if(array_intersect($allowed_roles, $user->roles) || current_user_can('manage_options')) {
100 $config = unserialize($item->config);
101 }
102 }
103
104 if($config) {
105 return new WP_REST_Response($config);
106 }
107 return new WP_REST_Response(null, 404);
108 }
109
110 function rest_api_permissions_check() {
111 return true;
112 }
113
114 function filesystem_method() {
115 return 'direct';
116 }
117
118 function request_filesystem_credentials() {
119 return true;
120 }
121
122 function getFileSystem() {
123 global $wp_filesystem;
124 $result = true;
125
126 if(!$wp_filesystem) {
127 require_once(ABSPATH . '/wp-admin/includes/file.php');
128
129 add_filter('filesystem_method', [$this, 'filesystem_method']);
130 add_filter('request_filesystem_credentials', [$this, 'request_filesystem_credentials']);
131
132 $credentials = request_filesystem_credentials(site_url(), '', true, false, null);
133
134 $result = WP_Filesystem($credentials);
135
136 remove_filter('filesystem_method', [$this, 'filesystem_method']);
137 remove_filter('request_filesystem_credentials', [$this, 'request_filesystem_credentials']);
138 }
139
140 if($result)
141 return $wp_filesystem;
142 return null;
143 }
144
145 function joinPaths() {
146 $paths = [];
147
148 foreach(func_get_args() as $arg) {
149 if($arg !== '') {
150 $paths[] = $arg;
151 }
152 }
153
154 return preg_replace('#/+#','/',join('/', $paths));
155 }
156
157 function joinUrls() {
158 $urls = [];
159
160 foreach(func_get_args() as $arg) {
161 if($arg !== '') {
162 $urls[] = $arg;
163 }
164 }
165
166 return preg_replace('/([^:])(\/{2,})/','$1/',join('/', $urls));
167 }
168
169 function IsNullOrEmptyString($str) {
170 return(!isset($str) || trim($str)==='');
171 }
172
173 function getAllowedRoles() {
174 $allowed_roles = ['administrator'];
175
176 $settings_key = 'vision_settings';
177 $settings_value = get_option($settings_key);
178 if($settings_value) {
179 $settings = unserialize($settings_value);
180 if(is_array($settings->roles)) $allowed_roles = array_merge($allowed_roles, $settings->roles);
181 }
182
183 return $allowed_roles;
184 }
185
186 function getLoaderGlobals($timestamp) {
187 $plugin_url = plugin_dir_url(dirname(__FILE__));
188
189 $globals = [
190 'plan' => VISION_PLUGIN_PLAN,
191 'version' => $timestamp,
192 'effects_url' => $plugin_url . 'assets/css/vision-effects.css',
193 'theme_base_url' => $plugin_url . 'assets/themes/',
194 'plugin_base_url' => $plugin_url . 'assets/vendor/vision/',
195 'plugin_version' => VISION_PLUGIN_VERSION,
196 'ssl' => is_ssl(),
197 'api' => [
198 'nonce' => wp_create_nonce( 'wp_rest' ),
199 'url' => esc_url_raw( rest_url( VISION_PLUGIN_REST_URL ) )
200 ]
201 ];
202
203 return $globals;
204 }
205
206 function embedLoader($in_footer, $timestamp) {
207 $plugin_url = plugin_dir_url(dirname(__FILE__));
208 wp_enqueue_script('vision_loader', $plugin_url . 'assets/js/loader.js', ['jquery'], VISION_PLUGIN_VERSION, $in_footer);
209 wp_localize_script('vision_loader', 'vision_globals', $this->getLoaderGlobals($timestamp));
210 }
211
212 /**
213 * generate main css text
214 */
215 function getMainCss($itemData, $itemId) {
216 $upload_dir = wp_upload_dir();
217
218 // create main css
219 $main_css = '';
220 $main_css .= '.vision-map-' . $itemId . ' {' . PHP_EOL;
221
222 $main_css .= (!$this->IsNullOrEmptyString($itemData->background->color) ? 'background-color:' . $itemData->background->color . ';' . PHP_EOL : '');
223 if(!$this->IsNullOrEmptyString($itemData->background->image->url)) {
224 $imageUrl = ($itemData->background->image->relative ? $upload_dir['baseurl'] : '') . $itemData->background->image->url;
225 $main_css .= 'background-image:url(' . $imageUrl . ');' . PHP_EOL;
226 }
227 $main_css .= ($itemData->background->size ? 'background-size:' . $itemData->background->size . ';' . PHP_EOL : '');
228 $main_css .= ($itemData->background->repeat ? 'background-repeat:' . $itemData->background->repeat . ';' . PHP_EOL : '');
229 $main_css .= ($itemData->background->position ? 'background-position:' . $itemData->background->position . ';' . PHP_EOL : '');
230
231 $main_css .= '}' . PHP_EOL;
232
233 $layerId = 0;
234 foreach($itemData->layers as $layerKey => $layer) {
235 if(!$layer->visible) {
236 continue;
237 }
238
239 $layerId++;
240 $layerSelector = '.vision-map-' . $itemId . ' .vision-layers [data-layer-id="' . $layer->id . '"] .vision-body';
241
242 // main
243 $main_css .= $layerSelector . ' {' . PHP_EOL;
244 switch($layer->type) {
245 case 'link': {
246 $main_css .= ($layer->link->normalColor ? 'background-color:' . $layer->link->normalColor . ';' . PHP_EOL : '');
247 $main_css .= ($layer->link->radius != NULL ? 'border-radius:' . $layer->link->radius . ';' . PHP_EOL : '');
248 } break;
249 case 'image': {
250 $main_css .= (!$this->IsNullOrEmptyString($layer->image->background->color) ? 'background-color:' . $layer->image->background->color . ';' . PHP_EOL : '');
251 if(!$this->IsNullOrEmptyString($layer->image->background->file->url)) {
252 $imageUrl = ($layer->image->background->file->relative ? $upload_dir['baseurl'] : '') . $layer->image->background->file->url;
253 $main_css .= 'background-image:url(' . $imageUrl . ');' . PHP_EOL;
254 }
255 $main_css .= ($layer->image->background->size ? 'background-size:' . $layer->image->background->size . ';' . PHP_EOL : '');
256 $main_css .= ($layer->image->background->repeat ? 'background-repeat:' . $layer->image->background->repeat . ';' . PHP_EOL : '');
257 $main_css .= ($layer->image->background->position ? 'background-position:' . $layer->image->background->position . ';' . PHP_EOL : '');
258 } break;
259 case 'text': {
260 $main_css .= (!$this->IsNullOrEmptyString($layer->text->background->color) ? 'background-color:' . $layer->text->background->color . ';' . PHP_EOL : '');
261 if(!$this->IsNullOrEmptyString($layer->text->background->file->url)) {
262 $imageUrl = ($layer->text->background->file->relative ? $upload_dir['baseurl'] : '') . $layer->text->background->file->url;
263 $main_css .= 'background-image:url(' . $imageUrl . ');' . PHP_EOL;
264 }
265 $main_css .= ($layer->text->background->size ? 'background-size:' . $layer->text->background->size . ';' . PHP_EOL : '');
266 $main_css .= ($layer->text->background->repeat ? 'background-repeat:' . $layer->text->background->repeat . ';' . PHP_EOL : '');
267 $main_css .= ($layer->text->background->position ? 'background-position:' . $layer->text->background->position . ';' . PHP_EOL : '');
268
269 $main_css .= ($layer->text->font ? 'font-family:"' . str_replace('+', ' ', $layer->text->font) . '",sans-serif;' . PHP_EOL : '');
270 $main_css .= ($layer->text->color ? 'color:' . $layer->text->color . ';' . PHP_EOL : '');
271 $main_css .= ($layer->text->size != NULL ? 'font-size:' . $layer->text->size . 'px;' . PHP_EOL : '');
272 $main_css .= ($layer->text->lineHeight != NULL ? 'line-height:' . $layer->text->lineHeight . 'px;' . PHP_EOL : '');
273 $main_css .= ($layer->text->align ? 'text-align:' . $layer->text->align . ';' . PHP_EOL : '');
274 $main_css .= ($layer->text->letterSpacing != NULL ? 'letter-spacing:' . $layer->text->letterSpacing . 'px;' . PHP_EOL : '');
275 } break;
276 }
277 $main_css .= '}' . PHP_EOL;
278
279 if($layer->type == 'link') {
280 $main_css .= $layerSelector . ':hover {' . PHP_EOL;
281 $main_css .= ($layer->link->hoverColor ? 'background-color:' . $layer->link->hoverColor . ';' . PHP_EOL : '');
282 $main_css .= '}' . PHP_EOL;
283 }
284 }
285
286 return $main_css;
287 }
288
289 /**
290 * Shortcode output for the plugin
291 */
292 function shortcode($atts) {
293 extract(shortcode_atts(['id'=>0, 'slug'=>NULL, 'class'=>NULL], $atts, VISION_SHORTCODE_NAME));
294
295 if(!$id && !$slug) {
296 return '<p>' . esc_html__('Error: invalid vision identifier attribute', 'vision') . '</p>';
297 }
298
299 $id = intval($id, 10);
300 $slug = sanitize_key($slug);
301 $class = sanitize_text_field($class);
302
303 global $wpdb;
304 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
305 $upload_dir = wp_upload_dir();
306
307 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
308 $sql = ($id ? $wpdb->prepare("SELECT * FROM {$table} WHERE id=%d AND NOT deleted", $id) : $wpdb->prepare("SELECT * FROM {$table} WHERE slug=%s AND NOT deleted LIMIT 0, 1", $slug));
309 $item = $wpdb->get_row($sql, OBJECT);
310 // phpcs:enable
311
312 $preview = filter_input(INPUT_GET, 'preview', FILTER_SANITIZE_NUMBER_INT);
313
314 if($item && ($item->active || (!$item->active && $preview == 1))) {
315 $version = strtotime(mysql2date('d M Y H:i:s', $item->modified));
316 $itemData = unserialize($item->data);
317 $id = $item->id;
318 $id_postfix = strtolower(wp_generate_password(5, false)); // generate unique postfix for $id to avoid clashes with multiple same shortcode use
319 $id_element = 'vision-' . $id . '-' . $id_postfix;
320
321 array_push($this->shortcodes, ['id' => $item->id, 'version' => $version]);
322
323 if(sizeof($this->shortcodes) == 1) {
324 $this->embedLoader(true, $version);
325 }
326
327 ob_start(); // turn on buffering
328
329 echo '<!-- vision begin -->' . PHP_EOL;
330 echo '<div ';
331 echo (property_exists($itemData, 'containerId') && $itemData->containerId ? 'id="' . esc_attr($itemData->containerId) . '" ':'');
332 echo 'class="vision-map vision-map-' . esc_attr($id . ($class ? ' ' . $class : '')) . '"';
333 echo 'data-json-src="'. esc_url_raw( rest_url( VISION_PLUGIN_REST_URL ) ) . '/item/' . esc_attr($item->id) . ($preview ? '?preview=1' : '') . '" ';
334 echo 'data-item-id="' . esc_attr($item->id) . '" ';
335 echo 'tabindex="1" ';
336 echo '>' . PHP_EOL;
337 if (property_exists($itemData, 'image')) {
338 $upload_dir = wp_upload_dir();
339 $imageUrl = ($itemData->image->relative ? $upload_dir['baseurl'] : '') . $itemData->image->url;
340 echo "<img src='" . esc_url($imageUrl). "' class='vision-img-placeholder' width='100%'>";
341 }
342
343 //=============================================
344 // STORE BEGIN
345 echo '<div class="vision-store" style="display:none;">' . PHP_EOL;
346 echo '<div class="vision-layers-data">' . PHP_EOL;
347 foreach($itemData->layers as $layerKey => $layer) {
348 if(!$layer->visible) {
349 continue;
350 }
351
352 //=============================================
353 // LAYER BEGIN
354 echo '<div class="vision-layer" data-layer-id="' . esc_attr($layer->id) . '">';
355
356 if($layer->contentData) {
357 echo do_shortcode($layer->contentData);
358 }
359
360 if($layer->type == 'text') {
361 echo wp_kses_post($layer->text->data);
362 }
363
364 echo '</div>' . PHP_EOL;
365 // LAYER END
366 //=============================================
367 }
368 echo '</div>' . PHP_EOL;
369
370 echo '<div class="vision-tooltips-data">' . PHP_EOL;
371 foreach($itemData->layers as $layerKey => $layer) {
372 if(!$layer->visible) {
373 continue;
374 }
375
376 //=============================================
377 // TOOLTIP BEGIN
378 echo '<div class="vision-data" data-layer-id="' . esc_attr($layer->id) . '">';
379 echo do_shortcode($layer->tooltip->data);
380 echo '</div>' . PHP_EOL;
381 // TOOLTIP END
382 //=============================================
383 }
384 echo '</div>' . PHP_EOL;
385
386 echo '<div class="vision-popovers-data">' . PHP_EOL;
387 foreach($itemData->layers as $layerKey => $layer) {
388 if(!$layer->visible) {
389 continue;
390 }
391
392 //=============================================
393 // POPOVER BEGIN
394 echo '<div class="vision-data" data-layer-id="' . esc_attr($layer->id) . '">';
395 echo do_shortcode($layer->popover->data);
396 echo '</div>' . PHP_EOL;
397 // POPOVER END
398 //=============================================
399 }
400 echo '</div>' . PHP_EOL;
401
402 echo '</div>' . PHP_EOL;
403 // STORE END
404 //=============================================
405
406 echo '</div>' . PHP_EOL;
407
408 $css = $this->getMainCss($itemData, $id) . ($itemData->customCSS->active ? $itemData->customCSS->data : '');
409 $css = preg_replace('/[^\/\\\\a-zA-Z0-9\s\_\%\=\[\]\(\)\{\}\:\;\.\,\#\$\-\"\'\']/', '', $css);
410
411 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
412 echo '<style>' . $css . '</style>';
413
414 echo '<!-- vision end -->' . PHP_EOL;
415
416 $output = ob_get_contents(); // get the buffered content into a var
417 ob_end_clean(); // clean buffer
418
419 return $output;
420 }
421
422 return '<p>' . esc_html__('Error: the vision item can’t be found', 'vision') . '</p>';
423 }
424
425 /**
426 * Run a filter to obtain some custom url settings, compare them to the current url
427 * and if a match is found the custom callback is fired, the custom view is loaded
428 * and request is stopped.
429 */
430 function do_parse_request($result) {
431 if(current_filter() !== 'do_parse_request') {
432 return $result;
433 }
434
435 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
436 $url = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
437
438 if(preg_match('/vision\/map\/([a-z0-9_-]+)/', $url, $matches)) {
439 $preview = filter_input(INPUT_GET, 'preview', FILTER_SANITIZE_NUMBER_INT);
440
441 global $wpdb;
442 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
443 $shortcode = false;
444
445 if(is_numeric($matches[1])) {
446 $vision_map_id = $matches[1];
447
448 if($vision_map_id != null) {
449 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
450 $sql = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%d AND NOT deleted", $vision_map_id);
451 $item = $wpdb->get_row($sql, OBJECT);
452 // phpcs:enable
453
454 if($item && ($item->active || (!$item->active && $preview == 1))) {
455 $this->vision_map_id = $item->id;
456 $this->vision_map_version = strtotime(mysql2date('Y-m-d H:i:s', $item->modified));
457 $shortcode = true;
458 }
459 }
460 } else {
461 $vision_map_slug = $matches[1];
462
463 if($vision_map_slug != null) {
464 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
465 $sql = $wpdb->prepare("SELECT * FROM {$table} WHERE slug=%s AND NOT deleted", $vision_map_slug);
466 $item = $wpdb->get_row($sql, OBJECT);
467 // phpcs:enable
468
469 if($item && ($item->active || (!$item->active && $preview == 1))) {
470 $this->vision_map_id = $item->id;
471 $this->vision_map_version = strtotime(mysql2date('Y-m-d H:i:s', $item->modified));
472
473 $shortcode = true;
474 }
475 }
476 }
477
478 if($shortcode) {
479 require_once(plugin_dir_path(dirname(__FILE__)) . 'includes/page-preview.php');
480 exit();
481 }
482 }
483
484 return $result;
485 }
486
487 /**
488 * Prepare upload directory
489 */
490 function admin_notices() {
491 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
492 if(!($page==='vision' || $page==='vision_item')) {
493 return;
494 }
495
496 if(!file_exists(VISION_PLUGIN_UPLOAD_DIR)) {
497 wp_mkdir_p(VISION_PLUGIN_UPLOAD_DIR);
498 }
499
500 if(!file_exists(VISION_PLUGIN_UPLOAD_DIR)) {
501 echo '<div class="notice notice-error is-dismissible">';
502 echo '<p>' . esc_html__('The plugin upload directory could not be created', 'vision') . '</p>';
503 echo '<p>' . esc_html__('Please run the following commands in order to make the directory', 'vision') . '<br>';
504 echo '<b>mkdir ' . esc_attr(VISION_PLUGIN_UPLOAD_DIR) . '</b><br>';
505 echo '<b>chmod 777 ' . esc_attr(VISION_PLUGIN_UPLOAD_DIR) . '</b></p>';
506 echo '</div>';
507 return;
508 }
509
510 if(!wp_is_writable(VISION_PLUGIN_UPLOAD_DIR)) {
511 echo '<div class="notice notice-error is-dismissible">';
512 echo '<p>' . esc_html__('The plugin upload directory is not writable, therefore the css and js files cannot be saved.', 'vision') . '</p>';
513 echo '<p>' . esc_html__('Please run the following commands in order to make the directory', 'vision') . '<br>';
514 echo '<b>chmod 777 ' . esc_attr(VISION_PLUGIN_UPLOAD_DIR) . '</b></p>';
515 echo '</div>';
516 return;
517 }
518
519 if(!file_exists(VISION_PLUGIN_UPLOAD_DIR . '/' . 'index.php')) {
520 $data = '<?php' . PHP_EOL . '// silence is golden' . PHP_EOL . '?>';
521
522 $wp_filesystem = $this->getFileSystem();
523 $wp_filesystem->put_contents(VISION_PLUGIN_UPLOAD_DIR . '/' . 'index.php', $data);
524 }
525 }
526
527 /**
528 * Fires at the beginning of the content section in an admin page
529 */
530 function in_admin_header() {
531 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
532
533 if(!(($page==='vision') || ($page==='vision_item') || ($page==='vision_settings'))) {
534 return;
535 }
536
537 remove_all_actions('admin_notices');
538 remove_all_actions('all_admin_notices');
539 add_action('admin_notices', [$this, 'admin_notices']);
540 }
541
542 /**
543 * Register the administration menu for this plugin into the WordPress Dashboard menu.
544 */
545 function admin_menu() {
546 // add "edit_posts" if we want to give access to author, editor and contributor roles
547 add_menu_page(esc_html__('Vision', 'vision'), esc_html__('Vision', 'vision'), 'read', 'vision', [$this, 'admin_menu_page_items'], 'dashicons-format-image');
548 add_submenu_page('vision', esc_html__('Vision', 'vision'), esc_html__('All Items', 'vision'), 'read', 'vision', [$this, 'admin_menu_page_items']);
549 add_submenu_page('vision', esc_html__('Vision', 'vision'), esc_html__('Add New', 'vision'), 'read', 'vision_item', [$this, 'admin_menu_page_item']);
550 add_submenu_page('vision', esc_html__('Vision', 'vision'), esc_html__('Settings', 'vision'), 'manage_options', 'vision_settings', [$this, 'admin_menu_page_settings']);
551
552 add_submenu_page('vision', esc_html__('Vision', 'vision'), esc_html__('Upgrade to Pro', 'vision'), 'manage_options', 'vision_upgrade_to_pro', [$this, 'admin_menu_page_upgrade_to_pro']);
553
554 }
555
556 function admin_menu_highlight( $submenu_file, $parent_file ) {
557 $page = sanitize_key( filter_input(INPUT_GET, 'page', FILTER_DEFAULT ) );
558 if ( in_array( $page, [ 'vision_item' ] ) ) {
559 $id = sanitize_key( filter_input(INPUT_GET, 'id', FILTER_DEFAULT ) );
560 if ( !empty( $id ) ) {
561 $submenu_file = 'vision';
562 }
563 }
564 return $submenu_file;
565 }
566
567 function admin_footer() {
568 if(get_current_screen() && get_current_screen()->base !== 'plugins') {
569 return;
570 }
571
572 $globals = [
573 'token' => $this->get_token(),
574 'ajax' => [
575 'url' => VISION_FEEDBACK_URL
576 ]
577 ];
578
579 wp_enqueue_style('vision-feedback', VISION_PLUGIN_URL . 'assets/css/feedback.css', [], VISION_PLUGIN_VERSION);
580 wp_enqueue_script('vision-feedback', VISION_PLUGIN_URL . 'assets/js/feedback.js', ['jquery'], VISION_PLUGIN_VERSION, false);
581 wp_localize_script('vision-feedback', 'vision_feedback_globals', $globals);
582
583 require_once(plugin_dir_path(dirname(__FILE__)) . 'templates/feedback.php');
584 }
585
586 function get_token() {
587 global $wp_version;
588 $current_user = wp_get_current_user();
589
590 $data = [
591 'plugin_name' => VISION_PLUGIN_NAME,
592 'plugin_version' => VISION_PLUGIN_VERSION,
593 'wordpress' => $wp_version,
594 'php' => PHP_VERSION,
595 'email' => $current_user->user_email,
596 'site' => trim(str_replace(['http://', 'https://'], '', get_site_url()), '/')
597 ];
598 return base64_encode(wp_json_encode($data));
599 }
600
601 /**
602 * Custom redirects
603 */
604 function page_redirects() {
605 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
606
607 if($page==='vision') {
608 $action = sanitize_key(filter_input(INPUT_GET, 'action', FILTER_DEFAULT));
609 if($action) {
610 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
611 $url = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
612
613 $url = remove_query_arg(['action', 'id', '_wpnonce'], $url );
614 header('Refresh:0; url="' . $url . '"', true, 303);
615 //wp_redirect($url); // does not work delete and dublicate operations on XAMPP
616 }
617 }
618 }
619
620 /**
621 * Show admin menu items page
622 */
623 function admin_menu_page_items() {
624 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
625
626 if($page==='vision') {
627 $plugin_url = plugin_dir_url( dirname(__FILE__) );
628 $upload_dir = wp_upload_dir();
629
630 wp_enqueue_style('vision_admin', $plugin_url . 'assets/css/admin.css', [], VISION_PLUGIN_VERSION, 'all' );
631 wp_enqueue_style('vision_lucide', $plugin_url . 'assets/vendor/lucide/lucide.css', [], VISION_PLUGIN_VERSION, 'all' );
632
633 wp_enqueue_script('vision_admin', $plugin_url . 'assets/js/admin.js', ['jquery'], VISION_PLUGIN_VERSION, false );
634
635 // global settings to help ajax work
636 $globals = [
637 'plan' => VISION_PLUGIN_PLAN,
638 'msg_pro_title' => esc_html__('Available only in Pro version', 'vision'),
639 'upload_url' => $upload_dir['baseurl'],
640 'ajax_url' => admin_url('admin-ajax.php'),
641 'ajax_nonce' => wp_create_nonce('vision_ajax' ),
642 'ajax_msg_error' => esc_html__('Uncaught Error', 'vision') //Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information
643 ];
644 $globals['ajax_action_update'] = $this->ajax_action_item_update_status;
645
646 require_once(plugin_dir_path( dirname(__FILE__) ) . 'includes/list-table-items.php');
647 require_once(plugin_dir_path( dirname(__FILE__) ) . 'includes/page-items.php');
648
649 wp_localize_script('vision_admin', 'vision_globals', $globals);
650 }
651 }
652
653 /**
654 * Show admin menu item page
655 */
656 function admin_menu_page_item() {
657 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
658 if($page==='vision_item') {
659 $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
660 if ( VISION_PLUGIN_PLAN == 'lite' && !$id ) {
661 global $wpdb;
662 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
663
664 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
665 $count = $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
666
667 if ( $count >= 3 ) {
668 echo '<div class="notice notice-error is-dismissible">';
669 echo '<p>Vision: ' . esc_html__('You can create only 3 maps. If you need more, upgrade to the pro version.', 'vision') . '</p>';
670 echo '</div>';
671 return;
672 }
673 }
674
675 $plugin_url = plugin_dir_url(dirname(__FILE__));
676 $upload_dir = wp_upload_dir();
677
678 wp_enqueue_style('vision_admin', $plugin_url . 'assets/css/admin.css', [], VISION_PLUGIN_VERSION, 'all' );
679 wp_enqueue_style('vision_notify', $plugin_url . 'assets/css/notify.css', [], VISION_PLUGIN_VERSION, 'all' );
680 wp_enqueue_style('vision_lucide', $plugin_url . 'assets/vendor/lucide/lucide.css', [], VISION_PLUGIN_VERSION, 'all' );
681 wp_enqueue_style('vision_vision_effects', $plugin_url . 'assets/css/vision-effects.css', [], VISION_PLUGIN_VERSION, 'all' );
682
683 wp_enqueue_script('vision_notify', $plugin_url . 'assets/js/notify.js', ['jquery'], VISION_PLUGIN_VERSION, false );
684 wp_enqueue_script('vision_ace', $plugin_url . 'assets/vendor/ace/ace.js', [], VISION_PLUGIN_VERSION, false );
685 wp_enqueue_script('vision_url', $plugin_url . 'assets/vendor/url/url.js', [], VISION_PLUGIN_VERSION, false );
686 wp_enqueue_script('vision_admin', $plugin_url . 'assets/js/admin.js', ['jquery'], VISION_PLUGIN_VERSION, false );
687
688 wp_enqueue_media();
689
690 // global settings to help ajax work
691 $globals = [
692 'plan' => VISION_PLUGIN_PLAN,
693 'msg_pro_title' => esc_html__('Available only in Pro version', 'vision'),
694 'msg_custom_js_error' => esc_html__('Custom js code error', 'vision'),
695 'msg_layer_id_error' => esc_html__('The layer ID should be unique', 'vision'),
696 'wp_base_url' => get_site_url(),
697 'upload_base_url' => $upload_dir['baseurl'],
698 'plugin_base_url' => $plugin_url,
699 'ajax_url' => admin_url('admin-ajax.php'),
700 'ajax_nonce' => wp_create_nonce('vision_ajax'),
701 'ajax_msg_error' => esc_html__('Uncaught Error', 'vision') //Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information
702 ];
703
704 $globals['ajax_action_get'] = $this->ajax_action_settings_get;
705 $globals['ajax_action_update'] = $this->ajax_action_item_update;
706 $globals['ajax_action_modal'] = $this->ajax_action_modal;
707 $globals['ajax_item_id'] = $id;
708 $globals['settings'] = NULL;
709 $globals['config'] = NULL;
710
711 $settings_key = 'vision_settings';
712 $settings_value = get_option($settings_key);
713 if($settings_value) {
714 $globals['settings'] = unserialize($settings_value); // json_encode(unserialize($settings_value)) problem with double quotes
715 }
716
717 // get item data from DB
718 if($id) {
719 global $wpdb;
720 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
721
722 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
723 $query = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%s", $id);
724 $item = $wpdb->get_row($query, OBJECT);
725 // phpcs:enable
726
727 if($item) {
728 $globals['config'] = unserialize($item->data); // json_encode(unserialize($item->data)) problem with double quotes
729 }
730 } else {
731 // new item
732 $item = (object) [
733 'author' => get_current_user_id(),
734 'editor' => get_current_user_id(),
735 'created' => current_time('mysql', 1),
736 'modified' => current_time('mysql', 1)
737 ];
738 }
739
740 require_once( plugin_dir_path( dirname(__FILE__) ) . 'includes/page-item.php' );
741
742 // set global settings
743 wp_localize_script('vision_admin', 'vision_globals', $globals);
744 }
745 }
746
747 /**
748 * Show admin menu settings page
749 */
750 function admin_menu_page_settings() {
751 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
752 if($page==='vision_settings') {
753 $plugin_url = plugin_dir_url(dirname(__FILE__));
754
755 wp_enqueue_style('vision_admin', $plugin_url . 'assets/css/admin.css', [], VISION_PLUGIN_VERSION, 'all' );
756 wp_enqueue_style('vision_lucide', $plugin_url . 'assets/vendor/lucide/lucide.css', [], VISION_PLUGIN_VERSION, 'all' );
757 wp_enqueue_script('vision_admin', $plugin_url . 'assets/js/admin.js', ['jquery'], VISION_PLUGIN_VERSION, false );
758
759 // global settings to help ajax work
760 $globals = [
761 'plan' => VISION_PLUGIN_PLAN,
762 'msg_pro_title' => esc_html__('Available only in Pro version', 'vision'),
763 'ajax_url' => admin_url('admin-ajax.php'),
764 'ajax_nonce' => wp_create_nonce('vision_ajax' ),
765 'ajax_msg_error' => esc_html__('Uncaught Error', 'vision') //Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information
766 ];
767
768 $globals['ajax_action_update'] = $this->ajax_action_settings_update;
769 $globals['ajax_action_get'] = $this->ajax_action_settings_get;
770 $globals['ajax_action_modal'] = $this->ajax_action_modal;
771 $globals['ajax_action_delete_data'] = $this->ajax_action_delete_data;
772 $globals['config'] = NULL;
773
774 // read settings
775 $settings_key = 'vision_settings';
776 $settings_value = get_option($settings_key);
777 if($settings_value) {
778 $globals['config'] = wp_json_encode(unserialize($settings_value));
779 }
780
781 require_once(plugin_dir_path( dirname(__FILE__) ) . 'includes/page-settings.php' );
782
783 wp_localize_script('vision_admin', 'vision_globals', $globals);
784 }
785 }
786
787 /**
788 * Show admin menu upgrade to pro page
789 */
790 function admin_menu_page_upgrade_to_pro() {
791 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
792 if($page==='vision_upgrade_to_pro') {
793 echo '<script>window.location = "https://1.envato.market/getvision"</script>';
794 }
795 }
796
797 /**
798 * Ajax update item state
799 */
800 function ajax_item_update_status() {
801 $error = false;
802 $data = [];
803 $config = filter_input(INPUT_POST, 'config', FILTER_UNSAFE_RAW);
804
805 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
806 global $wpdb;
807 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
808
809 $config = json_decode($config);
810 $result = false;
811
812 if(isset($config->id) && isset($config->active)) {
813 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
814 $query = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%s", $config->id);
815 $item = $wpdb->get_row($query, OBJECT );
816 // phpcs:enable
817
818 if($item && (current_user_can('manage_options') || get_current_user_id()==$item->author) ) {
819 $itemData = unserialize($item->data);
820 $itemData->active = $config->active;
821
822 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
823 $result = $wpdb->update(
824 $table,
825 ['active' => $itemData->active, 'data' => serialize($itemData)],
826 ['id' => $config->id]
827 );
828 }
829 }
830
831 if($result) {
832 $data['id'] = $config->id;
833 $data['msg'] = esc_html__('The item was successfully updated', 'vision');
834 } else {
835 $error = true;
836 $data['msg'] = esc_html__('The operation failed, can\'t update item', 'vision');
837 }
838 } else {
839 $error = true;
840 $data['msg'] = esc_html__('The operation failed', 'vision');
841 }
842
843 if($error) {
844 wp_send_json_error($data);
845 } else {
846 wp_send_json_success($data);
847 }
848
849 wp_die(); // this is required to terminate immediately and return a proper response
850 }
851
852 /**
853 * Ajax update item data
854 */
855 function ajax_item_update() {
856 $error = false;
857 $data = [];
858
859 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
860 global $wpdb;
861 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
862
863 $inputId = filter_input(INPUT_POST, 'id', FILTER_UNSAFE_RAW);
864 $inputData = filter_input(INPUT_POST, 'data', FILTER_UNSAFE_RAW);
865 $inputConfig = filter_input(INPUT_POST, 'config', FILTER_UNSAFE_RAW);
866 $itemData = json_decode($inputData);
867 $itemConfig = json_decode($inputConfig);
868 $flag = true;
869
870 if( VISION_PLUGIN_PLAN == 'lite' && !$inputId ) {
871 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
872 $count = $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
873
874 if ( $count >= 3 ) {
875 $flag = false;
876 $error = true;
877 $data['msg'] = esc_html__('You can create only 3 maps. If you need more, upgrade to the pro version.', 'vision');
878 }
879 }
880
881 if($flag) {
882 $itemConfig->modified = current_time('mysql', 1);
883
884 if($inputId) {
885 $result = false;
886
887 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
888 $query = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%s", $inputId);
889 $item = $wpdb->get_row($query, OBJECT);
890 // phpcs:enable
891
892 if($item && (current_user_can('manage_options') || get_current_user_id()==$item->author) ) {
893 $itemData->slug = sanitize_title(($itemData->slug ? $itemData->slug : $itemData->title));
894
895 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
896 $result = $wpdb->update(
897 $table,
898 [
899 'title' => $itemData->title,
900 'slug' => $itemData->slug,
901 'active' => $itemData->active,
902 'data' => serialize($itemData),
903 'config' => serialize($itemConfig),
904 //'author' => get_current_user_id(),
905 'editor' => get_current_user_id(),
906 //'date' => NULL,
907 'modified' => current_time('mysql', 1)
908 ],
909 ['id' => $inputId]
910 );
911 }
912
913 if($result) {
914 $data['id'] = $inputId;
915 $data['msg'] = esc_html__('The item was successfully updated', 'vision');
916 } else {
917 $error = true;
918 $data['msg'] = esc_html__('The operation failed, can\'t update item', 'vision');
919 }
920 } else {
921 $itemData->slug = sanitize_title(($itemData->slug ? $itemData->slug : $itemData->title));
922
923 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
924 $result = $wpdb->insert(
925 $table,
926 [
927 'title' => $itemData->title,
928 'slug' => $itemData->slug,
929 'active' => $itemData->active,
930 'data' => serialize($itemData),
931 'config' => serialize($itemConfig),
932 'author' => get_current_user_id(),
933 'editor' => get_current_user_id(),
934 'created' => current_time('mysql', 1),
935 'modified' => current_time('mysql', 1)
936 ]);
937
938 if($result) {
939 $data['id'] = $inputId = $wpdb->insert_id;
940 $data['msg'] = esc_html__('The item was successfully created', 'vision');
941 } else {
942 $error = true;
943 $data['msg'] = esc_html__('The operation failed, can\'t create item', 'vision');
944 }
945 }
946 }
947 } else {
948 $error = true;
949 $data['msg'] = esc_html__('The operation failed', 'vision');
950 }
951
952 if($error) {
953 wp_send_json_error($data);
954 } else {
955 wp_send_json_success($data);
956 }
957
958 wp_die(); // this is required to terminate immediately and return a proper response
959 }
960
961 /**
962 * Ajax update settings data
963 */
964 function ajax_settings_update() {
965 $error = false;
966 $data = [];
967 $config = filter_input(INPUT_POST, 'config', FILTER_UNSAFE_RAW);
968
969 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
970 $settings_key = 'vision_settings';
971 $settings_value = serialize(json_decode($config));
972 $result = false;
973
974 if(get_option($settings_key) == false) {
975 $autoload = 'no';
976 $result = add_option($settings_key, $settings_value, "", $autoload);
977 } else {
978 $old_settings_value = get_option($settings_key);
979 if($old_settings_value === $settings_value) {
980 $result = true;
981 } else {
982 $result = update_option($settings_key, $settings_value);
983 }
984 }
985
986 if($result) {
987 $data['msg'] = esc_html__('The settings were successfully updated', 'vision');
988 } else {
989 $error = true;
990 $data['msg'] = esc_html__('The operation failed, can\'t update settings', 'vision');
991 }
992 }
993
994 if($error) {
995 wp_send_json_error($data);
996 } else {
997 wp_send_json_success($data);
998 }
999
1000 wp_die(); // this is required to terminate immediately and return a proper response
1001 }
1002
1003 /**
1004 * Ajax settings get data
1005 */
1006 function ajax_settings_get() {
1007 $error = false;
1008 $data = [];
1009 $type = sanitize_key(filter_input(INPUT_POST, 'type', FILTER_DEFAULT));
1010
1011 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
1012 switch($type) {
1013 case 'roles': {
1014 $data['list'] = [];
1015
1016 $roles = wp_roles()->roles;
1017 foreach($roles as $key => $role) {
1018 if(array_key_exists('read', $role['capabilities'])) {
1019 array_push($data['list'], ['id' => $key, 'name' => translate_user_role($role['name'])]);
1020 }
1021 }
1022 }
1023 break;
1024 case 'themes': {
1025 $data['list'] = [];
1026
1027 $files = glob(plugin_dir_path( dirname(__FILE__) ) . 'assets/themes/*.css');
1028 foreach($files as $file) {
1029 $filename = basename($file, '.css');
1030 array_push($data['list'], ['id' => $filename, 'title' => str_replace('-', ' ', $filename)]);
1031 }
1032 }
1033 break;
1034 case 'editor-themes': {
1035 $data['list'] = [];
1036
1037 $files = glob(plugin_dir_path( dirname(__FILE__) ) . 'assets/vendor/ace/theme-*.js');
1038 foreach($files as $file) {
1039 $filename = str_replace('theme-','',basename($file, '.js'));
1040 array_push($data['list'], ['id' => $filename, 'title' => str_replace('_', ' ', $filename)]);
1041 }
1042 }
1043 break;
1044 case 'fonts': {
1045 $data['list'] = array(
1046 array('fontname' => 'none'),
1047 array('fontname' => 'Aclonica'),
1048 array('fontname' => 'Allan'),
1049 array('fontname' => 'Annie+Use+Your+Telescope'),
1050 array('fontname' => 'Anonymous+Pro'),
1051 array('fontname' => 'Allerta+Stencil'),
1052 array('fontname' => 'Allerta'),
1053 array('fontname' => 'Amaranth'),
1054 array('fontname' => 'Anton'),
1055 array('fontname' => 'Architects+Daughter'),
1056 array('fontname' => 'Arimo'),
1057 array('fontname' => 'Artifika'),
1058 array('fontname' => 'Arvo'),
1059 array('fontname' => 'Asset'),
1060 array('fontname' => 'Astloch'),
1061 array('fontname' => 'Bangers'),
1062 array('fontname' => 'Bentham'),
1063 array('fontname' => 'Bevan'),
1064 array('fontname' => 'Bigshot+One'),
1065 array('fontname' => 'Bowlby+One'),
1066 array('fontname' => 'Bowlby+One+SC'),
1067 array('fontname' => 'Brawler'),
1068 array('fontname' => 'Cabin'),
1069 array('fontname' => 'Calligraffitti'),
1070 array('fontname' => 'Candal'),
1071 array('fontname' => 'Cantarell'),
1072 array('fontname' => 'Cardo'),
1073 array('fontname' => 'Carter One'),
1074 array('fontname' => 'Caudex'),
1075 array('fontname' => 'Cedarville+Cursive'),
1076 array('fontname' => 'Cherry+Cream+Soda'),
1077 array('fontname' => 'Chewy'),
1078 array('fontname' => 'Coda'),
1079 array('fontname' => 'Coming+Soon'),
1080 array('fontname' => 'Copse'),
1081 array('fontname' => 'Cousine'),
1082 array('fontname' => 'Covered+By+Your+Grace'),
1083 array('fontname' => 'Crafty+Girls'),
1084 array('fontname' => 'Crimson+Text'),
1085 array('fontname' => 'Crushed'),
1086 array('fontname' => 'Cuprum'),
1087 array('fontname' => 'Damion'),
1088 array('fontname' => 'Dancing+Script'),
1089 array('fontname' => 'Dawning+of+a+New+Day'),
1090 array('fontname' => 'Didact+Gothic'),
1091 array('fontname' => 'Droid+Sans'),
1092 array('fontname' => 'Droid+Sans+Mono'),
1093 array('fontname' => 'Droid+Serif'),
1094 array('fontname' => 'EB+Garamond'),
1095 array('fontname' => 'Expletus+Sans'),
1096 array('fontname' => 'Fontdiner+Swanky'),
1097 array('fontname' => 'Forum'),
1098 array('fontname' => 'Francois+One'),
1099 array('fontname' => 'Geo'),
1100 array('fontname' => 'Give+You+Glory'),
1101 array('fontname' => 'Goblin+One'),
1102 array('fontname' => 'Goudy+Bookletter+1911'),
1103 array('fontname' => 'Gravitas+One'),
1104 array('fontname' => 'Gruppo'),
1105 array('fontname' => 'Hammersmith+One'),
1106 array('fontname' => 'Holtwood+One+SC'),
1107 array('fontname' => 'Homemade+Apple'),
1108 array('fontname' => 'Inconsolata'),
1109 array('fontname' => 'Indie+Flower'),
1110 array('fontname' => 'IM+Fell+DW+Pica'),
1111 array('fontname' => 'IM+Fell+DW+Pica+SC'),
1112 array('fontname' => 'IM+Fell+Double+Pica'),
1113 array('fontname' => 'IM+Fell+Double+Pica+SC'),
1114 array('fontname' => 'IM+Fell+English'),
1115 array('fontname' => 'IM+Fell+English+SC'),
1116 array('fontname' => 'IM+Fell+French+Canon'),
1117 array('fontname' => 'IM+Fell+French+Canon+SC'),
1118 array('fontname' => 'IM+Fell+Great+Primer'),
1119 array('fontname' => 'IM+Fell+Great+Primer+SC'),
1120 array('fontname' => 'Irish+Grover'),
1121 array('fontname' => 'Irish+Growler'),
1122 array('fontname' => 'Istok+Web'),
1123 array('fontname' => 'Josefin+Sans'),
1124 array('fontname' => 'Josefin+Slab'),
1125 array('fontname' => 'Judson'),
1126 array('fontname' => 'Jura'),
1127 array('fontname' => 'Just+Another+Hand'),
1128 array('fontname' => 'Just+Me+Again+Down+Here'),
1129 array('fontname' => 'Kameron'),
1130 array('fontname' => 'Kenia'),
1131 array('fontname' => 'Kranky'),
1132 array('fontname' => 'Kreon'),
1133 array('fontname' => 'Kristi'),
1134 array('fontname' => 'La+Belle+Aurore'),
1135 array('fontname' => 'Lato'),
1136 array('fontname' => 'League+Script'),
1137 array('fontname' => 'Lekton'),
1138 array('fontname' => 'Limelight'),
1139 array('fontname' => 'Lobster'),
1140 array('fontname' => 'Lobster Two'),
1141 array('fontname' => 'Lora'),
1142 array('fontname' => 'Love+Ya+Like+A+Sister'),
1143 array('fontname' => 'Loved+by+the+King'),
1144 array('fontname' => 'Luckiest+Guy'),
1145 array('fontname' => 'Maiden+Orange'),
1146 array('fontname' => 'Mako'),
1147 array('fontname' => 'Maven+Pro'),
1148 array('fontname' => 'Meddon'),
1149 array('fontname' => 'MedievalSharp'),
1150 array('fontname' => 'Megrim'),
1151 array('fontname' => 'Merriweather'),
1152 array('fontname' => 'Metrophobic'),
1153 array('fontname' => 'Michroma'),
1154 array('fontname' => 'Miltonian+Tattoo'),
1155 array('fontname' => 'Miltonian'),
1156 array('fontname' => 'Modern Antiqua'),
1157 array('fontname' => 'Monofett'),
1158 array('fontname' => 'Molengo'),
1159 array('fontname' => 'Mountains of Christmas'),
1160 array('fontname' => 'Muli'),
1161 array('fontname' => 'Neucha'),
1162 array('fontname' => 'Neuton'),
1163 array('fontname' => 'News+Cycle'),
1164 array('fontname' => 'Nixie+One'),
1165 array('fontname' => 'Nobile'),
1166 array('fontname' => 'Nova+Cut'),
1167 array('fontname' => 'Nova+Flat'),
1168 array('fontname' => 'Nova+Mono'),
1169 array('fontname' => 'Nova+Oval'),
1170 array('fontname' => 'Nova+Round'),
1171 array('fontname' => 'Nova+Script'),
1172 array('fontname' => 'Nova+Slim'),
1173 array('fontname' => 'Nova+Square'),
1174 array('fontname' => 'Nunito'),
1175 array('fontname' => 'OFL+Sorts+Mill+Goudy+TT'),
1176 array('fontname' => 'Old+Standard+TT'),
1177 array('fontname' => 'Open+Sans'),
1178 array('fontname' => 'Orbitron'),
1179 array('fontname' => 'Oswald'),
1180 array('fontname' => 'Over+the+Rainbow'),
1181 array('fontname' => 'Reenie+Beanie'),
1182 array('fontname' => 'Pacifico'),
1183 array('fontname' => 'Patrick+Hand'),
1184 array('fontname' => 'Paytone+One'),
1185 array('fontname' => 'Permanent+Marker'),
1186 array('fontname' => 'Philosopher'),
1187 array('fontname' => 'Play'),
1188 array('fontname' => 'Playfair+Display'),
1189 array('fontname' => 'Podkova'),
1190 array('fontname' => 'PT+Sans'),
1191 array('fontname' => 'PT+Sans+Narrow'),
1192 array('fontname' => 'PT+Serif'),
1193 array('fontname' => 'PT+Serif Caption'),
1194 array('fontname' => 'Puritan'),
1195 array('fontname' => 'Quattrocento'),
1196 array('fontname' => 'Quattrocento+Sans'),
1197 array('fontname' => 'Radley'),
1198 array('fontname' => 'Redressed'),
1199 array('fontname' => 'Rock+Salt'),
1200 array('fontname' => 'Rokkitt'),
1201 array('fontname' => 'Ruslan+Display'),
1202 array('fontname' => 'Schoolbell'),
1203 array('fontname' => 'Shadows+Into+Light'),
1204 array('fontname' => 'Shanti'),
1205 array('fontname' => 'Sigmar+One'),
1206 array('fontname' => 'Six+Caps'),
1207 array('fontname' => 'Slackey'),
1208 array('fontname' => 'Smythe'),
1209 array('fontname' => 'Special+Elite'),
1210 array('fontname' => 'Stardos+Stencil'),
1211 array('fontname' => 'Sue+Ellen+Francisco'),
1212 array('fontname' => 'Sunshiney'),
1213 array('fontname' => 'Swanky+and+Moo+Moo'),
1214 array('fontname' => 'Syncopate'),
1215 array('fontname' => 'Tangerine'),
1216 array('fontname' => 'Tenor+Sans'),
1217 array('fontname' => 'Terminal+Dosis+Light'),
1218 array('fontname' => 'The+Girl+Next+Door'),
1219 array('fontname' => 'Tinos'),
1220 array('fontname' => 'Ubuntu'),
1221 array('fontname' => 'Ultra'),
1222 array('fontname' => 'Unkempt'),
1223 array('fontname' => 'UnifrakturMaguntia'),
1224 array('fontname' => 'Varela'),
1225 array('fontname' => 'Varela Round'),
1226 array('fontname' => 'Vibur'),
1227 array('fontname' => 'Vollkorn'),
1228 array('fontname' => 'VT323'),
1229 array('fontname' => 'Waiting+for+the+Sunrise'),
1230 array('fontname' => 'Wallpoet'),
1231 array('fontname' => 'Walter+Turncoat'),
1232 array('fontname' => 'Wire+One'),
1233 array('fontname' => 'Yanone+Kaffeesatz'),
1234 array('fontname' => 'Yeseva+One'),
1235 array('fontname' => 'Zeyada')
1236 );
1237 }
1238 break;
1239 default: {
1240 $error = true;
1241 $data['msg'] = esc_html__('The operation failed', 'vision');
1242 }
1243 break;
1244 }
1245 } else {
1246 $error = true;
1247 $data['msg'] = esc_html__('The operation failed', 'vision');
1248 }
1249
1250 if($error) {
1251 wp_send_json_error($data);
1252 } else {
1253 wp_send_json_success($data);
1254 }
1255
1256 wp_die(); // this is required to terminate immediately and return a proper response
1257 }
1258
1259 /**
1260 * Ajax delete all data from tables
1261 */
1262 function ajax_delete_data() {
1263 $error = true;
1264 $data = [];
1265 $data['msg'] = esc_html__('The operation failed, can\'t delete data', 'vision');
1266
1267 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
1268 global $wpdb;
1269 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
1270
1271 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1272 foreach($wpdb->get_results("SELECT id FROM {$table}") as $key => $item) {
1273 // [filemanager] delete file
1274 if(wp_is_writable(VISION_PLUGIN_UPLOAD_DIR)) {
1275 $file_json = 'config.json';
1276 $file_main_css = 'main.css';
1277 $file_custom_css = 'custom.css';
1278 $file_root_path = VISION_PLUGIN_UPLOAD_DIR . '/' . $item->id . '/';
1279
1280 if(file_exists($file_root_path . $file_json)) {
1281 wp_delete_file($file_root_path . $file_json);
1282 }
1283 wp_delete_file($file_root_path . $file_main_css);
1284 wp_delete_file($file_root_path . $file_custom_css);
1285
1286 $wp_filesystem = $this->getFileSystem();
1287 if($wp_filesystem->is_dir($file_root_path)) {
1288 $wp_filesystem->rmdir($file_root_path);
1289 }
1290 }
1291 }
1292
1293 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1294 $result = $wpdb->query("TRUNCATE TABLE {$table}");
1295
1296 if($result) {
1297 $error = false;
1298 $data['msg'] = esc_html__('All data deleted', 'vision');
1299 }
1300 }
1301
1302 if($error) {
1303 wp_send_json_error($data);
1304 } else {
1305 wp_send_json_success($data);
1306 }
1307
1308 wp_die(); // this is required to terminate immediately and return a proper response
1309 }
1310
1311 /**
1312 * Ajax settings get data
1313 */
1314 function ajax_modal() {
1315 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
1316 $modalName = sanitize_file_name(filter_input(INPUT_GET, 'name', FILTER_DEFAULT));
1317 $modalPath = plugin_dir_path( dirname(__FILE__) ) . 'includes/modal-' . $modalName . '.php';
1318
1319 if(file_exists($modalPath)) {
1320 require_once( $modalPath );
1321 }
1322 }
1323
1324 wp_die(); // this is required to terminate immediately and return a proper response
1325 }
1326 }
1327 ?>