PluginProbe
Boxzilla – WordPress Popup Builder / 3.4.9
Boxzilla – WordPress Popup Builder v3.4.9
3.4.11 3.4.10 3.4.9 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 trunk 3.0 3.0.1 3.0.2 3.0.3 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 All 72 releases
boxzilla / src / admin / class-admin.php

class-admin.php in Boxzilla – WordPress Popup Builder 3.4.9, at src/admin/class-admin.php

809 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Boxzilla\Admin;
4
5 use Boxzilla\Plugin;
6 use Boxzilla\Box;
7 use Boxzilla\Boxzilla;
8 use WP_Post;
9 use WP_Screen;
10
11 if (! defined('ABSPATH')) {
12 exit;
13 }
14
15 class Admin
16 {
17 /**
18 * @var Plugin $plugin
19 */
20 private $plugin;
21
22 /**
23 * @var Boxzilla
24 */
25 protected $boxzilla;
26
27 /**
28 * @var ReviewNotice
29 */
30 protected $review_notice;
31
32 /**
33 * @param Plugin $plugin
34 * @param Boxzilla $boxzilla
35 */
36 public function __construct(Plugin $plugin, Boxzilla $boxzilla)
37 {
38 $this->plugin = $plugin;
39 $this->boxzilla = $boxzilla;
40 $this->review_notice = new ReviewNotice();
41 }
42
43 /**
44 * Initialise the all admin related stuff
45 */
46 public function init()
47 {
48 $this->add_hooks();
49 $this->run_migrations();
50 $this->review_notice->init();
51 }
52
53 /**
54 * Add necessary hooks
55 */
56 protected function add_hooks()
57 {
58 add_action('admin_init', [ $this, 'lazy_add_hooks' ]);
59 add_action('admin_init', [ $this, 'register' ]);
60 add_action('admin_menu', [ $this, 'menu' ]);
61 add_action('admin_notices', [ $this, 'notices' ]);
62 add_action('save_post_boxzilla-box', [ $this, 'save_box_options' ], 20, 2);
63 add_action('trashed_post', [ $this, 'flush_rules' ]);
64 add_action('untrashed_post', [ $this, 'flush_rules' ]);
65 add_filter('bulk_actions-edit-boxzilla-box', [ $this, 'bulk_action_add' ]);
66 add_filter('handle_bulk_actions-edit-boxzilla-box', [ $this, 'bulk_action_handle' ], 10, 3);
67 }
68
69 public function bulk_action_add($bulk_actions)
70 {
71 $bulk_actions['boxzilla_duplicate_box'] = esc_attr__('Duplicate box', 'boxzilla');
72 return $bulk_actions;
73 }
74
75 public function bulk_action_handle($redirect_to, $doaction, $post_ids)
76 {
77 if ($doaction !== 'boxzilla_duplicate_box' || empty($post_ids)) {
78 return $redirect_to;
79 }
80
81 foreach ($post_ids as $post_id) {
82 $post = get_post($post_id);
83 if ($post->post_type !== 'boxzilla-box') {
84 continue;
85 }
86
87 $new_post_id = wp_insert_post(
88 [
89 'post_type' => $post->post_type,
90 'post_title' => $post->post_title,
91 'post_content' => $post->post_content,
92 'post_status' => 'draft',
93 ]
94 );
95
96 $options = get_post_meta($post_id, 'boxzilla_options', true);
97 add_post_meta($new_post_id, 'boxzilla_options', $options);
98
99 $this->flush_rules($new_post_id);
100 }
101
102 return $redirect_to;
103 }
104
105 /**
106 * All logic for admin notices lives here.
107 */
108 public function notices()
109 {
110 global $pagenow,
111 $current_screen;
112
113 if (
114 ( $pagenow === 'plugins.php' || ( $current_screen && $current_screen->post_type === 'boxzilla-box' ) )
115 && current_user_can('install_plugins')
116 && is_plugin_active('scroll-triggered-boxes/index.php')
117 ) {
118 ?>
119 <div class="notice notice-info">
120 <p><?php esc_html_e('Awesome, you are using Boxzilla! You can now safely deactivate the Scroll Triggered Boxes plugin.', 'boxzilla'); ?></p>
121 </div>
122 <?php
123 }
124 }
125
126 /**
127 * Checks current version against stored version & runs necessary update routines.
128 */
129 protected function run_migrations()
130 {
131
132 // Only run if db option is at older version than code constant
133 $previous_version = get_option('boxzilla_version', '0');
134 $current_version = $this->plugin->version();
135
136 if (version_compare($current_version, $previous_version, '<=')) {
137 return;
138 }
139
140 $upgrade_routines = new Migrations($previous_version, $current_version, __DIR__ . '/migrations');
141 $upgrade_routines->run();
142 update_option('boxzilla_version', $current_version);
143 }
144
145 public function lazy_add_hooks()
146 {
147 global $pagenow;
148
149 add_action('admin_enqueue_scripts', [ $this, 'load_assets' ]);
150 add_action('add_meta_boxes', [ $this, 'add_meta_boxes' ]);
151 add_filter('tiny_mce_before_init', [ $this, 'tinymce_init' ]);
152 add_filter('manage_edit-boxzilla-box_columns', [ $this, 'post_type_column_titles' ]);
153 add_action('manage_boxzilla-box_posts_custom_column', [ $this, 'post_type_column_content' ], 10, 2);
154 add_filter('admin_footer_text', [ $this, 'admin_footer_text' ]);
155
156 if ($pagenow === 'plugins.php') {
157 add_filter('plugin_action_links', [ $this, 'add_plugin_settings_link' ], 10, 2);
158 add_filter('plugin_row_meta', [ $this, 'add_plugin_meta_links' ], 10, 2);
159 }
160 }
161
162 /**
163 * @param $post_id
164 */
165 public function post_type_column_box_id_content($post_id)
166 {
167 echo absint($post_id);
168 }
169
170 /**
171 * @param $column
172 * @param $post_id
173 */
174 public function post_type_column_content($column, $post_id)
175 {
176 $method_name = 'post_type_column_' . $column . '_content';
177 if (method_exists($this, $method_name)) {
178 call_user_func([ $this, $method_name ], $post_id);
179 }
180 }
181
182 /**
183 * @param $columns
184 *
185 * @return mixed
186 */
187 public function post_type_column_titles($columns)
188 {
189 $columns = self::array_insert(
190 $columns,
191 [
192 'box_id' => esc_html__('Box ID', 'boxzilla'),
193 ],
194 1
195 );
196
197 $columns['title'] = esc_html__('Box Title', 'boxzilla');
198
199 return $columns;
200 }
201
202 /**
203 * Register stuffs
204 */
205 public function register()
206 {
207
208 register_setting('boxzilla_settings', 'boxzilla_settings', [ $this, 'sanitize_settings' ]);
209
210 wp_register_script(
211 'boxzilla-admin',
212 $this->plugin->url('/assets/js/admin-script.js'),
213 [
214 'jquery',
215 'wp-util',
216 'wp-color-picker',
217 'suggest',
218 ],
219 $this->plugin->version(),
220 true
221 );
222
223 wp_register_style('boxzilla-admin', $this->plugin->url('/assets/css/admin-styles.css'), [], $this->plugin->version());
224 }
225
226 /**
227 * Renders the Boxzilla admin menu items
228 */
229 public function menu()
230 {
231 $menu_items = [
232 [
233 esc_html__('Settings', 'boxzilla'),
234 esc_html__('Settings', 'boxzilla'),
235 'boxzilla-settings',
236 [ $this, 'show_settings_page' ],
237 ],
238 [
239 esc_html__('Extensions', 'boxzilla'),
240 '<span style="color: orange">' . esc_html__('Extensions', 'boxzilla') . '</span>',
241 'boxzilla-extensions',
242 [ $this, 'show_extensions_page' ],
243 ],
244 ];
245
246 $menu_items = apply_filters('boxzilla_admin_menu_items', $menu_items);
247
248 foreach ($menu_items as $item) {
249 add_submenu_page('edit.php?post_type=boxzilla-box', $item[0] . '- Boxzilla', $item[1], 'manage_options', $item[2], $item[3]);
250 }
251 }
252
253 /**
254 * Shows the settings page
255 */
256 public function show_settings_page()
257 {
258 $opts = $this->boxzilla->options;
259 require __DIR__ . '/views/settings.php';
260 }
261
262 /**
263 * Shows the extensions page
264 */
265 public function show_extensions_page()
266 {
267 $extensions = $this->fetch_extensions();
268 require __DIR__ . '/views/extensions.php';
269 }
270
271 /**
272 * Are we currently editing a box?
273 *
274 * @return bool
275 */
276 protected function on_edit_box_page()
277 {
278 global $pagenow;
279
280 if (! in_array($pagenow, [ 'post-new.php', 'post.php' ], true)) {
281 return false;
282 }
283
284 if (isset($_GET['post_type']) && $_GET['post_type'] === 'boxzilla-box') {
285 return true;
286 }
287
288 if (get_post_type() === 'boxzilla-box') {
289 return true;
290 }
291
292 return false;
293 }
294
295 /**
296 * @param $args
297 *
298 * @return mixed
299 */
300 public function tinymce_init($args)
301 {
302
303 // only act on our post type
304 if (get_post_type() !== 'boxzilla-box') {
305 return $args;
306 }
307
308 $args['setup'] = 'function( editor ) { if(typeof(window.Boxzilla_Admin) === \'undefined\') { return; } editor.on("PreInit", window.Boxzilla_Admin.Designer.init ); }';
309
310 return $args;
311 }
312
313 /**
314 * Load plugin assets
315 */
316 public function load_assets()
317 {
318 $screen = get_current_screen();
319
320 if (! $screen instanceof WP_Screen) {
321 return false;
322 }
323
324 if ($screen->base === 'edit' && $screen->post_type === 'boxzilla-box') {
325 wp_enqueue_style('boxzilla-admin');
326 }
327
328 if ($screen->base === 'post' && $screen->post_type === 'boxzilla-box') {
329 // color picker
330 wp_enqueue_style('wp-color-picker');
331
332 // load scripts
333 wp_enqueue_script('boxzilla-admin');
334
335 $data = [
336 'and' => esc_html__('and', 'boxzilla'),
337 'or' => esc_html__('or', 'boxzilla'),
338 'enterCommaSeparatedValues' => esc_html__('Enter a comma-separated list of values.', 'boxzilla'),
339 'enterCommaSeparatedPosts' => esc_html__("Enter a comma-separated list of post slugs or post ID's..", 'boxzilla'),
340 'enterCommaSeparatedPages' => esc_html__("Enter a comma-separated list of page slugs or page ID's..", 'boxzilla'),
341 'enterCommaSeparatedPostTypes' => esc_html__('Enter a comma-separated list of post types..', 'boxzilla'),
342 'enterCommaSeparatedRelativeUrls' => esc_html__("Enter a comma-separated list of relative URL's, eg /contact/", 'boxzilla'),
343 ];
344 wp_localize_script('boxzilla-admin', 'boxzilla_i18n', $data);
345
346 // load stylesheets
347 wp_enqueue_style('boxzilla-admin');
348
349 // allow add-ons to easily load their own scripts or stylesheets
350 do_action('boxzilla_load_admin_assets');
351 }
352
353 if (isset($_GET['page']) && $_GET['page'] === 'boxzilla-settings') {
354 wp_enqueue_style('boxzilla-admin');
355 }
356 }
357
358 /**
359 * Register meta boxes
360 *
361 * @param string $post_type
362 */
363 public function add_meta_boxes($post_type)
364 {
365 if ($post_type !== 'boxzilla-box') {
366 return;
367 }
368
369 add_meta_box(
370 'boxzilla-box-appearance-controls',
371 esc_html__('Box Appearance', 'boxzilla'),
372 [ $this, 'metabox_box_appearance_controls' ],
373 'boxzilla-box',
374 'normal',
375 'core'
376 );
377
378 add_meta_box(
379 'boxzilla-box-options-controls',
380 esc_html__('Box Options', 'boxzilla'),
381 [ $this, 'metabox_box_option_controls' ],
382 'boxzilla-box',
383 'normal',
384 'core'
385 );
386
387 add_meta_box(
388 'boxzilla-support',
389 esc_html__('Looking for help?', 'boxzilla'),
390 [ $this, 'metabox_support' ],
391 'boxzilla-box',
392 'side'
393 );
394
395 add_meta_box(
396 'boxzilla-our-other-plugins',
397 esc_html__('Our other plugins', 'boxzilla'),
398 [ $this, 'metabox_our_other_plugins' ],
399 'boxzilla-box',
400 'side'
401 );
402 }
403
404 /**
405 * @param \WP_Post $post
406 * @param $metabox
407 */
408 public function metabox_box_appearance_controls(\WP_Post $post, $metabox)
409 {
410
411 // get box options
412 $box = new Box($post);
413 $opts = $box->get_options();
414
415 // include view
416 include __DIR__ . '/views/metaboxes/box-appearance-controls.php';
417 }
418
419 /**
420 * @param \WP_Post $post
421 * @param $metabox
422 */
423 public function metabox_box_option_controls(\WP_Post $post, $metabox)
424 {
425
426 // get box options
427 $box = new Box($post);
428 $opts = $box->get_options();
429 $global_opts = $this->boxzilla->options;
430
431 if (empty($opts['rules'])) {
432 $opts['rules'][] = [
433 'condition' => '',
434 'qualifier' => 1,
435 'value' => '',
436 ];
437 }
438
439 // include view
440 include __DIR__ . '/views/metaboxes/box-option-controls.php';
441 }
442
443 /**
444 * @param \WP_Post $post
445 * @param $metabox
446 */
447 public function metabox_our_other_plugins(\WP_Post $post, $metabox)
448 {
449 include __DIR__ . '/views/metaboxes/our-other-plugins.php';
450 }
451
452 /**
453 * @param \WP_Post $post
454 * @param $metabox
455 */
456 public function metabox_support(\WP_Post $post, $metabox)
457 {
458 include __DIR__ . '/views/metaboxes/need-help.php';
459 }
460
461
462 /**
463 * Saves box options and rules
464 *
465 * @param int $box_id
466 * @param \WP_Post $post
467 */
468 public function save_box_options($box_id, $post)
469 {
470 // Only act on our own post type
471 if ($post->post_type !== 'boxzilla-box') {
472 return;
473 }
474
475 // is this a revision save?
476 if (wp_is_post_revision($box_id) || ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )) {
477 return;
478 }
479
480 // can user edit this post?
481 if (! current_user_can('edit_post', $box_id)) {
482 return;
483 }
484
485 // make sure options array is set
486 if (! isset($_POST['boxzilla_box']) || ! is_array($_POST['boxzilla_box'])) {
487 return;
488 }
489
490 // get new options from $_POST
491 $opts = $this->sanitize_box_options($_POST['boxzilla_box']);
492
493 // allow extensions to filter the saved options
494 $opts = apply_filters('boxzilla_saved_options', $opts, $box_id);
495
496 // save individual box settings
497 update_post_meta($box_id, 'boxzilla_options', $opts);
498
499 // update global settings if given
500 if (! empty($_POST['boxzilla_global_settings'])) {
501 $raw_global_settings = $_POST['boxzilla_global_settings'];
502 $global_settings = get_option('boxzilla_settings', []);
503 if (! is_array($global_settings)) {
504 $global_settings = [];
505 }
506 if (isset($raw_global_settings['test_mode'])) {
507 $global_settings['test_mode'] = absint($raw_global_settings['test_mode']);
508 }
509 update_option('boxzilla_settings', $global_settings);
510 }
511
512 $this->flush_rules($box_id);
513 }
514
515 /**
516 * @param array $opts
517 *
518 * @return array
519 */
520 public function sanitize_settings($opts)
521 {
522 $opts['test_mode'] = (int) $opts['test_mode'] ? 1 : 0;
523 return $opts;
524 }
525
526 /**
527 * @param string $url_string
528 *
529 * @return string
530 */
531 public function sanitize_url($url_string)
532 {
533 // if empty, just return a slash
534 if (empty($url_string)) {
535 return '/';
536 }
537
538 // if string looks like an absolute URL, extract just the path
539 if (preg_match('/^((https|http)?\:\/\/)?(\w+\.)?\w+\.\w+\.*/i', $url_string)) {
540 // make sure URL has scheme prepended, to make parse_url() understand..
541 $url_string = 'https://' . str_replace([ 'http://', 'https://' ], '', $url_string);
542
543 // get just the path
544 $url_string = parse_url($url_string, PHP_URL_PATH);
545 }
546
547 return $url_string;
548 }
549
550 /**
551 * @param array $rule
552 * @return array The sanitized rule array
553 */
554 public function sanitize_box_rule($rule)
555 {
556 $rule['value'] = trim($rule['value']);
557
558 // convert to array
559 $rule['value'] = explode(',', trim($rule['value'], ','));
560
561 // trim all whitespace in value field
562 $rule['value'] = array_map('trim', $rule['value']);
563
564 // Make sure "is_url" values have a leading slash
565 if ($rule['condition'] === 'is_url') {
566 $rule['value'] = array_map([ $this, 'sanitize_url' ], $rule['value']);
567 }
568
569 // (re)set value to 0 when condition is everywhere
570 if ($rule['condition'] === 'everywhere') {
571 $rule['value'] = '';
572 }
573
574 // convert back to string before saving
575 if (is_array($rule['value'])) {
576 $rule['value'] = join(',', $rule['value']);
577 }
578
579 return $rule;
580 }
581
582 /**
583 * @param array $css
584 * @return array
585 */
586 public function sanitize_box_css($css)
587 {
588
589 // sanitize settings
590 if ('' !== $css['width']) {
591 $css['width'] = absint($css['width']);
592 }
593
594 if ('' !== $css['border_width']) {
595 $css['border_width'] = absint($css['border_width']);
596 }
597
598 // make sure colors start with `#`
599 $color_keys = [ 'color', 'background_color', 'border_color' ];
600 foreach ($color_keys as $key) {
601 $value = $css[ $key ];
602 $color = sanitize_text_field($value);
603
604 // make sure color starts with `#`
605 if ('' !== $color && $color[0] !== '#') {
606 $color = '#' . $color;
607 }
608 $css[ $key ] = $color;
609 }
610
611 return $css;
612 }
613
614 /**
615 * Sanitize the options for this box.
616 *
617 * @param array $opts
618 *
619 * @return array
620 */
621 protected function sanitize_box_options($opts)
622 {
623 $defaults = [
624 'rules' => [],
625 'css' => [],
626 ];
627
628 $opts = array_replace_recursive($defaults, $opts);
629
630 $opts['rules'] = array_map([ $this, 'sanitize_box_rule' ], $opts['rules']);
631 $opts['css'] = $this->sanitize_box_css($opts['css']);
632 $opts['cookie']['triggered'] = absint($opts['cookie']['triggered']);
633 $opts['cookie']['dismissed'] = absint($opts['cookie']['dismissed']);
634 $opts['trigger'] = sanitize_text_field($opts['trigger']);
635 $opts['trigger_percentage'] = absint($opts['trigger_percentage']);
636 $opts['trigger_element'] = sanitize_text_field($opts['trigger_element']);
637 $opts['screen_size_condition']['value'] = intval($opts['screen_size_condition']['value']);
638
639 return $opts;
640 }
641
642 /**
643 * Add the settings link to the Plugins overview
644 *
645 * @param array $links
646 * @param string $slug
647 *
648 * @return array
649 */
650 public function add_plugin_settings_link($links, $slug)
651 {
652 if ($slug !== $this->plugin->slug() || ! is_array($links)) {
653 return $links;
654 }
655
656 $href = admin_url('edit.php?post_type=boxzilla-box');
657 $label = esc_html__('Boxes', 'boxzilla');
658 $settings_link = "<a href=\"{$href}\">{$label}</a>";
659 array_unshift($links, $settings_link);
660 return $links;
661 }
662
663 /**
664 * Adds meta links to the plugin in the WP Admin > Plugins screen
665 *
666 * @param array $links
667 * @param string $slug
668 *
669 * @return array
670 */
671 public function add_plugin_meta_links($links, $slug)
672 {
673 if ($slug !== $this->plugin->slug()) {
674 return $links;
675 }
676
677 $links[] = '<a href="https://boxzillaplugin.com/kb/">Documentation</a>';
678 $links[] = '<a href="https://boxzillaplugin.com/add-ons/">Add-ons</a>';
679
680 return $links;
681 }
682
683 /**
684 * Flush all box rules
685 *
686 * Loops through all published boxes and fills the rules option
687 *
688 * @param int $post_id
689 */
690 public function flush_rules($post_id)
691 {
692
693 // only act on our own post type
694 $post = get_post($post_id);
695 if (! $post instanceof WP_Post || $post->post_type !== 'boxzilla-box') {
696 return;
697 }
698
699 // get all published boxes
700 $query = new \WP_Query();
701 $boxes = $query->query(
702 [
703 'post_type' => 'boxzilla-box',
704 'post_status' => 'publish',
705 'posts_per_page' => - 1,
706 'ignore_sticky_posts' => true,
707 'no_found_rows' => true,
708 ]
709 );
710
711 // setup empty array of rules
712 $rules = [];
713
714 // fill rules array
715 if (is_array($boxes)) {
716 foreach ($boxes as $box) {
717 // get box meta data
718 $box_meta = get_post_meta($box->ID, 'boxzilla_options', true);
719 if (! $box_meta || ! is_array($box_meta) || empty($box_meta['rules'])) {
720 continue;
721 }
722
723 // add box rules to all rules
724 $rules[ $box->ID ] = (array) $box_meta['rules'];
725 $rules[ $box->ID ]['comparision'] = isset($box_meta['rules_comparision']) ? $box_meta['rules_comparision'] : 'any';
726 }
727 }
728
729 update_option('boxzilla_rules', $rules);
730 }
731
732 /**
733 * Fetches a list of available add-on plugins
734 *
735 * @return array
736 */
737 protected function fetch_extensions()
738 {
739 $extensions = get_transient('boxzilla_remote_extensions');
740 if ($extensions) {
741 return $extensions;
742 }
743
744 $response = wp_remote_get('https://my.boxzillaplugin.com/api/v2/plugins');
745 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) >= 400) {
746 return [];
747 }
748
749 $body = wp_remote_retrieve_body($response);
750 $data = json_decode($body);
751 if (is_array($data)) {
752 set_transient('boxzilla_remote_extensions', $data, 24 * HOUR_IN_SECONDS);
753 return $data;
754 }
755
756 return [];
757 }
758
759 /**
760 * @param $arr
761 * @param $insert
762 * @param $position
763 *
764 * @return array
765 */
766 public static function array_insert($arr, $insert, $position)
767 {
768 $i = 0;
769 $ret = [];
770 foreach ($arr as $key => $value) {
771 if ($i == $position) {
772 foreach ($insert as $ikey => $ivalue) {
773 $ret[ $ikey ] = $ivalue;
774 }
775 }
776 $ret[ $key ] = $value;
777 $i++;
778 }
779
780 return $ret;
781 }
782
783 /**
784 * @param string $text
785 *
786 * @return string
787 */
788 public function admin_footer_text($text)
789 {
790 $screen = get_current_screen();
791
792 if (! $screen instanceof WP_Screen) {
793 return $text;
794 }
795
796 $on_edit_page = $screen->parent_base === 'edit' && $screen->post_type === 'boxzilla-box';
797 if ($on_edit_page) {
798 return sprintf('If you enjoy using <strong>Boxzilla</strong>, please <a href="%s" target="_blank">leave us a �
799
800
801
802
803 rating</a>. A <strong style="text-decoration: underline;">huge</strong> thank you in advance!', 'https://wordpress.org/support/view/plugin-reviews/boxzilla?rate=5#postform');
804 }
805
806 return $text;
807 }
808 }
809