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

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