PluginProbe
Boxzilla – WordPress Popup Builder / 3.4.6
Boxzilla – WordPress Popup Builder v3.4.6
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.6, at src/admin/class-admin.php

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