PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.1.3
Page Builder: Pagelayer – Drag and Drop website builder v2.1.3
2.2.1 2.2.0 2.1.9 2.1.8 2.1.7 2.1.6 2.1.5 2.1.4 2.1.3 trunk 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5 0.9.6 0.9.7 0.9.8 0.9.9 1.0.0 1.0.2 1.0.3 1.0.4 1.0.5 All 129 releases
pagelayer / main / functions.php

functions.php in Page Builder: Pagelayer – Drag and Drop website builder 2.1.3, at main/functions.php

4,084 lines 103.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 //////////////////////////////////////////////////////////////
4 //===========================================================
5 // class.php
6 //===========================================================
7 // PAGELAYER
8 // Inspired by the DESIRE to be the BEST OF ALL
9 // ----------------------------------------------------------
10 // Started by: Pulkit Gupta
11 // Date: 23rd Jan 2017
12 // Time: 23:00 hrs
13 // Site: http://pagelayer.com/wordpress (PAGELAYER)
14 // ----------------------------------------------------------
15 // Please Read the Terms of use at http://pagelayer.com/tos
16 // ----------------------------------------------------------
17 //===========================================================
18 // (c)Pagelayer Team
19 //===========================================================
20 //////////////////////////////////////////////////////////////
21
22 // Are we being accessed directly ?
23 if(!defined('PAGELAYER_VERSION')) {
24 exit('Hacking Attempt !');
25 }
26
27 // Get the client IP
28 function _pagelayer_getip(){
29 if(isset($_SERVER["REMOTE_ADDR"])){
30 return $_SERVER["REMOTE_ADDR"];
31 }elseif(isset($_SERVER["HTTP_X_FORWARDED_FOR"])){
32 return $_SERVER["HTTP_X_FORWARDED_FOR"];
33 }elseif(isset($_SERVER["HTTP_CLIENT_IP"])){
34 return $_SERVER["HTTP_CLIENT_IP"];
35 }
36 }
37
38 // Get the client IP
39 function pagelayer_getip(){
40
41 global $pagelayer;
42
43 // Just so that we have something
44 $ip = _pagelayer_getip();
45 $method = @$pagelayer->ip_method;
46
47 $pagelayer->ip_method = (int) $method;
48
49 if(isset($_SERVER["REMOTE_ADDR"])){
50 $ip = $_SERVER["REMOTE_ADDR"];
51 }
52
53 if(isset($_SERVER["HTTP_X_FORWARDED_FOR"]) && $method == 1){
54 $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
55 }
56
57 if(isset($_SERVER["HTTP_CLIENT_IP"]) && $method == 2){
58 $ip = $_SERVER["HTTP_CLIENT_IP"];
59 }
60
61 // Hacking fix for X-Forwarded-For
62 if(!pagelayer_valid_ip($ip)){
63 return '';
64 }
65
66 return $ip;
67
68 }
69
70 // Execute a select query and return an array
71 function pagelayer_selectquery($query, $array = 0){
72 global $wpdb;
73
74 $result = $wpdb->get_results($query, 'ARRAY_A');
75
76 if(empty($array)){
77 return current($result);
78 }else{
79 return $result;
80 }
81 }
82
83 // Check if an IP is valid
84 function pagelayer_valid_ip($ip){
85
86 // IPv6
87 if(pagelayer_valid_ipv6($ip)){
88 return true;
89 }
90
91 // IPv4
92 if(!ip2long($ip)){
93 return false;
94 }
95
96 return true;
97 }
98
99 function pagelayer_valid_ipv6($ip){
100
101 $pattern = '/^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/';
102
103 if(!preg_match($pattern, $ip)){
104 return false;
105 }
106
107 return true;
108
109 }
110
111 // Check if a field is posted via POST else return default value
112 function pagelayer_optpost($name, $default = ''){
113
114 if(!empty($_POST[$name])){
115 return pagelayer_inputsec(pagelayer_htmlizer(trim($_POST[$name])));
116 }
117
118 return $default;
119 }
120
121 // Check if a field is posted via GET else return default value
122 function pagelayer_optget($name, $default = ''){
123
124 if(!empty($_GET[$name])){
125 return pagelayer_inputsec(pagelayer_htmlizer(trim($_GET[$name])));
126 }
127
128 return $default;
129 }
130
131 // Check if a field is posted via GET or POST else return default value
132 function pagelayer_optreq($name, $default = ''){
133
134 if(!empty($_REQUEST[$name])){
135 return pagelayer_inputsec(pagelayer_htmlizer(trim($_REQUEST[$name])));
136 }
137
138 return $default;
139 }
140
141 // For filling in posted values
142 function pagelayer_POSTval($name, $default = ''){
143
144 return (!empty($_POST) ? (!isset($_POST[$name]) ? '' : esc_html($_POST[$name])) : $default);
145
146 }
147
148 function pagelayer_POSTchecked($name, $default = false){
149
150 return (!empty($_POST) ? (isset($_POST[$name]) ? 'checked="checked"' : '') : (!empty($default) ? 'checked="checked"' : ''));
151
152 }
153
154 // For check isset value
155 function pagelayer_isset($var, $name, $default = ''){
156
157 return isset($var[$name]) ? $var[$name] : $default;
158
159 }
160
161 function pagelayer_POSTselect($name, $value, $default = false){
162
163 if(empty($_POST)){
164 if(!empty($default)){
165 return 'selected="selected"';
166 }
167 }else{
168 if(isset($_POST[$name])){
169 if(trim($_POST[$name]) == $value){
170 return 'selected="selected"';
171 }
172 }
173 }
174
175 }
176
177 function pagelayer_inputsec($string){
178
179 $string = addslashes($string);
180
181 // This is to replace ` which can cause the command to be executed in exec()
182 $string = str_replace('`', '\`', $string);
183
184 return $string;
185
186 }
187
188 function pagelayer_htmlizer($string){
189
190 $string = htmlentities($string, ENT_QUOTES, 'UTF-8');
191
192 preg_match_all('/(&amp;#(\d{1,7}|x[0-9a-fA-F]{1,6});)/', $string, $matches);//r_print($matches);
193
194 foreach($matches[1] as $mk => $mv){
195 $tmp_m = pagelayer_entity_check($matches[2][$mk]);
196 $string = str_replace($matches[1][$mk], $tmp_m, $string);
197 }
198
199 return $string;
200
201 }
202
203 function pagelayer_entity_check($string){
204
205 //Convert Hexadecimal to Decimal
206 $num = ((substr($string, 0, 1) === 'x') ? hexdec(substr($string, 1)) : (int) $string);
207
208 //Squares and Spaces - return nothing
209 $string = (($num > 0x10FFFF || ($num >= 0xD800 && $num <= 0xDFFF) || $num < 0x20) ? '' : '&#'.$num.';');
210
211 return $string;
212
213 }
214
215 // Check if a checkbox is selected
216 function pagelayer_is_checked($post){
217
218 if(!empty($_POST[$post])){
219 return true;
220 }
221 return false;
222 }
223
224 // Report an error
225 function pagelayer_report_error($error = array()){
226
227 if(empty($error)){
228 return true;
229 }
230
231 $error_string = '<b>Please fix the below error(s) :</b> <br />';
232
233 foreach($error as $ek => $ev){
234 $error_string .= '* '.$ev.'<br />';
235 }
236
237 echo '<div id="message" class="error"><p>'
238 . __pl($error_string)
239 . '</p></div>';
240 }
241
242 // Report a notice
243 function pagelayer_report_notice($notice = array()){
244
245 global $wp_version;
246
247 if(empty($notice)){
248 return true;
249 }
250
251 // Which class do we have to use ?
252 if(version_compare($wp_version, '3.8', '<')){
253 $notice_class = 'updated';
254 }else{
255 $notice_class = 'updated';
256 }
257
258 $notice_string = '<b>Please check the below notice(s) :</b> <br />';
259
260 foreach($notice as $ek => $ev){
261 $notice_string .= '* '.$ev.'<br />';
262 }
263
264 echo '<div id="message" class="'.$notice_class.'"><p>'
265 . __pl($notice_string)
266 . '</p></div>';
267 }
268
269 // Convert an objext to array
270 function pagelayer_objectToArray($d){
271
272 if(is_object($d)){
273 $d = get_object_vars($d);
274 }
275
276 if(is_array($d)){
277 return array_map(__FUNCTION__, $d); // recursive
278 }elseif(is_object($d)){
279 return pagelayer_objectToArray($d);
280 }else{
281 return $d;
282 }
283 }
284
285 // Sanitize variables
286 function pagelayer_sanitize_variables($variables = array()){
287
288 if(is_array($variables)){
289 foreach($variables as $k => $v){
290 $variables[$k] = trim($v);
291 $variables[$k] = escapeshellcmd($v);
292 }
293 }else{
294 $variables = escapeshellcmd(trim($variables));
295 }
296
297 return $variables;
298 }
299
300 // Is multisite ?
301 function pagelayer_is_multisite() {
302
303 if(function_exists('get_site_option') && function_exists('is_multisite') && is_multisite()){
304 return true;
305 }
306
307 return false;
308 }
309
310 // Generate a random string
311 function pagelayer_RandomString($length = 10){
312 $characters = '0123456789abcdefghijklmnopqrstuvwxyz';
313 $charactersLength = strlen($characters);
314 $randomString = '';
315 for($i = 0; $i < $length; $i++){
316 $randomString .= $characters[rand(0, $charactersLength - 1)];
317 }
318 return $randomString;
319 }
320
321 function pagelayer_print($array){
322
323 echo '<pre>';
324 print_r($array);
325 echo '</pre>';
326
327 }
328
329 function pagelayer_cleanpath($path){
330 $path = str_replace('\\\\', '/', $path);
331 $path = str_replace('\\', '/', $path);
332 $path = str_replace('//', '/', $path);
333 return rtrim($path, '/');
334 }
335
336 // Returns the Numeric Value of results Per Page
337 function pagelayer_get_page($get = 'page', $resperpage = 50){
338
339 $resperpage = (!empty($_REQUEST['reslen']) && is_numeric($_REQUEST['reslen']) ? (int) pagelayer_optreq('reslen') : $resperpage);
340
341 if(pagelayer_optget($get)){
342 $pg = (int) pagelayer_optget($get);
343 $pg = $pg - 1;
344 $page = ($pg * $resperpage);
345 $page = ($page <= 0 ? 0 : $page);
346 }else{
347 $page = 0;
348 }
349 return $page;
350 }
351
352 // Are we editing from the Admin panel ?
353 function pagelayer_is_editing($force = false){
354
355 global $post, $pagelayer;
356
357 if(!empty($force)){
358 return true;
359 }
360
361 if(!is_admin()){
362 return false;
363 }
364
365 $current_file = basename($_SERVER['PHP_SELF']);
366
367 $type = get_post_type();
368 //echo $type;return false;
369 //$page = pagelayer_optreq('page');
370
371 // Are we in the live editor mode OR is this a post which is supported
372 if((pagelayer_supported_type($type) && in_array($current_file, array('post.php', 'post-new.php'))) || pagelayer_is_live()){
373 return true;
374 }else{
375 return false;
376 }
377
378 }
379
380 // Is the given post type editable by us ?
381 function pagelayer_supported_type($type){
382
383 global $pagelayer;
384
385 $type = trim($type);
386
387 if(in_array($type, $pagelayer->settings['post_types'])){
388 return true;
389 }
390
391 if($type == $pagelayer->builder['name']){
392 return true;
393 }
394
395 return false;
396
397 }
398
399 function pagelayer_shortlink($id){
400
401 $post = get_post( $id );
402 if ( ! empty( $post->ID ) ) {
403 $post_id = $post->ID;
404 }
405
406 $post_type = get_post_type_object( $post->post_type );
407
408 if ( 'page' === $post->post_type && get_option( 'page_on_front' ) == $post->ID && 'page' === get_option( 'show_on_front' ) ) {
409 $link = home_url( '/' );
410 } elseif ( $post_type->public ) {
411 $link = home_url( '?p=' . $post_id );
412 }
413
414 if(function_exists('is_post_status_viewable') && !is_post_status_viewable($post_id)){
415 $link = get_permalink( $post->ID );
416 }
417
418 $link .= substr_count($link, '?') > 0 ? '' : '?';
419 return $link;
420 }
421
422 // Pagelayer live link
423 function pagelayer_livelink($id){
424 return pagelayer_shortlink($id).'&pagelayer-live=1';
425 }
426
427 // Are we in live mode ?
428 function pagelayer_is_live(&$error = array()){
429
430 global $post;
431
432 // Are we seeing the post ?
433 if(!isset($post) || !isset($post->ID) || empty($post->ID)){
434 $error[] = 'Post ID is missing or blank - '.@$post->ID;
435 return false;
436 }
437
438 $parID = $post->ID;
439
440 // Is revision?
441 if(wp_is_post_revision($post->ID) ){
442 $parID = wp_get_post_parent_id($post->ID);
443 }
444
445 // Are you allowed to edit ?
446 if(!pagelayer_user_can_edit($parID)){
447 $error[] = 'You dont have editing rights for this page - '.$parID;
448 return false;
449 }
450
451 // Is it the live mode ?
452 if(pagelayer_optreq('pagelayer-live')){
453 $error[] = 'pagelayer-live is missing';
454 return true;
455 }
456
457 return false;
458
459 }
460
461 // Are we in live IFRAME mode ?
462 function pagelayer_is_live_iframe(&$error = array()){
463
464 // Are we seeing the post ?
465 if(!pagelayer_is_live($error)){
466 return false;
467 }
468
469 // Is it the live mode ?
470 if(pagelayer_optreq('pagelayer-iframe')){
471 return true;
472 }
473
474 $error[] = 'pagelayer-iframe missing in GET';
475
476 return false;
477
478 }
479
480 // Are we editing a live template
481 function pagelayer_is_live_template($post = []){
482
483 // Are we seeing the post ?
484 if(!pagelayer_is_live()){
485 return false;
486 }
487
488 if(!$post){
489 $post = $GLOBALS['post'];
490 }
491
492 if($post->post_type == 'pagelayer-template'){
493 return true;
494 }
495
496 return false;
497
498 }
499
500 function pagelayer_has_blocks($post = null) {
501 if ( ! has_blocks( $post ) ) {
502 return false;
503 }
504
505 if ( ! is_string( $post ) ) {
506 $wp_post = get_post( $post );
507 if ( $wp_post instanceof WP_Post ) {
508 $post = $wp_post->post_content;
509 }
510 }
511
512 return false !== strpos( $post, '<!-- wp:pagelayer/' );
513 }
514
515 // Can the current user edit the post ?
516 function pagelayer_user_can_edit($post = NULL){
517
518 global $wp_the_query, $current_user, $pagelayer;
519
520 $post = get_post($post);
521
522 if(empty($post)){
523 return false;
524 }
525
526 // No trash editing
527 if(get_post_status($post->ID) === 'trash'){
528 return false;
529 }
530
531 // Is pagelayer supposed to edit this ?
532 if(!pagelayer_supported_type($post->post_type)){
533 return false;
534 }
535
536 // Get the post type object
537 $object = get_post_type_object($post->post_type);
538
539 // Is this type editable by the user ?
540 if(!current_user_can($object->cap->edit_posts)){
541 return false;
542 }
543
544 // Is this type editable ?
545 if(!isset($object->cap->edit_post)){
546 return false;
547 }
548
549 // Can this user edit the post type ?
550 if(!current_user_can($object->cap->edit_post, $post->ID)){
551 return false;
552 }
553
554 // Page for blogs not allowed
555 if(get_option('page_for_posts') === $post->ID){
556 return false;
557 }
558
559 return true;
560
561 }
562
563 // Language sting function
564 function __pl($key){
565
566 global $pagelayer;
567
568 if(!empty($pagelayer->l[$key])){
569 return $pagelayer->l[$key];
570 }
571
572 return $key;
573
574 }
575
576 // Give the list of icon sources
577 function pagelayer_icon_sources(){
578 return array();
579 }
580
581 // Sets the memory limit
582 function pagelayer_memory_limit($mb){
583
584 $bytes = ($mb * 1024 * 1024);
585 $mb_str = (string) $mb.'M';
586
587 // Some servers might have ini_get disabled
588 if(function_exists('ini_get')){
589 $memory_limit = @ini_get('memory_limit');
590 }
591
592 if(empty($memory_limit)){
593 return;
594 }
595
596 $memory_limit_bytes = (strpos($memory_limit, 'M') ? (intval($memory_limit) * 1024 * 1024) : intval($memory_limit));
597
598 //$memory_limit_bytes > 0 is for memory limit = -1
599 if($memory_limit_bytes <= $bytes && $memory_limit_bytes > 0){
600
601 // Some servers might have ini_set disabled
602 if(function_exists('ini_set')){
603 @ini_set('memory_limit', $mb_str);
604 }
605 }
606
607 }
608
609 // Pagelayer the content
610 function pagelayer_the_content($content, $dump = false){
611 global $pagelayer;
612
613 $content = pagelayer_sanitize_content( $content );
614 $content = do_blocks( $content );
615 $content = do_shortcode( $content );
616
617 if($dump){
618 preg_match_all('/<div ([^>]*)pagelayer-id="([^"]*)"([^>]*)>/', $content, $matches);
619
620 foreach($matches[0] as $k => $div){
621 $id = $matches[2][$k];
622
623 if(empty($pagelayer->data_attr[$id])){
624 continue;
625 }
626
627 $data_attr = '<!-- '.pagelayer_serialize_attributes($pagelayer->data_attr[$id]).' -->';
628 $content = str_replace($div, $div.$data_attr, $content);
629 }
630 }
631
632 return $content;
633 }
634
635 function pagelayer_create_id(){
636 return pagelayer_RandomString(3).rand(1000, 9999);
637 }
638
639 // Loads the shortcodes
640 function pagelayer_load_shortcodes(){
641 global $pagelayer, $post;
642
643 if(!empty($pagelayer->shortcode_loaded)){
644 return;
645 }
646
647 pagelayer_memory_limit(128);
648
649 // We have loaded
650 $pagelayer->shortcode_loaded = 1;
651
652 do_action('pagelayer_before_load_shortcodes');
653
654 // pQuery
655 include_once(PAGELAYER_DIR.'/lib/pquery/IQuery.php');
656 include_once(PAGELAYER_DIR.'/lib/pquery/gan_formatter.php');
657 include_once(PAGELAYER_DIR.'/lib/pquery/gan_node_html.php');
658 include_once(PAGELAYER_DIR.'/lib/pquery/gan_tokenizer.php');
659 include_once(PAGELAYER_DIR.'/lib/pquery/gan_parser_html.php');
660 include_once(PAGELAYER_DIR.'/lib/pquery/gan_selector_html.php');
661 include_once(PAGELAYER_DIR.'/lib/pquery/gan_xml2array.php');
662 include_once(PAGELAYER_DIR.'/lib/pquery/pQuery.php');
663
664 include_once(PAGELAYER_DIR.'/main/shortcode_functions.php');
665
666 // Apply filter to load custom widgets functions
667 do_action('pagelayer_load_shortcode_functions');
668
669 include_once(PAGELAYER_DIR.'/main/shortcodes.php');
670
671 // Apply filter to load custom widgets
672 do_action('pagelayer_load_custom_widgets');
673
674 // Render Pagelayer element by blocks
675 add_action('pre_render_block', 'pagelayer_render_blocks', 10, 2);
676
677 // Add global widget data
678 if(defined('PAGELAYER_PREMIUM') && !pagelayer_is_gutenberg_editor()){
679
680 // Get global widget templates id by type
681 $args = [
682 'post_type' => $pagelayer->builder['name'],
683 'status' => 'publish',
684 'meta_key' => 'pagelayer_template_type',
685 'meta_value' => array('global_widget', 'section', 'global_section'),
686 'posts_per_page' => -1
687 ];
688
689 $query = new WP_Query($args);
690
691 $tmp_list = [];
692 $global_widgets = array();
693 $global_widgets['global_widget'] = array();
694 $global_widgets['section'] = array();
695 $global_widgets['global_section'] = array();
696
697 foreach($query->posts as $template){
698
699 // The type
700 $pagelayer_template_type = get_post_meta($template->ID, 'pagelayer_template_type', true);
701
702 $global_data = [];
703 $global_data['post_id'] = $template->ID;
704 $global_data['title'] = $template->post_title;
705 $global_data['$'] = pagelayer_the_content($template->post_content, true);
706 $global_widgets[$pagelayer_template_type][$template->ID] = $global_data;
707
708 }
709
710 $pagelayer->global_widgets = $global_widgets['global_widget'];
711 $pagelayer->saved_sections = $global_widgets['section'];
712 $pagelayer->global_sections = $global_widgets['global_section'];
713 }
714
715 do_action('pagelayer_after_load_shortcodes');
716 }
717
718 // Add the shortcodes to the pagelayer list
719 function pagelayer_add_shortcode($tag, $params = array()){
720
721 global $pagelayer, $post;
722
723 if($tag == 'pl_row'){
724 $inner_tag = 'pl_inner_row';
725 add_shortcode($inner_tag, 'pagelayer_render_shortcode');
726 }
727
728 if($tag == 'pl_col'){
729 $inner_tag = 'pl_inner_col';
730 add_shortcode($inner_tag, 'pagelayer_render_shortcode');
731 }
732
733 add_shortcode($tag, 'pagelayer_render_shortcode');//$params['func']);
734 //unset($params['func']);
735
736 // Is there a group ?
737 if(empty($params['group'])){
738 $params['group'] = 'misc';
739 }
740
741 // Add the advanced styling group
742 $params['options'] = [
743 'ele_bg_styles' => __pl('ele_bg_styles'),
744 'ele_styles' => __pl('ele_styles'),
745 'border_styles' => __pl('border_styles'),
746 'font_style' => __pl('font_style'),
747 'position_styles' => __pl('position_styles'),
748 'animation_styles' => __pl('animation_styles'),
749 'motion_effects' => __pl('Motion Effects'),
750 'responsive_styles' => __pl('responsive_styles'),
751 'attributes' => __pl('attributes'),
752 'custom_styles' => __pl('custom_styles'),
753 ];
754
755 if(!empty($params['skip_props_cat'])){
756 foreach($params['skip_props_cat'] as $k => $v){
757 unset($params['options'][$v]);
758 }
759 }
760
761 // Are the settings there which hold the params ?
762 if(empty($params['settings'])){
763 $params['settings'] = [
764 'params' => $params['name'],
765 ];
766 }
767
768 // Disable the style options
769 if(!empty($params['styles'])){
770 $params['settings'] = array_merge($params['settings'], $params['styles']);
771 unset($params['styles']);
772 }
773
774 /*// The following is for testing only
775 $r = [];
776 foreach($pagelayer->styles as $k => $v){
777 foreach($v as $kk => $vv){
778 $r[$kk] = $kk;
779 }
780 }
781 //print_r($r);die();
782
783 foreach($params['settings'] as $k => $v){
784 if(empty($params[$k])) continue;
785 foreach($params[$k] as $kk => $vv){
786 if(!empty($r[$kk])){
787 echo 'Duplicate KEY '.$kk.' in Shortcode '.$tag."<br>";
788 }
789 }
790 }
791 //die();*/
792
793 $params = apply_filters( 'pagelayer_shortcode_params', $params, $tag );
794
795 // Insert the shortcode
796 $pagelayer->shortcodes[$tag] = $params;
797 $pagelayer->groups[$params['group']][] = $tag;
798
799 // Export the default values
800 foreach($pagelayer->tabs as $tab){
801
802 if(empty($pagelayer->shortcodes[$tag][$tab])){
803 continue;
804 }
805
806 foreach($pagelayer->shortcodes[$tag][$tab] as $section => $Lsection){
807
808 $props = empty($pagelayer->shortcodes[$tag][$section]) ? @$pagelayer->styles[$section] : @$pagelayer->shortcodes[$tag][$section];
809
810 //echo $tab.' - '.$section.' - <br>';
811
812 if(empty($props)){
813 continue;
814 }
815
816 // Save customizer params
817 if( $tag == 'pl_customizer' ){
818 $pagelayer->customizer_params = array_merge($pagelayer->customizer_params, $props);
819 }
820
821 foreach($props as $prop => $param){
822
823 // Set default values to export for JS
824 if(isset($param['export-def']) && isset($param['default']) && $param['export-def'] == 1){
825 $pagelayer->default_params[$tag][$prop] = $param['default'];
826 }
827
828 }
829 }
830 }
831 }
832
833 // Add a freemium shortcode i.e. available for render, but not to drag or edit
834 function pagelayer_freemium_shortcode($tag, $params = array()){
835
836 // If we are the free version, we just allow render and some edits
837 if(!defined('PAGELAYER_PREMIUM')){
838
839 $params['not_visible'] = 1;
840 $params['freemium'] = 1;
841
842 $cats = empty($params['styles']) ? array() : $params['styles'];
843
844 if(!empty($params['settings'])){
845 $cats = array_merge($cats, $params['settings']);
846 }
847
848 $cats['params'] = $params['name'];
849 //pagelayer_print($cats);
850
851 foreach($cats as $k => $v){
852 if(empty($params[$k])) continue;
853
854 foreach($params[$k] as $kk => $vv){
855
856 if(empty($params[$k][$kk]['np'])){
857 $params[$k][$kk]['pro'] = 1;
858 }
859
860 }
861
862 }
863
864 }
865
866 return pagelayer_add_shortcode($tag, $params);
867 }
868
869 // Returns the permalink values
870 function pagelayer_permalink($id){
871
872 if(is_numeric($id)){
873 $id = (int) @$id;
874 $perma = get_permalink($id);
875
876 if(!empty($perma)){
877 $id = $perma;
878 }
879 }
880
881 $id = apply_filters('pagelayer_permalink', $id);
882
883 return $id;
884 }
885
886 // Returns the Image values
887 function pagelayer_image($id = 0){
888
889 global $pagelayer;
890
891 $ret = [];
892
893 if(!empty($id) && is_array($id)){
894
895 foreach($id as $key => $image){
896 $attachment = pagelayer_image(@$image);
897 if(!empty($attachment)){
898 foreach($attachment as $k => $v){
899 if($key == 'retina'){
900 $ret['retina-'.$k] = $v;
901 }else if($key == 'retina_mobile'){
902 $ret['retina-mobile-'.$k] = $v;
903 }else{
904 $ret[$k] = $v;
905 }
906 }
907 }
908 }
909
910 return $ret;
911 }
912
913 // External image ?
914 if(pagelayer_is_external_img($id)){
915
916 $ret['url'] = $id;
917
918 // Attachment
919 }elseif(!empty($id)){
920
921 $id = (int) @$id;
922
923 $image = get_post($id);
924
925 // Is there an attachment which is an image ?
926 if(!empty($image) && $image->post_type == 'attachment' && wp_attachment_is_image($id)){
927
928 // Need to export necessary media
929 if(!empty($pagelayer->export_mode)){
930 $pagelayer->media_to_export[] = $id;
931 }
932
933 $sizes = get_intermediate_image_sizes();
934 array_unshift($sizes, 'full');
935
936 foreach($sizes as $size){
937 $src = wp_get_attachment_image_src($id, $size);
938 $ret[$size.'-url'] = $src[0];
939 }
940
941 // Title and Alt
942 $title = esc_attr($image->post_title);
943 $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
944 $alt = empty($alt) ? $image->post_excerpt : $alt;
945 $alt = empty($alt) ? $image->post_title : $alt;
946 $alt = empty($alt) ? '' : esc_attr(trim(strip_tags($alt)));
947 $link = get_attachment_link($id);
948 $caption = wp_get_attachment_caption($id);
949 $caption = !empty($caption) ? esc_attr($caption) : '';
950
951 }
952
953 }
954
955 // First preference to full url
956 if(!empty($ret['full-url'])){
957 $ret['url'] = $ret['full-url'];
958 }
959
960 // No image
961 if(empty($ret['url'])){
962 $ret['url'] = PAGELAYER_URL.'/images/default-image.png';
963 }
964
965 // Extract filename without extension
966 $filename = pathinfo($ret['url'], PATHINFO_FILENAME);
967
968 // Skip title if same as filename
969 $title = (!empty($title) && $title != $filename) ? $title : '';
970
971 $ret['alt'] = @$alt;
972 $ret['title'] = @$title;
973 $ret['link'] = @$link;
974 $ret['caption'] = @$caption;
975
976 $ret = apply_filters('pagelayer_image', $ret);
977
978 if(pagelayer_is_default_img($ret['url'])){
979 $ret['no-image-set'] = 1;
980 }
981
982 return $ret;
983
984 }
985
986 // Checks if the given parameter is an external link or a wp attachment id
987 function pagelayer_is_external_img($img = ''){
988
989 if(empty($img)){
990 return false;
991 }
992
993 if(preg_match('#http://#is', $img) || preg_match('#https://#is', $img) || preg_match('#^{{#is', $img)){
994 return true;
995 }
996
997 return false;
998
999 }
1000
1001 // Checks if the given parameter is the default image
1002 function pagelayer_is_default_img($img){
1003
1004 if($img == PAGELAYER_URL.'/images/default-image.png'){
1005 return true;
1006 }
1007
1008 return false;
1009
1010 }
1011
1012 // Returns the attachment url
1013 function pagelayer_attachment($id){
1014
1015 $ret = [];
1016
1017 // External url ?
1018 if(pagelayer_is_external_img($id)){
1019
1020 $ret['url'] = $id;
1021
1022 // Attachment
1023 }elseif(!empty($id)){
1024
1025 // Need to export necessary media
1026 if(!empty($pagelayer->export_mode)){
1027 $pagelayer->media_to_export[] = $id;
1028 }
1029
1030 $ret['url'] = wp_get_attachment_url($id);
1031
1032 }
1033
1034 $ret = apply_filters('pagelayer_attachment', $ret);
1035
1036 return $ret;
1037
1038 }
1039
1040 // Convert the regular URL of a Video to a Embed URL
1041 // Todo : Check
1042 function pagelayer_video_url($source, $no_url = false){
1043
1044 global $pagelayer;
1045
1046 if (!empty($source)) {
1047
1048 $source = esc_url( $source );
1049 $source = str_replace('&amp;', '&', $source);
1050 $url = parse_url($source);
1051 $videoSite ='';
1052 $videoId ='';
1053 $vid_atts = [];
1054
1055 $youtubeRegExp = '/youtube\.com|youtu\.be/is';
1056 $vimeoRegExp = '/vimeo\.com/is';
1057
1058 if (preg_match($youtubeRegExp, $source)) {
1059 $videoSite = 'youtube';
1060 } else if (preg_match($vimeoRegExp, $source)) {
1061 $videoSite = 'vimeo';
1062 }
1063
1064 switch ($videoSite) {
1065 case 'youtube':
1066
1067 $pagelayer->append_yt_api = true;
1068
1069 if (preg_match('/youtube\.com/is', $source)) {
1070
1071 if (preg_match('/watch/is', $source)) {
1072 parse_str($url['query'], $parameters);
1073
1074 if (isset($parameters['v']) && !empty($parameters['v'])) {
1075 $videoId = $parameters['v'];
1076 }
1077
1078 } else if (preg_match('/embed/is', $url['path'])) {
1079 $path = explode('/', $url['path']);
1080 if (isset($path[2]) && !empty($path[2])) {
1081 $videoId = $path[2];
1082 }
1083 }
1084
1085 } else if (preg_match('/youtu\.be/is', $url['host'])) {
1086 $path = explode('/', $url['path']);
1087
1088 if (isset($path[1]) && !empty($path[1])) {
1089 $videoId = $path[1];
1090 }
1091
1092 }
1093
1094 $vid_atts['type'] = 'youtube';
1095 $vid_atts['src'] = '//www.youtube.com/embed/'.$videoId;
1096 $vid_atts['id'] = $videoId;
1097
1098 break;
1099 case 'vimeo':
1100
1101 if (preg_match('/player\.vimeo\.com/is', $url['host']) && preg_match('/video/is', $url['path'])) {
1102 $path = explode('video/', $source);
1103 } else if (preg_match('/vimeo\.com/is', $url['host'])) {
1104 $path = explode('.com/', $source);
1105 }
1106
1107 if(isset($path[1]) && !empty($path[1])) {
1108 $videoId = $path[1];
1109 }
1110
1111 $vid_atts['type'] = 'vimeo';
1112 $vid_atts['src'] = '//player.vimeo.com/video/'.$videoId;
1113 $vid_atts['id'] = $videoId;
1114
1115 break;
1116 default:
1117
1118 $vid_atts['type'] = 'local';
1119 $vid_atts['src'] = $source;
1120 $vid_atts['id'] = $videoId;
1121
1122 }
1123
1124 if(!$no_url){
1125 return $vid_atts['src'];
1126 }
1127
1128 return $vid_atts;
1129
1130 }
1131 }
1132
1133
1134 // As per the JS specification
1135 function pagelayer_escapeHTML($str){
1136
1137 $replace = [
1138 ']' => '&#93;',
1139 '[' => '&#91;',
1140 //'=' => '&#61;',
1141 '<' => '&lt;',
1142 '>' => '&gt;',
1143 '"' => '&quot;',
1144 //'&' => '&amp;',
1145 '\'' => '&#39;',
1146 '\\' => '&#92;'
1147 ];
1148
1149 $str = str_replace(array_keys($replace), array_values($replace), $str);
1150
1151 return $str;
1152 }
1153
1154 // As per the JS specification
1155 function pagelayer_unescapeHTML($str){
1156 $replace = [
1157 '#93' => ']',
1158 '#91' => '[',
1159 //'#61' => '=',
1160 'lt' => '<',
1161 'gt' => '>',
1162 'quot' => '"',
1163 //'amp' => '&',
1164 '#39' => '\'',
1165 '#92' => '\\'
1166 ];
1167
1168 foreach($replace as $k => $v){
1169 $str = str_replace('&'.$k.';', $v, $str);
1170 }
1171 return $str;
1172 }
1173
1174 // Converts a Unicode code point to its UTF-8 encoded string.
1175 function pagelayer_codepoint_to_utf8($num) {
1176 if ($num < 0x80) {
1177 return chr($num);
1178 } elseif ($num < 0x800) {
1179 return chr(0xC0 | ($num >> 6))
1180 . chr(0x80 | ($num & 0x3F));
1181 } elseif ($num < 0x10000) {
1182 return chr(0xE0 | ($num >> 12))
1183 . chr(0x80 | (($num >> 6) & 0x3F))
1184 . chr(0x80 | ($num & 0x3F));
1185 } elseif ($num < 0x110000) {
1186 return chr(0xF0 | ($num >> 18))
1187 . chr(0x80 | (($num >> 12) & 0x3F))
1188 . chr(0x80 | (($num >> 6) & 0x3F))
1189 . chr(0x80 | ($num & 0x3F));
1190 }
1191 return '';
1192 }
1193
1194 // To make decode entities faster
1195 function pagelayer_optimized_decode_entities($string, $req = true) {
1196
1197 // Fast replace common HTML entities
1198 $common_entities_map = [
1199 '&#93;' => ']', '&#91;' => '[', '&lt;' => '<', '&gt;' => '>', '&amp;' => '&', '&quot;' => '"', '&#39;' => "'",
1200 '&copy;' => '©', '&reg;' => '®', '&ndash;' => '', '&mdash;' => '', '&bull;' => '',
1201 '&hellip;' => '', '&lsquo;' => '', '&rsquo;' => '', '&ldquo;' => '', '&rdquo;' => ''
1202 ];
1203
1204 // Replace common entities first for performance
1205 $string = str_replace(array_keys($common_entities_map), array_values($common_entities_map), $string);
1206
1207 // Return early if no encoded entities exist
1208 if(!preg_match('/\\\\u[0-9a-fA-F]{4}|&#x[0-9a-fA-F]+;|&#\d+;/', $string)) {
1209 return $string;
1210 }
1211
1212 $string = preg_replace_callback(
1213 '/\\\\u([0-9a-fA-F]{4})|&#x([0-9a-fA-F]+);|&#([0-9]+);/',
1214 function ($matches) {
1215 if (!empty($matches[1])) {
1216 // Decode \uXXXX Unicode sequences
1217 return pagelayer_codepoint_to_utf8( hexdec($matches[1]) );
1218 }elseif (!empty($matches[2])) {
1219 // Decode hexadecimal HTML entities (&#x6A; → j)
1220 return pagelayer_codepoint_to_utf8( hexdec($matches[2]) );
1221 } elseif (!empty($matches[3])) {
1222 // Decode decimal HTML entities (&#106; → j)
1223 return pagelayer_codepoint_to_utf8( (int)$matches[3] );
1224 }
1225 return $matches[0];
1226 },
1227 $string
1228 );
1229
1230 // Additional decoding to cover remaining cases
1231 if($req){
1232 $string = pagelayer_optimized_decode_entities($string, false);
1233 }
1234
1235 return $string;
1236 }
1237
1238 // Return true if user can add js content
1239 function pagelayer_user_can_add_js_content(){
1240
1241 // Unfiltered_html cap needs to be checked for multisite
1242 if(current_user_can('unfiltered_html')){
1243 return true;
1244 }
1245
1246 $pagelayer_js_permission = get_option('pagelayer_js_permission');
1247 $current_user = wp_get_current_user();
1248
1249 // If not allowed any role by admin
1250 if(empty($pagelayer_js_permission) || empty($current_user->roles)){
1251 return false;
1252 }
1253
1254 foreach($current_user->roles as $role){
1255 if(in_array($role, $pagelayer_js_permission)){
1256 return true;
1257 }
1258 }
1259
1260 return false;
1261 }
1262
1263 // Check for XSS codes in our shortcodes submitted
1264 function pagelayer_xss_content($data){
1265
1266 $data = pagelayer_optimized_decode_entities($data);
1267
1268 $data = preg_split('/\s/', $data);
1269 $data = implode('', $data);
1270 //echo $data;
1271
1272 if(preg_match('/["\']javascript\:/is', $data)){
1273 return 'javascript';
1274 }
1275
1276 if(preg_match('/["\']vbscript\:/is', $data)){
1277 return 'vbscript';
1278 }
1279
1280 if(preg_match('/\-moz\-binding\:/is', $data)){
1281 return '-moz-binding';
1282 }
1283
1284 if(preg_match('/expression\(/is', $data)){
1285 return 'expression';
1286 }
1287
1288 if(preg_match('/\<(iframe|frame|script|style|link|applet|embed|xml|svg|object|layer|ilayer|meta)/is', $data, $matches)){
1289 return $matches[1];
1290 }
1291
1292 // These events not start with on
1293 $not_allowed = array('click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'load', 'unload', 'change', 'submit', 'reset', 'select', 'blur', 'focus', 'keydown', 'keypress', 'keyup', 'afterprint', 'beforeprint', 'beforeunload', 'error', 'hashchange', 'message', 'offline', 'online', 'pagehide', 'pageshow', 'popstate', 'resize', 'storage', 'contextmenu', 'input', 'invalid', 'search', 'mousewheel', 'wheel', 'drag', 'dragend', 'dragenter', 'dragleave', 'dragover', 'dragstart', 'drop', 'scroll', 'copy', 'cut', 'paste', 'abort', 'canplay', 'canplaythrough', 'cuechange', 'durationchange', 'emptied', 'ended', 'loadeddata', 'loadedmetadata', 'loadstart', 'pause', 'play', 'playing', 'progress', 'ratechange', 'seeked', 'seeking', 'stalled', 'suspend', 'timeupdate', 'volumechange', 'waiting', 'toggle', 'animationstart', 'animationcancel', 'animationend', 'animationiteration', 'auxclick', 'beforeinput', 'beforematch', 'beforexrselect', 'compositionend', 'compositionstart', 'compositionupdate', 'contentvisibilityautostatechange', 'focusout', 'focusin', 'fullscreenchange', 'fullscreenerror', 'gotpointercapture', 'lostpointercapture', 'mouseenter', 'mouseleave', 'pointercancel', 'pointerdown', 'pointerenter', 'pointerleave', 'pointermove', 'pointerout', 'pointerover', 'pointerrawupdate', 'pointerup', 'scrollend', 'securitypolicyviolation', 'touchcancel', 'touchend', 'touchmove', 'touchstart', 'transitioncancel', 'transitionend', 'transitionrun', 'transitionstart', 'MozMousePixelScroll', 'DOMActivate', 'afterscriptexecute', 'beforescriptexecute', 'DOMMouseScroll', 'willreveal', 'gesturechange', 'gestureend', 'gesturestart', 'mouseforcechanged', 'mouseforcedown', 'mouseforceup', 'mouseforceup', 'beforetoggle', 'selectstart', 'selectionchange');
1294
1295 $not_allowed = implode('|', $not_allowed);
1296
1297 if(preg_match('/(on|onwebkit)+('.($not_allowed).')=/is', $data, $matches)){
1298 return $matches[1].$matches[2];
1299 }
1300
1301 return;
1302
1303 }
1304
1305 // Check for XSS codes in our blocks array
1306 function pagelayer_sanitize_blocks_save_pre($block){
1307
1308 foreach($block as $k => $v){
1309
1310 // Recurse on arrays
1311 if(is_array($v)){
1312 $block[$k] = pagelayer_sanitize_blocks_save_pre($v);
1313
1314 // We dont support objects !
1315 }elseif(is_object($v)){
1316 $block[$k] = null;
1317 // Strings
1318 }else{
1319
1320 if(is_string($v)){
1321
1322 $v = wp_filter_post_kses($v);
1323
1324 while(true){
1325 $str = '"'.($v);
1326 $found = pagelayer_xss_content($str);
1327 //echo (string)$v.'--'.$found."\n";
1328
1329 if(strlen($found) > 0){
1330 // There is htmlentities?
1331 if(strpos($v, $found) === false){
1332 $v = '';
1333 break;
1334 }
1335 $v = str_replace($found, '', $v);
1336 }else{
1337 break;
1338 }
1339
1340 }
1341
1342 }
1343
1344 $block[$k] = $v;
1345 }
1346
1347 }
1348
1349 return $block;
1350 }
1351
1352 // Check for XSS codes in our shortcode attributes
1353 function pagelayer_sanitize_shortcode_atts($content){
1354
1355 // Do we have something suspicious ?
1356 $tmp_check = pagelayer_xss_content($content);
1357 if(empty($tmp_check)){
1358 return $content;
1359 }
1360
1361 pagelayer_load_shortcodes();
1362
1363 preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER );
1364
1365 $prefixes = ['pl_'];
1366
1367 $prefixes = apply_filters( 'pagelayer_valid_shortcode_tag', $prefixes);
1368
1369 foreach ($matches as $shortcode) {
1370
1371 $shortcode_name = $shortcode[2];
1372
1373 $vailid = false;
1374
1375 foreach($prefixes as $prefix) {
1376 if (strpos($shortcode_name, $prefix) === 0) {
1377 $vailid = true;
1378 break;
1379 }
1380 }
1381
1382 if(!$vailid){
1383 continue;
1384 }
1385
1386 $attrs = shortcode_parse_atts( $shortcode[3] );
1387 $atts = ' ';
1388
1389 foreach($attrs as $key => $value){
1390
1391 // Skip if key contains XSS
1392 if (!is_numeric($key) && strlen(pagelayer_xss_content($key . '=')) > 0) continue;
1393
1394 $value = wp_filter_post_kses($value);
1395
1396 // Skip if value contains XSS
1397 if (strlen(pagelayer_xss_content('"' . $value)) > 0) continue;
1398
1399 $atts .= is_numeric($key) ? $value . ' ' : $key . '="' . $value . '" ';
1400
1401 }
1402
1403 $new_shortcode = '[' . $shortcode_name . $atts . ']';
1404
1405 if(!empty($shortcode[5])){
1406 $new_shortcode .= $shortcode[5].'[/' . $shortcode_name .']';
1407 }
1408
1409 // Replace the original shortcode with sanitized attributes
1410 $content = str_replace($shortcode[0], $new_shortcode, $content);
1411 }
1412
1413 return $content;
1414 }
1415
1416 function pagelayer_getting_started_notice(){
1417
1418 // Is Sitepad setup done?
1419 $setup_done = get_option('sp_setup_done');
1420
1421 if(defined('SITEPAD') && empty($setup_done)){
1422 return;
1423 }
1424
1425 // If SitePad used custom BRAND SM
1426 if(defined('BRAND_SM_CUSTOM')){
1427 return;
1428 }
1429
1430 echo '
1431 <script type="application/javascript">
1432 jQuery(document).ready(function(){
1433 jQuery("#pagelayer-getting-started-notice").click(function(e){
1434
1435 if(jQuery(e.target).hasClass("notice-dismiss")){
1436 var data;
1437 jQuery("#pagelayer-getting-started-notice").hide();
1438 // Save this preference
1439 jQuery.post("'.admin_url('?pagelayer-getting-started=0&pagelayer_nonce='.wp_create_nonce("pagelayer_getting_started_nonce") ).'", data, function(response) {
1440 //alert(response);
1441 });
1442 return false;
1443 }
1444
1445 });
1446 });
1447 </script>
1448
1449 <div id="pagelayer-getting-started-notice" class="notice notice-success is-dismissible">
1450 <p style="font-size: 14px; font-weight: 600">';
1451 if(defined('SITEPAD')){
1452
1453 echo '<a href="'.BRAND_SM_URL.'"><img src="'.BRAND_SM_LOGO .'" style="vertical-align: middle; margin:0px 10px" width="24" /></a>'.__('Thanks for choosing '.BRAND_SM .'. We recommend that you see the short and sweet <a href="'.admin_url('admin.php?page=pagelayer_getting_started').'">Getting Started Video</a> to know the basics of '.BRAND_SM.'.');
1454
1455 }else{
1456
1457 echo '<a href="'.PAGELAYER_WWW_URL.'"><img src="'.PAGELAYER_URL.'/images/pagelayer-logo-256.png" style="vertical-align: middle; margin:0px 10px" width="24" /></a>'.__('Thanks for choosing Pagelayer. We recommend that you see the short and sweet <a href="'.admin_url('admin.php?page=pagelayer_getting_started').'">Getting Started Video</a> to know the basics of Pagelayer.', 'pagelayer');
1458
1459 }
1460
1461 echo '</p>
1462 </div>';
1463
1464 }
1465
1466 // Show Changelog promo
1467 function pagelayer_show_changelog_notice(){
1468
1469 // Is Sitepad setup done?
1470 if(defined('SITEPAD')){
1471 return;
1472 }
1473
1474 echo '
1475 <script type="application/javascript">
1476 jQuery(document).ready(function(){
1477 jQuery("#pagelayer-changelog-notice").click(function(e){
1478
1479 if(jQuery(e.target).hasClass("notice-dismiss")){
1480 var data;
1481 jQuery("#pagelayer-changelog-notice").hide();
1482 // Save this preference
1483 jQuery.post("'.admin_url('?pagelayer-changelog-notice=0&pagelayer_nonce='.wp_create_nonce("pagelayer_changelog_nonce") ).'", data, function(response) {
1484 //alert(response);
1485 });
1486 return false;
1487 }
1488
1489 });
1490 });
1491 </script>
1492
1493 <div id="pagelayer-changelog-notice" class="notice notice-info is-dismissible">
1494 <p style="font-size: 14px; font-weight: 600">
1495 <a href="'.PAGELAYER_WWW_URL.'"><img src="'.PAGELAYER_URL.'/images/pagelayer-logo-256.png" style="vertical-align: middle; margin:0px 10px" width="24" /></a>'.__('Empower Your Designs: Pagelayer 1.8.1 - Unleashing Seamless Integration with Gutenberg for Enhanced Website Creation! <a href="'.PAGELAYER_WWW_URL.'/blog/reinventing-pagelayer-for-gutenberg-a-seamless-fusion-of-powerful-page-building-and-wordpress-editor/">Read More</a>.', 'pagelayer') .'
1496 </p>
1497 </div>';
1498
1499 }
1500
1501 // Show promo notice on dashboard
1502 function pagelayer_show_promo(){
1503
1504 global $pagelayer_promo_opts;
1505 $opts = $pagelayer_promo_opts;
1506
1507 echo '<style>
1508 #pagelayer_promo a.pagelayer_promo_button {
1509 background-color: #4CAF50 !important;
1510 border: none !important;
1511 color: white !important;
1512 padding: 6px 10px !important;
1513 text-align: center !important;
1514 text-decoration: none !important;
1515 display: inline-block !important;
1516 font-size: 13px !important;
1517 margin: 4px 2px !important;
1518 -webkit-transition-duration: 0.4s;
1519 transition-duration: 0.4s;
1520 cursor: pointer !important;
1521 }
1522 #pagelayer_promo a.pagelayer_promo_button:focus,
1523 #pagelayer_promo a.pagelayer_promo_button:hover{
1524 border: none !important;
1525 color: white !important;
1526 box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19) !important;
1527 }
1528 #pagelayer_promo a.pagelayer_promo_buy {
1529 color: white !important;
1530 padding: 8px 12px !important;
1531 font-size: 14px !important;
1532 background-color: #4CAF50 !important;
1533 }
1534 #pagelayer_promo a.pagelayer_promo_button1 {
1535 color: white !important;
1536 background-color: #4CAF50 !important;
1537 border:3px solid #4CAF50 !important;
1538 }
1539 #pagelayer_promo a.pagelayer_promo_button1:hover {
1540 border:3px solid #4CAF50 !important;
1541 }
1542 #pagelayer_promo a.pagelayer_promo_button2 {
1543 color: white !important;
1544 background-color: #0085ba !important;
1545 }
1546 #pagelayer_promo a.pagelayer_promo_button3 {
1547 color: white !important;
1548 background-color: #365899 !important;
1549 }
1550 #pagelayer_promo a.pagelayer_promo_button4 {
1551 color: white !important;
1552 background-color: rgb(66, 184, 221) !important;
1553 }
1554 #pagelayer_promo a.pagelayer_promo-close{
1555 float:right !important;
1556 text-decoration:none !important;
1557 margin: 5px 10px 0px 0px !important;
1558 color: #666 !important;
1559 }
1560 #pagelayer_promo a.pagelayer_promo-close:hover{
1561 color: red !important;
1562 }
1563 #pagelayer_promo a:not(.pagelayer_promo_button):not(.pagelayer_promo-close) {
1564 color: #4CAF50 !important;
1565 text-decoration: underline !important;
1566 }
1567 #pagelayer_promo a:not(.pagelayer_promo_button):not(.pagelayer_promo-close):hover {
1568 color: #3e8e41 !important;
1569 }
1570 </style>
1571 <script type="application/javascript">
1572 jQuery(document).ready(function(){
1573 jQuery("#pagelayer_promo .pagelayer_promo-close").click(function(){
1574 var data;
1575 jQuery("#pagelayer_promo").hide();
1576 // Save this preference
1577 jQuery.post("'.admin_url('?pagelayer_promo=0').'", data, function(response) {
1578 //alert(response);
1579 });
1580 });
1581 });
1582 </script>
1583
1584 <div class="notice notice-success" id="pagelayer_promo" style="min-height:90px">
1585 <a class="pagelayer_promo-close" href="javascript:" aria-label="Dismiss this Notice">
1586 <span class="dashicons dashicons-dismiss"></span> Dismiss
1587 </a>';
1588
1589 if(!empty($opts['image'])){
1590 echo '<a href="'.$opts['website'].'"><img src="'.$opts['image'].'" style="float:left; margin:10px 20px 10px 10px" width="67" /></a>';
1591 }
1592
1593 echo '
1594 <p style="font-size:13px">We are glad you like <a href="'.$opts['website'].'"><b>Pagelayer</b></a> and have been using it since the past few days. It is time to take the next step !</p>
1595 <p>
1596 '.(empty($opts['pro_url']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_buy" target="_blank" href="'.$opts['pro_url'].'">Buy Pagelayer Pro</a>').'
1597 '.(empty($opts['rating']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button2" target="_blank" href="'.$opts['rating'].'">Rate it 5�
1598 \'s</a>').'
1599 '.(empty($opts['facebook']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button3" target="_blank" href="'.$opts['facebook'].'"><span class="dashicons dashicons-thumbs-up"></span> Facebook</a>').'
1600 '.(empty($opts['twitter']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button4" target="_blank" href="'.$opts['twitter'].'"><span class="dashicons dashicons-twitter"></span> Tweet</a>').'
1601 '.(empty($opts['website']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button4" target="_blank" href="'.$opts['website'].'">Visit our website</a>').'
1602 </p>
1603 <p style="font-size:13px"><a href="'.$opts['pro_url'].'"><b>Pagelayer Pro</b></a> has many more features like 60+ widgets, 400+ sections, Theme Builder, WooCommerce Builder, Theme Creator and Exporter, Form Builder, Popup Builder, etc.';
1604
1605 if(date('Ymd') <= 20200331){
1606 echo '<br><span style="font-size: 14px"><b>Promotional Offer</b></span> : If you buy <a href="'.$opts['pro_url'].'"><b>Pagelayer Pro</b></a> before <b>31st March, 2020</b> then you will get an additional year free and your license will expire on <b>31st March, 2022</b>.';
1607 }
1608
1609 echo '</p></div>';
1610
1611 }
1612
1613 // Are we to show a promo ?
1614 function pagelayer_maybe_promo($opts){
1615
1616 global $pagelayer_promo_opts;
1617
1618 // There must be an interval
1619 if(!current_user_can('activate_plugins')){
1620 return false;
1621 }
1622
1623 // There must be an interval
1624 if(empty($opts['interval'])){
1625 return false;
1626 }
1627
1628 // Are we to show a promo
1629 $opt_name = 'pagelayer_promo_time';
1630 $promo_time = get_option($opt_name);
1631
1632 // First time access
1633 if(empty($promo_time)){
1634 update_option($opt_name, time() + (!empty($opts['after']) ? $opts['after'] * 86400 : 0));
1635 $promo_time = get_option($opt_name);
1636 }
1637
1638 // Is there interval elapsed
1639 if(time() > $promo_time){
1640 $pagelayer_promo_opts = $opts;
1641 add_action('admin_notices', 'pagelayer_show_promo');
1642 }
1643
1644 // Are we to disable the promo
1645 if(isset($_GET['pagelayer_promo']) && (int)$_GET['pagelayer_promo'] == 0){
1646 update_option($opt_name, time() + ($opts['interval'] * 86400));
1647 die('DONE');
1648 }
1649
1650 }
1651
1652 // Show the Pro notice
1653 function pagelayer_show_pro_notice(){
1654
1655 if(defined('PAGELAYER_PREMIUM')){
1656 return;
1657 }
1658
1659 echo '<div class="pagelayer-notice pagelayer-notice-info">'.__('This feature is a part of <a href="'.PAGELAYER_PRO_PRICE_URL.'" target="_blank">Pagelayer Pro</a>. You will need to purchase <a href="'.PAGELAYER_PRO_PRICE_URL.'" target="_blank">Pagelayer Pro</a> to use this feature.').'</div>';
1660
1661 }
1662
1663 // Show the Pro Div
1664 function pagelayer_show_pro_div($head = '', $message = '', $admin_css = 1){
1665
1666 if(defined('PAGELAYER_PREMIUM')){
1667 return;
1668 }
1669
1670 if(basename(get_template_directory()) == 'popularfx'){
1671 $pro_url = 'https://popularfx.com/pricing?from=pagelayer-plugin';
1672 $pro_txt = 'PopularFX Pro';
1673 }else{
1674 $pro_url = PAGELAYER_PRO_PRICE_URL;
1675 $pro_txt = 'Pagelayer Pro';
1676 }
1677
1678 if(!empty($admin_css)){
1679 wp_enqueue_style( 'pagelayer-admin', PAGELAYER_CSS.'/pagelayer-admin.css', array(), PAGELAYER_VERSION);
1680 }
1681
1682 echo '<div class="pagelayer-pro-div">';
1683
1684 if(!empty($head)){
1685 echo '<h1 class="pagelayer-pro-head">'.$head.'</h1>';
1686 }
1687
1688 echo '<div class="pagelayer-pro-message">';
1689
1690 if(empty($message)){
1691
1692 echo __('This feature is a part of <a href="'.$pro_url.'" target="_blank">'.$pro_txt.'</a>. You will need to purchase <a href="'.$pro_url.'" target="_blank">'.$pro_txt.'</a> to use this feature.');
1693
1694 }else{
1695
1696 echo $message;
1697 echo ' '.__('This feature is a part of <a href="'.$pro_url.'" target="_blank">'.$pro_txt.'</a>.');
1698
1699 }
1700
1701 echo '</div>
1702 <center><a class="button-pagelayer" href="'.$pro_url.'" target="_blank" style="text-decoration: none;">'.sprintf(__('Upgrade to %s', 'pagelayer'), $pro_txt).'</a></center>
1703 </div>';
1704
1705 }
1706
1707 // Bread Crumbs with links
1708 function pagelayer_get_breadcrumb(){
1709 global $post;
1710
1711 // Home page
1712 $ret = '<a href="'.home_url().'" rel="nofollow">{{home}}</a>';
1713
1714 // Is Front page
1715 if(is_front_page()){
1716 return $ret;
1717
1718 // Is search query
1719 }elseif(is_search()){
1720 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><b class="pagelayer-breadcrumb-prefix" if="{{search_prefix}}">{{search_prefix}}</b>';
1721 $ret .= '<em>';
1722 $ret .= '<span>'.get_search_query().'</span>';
1723 $ret .= '</em>';
1724
1725 //Is category or single post
1726 }elseif(is_category() || is_single()){
1727
1728 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
1729 $categories = get_the_category();
1730 $separator = ' ';
1731 $output = '';
1732 if(!empty($categories)){
1733 $ret .= get_category_parents($categories[0], true, ' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b> ');
1734 }
1735 if(is_single()) {
1736 /* if (empty($categories)){
1737 $ret .= ' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b> ';
1738 } */
1739 $ret .= '<span>'.get_the_title().'</span>';
1740 }
1741
1742 // Is page
1743 }elseif(is_page() ){
1744 if(!empty($post->post_parent)){
1745 $ancestors = array_reverse(get_post_ancestors( $post->ID ));
1746 $page_on_front = get_option('page_on_front');
1747
1748 foreach( $ancestors as $ancestor ){
1749
1750 if($page_on_front == $ancestor){
1751 continue;
1752 }
1753
1754 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><a href="'.get_permalink($ancestor).'">'.get_the_title($ancestor).'</a>';
1755 }
1756
1757 $ret .=' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><span>'.get_the_title().'</span>';
1758
1759 }else{
1760 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
1761 $ret .= '<span>'.get_the_title().'</span>';
1762 }
1763 }else{
1764 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
1765 $ret .= '<span>'.wp_title('', false ).'</span>';
1766 }
1767
1768 // wooCommerce Integration left
1769
1770 return $ret;
1771 }
1772
1773 // Portfolio Posts
1774 function pagelayer_widget_posts($args){
1775
1776 $r = new \WP_Query($args);
1777
1778 $ret = '';
1779 if ( $r->have_posts() ){
1780
1781 if($args['filter_by'] != 'none' && $args['post_type'] == 'post'){
1782 $ret .= '<div class="pagelayer-postfolio-filter">';
1783
1784 $data_filter = ( $args['filter_by'] == 'category' ? get_categories() : get_tags() );
1785
1786 if(!empty($data_filter)){
1787
1788 $ret .= '<div class="pagelayer-postfolio-btn" data-filter="all">'.__pl('All').'</div>';
1789
1790 foreach($data_filter as $filter) {
1791 $ret .= '<div class="pagelayer-postfolio-btn" data-filter="'.$filter->name.'">' . $filter->name . '</div>';
1792 }
1793
1794 }
1795
1796 $ret .= '</div>';
1797 }
1798
1799 $ret .= '<div class="pagelayer-postfolio-container">';
1800
1801 while ( $r->have_posts() ) : $r->the_post();
1802 $post_meta = ( $args['filter_by'] == 'category' ? get_the_category() : get_the_tags() );
1803 $meta_attr = '';
1804 if($post_meta){
1805
1806 $meta_array = array();
1807 foreach( $post_meta as $meta ){
1808 $meta_array[] = $meta->name;
1809 }
1810 $meta_attr .= ' data-category="'.implode(' ', $meta_array).'"';
1811 }
1812
1813 $ret .= '<div class="pagelayer-postfolio-thumb"'.(has_post_thumbnail() ? ' style="background:url('.get_the_post_thumbnail_url().')"' : ''). $meta_attr .'>';
1814 $ret .= '<a href="'.esc_url( get_permalink() ).'" rel="bookmark">';
1815 $ret .= '<div class="pagelayer-postfolio-content">';
1816 $ret .= '<h4 class="pagelayer-entry-title">'.get_the_title().'</h4>';
1817 $ret .= '</div></a></div>';
1818
1819 endwhile;
1820
1821 $ret .= '</div>';
1822
1823 }
1824
1825 return $ret;
1826 }
1827
1828 // List all available sizes of images registered on WordPress
1829 function pagelayer_image_sizes(){
1830
1831 $sizes = array();
1832 $sizes = get_intermediate_image_sizes();
1833 $ret = array();
1834 foreach($sizes as $size){
1835 $ret[$size] = __pl($size);
1836 }
1837
1838 return $ret;
1839 }
1840
1841 function pagelayer_remove_excerpt_more($more){
1842 return '';
1843 }
1844
1845 function pagelayer_posts($params, $args = []){
1846 global $post, $wp_query;
1847
1848 if(isset($params['exc_length'])){
1849 $exc_length = (int) $params['exc_length'];
1850 add_filter( 'excerpt_length', function($length) use($exc_length){
1851 return $exc_length;
1852 }, 999 );
1853 }
1854
1855 // add_filter('excerpt_more', 'pagelayer_remove_excerpt_more', 999);
1856
1857 // If args is empty
1858 if(empty($args)){
1859 $args = array(
1860 'post_type' => $params['post_type'],
1861 'posts_per_page' => $params['posts_per_page'],
1862 'order' => $params['order']
1863 );
1864
1865 if(!empty($params['paged'])){
1866 $args['paged'] = $params['paged'];
1867 }
1868
1869 if (!empty($params['term']) || !empty($params['exc_term'])) {
1870 $tax_query = [];
1871
1872 if (!empty($params['term'])) {
1873 $terms = explode(',', $params['term']);
1874 $include = array_reduce($terms, function ($carry, $term) {
1875 list($taxonomy, $slug, $id) = explode(':', $term);
1876 $carry[$taxonomy][] = $slug;
1877 return $carry;
1878 }, []);
1879
1880 $filters = array_filter([
1881 isset($include['category']) ? [
1882 'taxonomy' => 'category',
1883 'field' => 'slug',
1884 'terms' => $include['category'],
1885 'include_children' => false,
1886 ] : null,
1887 isset($include['post_tag']) ? [
1888 'taxonomy' => 'post_tag',
1889 'field' => 'slug',
1890 'terms' => $include['post_tag'],
1891 'include_children' => false,
1892 ] : null,
1893 ]);
1894
1895 if(!empty($filters)){
1896 $tax_query[] = array_merge(['relation' => 'OR'], $filters);
1897 }
1898 }
1899
1900 // Handle exclusions
1901 if (!empty($params['exc_term'])) {
1902 $terms = explode(',', $params['exc_term']);
1903 $include = array_reduce($terms, function ($carry, $term) {
1904 list($taxonomy, $slug, $id) = explode(':', $term);
1905 $carry[$taxonomy][] = $slug;
1906 return $carry;
1907 }, []);
1908
1909 $filters = array_filter([
1910 isset($include['category']) ? [
1911 'taxonomy' => 'category',
1912 'field' => 'slug',
1913 'terms' => $include['category'],
1914 'operator' => 'NOT IN',
1915 'include_children' => false,
1916 ] : null,
1917 isset($include['post_tag']) ? [
1918 'taxonomy' => 'post_tag',
1919 'field' => 'slug',
1920 'terms' => $include['post_tag'],
1921 'operator' => 'NOT IN',
1922 'include_children' => false,
1923 ] : null,
1924 ]);
1925
1926 if(!empty($filters)){
1927 $tax_query[] = array_merge(['relation' => 'AND'], $filters);
1928 }
1929 }
1930
1931 // Apply the combined tax_query
1932 if(!empty($tax_query)){
1933 $args['tax_query'] = array_merge(['relation' => 'AND'], $tax_query);
1934 }
1935 }
1936
1937 if(!empty($params['author_name'])){
1938 $author_name = explode(':', $params['author_name']);
1939 $args['author_name'] = $author_name[0];
1940 }
1941
1942 if(!empty($params['exc_author'])){
1943 $exc_author = explode(':', $params['exc_author']);
1944 $args['author'] = '-'.$exc_author[1];
1945 }
1946
1947 if (!empty($params['offset'])) {
1948 $args['offset'] = (int) $params['offset'];
1949
1950 // Make Compatible for Infinite load
1951 if(!empty($params['infinite_types']) && !empty($params['paged']) && $params['paged'] > 1 ){
1952 $args['offset'] = $args['offset'] + (($params['paged'] - 1) * $params['posts_per_page']);
1953 }
1954 }
1955
1956 if(!empty($params['ignore_sticky'])){
1957 $args['ignore_sticky_posts'] = $params['ignore_sticky'];
1958 }
1959
1960 if(!empty($params['orderby'])){
1961 $args['orderby'] = $params['orderby'];
1962 }
1963
1964 if(!empty($params['by_period'])){
1965 $date_arg = array();
1966 switch($params['by_period']){
1967 case 'last_day':
1968 $date_arg['day'] = date('j')-1;
1969 break;
1970 case 'last_week':
1971 $date_arg['week'] = date('W')-1;
1972 break;
1973 case 'last_month':
1974 $date_arg['month'] = date('n')-1;
1975 break;
1976 case 'last_year':
1977 $date_arg['year'] = date('Y')-1;
1978 break;
1979 case 'custom':
1980 $date_arg['before'] = $params['before_date'];
1981 $date_arg['after'] = $params['after_date'];
1982 break;
1983 }
1984 $args['date_query'] = array(
1985 $date_arg
1986 );
1987 }
1988 }
1989 //pagelayer_print($args);
1990
1991 // Only see published posts
1992 $args['post_status'] = 'publish';
1993
1994 $postsquery = new WP_Query($args);
1995 $data = '';
1996
1997 if(!wp_doing_ajax() && !empty($params['infinite_types'])){
1998 $data.='<div class="pagelayer-post-max" data-max="'.$postsquery->max_num_pages.'"></div>';
1999 }
2000
2001 if(!$postsquery->have_posts()){
2002 return '<h3>No posts found!</h3>';
2003 }
2004
2005 // To reset the post when the $wp_query->post is empty
2006 $orig_post = $post;
2007
2008 while($postsquery->have_posts()) : $postsquery->the_post();
2009 $data .= '<div class="pagelayer-wposts-col">
2010 <div class="pagelayer-wposts-post">
2011 <div class="pagelayer-wposts-featured">';
2012 $data .= '<a href="'. get_the_permalink() .'">';
2013
2014 if(!empty($params['show_thumb'])){
2015 $data .= '<div class="pagelayer-wposts-thumb" style="background:url('.(has_post_thumbnail($postsquery->ID) ? get_the_post_thumbnail_url($postsquery->ID, $params['thumb_size']) : ( empty($params['thumb_img_type']) || empty($params['def_thumb_img']) ? PAGELAYER_URL.'/images/no_screenshot.png' : $params['def_thumb_img']) ).')"></div>';
2016 }
2017 /* if($params['show_thumb'] && has_post_thumbnail( $postsquery->ID )){
2018 $data .= get_the_post_thumbnail_url($postsquery->ID,$params['thumb_size']);
2019 } */
2020 $data .= '</a></div>
2021 <div class="pagelayer-wposts-content">';
2022
2023 if(!empty($params['show_title'])){
2024 $data .= '<a href="'.esc_url( get_permalink() ).'" rel="bookmark"><div class="pagelayer-wposts-title">'. get_the_title().'</div></a>';
2025 }
2026
2027 $data .= '<div class="pagelayer-wposts-meta">';
2028 $sep = '';
2029 if(!empty($params['meta_sep'])){
2030 $sep = ' <b class="pagelayer-wposts-sep">'.$params['meta_sep'].'</b> ';
2031 }
2032 if(!empty($params['author'])){
2033 $data .= '<span class="pagelayer-wposts-author">By <a class="pagelayer-wposts-author-url" href="'.esc_url(get_author_posts_url(get_the_author_meta('ID'))).'">'.esc_html(get_the_author()).'</a></span>'.$sep;
2034 }
2035 if(!empty($params['date'])){
2036 $data .= '<span class="pagelayer-wposts-date"><time class="pagelayer-wposts-entry-date published updated" datetime="'.get_the_date('c').'"><span class="date-d">'.get_the_date('j').'</span> <span class="date-my">'.get_the_date('M, y').'</span></time></span>'.$sep;
2037 }
2038
2039 if(!empty($params['category'])){
2040 $category = get_the_category();
2041 $singlecategory = '';
2042 foreach( $category as $cat ){
2043 $singlecategory .= '<a href="' . get_tag_link( $cat->term_id ) . '">'. $cat->name .'</a>';
2044 }
2045
2046 if(!empty($singlecategory)){
2047 $data .= '<span class="pagelayer-wposts-category">' . $singlecategory . '</span>'.$sep;
2048 }
2049
2050 }
2051
2052 if(!empty($params['tags'])){
2053 $tags = get_the_tags();
2054 $singletag = '';
2055 if(!empty($tags)){
2056 foreach( $tags as $tag ){
2057 $singletag .= '<a href="' . get_tag_link( $tag->term_id ) . '">'. $tag->name .'</a>';
2058 }
2059 if(!empty($singletag)){
2060 $data .= '<span class="pagelayer-wposts-tags">'.$singletag.'</span>'.$sep;
2061 }
2062 }
2063
2064 }
2065
2066 if(!empty($params['comments']) && comments_open($postsquery->ID)){
2067 $data .= '<span class="pagelayer-wposts-comments"><a href="' . esc_url( get_permalink() ) . '">' . esc_html(get_comments_number()).' '.__pl('comments').'</a></span>'.$sep;
2068 }
2069
2070 $data .= '</div>';
2071
2072 if(!empty($params['show_content'])){
2073 $data .= '<div class="pagelayer-wposts-excerpt">';
2074
2075 if($params['show_content'] == 'excerpt'){
2076 $post_excerpt = get_the_excerpt();
2077 $trimmed_excerpt = !empty($params['exc_length']) ? wp_trim_words($post_excerpt, (int) $params['exc_length']) : $post_excerpt;
2078 $data .= pagelayer_the_content($trimmed_excerpt);
2079 } elseif ($params['show_content'] == 'full') {
2080 $data .= pagelayer_the_content(get_the_content());
2081 }
2082 $data .= '</div>';
2083 }
2084
2085 if(!empty($params['show_more'])){
2086 $data .= '<div class="pagelayer-wposts-mdiv"><a class="pagelayer-wposts-more pagelayer-btn-holder pagelayer-ele-link '.$params['btn_type'].' '.$params['size'].' '.$params['icon_position'].'" href="'. get_the_permalink().'">';
2087
2088 if($params['icon']){
2089 $data .= '<i class="'.$params['icon'].' pagelayer-btn-icon"></i>';
2090 }
2091
2092 if($params['more']){
2093 $data .= '<span class="pagelayer-btn-text">'.$params['more'].'</span>';
2094 }
2095
2096 if($params['icon']){
2097 $data .= '<i class="'.$params['icon'].' pagelayer-btn-icon"></i>';
2098 }
2099
2100 $data .= '</a></div>';
2101
2102 //$data .= '<a class="pagelayer-wposts-more" href="'. get_the_permalink().'">'.$params['more'].'</a>';
2103 }
2104
2105 //$data .= '<div class="pagelayer-wposts-date"><p>'.get_the_date().'</p></div>';
2106 $data .= '</div></div></div>';
2107 endwhile;
2108
2109 // In the Gutenberg while adding new page the $wp_query->post was empty
2110 if ( !isset( $wp_query ) || empty($wp_query->post) ) {
2111 $GLOBALS['post'] = $orig_post;
2112 }else{
2113 wp_reset_postdata();
2114 }
2115
2116 return $data;
2117 }
2118
2119 // Get Post Revision
2120 function pagelayer_get_post_revision_by_id($postID){
2121
2122 // Insert the post revision into the database
2123 $post_revisions = array();
2124 $reviews = wp_get_post_revisions($postID);
2125
2126 foreach($reviews as $values){
2127
2128 $date_format = date_i18n('j-M @ H:i', strtotime( $values->post_modified ) );
2129 $user_meta = get_userdata($values->post_author);
2130
2131 if ( false !== strpos( $values->post_name, 'autosave' ) ) {
2132 $type = 'autosave';
2133 } else {
2134 $type = 'revision';
2135 }
2136
2137 $post_tmp_data = array(
2138 'ID' => $values->ID,
2139 'post_author_name' => $user_meta->data->display_name,
2140 'post_author_url' => get_avatar_url($values->post_author),
2141 'post_date' => $date_format,
2142 'post_date_ago' => human_time_diff(strtotime($values->post_modified), current_time( 'timestamp' )) . ' ago ',
2143 'post_type' => $type,
2144 );
2145
2146 $post_revisions[] = $post_tmp_data;
2147 }
2148
2149 return $post_revisions;
2150 }
2151
2152 // Gets author data
2153 function pagelayer_author_data($postID){
2154
2155 $authorID = get_post_field('post_author', $postID);
2156 $data['display_name'] = get_the_author_meta( 'display_name' , $authorID );
2157 $data['description'] = get_the_author_meta( 'description' , $authorID );
2158 $data['user_url'] = get_author_posts_url( $authorID , '' );
2159 $data['avatar'] = get_avatar_url( $authorID );
2160
2161 return $data;
2162 }
2163
2164 // Posts Slider
2165 function pagelayer_posts_slider($params){
2166
2167 $args = array();
2168
2169 if(isset($params['post']['post_type'])){
2170 $args['post_type'] = $params['post']['post_type'];
2171 }
2172
2173 if(isset($params['post']['category'])){
2174 $args['category_name'] = $params['post']['category'];
2175 }
2176
2177 if(isset($params['post']['tags'])){
2178 $args['tag'] = $params['post']['tags'];
2179 }
2180
2181 if(isset($params['post']['order_by'])){
2182 $args['orderby'] = $params['post']['order_by'];
2183 }
2184
2185 if(isset($params['post']['sort_order'])){
2186 $args['order'] = $params['post']['sort_order'];
2187 }
2188
2189 if(isset($params['post']['post_count'])){
2190 $args['posts_per_page'] = $params['post']['post_count'];
2191 }
2192
2193 $data = '';
2194 $postsquery = new WP_Query($args);
2195 if ( $postsquery->have_posts() ){
2196 while ( $postsquery->have_posts() ) : $postsquery->the_post();
2197 $data .= '<li class="pagelayer-posts-slider-col">
2198 <div class="pagelayer-posts-slider-post">
2199 <div class="pagelayer-posts-slider-featured-img">';
2200 $data .= '<a href="'. get_the_permalink() .'">';
2201 if(has_post_thumbnail( $postsquery->ID ) ){
2202 if($params['post']['image_size'] == "full" || $params['post']['image_size'] == "custom" ){
2203 $image = wp_get_attachment_image_src( get_post_thumbnail_id( $postsquery->ID ), 'single-post-thumbnail' );
2204 $data .= '<img class="pagelayer-img" src="'.$image[0].'" class="pagelayer-posts-slider-img">';
2205 }else if($params['post']['image_size'] == "thumbnail"){
2206 $data .= get_the_post_thumbnail();
2207 }
2208 }
2209 $data .= '</a></div>
2210 <div class="pagelayer-posts-slider-content">';
2211 $data .= '<p class="pagelayer-posts-slider-title">'. get_the_title().'</p>';
2212 $data .= '<div class="pagelayer-posts-slider-excerpt">';
2213 if($params['post']['show_excerpt'] == "true"){
2214 if(has_excerpt()){
2215 $excerpt = get_the_excerpt();
2216 $data .= pagelayer_the_content($excerpt);
2217 }
2218 }
2219 $data .= '</div>';
2220 $data .= '<a class="pagelayer-posts-slider-link" href="'. get_the_permalink().'">Read More</a>';
2221 $data .= '<div class="pagelayer-post-slider-date"><p>'.get_the_date().'</p></div>';
2222 $data .= '</div></div></li>';
2223 endwhile;
2224 }
2225 return $data;
2226 }
2227
2228 // Gets the site logo URLs
2229 function pagelayer_site_logo(){
2230
2231 if(get_theme_mod('custom_logo')){
2232 $logo_id = get_theme_mod('custom_logo');
2233 return pagelayer_image($logo_id);
2234 }
2235
2236 return NULL;
2237 }
2238
2239 // Create select options
2240 function pagelayer_create_sel_options( $opt_array , $selected = ''){
2241 $options = '';
2242 foreach($opt_array as $x => $val){
2243
2244 // Single item
2245 if(is_string($opt_array[$x])){
2246 $options .= pagelayer_sel_option($x, $val, $selected);
2247
2248 // Groups
2249 }else{
2250
2251 if(array_key_exists('hide_drop', $opt_array[$x]) && !empty($opt_array[$x]['hide_drop'])){
2252 continue;
2253 }
2254
2255 // If Label is there, then its a normal option
2256 if(array_key_exists('label', $opt_array[$x])){
2257 $options .= pagelayer_sel_option($x, $opt_array[$x]['label'], $selected);
2258
2259 // Optgroups
2260 } else{
2261 $options .= '<optgroup label="'. $x .'">';
2262 $options .= pagelayer_create_sel_options($opt_array[$x], $selected);
2263 $options .= '</optgroup>';
2264 }
2265 }
2266 }
2267
2268 return $options;
2269 }
2270
2271 // Create option HTML
2272 function pagelayer_sel_option($val, $lang, $selected){
2273 return '<option value="'. $val .'" '. (($val != $selected) ? '' : 'selected="selected"') .' >'. $lang .'</option>';
2274 }
2275
2276 // Get values from multi-dimensional array by key
2277 function pagelayer_multi_array_search(&$array, $key){
2278
2279 if(!is_array($array)){
2280 return false;
2281 }
2282
2283 foreach ($array as $k => $v) {
2284
2285 if($k == $key){
2286 return $v;
2287 }
2288
2289 if (is_array($v)) {
2290 $found = pagelayer_multi_array_search($v, $key);
2291 if(!empty($found)){
2292 return $found;
2293 }
2294 }
2295 }
2296
2297 return false;
2298 }
2299
2300 function pagelayer_get_post_term(){
2301
2302 $args = [
2303 'taxonomy' => array('category','post_tag'),
2304 'hide_empty' => false,
2305 ];
2306
2307 $terms = get_terms( $args );
2308
2309 $ret = array();
2310 foreach ( $terms as $term ) {
2311 $ret[$term->taxonomy.':'.$term->slug.':'.$term->term_taxonomy_id] = $term->taxonomy .': '. $term->name;
2312 }
2313 //pagelayer_print($terms);die();
2314 return $ret;
2315 }
2316
2317 function pagelayer_get_post_author(){
2318
2319 $args = [
2320 'capability' => array( 'edit_posts' ),
2321 'fields' => [
2322 'ID',
2323 'display_name',
2324 'user_nicename',
2325 ]
2326 ];
2327
2328 // Capability queries were only introduced in WP 5.9.
2329 if( version_compare( $GLOBALS['wp_version'], '5.9-alpha', '<' ) ){
2330 $args['who'] = 'authors';
2331 unset( $args['capability'] );
2332 }
2333
2334 $authors = new \WP_User_Query( $args );
2335
2336 $ret = array();
2337 foreach ( $authors->get_results() as $author ) {
2338 $ret[$author->user_nicename.':'.$author->ID] = $author->display_name;
2339 }
2340 //pagelayer_print($authors->get_results());die();
2341 return $ret;
2342 }
2343
2344 // Gets the registered post types
2345 function pagelayer_get_public_post_types( $args = [] ) {
2346
2347 global $pagelayer;
2348
2349 $post_type_args = [
2350 'public' => true,
2351 ];
2352
2353 $post_type_args = wp_parse_args( $post_type_args, $args );
2354
2355 $_post_types = get_post_types( $post_type_args, 'objects' );
2356
2357 $post_types = array();
2358
2359 foreach ( $_post_types as $post_type => $object ) {
2360
2361 if($post_type == $pagelayer->builder['name']){
2362 continue;
2363 }
2364
2365 $post_types[ $post_type ] = $object->label;
2366 }
2367 //print_r($post_types);
2368
2369 return $post_types;
2370 }
2371
2372 // Simply echo and dir
2373 function pagelayer_json_output(&$done){
2374
2375 echo json_encode($done);
2376 wp_die();
2377
2378 }
2379
2380 // Get the current query for render the product
2381 function pagelayer_shortcode_current_query($query_args, $atts, $type){
2382 global $wp_query;
2383
2384 if($type == 'pagelayer_current_query'){
2385
2386 if ( ! is_page( wc_get_page_id( 'shop' ) ) ) {
2387 $query_args = $wp_query->query_vars;
2388 }
2389
2390 add_action( "woocommerce_shortcode_before_{$type}_loop", function () {
2391 wc_set_loop_prop( 'is_shortcode', false );
2392 } );
2393
2394 if(!empty($atts['paginate'])){
2395 $page = get_query_var( 'paged', 1 );
2396
2397 if( 1 < $page ) {
2398 $query_args['paged'] = $page;
2399 }
2400 }
2401
2402 // Always query only IDs
2403 $query_args['fields'] = 'ids';
2404
2405 }
2406
2407 return $query_args;
2408 }
2409
2410 // Loads the tags which have parameters of a particular type
2411 function pagelayer_get_prop_type($types){
2412
2413 global $pagelayer;
2414
2415 if(!is_array($types)){
2416 $types = [$types];
2417 }
2418
2419 $ret = [];
2420
2421 // Loop thru all shortcodes
2422 foreach($pagelayer->shortcodes as $tag => $vvv){
2423
2424 // Lets create the CSS, Classes, Attr. Also clean the dependent atts
2425 foreach($pagelayer->tabs as $tab){
2426
2427 if(empty($pagelayer->shortcodes[$tag][$tab])){
2428 continue;
2429 }
2430
2431 foreach($pagelayer->shortcodes[$tag][$tab] as $section => $Lsection){
2432
2433 $props = empty($pagelayer->shortcodes[$tag][$section]) ? @$pagelayer->styles[$section] : @$pagelayer->shortcodes[$tag][$section];
2434
2435 //echo $tab.' - '.$section.' - <br>';
2436
2437 if(empty($props)){
2438 continue;
2439 }
2440
2441 // Loop all props
2442 foreach($props as $prop => $param){
2443
2444 // Load any attachment values
2445 if(!in_array($param['type'], $types)){
2446 continue;
2447 }
2448
2449 $ret[$tag][$prop] = $param['type'];
2450
2451 }
2452
2453 }
2454
2455 }
2456
2457 }
2458
2459 //r_print($ret);die();
2460
2461 return $ret;
2462
2463 }
2464
2465 function pagelayer_export_content($content){
2466
2467 global $pagelayer;
2468
2469 // Just call do_shortcode so we can get list of media files to export
2470 //do_shortcode($content);
2471
2472 $theme_url = preg_replace('/http(s?):\/\//is', '', get_stylesheet_directory_uri());
2473
2474 $content = preg_replace('/http(s?):\/\/'.preg_quote($theme_url, '/').'/is', '{{theme_url}}', $content);
2475
2476 // Remove unnecessary spaces
2477 $content = preg_replace('/--\>\s*(?!<!--)/is', '-->', $content);
2478
2479 // Replace links of the theme for images
2480 $content = pagelayer_export_theme_links($content, get_stylesheet_directory_uri());
2481
2482 ////////////////////
2483 // Handle Link IDs
2484 ////////////////////
2485
2486 if(empty($pagelayer->e['link_tags'])){
2487 $pagelayer->e['link_tags'] = pagelayer_get_prop_type('link');
2488 //r_print($pagelayer->e['link_tags']);die();
2489 }
2490
2491 if(empty($pagelayer->e['media_tags'])){
2492 $pagelayer->e['media_tags'] = pagelayer_get_prop_type(['image', 'video', 'audio', 'media', 'multi_image']);
2493 //r_print($pagelayer->e['media_tags']);die();
2494 }
2495
2496 $parsed = parse_blocks($content);
2497 //r_print($parsed);//die();
2498
2499 $parsed = pagelayer_export_link_ids($parsed);
2500
2501 // Export the media as well
2502 $parsed = pagelayer_export_media($parsed);
2503
2504 // Reserialize
2505 $content = serialize_blocks($parsed);
2506
2507 // We store in SP format
2508 $content = str_replace('<!-- wp:pagelayer', '<!-- sp:pagelayer', $content);
2509 $content = str_replace('<!-- /wp:pagelayer', '<!-- /sp:pagelayer', $content);
2510
2511 // Just pass the content to
2512 $content = pagelayer_export_extract_menu_ids($content);
2513
2514 // Apply a filter
2515 $content = apply_filters('pagelayer_export_content', $content);
2516
2517 return $content;
2518
2519 }
2520
2521 // Export the menu IDs
2522 function pagelayer_export_extract_menu_ids($content){
2523
2524 global $pagelayer;
2525
2526 // Any Menu ?
2527 preg_match_all('/\[pl_wp_menu ([^\]]*)nav_list="(\d*)"([^\]]*)\]/is', $content, $matches);
2528 //r_print($matches);
2529
2530 if(!empty($matches[2])){
2531
2532 foreach($matches[2] as $k => $v){
2533 $v = (int)$v;
2534 $pagelayer->export_menus[$v] = $v;
2535 }
2536 //r_print($pagelayer->export_menus);
2537
2538 }
2539
2540 // Also for block format
2541 preg_match_all('/<!--\s+(?P<closer>\/)?sp:pagelayer\/pl_wp_menu\s+(?P<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*+)?}\s+)?(?P<void>\/)?-->/s', $content, $matches);
2542
2543 if(!empty($matches['attrs'])){
2544
2545 foreach($matches['attrs'] as $k => $v){
2546 preg_match('/nav_list"\s*:\s*"(\d*)"/is', $v, $vmatch);
2547
2548 if(!empty($vmatch[1])){
2549 $vmatch[1] = (int)$vmatch[1];
2550 $pagelayer->export_menus[$vmatch[1]] = $vmatch[1];
2551 //r_print($pagelayer->export_menus);
2552 }
2553 }
2554 }
2555
2556 return $content;
2557
2558 }
2559
2560 function pagelayer_export_link_ids($parsed){
2561
2562 global $pagelayer;
2563
2564 foreach($parsed as $k => $v){
2565
2566 if(!empty($v['innerBlocks'])){
2567 $parsed[$k]['innerBlocks'] = pagelayer_export_link_ids($v['innerBlocks']);
2568 }
2569
2570 if(!preg_match('/pagelayer/is', $v['blockName'])){
2571 continue;
2572 }
2573
2574 $tag = str_replace('pagelayer/', '', $v['blockName']);
2575 //echo $tag;//die();
2576
2577 // Is there a tag having a link prop
2578 if(empty($pagelayer->e['link_tags'][$tag])){
2579 continue;
2580 }
2581 //echo $tag;die();
2582
2583 foreach($pagelayer->e['link_tags'][$tag] as $kk => $vv){
2584 if(!empty($v['attrs'][$kk]) && is_numeric($v['attrs'][$kk])){
2585 $linked = get_post($v['attrs'][$kk]);
2586 if(!empty($linked->post_name)){
2587 $parsed[$k]['attrs'][$kk] = '||link_id|'.$linked->post_type.'|'.$linked->post_name.'||';
2588 }
2589 //echo $tag;echo '-'.$kk;r_print($parsed[$k]['attrs']);die();
2590 }
2591 }
2592
2593 }
2594
2595 return $parsed;
2596
2597 }
2598
2599 // Replace theme links with theme_url
2600 function pagelayer_export_theme_links($content, $link){
2601
2602 global $sitepad;
2603
2604 // Theme URL correction code
2605 $theme_url = preg_replace('/http(s?):\/\//is', '', $link);
2606
2607 $theme_urls[0] = 'http://'.$theme_url;
2608 $theme_urls[1] = 'https://'.$theme_url;
2609 $theme_urls[2] = $theme_url;
2610 $theme_urls[3] = str_replace('/', '\\/', $theme_urls[0]);
2611 $theme_urls[4] = str_replace('/', '\\/', $theme_urls[1]);
2612 $theme_urls[5] = str_replace('/', '\\/', $theme_url);
2613
2614 foreach($theme_urls as $k => $v){
2615 $content = preg_replace_callback('/'.preg_quote($v, '/').'([^"]*)/is', 'pagelayer_export_theme_links_replacer', $content);
2616 }
2617
2618 $content = str_ireplace($theme_urls, '{{theme_url}}', $content);
2619
2620 return $content;
2621 }
2622
2623 // This function is a part of pagelayer_export_theme_links
2624 function pagelayer_export_theme_links_replacer($matches){
2625 return '{{theme_url}}'.str_replace('\\/', '/', $matches[1]);
2626 }
2627
2628 // Export media
2629 function pagelayer_export_media($parsed){
2630
2631 global $pagelayer;
2632
2633 foreach($parsed as $k => $v){
2634
2635 if(!empty($v['innerBlocks'])){
2636 $parsed[$k]['innerBlocks'] = pagelayer_export_media($v['innerBlocks']);
2637 }
2638
2639 if(!preg_match('/pagelayer/is', $v['blockName'])){
2640 continue;
2641 }
2642
2643 $tag = str_replace('pagelayer/', '', $v['blockName']);
2644 //echo $tag;//die();
2645
2646 // Is there a tag having a link prop
2647 if(empty($pagelayer->e['media_tags'][$tag])){
2648 continue;
2649 }
2650 //echo $tag;die();
2651
2652 foreach($pagelayer->e['media_tags'][$tag] as $kk => $vv){
2653
2654 if(empty($v['attrs'][$kk])){
2655 continue;
2656 }
2657
2658 $is_array = 0;
2659
2660 // Is it an array
2661 if(is_array($v['attrs'][$kk])){
2662
2663 $ids = $v['attrs'][$kk];
2664 $is_array = 1;
2665
2666 // Is it of the format 1,2,3
2667 }elseif(preg_match('/^((\d*)(,?))*$/is', $v['attrs'][$kk])){
2668
2669 $ids = pagelayer_maybe_explode(',', $v['attrs'][$kk]);
2670
2671 // Its a number or string
2672 }else{
2673
2674 // Is it our default image ?
2675 if(preg_match('/pagelayer-pro\/images\/default-image.png$/is', $v['attrs'][$kk])){
2676 $parsed[$k]['attrs'][$kk] = '';
2677 continue;
2678 }
2679
2680 // It should be a number
2681 if(!is_numeric($v['attrs'][$kk])){
2682 continue;
2683 }
2684
2685 $ids = [$v['attrs'][$kk]];
2686 }
2687
2688 $ret = [];
2689
2690 foreach($ids as $id){
2691
2692 $file = pagelayer_export_media_files($id, $exp_img_url);
2693
2694 // Did it export ?
2695 if(empty($file) || !file_exists($file)){
2696 continue;
2697 }
2698
2699 $ret[] = $exp_img_url;
2700
2701 }
2702
2703 $parsed[$k]['attrs'][$kk] = $is_array ? $ret : implode(',', $ret);
2704 //echo $tag;echo '-'.$kk;r_print($parsed[$k]['attrs']);die();
2705 }
2706
2707 }
2708
2709 return $parsed;
2710
2711 }
2712
2713 // Exports the media to the images folder of the current theme
2714 function pagelayer_export_media_files($id, &$url = ''){
2715
2716 $theme_dir = get_stylesheet_directory();
2717 $image_dir = $theme_dir.'/images/';
2718 @mkdir($image_dir);
2719
2720 // Get the file path
2721 $file = get_attached_file($id);
2722
2723 if(empty($file) || !file_exists($file)){
2724 return false;
2725 }
2726
2727 $dest_file = $image_dir.basename($file);
2728
2729 // Copy the file
2730 copy($file, $dest_file);
2731
2732 // Replace the text
2733 $url = '{{theme_url}}/images/'.basename($file);
2734
2735 return $dest_file;
2736
2737 //echo $content;
2738 }
2739
2740 // Insert a post which is a Pagelayer Post
2741 function pagelayer_sanitize_content($content){
2742
2743 if(empty($content)){
2744 return $content;
2745 }
2746
2747 // Replace Vars
2748 $template_vars = pagelayer_template_vars();
2749
2750 foreach($template_vars as $key => $val){
2751 $content = str_replace($key, $val, $content);
2752 }
2753
2754 if(defined('PAGELAYER_BLOCK_PREFIX') && PAGELAYER_BLOCK_PREFIX == 'wp'){
2755 $content = str_replace('<!-- sp:pagelayer', '<!-- wp:pagelayer', $content);
2756 $content = str_replace('<!-- /sp:pagelayer', '<!-- /wp:pagelayer', $content);
2757 }
2758
2759 return $content;
2760 }
2761
2762 // Insert a post which is a Pagelayer Post
2763 function pagelayer_insert_content($post, &$ret){
2764
2765 $post = apply_filters('pagelayer_start_insert_content', $post);
2766
2767 $post['post_content'] = pagelayer_sanitize_content($post['post_content']);
2768 //pagelayer_print($post);die();
2769
2770 // Add slashes for safe insert
2771 $post['post_content'] = wp_slash($post['post_content']);
2772
2773 $post = apply_filters('pagelayer_pre_insert_content', $post);
2774
2775 // Now insert / update the post
2776 $ret = wp_insert_post($post);
2777
2778 // Did we save the post ?
2779 if(empty($ret) || is_wp_error($ret)){
2780 return false;
2781 }
2782
2783 // Convert to pagelayer accessed post
2784 if(!add_post_meta($ret, 'pagelayer-data', time(), true)){
2785 update_post_meta($ret, 'pagelayer-data', time());
2786 }
2787
2788 return $ret;
2789
2790 }
2791
2792 // Gets the list of enabled fonts
2793 function pagelayer_enabled_icons(){
2794
2795 $stored_icons = get_option('pagelayer_icons_set');
2796 if(empty($stored_icons)){
2797 update_option('pagelayer_icons_set', ['font-awesome5']);
2798 $stored_icons = get_option('pagelayer_icons_set');
2799 }
2800
2801 return $stored_icons;
2802
2803 }
2804
2805 // Prevent pro activate text for installer
2806 function pagelayer_install_plugin_complete_actions($install_actions, $api, $plugin_file){
2807
2808 if($plugin_file == PAGELAYER_PREMIUM_BASE){
2809 return array();
2810 }
2811
2812 return $install_actions;
2813 }
2814
2815 // Handle hexa to rgba and also remove alpha which is ff
2816 function pagelayer_hex8_to_rgba($val){
2817
2818 // If opacity is ff then discard ff
2819 if(preg_match('/^#([a-f0-9]{6})ff$/is', $val)){
2820 return substr($val, 0, 7);
2821 }
2822
2823 // Lets handle the RGB+opacity
2824 if(preg_match('/#([a-f0-9]{8})$/is', $val)){
2825 $val = pagelayer_hex2rgba($val);
2826 }
2827
2828 return $val;
2829
2830 }
2831
2832 // Convert to RGBA from HEX
2833 function pagelayer_hex2rgba($color){
2834
2835 //Return if no color provided
2836 if(empty($color)){
2837 return;
2838 }
2839
2840 //Sanitize $color if "#" is provided
2841 if ($color[0] == '#'){
2842 $color = substr( $color, 1 );
2843 }
2844
2845 //Check if color has 6 or 3 characters and get values
2846 if (strlen($color) == 8) {
2847 $hex = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
2848 $alpha = $color[6] . $color[7];
2849 //$alpha = '';
2850 } elseif (strlen($color) == 6) {
2851 $hex = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
2852 } elseif ( strlen( $color ) == 3 ) {
2853 $hex = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
2854 } else {
2855 return;
2856 }
2857
2858 //Convert hexadec to rgb
2859 $rgb = array_map('hexdec', $hex);
2860
2861 //Check if opacity is set(rgba or rgb)
2862 if($alpha){
2863
2864 $alpha = number_format((float)hexdec($alpha) / 255, 2, '.', '');
2865 //print_r($alpha);
2866 if(abs($alpha) > 1){
2867 $alpha = 1.0;
2868 }
2869 $output = 'rgba('.implode(",",$rgb).','.$alpha.')';
2870 } else {
2871 $output = 'rgb('.implode(",",$rgb).')';
2872 }
2873
2874 //Return rgb(a) color string
2875 return $output;
2876 }
2877
2878 // Get social URLs
2879 function pagelayer_get_social_urls(){
2880
2881 $urls = array();
2882
2883 $urls['facebook'] = get_option('pagelayer-facebook-url');
2884 $urls['twitter'] = get_option('pagelayer-twitter-url');
2885 $urls['instagram'] = get_option('pagelayer-instagram-url');
2886 $urls['linkedin'] = get_option('pagelayer-linkedin-url');
2887 $urls['youtube'] = get_option('pagelayer-youtube-url');
2888 $urls['google'] = get_option('pagelayer-gplus-url');
2889
2890 foreach($urls as $k => $v){
2891
2892 if(empty($v)){
2893 unset($urls[$k]);
2894 continue;
2895 }
2896
2897 $urls[$k] = esc_url($v);
2898 }
2899
2900 return $urls;
2901 }
2902
2903 function pagelayer_get_option($opt){
2904 $ret = get_option($opt);
2905
2906 $opts = array(
2907 'pagelayer-address' => '1, My Address, My Street, New York City, NY, USA',
2908 'pagelayer-phone' => '+1234567890',
2909 'pagelayer-copyright' => '© '.date('Y').' '.get_option('blogname'),
2910 'pagelayer_cf_to_email' => 'contact@domain.com',
2911 'pagelayer_cf_success' => __pl('cf_success'),
2912 'pagelayer_cf_failed' => __pl('cf_failed'),
2913 );
2914
2915 if(empty($ret)){
2916 return $opts[$opt];
2917 }
2918
2919 return wp_kses_post($ret);
2920 }
2921
2922 // Uploads an image / media
2923 function pagelayer_upload_media($filename, $blob){
2924
2925 if(empty($blob)){
2926 return false;
2927 }
2928
2929 $md5 = md5($blob);
2930
2931 // Do we have this image
2932 $args = array(
2933 'post_type' => 'attachment',
2934 'post_status' => 'inherit',
2935 'meta_query' => array(
2936 array(
2937 'key' => 'pagelayer_image_md5',
2938 'value' => $md5,
2939 )
2940 )
2941 );
2942
2943 $query = new WP_Query($args);
2944
2945 // If we found the image, return
2946 foreach($query->posts as $ck => $cv){
2947 return $cv->ID;
2948 }
2949
2950 $upload = wp_upload_bits($filename, null, $blob);
2951
2952 if( !empty( $upload['error'] ) ) {
2953 return false;
2954 }
2955
2956 $file_path = $upload['file'];
2957 $file_name = basename( $file_path );
2958 $file_type = wp_check_filetype( $file_name, null );
2959 $attachment_title = sanitize_file_name( pathinfo( $file_name, PATHINFO_FILENAME ) );
2960 $wp_upload_dir = wp_upload_dir();
2961
2962 $post_info = array(
2963 'guid' => $wp_upload_dir['url'] . '/' . $file_name,
2964 'post_mime_type'=> $file_type['type'],
2965 'post_title' => $attachment_title,
2966 'post_content' => '',
2967 'post_status' => 'inherit',
2968 );
2969
2970 $attach_id = wp_insert_attachment( $post_info, $file_path, $parent_post_id );
2971 update_post_meta($attach_id, 'pagelayer_image_md5', $md5);
2972
2973 $lib = ABSPATH . 'site-admin/includes/image.php';
2974 $media = ABSPATH . 'site-admin/includes/media.php';
2975 $media = file_exists($media) ? $media : ABSPATH . 'wp-admin/includes/media.php';
2976 $lib = file_exists($lib) ? $lib : ABSPATH . 'wp-admin/includes/image.php';
2977
2978 require_once($media);
2979 require_once($lib);
2980
2981 $attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
2982 wp_update_attachment_metadata( $attach_id, $attach_data );
2983
2984 return $attach_id;
2985
2986 }
2987
2988 // Show the notice of importing the active themes content
2989 function pagelayer_theme_import_notices($return = false){
2990
2991 $theme = wp_get_theme();
2992
2993 $imported = get_option('pagelayer_theme_'.get_template().'_imported');
2994 $show = 0;
2995
2996 // We need to import the content
2997 if(empty($imported) && is_admin() && current_user_can('switch_themes')){
2998 $show = 1;
2999 }
3000
3001 $dismissed = get_option('pagelayer_theme_'.get_template().'_dismissed');
3002
3003 // Is this dismissed
3004 if($dismissed){
3005 $show = 0;
3006 }
3007
3008 //$show = 1;
3009
3010 // Is it the importer page ?
3011 if(!empty($_REQUEST['page']) && $_REQUEST['page'] == 'pagelayer_import'){
3012 $show = 0;
3013 }
3014
3015 // Show the message
3016 if(!empty($show)){
3017 $str = '
3018
3019 <style>
3020 .pagelayer_promo_button {
3021 background-color: #4CAF50; /* Green */
3022 border: none;
3023 color: white;
3024 padding: 6px 10px;
3025 text-align: center;
3026 text-decoration: none;
3027 display: inline-block;
3028 font-size: 13px;
3029 margin: 4px 2px;
3030 -webkit-transition-duration: 0.4s; /* Safari */
3031 transition-duration: 0.4s;
3032 cursor: pointer;
3033 }
3034 .pagelayer_promo_button:focus,
3035 .pagelayer_promo_button:hover{
3036 border: none;
3037 color: white;
3038 box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
3039 color: white;
3040 }
3041 .pagelayer_promo_buy {
3042 color: white;
3043 padding: 8px 12px;
3044 font-size: 14px;
3045 }
3046 .pagelayer_promo_button1 {
3047 color: white;
3048 background-color: #4CAF50;
3049 border:3px solid #4CAF50;
3050 }
3051 .pagelayer_promo_button1:hover {
3052 border:3px solid #4CAF50;
3053 }
3054 .pagelayer_promo_button2 {
3055 color: white;
3056 background-color: #0085ba;
3057 }
3058 .pagelayer_promo_button3 {
3059 color: white;
3060 background-color: #365899;
3061 }
3062 .pagelayer_promo_button4 {
3063 color: white;
3064 background-color: rgb(66, 184, 221);
3065 }
3066 .pagelayer_promo-close{
3067 float:right;
3068 text-decoration:none;
3069 margin: 5px 10px 0px 0px;
3070 }
3071 .pagelayer_promo-close:hover{
3072 color: red;
3073 }
3074 </style>
3075
3076 <script type="application/javascript">
3077 jQuery(document).ready(function(){
3078 jQuery("#pagelayer_promo .pagelayer_promo-close").click(function(){
3079 var data;
3080 jQuery("#pagelayer_promo").hide();
3081 // Save this preference
3082 jQuery.post("'.admin_url('?pagelayer_promo=0').'", data, function(response) {
3083 //alert(response);
3084 });
3085 });
3086 });
3087 </script>
3088
3089 <div class="notice notice-success" id="pagelayer_promo" style="min-height:30px">
3090 <a class="pagelayer_promo-close" href="javascript:" aria-label="Dismiss this Notice">
3091 <span class="dashicons dashicons-dismiss"></span> Dismiss
3092 </a>';
3093
3094 $str .= apply_filters('pagelayer_theme_import_notice_content', '<p>Please click <a href="'.admin_url('admin.php?page=pagelayer_import').'">here</a> to import your themes content</p>').'
3095
3096 </div>';
3097
3098 // Print it
3099 if(empty($return)){
3100 echo $str;
3101 }else{
3102 return $str;
3103 }
3104 }
3105
3106 }
3107
3108 // Parse the array variables
3109 function pagelayer_replace_vars( $string, $array, $pre = '', $suf = ''){
3110
3111 $array = (array) $array;
3112
3113 foreach($array as $kk => $vv){
3114
3115 if(is_array($vv)){
3116 $vv = pagelayer_flat_join($vv);
3117 }
3118
3119 $string = str_replace($pre.$kk.$suf, $vv, $string);
3120 }
3121 return $string;
3122 }
3123
3124 // Add Attachment to the contact the email
3125 function pagelayer_cf_email_attachment( &$phpmailer) {
3126
3127 if ( ! empty( $_FILES ) ) {
3128 foreach ( $_FILES as $attachment ) {
3129
3130 if(empty($attachment['name'])){
3131 continue;
3132 }
3133
3134 try {
3135 $phpmailer->addAttachment($attachment['tmp_name'], $attachment['name'], $encoding = 'base64', $attachment['type'], $disposition = 'attachment');
3136 } catch ( \Exception $e ) {
3137 continue;
3138 }
3139 }
3140 }
3141
3142 }
3143
3144 function pagelayer_array_flatten( $input ) {
3145 if ( ! is_array( $input ) ) {
3146 return array( $input );
3147 }
3148
3149 $output = array();
3150
3151 foreach ( $input as $value ) {
3152 $output = array_merge( $output, pagelayer_array_flatten( $value ) );
3153 }
3154
3155 return $output;
3156 }
3157
3158 function pagelayer_flat_join( $array ) {
3159 $array = pagelayer_array_flatten( $array );
3160 $output = array();
3161
3162 foreach ( (array) $array as $value ) {
3163 $output[] = trim( (string) $value );
3164 }
3165
3166 return implode( ', ', $output );
3167 }
3168
3169 // Verifies the Google Captcha
3170 function pagelayer_captcha_verify(){
3171
3172 // If secret key is not there, return
3173 $captcha_secret = get_option('pagelayer_google_captcha_secret');
3174
3175 if(empty($captcha_secret)){
3176 return true;
3177 }
3178
3179 $response = !empty($_POST['g-recaptcha-response']) ? sanitize_text_field($_POST['g-recaptcha-response']) : '';
3180
3181 $ip = pagelayer_getip();
3182
3183 // Is the IP or response not there ?
3184 if(empty($response) || empty($ip)){
3185 return false;
3186 }
3187
3188 $url = 'https://www.google.com/recaptcha/api/siteverify';
3189
3190 // Verify the post
3191 $req = wp_remote_post($url, array(
3192 'timeout' => 20,
3193 'body' => array(
3194 'secret' => $captcha_secret,
3195 'response' => $response,
3196 'remoteip' => $ip
3197 )
3198 )
3199 );
3200
3201 // Was there an error posting ?
3202 if(is_wp_error($req)){
3203 return false;
3204 }
3205
3206 // Process the post response
3207 $resp = wp_remote_retrieve_body($req);
3208
3209 // Is the body valid
3210 if(empty($resp)){
3211 return false;
3212 }
3213
3214 $json = json_decode($resp, true);
3215
3216 if(!empty($json['success']) && // for v2 and v3
3217 (!isset($json['score']) || $json['score'] >= 0.5 && $json['action'] === 'submit') // For v3
3218 ){
3219 return true;
3220 }
3221
3222 return false;
3223 }
3224
3225 // Pagelayer serialize attributes
3226 function pagelayer_serialize_attributes( $block_attributes ) {
3227 $encoded_attributes = json_encode( $block_attributes, JSON_FORCE_OBJECT);
3228 $encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes );
3229 $encoded_attributes = preg_replace( '/</', '\\u003c', $encoded_attributes );
3230 $encoded_attributes = preg_replace( '/>/', '\\u003e', $encoded_attributes );
3231 // Regex: /\\"/
3232 $encoded_attributes = preg_replace( '/\\\\"/', '\\u0022', $encoded_attributes );
3233
3234 return $encoded_attributes;
3235 }
3236
3237 function pagelayer_enable_giver(){
3238 global $pagelayer;
3239 return !empty($pagelayer->settings['enable_giver']) && $pagelayer->settings['enable_giver'] == 1;
3240 }
3241
3242 function pagelayer_load_font_options(){
3243 include_once(PAGELAYER_DIR.'/main/font-options.php');
3244 }
3245
3246 function pagelayer_is_utf8($str) {
3247 return (bool) preg_match('//u', $str);
3248 }
3249
3250 // Create blank images
3251 function pagelayer_create_blank_image($width, $height){
3252
3253 $im = @imagecreate($width, $height);
3254
3255 if(empty($im)){
3256 return false;
3257 }
3258
3259 $background_color = imagecolorallocate($im, 220, 220, 220);
3260 $text_color = imagecolorallocate($im, 110, 110, 110);
3261 $string = $width.' x '.$height;
3262 $font_size = 30;
3263 $sx = ($width / 2) - (strlen($string) * $font_size / 2);
3264 $sy = ($height / 2) - ($font_size / 2);
3265 $font = realpath(PAGELAYER_DIR.'/fonts/OpenSans-BoldItalic.ttf');
3266 imagettftext($im, $font_size, 0, $sx, $sy, $text_color, $font, $string);
3267 ob_start();
3268 imagepng($im);
3269 imagedestroy($im);
3270
3271 return ob_get_clean();
3272
3273 }
3274
3275 // Get category name by post type
3276 function pagelayer_post_type_category($post_type){
3277
3278 $taxonomies = get_object_taxonomies( $post_type, 'objects');
3279
3280 foreach( $taxonomies as $key => $tax){
3281 if(!empty($tax->hierarchical)){
3282 return $key;
3283 }
3284 }
3285
3286 return false;
3287
3288 }
3289
3290 // Get tag name by post type
3291 function pagelayer_post_type_tag($post_type){
3292
3293 $taxonomies = get_object_taxonomies( $post_type, 'objects');
3294
3295 foreach( $taxonomies as $key => $tax){
3296 if(!empty($tax->show_tagcloud) && empty($tax->hierarchical)){
3297 return $key;
3298 }
3299 }
3300 return false;
3301
3302 }
3303
3304 // Get checkboxes of post categories.
3305 function pagelayer_post_cats($post, &$cat_name = ''){
3306
3307 $ret = [];
3308
3309 $cat_name = pagelayer_post_type_category($post->post_type);
3310
3311 if(empty($cat_name)){
3312 return $ret;
3313 }
3314
3315 include_once(ABSPATH.PAGELAYER_CMS_DIR_PREFIX.'-admin/includes/template.php');
3316
3317 $args1 = array(
3318 'taxonomy' => $cat_name,
3319 'checked_ontop' => false,
3320 'echo' => false,
3321 );
3322
3323 $ret['with_checkbox'] = '<ul class="pagelayer-post-category" >'.wp_terms_checklist($post->ID, $args1 ).'</ul>';
3324
3325 $args2 = array(
3326 'taxonomy' => $cat_name,
3327 'hierarchical' => true,
3328 'echo' => 0,
3329 'class' => 'pagelayer-add-cat',
3330 'name' => 'pagelayer_cat_parent',
3331 'style' => 'list',
3332 'hide_empty' => 0,
3333 );
3334
3335 $ret['without_checkbox'] = wp_dropdown_categories( $args2 );
3336
3337 return $ret;
3338
3339 }
3340
3341 // Get checkboxes of post tags.
3342 function pagelayer_post_tags($post, &$tag_name = ''){
3343
3344 $ret = [];
3345
3346 $tag_name = pagelayer_post_type_tag($post->post_type);
3347
3348 if(empty($tag_name)){
3349 return $ret;
3350 }
3351
3352 $ret['postTags'] = wp_get_post_terms( $post->ID, $tag_name );
3353
3354 $ret['allTags'] = get_tags(array( 'hide_empty' => false, 'taxonomy' => $tag_name ));
3355
3356 return $ret;
3357
3358 }
3359
3360 // Get users who can edit a particular post type
3361 function pagelayer_post_authors_by_type($post_type){
3362
3363 global $wp_post_types;
3364
3365 if(empty($wp_post_types[$post_type])){
3366 $users = get_users( array( 'role__in' => array( 'administrator' ) ) );
3367 }else{
3368 $req_role = $wp_post_types[$post_type]->cap->edit_posts;
3369 $roles__in = [];
3370 foreach( wp_roles()->roles as $role_slug => $role ){
3371 if( ! empty( $role['capabilities'][$req_role] ) )
3372 $roles__in[] = $role_slug;
3373 }
3374 $users = get_users( array( 'role__in' => $roles__in ) );
3375 }
3376
3377 $user_array = [];
3378
3379 foreach ( $users as $user ) {
3380 $user_array[$user->ID] = $user->display_name;
3381 }
3382
3383 return $user_array;
3384 }
3385
3386 function pagelayer_parent_post_prop($post){
3387 global $wp_post_types;
3388
3389 if(!empty($wp_post_types[$post->post_type]->hierarchical)){
3390 return pagelayer_list_parents(0, 0, $post, []);
3391 }else{
3392 return [];
3393 }
3394 }
3395
3396 function pagelayer_list_parents( $parent = 0, $level = 0, $post = null, $values=array('')){
3397
3398 global $wpdb;
3399
3400 $post = get_post( $post );
3401
3402 $items = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_parent, post_title FROM $wpdb->posts
3403 WHERE post_parent = %d
3404 AND post_type = '".$post->post_type."'
3405 AND post_status = 'publish'
3406 ORDER BY menu_order", $parent ) );
3407
3408 if ( !empty($items) ) {
3409 foreach ( $items as $item ) {
3410
3411 // A page cannot be its own parent.
3412 if ( $post && $post->ID && (int) $item->ID === $post->ID ) {
3413 continue;
3414 }
3415
3416 $pad = str_repeat( '-', $level );
3417
3418 if(count($values)==0){
3419 $values[] = '';
3420 }
3421
3422 $values[' '.$item->ID] = $pad.esc_html( $item->post_title );
3423
3424 $values = pagelayer_list_parents($item->ID, $level + 1, $post, $values );
3425 }
3426 }
3427
3428 return $values;
3429 }
3430
3431 // Maybe explode
3432 function pagelayer_maybe_explode( $separator = ',', $string = '', $limit = PHP_INT_MAX ){
3433
3434 if(is_array($string)){
3435 return $string;
3436 }
3437
3438 return explode($separator, $string, $limit);
3439 }
3440
3441 // Maybe implode
3442 function pagelayer_maybe_implode($array, $separator = ','){
3443
3444 if(is_array($array)){
3445 return @implode($separator, $array);
3446 }
3447
3448 return $array;
3449
3450 }
3451
3452 // Sanitize text field or array
3453 function pagelayer_sanitize_text_field($str) {
3454
3455 if ( !is_object( $str ) && !is_array( $str ) ) {
3456 return sanitize_text_field($str);
3457 }
3458
3459 if( is_array($str) ){
3460 return array_map( 'pagelayer_sanitize_text_field', $str);
3461 }
3462
3463 return $str;
3464 }
3465
3466 // Sanitize posts data for WP_Query
3467 function pagelayer_sanitize_posts_data($data, $only_allowed = true) {
3468
3469 $allowed_keys = [
3470 'post_type', 'posts_per_page', 'order', 'orderby', 'paged',
3471 'filter_by', 'term', 'exc_term', 'cat', 'category_name',
3472 'tag', 'author', 'author_name', 'post__in', 'post__not_in',
3473 'include', 'exclude', 'search', 's', 'exact', 'sentence',
3474 'post_status', 'post_parent', 'offset',
3475 'posts_per_archive_page', 'page', 'ignore_sticky_posts'
3476 ];
3477
3478 $sanitized = [];
3479
3480 foreach($data as $key => $value){
3481 if($only_allowed && !in_array($key, $allowed_keys)) {
3482 continue;
3483 }
3484
3485 $sanitized[$key] = pagelayer_sanitize_text_field($value);
3486 }
3487
3488 // Security: Restrict post_status to prevent information disclosure
3489 // Only users who can read private posts or edit others' posts should be able to query non-public statuses
3490 if(isset($sanitized['post_status'])){
3491 $requested_status = $sanitized['post_status'];
3492
3493 // If requesting something other than publish, verify permissions
3494 if ($requested_status !== 'publish') {
3495 // Check if the user has permission to read private posts or edit others' posts
3496 // This prevents contributors from seeing titles of private posts they don't own.
3497 if (!current_user_can('read_private_posts') && !current_user_can('edit_others_posts')) {
3498 $sanitized['post_status'] = 'publish';
3499 }
3500 }
3501 }else{
3502 // Default to publish for safety if not specified
3503 $sanitized['post_status'] = 'publish';
3504 }
3505
3506 if(isset($sanitized['posts_per_page'])){
3507 $sanitized['posts_per_page'] = (int) $sanitized['posts_per_page'];
3508 if ($sanitized['posts_per_page'] > 100) {
3509 $sanitized['posts_per_page'] = 100;
3510 }
3511 }
3512
3513 if(isset($sanitized['paged'])){
3514 $sanitized['paged'] = (int) $sanitized['paged'];
3515 }
3516
3517 if(isset($sanitized['offset'])){
3518 $sanitized['offset'] = (int) $sanitized['offset'];
3519 }
3520
3521 if(isset($sanitized['post__in']) && is_string($sanitized['post__in'])){
3522 $sanitized['post__in'] = array_map('intval', explode(',', $sanitized['post__in']));
3523 }
3524
3525 if(isset($sanitized['post__not_in']) && is_string($sanitized['post__not_in'])){
3526 $sanitized['post__not_in'] = array_map('intval', explode(',', $sanitized['post__not_in']));
3527 }
3528
3529 if(isset($sanitized['post_parent'])){
3530 $sanitized['post_parent'] = (int) $sanitized['post_parent'];
3531 }
3532
3533 if(isset($sanitized['cat'])){
3534 $sanitized['cat'] = (int) $sanitized['cat'];
3535 }
3536
3537 if(isset($sanitized['author'])){
3538 $sanitized['author'] = (int) $sanitized['author'];
3539 }
3540
3541 return $sanitized;
3542 }
3543
3544 // Update nav menu item
3545 function pagelayer_save_nav_menu_items($items){
3546
3547 // Menu setting keys
3548 $allowed_post = array('title' => 'post_title');
3549 $allowed_meta = array('_pagelayer_content');
3550
3551 foreach($items as $id => $values){
3552
3553 $meta_input = array();
3554 $id = (int) $id;
3555 $post = get_post($id);
3556
3557 // Post found ?
3558 if(empty($post)){
3559 continue;
3560 }
3561
3562 foreach($values as $kk => $vv){
3563
3564 if(array_key_exists($kk, $allowed_post)){
3565 $name = $allowed_post[$kk];
3566 $post->$name = $vv;
3567 }
3568
3569 if(!in_array($kk, $allowed_meta)){
3570 continue;
3571 }
3572
3573 $meta_input[$kk] = stripslashes_deep($vv);
3574 }
3575
3576 if(isset($meta_input['_pagelayer_content'])){
3577 $meta_input['_pagelayer_content'] = base64_decode($meta_input['_pagelayer_content']);
3578 }
3579
3580 $post->meta_input = $meta_input;
3581 wp_update_post($post);
3582 }
3583 }
3584
3585 // Update customizer options
3586 function pagelayer_save_customizer_options($customizer_options){
3587 global $pagelayer;
3588
3589 // To load customizer params array
3590 if(empty($pagelayer->customizer_params)){
3591 pagelayer_load_shortcodes();
3592 }
3593
3594 $customizer_options = apply_filters( 'pagelayer_save_customizer_options', $customizer_options );
3595 $customizer_data = array();
3596 $customizer_option_data = array();
3597
3598 foreach($pagelayer->customizer_params as $ck => $cv){
3599 foreach($pagelayer->screens as $sk => $sv){
3600
3601 $screen = (!empty($sv) ? '_'.$sv : '');
3602 $screen_key = $ck.$screen;
3603
3604 // Save to pagelayer customizer mods
3605 if( empty($cv['option']) ){
3606 if( isset($customizer_options[$screen_key])){
3607 $customizer_data[$screen_key] = $customizer_options[$screen_key];
3608 }
3609 continue;
3610 }
3611
3612 $option_key = $cv['option'].$screen;
3613
3614 // Update option
3615 if( isset($customizer_options[$screen_key] ) ) {
3616 update_option( $option_key, $customizer_options[$screen_key]);
3617 continue;
3618 }
3619
3620 delete_option($option_key);
3621 }
3622 }
3623
3624 // Set Typography settings for global and current post type
3625 $posttype=array(
3626 '' => '', // Make this empty for global values
3627 'current' => $customizer_options['pagelayer_current_post_type']
3628 );
3629
3630 $typo = ['font-family', 'font-size', 'font-style', 'font-weight', 'font-variant', 'decoration-line', 'line-height', 'text-transform', 'text-spacing', 'word-spacing'];
3631
3632 foreach($posttype as $type => $tv){
3633
3634 foreach($pagelayer->css_settings as $set => $params){
3635
3636 foreach($pagelayer->screens as $sk => $sv){
3637
3638 $screen = (!empty($sv) ? '_'.$sv : '');
3639 $post_type = (!empty($tv) ? '_'.$tv : '');
3640 $post_key = (!empty($type) ? $type.'_' : '');
3641 $post_key_set = $post_key.$set;
3642
3643 // Create key as per customizer shortcode
3644 $key = $post_key_set.$screen;
3645
3646 // Create option keys for the global and current post type
3647 $option_setting = empty($params['key']) ? 'pagelayer_'.$set.'_css'.$post_type : $params['key'].$post_type;
3648
3649 $props = array(
3650 'color' => $post_key_set.'_color'.$screen,
3651 'padding' => $post_key_set.'_padding'.$screen,
3652 'margin' => $post_key_set.'_margin'.$screen,
3653 'background-color' => $post_key_set.'_background_color'.$screen,
3654 );
3655
3656 $globalsetting = array();
3657
3658 // Set Typography
3659 if(isset($customizer_options[$key])){
3660 foreach($customizer_options[$key] as $k => $v){
3661 if($v == 'Default' || empty($v)){
3662 unset($customizer_options[$key][$k]);
3663 }
3664
3665 // For sidebar, width default should not be saved
3666 if($set == 'sidebar' && $k == 'width' && $v == 20){
3667 unset($customizer_options[$key][$k]);
3668 }
3669
3670 $globalsetting[$key][$typo[$k]] = $customizer_options[$key][$k];
3671 unset($customizer_options[$key][$k]);
3672 }
3673 }
3674
3675 // Set other props with typography
3676 foreach($props as $pk => $pv){
3677
3678 if(!isset($customizer_options[$pv])){
3679 continue;
3680 }
3681
3682 $globalsetting[$key][$pk] = $customizer_options[$pv];
3683 unset($customizer_options[$pv]);
3684
3685 }
3686
3687 // Are we to save ?
3688 if(!empty($globalsetting[$key])){
3689 update_option($option_setting.$screen, $globalsetting[$key]);
3690 }else{
3691 delete_option($option_setting.$screen);
3692 }
3693
3694 }
3695
3696 }
3697 }
3698
3699 $customizer_data = apply_filters( 'pagelayer_customizer_options', $customizer_data, $customizer_options);
3700
3701 update_option('pagelayer_customizer_mods', $customizer_data);
3702 }
3703
3704 // Get customizer options values
3705 // return array to set customizer block attributes
3706 function pagelayer_get_customizer_options(){
3707 global $pagelayer, $post;
3708
3709 $options = array();
3710
3711 // To load customizer params array
3712 if(empty($pagelayer->customizer_params)){
3713 pagelayer_load_shortcodes();
3714 }
3715
3716 // Get values form options
3717 foreach($pagelayer->customizer_params as $ck => $cv){
3718
3719 if( empty($cv['option']) ){
3720 continue;
3721 }
3722
3723 $screens = array('desktop' => '');
3724
3725 if( !empty($cv['screen']) ){
3726 $screens = $pagelayer->screens;
3727 }
3728
3729 foreach($screens as $sk => $sv){
3730
3731 $screen = (!empty($sv) ? '_'.$sv : '');
3732 $screen_key = $cv['option'].$screen;
3733 $screen_ck = $ck.$screen;
3734
3735 // Get option value
3736 $c_option = get_option($screen_key);
3737
3738 if(empty($c_option)){
3739 continue;
3740 }
3741
3742 $options[$screen_ck] = $c_option;
3743 }
3744 }
3745
3746
3747 // Get values from pagelayer mods
3748 $mods = get_option('pagelayer_customizer_mods');
3749
3750 if(!empty($mods)){
3751 $options = array_merge($options, $mods);
3752 }
3753
3754 $posttype=array(
3755 '' => '',
3756 'current' => $post->post_type
3757 );
3758
3759 $typo = ['font-family', 'font-size', 'font-style', 'font-weight', 'font-variant', 'decoration-line', 'line-height', 'text-transform', 'text-spacing', 'word-spacing'];
3760
3761 foreach($posttype as $type => $tv){
3762
3763 foreach($pagelayer->css_settings as $set => $params){
3764
3765 foreach($pagelayer->screens as $sk => $sv){
3766
3767 $screen = (!empty($sv) ? '_'.$sv : '');
3768 $postprefix = (!empty($tv) ? '_'.$tv : '');
3769 $postk = (!empty($type) ? $type.'_' : '');
3770 $post_key_set = $postk.$set;
3771
3772 // Create key as per customizer shortcode
3773 $key = $post_key_set.$screen;
3774
3775 // Create option keys for the global and current post type
3776 $setting = empty($params['key']) ? 'pagelayer_'.$set.'_css'.$postprefix : $params['key'].$postprefix;
3777
3778 $props = array(
3779 'color' => $post_key_set.'_color'.$screen,
3780 'padding' => $post_key_set.'_padding'.$screen,
3781 'margin' => $post_key_set.'_margin'.$screen,
3782 'background-color' => $post_key_set.'_background_color'.$screen,
3783 );
3784
3785 $optarray = get_option($setting.$screen);
3786
3787 if(!empty($optarray)){
3788
3789 // Get Typography
3790 foreach($typo as $tk => $tv){
3791
3792 $tval = '';
3793
3794 if(isset($optarray[$tv])){
3795 $tval = $optarray[$tv];
3796 }
3797
3798 $options[$key][$tk] = $tval;
3799 }
3800
3801 foreach($props as $pk => $pv){
3802 if(empty( $optarray[$pk])){
3803 continue;
3804 }
3805
3806 $options[$pv] = $optarray[$pk];
3807 }
3808 }
3809 }
3810 }
3811 }
3812
3813 $options = apply_filters( 'pagelayer_get_customizer_options', $options);
3814
3815 return $options;
3816 }
3817
3818 // Sanitize style props for colors and fons
3819 function pagelayer_load_global_palette(){
3820 global $pagelayer;
3821
3822 // Default global colors
3823 $pagelayer->global_colors = array(
3824 'primary' => array(
3825 'title' => 'Primary',
3826 'value' => '#007bff',
3827 ),
3828 'secondary' => array(
3829 'title' => 'Secondary',
3830 'value' => '#6c757d',
3831 ),
3832 'text' => array(
3833 'title' => 'Text',
3834 'value' => '#1d1d1d',
3835 ),
3836 'accent' => array(
3837 'title' => 'Accent',
3838 'value' => '#61ce70',
3839 ),
3840 );
3841
3842 // Global color
3843 $global_color = get_option('pagelayer_global_colors');
3844
3845 if(!empty($global_color)){
3846 $pagelayer->global_colors = json_decode($global_color, true);
3847 }
3848
3849 // Default global fonts
3850 $pagelayer->global_fonts = array(
3851 'primary' => array(
3852 'title' => 'Primary',
3853 'value' => $pagelayer->default_font_styles(),
3854 ),
3855 'secondary' => array(
3856 'title' => 'Secondary',
3857 'value' => $pagelayer->default_font_styles(array('font-family' => 'Roboto')),
3858 ),
3859 'text' => array(
3860 'title' => 'Text',
3861 'value' => $pagelayer->default_font_styles(array('font-family' => 'Montserrat')),
3862 ),
3863 'accent' => array(
3864 'title' => 'Accent',
3865 'value' => $pagelayer->default_font_styles(array('font-family' => 'Poppins')),
3866 ),
3867 );
3868
3869 // Global font
3870 $global_font = get_option('pagelayer_global_fonts');
3871
3872 if(!empty($global_font)){
3873 $pagelayer->global_fonts = json_decode($global_font, true);
3874 }
3875 }
3876
3877 // Get global colors
3878 function pagelayer_sanitize_global_color($val){
3879 global $pagelayer;
3880
3881 if(!is_string($val) || $val[0] != '$'){
3882 return $val;
3883 }
3884
3885 $gkey = substr($val, 1);
3886 $gcolor = isset($pagelayer->global_colors[$gkey]) ? $gkey : 'primary';
3887 $val = 'var(--pagelayer-color-'.$gcolor.')';
3888
3889 return $val;
3890 }
3891
3892 // Sanitize style props for colors and fons
3893 function pagelayer_sanitize_global_style($val, $val_desk = '', $mode = 'desktop'){
3894 global $pagelayer;
3895
3896 // Sanitize Global background color
3897 if( !empty($val['background-color']) && $val['background-color'][0] == '$'){
3898 $val['background-color'] = pagelayer_sanitize_global_color($val['background-color']);
3899 }
3900
3901 // Sanitize Global color
3902 if( !empty($val['color']) && $val['color'][0] == '$'){
3903 $val['color'] = pagelayer_sanitize_global_color($val['color']);
3904 }
3905
3906 // Not set global for typo
3907 if(empty($val['global-font']) && empty($val_desk['global-font'])){
3908 return $val;
3909 }
3910
3911 $_desk_global = false;
3912
3913 if(empty($val['global-font'])){
3914 $font_key = @$val_desk['global-font'];
3915 $_desk_global = true;
3916 }else{
3917 $font_key = $val['global-font'];
3918 unset($val['global-font']);
3919 }
3920
3921 if(empty($font_key)){
3922 return $val;
3923 }
3924
3925 if(!isset($pagelayer->global_fonts[$font_key])){
3926 $font_key = 'primary';
3927 }
3928
3929 $_val = [];
3930
3931 // Apply global typo
3932 foreach($pagelayer->typo_props as $typo_key){
3933
3934 if(!empty($val[$typo_key])){
3935 continue;
3936 }
3937
3938 $global_val = $pagelayer->global_fonts[$font_key]['value'];
3939
3940 if( empty($global_val[$typo_key]) || (is_array($global_val[$typo_key]) && empty($global_val[$typo_key][$mode])) || (!is_array($global_val[$typo_key]) && !empty($_desk_global) && $mode != 'desktop') ){
3941 continue;
3942 }
3943
3944 $_val[$typo_key] = 'var(--pagelayer-font-'.$font_key.'-'.$typo_key.')';
3945 }
3946
3947 // This array contains other values like margin padding so we merge the array
3948 $val = empty($val) ? array() : $val;
3949 $val = array_merge($val, $_val);
3950 return $val;
3951 }
3952
3953 //Check an empty array
3954 function pagelayer_is_empty_array($arr){
3955
3956 foreach ($arr as $key => $value) {
3957 if (trim($value) !== '') return false;
3958 }
3959
3960 return true;
3961 }
3962
3963 // Pagelayer load font family
3964 function pagelayer_load_font_family($font, $font_weight='', $font_style=''){
3965 global $pagelayer;
3966
3967 // Load global fonts
3968 if(strripos($font, 'var(') !== false){
3969 $matches = [];
3970 preg_match('/(var\(--pagelayer-font-)(\w+)(-font-family\))/i', $font, $matches);
3971 $font_key = @$matches[2];
3972 $font = @$pagelayer->global_fonts[$font_key]['value']['font-family'];
3973 }
3974
3975 // Load global fonts weight
3976 if(!empty($font_weight) && strripos($font_weight, 'var(') !== false){
3977 $matches = [];
3978 preg_match('/(var\(--pagelayer-font-)(\w+)(-font-weight\))/i', $font_weight, $matches);
3979 $font_key = @$matches[2];
3980
3981 // Convert in string
3982 $font_weight = @$pagelayer->global_fonts[$font_key]['value']['font-weight'];
3983 }
3984
3985 // Load global fonts style
3986 if(!empty($font_style) && strripos($font_style, 'var(') !== false){
3987 $matches = [];
3988 preg_match('/(var\(--pagelayer-font-)(\w+)(-font-style\))/i', $font_style, $matches);
3989 $font_key = @$matches[2];
3990
3991 // Convert in string
3992 $font_style = @$pagelayer->global_fonts[$font_key]['value']['font-style'];
3993 }
3994
3995 if(empty($font)){
3996 return;
3997 }
3998
3999 $font_weights = array('400' =>'400');
4000 $font_style = empty($font_style) ? 'normal' : $font_style;
4001 $font_style = in_array($font_style, ['italic', 'oblique']) ? 'i' : '';
4002
4003 if(!empty($font_weight)){
4004
4005 if(!is_array($font_weight)){
4006 $font_weight = array($font_weight);
4007 }
4008
4009 foreach($font_weight as $weight){
4010 $font_weights[$weight.$font_style] = $weight.$font_style;
4011 }
4012 }
4013
4014 foreach($font_weights as $fkey => $fvalue){
4015 $pagelayer->runtime_fonts[$font][$fkey] = $fvalue;
4016 }
4017
4018 }
4019
4020 function pagelayer_update_plugin_notice(){
4021 if(defined('SOFTACULOUS_PLUGIN_UPDATE_NOTICE')){
4022 return;
4023 }
4024
4025 $to_update_plugins = apply_filters('softaculous_plugin_update_notice', []);
4026
4027 if(empty($to_update_plugins)){
4028 return;
4029 }
4030
4031 /* translators: %1$s is replaced with a "string" of name of plugins, and %2$s is replaced with "string" which can be "is" or "are" based on the count of the plugin */
4032 $msg = sprintf(__('New versions of %1$s %2$s available. Updating ensures better performance, security, and access to the latest features.', 'pagelayer'), '<b>'.esc_html(implode(', ', $to_update_plugins)).'</b>', (count($to_update_plugins) > 1 ? 'are' : 'is')) . ' <a class="button button-primary" href='.esc_url(admin_url('plugins.php?plugin_status=upgrade')).'>Update Now</a>';
4033
4034 define('SOFTACULOUS_PLUGIN_UPDATE_NOTICE', true); // To make sure other plugins don't return a Notice
4035 echo '<div class="notice notice-info is-dismissible" id="pagelayer-plugin-update-notice">
4036 <p>'.$msg. '</p>
4037 </div>';
4038
4039 wp_register_script('pagelayer-update-notice', '', ['jquery'], '', true);
4040 wp_enqueue_script('pagelayer-update-notice');
4041 wp_add_inline_script('pagelayer-update-notice', 'jQuery("#pagelayer-plugin-update-notice").on("click", function(e){
4042 let target = jQuery(e.target);
4043
4044 if(!target.hasClass("notice-dismiss")){
4045 return;
4046 }
4047
4048 var data;
4049
4050 // Hide it
4051 jQuery("#pagelayer-plugin-update-notice").hide();
4052
4053 // Save this preference
4054 jQuery.post("'.admin_url('admin-ajax.php?action=pagelayer_close_update_notice').'&pagelayer_nonce='.wp_create_nonce('pagelayer_promo_nonce').'", data, function(response) {
4055 //alert(response);
4056 });
4057 });');
4058 }
4059
4060 function pagelayer_update_plugin_notice_filter($plugins = []){
4061 $plugins['pagelayer/pagelayer.php'] = 'Pagelayer';
4062 return $plugins;
4063 }
4064
4065 function pagelayer_is_comment_mode(){
4066
4067 if(file_exists(PAGELAYER_DIR.'/comment_mode.php') && !empty($_REQUEST['cmode'])){
4068 include_once(PAGELAYER_DIR.'/comment_mode.php');
4069 return true;
4070 }
4071
4072 return false;
4073 }
4074
4075 function pagelayer_esc_crlf($value){
4076
4077 // Remove CRLF to prevent header injection
4078 $value = str_replace(array("\r", "\n", "%0a", "%0d"), '', $value);
4079
4080 // Trim spaces
4081 $value = trim($value);
4082
4083 return $value;
4084 }