PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / 2.2.7
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts v2.2.7
2.7.7 2.7.6 2.7.5 2.7.4 trunk 1.3 2.0.4 2.0.6 2.1.91 2.2.4 2.2.7 2.2.9 2.3.1 2.3.10 2.4.10 2.4.2 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.6.0 2.6.1 2.7.0 All 28 releases
← All changes | includes/class.execute.snippet.php +951 -1198 2.4.82.2.7 View file →
@@ -1,1198 +1,951 @@
1 -<?php
2 -/**
3 - * Execute snippet
4 - *
5 - * @author Artem Prihodko <webtemyk@yandex.ru>
6 - * @copyright (c) 2020, CreativeMotion
7 - * @version 2.4
8 - */
9 -
10 -// Exit if accessed directly
11 -if ( ! defined( 'ABSPATH' ) ) {
12 - exit;
13 -}
14 -
15 -class WINP_Execute_Snippet {
16 -
17 - /**
18 - * @var self
19 - */
20 - private static $instance;
21 -
22 - /**
23 - * @var array
24 - */
25 - public $snippets;
26 -
27 - /**
28 - * @var WINP_Insertion_Locations
29 - */
30 - public $snippets_locations;
31 -
32 - public static function app() {
33 - if ( self::$instance === null ) {
34 - self::$instance = new self();
35 - }
36 -
37 - return self::$instance;
38 - }
39 -
40 - /**
41 - * WINP_Execute_Snippet constructor.
42 - */
43 - public function __construct() {
44 - self::$instance = $this;
45 -
46 - if ( ! defined( 'WINP_UPLOAD_DIR' ) ) {
47 - $dir = wp_upload_dir();
48 - define( 'WINP_UPLOAD_DIR', $dir['basedir'] . '/winp-css-js' );
49 - }
50 -
51 - if ( ! defined( 'WINP_UPLOAD_URL' ) ) {
52 - $dir = wp_upload_dir();
53 - define( 'WINP_UPLOAD_URL', $dir['baseurl'] . '/winp-css-js' );
54 - }
55 - global $wpdb;
56 -
57 - $sql = "SELECT {$wpdb->posts}.ID, {$wpdb->posts}.post_content, p2.meta_value as priority
58 - FROM {$wpdb->posts}
59 - INNER JOIN {$wpdb->postmeta} p1 ON ({$wpdb->posts}.ID = p1.post_id)
60 - INNER JOIN {$wpdb->postmeta} p2 ON ({$wpdb->posts}.ID = p2.post_id)
61 - INNER JOIN {$wpdb->postmeta} p3 ON ({$wpdb->posts}.ID = p3.post_id)
62 - WHERE (( p1.meta_key = '" . WINP_Plugin::app()->getPrefix() . "snippet_scope' AND p1.meta_value = '%s')
63 - AND
64 - ( p3.meta_key = '" . WINP_Plugin::app()->getPrefix() . "snippet_activate' AND p3.meta_value = '1')
65 - AND p2.meta_key = '" . WINP_Plugin::app()->getPrefix() . "snippet_priority' )
66 - AND {$wpdb->posts}.post_type = '" . WINP_SNIPPETS_POST_TYPE . "'
67 - AND ({$wpdb->posts}.post_status = 'publish')
68 - ORDER BY CAST(priority AS UNSIGNED) %s";
69 -
70 - $this->snippets['evrywhere'] = $wpdb->get_results( sprintf( $sql, 'evrywhere', 'DESC' ) );
71 - $this->snippets['auto'] = $wpdb->get_results( sprintf( $sql, 'auto', 'ASC' ) );
72 -
73 - global $winp_snippets_locations;
74 - $this->snippets_locations = new WINP_Insertion_Locations();
75 - }
76 -
77 - /**
78 - * Register hooks
79 - */
80 - public function registerHooks() {
81 - add_action( 'plugins_loaded', [ $this, 'executeEverywhereSnippets' ], 1 );
82 -
83 - if ( ! is_admin() ) { #issue PCS-45 fix bug with WPBPage Builder Frontend Editor
84 - add_action( 'wp_head', [ $this, 'executeHeaderSnippets' ] );
85 - add_action( 'wp_footer', [ $this, 'executeFooterSnippets' ] );
86 - add_action( 'the_post', [ $this, 'executePostSnippets' ], 10, 2 );
87 - add_filter( 'the_content', [ $this, 'executeContentSnippets' ] );
88 - add_filter( 'the_excerpt', [ $this, 'executeExcerptSnippets' ] );
89 - // Бесполезный хук, который вызывается на каждый комментарий. Если их много, увеличивается нагрузка
90 - //add_filter( 'wp_list_comments_args', [ $this, 'executeListCommentsSnippets' ] );
91 -
92 - //add_action( 'wp_head', [ $this, 'executeWoocommerceSnippets' ] );
93 -
94 - if ( ! empty( $this->snippets_locations->getInsertion( 'custom' ) ) ) {
95 - add_action( 'wp_head', [ $this, 'executeCustomSnippets' ] );
96 - }
97 - }
98 - }
99 -
100 - /**
101 - * Execute the everywhere snippets once the plugins are loaded
102 - */
103 - public function executeEverywhereSnippets() {
104 - echo $this->executeActiveSnippets( 'evrywhere' );
105 - }
106 -
107 - /**
108 - * Execute the snippets in header of page once the plugins are loaded
109 - */
110 - public function executeHeaderSnippets() {
111 - echo $this->executeActiveSnippets( 'auto', 'header' );
112 - }
113 -
114 - /**
115 - * Execute the snippets in footer of page once the plugins are loaded
116 - */
117 - public function executeFooterSnippets() {
118 - echo $this->executeActiveSnippets( 'auto', 'footer' );
119 - }
120 -
121 - /**
122 - * Execute the snippets before post
123 - *
124 - * @param WP_Post $post
125 - * @param WP_Query $query
126 - */
127 - public function executePostSnippets( $post, $query ) {
128 - $content = '';
129 -
130 - $post_type = ! empty( $post ) ? $post->post_type : get_post( $post->ID )->post_type;
131 - if ( is_singular( [ $post_type ] ) ) {
132 - if ( did_action( 'get_header' ) ) {
133 - // Перед заголовком
134 - $content = $this->executeActiveSnippets( 'auto', 'before_post' );
135 - }
136 - } else {
137 - if ( $query->post_count > 0 ) {
138 - if ( $query->post_count > 1 && $query->current_post > 0 && $query->post_count > $query->current_post ) {
139 - // Между записями
140 - $content = $this->executeActiveSnippets( 'auto', 'between_posts' );
141 - }
142 - // Перед записью
143 - $content .= $this->executeActiveSnippets( 'auto', 'before_posts', '', $query );
144 -
145 - // После записи
146 - $content .= $this->executeActiveSnippets( 'auto', 'after_posts', '', $query );
147 - }
148 - }
149 -
150 - echo $content;
151 - }
152 -
153 - /**
154 - * Handle paragraph content
155 - *
156 - * @param $content
157 - * @param $snippet_content
158 - * @param $paragraph_number
159 - * @param $type
160 - *
161 - * @return mixed
162 - */
163 - private function handleParagraphContent( $content, $snippet_content, $paragraph_number, $type = 'before' ) {
164 - if ( 'before' == $type ) {
165 - preg_match_all( '/<p(.*?)>/', $content, $matches );
166 - } else {
167 - preg_match_all( '/<\/p>/', $content, $matches );
168 - }
169 - $paragraphs = $matches[0];
170 -
171 - if ( $paragraph_number == 0 ) {
172 - $paragraph_number = 1;
173 - }
174 -
175 - if ( $content && $snippet_content && $paragraphs && $paragraph_number <= count( $paragraphs ) ) {
176 - $offset = 0;
177 - foreach ( $paragraphs as $paragraph_key => $paragraph ) {
178 - $position = strpos( $content, $paragraph, $offset ); // Позиция тега параграфа
179 - // Если указанный номер параграфа совпадает с текущим
180 - if ( $paragraph_key + 1 == $paragraph_number ) {
181 - if ( 'before' == $type ) {
182 - $content = substr( $content, 0, $position ) . $snippet_content . substr( $content, $position );
183 - } else {
184 - $content = substr( $content, 0, $position + 4 ) . $snippet_content . substr( $content, $position + 4 );
185 - }
186 - break;
187 - } else {
188 - $offset = $position + 1;
189 - }
190 - }
191 - }
192 -
193 - return $content;
194 - }
195 -
196 - /**
197 - * Handle posts content
198 - *
199 - * @param string $content
200 - * @param string $snippet_content
201 - * @param integer $post_number
202 - * @param string $type
203 - * @param object $query
204 - *
205 - * @return mixed
206 - */
207 - private function handlePostsContent( $content, $snippet_content, $post_number, $type, $query ) {
208 - global $winp_after_post_content;
209 - if ( $query->post_count > 0 ) {
210 - if ( $post_number == 0 ) {
211 - $post_number = 1;
212 - }
213 -
214 - if ( 'before' == $type && $query->current_post + 1 == $post_number ) {
215 - return $snippet_content;
216 - } elseif ( 'after' == $type ) {
217 - // Номер поста совпадает
218 - if ( $query->current_post == $post_number ) {
219 - return $snippet_content;
220 - // Если это последний пост и указанный номер поста больше общего количества постов,
221 - // то нужно сохранить контент сниппета для вывода в конце данного поста
222 - } elseif ( $query->current_post + 1 == $query->post_count && $post_number >= $query->post_count ) {
223 - $winp_after_post_content[ $query->post->ID ] = $snippet_content;
224 - }
225 - }
226 - }
227 -
228 - return $content;
229 - }
230 -
231 - /**
232 - * Execute the snippets page content
233 - *
234 - * @param $content
235 - *
236 - * @return mixed
237 - */
238 - public function executeContentSnippets( $content ) {
239 - global $post, $winp_after_post_content;
240 -
241 - $post_type = ! empty( $post ) ? $post->post_type : false;
242 -
243 - if ( is_category() || is_archive() || is_tag() || is_tax() || is_search() ) {
244 - // Перед коротким описанием
245 - $content = $this->executeActiveSnippets( 'auto', 'before_excerpt' ) . $content;
246 -
247 - // После короткого описания
248 - $content .= $this->executeActiveSnippets( 'auto', 'after_excerpt' );
249 - }
250 -
251 - if ( is_singular( [ $post_type ] ) ) {
252 - // Перед параграфом
253 - $content = $this->executeActiveSnippets( 'auto', 'before_paragraph', $content );
254 -
255 - // После параграфа
256 - $content = $this->executeActiveSnippets( 'auto', 'after_paragraph', $content );
257 -
258 - // После заголовка
259 - $content = $this->executeActiveSnippets( 'auto', 'before_content' ) . $content;
260 -
261 - // После текста
262 - $content .= $this->executeActiveSnippets( 'auto', 'after_content' );
263 -
264 - // После поста
265 - $content .= $this->executeActiveSnippets( 'auto', 'after_post' );
266 -
267 - if ( ! comments_open( $post->ID ) && ! get_comments_number( $post->ID ) ) {
268 - remove_filter( 'wp_list_comments_args', [ $this, 'executeListCommentsSnippets' ] );
269 - }
270 - } elseif ( ! is_null( $post ) && isset( $winp_after_post_content[ $post->ID ] ) ) {
271 - // После последнего поста в списке
272 - $content .= $winp_after_post_content[ $post->ID ];
273 - unset( $winp_after_post_content[ $post->ID ] );
274 - }
275 -
276 - return $content;
277 - }
278 -
279 - /**
280 - * Execute the snippets page excerpt
281 - *
282 - * @param $excerpt
283 - *
284 - * @return mixed
285 - */
286 - public function executeExcerptSnippets( $excerpt ) {
287 - if ( is_category() || is_archive() || is_tag() || is_tax() || is_search() ) {
288 - // Перед коротким описанием
289 - $excerpt = $this->executeActiveSnippets( 'auto', 'before_excerpt' ) . $excerpt;
290 -
291 - // После короткого описания
292 - $excerpt .= $this->executeActiveSnippets( 'auto', 'after_excerpt' );
293 - }
294 -
295 - return $excerpt;
296 - }
297 -
298 - /**
299 - * Execute the list comments filter
300 - *
301 - * @param $args
302 - *
303 - * @return mixed
304 - */
305 - public function executeListCommentsSnippets( $args ) {
306 - global $winp_wp_data;
307 -
308 - $winp_wp_data['winp_comments_saved_end_callback'] = $args['end-callback'];
309 - $args['end-callback'] = [ $this, 'executeCommentsSnippets' ];
310 -
311 - return $args;
312 - }
313 -
314 - /**
315 - * Execute the snippets after page comments
316 - *
317 - * @param $comment
318 - * @param $args
319 - * @param $depth
320 - */
321 - public function executeCommentsSnippets( $comment, $args, $depth ) {
322 - global $winp_wp_data, $post;
323 -
324 - if ( ! empty( $winp_wp_data['winp_comments_saved_end_callback'] ) ) {
325 - echo call_user_func( $winp_wp_data['winp_comments_saved_end_callback'], $comment, $args, $depth );
326 - }
327 -
328 - $content = '';
329 -
330 - $post_type = ! empty( $post ) ? $post->post_type : false;
331 - if ( is_singular( [ $post_type ] ) ) {
332 - // После комментариев
333 - $content = $this->executeActiveSnippets( 'auto', 'after_post' );
334 - }
335 -
336 - echo $content;
337 - }
338 -
339 - /**
340 - * Execute the custom snippets
341 - *
342 - * @since 2.4
343 - */
344 - public function executeCustomSnippets() {
345 - $locations = $this->snippets_locations->getInsertion( 'custom' );
346 - foreach ( $locations as $location => $data ) {
347 - $this->executeActiveSnippets( 'auto', $location );
348 - }
349 - }
350 -
351 - /**
352 - * Execute Woocommerce actions/hooks
353 - *
354 - * @param $location
355 - * @param $snippet_content
356 - *
357 - * @since 2.4
358 - */
359 - public function woocommerce_actions( $location, $snippet_content = '' ) {
360 - $action = function () use ( $location, $snippet_content ) {
361 - echo $snippet_content;
362 - };
363 -
364 - switch ( $location ) {
365 - case 'woo_before_shop_loop':
366 - add_filter( 'woocommerce_product_loop_start', function ( $content ) use ( $snippet_content ) {
367 - return $snippet_content . $content;
368 - } );
369 - break;
370 - case 'woo_after_shop_loop':
371 - add_filter( 'woocommerce_product_loop_end', function ( $content ) use ( $snippet_content ) {
372 - return $content . $snippet_content;
373 - } );
374 - break;
375 - case 'woo_before_single_product':
376 - add_action( 'woocommerce_before_single_product', $action, 10, 2 );
377 - break;
378 - case 'woo_after_single_product':
379 - add_action( 'woocommerce_after_single_product', $action, 10, 2 );
380 - break;
381 - case 'woo_before_single_product_summary':
382 - add_action( 'woocommerce_before_single_product_summary', $action, 10, 2 );
383 - break;
384 - case 'woo_after_single_product_summary':
385 - add_action( 'woocommerce_after_single_product_summary', $action, 10, 2 );
386 - break;
387 - case 'woo_single_product_summary_title':
388 - add_action( 'woocommerce_single_product_summary', $action, 6, 2 );
389 - break;
390 - case 'woo_single_product_summary_price':
391 - add_action( 'woocommerce_single_product_summary', $action, 15, 2 );
392 - break;
393 - case 'woo_single_product_summary_excerpt':
394 - add_action( 'woocommerce_single_product_summary', $action, 25, 2 );
395 - break;
396 - default:
397 - break;
398 - }
399 - }
400 -
401 - /**
402 - * Execute Woocommerce actions/hooks
403 - *
404 - * @param $location
405 - * @param $snippet_content
406 - *
407 - * @since 2.4
408 - */
409 - public function custom_actions( $location, $snippet_content = '' ) {
410 - if ( ! empty( $this->snippets_locations->getLocation( $location ) ) ) {
411 - /**
412 - * Action for a custom location applied in 'wbcr/woody/add_custom_location' filter
413 - *
414 - * @param array $location Slug of the location.
415 - * @param string $snippet_content Rendered snippet content
416 - *
417 - * @since 2.4
418 - */
419 - do_action( "wbcr/woody/do_custom_location/{$location}", $snippet_content );
420 - }
421 - }
422 -
423 - /**
424 - * Execute the snippets once the plugins are loaded
425 - *
426 - * @param string $scope
427 - * @param string $location
428 - * @param string $content
429 - * @param array $custom_params
430 - *
431 - * @return string
432 - */
433 - public function executeActiveSnippets( $scope = 'evrywhere', $location = '', $content = '', $custom_params = [] ) {
434 - /*
435 - global $wpdb;
436 -
437 - if ( $scope == 'evrywhere' ) {
438 - $sort = 'DESC';
439 - } else {
440 - $sort = 'ASC';
441 - }
442 - $snippets = $wpdb->get_results( "SELECT {$wpdb->posts}.ID, {$wpdb->posts}.post_content, p2.meta_value as priority
443 - FROM {$wpdb->posts}
444 - INNER JOIN {$wpdb->postmeta} p1 ON ({$wpdb->posts}.ID = p1.post_id)
445 - INNER JOIN {$wpdb->postmeta} p2 ON ({$wpdb->posts}.ID = p2.post_id)
446 - INNER JOIN {$wpdb->postmeta} p3 ON ({$wpdb->posts}.ID = p3.post_id)
447 - WHERE (( p1.meta_key = '" . WINP_Plugin::app()->getPrefix() . "snippet_scope' AND p1.meta_value = '{$scope}')
448 - AND
449 - ( p3.meta_key = '" . WINP_Plugin::app()->getPrefix() . "snippet_activate' AND p3.meta_value = '1')
450 - AND p2.meta_key = '" . WINP_Plugin::app()->getPrefix() . "snippet_priority' )
451 - AND {$wpdb->posts}.post_type = '" . WINP_SNIPPETS_POST_TYPE . "'
452 - AND ({$wpdb->posts}.post_status = 'publish')
453 - ORDER BY CAST(priority AS UNSIGNED) {$sort}" );
454 - */
455 - $snippets = $this->snippets[ $scope ] ?? [];
456 -
457 - if ( empty( $snippets ) ) {
458 - return $content;
459 - }
460 -
461 - foreach ( (array) $snippets as $snippet ) {
462 - $id = (int) $snippet->ID;
463 - //$is_active = (int) WINP_Helper::getMetaOption( $id, 'snippet_activate', 0 );
464 - // Если это сниппет с автовставкой и выбранное место подходит под активный action
465 - $avail_place = ( 'auto' == $scope ? $location == WINP_Helper::getMetaOption( $id, 'snippet_location', '' ) : true );
466 - // Если условие отображения сниппета выполняется
467 - $snippet_type = WINP_Helper::getMetaOption( $id, 'snippet_type', WINP_SNIPPET_TYPE_PHP );
468 - $is_condition = $snippet_type != WINP_SNIPPET_TYPE_PHP ? $this->checkCondition( $id ) : true;
469 -
470 - if ( $avail_place && $is_condition ) {
471 - $post_id = (int) WINP_Plugin::app()->request->post( 'post_ID', 0 );
472 -
473 - if ( isset( $_POST['wbcr_inp_snippet_scope'] ) && $post_id === $id && WINP_Plugin::app()->currentUserCan() ) {
474 - return $content;
475 - }
476 -
477 - if ( WINP_Helper::is_safe_mode() ) {
478 - return $content;
479 - }
480 -
481 - // WPML Compatibility
482 - if ( defined( 'WPML_PLUGIN_FILE' ) ) {
483 - $wpml_langs = WINP_Helper::getMetaOption( $id, 'snippet_wpml_lang', '' );
484 - if ( $wpml_langs !== '' && defined( 'ICL_LANGUAGE_CODE' ) ) {
485 - if ( ! in_array( ICL_LANGUAGE_CODE, explode( ',', $wpml_langs ) ) ) {
486 - continue;
487 - }
488 - }
489 - }
490 -
491 - $snippet_code = WINP_Helper::get_snippet_code( $snippet );
492 -
493 - /**
494 - * Filter snippet code before execute
495 - */
496 - $snippet_code = apply_filters( 'wbcr/inp/execute_snippet/snippet_code', $snippet_code, $id );
497 -
498 - if ( WINP_Plugin::app()->getOption( 'execute_shortcode' ) ) {
499 - $snippet_code = do_shortcode( $snippet_code );
500 - }
501 -
502 - if ( $snippet_type === WINP_SNIPPET_TYPE_TEXT || $snippet_type === WINP_SNIPPET_TYPE_AD ) {
503 - $snippet_content = '<div class="winp-text-snippet-container">' . $snippet_code . '</div>';
504 - } elseif ( $snippet_type === WINP_SNIPPET_TYPE_CSS || $snippet_type === WINP_SNIPPET_TYPE_JS ) {
505 - $snippet_content = self::getJsCssSnippetData( $id );
506 - } elseif ( $snippet_type === WINP_SNIPPET_TYPE_HTML ) {
507 - $snippet_content = $snippet_code;
508 - } else {
509 - $code = $this->prepareCode( $snippet_code, $id );
510 - ob_start();
511 - $this->executeSnippet( $code, $id, false );
512 - $snippet_content = ob_get_contents();
513 - ob_end_clean();
514 - }
515 -
516 - if ( 'auto' == $scope ) {
517 - switch ( $location ) {
518 - case 'before_paragraph': // Перед параграфом
519 - $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
520 - $content = $this->handleParagraphContent( $content, $snippet_content, $location_number );
521 - break;
522 - case 'after_paragraph': // После параграфа
523 - $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
524 - $content = $this->handleParagraphContent( $content, $snippet_content, $location_number, 'after' );
525 - break;
526 - case 'before_posts': // Перед записью
527 - $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
528 - $content = $this->handlePostsContent( $content, $snippet_content, $location_number, 'before', $custom_params );
529 - break;
530 - case 'after_posts': // После записи
531 - $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
532 - $content = $this->handlePostsContent( $content, $snippet_content, $location_number, 'after', $custom_params );
533 - break;
534 - default:
535 - $content = $snippet_content . $content;
536 - }
537 -
538 - /**
539 - * Action for woo actions
540 - *
541 - * @param array $location Slug of the location.
542 - * @param string $snippet_content Rendered snippet content
543 - *
544 - * @since 2.4
545 - */
546 - do_action( 'wbcr/woody/do_woocommerce_actions', $location, $snippet_content );
547 -
548 - //$this->woocommerce_actions( $location, $snippet_content );
549 - $this->custom_actions( $location, $snippet_content );
550 - } else {
551 - $content = $snippet_content . $content;
552 - }
553 - }
554 - }
555 -
556 - return $content;
557 - }
558 -
559 - /**
560 - * Get js or css snippet data
561 - *
562 - * @param $snippet_id
563 - *
564 - * @return mixed|string
565 - */
566 - public static function getJsCssSnippetData( $snippet_id ) {
567 - $snippet_type = WINP_Helper::get_snippet_type( $snippet_id );
568 -
569 - $linking = WINP_Helper::getMetaOption( $snippet_id, 'snippet_linking' );
570 - $filetype = WINP_Helper::getMetaOption( $snippet_id, 'filetype', $snippet_type );
571 -
572 - $file_name = $snippet_id . '.' . $filetype;
573 - $slug = WINP_Helper::getMetaOption( $snippet_id, 'css_js_slug' );
574 - if ( ! empty( $slug ) ) {
575 - $file_name = $slug . '.' . $filetype;
576 - }
577 -
578 - if ( file_exists( WINP_UPLOAD_DIR . '/' . $file_name ) ) {
579 - if ( 'inline' == $linking ) {
580 - return file_get_contents( WINP_UPLOAD_DIR . '/' . $file_name );
581 - }
582 -
583 - if ( 'external' == $linking ) {
584 - $file_name .= '?ver=' . WINP_Helper::getMetaOption( $snippet_id, 'css_js_version', time() );
585 -
586 - if ( 'js' == $snippet_type ) {
587 - return PHP_EOL . "<script type='text/javascript' src='" . WINP_UPLOAD_URL . '/' . $file_name . "'></script>" . PHP_EOL;
588 - }
589 -
590 - if ( 'css' == $snippet_type ) {
591 - $short_filename = preg_replace( '@\.css\?ver=.*$@', '', $file_name );
592 -
593 - return PHP_EOL . "<link rel='stylesheet' id='" . $short_filename . "-css' href='" . WINP_UPLOAD_URL . '/' . $file_name . "' type='text/css' media='all' />" . PHP_EOL;
594 - }
595 - }
596 - }
597 -
598 - return '';
599 - }
600 -
601 - /**
602 - * Execute a snippet
603 - *
604 - * Code must NOT be escaped, as
605 - * it will be executed directly
606 - *
607 - * @param string $code The snippet code to execute
608 - * @param int $id The snippet ID
609 - * @param bool $catch_output Whether to attempt to suppress the output of execution using buffers
610 - *
611 - * @return mixed The result of the code execution
612 - */
613 - public function executeSnippet( $code, $id = 0, $catch_output = true ) {
614 - $id = (int) $id;
615 -
616 - if ( ! $id || empty( $code ) ) {
617 - return false;
618 - }
619 -
620 - if ( $catch_output ) {
621 - ob_start();
622 - }
623 -
624 - $snippet = get_post( $id );
625 -
626 - if ( empty( $snippet ) || $snippet->post_type !== WINP_SNIPPETS_POST_TYPE ) {
627 - return false;
628 - }
629 -
630 - $snippet_type = WINP_Helper::getMetaOption( $id, 'snippet_type', true );
631 -
632 - if ( $snippet_type == WINP_SNIPPET_TYPE_UNIVERSAL ) {
633 - $result = eval( '?>' . $code . '<?php ' );
634 - } elseif ( $snippet_type == WINP_SNIPPET_TYPE_PHP ) {
635 - $result = eval( $code );
636 - } else {
637 - $result = ! empty( $code );
638 - }
639 -
640 - if ( $catch_output ) {
641 - ob_end_clean();
642 - }
643 -
644 - return $result;
645 - }
646 -
647 - /**
648 - * Get property value
649 - *
650 - * @param $value
651 - * @param $property
652 - *
653 - * @return null
654 - */
655 - private function getPropertyValue( $value, $property ) {
656 - if ( is_object( $value ) ) {
657 - return $value->$property ?? null;
658 - } elseif ( isset( $value[ $property ] ) ) {
659 - return $value[ $property ];
660 - }
661 -
662 - return null;
663 - }
664 -
665 - /**
666 - * Check conditional execution logic for the snippet
667 - *
668 - * @param $snippet_id
669 - *
670 - * @return bool
671 - */
672 - public function checkCondition( $snippet_id ) {
673 - // Итоговый результат условий
674 - $result = true;
675 - // Получаем сохранённые параметры условий
676 - $filters = get_post_meta( $snippet_id, WINP_Plugin::app()->getPrefix() . 'snippet_filters' );
677 - // Если условия указаны
678 - if ( ! ( empty( $filters ) || isset( $filters[0] ) && empty( $filters[0] ) ) ) {
679 - foreach ( $filters[0] as $filter ) {
680 - $conditions = $this->getPropertyValue( $filter, 'conditions' );
681 - // Если условия пусты, то пропускаем цикл
682 - if ( empty( $conditions ) ) {
683 - continue;
684 - }
685 - // Промежуточный результат AND условий
686 - $and_conditions = null;
687 - // Проходим по AND условиям
688 - foreach ( $conditions as $scope ) {
689 - $scope_conditions = $this->getPropertyValue( $scope, 'conditions' );
690 - // Если условия пусты, то пропускаем цикл
691 - if ( empty( $scope_conditions ) ) {
692 - continue;
693 - }
694 - // Промежуточный результат OR условий
695 - $or_conditions = null;
696 - // Проходим по OR условиям
697 - foreach ( $scope_conditions as $condition ) {
698 - $method_name = str_replace( '-', '_', $this->getPropertyValue( $condition, 'param' ) );
699 - $operator = $this->getPropertyValue( $condition, 'operator' );
700 - $value = $this->getPropertyValue( $condition, 'value' );
701 - // Получаем результат OR условий
702 - $or_conditions = is_null( $or_conditions ) ? $this->call_method( $method_name, $operator, $value ) : $or_conditions || $this->call_method( $method_name, $operator, $value );
703 - }
704 - // Получаем результат AND условий
705 - $and_conditions = is_null( $and_conditions ) ? $or_conditions : $and_conditions && $or_conditions;
706 - }
707 - // Получаем результат блока условий
708 - $result = $this->getPropertyValue( $filter, 'type' ) == 'showif' ? $and_conditions : ! $and_conditions;
709 - }
710 - }
711 -
712 - return $result;
713 - }
714 -
715 - /**
716 - * Call specified method
717 - *
718 - * @param $method_name
719 - * @param $operator
720 - * @param $value
721 - *
722 - * @return bool
723 - */
724 - private function call_method( $method_name, $operator, $value ) {
725 - if ( method_exists( $this, $method_name ) ) {
726 - return $this->$method_name( $operator, $value );
727 - } else {
728 - return apply_filters( 'wbcr/inp/execute/check_condition', false, $method_name, $operator, $value );
729 - }
730 - }
731 -
732 - /**
733 - * Retrieve the first error in a snippet's code
734 - *
735 - * @param int $snippet_id
736 - *
737 - * @return array|bool
738 - */
739 - public function getSnippetError( $snippet_id ) {
740 - if ( ! intval( $snippet_id ) ) {
741 - return false;
742 - }
743 -
744 - $snippet = get_post( $snippet_id );
745 -
746 - if ( ! $snippet ) {
747 - return false;
748 - }
749 -
750 - $snippet_code = WINP_Helper::get_snippet_code( $snippet );
751 - $snippet_code = $this->prepareCode( $snippet_code, $snippet_id );
752 -
753 - $result = $this->executeSnippet( $snippet_code, $snippet_id );
754 -
755 - if ( false !== $result ) {
756 - return false;
757 - }
758 -
759 - $error = error_get_last();
760 -
761 - if ( is_null( $error ) ) {
762 - return false;
763 - }
764 -
765 - return $error;
766 - }
767 -
768 - /**
769 - * Prepare the code by removing php tags from beginning and end
770 - *
771 - * @param string $code
772 - * @param integer $snippet_id
773 - *
774 - * @return string
775 - */
776 - public function prepareCode( $code, $snippet_id ) {
777 - $snippet_type = WINP_Helper::get_snippet_type( $snippet_id );
778 - if ( $snippet_type != WINP_SNIPPET_TYPE_UNIVERSAL && $snippet_type != WINP_SNIPPET_TYPE_CSS && $snippet_type != WINP_SNIPPET_TYPE_JS && $snippet_type != WINP_SNIPPET_TYPE_HTML ) {
779 - /* Remove <?php and <? from beginning of snippet */
780 - $code = preg_replace( '|^[\s]*<\?(php)?|', '', $code );
781 -
782 - /* Remove ?> from end of snippet */
783 - $code = preg_replace( '|\?>[\s]*$|', '', $code );
784 - }
785 -
786 - return $code;
787 - }
788 -
789 - /**
790 - * Get current URL
791 - *
792 - * @return string
793 - */
794 - private function getCurrentUrl() {
795 - $out = '';
796 - $url = explode( '?', $_SERVER['REQUEST_URI'], 2 );
797 - if ( isset( $url[0] ) ) {
798 - $out = trim( $url[0], '/' );
799 - }
800 -
801 - return $out ? urldecode( $out ) : '/';
802 - }
803 -
804 - /**
805 - * Get referer URL
806 - *
807 - * @return string
808 - */
809 - private function getRefererUrl() {
810 - $out = '';
811 - $url = explode( '?', str_replace( site_url(), '', $_SERVER['HTTP_REFERER'] ), 2 );
812 - if ( isset( $url[0] ) ) {
813 - $out = trim( $url[0], '/' );
814 - }
815 -
816 - return $out ? urldecode( $out ) : '/';
817 - }
818 -
819 - /**
820 - * Check by operator
821 - *
822 - * @param $operation
823 - * @param $first
824 - * @param $second
825 - * @param $third
826 - *
827 - * @return bool
828 - */
829 - public function checkByOperator( $operation, $first, $second, $third = false ) {
830 - switch ( $operation ) {
831 - case 'equals':
832 - if ( is_array( $second ) ) {
833 - return in_array( $first, $second );
834 - } else {
835 - return $first === $second;
836 - }
837 - case 'notequal':
838 - if ( is_array( $second ) ) {
839 - return ! in_array( $first, $second );
840 - } else {
841 - return $first !== $second;
842 - }
843 - case 'less':
844 - case 'older':
845 - return $first > $second;
846 - case 'greater':
847 - case 'younger':
848 - return $first < $second;
849 - case 'contains':
850 - return strpos( $first, $second ) !== false;
851 - case 'notcontain':
852 - return strpos( $first, $second ) === false;
853 - case 'between':
854 - return $first < $second && $second < $third;
855 -
856 - default:
857 - return $first === $second;
858 - }
859 - }
860 -
861 - /**
862 - * A role of the user who views your website. The role "guest" is applied for unregistered users.
863 - *
864 - * @param string $operator
865 - * @param string $value
866 - *
867 - * @return boolean
868 - */
869 - private function user_role( $operator, $value ) {
870 - if ( ! is_user_logged_in() ) {
871 - return $this->checkByOperator( $operator, $value, 'guest' );
872 - } else {
873 - $current_user = wp_get_current_user();
874 - if ( ! ( $current_user instanceof WP_User ) ) {
875 - return false;
876 - }
877 -
878 - return $this->checkByOperator( $operator, $value, $current_user->roles[0] );
879 - }
880 - }
881 -
882 - /**
883 - * Get timestamp
884 - *
885 - * @param $units
886 - * @param $count
887 - *
888 - * @return integer
889 - */
890 - private function getTimestamp( $units, $count ) {
891 - switch ( $units ) {
892 - case 'seconds':
893 - return $count;
894 - case 'minutes':
895 - return $count * MINUTE_IN_SECONDS;
896 - case 'hours':
897 - return $count * HOUR_IN_SECONDS;
898 - case 'days':
899 - return $count * DAY_IN_SECONDS;
900 - case 'weeks':
901 - return $count * WEEK_IN_SECONDS;
902 - case 'months':
903 - return $count * MONTH_IN_SECONDS;
904 - case 'years':
905 - return $count * YEAR_IN_SECONDS;
906 -
907 - default:
908 - return $count;
909 - }
910 - }
911 -
912 - /**
913 - * Get date timestamp
914 - *
915 - * @param $value
916 - *
917 - * @return integer
918 - */
919 - public function getDateTimestamp( $value ) {
920 - if ( is_object( $value ) ) {
921 - return ( current_time( 'timestamp' ) - $this->getTimestamp( $value->units, $value->unitsCount ) ) * 1000;
922 - } else {
923 - return $value;
924 - }
925 - }
926 -
927 - /**
928 - * The date when the user who views your website was registered.
929 - * For unregistered users this date always equals to 1 Jan 1970.
930 - *
931 - * @param string $operator
932 - * @param string $value
933 - *
934 - * @return boolean
935 - */
936 - private function user_registered( $operator, $value ) {
937 - if ( ! is_user_logged_in() ) {
938 - return false;
939 - } else {
940 - $user = wp_get_current_user();
941 - $registered = strtotime( $user->data->user_registered ) * 1000;
942 -
943 - if ( $operator == 'equals' || $operator == 'notequal' ) {
944 - $registered = $registered / 1000;
945 - $timestamp = round( $this->getDateTimestamp( $value ) / 1000 );
946 -
947 - return $this->checkByOperator( $operator, date( 'Y-m-d', $timestamp ), date( 'Y-m-d', $registered ) );
948 - } elseif ( $operator == 'between' ) {
949 - $start_timestamp = $this->getDateTimestamp( $value->start );
950 - $end_timestamp = $this->getDateTimestamp( $value->end );
951 -
952 - return $this->checkByOperator( $operator, $start_timestamp, $registered, $end_timestamp );
953 - } else {
954 - $timestamp = $this->getDateTimestamp( $value );
955 -
956 - return $this->checkByOperator( $operator, $timestamp, $registered );
957 - }
958 - }
959 - }
960 -
961 - /**
962 - * Check the user views your website from mobile device or not
963 - *
964 - * @param string $operator
965 - * @param string $value
966 - *
967 - * @return boolean
968 - *
969 - * @link https://stackoverflow.com/a/4117597
970 - */
971 - private function user_mobile( $operator, $value ) {
972 - $useragent = $_SERVER['HTTP_USER_AGENT'];
973 -
974 - if ( preg_match( '/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $useragent ) || preg_match( '/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr( $useragent, 0, 4 ) ) ) {
975 - return $operator === 'equals' && $value === 'yes' || $operator === 'notequal' && $value === 'no';
976 - } else {
977 - return $operator === 'notequal' && $value === 'yes' || $operator === 'equals' && $value === 'no';
978 - }
979 - }
980 -
981 - /**
982 - * Determines whether the user's browser has a cookie with a given name
983 - *
984 - * @param $operator
985 - * @param $value
986 - *
987 - * @return boolean
988 - */
989 - private function user_cookie_name( $operator, $value ) {
990 - if ( isset( $_COOKIE[ $value ] ) ) {
991 - return $operator === 'equals';
992 - } else {
993 - return $operator === 'notequal';
994 - }
995 - }
996 -
997 - /**
998 - * A some selected page
999 - *
1000 - * @param $operator
1001 - * @param $value
1002 - *
1003 - * @return boolean
1004 - */
1005 - private function location_some_page( $operator, $value ) {
1006 - $post_id = ( ! is_404() && ! is_search() && ! is_archive() && ! is_home() ) ? get_the_ID() : false;
1007 -
1008 - switch ( $value ) {
1009 - case 'base_web': // Basic - Entire Website
1010 - $result = true;
1011 - break;
1012 - case 'base_sing': // Basic - All Singulars
1013 - $result = is_singular();
1014 - break;
1015 - case 'base_arch': // Basic - All Archives
1016 - $result = is_archive();
1017 - break;
1018 - case 'spec_404': // Special Pages - 404 Page
1019 - $result = is_404();
1020 - break;
1021 - case 'spec_search': // Special Pages - Search Page
1022 - $result = is_search();
1023 - break;
1024 - case 'spec_blog': // Special Pages - Blog / Posts Page
1025 - $result = is_home();
1026 - break;
1027 - case 'spec_front': // Special Pages - Front Page
1028 - $result = is_front_page();
1029 - break;
1030 - case 'spec_date': // Special Pages - Date Archive
1031 - $result = is_date();
1032 - break;
1033 - case 'spec_auth': // Special Pages - Author Archive
1034 - $result = is_author();
1035 - break;
1036 - case 'post_all': // Posts - All Posts
1037 - case 'page_all': // Pages - All Pages
1038 - $result = false;
1039 - if ( false !== $post_id ) {
1040 - $post_type = 'post_all' == $value ? 'post' : 'page';
1041 - $result = $post_type == get_post_type( $post_id );
1042 - }
1043 - break;
1044 - case 'post_arch': // Posts - All Posts Archive
1045 - case 'page_arch': // Pages - All Pages Archive
1046 - $result = false;
1047 - if ( is_archive() ) {
1048 - $post_type = 'post_arch' == $value ? 'post' : 'page';
1049 - $result = $post_type == get_post_type();
1050 - }
1051 - break;
1052 - case 'post_cat': // Posts - All Categories Archive
1053 - case 'post_tag': // Posts - All Tags Archive
1054 - $result = false;
1055 - if ( is_archive() && 'post' == get_post_type() ) {
1056 - $taxonomy = 'post_tag' == $value ? 'post_tag' : 'category';
1057 - $obj = get_queried_object();
1058 -
1059 - $current_taxonomy = '';
1060 - if ( '' !== $obj && null !== $obj ) {
1061 - $current_taxonomy = $obj->taxonomy;
1062 - }
1063 -
1064 - if ( $current_taxonomy == $taxonomy ) {
1065 - $result = true;
1066 - }
1067 - }
1068 - break;
1069 -
1070 - default:
1071 - $result = false;
1072 - }
1073 -
1074 - if ( WINP_Helper::is_woo_active() ) {
1075 - switch ( $value ) {
1076 - case 'woo_product':
1077 - $result = is_product();
1078 - break;
1079 - case 'woo_arch':
1080 - $result = is_shop();
1081 - break;
1082 - case 'woo_cart':
1083 - $result = is_cart();
1084 - break;
1085 - case 'woo_checkout':
1086 - $result = is_checkout();
1087 - break;
1088 - case 'woo_checkout_pay':
1089 - $result = is_checkout_pay_page();
1090 - break;
1091 - case 'woo_cat':
1092 - $result = is_product_category();
1093 - break;
1094 - case 'woo_tag':
1095 - $result = is_product_tag();
1096 - break;
1097 - }
1098 - }
1099 -
1100 - return $this->checkByOperator( $operator, $result, true );
1101 - }
1102 -
1103 - /**
1104 - * An URL of the current page where a user who views your website is located
1105 - *
1106 - * @param $operator
1107 - * @param $value
1108 - *
1109 - * @return boolean
1110 - */
1111 - private function location_page( $operator, $value ) {
1112 - $url = $this->getCurrentUrl();
1113 -
1114 - return $url ? $this->checkByOperator( $operator, trim( $url, '/' ), trim( $value, '/' ) ) : false;
1115 - }
1116 -
1117 - /**
1118 - * A referrer URL which has brought a user to the current page
1119 - *
1120 - * @param $operator
1121 - * @param $value
1122 - *
1123 - * @return boolean
1124 - */
1125 - private function location_referrer( $operator, $value ) {
1126 - $url = $this->getRefererUrl();
1127 -
1128 - return $url ? $this->checkByOperator( $operator, trim( $url, '/' ), trim( $value, '/' ) ) : false;
1129 - }
1130 -
1131 - /**
1132 - * A post type of the current page
1133 - *
1134 - * @param $operator
1135 - * @param $value
1136 - *
1137 - * @return boolean
1138 - */
1139 - private function location_post_type( $operator, $value ) {
1140 - if ( is_singular() ) {
1141 - return $this->checkByOperator( $operator, $value, get_post_type() );
1142 - }
1143 -
1144 - return false;
1145 - }
1146 -
1147 - /**
1148 - * A taxonomy page
1149 - *
1150 - * @param $operator
1151 - * @param $value
1152 - *
1153 - * @return boolean
1154 - * @since 2.2.8 The bug is fixed, the condition was not checked
1155 - * for tachonomies, only posts.
1156 - */
1157 - private function location_taxonomy( $operator, $value ) {
1158 - $term_id = null;
1159 -
1160 - if ( is_tax() || is_tag() || is_category() ) {
1161 - $term_id = get_queried_object()->term_id;
1162 -
1163 - if ( $term_id ) {
1164 - return $this->checkByOperator( $operator, intval( $value ), $term_id );
1165 - }
1166 - }
1167 -
1168 - return false;
1169 - }
1170 -
1171 - /**
1172 - * A taxonomy of the current page
1173 - *
1174 - * @param $operator
1175 - * @param $value
1176 - *
1177 - * @return boolean
1178 - * @since 2.4.0
1179 - */
1180 - private function page_taxonomy( $operator, $value ) {
1181 - $term_id = null;
1182 -
1183 - if ( is_singular() ) {
1184 - $post_cat = get_the_category( get_the_ID() );
1185 - if ( is_array( $post_cat ) ) {
1186 - foreach ( $post_cat as $item ) {
1187 - $term_id[] = $item->term_id;
1188 - }
1189 - }
1190 - }
1191 -
1192 - if ( $term_id ) {
1193 - return $this->checkByOperator( $operator, intval( $value ), $term_id );
1194 - }
1195 -
1196 - return false;
1197 - }
1198 -}
1 +<?php
2 +/**
3 + * Execute snippet
4 + *
5 + * @author Webcraftic <wordpress.webraftic@gmail.com>
6 + * @copyright (c) 16.11.2018, Webcraftic
7 + * @version 1.0
8 + */
9 +
10 +// Exit if accessed directly
11 +if ( ! defined( 'ABSPATH' ) ) {
12 + exit;
13 +}
14 +
15 +class WINP_Execute_Snippet {
16 +
17 + /**
18 + * WINP_Execute_Snippet constructor.
19 + */
20 + public function __construct() {
21 + if ( ! defined( 'WINP_UPLOAD_DIR' ) ) {
22 + $dir = wp_upload_dir();
23 + define( 'WINP_UPLOAD_DIR', $dir['basedir'] . '/winp-css-js' );
24 + }
25 +
26 + if ( ! defined( 'WINP_UPLOAD_URL' ) ) {
27 + $dir = wp_upload_dir();
28 + define( 'WINP_UPLOAD_URL', $dir['baseurl'] . '/winp-css-js' );
29 + }
30 + }
31 +
32 + /**
33 + * Register hooks
34 + */
35 + public function registerHooks() {
36 + add_action( 'plugins_loaded', [ $this, 'executeEverywhereSnippets' ], 1 );
37 +
38 + if ( ! is_admin() ) { #issue PCS-45 fix bug with WPBPage Builder Frontend Editor
39 + add_action( 'wp_head', [ $this, 'executeHeaderSnippets' ] );
40 + add_action( 'wp_footer', [ $this, 'executeFooterSnippets' ] );
41 + add_filter( 'the_post', [ $this, 'executePostSnippets' ], 10, 2 );
42 + add_filter( 'the_content', [ $this, 'executeContentSnippets' ] );
43 + add_filter( 'the_excerpt', [ $this, 'executeExcerptSnippets' ] );
44 + add_filter( 'wp_list_comments_args', [ $this, 'executeListCommentsSnippets' ] );
45 + }
46 + }
47 +
48 + /**
49 + * Execute the evrywhere snippets once the plugins are loaded
50 + */
51 + public function executeEverywhereSnippets() {
52 + echo $this->executeActiveSnippets( 'evrywhere' );
53 + }
54 +
55 + /**
56 + * Execute the snippets in header of page once the plugins are loaded
57 + */
58 + public function executeHeaderSnippets() {
59 + echo $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_HEADER );
60 + }
61 +
62 + /**
63 + * Execute the snippets in footer of page once the plugins are loaded
64 + */
65 + public function executeFooterSnippets() {
66 + echo $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_FOOTER );
67 + }
68 +
69 + /**
70 + * Execute the snippets before post
71 + *
72 + * @param $data
73 + * @param $query
74 + */
75 + public function executePostSnippets( $data, $query ) {
76 + global $post;
77 +
78 + $content = '';
79 +
80 + $post_type = ! empty( $post ) ? $post->post_type : get_post( $data->ID )->post_type;
81 + if ( is_singular( [ $post_type ] ) && $post->ID == $data->ID ) {
82 + if ( did_action( 'get_header' ) ) {
83 + // Перед заголовком
84 + $content = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_BEFORE_POST );
85 + }
86 + } else {
87 + if ( $query->post_count > 0 ) {
88 + if ( $query->post_count > 1 && $query->current_post > 0 && $query->post_count > $query->current_post ) {
89 + // Между записями
90 + $content = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_BETWEEN_POSTS );
91 + }
92 + // Перед записью
93 + $content .= $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_BEFORE_POSTS, '', $query );
94 +
95 + // После записи
96 + $content .= $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_AFTER_POSTS, '', $query );
97 + }
98 + }
99 +
100 + echo $content;
101 + }
102 +
103 + /**
104 + * Handle paragraph content
105 + *
106 + * @param $content
107 + * @param $snippet_content
108 + * @param $paragraph_number
109 + * @param $type
110 + *
111 + * @return mixed
112 + */
113 + private function handleParagraphContent( $content, $snippet_content, $paragraph_number, $type = 'before' ) {
114 + if ( 'before' == $type ) {
115 + preg_match_all( "/<p(.*?)>/", $content, $matches );
116 + } else {
117 + preg_match_all( "/<\/p>/", $content, $matches );
118 + }
119 + $paragraphs = $matches[0];
120 +
121 + if ( $paragraph_number == 0 ) {
122 + $paragraph_number = 1;
123 + }
124 +
125 + if ( $content && $snippet_content && $paragraphs && $paragraph_number <= count( $paragraphs ) ) {
126 + $offset = 0;
127 + foreach ( $paragraphs as $paragraph_key => $paragraph ) {
128 + $position = strpos( $content, $paragraph, $offset ); // Позиция тега параграфа
129 + // Если указанный номер параграфа совпадает с текущим
130 + if ( $paragraph_key + 1 == $paragraph_number ) {
131 + if ( 'before' == $type ) {
132 + $content = substr( $content, 0, $position ) . $snippet_content . substr( $content, $position );
133 + } else {
134 + $content = substr( $content, 0, $position + 4 ) . $snippet_content . substr( $content, $position + 4 );
135 + }
136 + break;
137 + } else {
138 + $offset = $position + 1;
139 + }
140 + }
141 + }
142 +
143 + return $content;
144 + }
145 +
146 + /**
147 + * Handle posts content
148 + *
149 + * @param string $content
150 + * @param string $snippet_content
151 + * @param integer $post_number
152 + * @param string $type
153 + * @param object $query
154 + *
155 + * @return mixed
156 + */
157 + private function handlePostsContent( $content, $snippet_content, $post_number, $type, $query ) {
158 + global $winp_after_post_content;
159 + if ( $query->post_count > 0 ) {
160 + if ( $post_number == 0 ) {
161 + $post_number = 1;
162 + }
163 +
164 + if ( 'before' == $type && $query->current_post + 1 == $post_number ) {
165 + return $snippet_content;
166 + } else if ( 'after' == $type ) {
167 + // Номер поста совпадает
168 + if ( $query->current_post == $post_number ) {
169 + return $snippet_content;
170 + // Если это последний пост и указанный номер поста больше общего количества постов,
171 + // то нужно сохранить контент сниппета для вывода в конце данного поста
172 + } else if ( $query->current_post + 1 == $query->post_count && $post_number >= $query->post_count ) {
173 + $winp_after_post_content[ $query->post->ID ] = $snippet_content;
174 + }
175 + }
176 + }
177 +
178 + return $content;
179 + }
180 +
181 + /**
182 + * Execute the snippets page content
183 + *
184 + * @param $content
185 + *
186 + * @return mixed
187 + */
188 + public function executeContentSnippets( $content ) {
189 + global $post, $winp_after_post_content;
190 +
191 + $post_type = ! empty( $post ) ? $post->post_type : false;
192 +
193 + if ( is_category() || is_archive() || is_tag() || is_tax() || is_search() ) {
194 + // Перед коротким описанием
195 + $content = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_BEFORE_EXCERPT ) . $content;
196 +
197 + // После короткого описания
198 + $content .= $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_AFTER_EXCERPT );
199 + }
200 +
201 + if ( is_singular( [ $post_type ] ) ) {
202 + // Перед параграфом
203 + $content = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_BEFORE_PARAGRAPH, $content );
204 +
205 + // После параграфа
206 + $content = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_AFTER_PARAGRAPH, $content );
207 +
208 + // После заголовка
209 + $content = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_BEFORE_CONTENT ) . $content;
210 +
211 + // После текста
212 + $content .= $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_AFTER_CONTENT );
213 +
214 + // После поста
215 + $content .= $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_AFTER_POST );
216 +
217 + if ( ! comments_open( $post->ID ) && ! get_comments_number( $post->ID ) ) {
218 + remove_filter( 'wp_list_comments_args', [ $this, 'executeListCommentsSnippets' ] );
219 + }
220 + } else if ( ! is_null( $post ) && isset( $winp_after_post_content[ $post->ID ] ) ) {
221 + // После последнего поста в списке
222 + $content .= $winp_after_post_content[ $post->ID ];
223 + unset( $winp_after_post_content[ $post->ID ] );
224 + }
225 +
226 + return $content;
227 + }
228 +
229 + /**
230 + * Execute the snippets page excerpt
231 + *
232 + * @param $excerpt
233 + *
234 + * @return mixed
235 + */
236 + public function executeExcerptSnippets( $excerpt ) {
237 + if ( is_category() || is_archive() || is_tag() || is_tax() || is_search() ) {
238 + // Перед коротким описанием
239 + $excerpt = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_BEFORE_EXCERPT ) . $excerpt;
240 +
241 + // После короткого описания
242 + $excerpt .= $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_AFTER_EXCERPT );
243 + }
244 +
245 + return $excerpt;
246 + }
247 +
248 + /**
249 + * Execute the list comments filter
250 + *
251 + * @param $args
252 + *
253 + * @return mixed
254 + */
255 + public function executeListCommentsSnippets( $args ) {
256 + global $winp_wp_data;
257 +
258 + $winp_wp_data['winp_comments_saved_end_callback'] = $args['end-callback'];
259 + $args['end-callback'] = [ $this, 'executeCommentsSnippets' ];
260 +
261 + return $args;
262 + }
263 +
264 + /**
265 + * Execute the snippets after page comments
266 + *
267 + * @param $comment
268 + * @param $args
269 + * @param $depth
270 + */
271 + public function executeCommentsSnippets( $comment, $args, $depth ) {
272 + global $winp_wp_data, $post;
273 +
274 + if ( ! empty ( $winp_wp_data['winp_comments_saved_end_callback'] ) ) {
275 + echo call_user_func( $winp_wp_data['winp_comments_saved_end_callback'], $comment, $args, $depth );
276 + }
277 +
278 + $content = '';
279 +
280 + $post_type = ! empty( $post ) ? $post->post_type : false;
281 + if ( is_singular( [ $post_type ] ) ) {
282 + // После комментариев
283 + $content = $this->executeActiveSnippets( 'auto', WINP_SNIPPET_AUTO_AFTER_POST );
284 + }
285 +
286 + echo $content;
287 + }
288 +
289 + /**
290 + * Execute the snippets once the plugins are loaded
291 + *
292 + * @param string $scope
293 + * @param string $auto
294 + * @param string $content
295 + * @param array $custom_params
296 + *
297 + * @return string
298 + */
299 + public function executeActiveSnippets( $scope = 'evrywhere', $auto = '', $content = '', $custom_params = [] ) {
300 + global $wpdb;
301 +
302 + $snippets = $wpdb->get_results( "SELECT {$wpdb->posts}.ID, {$wpdb->posts}.post_content
303 + FROM {$wpdb->posts}
304 + INNER JOIN {$wpdb->postmeta} ON ( {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id )
305 + WHERE ( ( {$wpdb->postmeta}.meta_key = '" . WINP_Plugin::app()->getPrefix() . "snippet_scope' AND {$wpdb->postmeta}.meta_value = '{$scope}' ) ) AND {$wpdb->posts}.post_type = '" . WINP_SNIPPETS_POST_TYPE . "' AND ( ({$wpdb->posts}.post_status = 'publish') )" );
306 +
307 + if ( empty( $snippets ) ) {
308 + return $content;
309 + }
310 +
311 + foreach ( (array) $snippets as $snippet ) {
312 + $id = (int) $snippet->ID;
313 +
314 + $is_active = (int) WINP_Helper::getMetaOption( $id, 'snippet_activate', 0 );
315 + // Если это сниппет с автовставкой и выбранное место подходит под активный action
316 + $avail_place = ( 'auto' == $scope ? $auto == WINP_Helper::getMetaOption( $id, 'snippet_location', '' ) : true );
317 + // Если условие отображения сниппена выполняется
318 + $snippet_type = WINP_Helper::getMetaOption( $id, 'snippet_type', WINP_SNIPPET_TYPE_PHP );
319 + $is_condition = $snippet_type != WINP_SNIPPET_TYPE_PHP ? $this->checkCondition( $id ) : true;
320 +
321 + if ( $is_active && $avail_place && $is_condition ) {
322 + $post_id = (int) WINP_Plugin::app()->request->post( 'post_ID', 0 );
323 +
324 + if ( isset( $_POST['wbcr_inp_snippet_scope'] ) && $post_id === $id && WINP_Plugin::app()->currentUserCan() ) {
325 + return $content;
326 + }
327 +
328 + if ( WINP_Helper::is_safe_mode() ) {
329 + return $content;
330 + }
331 +
332 + $snippet_code = WINP_Helper::get_snippet_code( $snippet );
333 +
334 + if ( $snippet_type === WINP_SNIPPET_TYPE_TEXT ) {
335 + $snippet_content = '<div class="winp-text-snippet-contanier">' . $snippet_code . '</div>';
336 + } else if ( $snippet_type === WINP_SNIPPET_TYPE_CSS || $snippet_type === WINP_SNIPPET_TYPE_JS ) {
337 + $snippet_content = self::getJsCssSnippetData( $id );
338 + } else if ( $snippet_type === WINP_SNIPPET_TYPE_HTML ) {
339 + $snippet_content = $snippet_code;
340 + } else {
341 + $code = $this->prepareCode( $snippet_code, $id );
342 + ob_start();
343 + $this->executeSnippet( $code, $id, false );
344 + $snippet_content = ob_get_contents();
345 + ob_end_clean();
346 + }
347 +
348 + if ( 'auto' == $scope ) {
349 + switch ( $auto ) {
350 + case WINP_SNIPPET_AUTO_BEFORE_PARAGRAPH: // Перед параграфом
351 + $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
352 + $content = $this->handleParagraphContent( $content, $snippet_content, $location_number );
353 + break;
354 + case WINP_SNIPPET_AUTO_AFTER_PARAGRAPH: // После параграфа
355 + $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
356 + $content = $this->handleParagraphContent( $content, $snippet_content, $location_number, 'after' );
357 + break;
358 + case WINP_SNIPPET_AUTO_BEFORE_POSTS: // Перед записью
359 + $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
360 + $content = $this->handlePostsContent( $content, $snippet_content, $location_number, 'before', $custom_params );
361 + break;
362 + case WINP_SNIPPET_AUTO_AFTER_POSTS: // После записи
363 + $location_number = WINP_Helper::getMetaOption( $id, 'snippet_p_number', 0 );
364 + $content = $this->handlePostsContent( $content, $snippet_content, $location_number, 'after', $custom_params );
365 + break;
366 + default:
367 + $content = $snippet_content . $content;
368 + }
369 + } else {
370 + $content = $snippet_content . $content;
371 + }
372 + }
373 + }
374 +
375 + return $content;
376 + }
377 +
378 + /**
379 + * Get js or css snippet data
380 + *
381 + * @param $snippet_id
382 + *
383 + * @return mixed|string
384 + */
385 + public static function getJsCssSnippetData( $snippet_id ) {
386 + $snippet_type = WINP_Helper::get_snippet_type( $snippet_id );
387 +
388 + $linking = WINP_Helper::getMetaOption( $snippet_id, 'snippet_linking' );
389 + $filetype = WINP_Helper::getMetaOption( $snippet_id, 'filetype', $snippet_type );
390 +
391 + $file_name = $snippet_id . '.' . $filetype;
392 + $slug = WINP_Helper::getMetaOption( $snippet_id, 'css_js_slug' );
393 + if ( ! empty( $slug ) ) {
394 + $file_name = $slug . '.' . $filetype;
395 + }
396 +
397 + if ( file_exists( WINP_UPLOAD_DIR . '/' . $file_name ) ) {
398 + if ( 'inline' == $linking ) {
399 + return file_get_contents( WINP_UPLOAD_DIR . '/' . $file_name );
400 + }
401 +
402 + if ( 'external' == $linking ) {
403 + $file_name .= '?ver=' . WINP_Helper::getMetaOption( $snippet_id, 'css_js_version', time() );
404 +
405 + if ( 'js' == $snippet_type ) {
406 + return PHP_EOL . "<script type='text/javascript' src='" . WINP_UPLOAD_URL . '/' . $file_name . "'></script>" . PHP_EOL;
407 + }
408 +
409 + if ( 'css' == $snippet_type ) {
410 + $short_filename = preg_replace( '@\.css\?ver=.*$@', '', $file_name );
411 +
412 + return PHP_EOL . "<link rel='stylesheet' id='" . $short_filename . "-css' href='" . WINP_UPLOAD_URL . '/' . $file_name . "' type='text/css' media='all' />" . PHP_EOL;
413 + }
414 + }
415 + }
416 +
417 + return "";
418 + }
419 +
420 + /**
421 + * Execute a snippet
422 + *
423 + * Code must NOT be escaped, as
424 + * it will be executed directly
425 + *
426 + * @param string $code The snippet code to execute
427 + * @param int $id The snippet ID
428 + * @param bool $catch_output Whether to attempt to suppress the output of execution using buffers
429 + *
430 + * @return mixed The result of the code execution
431 + */
432 + public function executeSnippet( $code, $id = 0, $catch_output = true ) {
433 + $id = (int) $id;
434 +
435 + if ( ! $id || empty( $code ) ) {
436 + return false;
437 + }
438 +
439 + if ( $catch_output ) {
440 + ob_start();
441 + }
442 +
443 + $snippet = get_post( $id );
444 +
445 + if ( empty( $snippet ) || $snippet->post_type !== WINP_SNIPPETS_POST_TYPE ) {
446 + return false;
447 + }
448 +
449 + $snippet_type = WINP_Helper::getMetaOption( $id, 'snippet_type', true );
450 +
451 + if ( $snippet_type == WINP_SNIPPET_TYPE_UNIVERSAL ) {
452 + $result = eval( "?>" . $code . "<?php " );
453 + } else if ( $snippet_type == WINP_SNIPPET_TYPE_PHP ) {
454 + $result = eval( $code );
455 + } else {
456 + $result = ! empty( $code );
457 + }
458 +
459 + if ( $catch_output ) {
460 + ob_end_clean();
461 + }
462 +
463 + return $result;
464 + }
465 +
466 + /**
467 + * Get property value
468 + *
469 + * @param $value
470 + * @param $property
471 + *
472 + * @return null
473 + */
474 + private function getPropertyValue( $value, $property ) {
475 + if ( is_object( $value ) ) {
476 + return $value->$property;
477 + } else if ( isset( $value[ $property ] ) ) {
478 + return $value[ $property ];
479 + }
480 +
481 + return null;
482 + }
483 +
484 + /**
485 + * Check conditional execution logic for the snippet
486 + *
487 + * @param $snippet_id
488 + *
489 + * @return bool
490 + */
491 + public function checkCondition( $snippet_id ) {
492 + // Итоговый результат условий
493 + $result = true;
494 + // Получаем сохранённые параметры условий
495 + $filters = get_post_meta( $snippet_id, WINP_Plugin::app()->getPrefix() . 'snippet_filters' );
496 + // Если условия указаны
497 + if ( ! ( empty( $filters ) || isset( $filters[0] ) && empty( $filters[0] ) ) ) {
498 + foreach ( $filters[0] as $filter ) {
499 + $conditions = $this->getPropertyValue( $filter, 'conditions' );
500 + // Если условия пусты, то пропускаем цикл
501 + if ( empty( $conditions ) ) {
502 + continue;
503 + }
504 + // Промежуточный результат AND условий
505 + $and_conditions = null;
506 + // Проходим по AND условиям
507 + foreach ( $conditions as $scope ) {
508 + $scope_conditions = $this->getPropertyValue( $scope, 'conditions' );
509 + // Если условия пусты, то пропускаем цикл
510 + if ( empty( $scope_conditions ) ) {
511 + continue;
512 + }
513 + // Промежуточный результат OR условий
514 + $or_conditions = null;
515 + // Проходим по OR условиям
516 + foreach ( $scope_conditions as $condition ) {
517 + $method_name = str_replace( '-', '_', $this->getPropertyValue( $condition, 'param' ) );
518 + $operator = $this->getPropertyValue( $condition, 'operator' );
519 + $value = $this->getPropertyValue( $condition, 'value' );
520 + // Получаем результат OR условий
521 + $or_conditions = is_null( $or_conditions ) ? $this->call_method( $method_name, $operator, $value ) : $or_conditions || $this->call_method( $method_name, $operator, $value );
522 + }
523 + // Получаем результат AND условий
524 + $and_conditions = is_null( $and_conditions ) ? $or_conditions : $and_conditions && $or_conditions;
525 + }
526 + // Получаем результат блока условий
527 + $result = $this->getPropertyValue( $filter, 'type' ) == 'showif' ? $and_conditions : ! $and_conditions;
528 + }
529 + }
530 +
531 + return $result;
532 + }
533 +
534 + /**
535 + * Call specified method
536 + *
537 + * @param $method_name
538 + * @param $operator
539 + * @param $value
540 + *
541 + * @return bool
542 + */
543 + private function call_method( $method_name, $operator, $value ) {
544 + if ( method_exists( $this, $method_name ) ) {
545 + return $this->$method_name( $operator, $value );
546 + } else {
547 + return apply_filters( 'wbcr/inp/execute/check_condition', false, $method_name, $operator, $value );
548 + }
549 + }
550 +
551 + /**
552 + * Retrieve the first error in a snippet's code
553 + *
554 + * @param int $snippet_id
555 + *
556 + * @return array|bool
557 + */
558 + public function getSnippetError( $snippet_id ) {
559 + if ( ! intval( $snippet_id ) ) {
560 + return false;
561 + }
562 +
563 + $snippet = get_post( $snippet_id );
564 +
565 + if ( ! $snippet ) {
566 + return false;
567 + }
568 +
569 + $snippet_code = WINP_Helper::get_snippet_code( $snippet );
570 + $snippet_code = $this->prepareCode( $snippet_code, $snippet_id );
571 +
572 + $result = $this->executeSnippet( $snippet_code, $snippet_id );
573 +
574 + if ( false !== $result ) {
575 + return false;
576 + }
577 +
578 + $error = error_get_last();
579 +
580 + if ( is_null( $error ) ) {
581 + return false;
582 + }
583 +
584 + return $error;
585 + }
586 +
587 + /**
588 + * Prepare the code by removing php tags from beginning and end
589 + *
590 + * @param string $code
591 + * @param integer $snippet_id
592 + *
593 + * @return string
594 + */
595 + public function prepareCode( $code, $snippet_id ) {
596 + $snippet_type = WINP_Helper::get_snippet_type( $snippet_id );
597 + if ( $snippet_type != WINP_SNIPPET_TYPE_UNIVERSAL && $snippet_type != WINP_SNIPPET_TYPE_CSS && $snippet_type != WINP_SNIPPET_TYPE_JS && $snippet_type != WINP_SNIPPET_TYPE_HTML ) {
598 + /* Remove <?php and <? from beginning of snippet */
599 + $code = preg_replace( '|^[\s]*<\?(php)?|', '', $code );
600 +
601 + /* Remove ?> from end of snippet */
602 + $code = preg_replace( '|\?>[\s]*$|', '', $code );
603 + }
604 +
605 + return $code;
606 + }
607 +
608 + /**
609 + * Get current URL
610 + *
611 + * @return string
612 + */
613 + private function getCurrentUrl() {
614 + $out = "";
615 + $url = explode( '?', $_SERVER['REQUEST_URI'], 2 );
616 + if ( isset( $url[0] ) ) {
617 + $out = trim( $url[0], '/' );
618 + }
619 +
620 + return $out ? urldecode( $out ) : '/';
621 + }
622 +
623 + /**
624 + * Get referer URL
625 + *
626 + * @return string
627 + */
628 + private function getRefererUrl() {
629 + $out = "";
630 + $url = explode( '?', str_replace( site_url(), '', $_SERVER['HTTP_REFERER'] ), 2 );
631 + if ( isset( $url[0] ) ) {
632 + $out = trim( $url[0], '/' );
633 + }
634 +
635 + return $out ? urldecode( $out ) : '/';
636 + }
637 +
638 + /**
639 + * Check by operator
640 + *
641 + * @param $operation
642 + * @param $first
643 + * @param $second
644 + * @param $third
645 + *
646 + * @return bool
647 + */
648 + public function checkByOperator( $operation, $first, $second, $third = false ) {
649 + switch ( $operation ) {
650 + case 'equals':
651 + return $first === $second;
652 + case 'notequal':
653 + return $first !== $second;
654 + case 'less':
655 + case 'older':
656 + return $first > $second;
657 + case 'greater':
658 + case 'younger':
659 + return $first < $second;
660 + case 'contains':
661 + return strpos( $first, $second ) !== false;
662 + case 'notcontain':
663 + return strpos( $first, $second ) === false;
664 + case 'between':
665 + return $first < $second && $second < $third;
666 +
667 + default:
668 + return $first === $second;
669 + }
670 + }
671 +
672 + /**
673 + * A role of the user who views your website. The role "guest" is applied for unregistered users.
674 + *
675 + * @param string $operator
676 + * @param string $value
677 + *
678 + * @return boolean
679 + */
680 + private function user_role( $operator, $value ) {
681 + if ( ! is_user_logged_in() ) {
682 + return $this->checkByOperator( $operator, $value, 'guest' );
683 + } else {
684 + $current_user = wp_get_current_user();
685 + if ( ! ( $current_user instanceof WP_User ) ) {
686 + return false;
687 + }
688 +
689 + return $this->checkByOperator( $operator, $value, $current_user->roles[0] );
690 + }
691 + }
692 +
693 + /**
694 + * Get timestamp
695 + *
696 + * @param $units
697 + * @param $count
698 + *
699 + * @return integer
700 + */
701 + private function getTimestamp( $units, $count ) {
702 + switch ( $units ) {
703 + case 'seconds':
704 + return $count;
705 + case 'minutes':
706 + return $count * MINUTE_IN_SECONDS;
707 + case 'hours':
708 + return $count * HOUR_IN_SECONDS;
709 + case 'days':
710 + return $count * DAY_IN_SECONDS;
711 + case 'weeks':
712 + return $count * WEEK_IN_SECONDS;
713 + case 'months':
714 + return $count * MONTH_IN_SECONDS;
715 + case 'years':
716 + return $count * YEAR_IN_SECONDS;
717 +
718 + default:
719 + return $count;
720 + }
721 + }
722 +
723 + /**
724 + * Get date timestamp
725 + *
726 + * @param $value
727 + *
728 + * @return integer
729 + */
730 + public function getDateTimestamp( $value ) {
731 + if ( is_object( $value ) ) {
732 + return ( current_time( 'timestamp' ) - $this->getTimestamp( $value->units, $value->unitsCount ) ) * 1000;
733 + } else {
734 + return $value;
735 + }
736 + }
737 +
738 + /**
739 + * The date when the user who views your website was registered.
740 + * For unregistered users this date always equals to 1 Jan 1970.
741 + *
742 + * @param string $operator
743 + * @param string $value
744 + *
745 + * @return boolean
746 + */
747 + private function user_registered( $operator, $value ) {
748 + if ( ! is_user_logged_in() ) {
749 + return false;
750 + } else {
751 + $user = wp_get_current_user();
752 + $registered = strtotime( $user->data->user_registered ) * 1000;
753 +
754 + if ( $operator == 'equals' || $operator == 'notequal' ) {
755 + $registered = $registered / 1000;
756 + $timestamp = round( $this->getDateTimestamp( $value ) / 1000 );
757 +
758 + return $this->checkByOperator( $operator, date( "Y-m-d", $timestamp ), date( "Y-m-d", $registered ) );
759 + } else if ( $operator == 'between' ) {
760 + $start_timestamp = $this->getDateTimestamp( $value->start );
761 + $end_timestamp = $this->getDateTimestamp( $value->end );
762 +
763 + return $this->checkByOperator( $operator, $start_timestamp, $registered, $end_timestamp );
764 + } else {
765 + $timestamp = $this->getDateTimestamp( $value );
766 +
767 + return $this->checkByOperator( $operator, $timestamp, $registered );
768 + }
769 + }
770 + }
771 +
772 + /**
773 + * Check the user views your website from mobile device or not
774 + *
775 + * @param string $operator
776 + * @param string $value
777 + *
778 + * @return boolean
779 + *
780 + * @link https://stackoverflow.com/a/4117597
781 + */
782 + private function user_mobile( $operator, $value ) {
783 + $useragent = $_SERVER['HTTP_USER_AGENT'];
784 +
785 + if ( preg_match( '/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i', $useragent ) || preg_match( '/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr( $useragent, 0, 4 ) ) ) {
786 + return $operator === 'equals' && $value === 'yes' || $operator === 'notequal' && $value === 'no';
787 + } else {
788 + return $operator === 'notequal' && $value === 'yes' || $operator === 'equals' && $value === 'no';
789 + }
790 + }
791 +
792 + /**
793 + * Determines whether the user's browser has a cookie with a given name
794 + *
795 + * @param $operator
796 + * @param $value
797 + *
798 + * @return boolean
799 + */
800 + private function user_cookie_name( $operator, $value ) {
801 + if ( isset( $_COOKIE[ $value ] ) ) {
802 + return $operator === 'equals';
803 + } else {
804 + return $operator === 'notequal';
805 + }
806 + }
807 +
808 + /**
809 + * A some selected page
810 + *
811 + * @param $operator
812 + * @param $value
813 + *
814 + * @return boolean
815 + */
816 + private function location_some_page( $operator, $value ) {
817 + $post_id = ( ! is_404() && ! is_search() && ! is_archive() && ! is_home() ) ? get_the_ID() : false;
818 +
819 + switch ( $value ) {
820 + case 'base_web': // Basic - Entire Website
821 + $result = true;
822 + break;
823 + case 'base_sing': // Basic - All Singulars
824 + $result = is_singular();
825 + break;
826 + case 'base_arch': // Basic - All Archives
827 + $result = is_archive();
828 + break;
829 + case 'spec_404': // Special Pages - 404 Page
830 + $result = is_404();
831 + break;
832 + case 'spec_search': // Special Pages - Search Page
833 + $result = is_search();
834 + break;
835 + case 'spec_blog': // Special Pages - Blog / Posts Page
836 + $result = is_home();
837 + break;
838 + case 'spec_front': // Special Pages - Front Page
839 + $result = is_front_page();
840 + break;
841 + case 'spec_date': // Special Pages - Date Archive
842 + $result = is_date();
843 + break;
844 + case 'spec_auth': // Special Pages - Author Archive
845 + $result = is_author();
846 + break;
847 + case 'post_all': // Posts - All Posts
848 + case 'page_all': // Pages - All Pages
849 + $result = false;
850 + if ( false !== $post_id ) {
851 + $post_type = 'post_all' == $value ? 'post' : 'page';
852 + $result = $post_type == get_post_type( $post_id );
853 + }
854 + break;
855 + case 'post_arch': // Posts - All Posts Archive
856 + case 'page_arch': // Pages - All Pages Archive
857 + $result = false;
858 + if ( is_archive() ) {
859 + $post_type = 'post_arch' == $value ? 'post' : 'page';
860 + $result = $post_type == get_post_type();
861 + }
862 + break;
863 + case 'post_cat': // Posts - All Categories Archive
864 + case 'post_tag': // Posts - All Tags Archive
865 + $result = false;
866 + if ( is_archive() && 'post' == get_post_type() ) {
867 + $taxonomy = 'post_tag' == $value ? 'post_tag' : 'category';
868 + $obj = get_queried_object();
869 +
870 + $current_taxonomy = '';
871 + if ( '' !== $obj && null !== $obj ) {
872 + $current_taxonomy = $obj->taxonomy;
873 + }
874 +
875 + if ( $current_taxonomy == $taxonomy ) {
876 + $result = true;
877 + }
878 + }
879 + break;
880 +
881 + default:
882 + $result = true;
883 + }
884 +
885 + return $this->checkByOperator( $operator, $result, true );
886 + }
887 +
888 + /**
889 + * An URL of the current page where a user who views your website is located
890 + *
891 + * @param $operator
892 + * @param $value
893 + *
894 + * @return boolean
895 + */
896 + private function location_page( $operator, $value ) {
897 + $url = $this->getCurrentUrl();
898 +
899 + return $url ? $this->checkByOperator( $operator, trim( $url, '/' ), trim( $value, '/' ) ) : false;
900 + }
901 +
902 + /**
903 + * A referrer URL which has brought a user to the current page
904 + *
905 + * @param $operator
906 + * @param $value
907 + *
908 + * @return boolean
909 + */
910 + private function location_referrer( $operator, $value ) {
911 + $url = $this->getRefererUrl();
912 +
913 + return $url ? $this->checkByOperator( $operator, trim( $url, '/' ), trim( $value, '/' ) ) : false;
914 + }
915 +
916 + /**
917 + * A post type of the current page
918 + *
919 + * @param $operator
920 + * @param $value
921 + *
922 + * @return boolean
923 + */
924 + private function location_post_type( $operator, $value ) {
925 + if ( is_singular() ) {
926 + return $this->checkByOperator( $operator, $value, get_post_type() );
927 + }
928 +
929 + return false;
930 + }
931 +
932 + /**
933 + * A taxonomy of the current page
934 + *
935 + * @param $operator
936 + * @param $value
937 + *
938 + * @return boolean
939 + */
940 + private function location_taxonomy( $operator, $value ) {
941 + global $post;
942 +
943 + $post_cat = get_the_category( $post->ID );
944 + if ( isset( $post_cat[0] ) ) {
945 + return $this->checkByOperator( $operator, intval( $value ), $post_cat[0]->term_id );
946 + }
947 +
948 + return false;
949 + }
950 +
951 +}