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

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