PluginProbe
Boxzilla – WordPress Popup Builder / 3.4.3
Boxzilla – WordPress Popup Builder v3.4.3
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.3, at src/admin/class-admin.php

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