PluginProbe
Boxzilla – WordPress Popup Builder / 3.2
Boxzilla – WordPress Popup Builder v3.2
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
← All changes | src/class-loader.php +332 -354 3.4.103.2 View file →
@@ -1,354 +1,332 @@
1 -<?php
2 -
3 -namespace Boxzilla;
4 -
5 -if (! defined('ABSPATH')) {
6 - exit;
7 -}
8 -
9 -class BoxLoader
10 -{
11 - /**
12 - * @var Plugin
13 - */
14 - private $plugin;
15 -
16 - /**
17 - * @var array
18 - */
19 - private $box_ids_to_load = [];
20 -
21 - /**
22 - * @var array
23 - */
24 - protected $options;
25 -
26 - /**
27 - * Constructor
28 - *
29 - * @param Plugin $plugin
30 - * @param array $options
31 - */
32 - public function __construct(Plugin $plugin, array $options)
33 - {
34 - $this->plugin = $plugin;
35 - $this->options = $options;
36 - }
37 -
38 - /**
39 - * Initializes the plugin, runs on `wp` hook.
40 - */
41 - public function init()
42 - {
43 - $this->box_ids_to_load = $this->filter_boxes();
44 -
45 - // Only add other hooks if necessary
46 - add_action('wp_head', [$this, 'print_preload_js'], 10, 0);
47 - if (count($this->box_ids_to_load) > 0) {
48 - add_action('wp_footer', [ $this, 'print_boxes_content' ], 1);
49 - add_action('wp_enqueue_scripts', [ $this, 'load_assets' ], 90);
50 - }
51 - }
52 -
53 - /**
54 - * Prints the preload API so that the Boxzilla JS API can be used before Boxzilla itself is loaded
55 - * This allows us to defer the Boxzilla script itself.
56 - */
57 - public function print_preload_js(): void
58 - {
59 - echo '<script>';
60 - include BOXZILLA_DIR . '/assets/js/preload.js';
61 - echo '</script>';
62 - }
63 -
64 - /**
65 - * Get global rules for all boxes
66 - *
67 - * @return array
68 - */
69 - protected function get_filter_rules(): array
70 - {
71 - $rules = get_option('boxzilla_rules', []);
72 - return is_array($rules) ? $rules : [];
73 - }
74 -
75 -
76 - /**
77 - * Match a string against an array of patterns, glob-style.
78 - *
79 - * @param string $string
80 - * @param array $patterns
81 - * @param bool $contains
82 - * @return bool
83 - */
84 - protected function match_patterns($string, array $patterns, $contains = false)
85 - {
86 - $string = strtolower($string);
87 -
88 - foreach ($patterns as $pattern) {
89 - $pattern = rtrim($pattern, '/');
90 - $pattern = strtolower($pattern);
91 -
92 - if ($contains) {
93 - // contains means we should do a simple occurrence check
94 - // does not support wildcards
95 - $match = strpos($string, $pattern) !== false;
96 - } elseif (function_exists('fnmatch')) {
97 - $match = fnmatch($pattern, $string);
98 - } else {
99 - $match = ( $pattern === $string );
100 - }
101 -
102 - if ($match) {
103 - return true;
104 - }
105 - }
106 -
107 - return false;
108 - }
109 -
110 - /**
111 - * @return string
112 - */
113 - protected function get_request_url()
114 - {
115 - return rtrim($_SERVER['REQUEST_URI'] ?? '', '/');
116 - }
117 -
118 - /**
119 - * Check if this rule passes (conditional matches expected value)
120 - *
121 - * @param string $condition
122 - * @param string $value
123 - * @param boolean $qualifier
124 - *
125 - * @return bool
126 - */
127 - protected function match_rule($condition, $value, $qualifier = true)
128 - {
129 - $matched = false;
130 -
131 - // cast value to array & trim whitespace or excess comma's
132 - $values = array_map('trim', explode(',', rtrim(trim($value), ',')));
133 -
134 - switch ($condition) {
135 - case 'everywhere':
136 - $matched = true;
137 - break;
138 -
139 - case 'is_url':
140 - $url = $this->get_request_url();
141 - $matched = $this->match_patterns($url, $values, $qualifier === 'contains' || $qualifier === 'not_contains');
142 - break;
143 -
144 - case 'is_referer':
145 - if (! empty($_SERVER['HTTP_REFERER'])) {
146 - $referer = $_SERVER['HTTP_REFERER'];
147 - $matched = $this->match_patterns($referer, $values, $qualifier === 'contains' || $qualifier === 'not_contains');
148 - }
149 - break;
150 -
151 - case 'is_post_type':
152 - $post_type = (string) get_post_type();
153 - $matched = in_array($post_type, $values, true);
154 - break;
155 -
156 - case 'is_single':
157 - case 'is_post':
158 - // convert to empty string if array with just empty string in it
159 - $value = ( $values === [ '' ] ) ? '' : $values;
160 - $matched = is_single($value);
161 - break;
162 -
163 - case 'is_post_in_category':
164 - $matched = is_singular() && has_category($values);
165 - break;
166 -
167 - case 'is_page':
168 - $matched = is_page($values);
169 - break;
170 -
171 - case 'is_post_with_tag':
172 - $matched = is_singular() && has_tag($values);
173 - break;
174 -
175 - case 'is_user_logged_in':
176 - $matched = is_user_logged_in();
177 - break;
178 - }
179 -
180 - /**
181 - * Filters whether a given box rule matches the condition and expected value.
182 - *
183 - * The dynamic portion of the hook, `$condition`, refers to the condition being matched.
184 - *
185 - * @param boolean $matched
186 - * @param array $values
187 - */
188 - $matched = apply_filters('boxzilla_box_rule_matches_' . $condition, $matched, $values);
189 -
190 - // if qualifier is set to false, we need to reverse this value here.
191 - if (! $qualifier || $qualifier === 'not_contains') {
192 - $matched = ! $matched;
193 - }
194 -
195 - return $matched;
196 - }
197 -
198 - /**
199 - * Checks which boxes should be loaded for this request.
200 - *
201 - * @return array
202 - */
203 - private function filter_boxes()
204 - {
205 - $box_ids_to_load = [];
206 - $rules = $this->get_filter_rules();
207 -
208 - foreach ($rules as $box_id => $box_rules) {
209 - $matched = false;
210 - $comparision = isset($box_rules['comparision']) ? $box_rules['comparision'] : 'any';
211 -
212 - // loop through all rules for all boxes
213 - foreach ($box_rules as $rule) {
214 - // skip faulty values (and comparision rule)
215 - if (! is_array($rule) || empty($rule['condition'])) {
216 - continue;
217 - }
218 -
219 - $qualifier = isset($rule['qualifier']) ? $rule['qualifier'] : true;
220 - $matched = $this->match_rule($rule['condition'], $rule['value'], $qualifier);
221 -
222 - // break out of loop if we've already matched
223 - if ($comparision === 'any' && $matched) {
224 - break;
225 - }
226 -
227 - // no need to continue if this rule didn't match
228 - if ($comparision === 'all' && ! $matched) {
229 - break;
230 - }
231 - }
232 -
233 - // value of $matched at this point determines whether box should be loaded
234 - $load_box = $matched;
235 -
236 - /**
237 - * Filters whether a box should be loaded into the page HTML.
238 - *
239 - * The dynamic portion of the hook, `$box_id`, refers to the ID of the box. Return true if you want to output the box.
240 - *
241 - * @param boolean $load_box
242 - */
243 - $load_box = apply_filters('boxzilla_load_box_' . $box_id, $load_box);
244 -
245 - /**
246 - * Filters whether a box should be loaded into the page HTML.
247 - *
248 - * @param boolean $load_box
249 - * @param int $box_id
250 - */
251 - $load_box = apply_filters('boxzilla_load_box', $load_box, $box_id);
252 -
253 - // if matched, box should be loaded on this page
254 - if ($load_box) {
255 - $box_ids_to_load[] = $box_id;
256 - }
257 - }
258 -
259 - /**
260 - * Filters which boxes should be loaded on this page, expects an array of post ID's.
261 - *
262 - * @param array $box_ids_to_load
263 - */
264 - return apply_filters('boxzilla_load_boxes', $box_ids_to_load);
265 - }
266 -
267 - /**
268 - * Load plugin styles
269 - */
270 - public function load_assets()
271 - {
272 - wp_enqueue_style('boxzilla', $this->plugin->url('/assets/css/styles.css'), [], $this->plugin->version());
273 - wp_enqueue_script('boxzilla', $this->plugin->url('/assets/js/script.js'), [], $this->plugin->version(), [
274 - 'strategy' => 'defer',
275 - 'in_footer' => true,
276 - ]);
277 -
278 - // create boxzilla_Global_Options object
279 - $plugin_options = $this->options;
280 - $boxes = $this->get_matched_boxes();
281 -
282 - $data = [
283 - 'testMode' => (bool) $plugin_options['test_mode'],
284 - 'boxes' => (array) array_map(
285 - function (Box $box) {
286 - return $box->get_client_options();
287 - },
288 - $boxes
289 - ),
290 - ];
291 -
292 - wp_localize_script('boxzilla', 'boxzilla_options', $data);
293 -
294 - do_action('boxzilla_load_assets', $this);
295 - }
296 -
297 - public function print_boxes_content()
298 - {
299 - $boxes = $this->get_matched_boxes();
300 - if (empty($boxes)) {
301 - return;
302 - }
303 -
304 - echo '<div style="display: none;">';
305 - foreach ($boxes as $box) {
306 - printf('<div id="boxzilla-box-%d-content">%s</div>', absint($box->ID), $box->get_content());
307 - }
308 - echo '</div>';
309 - }
310 -
311 - /**
312 - * Get an array of Box objects. These are the boxes that will be loaded for the current request.
313 - *
314 - * @return Box[]
315 - */
316 - public function get_matched_boxes()
317 - {
318 - static $boxes;
319 -
320 - if (is_null($boxes)) {
321 - if (count($this->box_ids_to_load) === 0) {
322 - return [];
323 - }
324 -
325 - // query Box posts
326 - $q = new \WP_Query();
327 - $posts = $q->query(
328 - [
329 - 'post_type' => 'boxzilla-box',
330 - 'post_status' => 'publish',
331 - 'post__in' => $this->box_ids_to_load,
332 - 'posts_per_page' => count($this->box_ids_to_load),
333 - 'ignore_sticky_posts' => true,
334 - 'no_found_rows' => true,
335 - ]
336 - );
337 -
338 - // create `Box` instances out of \WP_Post instances
339 - $boxes = [];
340 - foreach ($posts as $key => $post) {
341 - $box = new Box($post);
342 -
343 - // skip boxes without any content
344 - if ($box->get_content() === '') {
345 - continue;
346 - }
347 -
348 - $boxes[ $key ] = $box;
349 - }
350 - }
351 -
352 - return $boxes;
353 - }
354 -}
1 +<?php
2 +
3 +namespace Boxzilla;
4 +
5 +class BoxLoader {
6 +
7 + /**
8 + * @var Plugin
9 + */
10 + private $plugin;
11 +
12 + /**
13 + * @var array
14 + */
15 + private $box_ids_to_load = array();
16 +
17 + /**
18 + * @var array
19 + */
20 + protected $options;
21 +
22 + /**
23 + * Constructor
24 + *
25 + * @param Plugin $plugin
26 + * @param array $options
27 + */
28 + public function __construct( Plugin $plugin, array $options ) {
29 + $this->plugin = $plugin;
30 + $this->options = $options;
31 + }
32 +
33 + /**
34 + * Initializes the plugin, runs on `wp` hook.
35 + */
36 + public function init() {
37 +
38 + $this->box_ids_to_load = $this->filter_boxes();
39 +
40 + // Only add other hooks if necessary
41 + if( count( $this->box_ids_to_load ) > 0 ) {
42 + add_action( 'wp_footer', array( $this, 'print_boxes_content' ) );
43 + add_action( 'wp_enqueue_scripts', array( $this, 'load_assets' ), 90 );
44 + }
45 + }
46 +
47 + /**
48 + * Get global rules for all boxes
49 + *
50 + * @return array
51 + */
52 + protected function get_filter_rules() {
53 + $rules = get_option( 'boxzilla_rules', array() );
54 +
55 + if( ! is_array( $rules ) ) {
56 + return array();
57 + }
58 +
59 + return $rules;
60 + }
61 +
62 +
63 + /**
64 + * Match a string against an array of patterns, glob-style.
65 + *
66 + * @param string $string
67 + * @param array $patterns
68 + *
69 + * @return boolean
70 + */
71 + protected function match_patterns( $string, $patterns ) {
72 + $string = strtolower( $string );
73 +
74 + foreach( $patterns as $pattern ) {
75 +
76 + $pattern = rtrim( $pattern, '/' );
77 + $pattern = strtolower( $pattern );
78 +
79 + if( function_exists( 'fnmatch' ) ) {
80 + $match = fnmatch( $pattern, $string );
81 + } else {
82 + $match = ( $pattern === $string );
83 + }
84 +
85 + if( $match ) {
86 + return true;
87 + }
88 + }
89 +
90 + return false;
91 + }
92 +
93 + /**
94 + * @return string
95 + */
96 + protected function get_request_url() {
97 + // strip trailing slashes
98 + $request_uri = rtrim( $_SERVER['REQUEST_URI'], '/' );
99 +
100 + // strip ? and query string
101 + $qpos = strpos( $request_uri, '?' );
102 + if( $qpos ) {
103 + $request_uri = substr( $request_uri, 0, $qpos );
104 + }
105 +
106 + return $request_uri;
107 + }
108 +
109 + /**
110 + * Check if this rule passes (conditional matches expected value)
111 + *
112 + * @param string $condition
113 + * @param string $value
114 + * @param boolean $qualifier
115 + *
116 + * @return bool
117 + */
118 + protected function match_rule( $condition, $value, $qualifier = true ) {
119 +
120 + $matched = false;
121 +
122 + // cast value to array & trim whitespace or excess comma's
123 + $value = array_map( 'trim', explode( ',', rtrim( trim( $value ), ',' ) ) );
124 +
125 + switch ( $condition ) {
126 + case 'everywhere';
127 + $matched = true;
128 + break;
129 +
130 + case 'is_url':
131 + $matched = $this->match_patterns( $this->get_request_url(), $value );
132 + break;
133 +
134 + case 'is_referer':
135 + if( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
136 + $referer = $_SERVER['HTTP_REFERER'];
137 + $matched = $this->match_patterns( $referer, $value );
138 + }
139 + break;
140 +
141 + case 'is_post_type':
142 + $post_type = (string) get_post_type();
143 + $matched = in_array( $post_type, (array) $value );
144 + break;
145 +
146 + case 'is_single':
147 + case 'is_post':
148 + // convert to empty string if array with just empty string in it
149 + $value = ( $value === array( '' ) ) ? '' : $value;
150 + $matched = is_single( $value );
151 + break;
152 +
153 + case 'is_post_in_category':
154 + $matched = is_singular( 'post' ) && has_category( $value );
155 + break;
156 +
157 +
158 + case 'is_page':
159 + $matched = is_page( $value );
160 + break;
161 +
162 + case 'is_post_with_tag':
163 + $matched = is_singular( 'post' ) && has_tag( $value );
164 + break;
165 +
166 + case 'is_user_logged_in':
167 + $matched = is_user_logged_in();
168 + break;
169 + }
170 +
171 + /**
172 + * Filters whether a given box rule matches the condition and expected value.
173 + *
174 + * The dynamic portion of the hook, `$condition`, refers to the condition being matched.
175 + *
176 + * @param boolean $matched
177 + * @param array $value
178 + */
179 + $matched = apply_filters( 'boxzilla_box_rule_matches_' . $condition, $matched, $value );
180 +
181 + // if qualifier is set to false, we need to reverse this value here.
182 + if( ! $qualifier ) {
183 + $matched = ! $matched;
184 + }
185 +
186 + return $matched;
187 + }
188 +
189 + /**
190 + * Checks which boxes should be loaded for this request.
191 + *
192 + * @return array
193 + */
194 + private function filter_boxes() {
195 +
196 + $box_ids_to_load = array();
197 + $rules = $this->get_filter_rules();
198 +
199 + foreach( $rules as $box_id => $box_rules ) {
200 +
201 + $matched = false;
202 + $comparision = isset( $box_rules['comparision'] ) ? $box_rules['comparision'] : 'any';
203 +
204 + // loop through all rules for all boxes
205 + foreach ( $box_rules as $rule ) {
206 +
207 + // skip faulty values (and comparision rule)
208 + if( empty( $rule['condition'] ) ) {
209 + continue;
210 + }
211 +
212 + $qualifier = isset( $rule['qualifier'] ) ? $rule['qualifier'] : true;
213 + $matched = $this->match_rule( $rule['condition'], $rule['value'], $qualifier );
214 +
215 + // break out of loop if we've already matched
216 + if( $comparision === 'any' && $matched ) {
217 + break;
218 + }
219 +
220 + // no need to continue if this rule didn't match
221 + if( $comparision === 'all' && ! $matched ) {
222 + break;
223 + }
224 + }
225 +
226 + // value of $matched at this point determines whether box should be loaded
227 + $load_box = $matched;
228 +
229 + /**
230 + * Filters whether a box should be loaded into the page HTML.
231 + *
232 + * The dynamic portion of the hook, `$box_id`, refers to the ID of the box. Return true if you want to output the box.
233 + *
234 + * @param boolean $load_box
235 + */
236 + $load_box = apply_filters( 'boxzilla_load_box_' . $box_id, $load_box );
237 +
238 + /**
239 + * Filters whether a box should be loaded into the page HTML.
240 + *
241 + * @param boolean $load_box
242 + * @param int $box_id
243 + */
244 + $load_box = apply_filters( 'boxzilla_load_box', $load_box, $box_id );
245 +
246 + // if matched, box should be loaded on this page
247 + if ( $load_box ) {
248 + $box_ids_to_load[] = $box_id;
249 + }
250 +
251 + }
252 +
253 + return $box_ids_to_load;
254 + }
255 +
256 + /**
257 + * Load plugin styles
258 + */
259 + public function load_assets() {
260 + $pre_suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
261 + wp_enqueue_script('boxzilla', $this->plugin->url('/assets/js/script' . $pre_suffix . '.js' ), array(), $this->plugin->version(), true );
262 +
263 + // create boxzilla_Global_Options object
264 + $plugin_options = $this->options;
265 + $boxes = $this->get_matched_boxes();
266 +
267 + $data = array(
268 + 'testMode' => (bool) $plugin_options['test_mode'],
269 + 'boxes' => array_map( function(Box $box) { return $box->get_client_options(); }, $boxes ),
270 + );
271 +
272 + wp_localize_script( 'boxzilla', 'boxzilla_options', $data );
273 +
274 + do_action( 'boxzilla_load_assets', $this );
275 + }
276 +
277 + public function print_boxes_content() {
278 + $boxes = $this->get_matched_boxes();
279 + if( empty( $boxes ) ) {
280 + return;
281 + }
282 +
283 + echo '<div style="display: none;">';
284 + foreach( $boxes as $box ) {
285 + echo sprintf( '<div id="boxzilla-box-%d-content">', $box->ID ) . $box->get_content() . '</div>';
286 + }
287 + echo '</div>';
288 + }
289 +
290 + /**
291 + * Get an array of Box objects. These are the boxes that will be loaded for the current request.
292 + *
293 + * @return Box[]
294 + */
295 + public function get_matched_boxes() {
296 + static $boxes;
297 +
298 + if( is_null( $boxes ) ) {
299 +
300 + if( count( $this->box_ids_to_load ) === 0 ) {
301 + $boxes = array();
302 + return $boxes;
303 + }
304 +
305 + // query Box posts
306 + $posts = get_posts(
307 + array(
308 + 'post_type' => 'boxzilla-box',
309 + 'post_status' => 'publish',
310 + 'post__in' => $this->box_ids_to_load,
311 + 'numberposts' => -1
312 + )
313 + );
314 +
315 + // create `Box` instances out of \WP_Post instances
316 + $boxes = array();
317 + foreach ( $posts as $key => $post ) {
318 + // skip posts with no content
319 + if( empty( trim( $post->post_content ) ) ) {
320 + continue;
321 + }
322 +
323 + $boxes[ $key ] = new Box( $post );
324 + }
325 + }
326 +
327 + return $boxes;
328 + }
329 +
330 +}
331 +
332 +