PluginProbe
Vision – Interactive Image Map with Hotspots Builder / 1.9.7
Vision – Interactive Image Map with Hotspots Builder v1.9.7
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.7, at includes/plugin.php

1,340 lines 52.5 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
661 if ( VISION_PLUGIN_PLAN == 'lite' && !$id ) {
662 global $wpdb;
663 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
664
665 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
666 $count = $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
667
668 if ( $count >= 1 ) {
669 echo '<div class="notice notice-error is-dismissible">';
670 echo '<p>Vision: ' . esc_html__('You can create only 1 map. If you need more, upgrade to the pro version.', 'vision') . '</p>';
671 echo '</div>';
672 return;
673 }
674 }
675
676 $plugin_url = plugin_dir_url(dirname(__FILE__));
677 $upload_dir = wp_upload_dir();
678
679 wp_enqueue_style('vision_admin', $plugin_url . 'assets/css/admin.css', [], VISION_PLUGIN_VERSION, 'all' );
680 wp_enqueue_style('vision_notify', $plugin_url . 'assets/css/notify.css', [], VISION_PLUGIN_VERSION, 'all' );
681 wp_enqueue_style('vision_lucide', $plugin_url . 'assets/vendor/lucide/lucide.css', [], VISION_PLUGIN_VERSION, 'all' );
682 wp_enqueue_style('vision_vision_effects', $plugin_url . 'assets/css/vision-effects.css', [], VISION_PLUGIN_VERSION, 'all' );
683
684 wp_enqueue_script('vision_notify', $plugin_url . 'assets/js/notify.js', ['jquery'], VISION_PLUGIN_VERSION, false );
685 wp_enqueue_script('vision_ace', $plugin_url . 'assets/vendor/ace/ace.js', [], VISION_PLUGIN_VERSION, false );
686 wp_enqueue_script('vision_url', $plugin_url . 'assets/vendor/url/url.js', [], VISION_PLUGIN_VERSION, false );
687 wp_enqueue_script('vision_admin', $plugin_url . 'assets/js/admin.js', ['jquery'], VISION_PLUGIN_VERSION, false );
688
689 wp_enqueue_media();
690
691 // global settings to help ajax work
692 $globals = [
693 'plan' => VISION_PLUGIN_PLAN,
694 'msg_pro_title' => esc_html__('Available only in Pro version', 'vision'),
695 'msg_custom_js_error' => esc_html__('Custom js code error', 'vision'),
696 'msg_layer_id_error' => esc_html__('The layer ID should be unique', 'vision'),
697 'wp_base_url' => get_site_url(),
698 'upload_base_url' => $upload_dir['baseurl'],
699 'plugin_base_url' => $plugin_url,
700 'ajax_url' => admin_url('admin-ajax.php'),
701 'ajax_nonce' => wp_create_nonce('vision_ajax'),
702 'ajax_msg_error' => esc_html__('Uncaught Error', 'vision') //Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information
703 ];
704
705 $globals['ajax_action_get'] = $this->ajax_action_settings_get;
706 $globals['ajax_action_update'] = $this->ajax_action_item_update;
707 $globals['ajax_action_modal'] = $this->ajax_action_modal;
708 $globals['ajax_item_id'] = $id;
709 $globals['settings'] = NULL;
710 $globals['config'] = NULL;
711
712 $settings_key = 'vision_settings';
713 $settings_value = get_option($settings_key);
714 if($settings_value) {
715 $globals['settings'] = unserialize($settings_value); // json_encode(unserialize($settings_value)) problem with double quotes
716 }
717
718 // get item data from DB
719 if($id) {
720 global $wpdb;
721 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
722
723 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
724 $query = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%s", $id);
725 $item = $wpdb->get_row($query, OBJECT);
726 // phpcs:enable
727
728 if($item) {
729 $globals['config'] = unserialize($item->data); // json_encode(unserialize($item->data)) problem with double quotes
730 }
731 } else {
732 // new item
733 $item = (object) [
734 'author' => get_current_user_id(),
735 'editor' => get_current_user_id(),
736 'created' => current_time('mysql', 1),
737 'modified' => current_time('mysql', 1)
738 ];
739 }
740
741 require_once( plugin_dir_path( dirname(__FILE__) ) . 'includes/page-item.php' );
742
743 // set global settings
744 wp_localize_script('vision_admin', 'vision_globals', $globals);
745 }
746 }
747
748 /**
749 * Show admin menu settings page
750 */
751 function admin_menu_page_settings() {
752 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
753 if($page==='vision_settings') {
754 $plugin_url = plugin_dir_url(dirname(__FILE__));
755
756 wp_enqueue_style('vision_admin', $plugin_url . 'assets/css/admin.css', [], VISION_PLUGIN_VERSION, 'all' );
757 wp_enqueue_style('vision_lucide', $plugin_url . 'assets/vendor/lucide/lucide.css', [], VISION_PLUGIN_VERSION, 'all' );
758 wp_enqueue_script('vision_admin', $plugin_url . 'assets/js/admin.js', ['jquery'], VISION_PLUGIN_VERSION, false );
759
760 // global settings to help ajax work
761 $globals = [
762 'plan' => VISION_PLUGIN_PLAN,
763 'msg_pro_title' => esc_html__('Available only in Pro version', 'vision'),
764 'ajax_url' => admin_url('admin-ajax.php'),
765 'ajax_nonce' => wp_create_nonce('vision_ajax' ),
766 'ajax_msg_error' => esc_html__('Uncaught Error', 'vision') //Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information
767 ];
768
769 $globals['ajax_action_update'] = $this->ajax_action_settings_update;
770 $globals['ajax_action_get'] = $this->ajax_action_settings_get;
771 $globals['ajax_action_modal'] = $this->ajax_action_modal;
772 $globals['ajax_action_delete_data'] = $this->ajax_action_delete_data;
773 $globals['config'] = NULL;
774
775 // read settings
776 $settings_key = 'vision_settings';
777 $settings_value = get_option($settings_key);
778 if($settings_value) {
779 $globals['config'] = wp_json_encode(unserialize($settings_value));
780 }
781
782 require_once(plugin_dir_path( dirname(__FILE__) ) . 'includes/page-settings.php' );
783
784 wp_localize_script('vision_admin', 'vision_globals', $globals);
785 }
786 }
787
788 /**
789 * Show admin menu upgrade to pro page
790 */
791 function admin_menu_page_upgrade_to_pro() {
792 $page = sanitize_key(filter_input(INPUT_GET, 'page', FILTER_DEFAULT));
793 if($page==='vision_upgrade_to_pro') {
794 echo '<script>window.location = "https://1.envato.market/getvision"</script>';
795 }
796 }
797
798 /**
799 * Ajax update item state
800 */
801 function ajax_item_update_status() {
802 $error = false;
803 $data = [];
804 $config = filter_input(INPUT_POST, 'config', FILTER_UNSAFE_RAW);
805
806 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
807 global $wpdb;
808 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
809
810 $config = json_decode($config);
811 $result = false;
812
813 if(isset($config->id) && isset($config->active)) {
814 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
815 $query = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%s", $config->id);
816 $item = $wpdb->get_row($query, OBJECT );
817 // phpcs:enable
818
819 if($item && (current_user_can('manage_options') || get_current_user_id()==$item->author) ) {
820 $itemData = unserialize($item->data);
821 $itemData->active = $config->active;
822
823 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
824 $result = $wpdb->update(
825 $table,
826 ['active' => $itemData->active, 'data' => serialize($itemData)],
827 ['id' => $config->id]
828 );
829 }
830 }
831
832 if($result) {
833 $data['id'] = $config->id;
834 $data['msg'] = esc_html__('The item was successfully updated', 'vision');
835 } else {
836 $error = true;
837 $data['msg'] = esc_html__('The operation failed, can\'t update item', 'vision');
838 }
839 } else {
840 $error = true;
841 $data['msg'] = esc_html__('The operation failed', 'vision');
842 }
843
844 if($error) {
845 wp_send_json_error($data);
846 } else {
847 wp_send_json_success($data);
848 }
849
850 wp_die(); // this is required to terminate immediately and return a proper response
851 }
852
853 /**
854 * Ajax update item data
855 */
856 function ajax_item_update() {
857 $error = false;
858 $data = [];
859
860 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
861 global $wpdb;
862 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
863
864 $inputId = filter_input(INPUT_POST, 'id', FILTER_UNSAFE_RAW);
865 $inputData = filter_input(INPUT_POST, 'data', FILTER_UNSAFE_RAW);
866 $inputConfig = filter_input(INPUT_POST, 'config', FILTER_UNSAFE_RAW);
867 $itemData = json_decode($inputData);
868 $itemConfig = json_decode($inputConfig);
869 $flag = true;
870
871 if( VISION_PLUGIN_PLAN == 'lite' && !$inputId ) {
872 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
873 $count = $wpdb->get_var("SELECT COUNT(*) FROM {$table}");
874
875 if ( $count >= 1 ) {
876 $flag = false;
877 $error = true;
878 $data['msg'] = esc_html__('You can create only 1 map. If you need more, upgrade to the pro version.', 'vision');
879 }
880 }
881
882 if( $itemData === NULL || $itemConfig === NULL ) {
883 $flag = false;
884 $error = true;
885 $data['msg'] = esc_html__('Error decoding JSON: ' . json_last_error_msg(), 'vision');
886 }
887
888 if($flag) {
889 $itemConfig->modified = current_time('mysql', 1);
890
891 if($inputId) {
892 $result = false;
893
894 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
895 $query = $wpdb->prepare("SELECT * FROM {$table} WHERE id=%s", $inputId);
896 $item = $wpdb->get_row($query, OBJECT);
897 // phpcs:enable
898
899 if($item && (current_user_can('manage_options') || get_current_user_id()==$item->author) ) {
900 $itemData->slug = sanitize_title(($itemData->slug ? $itemData->slug : $itemData->title));
901
902 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
903 $result = $wpdb->update(
904 $table,
905 [
906 'title' => $itemData->title,
907 'slug' => $itemData->slug,
908 'active' => $itemData->active,
909 'data' => serialize($itemData),
910 'config' => serialize($itemConfig),
911 //'author' => get_current_user_id(),
912 'editor' => get_current_user_id(),
913 //'date' => NULL,
914 'modified' => current_time('mysql', 1)
915 ],
916 ['id' => $inputId]
917 );
918 }
919
920 if($result) {
921 $data['id'] = $inputId;
922 $data['msg'] = esc_html__('The item was successfully updated', 'vision');
923 } else {
924 $error = true;
925 $data['msg'] = esc_html__('The operation failed, can\'t update item', 'vision');
926 }
927 } else {
928 $itemData->slug = sanitize_title(($itemData->slug ? $itemData->slug : $itemData->title));
929
930 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
931 $result = $wpdb->insert(
932 $table,
933 [
934 'title' => $itemData->title,
935 'slug' => $itemData->slug,
936 'active' => $itemData->active,
937 'data' => serialize($itemData),
938 'config' => serialize($itemConfig),
939 'author' => get_current_user_id(),
940 'editor' => get_current_user_id(),
941 'created' => current_time('mysql', 1),
942 'modified' => current_time('mysql', 1)
943 ]);
944
945 if($result) {
946 $data['id'] = $inputId = $wpdb->insert_id;
947 $data['msg'] = esc_html__('The item was successfully created', 'vision');
948 } else {
949 $error = true;
950 $data['msg'] = esc_html__('The operation failed, can\'t create item', 'vision');
951 }
952 }
953 }
954 } else {
955 $error = true;
956 $data['msg'] = esc_html__('The operation failed', 'vision');
957 }
958
959 if($error) {
960 wp_send_json_error($data);
961 } else {
962 wp_send_json_success($data);
963 }
964
965 wp_die(); // this is required to terminate immediately and return a proper response
966 }
967
968 /**
969 * Ajax update settings data
970 */
971 function ajax_settings_update() {
972 $error = false;
973 $data = [];
974 $config = filter_input(INPUT_POST, 'config', FILTER_UNSAFE_RAW);
975 $config = json_decode($config);
976
977 if($config !== NULL) {
978 if (check_ajax_referer('vision_ajax', 'nonce', false)) {
979 $settings_key = 'vision_settings';
980 $settings_value = serialize($config);
981 $result = false;
982
983 if (get_option($settings_key) == false) {
984 $autoload = 'no';
985 $result = add_option($settings_key, $settings_value, "", $autoload);
986 } else {
987 $old_settings_value = get_option($settings_key);
988 if ($old_settings_value === $settings_value) {
989 $result = true;
990 } else {
991 $result = update_option($settings_key, $settings_value);
992 }
993 }
994
995 if ($result) {
996 $data['msg'] = esc_html__('The settings were successfully updated', 'vision');
997 } else {
998 $error = true;
999 $data['msg'] = esc_html__('The operation failed, can\'t update settings', 'vision');
1000 }
1001 }
1002 } else {
1003 $error = true;
1004 $data['msg'] = esc_html__('Error decoding JSON: ' . json_last_error_msg(), 'vision');
1005 }
1006
1007 if($error) {
1008 wp_send_json_error($data);
1009 } else {
1010 wp_send_json_success($data);
1011 }
1012
1013 wp_die(); // this is required to terminate immediately and return a proper response
1014 }
1015
1016 /**
1017 * Ajax settings get data
1018 */
1019 function ajax_settings_get() {
1020 $error = false;
1021 $data = [];
1022 $type = sanitize_key(filter_input(INPUT_POST, 'type', FILTER_DEFAULT));
1023
1024 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
1025 switch($type) {
1026 case 'roles': {
1027 $data['list'] = [];
1028
1029 $roles = wp_roles()->roles;
1030 foreach($roles as $key => $role) {
1031 if(array_key_exists('read', $role['capabilities'])) {
1032 array_push($data['list'], ['id' => $key, 'name' => translate_user_role($role['name'])]);
1033 }
1034 }
1035 }
1036 break;
1037 case 'themes': {
1038 $data['list'] = [];
1039
1040 $files = glob(plugin_dir_path( dirname(__FILE__) ) . 'assets/themes/*.css');
1041 foreach($files as $file) {
1042 $filename = basename($file, '.css');
1043 array_push($data['list'], ['id' => $filename, 'title' => str_replace('-', ' ', $filename)]);
1044 }
1045 }
1046 break;
1047 case 'editor-themes': {
1048 $data['list'] = [];
1049
1050 $files = glob(plugin_dir_path( dirname(__FILE__) ) . 'assets/vendor/ace/theme-*.js');
1051 foreach($files as $file) {
1052 $filename = str_replace('theme-','',basename($file, '.js'));
1053 array_push($data['list'], ['id' => $filename, 'title' => str_replace('_', ' ', $filename)]);
1054 }
1055 }
1056 break;
1057 case 'fonts': {
1058 $data['list'] = array(
1059 array('fontname' => 'none'),
1060 array('fontname' => 'Aclonica'),
1061 array('fontname' => 'Allan'),
1062 array('fontname' => 'Annie+Use+Your+Telescope'),
1063 array('fontname' => 'Anonymous+Pro'),
1064 array('fontname' => 'Allerta+Stencil'),
1065 array('fontname' => 'Allerta'),
1066 array('fontname' => 'Amaranth'),
1067 array('fontname' => 'Anton'),
1068 array('fontname' => 'Architects+Daughter'),
1069 array('fontname' => 'Arimo'),
1070 array('fontname' => 'Artifika'),
1071 array('fontname' => 'Arvo'),
1072 array('fontname' => 'Asset'),
1073 array('fontname' => 'Astloch'),
1074 array('fontname' => 'Bangers'),
1075 array('fontname' => 'Bentham'),
1076 array('fontname' => 'Bevan'),
1077 array('fontname' => 'Bigshot+One'),
1078 array('fontname' => 'Bowlby+One'),
1079 array('fontname' => 'Bowlby+One+SC'),
1080 array('fontname' => 'Brawler'),
1081 array('fontname' => 'Cabin'),
1082 array('fontname' => 'Calligraffitti'),
1083 array('fontname' => 'Candal'),
1084 array('fontname' => 'Cantarell'),
1085 array('fontname' => 'Cardo'),
1086 array('fontname' => 'Carter One'),
1087 array('fontname' => 'Caudex'),
1088 array('fontname' => 'Cedarville+Cursive'),
1089 array('fontname' => 'Cherry+Cream+Soda'),
1090 array('fontname' => 'Chewy'),
1091 array('fontname' => 'Coda'),
1092 array('fontname' => 'Coming+Soon'),
1093 array('fontname' => 'Copse'),
1094 array('fontname' => 'Cousine'),
1095 array('fontname' => 'Covered+By+Your+Grace'),
1096 array('fontname' => 'Crafty+Girls'),
1097 array('fontname' => 'Crimson+Text'),
1098 array('fontname' => 'Crushed'),
1099 array('fontname' => 'Cuprum'),
1100 array('fontname' => 'Damion'),
1101 array('fontname' => 'Dancing+Script'),
1102 array('fontname' => 'Dawning+of+a+New+Day'),
1103 array('fontname' => 'Didact+Gothic'),
1104 array('fontname' => 'Droid+Sans'),
1105 array('fontname' => 'Droid+Sans+Mono'),
1106 array('fontname' => 'Droid+Serif'),
1107 array('fontname' => 'EB+Garamond'),
1108 array('fontname' => 'Expletus+Sans'),
1109 array('fontname' => 'Fontdiner+Swanky'),
1110 array('fontname' => 'Forum'),
1111 array('fontname' => 'Francois+One'),
1112 array('fontname' => 'Geo'),
1113 array('fontname' => 'Give+You+Glory'),
1114 array('fontname' => 'Goblin+One'),
1115 array('fontname' => 'Goudy+Bookletter+1911'),
1116 array('fontname' => 'Gravitas+One'),
1117 array('fontname' => 'Gruppo'),
1118 array('fontname' => 'Hammersmith+One'),
1119 array('fontname' => 'Holtwood+One+SC'),
1120 array('fontname' => 'Homemade+Apple'),
1121 array('fontname' => 'Inconsolata'),
1122 array('fontname' => 'Indie+Flower'),
1123 array('fontname' => 'IM+Fell+DW+Pica'),
1124 array('fontname' => 'IM+Fell+DW+Pica+SC'),
1125 array('fontname' => 'IM+Fell+Double+Pica'),
1126 array('fontname' => 'IM+Fell+Double+Pica+SC'),
1127 array('fontname' => 'IM+Fell+English'),
1128 array('fontname' => 'IM+Fell+English+SC'),
1129 array('fontname' => 'IM+Fell+French+Canon'),
1130 array('fontname' => 'IM+Fell+French+Canon+SC'),
1131 array('fontname' => 'IM+Fell+Great+Primer'),
1132 array('fontname' => 'IM+Fell+Great+Primer+SC'),
1133 array('fontname' => 'Irish+Grover'),
1134 array('fontname' => 'Irish+Growler'),
1135 array('fontname' => 'Istok+Web'),
1136 array('fontname' => 'Josefin+Sans'),
1137 array('fontname' => 'Josefin+Slab'),
1138 array('fontname' => 'Judson'),
1139 array('fontname' => 'Jura'),
1140 array('fontname' => 'Just+Another+Hand'),
1141 array('fontname' => 'Just+Me+Again+Down+Here'),
1142 array('fontname' => 'Kameron'),
1143 array('fontname' => 'Kenia'),
1144 array('fontname' => 'Kranky'),
1145 array('fontname' => 'Kreon'),
1146 array('fontname' => 'Kristi'),
1147 array('fontname' => 'La+Belle+Aurore'),
1148 array('fontname' => 'Lato'),
1149 array('fontname' => 'League+Script'),
1150 array('fontname' => 'Lekton'),
1151 array('fontname' => 'Limelight'),
1152 array('fontname' => 'Lobster'),
1153 array('fontname' => 'Lobster Two'),
1154 array('fontname' => 'Lora'),
1155 array('fontname' => 'Love+Ya+Like+A+Sister'),
1156 array('fontname' => 'Loved+by+the+King'),
1157 array('fontname' => 'Luckiest+Guy'),
1158 array('fontname' => 'Maiden+Orange'),
1159 array('fontname' => 'Mako'),
1160 array('fontname' => 'Maven+Pro'),
1161 array('fontname' => 'Meddon'),
1162 array('fontname' => 'MedievalSharp'),
1163 array('fontname' => 'Megrim'),
1164 array('fontname' => 'Merriweather'),
1165 array('fontname' => 'Metrophobic'),
1166 array('fontname' => 'Michroma'),
1167 array('fontname' => 'Miltonian+Tattoo'),
1168 array('fontname' => 'Miltonian'),
1169 array('fontname' => 'Modern Antiqua'),
1170 array('fontname' => 'Monofett'),
1171 array('fontname' => 'Molengo'),
1172 array('fontname' => 'Mountains of Christmas'),
1173 array('fontname' => 'Muli'),
1174 array('fontname' => 'Neucha'),
1175 array('fontname' => 'Neuton'),
1176 array('fontname' => 'News+Cycle'),
1177 array('fontname' => 'Nixie+One'),
1178 array('fontname' => 'Nobile'),
1179 array('fontname' => 'Nova+Cut'),
1180 array('fontname' => 'Nova+Flat'),
1181 array('fontname' => 'Nova+Mono'),
1182 array('fontname' => 'Nova+Oval'),
1183 array('fontname' => 'Nova+Round'),
1184 array('fontname' => 'Nova+Script'),
1185 array('fontname' => 'Nova+Slim'),
1186 array('fontname' => 'Nova+Square'),
1187 array('fontname' => 'Nunito'),
1188 array('fontname' => 'OFL+Sorts+Mill+Goudy+TT'),
1189 array('fontname' => 'Old+Standard+TT'),
1190 array('fontname' => 'Open+Sans'),
1191 array('fontname' => 'Orbitron'),
1192 array('fontname' => 'Oswald'),
1193 array('fontname' => 'Over+the+Rainbow'),
1194 array('fontname' => 'Reenie+Beanie'),
1195 array('fontname' => 'Pacifico'),
1196 array('fontname' => 'Patrick+Hand'),
1197 array('fontname' => 'Paytone+One'),
1198 array('fontname' => 'Permanent+Marker'),
1199 array('fontname' => 'Philosopher'),
1200 array('fontname' => 'Play'),
1201 array('fontname' => 'Playfair+Display'),
1202 array('fontname' => 'Podkova'),
1203 array('fontname' => 'PT+Sans'),
1204 array('fontname' => 'PT+Sans+Narrow'),
1205 array('fontname' => 'PT+Serif'),
1206 array('fontname' => 'PT+Serif Caption'),
1207 array('fontname' => 'Puritan'),
1208 array('fontname' => 'Quattrocento'),
1209 array('fontname' => 'Quattrocento+Sans'),
1210 array('fontname' => 'Radley'),
1211 array('fontname' => 'Redressed'),
1212 array('fontname' => 'Rock+Salt'),
1213 array('fontname' => 'Rokkitt'),
1214 array('fontname' => 'Ruslan+Display'),
1215 array('fontname' => 'Schoolbell'),
1216 array('fontname' => 'Shadows+Into+Light'),
1217 array('fontname' => 'Shanti'),
1218 array('fontname' => 'Sigmar+One'),
1219 array('fontname' => 'Six+Caps'),
1220 array('fontname' => 'Slackey'),
1221 array('fontname' => 'Smythe'),
1222 array('fontname' => 'Special+Elite'),
1223 array('fontname' => 'Stardos+Stencil'),
1224 array('fontname' => 'Sue+Ellen+Francisco'),
1225 array('fontname' => 'Sunshiney'),
1226 array('fontname' => 'Swanky+and+Moo+Moo'),
1227 array('fontname' => 'Syncopate'),
1228 array('fontname' => 'Tangerine'),
1229 array('fontname' => 'Tenor+Sans'),
1230 array('fontname' => 'Terminal+Dosis+Light'),
1231 array('fontname' => 'The+Girl+Next+Door'),
1232 array('fontname' => 'Tinos'),
1233 array('fontname' => 'Ubuntu'),
1234 array('fontname' => 'Ultra'),
1235 array('fontname' => 'Unkempt'),
1236 array('fontname' => 'UnifrakturMaguntia'),
1237 array('fontname' => 'Varela'),
1238 array('fontname' => 'Varela Round'),
1239 array('fontname' => 'Vibur'),
1240 array('fontname' => 'Vollkorn'),
1241 array('fontname' => 'VT323'),
1242 array('fontname' => 'Waiting+for+the+Sunrise'),
1243 array('fontname' => 'Wallpoet'),
1244 array('fontname' => 'Walter+Turncoat'),
1245 array('fontname' => 'Wire+One'),
1246 array('fontname' => 'Yanone+Kaffeesatz'),
1247 array('fontname' => 'Yeseva+One'),
1248 array('fontname' => 'Zeyada')
1249 );
1250 }
1251 break;
1252 default: {
1253 $error = true;
1254 $data['msg'] = esc_html__('The operation failed', 'vision');
1255 }
1256 break;
1257 }
1258 } else {
1259 $error = true;
1260 $data['msg'] = esc_html__('The operation failed', 'vision');
1261 }
1262
1263 if($error) {
1264 wp_send_json_error($data);
1265 } else {
1266 wp_send_json_success($data);
1267 }
1268
1269 wp_die(); // this is required to terminate immediately and return a proper response
1270 }
1271
1272 /**
1273 * Ajax delete all data from tables
1274 */
1275 function ajax_delete_data() {
1276 $error = true;
1277 $data = [];
1278 $data['msg'] = esc_html__('The operation failed, can\'t delete data', 'vision');
1279
1280 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
1281 global $wpdb;
1282 $table = $wpdb->prefix . VISION_PLUGIN_NAME;
1283
1284 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1285 foreach($wpdb->get_results("SELECT id FROM {$table}") as $key => $item) {
1286 // [filemanager] delete file
1287 if(wp_is_writable(VISION_PLUGIN_UPLOAD_DIR)) {
1288 $file_json = 'config.json';
1289 $file_main_css = 'main.css';
1290 $file_custom_css = 'custom.css';
1291 $file_root_path = VISION_PLUGIN_UPLOAD_DIR . '/' . $item->id . '/';
1292
1293 if(file_exists($file_root_path . $file_json)) {
1294 wp_delete_file($file_root_path . $file_json);
1295 }
1296 wp_delete_file($file_root_path . $file_main_css);
1297 wp_delete_file($file_root_path . $file_custom_css);
1298
1299 $wp_filesystem = $this->getFileSystem();
1300 if($wp_filesystem->is_dir($file_root_path)) {
1301 $wp_filesystem->rmdir($file_root_path);
1302 }
1303 }
1304 }
1305
1306 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1307 $result = $wpdb->query("TRUNCATE TABLE {$table}");
1308
1309 if($result) {
1310 $error = false;
1311 $data['msg'] = esc_html__('All data deleted', 'vision');
1312 }
1313 }
1314
1315 if($error) {
1316 wp_send_json_error($data);
1317 } else {
1318 wp_send_json_success($data);
1319 }
1320
1321 wp_die(); // this is required to terminate immediately and return a proper response
1322 }
1323
1324 /**
1325 * Ajax settings get data
1326 */
1327 function ajax_modal() {
1328 if(check_ajax_referer('vision_ajax', 'nonce', false)) {
1329 $modalName = sanitize_file_name(filter_input(INPUT_GET, 'name', FILTER_DEFAULT));
1330 $modalPath = plugin_dir_path( dirname(__FILE__) ) . 'includes/modal-' . $modalName . '.php';
1331
1332 if(file_exists($modalPath)) {
1333 require_once( $modalPath );
1334 }
1335 }
1336
1337 wp_die(); // this is required to terminate immediately and return a proper response
1338 }
1339 }
1340 ?>