PluginProbe
Boxzilla – WordPress Popup Builder / 3.4.0
Boxzilla – WordPress Popup Builder v3.4.0
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 / class-loader.php

class-loader.php in Boxzilla – WordPress Popup Builder 3.4.0, at src/class-loader.php

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