PluginProbe
Boxzilla – WordPress Popup Builder / 3.4.8
Boxzilla – WordPress Popup Builder v3.4.8
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.8, at src/admin/class-admin.php

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