PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.1.5
Page Builder: Pagelayer – Drag and Drop website builder v2.1.5
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.5, at main/functions.php

4,097 lines 101.7 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 if(is_null($str)){
1138 return '';
1139 }
1140
1141 $replace = [
1142 ']' => '&#93;',
1143 '[' => '&#91;',
1144 //'=' => '&#61;',
1145 '<' => '&lt;',
1146 '>' => '&gt;',
1147 '"' => '&quot;',
1148 //'&' => '&amp;',
1149 '\'' => '&#39;',
1150 '\\' => '&#92;'
1151 ];
1152
1153 $str = str_replace(array_keys($replace), array_values($replace), $str);
1154
1155 return $str;
1156 }
1157
1158 // As per the JS specification
1159 function pagelayer_unescapeHTML($str){
1160
1161 if(is_null($str)){
1162 return '';
1163 }
1164
1165 $replace = [
1166 '#93' => ']',
1167 '#91' => '[',
1168 //'#61' => '=',
1169 'lt' => '<',
1170 'gt' => '>',
1171 'quot' => '"',
1172 //'amp' => '&',
1173 '#39' => '\'',
1174 '#92' => '\\'
1175 ];
1176
1177 foreach($replace as $k => $v){
1178 $str = str_replace('&'.$k.';', $v, $str);
1179 }
1180 return $str;
1181 }
1182
1183 // Converts a Unicode code point to its UTF-8 encoded string.
1184 function pagelayer_codepoint_to_utf8($num) {
1185 if ($num < 0x80) {
1186 return chr($num);
1187 } elseif ($num < 0x800) {
1188 return chr(0xC0 | ($num >> 6))
1189 . chr(0x80 | ($num & 0x3F));
1190 } elseif ($num < 0x10000) {
1191 return chr(0xE0 | ($num >> 12))
1192 . chr(0x80 | (($num >> 6) & 0x3F))
1193 . chr(0x80 | ($num & 0x3F));
1194 } elseif ($num < 0x110000) {
1195 return chr(0xF0 | ($num >> 18))
1196 . chr(0x80 | (($num >> 12) & 0x3F))
1197 . chr(0x80 | (($num >> 6) & 0x3F))
1198 . chr(0x80 | ($num & 0x3F));
1199 }
1200 return '';
1201 }
1202
1203 // To make decode entities faster
1204 function pagelayer_optimized_decode_entities($string, $req = true) {
1205
1206 // Fast replace common HTML entities
1207 $common_entities_map = [
1208 '&#93;' => ']', '&#91;' => '[', '&lt;' => '<', '&gt;' => '>', '&amp;' => '&', '&quot;' => '"', '&#39;' => "'",
1209 '&copy;' => '©', '&reg;' => '®', '&ndash;' => '', '&mdash;' => '', '&bull;' => '',
1210 '&hellip;' => '', '&lsquo;' => '', '&rsquo;' => '', '&ldquo;' => '', '&rdquo;' => ''
1211 ];
1212
1213 // Replace common entities first for performance
1214 $string = str_replace(array_keys($common_entities_map), array_values($common_entities_map), $string);
1215
1216 // Return early if no encoded entities exist
1217 if(!preg_match('/\\\\u[0-9a-fA-F]{4}|&#x[0-9a-fA-F]+;|&#\d+;/', $string)) {
1218 return $string;
1219 }
1220
1221 $string = preg_replace_callback(
1222 '/\\\\u([0-9a-fA-F]{4})|&#x([0-9a-fA-F]+);|&#([0-9]+);/',
1223 function ($matches) {
1224 if (!empty($matches[1])) {
1225 // Decode \uXXXX Unicode sequences
1226 return pagelayer_codepoint_to_utf8( hexdec($matches[1]) );
1227 }elseif (!empty($matches[2])) {
1228 // Decode hexadecimal HTML entities (&#x6A; → j)
1229 return pagelayer_codepoint_to_utf8( hexdec($matches[2]) );
1230 } elseif (!empty($matches[3])) {
1231 // Decode decimal HTML entities (&#106; → j)
1232 return pagelayer_codepoint_to_utf8( (int)$matches[3] );
1233 }
1234 return $matches[0];
1235 },
1236 $string
1237 );
1238
1239 // Additional decoding to cover remaining cases
1240 if($req){
1241 $string = pagelayer_optimized_decode_entities($string, false);
1242 }
1243
1244 return $string;
1245 }
1246
1247 // Return true if user can add js content
1248 function pagelayer_user_can_add_js_content(){
1249
1250 // Unfiltered_html cap needs to be checked for multisite
1251 if(current_user_can('unfiltered_html')){
1252 return true;
1253 }
1254
1255 $pagelayer_js_permission = get_option('pagelayer_js_permission');
1256 $current_user = wp_get_current_user();
1257
1258 // If not allowed any role by admin
1259 if(empty($pagelayer_js_permission) || empty($current_user->roles)){
1260 return false;
1261 }
1262
1263 foreach($current_user->roles as $role){
1264 if(in_array($role, $pagelayer_js_permission)){
1265 return true;
1266 }
1267 }
1268
1269 return false;
1270 }
1271
1272 // Check for XSS codes in our shortcodes submitted
1273 function pagelayer_xss_content($data){
1274
1275 $data = pagelayer_optimized_decode_entities($data);
1276
1277 // Keep a whitespace-preserved copy for the on* event-handler scan.
1278 $orig = $data;
1279
1280 $data = preg_split('/\s/', $data);
1281 $data = implode('', $data);
1282 //echo $data;
1283
1284 if(preg_match('/["\']javascript\:/is', $data)){
1285 return 'javascript';
1286 }
1287
1288 if(preg_match('/["\']vbscript\:/is', $data)){
1289 return 'vbscript';
1290 }
1291
1292 if(preg_match('/\-moz\-binding\:/is', $data)){
1293 return '-moz-binding';
1294 }
1295
1296 if(preg_match('/expression\(/is', $data)){
1297 return 'expression';
1298 }
1299
1300 if(preg_match('/\<(iframe|frame|script|style|link|applet|embed|xml|svg|object|layer|ilayer|meta)/is', $data, $matches)){
1301 return $matches[1];
1302 }
1303
1304 // Reject ANY on* event handler attribute. Per the HTML spec every attribute
1305 // name beginning with "on" (optionally followed by a letter and word chars)
1306 if(preg_match('/\bon(?:[a-z][a-z0-9-]*)?\s*=/i', $orig, $matches)){
1307 return $matches[0];
1308 }
1309
1310 return;
1311
1312 }
1313
1314 // Check for XSS codes in our blocks array
1315 function pagelayer_sanitize_blocks_save_pre($block){
1316
1317 foreach($block as $k => $v){
1318
1319 // Recurse on arrays
1320 if(is_array($v)){
1321 $block[$k] = pagelayer_sanitize_blocks_save_pre($v);
1322
1323 // We dont support objects !
1324 }elseif(is_object($v)){
1325 $block[$k] = null;
1326 // Strings
1327 }else{
1328
1329 if(is_string($v)){
1330
1331 $v = wp_filter_post_kses($v);
1332
1333 while(true){
1334 $str = '"'.($v);
1335 $found = pagelayer_xss_content($str);
1336 //echo (string)$v.'--'.$found."\n";
1337
1338 if(strlen($found) > 0){
1339 // There is htmlentities?
1340 if(strpos($v, $found) === false){
1341 $v = '';
1342 break;
1343 }
1344 $v = str_replace($found, '', $v);
1345 }else{
1346 break;
1347 }
1348
1349 }
1350
1351 }
1352
1353 $block[$k] = $v;
1354 }
1355
1356 }
1357
1358 return $block;
1359 }
1360
1361 // Check for XSS codes in our shortcode attributes
1362 function pagelayer_sanitize_shortcode_atts($content){
1363
1364 // Do we have something suspicious ?
1365 $tmp_check = pagelayer_xss_content($content);
1366 if(empty($tmp_check)){
1367 return $content;
1368 }
1369
1370 pagelayer_load_shortcodes();
1371
1372 preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER );
1373
1374 $prefixes = ['pl_'];
1375
1376 $prefixes = apply_filters( 'pagelayer_valid_shortcode_tag', $prefixes);
1377
1378 foreach ($matches as $shortcode) {
1379
1380 $shortcode_name = $shortcode[2];
1381
1382 $vailid = false;
1383
1384 foreach($prefixes as $prefix) {
1385 if (strpos($shortcode_name, $prefix) === 0) {
1386 $vailid = true;
1387 break;
1388 }
1389 }
1390
1391 if(!$vailid){
1392 continue;
1393 }
1394
1395 $attrs = shortcode_parse_atts( $shortcode[3] );
1396 $atts = ' ';
1397
1398 foreach($attrs as $key => $value){
1399
1400 // Skip if key contains XSS
1401 if (!is_numeric($key) && strlen(pagelayer_xss_content($key . '=')) > 0) continue;
1402
1403 $value = wp_filter_post_kses($value);
1404
1405 // Skip if value contains XSS
1406 if (strlen(pagelayer_xss_content('"' . $value)) > 0) continue;
1407
1408 $atts .= is_numeric($key) ? $value . ' ' : $key . '="' . $value . '" ';
1409
1410 }
1411
1412 $new_shortcode = '[' . $shortcode_name . $atts . ']';
1413
1414 if(!empty($shortcode[5])){
1415 $new_shortcode .= $shortcode[5].'[/' . $shortcode_name .']';
1416 }
1417
1418 // Replace the original shortcode with sanitized attributes
1419 $content = str_replace($shortcode[0], $new_shortcode, $content);
1420 }
1421
1422 return $content;
1423 }
1424
1425 function pagelayer_getting_started_notice(){
1426
1427 // Is Sitepad setup done?
1428 $setup_done = get_option('sp_setup_done');
1429
1430 if(defined('SITEPAD') && empty($setup_done)){
1431 return;
1432 }
1433
1434 // If SitePad used custom BRAND SM
1435 if(defined('BRAND_SM_CUSTOM')){
1436 return;
1437 }
1438
1439 echo '
1440 <script type="application/javascript">
1441 jQuery(document).ready(function(){
1442 jQuery("#pagelayer-getting-started-notice").click(function(e){
1443
1444 if(jQuery(e.target).hasClass("notice-dismiss")){
1445 var data;
1446 jQuery("#pagelayer-getting-started-notice").hide();
1447 // Save this preference
1448 jQuery.post("'.admin_url('?pagelayer-getting-started=0&pagelayer_nonce='.wp_create_nonce("pagelayer_getting_started_nonce") ).'", data, function(response) {
1449 //alert(response);
1450 });
1451 return false;
1452 }
1453
1454 });
1455 });
1456 </script>
1457
1458 <div id="pagelayer-getting-started-notice" class="notice notice-success is-dismissible">
1459 <p style="font-size: 14px; font-weight: 600">';
1460 if(defined('SITEPAD')){
1461
1462 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.'.');
1463
1464 }else{
1465
1466 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');
1467
1468 }
1469
1470 echo '</p>
1471 </div>';
1472
1473 }
1474
1475 // Show Changelog promo
1476 function pagelayer_show_changelog_notice(){
1477
1478 // Is Sitepad setup done?
1479 if(defined('SITEPAD')){
1480 return;
1481 }
1482
1483 echo '
1484 <script type="application/javascript">
1485 jQuery(document).ready(function(){
1486 jQuery("#pagelayer-changelog-notice").click(function(e){
1487
1488 if(jQuery(e.target).hasClass("notice-dismiss")){
1489 var data;
1490 jQuery("#pagelayer-changelog-notice").hide();
1491 // Save this preference
1492 jQuery.post("'.admin_url('?pagelayer-changelog-notice=0&pagelayer_nonce='.wp_create_nonce("pagelayer_changelog_nonce") ).'", data, function(response) {
1493 //alert(response);
1494 });
1495 return false;
1496 }
1497
1498 });
1499 });
1500 </script>
1501
1502 <div id="pagelayer-changelog-notice" class="notice notice-info is-dismissible">
1503 <p style="font-size: 14px; font-weight: 600">
1504 <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') .'
1505 </p>
1506 </div>';
1507
1508 }
1509
1510 // Show promo notice on dashboard
1511 function pagelayer_show_promo(){
1512
1513 global $pagelayer_promo_opts;
1514 $opts = $pagelayer_promo_opts;
1515
1516 echo '<style>
1517 #pagelayer_promo a.pagelayer_promo_button {
1518 background-color: #4CAF50 !important;
1519 border: none !important;
1520 color: white !important;
1521 padding: 6px 10px !important;
1522 text-align: center !important;
1523 text-decoration: none !important;
1524 display: inline-block !important;
1525 font-size: 13px !important;
1526 margin: 4px 2px !important;
1527 -webkit-transition-duration: 0.4s;
1528 transition-duration: 0.4s;
1529 cursor: pointer !important;
1530 }
1531 #pagelayer_promo a.pagelayer_promo_button:focus,
1532 #pagelayer_promo a.pagelayer_promo_button:hover{
1533 border: none !important;
1534 color: white !important;
1535 box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19) !important;
1536 }
1537 #pagelayer_promo a.pagelayer_promo_buy {
1538 color: white !important;
1539 padding: 8px 12px !important;
1540 font-size: 14px !important;
1541 background-color: #4CAF50 !important;
1542 }
1543 #pagelayer_promo a.pagelayer_promo_button1 {
1544 color: white !important;
1545 background-color: #4CAF50 !important;
1546 border:3px solid #4CAF50 !important;
1547 }
1548 #pagelayer_promo a.pagelayer_promo_button1:hover {
1549 border:3px solid #4CAF50 !important;
1550 }
1551 #pagelayer_promo a.pagelayer_promo_button2 {
1552 color: white !important;
1553 background-color: #0085ba !important;
1554 }
1555 #pagelayer_promo a.pagelayer_promo_button3 {
1556 color: white !important;
1557 background-color: #365899 !important;
1558 }
1559 #pagelayer_promo a.pagelayer_promo_button4 {
1560 color: white !important;
1561 background-color: rgb(66, 184, 221) !important;
1562 }
1563 #pagelayer_promo a.pagelayer_promo-close{
1564 float:right !important;
1565 text-decoration:none !important;
1566 margin: 5px 10px 0px 0px !important;
1567 color: #666 !important;
1568 }
1569 #pagelayer_promo a.pagelayer_promo-close:hover{
1570 color: red !important;
1571 }
1572 #pagelayer_promo a:not(.pagelayer_promo_button):not(.pagelayer_promo-close) {
1573 color: #4CAF50 !important;
1574 text-decoration: underline !important;
1575 }
1576 #pagelayer_promo a:not(.pagelayer_promo_button):not(.pagelayer_promo-close):hover {
1577 color: #3e8e41 !important;
1578 }
1579 </style>
1580 <script type="application/javascript">
1581 jQuery(document).ready(function(){
1582 jQuery("#pagelayer_promo .pagelayer_promo-close").click(function(){
1583 var data;
1584 jQuery("#pagelayer_promo").hide();
1585 // Save this preference
1586 jQuery.post("'.admin_url('?pagelayer_promo=0').'", data, function(response) {
1587 //alert(response);
1588 });
1589 });
1590 });
1591 </script>
1592
1593 <div class="notice notice-success" id="pagelayer_promo" style="min-height:90px">
1594 <a class="pagelayer_promo-close" href="javascript:" aria-label="Dismiss this Notice">
1595 <span class="dashicons dashicons-dismiss"></span> Dismiss
1596 </a>';
1597
1598 if(!empty($opts['image'])){
1599 echo '<a href="'.$opts['website'].'"><img src="'.$opts['image'].'" style="float:left; margin:10px 20px 10px 10px" width="67" /></a>';
1600 }
1601
1602 echo '
1603 <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>
1604 <p>
1605 '.(empty($opts['pro_url']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_buy" target="_blank" href="'.$opts['pro_url'].'">Buy Pagelayer Pro</a>').'
1606 '.(empty($opts['rating']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button2" target="_blank" href="'.$opts['rating'].'">Rate it 5�
1607 \'s</a>').'
1608 '.(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>').'
1609 '.(empty($opts['twitter']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button4" target="_blank" href="'.$opts['twitter'].'"><span class="dashicons dashicons-twitter"></span> Tweet</a>').'
1610 '.(empty($opts['website']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button4" target="_blank" href="'.$opts['website'].'">Visit our website</a>').'
1611 </p>
1612 <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.';
1613
1614 if(date('Ymd') <= 20200331){
1615 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>.';
1616 }
1617
1618 echo '</p></div>';
1619
1620 }
1621
1622 // Are we to show a promo ?
1623 function pagelayer_maybe_promo($opts){
1624
1625 global $pagelayer_promo_opts;
1626
1627 // There must be an interval
1628 if(!current_user_can('activate_plugins')){
1629 return false;
1630 }
1631
1632 // There must be an interval
1633 if(empty($opts['interval'])){
1634 return false;
1635 }
1636
1637 // Are we to show a promo
1638 $opt_name = 'pagelayer_promo_time';
1639 $promo_time = get_option($opt_name);
1640
1641 // First time access
1642 if(empty($promo_time)){
1643 update_option($opt_name, time() + (!empty($opts['after']) ? $opts['after'] * 86400 : 0));
1644 $promo_time = get_option($opt_name);
1645 }
1646
1647 // Is there interval elapsed
1648 if(time() > $promo_time){
1649 $pagelayer_promo_opts = $opts;
1650 add_action('admin_notices', 'pagelayer_show_promo');
1651 }
1652
1653 // Are we to disable the promo
1654 if(isset($_GET['pagelayer_promo']) && (int)$_GET['pagelayer_promo'] == 0){
1655 update_option($opt_name, time() + ($opts['interval'] * 86400));
1656 die('DONE');
1657 }
1658
1659 }
1660
1661 // Show the Pro notice
1662 function pagelayer_show_pro_notice(){
1663
1664 if(defined('PAGELAYER_PREMIUM')){
1665 return;
1666 }
1667
1668 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>';
1669
1670 }
1671
1672 // Show the Pro Div
1673 function pagelayer_show_pro_div($head = '', $message = '', $admin_css = 1){
1674
1675 if(defined('PAGELAYER_PREMIUM')){
1676 return;
1677 }
1678
1679 if(basename(get_template_directory()) == 'popularfx'){
1680 $pro_url = 'https://popularfx.com/pricing?from=pagelayer-plugin';
1681 $pro_txt = 'PopularFX Pro';
1682 }else{
1683 $pro_url = PAGELAYER_PRO_PRICE_URL;
1684 $pro_txt = 'Pagelayer Pro';
1685 }
1686
1687 if(!empty($admin_css)){
1688 wp_enqueue_style( 'pagelayer-admin', PAGELAYER_CSS.'/pagelayer-admin.css', array(), PAGELAYER_VERSION);
1689 }
1690
1691 echo '<div class="pagelayer-pro-div">';
1692
1693 if(!empty($head)){
1694 echo '<h1 class="pagelayer-pro-head">'.$head.'</h1>';
1695 }
1696
1697 echo '<div class="pagelayer-pro-message">';
1698
1699 if(empty($message)){
1700
1701 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.');
1702
1703 }else{
1704
1705 echo $message;
1706 echo ' '.__('This feature is a part of <a href="'.$pro_url.'" target="_blank">'.$pro_txt.'</a>.');
1707
1708 }
1709
1710 echo '</div>
1711 <center><a class="button-pagelayer" href="'.$pro_url.'" target="_blank" style="text-decoration: none;">'.sprintf(__('Upgrade to %s', 'pagelayer'), $pro_txt).'</a></center>
1712 </div>';
1713
1714 }
1715
1716 // Bread Crumbs with links
1717 function pagelayer_get_breadcrumb(){
1718 global $post;
1719
1720 // Home page
1721 $ret = '<a href="'.home_url().'" rel="nofollow">{{home}}</a>';
1722
1723 // Is Front page
1724 if(is_front_page()){
1725 return $ret;
1726
1727 // Is search query
1728 }elseif(is_search()){
1729 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><b class="pagelayer-breadcrumb-prefix" if="{{search_prefix}}">{{search_prefix}}</b>';
1730 $ret .= '<em>';
1731 $ret .= '<span>'.get_search_query().'</span>';
1732 $ret .= '</em>';
1733
1734 //Is category or single post
1735 }elseif(is_category() || is_single()){
1736
1737 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
1738 $categories = get_the_category();
1739 $separator = ' ';
1740 $output = '';
1741 if(!empty($categories)){
1742 $ret .= get_category_parents($categories[0], true, ' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b> ');
1743 }
1744 if(is_single()) {
1745 /* if (empty($categories)){
1746 $ret .= ' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b> ';
1747 } */
1748 $ret .= '<span>'.get_the_title().'</span>';
1749 }
1750
1751 // Is page
1752 }elseif(is_page() ){
1753 if(!empty($post->post_parent)){
1754 $ancestors = array_reverse(get_post_ancestors( $post->ID ));
1755 $page_on_front = get_option('page_on_front');
1756
1757 foreach( $ancestors as $ancestor ){
1758
1759 if($page_on_front == $ancestor){
1760 continue;
1761 }
1762
1763 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><a href="'.get_permalink($ancestor).'">'.get_the_title($ancestor).'</a>';
1764 }
1765
1766 $ret .=' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><span>'.get_the_title().'</span>';
1767
1768 }else{
1769 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
1770 $ret .= '<span>'.get_the_title().'</span>';
1771 }
1772 }else{
1773 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
1774 $ret .= '<span>'.wp_title('', false ).'</span>';
1775 }
1776
1777 // wooCommerce Integration left
1778
1779 return $ret;
1780 }
1781
1782 // Portfolio Posts
1783 function pagelayer_widget_posts($args){
1784
1785 $r = new \WP_Query($args);
1786
1787 $ret = '';
1788 if ( $r->have_posts() ){
1789
1790 if($args['filter_by'] != 'none' && $args['post_type'] == 'post'){
1791 $ret .= '<div class="pagelayer-postfolio-filter">';
1792
1793 $data_filter = ( $args['filter_by'] == 'category' ? get_categories() : get_tags() );
1794
1795 if(!empty($data_filter)){
1796
1797 $ret .= '<div class="pagelayer-postfolio-btn" data-filter="all">'.__pl('All').'</div>';
1798
1799 foreach($data_filter as $filter) {
1800 $ret .= '<div class="pagelayer-postfolio-btn" data-filter="'.$filter->name.'">' . $filter->name . '</div>';
1801 }
1802
1803 }
1804
1805 $ret .= '</div>';
1806 }
1807
1808 $ret .= '<div class="pagelayer-postfolio-container">';
1809
1810 while ( $r->have_posts() ) : $r->the_post();
1811 $post_meta = ( $args['filter_by'] == 'category' ? get_the_category() : get_the_tags() );
1812 $meta_attr = '';
1813 if($post_meta){
1814
1815 $meta_array = array();
1816 foreach( $post_meta as $meta ){
1817 $meta_array[] = $meta->name;
1818 }
1819 $meta_attr .= ' data-category="'.implode(' ', $meta_array).'"';
1820 }
1821
1822 $ret .= '<div class="pagelayer-postfolio-thumb"'.(has_post_thumbnail() ? ' style="background:url('.get_the_post_thumbnail_url().')"' : ''). $meta_attr .'>';
1823 $ret .= '<a href="'.esc_url( get_permalink() ).'" rel="bookmark">';
1824 $ret .= '<div class="pagelayer-postfolio-content">';
1825 $ret .= '<h4 class="pagelayer-entry-title">'.get_the_title().'</h4>';
1826 $ret .= '</div></a></div>';
1827
1828 endwhile;
1829
1830 $ret .= '</div>';
1831
1832 }
1833
1834 return $ret;
1835 }
1836
1837 // List all available sizes of images registered on WordPress
1838 function pagelayer_image_sizes(){
1839
1840 $sizes = array();
1841 $sizes = get_intermediate_image_sizes();
1842 $ret = array();
1843 foreach($sizes as $size){
1844 $ret[$size] = __pl($size);
1845 }
1846
1847 return $ret;
1848 }
1849
1850 function pagelayer_remove_excerpt_more($more){
1851 return '';
1852 }
1853
1854 function pagelayer_posts($params, $args = []){
1855 global $post, $wp_query;
1856
1857 if(isset($params['exc_length'])){
1858 $exc_length = (int) $params['exc_length'];
1859 add_filter( 'excerpt_length', function($length) use($exc_length){
1860 return $exc_length;
1861 }, 999 );
1862 }
1863
1864 // add_filter('excerpt_more', 'pagelayer_remove_excerpt_more', 999);
1865
1866 // If args is empty
1867 if(empty($args)){
1868 $args = array(
1869 'post_type' => $params['post_type'],
1870 'posts_per_page' => $params['posts_per_page'],
1871 'order' => $params['order']
1872 );
1873
1874 if(!empty($params['paged'])){
1875 $args['paged'] = $params['paged'];
1876 }
1877
1878 if (!empty($params['term']) || !empty($params['exc_term'])) {
1879 $tax_query = [];
1880
1881 if (!empty($params['term'])) {
1882 $terms = explode(',', $params['term']);
1883 $include = array_reduce($terms, function ($carry, $term) {
1884 list($taxonomy, $slug, $id) = explode(':', $term);
1885 $carry[$taxonomy][] = $slug;
1886 return $carry;
1887 }, []);
1888
1889 $filters = array_filter([
1890 isset($include['category']) ? [
1891 'taxonomy' => 'category',
1892 'field' => 'slug',
1893 'terms' => $include['category'],
1894 'include_children' => false,
1895 ] : null,
1896 isset($include['post_tag']) ? [
1897 'taxonomy' => 'post_tag',
1898 'field' => 'slug',
1899 'terms' => $include['post_tag'],
1900 'include_children' => false,
1901 ] : null,
1902 ]);
1903
1904 if(!empty($filters)){
1905 $tax_query[] = array_merge(['relation' => 'OR'], $filters);
1906 }
1907 }
1908
1909 // Handle exclusions
1910 if (!empty($params['exc_term'])) {
1911 $terms = explode(',', $params['exc_term']);
1912 $include = array_reduce($terms, function ($carry, $term) {
1913 list($taxonomy, $slug, $id) = explode(':', $term);
1914 $carry[$taxonomy][] = $slug;
1915 return $carry;
1916 }, []);
1917
1918 $filters = array_filter([
1919 isset($include['category']) ? [
1920 'taxonomy' => 'category',
1921 'field' => 'slug',
1922 'terms' => $include['category'],
1923 'operator' => 'NOT IN',
1924 'include_children' => false,
1925 ] : null,
1926 isset($include['post_tag']) ? [
1927 'taxonomy' => 'post_tag',
1928 'field' => 'slug',
1929 'terms' => $include['post_tag'],
1930 'operator' => 'NOT IN',
1931 'include_children' => false,
1932 ] : null,
1933 ]);
1934
1935 if(!empty($filters)){
1936 $tax_query[] = array_merge(['relation' => 'AND'], $filters);
1937 }
1938 }
1939
1940 // Apply the combined tax_query
1941 if(!empty($tax_query)){
1942 $args['tax_query'] = array_merge(['relation' => 'AND'], $tax_query);
1943 }
1944 }
1945
1946 if(!empty($params['author_name'])){
1947 $author_name = explode(':', $params['author_name']);
1948 $args['author_name'] = $author_name[0];
1949 }
1950
1951 if(!empty($params['exc_author'])){
1952 $exc_author = explode(':', $params['exc_author']);
1953 $args['author'] = '-'.$exc_author[1];
1954 }
1955
1956 if (!empty($params['offset'])) {
1957 $args['offset'] = (int) $params['offset'];
1958
1959 // Make Compatible for Infinite load
1960 if(!empty($params['infinite_types']) && !empty($params['paged']) && $params['paged'] > 1 ){
1961 $args['offset'] = $args['offset'] + (($params['paged'] - 1) * $params['posts_per_page']);
1962 }
1963 }
1964
1965 if(!empty($params['ignore_sticky'])){
1966 $args['ignore_sticky_posts'] = $params['ignore_sticky'];
1967 }
1968
1969 if(!empty($params['orderby'])){
1970 $args['orderby'] = $params['orderby'];
1971 }
1972
1973 if(!empty($params['by_period'])){
1974 $date_arg = array();
1975 switch($params['by_period']){
1976 case 'last_day':
1977 $date_arg['day'] = date('j')-1;
1978 break;
1979 case 'last_week':
1980 $date_arg['week'] = date('W')-1;
1981 break;
1982 case 'last_month':
1983 $date_arg['month'] = date('n')-1;
1984 break;
1985 case 'last_year':
1986 $date_arg['year'] = date('Y')-1;
1987 break;
1988 case 'custom':
1989 $date_arg['before'] = $params['before_date'];
1990 $date_arg['after'] = $params['after_date'];
1991 break;
1992 }
1993 $args['date_query'] = array(
1994 $date_arg
1995 );
1996 }
1997 }
1998 //pagelayer_print($args);
1999
2000 // Only see published posts
2001 $args['post_status'] = 'publish';
2002
2003 $postsquery = new WP_Query($args);
2004 $data = '';
2005
2006 if(!wp_doing_ajax() && !empty($params['infinite_types'])){
2007 $data.='<div class="pagelayer-post-max" data-max="'.$postsquery->max_num_pages.'"></div>';
2008 }
2009
2010 if(!$postsquery->have_posts()){
2011 return '<h3>No posts found!</h3>';
2012 }
2013
2014 // To reset the post when the $wp_query->post is empty
2015 $orig_post = $post;
2016
2017 while($postsquery->have_posts()) : $postsquery->the_post();
2018 $data .= '<div class="pagelayer-wposts-col">
2019 <div class="pagelayer-wposts-post">
2020 <div class="pagelayer-wposts-featured">';
2021 $data .= '<a href="'. get_the_permalink() .'">';
2022
2023 if(!empty($params['show_thumb'])){
2024 $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>';
2025 }
2026 /* if($params['show_thumb'] && has_post_thumbnail( $postsquery->ID )){
2027 $data .= get_the_post_thumbnail_url($postsquery->ID,$params['thumb_size']);
2028 } */
2029 $data .= '</a></div>
2030 <div class="pagelayer-wposts-content">';
2031
2032 if(!empty($params['show_title'])){
2033 $data .= '<a href="'.esc_url( get_permalink() ).'" rel="bookmark"><div class="pagelayer-wposts-title">'. get_the_title().'</div></a>';
2034 }
2035
2036 $data .= '<div class="pagelayer-wposts-meta">';
2037 $sep = '';
2038 if(!empty($params['meta_sep'])){
2039 $sep = ' <b class="pagelayer-wposts-sep">'.$params['meta_sep'].'</b> ';
2040 }
2041 if(!empty($params['author'])){
2042 $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;
2043 }
2044 if(!empty($params['date'])){
2045 $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;
2046 }
2047
2048 if(!empty($params['category'])){
2049 $category = get_the_category();
2050 $singlecategory = '';
2051 foreach( $category as $cat ){
2052 $singlecategory .= '<a href="' . get_tag_link( $cat->term_id ) . '">'. $cat->name .'</a>';
2053 }
2054
2055 if(!empty($singlecategory)){
2056 $data .= '<span class="pagelayer-wposts-category">' . $singlecategory . '</span>'.$sep;
2057 }
2058
2059 }
2060
2061 if(!empty($params['tags'])){
2062 $tags = get_the_tags();
2063 $singletag = '';
2064 if(!empty($tags)){
2065 foreach( $tags as $tag ){
2066 $singletag .= '<a href="' . get_tag_link( $tag->term_id ) . '">'. $tag->name .'</a>';
2067 }
2068 if(!empty($singletag)){
2069 $data .= '<span class="pagelayer-wposts-tags">'.$singletag.'</span>'.$sep;
2070 }
2071 }
2072
2073 }
2074
2075 if(!empty($params['comments']) && comments_open($postsquery->ID)){
2076 $data .= '<span class="pagelayer-wposts-comments"><a href="' . esc_url( get_permalink() ) . '">' . esc_html(get_comments_number()).' '.__pl('comments').'</a></span>'.$sep;
2077 }
2078
2079 $data .= '</div>';
2080
2081 if(!empty($params['show_content'])){
2082 $data .= '<div class="pagelayer-wposts-excerpt">';
2083
2084 if($params['show_content'] == 'excerpt'){
2085 $post_excerpt = get_the_excerpt();
2086 $trimmed_excerpt = !empty($params['exc_length']) ? wp_trim_words($post_excerpt, (int) $params['exc_length']) : $post_excerpt;
2087 $data .= pagelayer_the_content($trimmed_excerpt);
2088 } elseif ($params['show_content'] == 'full') {
2089 $data .= pagelayer_the_content(get_the_content());
2090 }
2091 $data .= '</div>';
2092 }
2093
2094 if(!empty($params['show_more'])){
2095 $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().'">';
2096
2097 if($params['icon']){
2098 $data .= '<i class="'.$params['icon'].' pagelayer-btn-icon"></i>';
2099 }
2100
2101 if($params['more']){
2102 $data .= '<span class="pagelayer-btn-text">'.$params['more'].'</span>';
2103 }
2104
2105 if($params['icon']){
2106 $data .= '<i class="'.$params['icon'].' pagelayer-btn-icon"></i>';
2107 }
2108
2109 $data .= '</a></div>';
2110
2111 //$data .= '<a class="pagelayer-wposts-more" href="'. get_the_permalink().'">'.$params['more'].'</a>';
2112 }
2113
2114 //$data .= '<div class="pagelayer-wposts-date"><p>'.get_the_date().'</p></div>';
2115 $data .= '</div></div></div>';
2116 endwhile;
2117
2118 // In the Gutenberg while adding new page the $wp_query->post was empty
2119 if ( !isset( $wp_query ) || empty($wp_query->post) ) {
2120 $GLOBALS['post'] = $orig_post;
2121 }else{
2122 wp_reset_postdata();
2123 }
2124
2125 return $data;
2126 }
2127
2128 // Get Post Revision
2129 function pagelayer_get_post_revision_by_id($postID){
2130
2131 // Insert the post revision into the database
2132 $post_revisions = array();
2133 $reviews = wp_get_post_revisions($postID);
2134
2135 foreach($reviews as $values){
2136
2137 $date_format = date_i18n('j-M @ H:i', strtotime( $values->post_modified ) );
2138 $user_meta = get_userdata($values->post_author);
2139
2140 if ( false !== strpos( $values->post_name, 'autosave' ) ) {
2141 $type = 'autosave';
2142 } else {
2143 $type = 'revision';
2144 }
2145
2146 $post_tmp_data = array(
2147 'ID' => $values->ID,
2148 'post_author_name' => $user_meta->data->display_name,
2149 'post_author_url' => get_avatar_url($values->post_author),
2150 'post_date' => $date_format,
2151 'post_date_ago' => human_time_diff(strtotime($values->post_modified), current_time( 'timestamp' )) . ' ago ',
2152 'post_type' => $type,
2153 );
2154
2155 $post_revisions[] = $post_tmp_data;
2156 }
2157
2158 return $post_revisions;
2159 }
2160
2161 // Gets author data
2162 function pagelayer_author_data($postID){
2163
2164 $authorID = get_post_field('post_author', $postID);
2165 $data['display_name'] = get_the_author_meta( 'display_name' , $authorID );
2166 $data['description'] = get_the_author_meta( 'description' , $authorID );
2167 $data['user_url'] = get_author_posts_url( $authorID , '' );
2168 $data['avatar'] = get_avatar_url( $authorID );
2169
2170 return $data;
2171 }
2172
2173 // Posts Slider
2174 function pagelayer_posts_slider($params){
2175
2176 $args = array();
2177
2178 if(isset($params['post']['post_type'])){
2179 $args['post_type'] = $params['post']['post_type'];
2180 }
2181
2182 if(isset($params['post']['category'])){
2183 $args['category_name'] = $params['post']['category'];
2184 }
2185
2186 if(isset($params['post']['tags'])){
2187 $args['tag'] = $params['post']['tags'];
2188 }
2189
2190 if(isset($params['post']['order_by'])){
2191 $args['orderby'] = $params['post']['order_by'];
2192 }
2193
2194 if(isset($params['post']['sort_order'])){
2195 $args['order'] = $params['post']['sort_order'];
2196 }
2197
2198 if(isset($params['post']['post_count'])){
2199 $args['posts_per_page'] = $params['post']['post_count'];
2200 }
2201
2202 $data = '';
2203 $postsquery = new WP_Query($args);
2204 if ( $postsquery->have_posts() ){
2205 while ( $postsquery->have_posts() ) : $postsquery->the_post();
2206 $data .= '<li class="pagelayer-posts-slider-col">
2207 <div class="pagelayer-posts-slider-post">
2208 <div class="pagelayer-posts-slider-featured-img">';
2209 $data .= '<a href="'. get_the_permalink() .'">';
2210 if(has_post_thumbnail( $postsquery->ID ) ){
2211 if($params['post']['image_size'] == "full" || $params['post']['image_size'] == "custom" ){
2212 $image = wp_get_attachment_image_src( get_post_thumbnail_id( $postsquery->ID ), 'single-post-thumbnail' );
2213 $data .= '<img class="pagelayer-img" src="'.$image[0].'" class="pagelayer-posts-slider-img">';
2214 }else if($params['post']['image_size'] == "thumbnail"){
2215 $data .= get_the_post_thumbnail();
2216 }
2217 }
2218 $data .= '</a></div>
2219 <div class="pagelayer-posts-slider-content">';
2220 $data .= '<p class="pagelayer-posts-slider-title">'. get_the_title().'</p>';
2221 $data .= '<div class="pagelayer-posts-slider-excerpt">';
2222 if($params['post']['show_excerpt'] == "true"){
2223 if(has_excerpt()){
2224 $excerpt = get_the_excerpt();
2225 $data .= pagelayer_the_content($excerpt);
2226 }
2227 }
2228 $data .= '</div>';
2229 $data .= '<a class="pagelayer-posts-slider-link" href="'. get_the_permalink().'">Read More</a>';
2230 $data .= '<div class="pagelayer-post-slider-date"><p>'.get_the_date().'</p></div>';
2231 $data .= '</div></div></li>';
2232 endwhile;
2233 }
2234 return $data;
2235 }
2236
2237 // Gets the site logo URLs
2238 function pagelayer_site_logo(){
2239
2240 if(get_theme_mod('custom_logo')){
2241 $logo_id = get_theme_mod('custom_logo');
2242 return pagelayer_image($logo_id);
2243 }
2244
2245 return NULL;
2246 }
2247
2248 // Create select options
2249 function pagelayer_create_sel_options( $opt_array , $selected = ''){
2250 $options = '';
2251 foreach($opt_array as $x => $val){
2252
2253 // Single item
2254 if(is_string($opt_array[$x])){
2255 $options .= pagelayer_sel_option($x, $val, $selected);
2256
2257 // Groups
2258 }else{
2259
2260 if(array_key_exists('hide_drop', $opt_array[$x]) && !empty($opt_array[$x]['hide_drop'])){
2261 continue;
2262 }
2263
2264 // If Label is there, then its a normal option
2265 if(array_key_exists('label', $opt_array[$x])){
2266 $options .= pagelayer_sel_option($x, $opt_array[$x]['label'], $selected);
2267
2268 // Optgroups
2269 } else{
2270 $options .= '<optgroup label="'. $x .'">';
2271 $options .= pagelayer_create_sel_options($opt_array[$x], $selected);
2272 $options .= '</optgroup>';
2273 }
2274 }
2275 }
2276
2277 return $options;
2278 }
2279
2280 // Create option HTML
2281 function pagelayer_sel_option($val, $lang, $selected){
2282 return '<option value="'. $val .'" '. (($val != $selected) ? '' : 'selected="selected"') .' >'. $lang .'</option>';
2283 }
2284
2285 // Get values from multi-dimensional array by key
2286 function pagelayer_multi_array_search(&$array, $key){
2287
2288 if(!is_array($array)){
2289 return false;
2290 }
2291
2292 foreach ($array as $k => $v) {
2293
2294 if($k == $key){
2295 return $v;
2296 }
2297
2298 if (is_array($v)) {
2299 $found = pagelayer_multi_array_search($v, $key);
2300 if(!empty($found)){
2301 return $found;
2302 }
2303 }
2304 }
2305
2306 return false;
2307 }
2308
2309 function pagelayer_get_post_term(){
2310
2311 $args = [
2312 'taxonomy' => array('category','post_tag'),
2313 'hide_empty' => false,
2314 ];
2315
2316 $terms = get_terms( $args );
2317
2318 $ret = array();
2319 foreach ( $terms as $term ) {
2320 $ret[$term->taxonomy.':'.$term->slug.':'.$term->term_taxonomy_id] = $term->taxonomy .': '. $term->name;
2321 }
2322 //pagelayer_print($terms);die();
2323 return $ret;
2324 }
2325
2326 function pagelayer_get_post_author(){
2327
2328 $args = [
2329 'capability' => array( 'edit_posts' ),
2330 'fields' => [
2331 'ID',
2332 'display_name',
2333 'user_nicename',
2334 ]
2335 ];
2336
2337 // Capability queries were only introduced in WP 5.9.
2338 if( version_compare( $GLOBALS['wp_version'], '5.9-alpha', '<' ) ){
2339 $args['who'] = 'authors';
2340 unset( $args['capability'] );
2341 }
2342
2343 $authors = new \WP_User_Query( $args );
2344
2345 $ret = array();
2346 foreach ( $authors->get_results() as $author ) {
2347 $ret[$author->user_nicename.':'.$author->ID] = $author->display_name;
2348 }
2349 //pagelayer_print($authors->get_results());die();
2350 return $ret;
2351 }
2352
2353 // Gets the registered post types
2354 function pagelayer_get_public_post_types( $args = [] ) {
2355
2356 global $pagelayer;
2357
2358 $post_type_args = [
2359 'public' => true,
2360 ];
2361
2362 $post_type_args = wp_parse_args( $post_type_args, $args );
2363
2364 $_post_types = get_post_types( $post_type_args, 'objects' );
2365
2366 $post_types = array();
2367
2368 foreach ( $_post_types as $post_type => $object ) {
2369
2370 if($post_type == $pagelayer->builder['name']){
2371 continue;
2372 }
2373
2374 $post_types[ $post_type ] = $object->label;
2375 }
2376 //print_r($post_types);
2377
2378 return $post_types;
2379 }
2380
2381 // Simply echo and dir
2382 function pagelayer_json_output(&$done){
2383
2384 echo json_encode($done);
2385 wp_die();
2386
2387 }
2388
2389 // Get the current query for render the product
2390 function pagelayer_shortcode_current_query($query_args, $atts, $type){
2391 global $wp_query;
2392
2393 if($type == 'pagelayer_current_query'){
2394
2395 if ( ! is_page( wc_get_page_id( 'shop' ) ) ) {
2396 $query_args = $wp_query->query_vars;
2397 }
2398
2399 add_action( "woocommerce_shortcode_before_{$type}_loop", function () {
2400 wc_set_loop_prop( 'is_shortcode', false );
2401 } );
2402
2403 if(!empty($atts['paginate'])){
2404 $page = get_query_var( 'paged', 1 );
2405
2406 if( 1 < $page ) {
2407 $query_args['paged'] = $page;
2408 }
2409 }
2410
2411 // Always query only IDs
2412 $query_args['fields'] = 'ids';
2413
2414 }
2415
2416 return $query_args;
2417 }
2418
2419 // Loads the tags which have parameters of a particular type
2420 function pagelayer_get_prop_type($types){
2421
2422 global $pagelayer;
2423
2424 if(!is_array($types)){
2425 $types = [$types];
2426 }
2427
2428 $ret = [];
2429
2430 // Loop thru all shortcodes
2431 foreach($pagelayer->shortcodes as $tag => $vvv){
2432
2433 // Lets create the CSS, Classes, Attr. Also clean the dependent atts
2434 foreach($pagelayer->tabs as $tab){
2435
2436 if(empty($pagelayer->shortcodes[$tag][$tab])){
2437 continue;
2438 }
2439
2440 foreach($pagelayer->shortcodes[$tag][$tab] as $section => $Lsection){
2441
2442 $props = empty($pagelayer->shortcodes[$tag][$section]) ? @$pagelayer->styles[$section] : @$pagelayer->shortcodes[$tag][$section];
2443
2444 //echo $tab.' - '.$section.' - <br>';
2445
2446 if(empty($props)){
2447 continue;
2448 }
2449
2450 // Loop all props
2451 foreach($props as $prop => $param){
2452
2453 // Load any attachment values
2454 if(!in_array($param['type'], $types)){
2455 continue;
2456 }
2457
2458 $ret[$tag][$prop] = $param['type'];
2459
2460 }
2461
2462 }
2463
2464 }
2465
2466 }
2467
2468 //r_print($ret);die();
2469
2470 return $ret;
2471
2472 }
2473
2474 function pagelayer_export_content($content){
2475
2476 global $pagelayer;
2477
2478 // Just call do_shortcode so we can get list of media files to export
2479 //do_shortcode($content);
2480
2481 $theme_url = preg_replace('/http(s?):\/\//is', '', get_stylesheet_directory_uri());
2482
2483 $content = preg_replace('/http(s?):\/\/'.preg_quote($theme_url, '/').'/is', '{{theme_url}}', $content);
2484
2485 // Remove unnecessary spaces
2486 $content = preg_replace('/--\>\s*(?!<!--)/is', '-->', $content);
2487
2488 // Replace links of the theme for images
2489 $content = pagelayer_export_theme_links($content, get_stylesheet_directory_uri());
2490
2491 ////////////////////
2492 // Handle Link IDs
2493 ////////////////////
2494
2495 if(empty($pagelayer->e['link_tags'])){
2496 $pagelayer->e['link_tags'] = pagelayer_get_prop_type('link');
2497 //r_print($pagelayer->e['link_tags']);die();
2498 }
2499
2500 if(empty($pagelayer->e['media_tags'])){
2501 $pagelayer->e['media_tags'] = pagelayer_get_prop_type(['image', 'video', 'audio', 'media', 'multi_image']);
2502 //r_print($pagelayer->e['media_tags']);die();
2503 }
2504
2505 $parsed = parse_blocks($content);
2506 //r_print($parsed);//die();
2507
2508 $parsed = pagelayer_export_link_ids($parsed);
2509
2510 // Export the media as well
2511 $parsed = pagelayer_export_media($parsed);
2512
2513 // Reserialize
2514 $content = serialize_blocks($parsed);
2515
2516 // We store in SP format
2517 $content = str_replace('<!-- wp:pagelayer', '<!-- sp:pagelayer', $content);
2518 $content = str_replace('<!-- /wp:pagelayer', '<!-- /sp:pagelayer', $content);
2519
2520 // Just pass the content to
2521 $content = pagelayer_export_extract_menu_ids($content);
2522
2523 // Apply a filter
2524 $content = apply_filters('pagelayer_export_content', $content);
2525
2526 return $content;
2527
2528 }
2529
2530 // Export the menu IDs
2531 function pagelayer_export_extract_menu_ids($content){
2532
2533 global $pagelayer;
2534
2535 // Any Menu ?
2536 preg_match_all('/\[pl_wp_menu ([^\]]*)nav_list="(\d*)"([^\]]*)\]/is', $content, $matches);
2537 //r_print($matches);
2538
2539 if(!empty($matches[2])){
2540
2541 foreach($matches[2] as $k => $v){
2542 $v = (int)$v;
2543 $pagelayer->export_menus[$v] = $v;
2544 }
2545 //r_print($pagelayer->export_menus);
2546
2547 }
2548
2549 // Also for block format
2550 preg_match_all('/<!--\s+(?P<closer>\/)?sp:pagelayer\/pl_wp_menu\s+(?P<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*+)?}\s+)?(?P<void>\/)?-->/s', $content, $matches);
2551
2552 if(!empty($matches['attrs'])){
2553
2554 foreach($matches['attrs'] as $k => $v){
2555 preg_match('/nav_list"\s*:\s*"(\d*)"/is', $v, $vmatch);
2556
2557 if(!empty($vmatch[1])){
2558 $vmatch[1] = (int)$vmatch[1];
2559 $pagelayer->export_menus[$vmatch[1]] = $vmatch[1];
2560 //r_print($pagelayer->export_menus);
2561 }
2562 }
2563 }
2564
2565 return $content;
2566
2567 }
2568
2569 function pagelayer_export_link_ids($parsed){
2570
2571 global $pagelayer;
2572
2573 foreach($parsed as $k => $v){
2574
2575 if(!empty($v['innerBlocks'])){
2576 $parsed[$k]['innerBlocks'] = pagelayer_export_link_ids($v['innerBlocks']);
2577 }
2578
2579 if(!preg_match('/pagelayer/is', $v['blockName'])){
2580 continue;
2581 }
2582
2583 $tag = str_replace('pagelayer/', '', $v['blockName']);
2584 //echo $tag;//die();
2585
2586 // Is there a tag having a link prop
2587 if(empty($pagelayer->e['link_tags'][$tag])){
2588 continue;
2589 }
2590 //echo $tag;die();
2591
2592 foreach($pagelayer->e['link_tags'][$tag] as $kk => $vv){
2593 if(!empty($v['attrs'][$kk]) && is_numeric($v['attrs'][$kk])){
2594 $linked = get_post($v['attrs'][$kk]);
2595 if(!empty($linked->post_name)){
2596 $parsed[$k]['attrs'][$kk] = '||link_id|'.$linked->post_type.'|'.$linked->post_name.'||';
2597 }
2598 //echo $tag;echo '-'.$kk;r_print($parsed[$k]['attrs']);die();
2599 }
2600 }
2601
2602 }
2603
2604 return $parsed;
2605
2606 }
2607
2608 // Replace theme links with theme_url
2609 function pagelayer_export_theme_links($content, $link){
2610
2611 global $sitepad;
2612
2613 // Theme URL correction code
2614 $theme_url = preg_replace('/http(s?):\/\//is', '', $link);
2615
2616 $theme_urls[0] = 'http://'.$theme_url;
2617 $theme_urls[1] = 'https://'.$theme_url;
2618 $theme_urls[2] = $theme_url;
2619 $theme_urls[3] = str_replace('/', '\\/', $theme_urls[0]);
2620 $theme_urls[4] = str_replace('/', '\\/', $theme_urls[1]);
2621 $theme_urls[5] = str_replace('/', '\\/', $theme_url);
2622
2623 foreach($theme_urls as $k => $v){
2624 $content = preg_replace_callback('/'.preg_quote($v, '/').'([^"]*)/is', 'pagelayer_export_theme_links_replacer', $content);
2625 }
2626
2627 $content = str_ireplace($theme_urls, '{{theme_url}}', $content);
2628
2629 return $content;
2630 }
2631
2632 // This function is a part of pagelayer_export_theme_links
2633 function pagelayer_export_theme_links_replacer($matches){
2634 return '{{theme_url}}'.str_replace('\\/', '/', $matches[1]);
2635 }
2636
2637 // Export media
2638 function pagelayer_export_media($parsed){
2639
2640 global $pagelayer;
2641
2642 foreach($parsed as $k => $v){
2643
2644 if(!empty($v['innerBlocks'])){
2645 $parsed[$k]['innerBlocks'] = pagelayer_export_media($v['innerBlocks']);
2646 }
2647
2648 if(!preg_match('/pagelayer/is', $v['blockName'])){
2649 continue;
2650 }
2651
2652 $tag = str_replace('pagelayer/', '', $v['blockName']);
2653 //echo $tag;//die();
2654
2655 // Is there a tag having a link prop
2656 if(empty($pagelayer->e['media_tags'][$tag])){
2657 continue;
2658 }
2659 //echo $tag;die();
2660
2661 foreach($pagelayer->e['media_tags'][$tag] as $kk => $vv){
2662
2663 if(empty($v['attrs'][$kk])){
2664 continue;
2665 }
2666
2667 $is_array = 0;
2668
2669 // Is it an array
2670 if(is_array($v['attrs'][$kk])){
2671
2672 $ids = $v['attrs'][$kk];
2673 $is_array = 1;
2674
2675 // Is it of the format 1,2,3
2676 }elseif(preg_match('/^((\d*)(,?))*$/is', $v['attrs'][$kk])){
2677
2678 $ids = pagelayer_maybe_explode(',', $v['attrs'][$kk]);
2679
2680 // Its a number or string
2681 }else{
2682
2683 // Is it our default image ?
2684 if(preg_match('/pagelayer-pro\/images\/default-image.png$/is', $v['attrs'][$kk])){
2685 $parsed[$k]['attrs'][$kk] = '';
2686 continue;
2687 }
2688
2689 // It should be a number
2690 if(!is_numeric($v['attrs'][$kk])){
2691 continue;
2692 }
2693
2694 $ids = [$v['attrs'][$kk]];
2695 }
2696
2697 $ret = [];
2698
2699 foreach($ids as $id){
2700
2701 $file = pagelayer_export_media_files($id, $exp_img_url);
2702
2703 // Did it export ?
2704 if(empty($file) || !file_exists($file)){
2705 continue;
2706 }
2707
2708 $ret[] = $exp_img_url;
2709
2710 }
2711
2712 $parsed[$k]['attrs'][$kk] = $is_array ? $ret : implode(',', $ret);
2713 //echo $tag;echo '-'.$kk;r_print($parsed[$k]['attrs']);die();
2714 }
2715
2716 }
2717
2718 return $parsed;
2719
2720 }
2721
2722 // Exports the media to the images folder of the current theme
2723 function pagelayer_export_media_files($id, &$url = ''){
2724
2725 $theme_dir = get_stylesheet_directory();
2726 $image_dir = $theme_dir.'/images/';
2727 @mkdir($image_dir);
2728
2729 // Get the file path
2730 $file = get_attached_file($id);
2731
2732 if(empty($file) || !file_exists($file)){
2733 return false;
2734 }
2735
2736 $dest_file = $image_dir.basename($file);
2737
2738 // Copy the file
2739 copy($file, $dest_file);
2740
2741 // Replace the text
2742 $url = '{{theme_url}}/images/'.basename($file);
2743
2744 return $dest_file;
2745
2746 //echo $content;
2747 }
2748
2749 // Insert a post which is a Pagelayer Post
2750 function pagelayer_sanitize_content($content){
2751
2752 if(empty($content)){
2753 return $content;
2754 }
2755
2756 // Replace Vars
2757 $template_vars = pagelayer_template_vars();
2758
2759 foreach($template_vars as $key => $val){
2760 $content = str_replace($key, $val, $content);
2761 }
2762
2763 if(defined('PAGELAYER_BLOCK_PREFIX') && PAGELAYER_BLOCK_PREFIX == 'wp'){
2764 $content = str_replace('<!-- sp:pagelayer', '<!-- wp:pagelayer', $content);
2765 $content = str_replace('<!-- /sp:pagelayer', '<!-- /wp:pagelayer', $content);
2766 }
2767
2768 return $content;
2769 }
2770
2771 // Insert a post which is a Pagelayer Post
2772 function pagelayer_insert_content($post, &$ret){
2773
2774 $post = apply_filters('pagelayer_start_insert_content', $post);
2775
2776 $post['post_content'] = pagelayer_sanitize_content($post['post_content']);
2777 //pagelayer_print($post);die();
2778
2779 // Add slashes for safe insert
2780 $post['post_content'] = wp_slash($post['post_content']);
2781
2782 $post = apply_filters('pagelayer_pre_insert_content', $post);
2783
2784 // Now insert / update the post
2785 $ret = wp_insert_post($post);
2786
2787 // Did we save the post ?
2788 if(empty($ret) || is_wp_error($ret)){
2789 return false;
2790 }
2791
2792 // Convert to pagelayer accessed post
2793 if(!add_post_meta($ret, 'pagelayer-data', time(), true)){
2794 update_post_meta($ret, 'pagelayer-data', time());
2795 }
2796
2797 return $ret;
2798
2799 }
2800
2801 // Gets the list of enabled fonts
2802 function pagelayer_enabled_icons(){
2803
2804 $stored_icons = get_option('pagelayer_icons_set');
2805 if(empty($stored_icons)){
2806 update_option('pagelayer_icons_set', ['font-awesome5']);
2807 $stored_icons = get_option('pagelayer_icons_set');
2808 }
2809
2810 return $stored_icons;
2811
2812 }
2813
2814 // Prevent pro activate text for installer
2815 function pagelayer_install_plugin_complete_actions($install_actions, $api, $plugin_file){
2816
2817 if($plugin_file == PAGELAYER_PREMIUM_BASE){
2818 return array();
2819 }
2820
2821 return $install_actions;
2822 }
2823
2824 // Handle hexa to rgba and also remove alpha which is ff
2825 function pagelayer_hex8_to_rgba($val){
2826
2827 // If opacity is ff then discard ff
2828 if(preg_match('/^#([a-f0-9]{6})ff$/is', $val)){
2829 return substr($val, 0, 7);
2830 }
2831
2832 // Lets handle the RGB+opacity
2833 if(preg_match('/#([a-f0-9]{8})$/is', $val)){
2834 $val = pagelayer_hex2rgba($val);
2835 }
2836
2837 return $val;
2838
2839 }
2840
2841 // Convert to RGBA from HEX
2842 function pagelayer_hex2rgba($color){
2843
2844 //Return if no color provided
2845 if(empty($color)){
2846 return;
2847 }
2848
2849 //Sanitize $color if "#" is provided
2850 if ($color[0] == '#'){
2851 $color = substr( $color, 1 );
2852 }
2853
2854 //Check if color has 6 or 3 characters and get values
2855 if (strlen($color) == 8) {
2856 $hex = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
2857 $alpha = $color[6] . $color[7];
2858 //$alpha = '';
2859 } elseif (strlen($color) == 6) {
2860 $hex = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
2861 } elseif ( strlen( $color ) == 3 ) {
2862 $hex = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
2863 } else {
2864 return;
2865 }
2866
2867 //Convert hexadec to rgb
2868 $rgb = array_map('hexdec', $hex);
2869
2870 //Check if opacity is set(rgba or rgb)
2871 if($alpha){
2872
2873 $alpha = number_format((float)hexdec($alpha) / 255, 2, '.', '');
2874 //print_r($alpha);
2875 if(abs($alpha) > 1){
2876 $alpha = 1.0;
2877 }
2878 $output = 'rgba('.implode(",",$rgb).','.$alpha.')';
2879 } else {
2880 $output = 'rgb('.implode(",",$rgb).')';
2881 }
2882
2883 //Return rgb(a) color string
2884 return $output;
2885 }
2886
2887 // Get social URLs
2888 function pagelayer_get_social_urls(){
2889
2890 $urls = array();
2891
2892 $urls['facebook'] = get_option('pagelayer-facebook-url');
2893 $urls['twitter'] = get_option('pagelayer-twitter-url');
2894 $urls['instagram'] = get_option('pagelayer-instagram-url');
2895 $urls['linkedin'] = get_option('pagelayer-linkedin-url');
2896 $urls['youtube'] = get_option('pagelayer-youtube-url');
2897 $urls['google'] = get_option('pagelayer-gplus-url');
2898
2899 foreach($urls as $k => $v){
2900
2901 if(empty($v)){
2902 unset($urls[$k]);
2903 continue;
2904 }
2905
2906 $urls[$k] = esc_url($v);
2907 }
2908
2909 return $urls;
2910 }
2911
2912 function pagelayer_get_option($opt){
2913 $ret = get_option($opt);
2914
2915 $opts = array(
2916 'pagelayer-address' => '1, My Address, My Street, New York City, NY, USA',
2917 'pagelayer-phone' => '+1234567890',
2918 'pagelayer-copyright' => '© '.date('Y').' '.get_option('blogname'),
2919 'pagelayer_cf_to_email' => 'contact@domain.com',
2920 'pagelayer_cf_success' => __pl('cf_success'),
2921 'pagelayer_cf_failed' => __pl('cf_failed'),
2922 );
2923
2924 if(empty($ret)){
2925 return $opts[$opt];
2926 }
2927
2928 return wp_kses_post($ret);
2929 }
2930
2931 // Uploads an image / media
2932 function pagelayer_upload_media($filename, $blob){
2933
2934 if(empty($blob)){
2935 return false;
2936 }
2937
2938 $md5 = md5($blob);
2939
2940 // Do we have this image
2941 $args = array(
2942 'post_type' => 'attachment',
2943 'post_status' => 'inherit',
2944 'meta_query' => array(
2945 array(
2946 'key' => 'pagelayer_image_md5',
2947 'value' => $md5,
2948 )
2949 )
2950 );
2951
2952 $query = new WP_Query($args);
2953
2954 // If we found the image, return
2955 foreach($query->posts as $ck => $cv){
2956 return $cv->ID;
2957 }
2958
2959 $upload = wp_upload_bits($filename, null, $blob);
2960
2961 if( !empty( $upload['error'] ) ) {
2962 return false;
2963 }
2964
2965 $file_path = $upload['file'];
2966 $file_name = basename( $file_path );
2967 $file_type = wp_check_filetype( $file_name, null );
2968 $attachment_title = sanitize_file_name( pathinfo( $file_name, PATHINFO_FILENAME ) );
2969 $wp_upload_dir = wp_upload_dir();
2970
2971 $post_info = array(
2972 'guid' => $wp_upload_dir['url'] . '/' . $file_name,
2973 'post_mime_type'=> $file_type['type'],
2974 'post_title' => $attachment_title,
2975 'post_content' => '',
2976 'post_status' => 'inherit',
2977 );
2978
2979 $attach_id = wp_insert_attachment( $post_info, $file_path, $parent_post_id );
2980 update_post_meta($attach_id, 'pagelayer_image_md5', $md5);
2981
2982 $lib = ABSPATH . 'site-admin/includes/image.php';
2983 $media = ABSPATH . 'site-admin/includes/media.php';
2984 $media = file_exists($media) ? $media : ABSPATH . 'wp-admin/includes/media.php';
2985 $lib = file_exists($lib) ? $lib : ABSPATH . 'wp-admin/includes/image.php';
2986
2987 require_once($media);
2988 require_once($lib);
2989
2990 $attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
2991 wp_update_attachment_metadata( $attach_id, $attach_data );
2992
2993 return $attach_id;
2994
2995 }
2996
2997 // Show the notice of importing the active themes content
2998 function pagelayer_theme_import_notices($return = false){
2999
3000 $theme = wp_get_theme();
3001
3002 $imported = get_option('pagelayer_theme_'.get_template().'_imported');
3003 $show = 0;
3004
3005 // We need to import the content
3006 if(empty($imported) && is_admin() && current_user_can('switch_themes')){
3007 $show = 1;
3008 }
3009
3010 $dismissed = get_option('pagelayer_theme_'.get_template().'_dismissed');
3011
3012 // Is this dismissed
3013 if($dismissed){
3014 $show = 0;
3015 }
3016
3017 //$show = 1;
3018
3019 // Is it the importer page ?
3020 if(!empty($_REQUEST['page']) && $_REQUEST['page'] == 'pagelayer_import'){
3021 $show = 0;
3022 }
3023
3024 // Show the message
3025 if(!empty($show)){
3026 $str = '
3027
3028 <style>
3029 .pagelayer_promo_button {
3030 background-color: #4CAF50; /* Green */
3031 border: none;
3032 color: white;
3033 padding: 6px 10px;
3034 text-align: center;
3035 text-decoration: none;
3036 display: inline-block;
3037 font-size: 13px;
3038 margin: 4px 2px;
3039 -webkit-transition-duration: 0.4s; /* Safari */
3040 transition-duration: 0.4s;
3041 cursor: pointer;
3042 }
3043 .pagelayer_promo_button:focus,
3044 .pagelayer_promo_button:hover{
3045 border: none;
3046 color: white;
3047 box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
3048 color: white;
3049 }
3050 .pagelayer_promo_buy {
3051 color: white;
3052 padding: 8px 12px;
3053 font-size: 14px;
3054 }
3055 .pagelayer_promo_button1 {
3056 color: white;
3057 background-color: #4CAF50;
3058 border:3px solid #4CAF50;
3059 }
3060 .pagelayer_promo_button1:hover {
3061 border:3px solid #4CAF50;
3062 }
3063 .pagelayer_promo_button2 {
3064 color: white;
3065 background-color: #0085ba;
3066 }
3067 .pagelayer_promo_button3 {
3068 color: white;
3069 background-color: #365899;
3070 }
3071 .pagelayer_promo_button4 {
3072 color: white;
3073 background-color: rgb(66, 184, 221);
3074 }
3075 .pagelayer_promo-close{
3076 float:right;
3077 text-decoration:none;
3078 margin: 5px 10px 0px 0px;
3079 }
3080 .pagelayer_promo-close:hover{
3081 color: red;
3082 }
3083 </style>
3084
3085 <script type="application/javascript">
3086 jQuery(document).ready(function(){
3087 jQuery("#pagelayer_promo .pagelayer_promo-close").click(function(){
3088 var data;
3089 jQuery("#pagelayer_promo").hide();
3090 // Save this preference
3091 jQuery.post("'.admin_url('?pagelayer_promo=0').'", data, function(response) {
3092 //alert(response);
3093 });
3094 });
3095 });
3096 </script>
3097
3098 <div class="notice notice-success" id="pagelayer_promo" style="min-height:30px">
3099 <a class="pagelayer_promo-close" href="javascript:" aria-label="Dismiss this Notice">
3100 <span class="dashicons dashicons-dismiss"></span> Dismiss
3101 </a>';
3102
3103 $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>').'
3104
3105 </div>';
3106
3107 // Print it
3108 if(empty($return)){
3109 echo $str;
3110 }else{
3111 return $str;
3112 }
3113 }
3114
3115 }
3116
3117 // Parse the array variables
3118 function pagelayer_replace_vars( $string, $array, $pre = '', $suf = ''){
3119
3120 $array = (array) $array;
3121
3122 foreach($array as $kk => $vv){
3123
3124 if(is_array($vv)){
3125 $vv = pagelayer_flat_join($vv);
3126 }
3127
3128 $string = str_replace($pre.$kk.$suf, $vv, $string);
3129 }
3130 return $string;
3131 }
3132
3133 // Add Attachment to the contact the email
3134 function pagelayer_cf_email_attachment( &$phpmailer) {
3135
3136 if ( ! empty( $_FILES ) ) {
3137 foreach ( $_FILES as $attachment ) {
3138
3139 if(empty($attachment['name'])){
3140 continue;
3141 }
3142
3143 try {
3144 $phpmailer->addAttachment($attachment['tmp_name'], $attachment['name'], $encoding = 'base64', $attachment['type'], $disposition = 'attachment');
3145 } catch ( \Exception $e ) {
3146 continue;
3147 }
3148 }
3149 }
3150
3151 }
3152
3153 function pagelayer_array_flatten( $input ) {
3154 if ( ! is_array( $input ) ) {
3155 return array( $input );
3156 }
3157
3158 $output = array();
3159
3160 foreach ( $input as $value ) {
3161 $output = array_merge( $output, pagelayer_array_flatten( $value ) );
3162 }
3163
3164 return $output;
3165 }
3166
3167 function pagelayer_flat_join( $array ) {
3168 $array = pagelayer_array_flatten( $array );
3169 $output = array();
3170
3171 foreach ( (array) $array as $value ) {
3172 $output[] = trim( (string) $value );
3173 }
3174
3175 return implode( ', ', $output );
3176 }
3177
3178 // Verifies the Google Captcha
3179 function pagelayer_captcha_verify(){
3180
3181 // If secret key is not there, return
3182 $captcha_secret = get_option('pagelayer_google_captcha_secret');
3183
3184 if(empty($captcha_secret)){
3185 return true;
3186 }
3187
3188 $response = !empty($_POST['g-recaptcha-response']) ? sanitize_text_field($_POST['g-recaptcha-response']) : '';
3189
3190 $ip = pagelayer_getip();
3191
3192 // Is the IP or response not there ?
3193 if(empty($response) || empty($ip)){
3194 return false;
3195 }
3196
3197 $url = 'https://www.google.com/recaptcha/api/siteverify';
3198
3199 // Verify the post
3200 $req = wp_remote_post($url, array(
3201 'timeout' => 20,
3202 'body' => array(
3203 'secret' => $captcha_secret,
3204 'response' => $response,
3205 'remoteip' => $ip
3206 )
3207 )
3208 );
3209
3210 // Was there an error posting ?
3211 if(is_wp_error($req)){
3212 return false;
3213 }
3214
3215 // Process the post response
3216 $resp = wp_remote_retrieve_body($req);
3217
3218 // Is the body valid
3219 if(empty($resp)){
3220 return false;
3221 }
3222
3223 $json = json_decode($resp, true);
3224
3225 if(!empty($json['success']) && // for v2 and v3
3226 (!isset($json['score']) || $json['score'] >= 0.5 && $json['action'] === 'submit') // For v3
3227 ){
3228 return true;
3229 }
3230
3231 return false;
3232 }
3233
3234 // Pagelayer serialize attributes
3235 function pagelayer_serialize_attributes( $block_attributes ) {
3236 $encoded_attributes = json_encode( $block_attributes, JSON_FORCE_OBJECT);
3237 $encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes );
3238 $encoded_attributes = preg_replace( '/</', '\\u003c', $encoded_attributes );
3239 $encoded_attributes = preg_replace( '/>/', '\\u003e', $encoded_attributes );
3240 // Regex: /\\"/
3241 $encoded_attributes = preg_replace( '/\\\\"/', '\\u0022', $encoded_attributes );
3242
3243 return $encoded_attributes;
3244 }
3245
3246 function pagelayer_enable_giver(){
3247 global $pagelayer;
3248 return !empty($pagelayer->settings['enable_giver']) && $pagelayer->settings['enable_giver'] == 1;
3249 }
3250
3251 function pagelayer_load_font_options(){
3252 include_once(PAGELAYER_DIR.'/main/font-options.php');
3253 }
3254
3255 function pagelayer_is_utf8($str) {
3256 return (bool) preg_match('//u', $str);
3257 }
3258
3259 // Create blank images
3260 function pagelayer_create_blank_image($width, $height){
3261
3262 $im = @imagecreate($width, $height);
3263
3264 if(empty($im)){
3265 return false;
3266 }
3267
3268 $background_color = imagecolorallocate($im, 220, 220, 220);
3269 $text_color = imagecolorallocate($im, 110, 110, 110);
3270 $string = $width.' x '.$height;
3271 $font_size = 30;
3272 $sx = ($width / 2) - (strlen($string) * $font_size / 2);
3273 $sy = ($height / 2) - ($font_size / 2);
3274 $font = realpath(PAGELAYER_DIR.'/fonts/OpenSans-BoldItalic.ttf');
3275 imagettftext($im, $font_size, 0, $sx, $sy, $text_color, $font, $string);
3276 ob_start();
3277 imagepng($im);
3278 imagedestroy($im);
3279
3280 return ob_get_clean();
3281
3282 }
3283
3284 // Get category name by post type
3285 function pagelayer_post_type_category($post_type){
3286
3287 $taxonomies = get_object_taxonomies( $post_type, 'objects');
3288
3289 foreach( $taxonomies as $key => $tax){
3290 if(!empty($tax->hierarchical)){
3291 return $key;
3292 }
3293 }
3294
3295 return false;
3296
3297 }
3298
3299 // Get tag name by post type
3300 function pagelayer_post_type_tag($post_type){
3301
3302 $taxonomies = get_object_taxonomies( $post_type, 'objects');
3303
3304 foreach( $taxonomies as $key => $tax){
3305 if(!empty($tax->show_tagcloud) && empty($tax->hierarchical)){
3306 return $key;
3307 }
3308 }
3309 return false;
3310
3311 }
3312
3313 // Get checkboxes of post categories.
3314 function pagelayer_post_cats($post, &$cat_name = ''){
3315
3316 $ret = [];
3317
3318 $cat_name = pagelayer_post_type_category($post->post_type);
3319
3320 if(empty($cat_name)){
3321 return $ret;
3322 }
3323
3324 include_once(ABSPATH.PAGELAYER_CMS_DIR_PREFIX.'-admin/includes/template.php');
3325
3326 $args1 = array(
3327 'taxonomy' => $cat_name,
3328 'checked_ontop' => false,
3329 'echo' => false,
3330 );
3331
3332 $ret['with_checkbox'] = '<ul class="pagelayer-post-category" >'.wp_terms_checklist($post->ID, $args1 ).'</ul>';
3333
3334 $args2 = array(
3335 'taxonomy' => $cat_name,
3336 'hierarchical' => true,
3337 'echo' => 0,
3338 'class' => 'pagelayer-add-cat',
3339 'name' => 'pagelayer_cat_parent',
3340 'style' => 'list',
3341 'hide_empty' => 0,
3342 );
3343
3344 $ret['without_checkbox'] = wp_dropdown_categories( $args2 );
3345
3346 return $ret;
3347
3348 }
3349
3350 // Get checkboxes of post tags.
3351 function pagelayer_post_tags($post, &$tag_name = ''){
3352
3353 $ret = [];
3354
3355 $tag_name = pagelayer_post_type_tag($post->post_type);
3356
3357 if(empty($tag_name)){
3358 return $ret;
3359 }
3360
3361 $ret['postTags'] = wp_get_post_terms( $post->ID, $tag_name );
3362
3363 $ret['allTags'] = get_tags(array( 'hide_empty' => false, 'taxonomy' => $tag_name ));
3364
3365 return $ret;
3366
3367 }
3368
3369 // Get users who can edit a particular post type
3370 function pagelayer_post_authors_by_type($post_type){
3371
3372 global $wp_post_types;
3373
3374 if(empty($wp_post_types[$post_type])){
3375 $users = get_users( array( 'role__in' => array( 'administrator' ) ) );
3376 }else{
3377 $req_role = $wp_post_types[$post_type]->cap->edit_posts;
3378 $roles__in = [];
3379 foreach( wp_roles()->roles as $role_slug => $role ){
3380 if( ! empty( $role['capabilities'][$req_role] ) )
3381 $roles__in[] = $role_slug;
3382 }
3383 $users = get_users( array( 'role__in' => $roles__in ) );
3384 }
3385
3386 $user_array = [];
3387
3388 foreach ( $users as $user ) {
3389 $user_array[$user->ID] = $user->display_name;
3390 }
3391
3392 return $user_array;
3393 }
3394
3395 function pagelayer_parent_post_prop($post){
3396 global $wp_post_types;
3397
3398 if(!empty($wp_post_types[$post->post_type]->hierarchical)){
3399 return pagelayer_list_parents(0, 0, $post, []);
3400 }else{
3401 return [];
3402 }
3403 }
3404
3405 function pagelayer_list_parents( $parent = 0, $level = 0, $post = null, $values=array('')){
3406
3407 global $wpdb;
3408
3409 $post = get_post( $post );
3410
3411 $items = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_parent, post_title FROM $wpdb->posts
3412 WHERE post_parent = %d
3413 AND post_type = '".$post->post_type."'
3414 AND post_status = 'publish'
3415 ORDER BY menu_order", $parent ) );
3416
3417 if ( !empty($items) ) {
3418 foreach ( $items as $item ) {
3419
3420 // A page cannot be its own parent.
3421 if ( $post && $post->ID && (int) $item->ID === $post->ID ) {
3422 continue;
3423 }
3424
3425 $pad = str_repeat( '-', $level );
3426
3427 if(count($values)==0){
3428 $values[] = '';
3429 }
3430
3431 $values[' '.$item->ID] = $pad.esc_html( $item->post_title );
3432
3433 $values = pagelayer_list_parents($item->ID, $level + 1, $post, $values );
3434 }
3435 }
3436
3437 return $values;
3438 }
3439
3440 // Maybe explode
3441 function pagelayer_maybe_explode( $separator = ',', $string = '', $limit = PHP_INT_MAX ){
3442
3443 if(is_array($string)){
3444 return $string;
3445 }
3446
3447 return explode($separator, $string, $limit);
3448 }
3449
3450 // Maybe implode
3451 function pagelayer_maybe_implode($array, $separator = ','){
3452
3453 if(is_array($array)){
3454 return @implode($separator, $array);
3455 }
3456
3457 if(is_null($array)){
3458 return '';
3459 }
3460
3461 return $array;
3462
3463 }
3464
3465 // Sanitize text field or array
3466 function pagelayer_sanitize_text_field($str) {
3467
3468 if ( !is_object( $str ) && !is_array( $str ) ) {
3469 return sanitize_text_field($str);
3470 }
3471
3472 if( is_array($str) ){
3473 return array_map( 'pagelayer_sanitize_text_field', $str);
3474 }
3475
3476 return $str;
3477 }
3478
3479 // Sanitize posts data for WP_Query
3480 function pagelayer_sanitize_posts_data($data, $only_allowed = true) {
3481
3482 $allowed_keys = [
3483 'post_type', 'posts_per_page', 'order', 'orderby', 'paged',
3484 'filter_by', 'term', 'exc_term', 'cat', 'category_name',
3485 'tag', 'author', 'author_name', 'post__in', 'post__not_in',
3486 'include', 'exclude', 'search', 's', 'exact', 'sentence',
3487 'post_status', 'post_parent', 'offset',
3488 'posts_per_archive_page', 'page', 'ignore_sticky_posts'
3489 ];
3490
3491 $sanitized = [];
3492
3493 foreach($data as $key => $value){
3494 if($only_allowed && !in_array($key, $allowed_keys)) {
3495 continue;
3496 }
3497
3498 $sanitized[$key] = pagelayer_sanitize_text_field($value);
3499 }
3500
3501 // Security: Restrict post_status to prevent information disclosure
3502 // Only users who can read private posts or edit others' posts should be able to query non-public statuses
3503 if(isset($sanitized['post_status'])){
3504 $requested_status = $sanitized['post_status'];
3505
3506 // If requesting something other than publish, verify permissions
3507 if ($requested_status !== 'publish') {
3508 // Check if the user has permission to read private posts or edit others' posts
3509 // This prevents contributors from seeing titles of private posts they don't own.
3510 if (!current_user_can('read_private_posts') && !current_user_can('edit_others_posts')) {
3511 $sanitized['post_status'] = 'publish';
3512 }
3513 }
3514 }else{
3515 // Default to publish for safety if not specified
3516 $sanitized['post_status'] = 'publish';
3517 }
3518
3519 if(isset($sanitized['posts_per_page'])){
3520 $sanitized['posts_per_page'] = (int) $sanitized['posts_per_page'];
3521 if ($sanitized['posts_per_page'] > 100) {
3522 $sanitized['posts_per_page'] = 100;
3523 }
3524 }
3525
3526 if(isset($sanitized['paged'])){
3527 $sanitized['paged'] = (int) $sanitized['paged'];
3528 }
3529
3530 if(isset($sanitized['offset'])){
3531 $sanitized['offset'] = (int) $sanitized['offset'];
3532 }
3533
3534 if(isset($sanitized['post__in']) && is_string($sanitized['post__in'])){
3535 $sanitized['post__in'] = array_map('intval', explode(',', $sanitized['post__in']));
3536 }
3537
3538 if(isset($sanitized['post__not_in']) && is_string($sanitized['post__not_in'])){
3539 $sanitized['post__not_in'] = array_map('intval', explode(',', $sanitized['post__not_in']));
3540 }
3541
3542 if(isset($sanitized['post_parent'])){
3543 $sanitized['post_parent'] = (int) $sanitized['post_parent'];
3544 }
3545
3546 if(isset($sanitized['cat'])){
3547 $sanitized['cat'] = (int) $sanitized['cat'];
3548 }
3549
3550 if(isset($sanitized['author'])){
3551 $sanitized['author'] = (int) $sanitized['author'];
3552 }
3553
3554 return $sanitized;
3555 }
3556
3557 // Update nav menu item
3558 function pagelayer_save_nav_menu_items($items){
3559
3560 // Menu setting keys
3561 $allowed_post = array('title' => 'post_title');
3562 $allowed_meta = array('_pagelayer_content');
3563
3564 foreach($items as $id => $values){
3565
3566 $meta_input = array();
3567 $id = (int) $id;
3568 $post = get_post($id);
3569
3570 // Post found ?
3571 if(empty($post)){
3572 continue;
3573 }
3574
3575 foreach($values as $kk => $vv){
3576
3577 if(array_key_exists($kk, $allowed_post)){
3578 $name = $allowed_post[$kk];
3579 $post->$name = $vv;
3580 }
3581
3582 if(!in_array($kk, $allowed_meta)){
3583 continue;
3584 }
3585
3586 $meta_input[$kk] = stripslashes_deep($vv);
3587 }
3588
3589 if(isset($meta_input['_pagelayer_content'])){
3590 $meta_input['_pagelayer_content'] = base64_decode($meta_input['_pagelayer_content']);
3591 }
3592
3593 $post->meta_input = $meta_input;
3594 wp_update_post($post);
3595 }
3596 }
3597
3598 // Update customizer options
3599 function pagelayer_save_customizer_options($customizer_options){
3600 global $pagelayer;
3601
3602 // To load customizer params array
3603 if(empty($pagelayer->customizer_params)){
3604 pagelayer_load_shortcodes();
3605 }
3606
3607 $customizer_options = apply_filters( 'pagelayer_save_customizer_options', $customizer_options );
3608 $customizer_data = array();
3609 $customizer_option_data = array();
3610
3611 foreach($pagelayer->customizer_params as $ck => $cv){
3612 foreach($pagelayer->screens as $sk => $sv){
3613
3614 $screen = (!empty($sv) ? '_'.$sv : '');
3615 $screen_key = $ck.$screen;
3616
3617 // Save to pagelayer customizer mods
3618 if( empty($cv['option']) ){
3619 if( isset($customizer_options[$screen_key])){
3620 $customizer_data[$screen_key] = $customizer_options[$screen_key];
3621 }
3622 continue;
3623 }
3624
3625 $option_key = $cv['option'].$screen;
3626
3627 // Update option
3628 if( isset($customizer_options[$screen_key] ) ) {
3629 update_option( $option_key, $customizer_options[$screen_key]);
3630 continue;
3631 }
3632
3633 delete_option($option_key);
3634 }
3635 }
3636
3637 // Set Typography settings for global and current post type
3638 $posttype=array(
3639 '' => '', // Make this empty for global values
3640 'current' => $customizer_options['pagelayer_current_post_type']
3641 );
3642
3643 $typo = ['font-family', 'font-size', 'font-style', 'font-weight', 'font-variant', 'decoration-line', 'line-height', 'text-transform', 'text-spacing', 'word-spacing'];
3644
3645 foreach($posttype as $type => $tv){
3646
3647 foreach($pagelayer->css_settings as $set => $params){
3648
3649 foreach($pagelayer->screens as $sk => $sv){
3650
3651 $screen = (!empty($sv) ? '_'.$sv : '');
3652 $post_type = (!empty($tv) ? '_'.$tv : '');
3653 $post_key = (!empty($type) ? $type.'_' : '');
3654 $post_key_set = $post_key.$set;
3655
3656 // Create key as per customizer shortcode
3657 $key = $post_key_set.$screen;
3658
3659 // Create option keys for the global and current post type
3660 $option_setting = empty($params['key']) ? 'pagelayer_'.$set.'_css'.$post_type : $params['key'].$post_type;
3661
3662 $props = array(
3663 'color' => $post_key_set.'_color'.$screen,
3664 'padding' => $post_key_set.'_padding'.$screen,
3665 'margin' => $post_key_set.'_margin'.$screen,
3666 'background-color' => $post_key_set.'_background_color'.$screen,
3667 );
3668
3669 $globalsetting = array();
3670
3671 // Set Typography
3672 if(isset($customizer_options[$key])){
3673 foreach($customizer_options[$key] as $k => $v){
3674 if($v == 'Default' || empty($v)){
3675 unset($customizer_options[$key][$k]);
3676 }
3677
3678 // For sidebar, width default should not be saved
3679 if($set == 'sidebar' && $k == 'width' && $v == 20){
3680 unset($customizer_options[$key][$k]);
3681 }
3682
3683 $globalsetting[$key][$typo[$k]] = $customizer_options[$key][$k];
3684 unset($customizer_options[$key][$k]);
3685 }
3686 }
3687
3688 // Set other props with typography
3689 foreach($props as $pk => $pv){
3690
3691 if(!isset($customizer_options[$pv])){
3692 continue;
3693 }
3694
3695 $globalsetting[$key][$pk] = $customizer_options[$pv];
3696 unset($customizer_options[$pv]);
3697
3698 }
3699
3700 // Are we to save ?
3701 if(!empty($globalsetting[$key])){
3702 update_option($option_setting.$screen, $globalsetting[$key]);
3703 }else{
3704 delete_option($option_setting.$screen);
3705 }
3706
3707 }
3708
3709 }
3710 }
3711
3712 $customizer_data = apply_filters( 'pagelayer_customizer_options', $customizer_data, $customizer_options);
3713
3714 update_option('pagelayer_customizer_mods', $customizer_data);
3715 }
3716
3717 // Get customizer options values
3718 // return array to set customizer block attributes
3719 function pagelayer_get_customizer_options(){
3720 global $pagelayer, $post;
3721
3722 $options = array();
3723
3724 // To load customizer params array
3725 if(empty($pagelayer->customizer_params)){
3726 pagelayer_load_shortcodes();
3727 }
3728
3729 // Get values form options
3730 foreach($pagelayer->customizer_params as $ck => $cv){
3731
3732 if( empty($cv['option']) ){
3733 continue;
3734 }
3735
3736 $screens = array('desktop' => '');
3737
3738 if( !empty($cv['screen']) ){
3739 $screens = $pagelayer->screens;
3740 }
3741
3742 foreach($screens as $sk => $sv){
3743
3744 $screen = (!empty($sv) ? '_'.$sv : '');
3745 $screen_key = $cv['option'].$screen;
3746 $screen_ck = $ck.$screen;
3747
3748 // Get option value
3749 $c_option = get_option($screen_key);
3750
3751 if(empty($c_option)){
3752 continue;
3753 }
3754
3755 $options[$screen_ck] = $c_option;
3756 }
3757 }
3758
3759
3760 // Get values from pagelayer mods
3761 $mods = get_option('pagelayer_customizer_mods');
3762
3763 if(!empty($mods)){
3764 $options = array_merge($options, $mods);
3765 }
3766
3767 $posttype=array(
3768 '' => '',
3769 'current' => $post->post_type
3770 );
3771
3772 $typo = ['font-family', 'font-size', 'font-style', 'font-weight', 'font-variant', 'decoration-line', 'line-height', 'text-transform', 'text-spacing', 'word-spacing'];
3773
3774 foreach($posttype as $type => $tv){
3775
3776 foreach($pagelayer->css_settings as $set => $params){
3777
3778 foreach($pagelayer->screens as $sk => $sv){
3779
3780 $screen = (!empty($sv) ? '_'.$sv : '');
3781 $postprefix = (!empty($tv) ? '_'.$tv : '');
3782 $postk = (!empty($type) ? $type.'_' : '');
3783 $post_key_set = $postk.$set;
3784
3785 // Create key as per customizer shortcode
3786 $key = $post_key_set.$screen;
3787
3788 // Create option keys for the global and current post type
3789 $setting = empty($params['key']) ? 'pagelayer_'.$set.'_css'.$postprefix : $params['key'].$postprefix;
3790
3791 $props = array(
3792 'color' => $post_key_set.'_color'.$screen,
3793 'padding' => $post_key_set.'_padding'.$screen,
3794 'margin' => $post_key_set.'_margin'.$screen,
3795 'background-color' => $post_key_set.'_background_color'.$screen,
3796 );
3797
3798 $optarray = get_option($setting.$screen);
3799
3800 if(!empty($optarray)){
3801
3802 // Get Typography
3803 foreach($typo as $tk => $tv){
3804
3805 $tval = '';
3806
3807 if(isset($optarray[$tv])){
3808 $tval = $optarray[$tv];
3809 }
3810
3811 $options[$key][$tk] = $tval;
3812 }
3813
3814 foreach($props as $pk => $pv){
3815 if(empty( $optarray[$pk])){
3816 continue;
3817 }
3818
3819 $options[$pv] = $optarray[$pk];
3820 }
3821 }
3822 }
3823 }
3824 }
3825
3826 $options = apply_filters( 'pagelayer_get_customizer_options', $options);
3827
3828 return $options;
3829 }
3830
3831 // Sanitize style props for colors and fons
3832 function pagelayer_load_global_palette(){
3833 global $pagelayer;
3834
3835 // Default global colors
3836 $pagelayer->global_colors = array(
3837 'primary' => array(
3838 'title' => 'Primary',
3839 'value' => '#007bff',
3840 ),
3841 'secondary' => array(
3842 'title' => 'Secondary',
3843 'value' => '#6c757d',
3844 ),
3845 'text' => array(
3846 'title' => 'Text',
3847 'value' => '#1d1d1d',
3848 ),
3849 'accent' => array(
3850 'title' => 'Accent',
3851 'value' => '#61ce70',
3852 ),
3853 );
3854
3855 // Global color
3856 $global_color = get_option('pagelayer_global_colors');
3857
3858 if(!empty($global_color)){
3859 $pagelayer->global_colors = json_decode($global_color, true);
3860 }
3861
3862 // Default global fonts
3863 $pagelayer->global_fonts = array(
3864 'primary' => array(
3865 'title' => 'Primary',
3866 'value' => $pagelayer->default_font_styles(),
3867 ),
3868 'secondary' => array(
3869 'title' => 'Secondary',
3870 'value' => $pagelayer->default_font_styles(array('font-family' => 'Roboto')),
3871 ),
3872 'text' => array(
3873 'title' => 'Text',
3874 'value' => $pagelayer->default_font_styles(array('font-family' => 'Montserrat')),
3875 ),
3876 'accent' => array(
3877 'title' => 'Accent',
3878 'value' => $pagelayer->default_font_styles(array('font-family' => 'Poppins')),
3879 ),
3880 );
3881
3882 // Global font
3883 $global_font = get_option('pagelayer_global_fonts');
3884
3885 if(!empty($global_font)){
3886 $pagelayer->global_fonts = json_decode($global_font, true);
3887 }
3888 }
3889
3890 // Get global colors
3891 function pagelayer_sanitize_global_color($val){
3892 global $pagelayer;
3893
3894 if(!is_string($val) || $val[0] != '$'){
3895 return $val;
3896 }
3897
3898 $gkey = substr($val, 1);
3899 $gcolor = isset($pagelayer->global_colors[$gkey]) ? $gkey : 'primary';
3900 $val = 'var(--pagelayer-color-'.$gcolor.')';
3901
3902 return $val;
3903 }
3904
3905 // Sanitize style props for colors and fons
3906 function pagelayer_sanitize_global_style($val, $val_desk = '', $mode = 'desktop'){
3907 global $pagelayer;
3908
3909 // Sanitize Global background color
3910 if( !empty($val['background-color']) && $val['background-color'][0] == '$'){
3911 $val['background-color'] = pagelayer_sanitize_global_color($val['background-color']);
3912 }
3913
3914 // Sanitize Global color
3915 if( !empty($val['color']) && $val['color'][0] == '$'){
3916 $val['color'] = pagelayer_sanitize_global_color($val['color']);
3917 }
3918
3919 // Not set global for typo
3920 if(empty($val['global-font']) && empty($val_desk['global-font'])){
3921 return $val;
3922 }
3923
3924 $_desk_global = false;
3925
3926 if(empty($val['global-font'])){
3927 $font_key = @$val_desk['global-font'];
3928 $_desk_global = true;
3929 }else{
3930 $font_key = $val['global-font'];
3931 unset($val['global-font']);
3932 }
3933
3934 if(empty($font_key)){
3935 return $val;
3936 }
3937
3938 if(!isset($pagelayer->global_fonts[$font_key])){
3939 $font_key = 'primary';
3940 }
3941
3942 $_val = [];
3943
3944 // Apply global typo
3945 foreach($pagelayer->typo_props as $typo_key){
3946
3947 if(!empty($val[$typo_key])){
3948 continue;
3949 }
3950
3951 $global_val = $pagelayer->global_fonts[$font_key]['value'];
3952
3953 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') ){
3954 continue;
3955 }
3956
3957 $_val[$typo_key] = 'var(--pagelayer-font-'.$font_key.'-'.$typo_key.')';
3958 }
3959
3960 // This array contains other values like margin padding so we merge the array
3961 $val = empty($val) ? array() : $val;
3962 $val = array_merge($val, $_val);
3963 return $val;
3964 }
3965
3966 //Check an empty array
3967 function pagelayer_is_empty_array($arr){
3968
3969 foreach ($arr as $key => $value) {
3970 if (trim($value) !== '') return false;
3971 }
3972
3973 return true;
3974 }
3975
3976 // Pagelayer load font family
3977 function pagelayer_load_font_family($font, $font_weight='', $font_style=''){
3978 global $pagelayer;
3979
3980 // Load global fonts
3981 if(strripos($font, 'var(') !== false){
3982 $matches = [];
3983 preg_match('/(var\(--pagelayer-font-)(\w+)(-font-family\))/i', $font, $matches);
3984 $font_key = @$matches[2];
3985 $font = @$pagelayer->global_fonts[$font_key]['value']['font-family'];
3986 }
3987
3988 // Load global fonts weight
3989 if(!empty($font_weight) && strripos($font_weight, 'var(') !== false){
3990 $matches = [];
3991 preg_match('/(var\(--pagelayer-font-)(\w+)(-font-weight\))/i', $font_weight, $matches);
3992 $font_key = @$matches[2];
3993
3994 // Convert in string
3995 $font_weight = @$pagelayer->global_fonts[$font_key]['value']['font-weight'];
3996 }
3997
3998 // Load global fonts style
3999 if(!empty($font_style) && strripos($font_style, 'var(') !== false){
4000 $matches = [];
4001 preg_match('/(var\(--pagelayer-font-)(\w+)(-font-style\))/i', $font_style, $matches);
4002 $font_key = @$matches[2];
4003
4004 // Convert in string
4005 $font_style = @$pagelayer->global_fonts[$font_key]['value']['font-style'];
4006 }
4007
4008 if(empty($font)){
4009 return;
4010 }
4011
4012 $font_weights = array('400' =>'400');
4013 $font_style = empty($font_style) ? 'normal' : $font_style;
4014 $font_style = in_array($font_style, ['italic', 'oblique']) ? 'i' : '';
4015
4016 if(!empty($font_weight)){
4017
4018 if(!is_array($font_weight)){
4019 $font_weight = array($font_weight);
4020 }
4021
4022 foreach($font_weight as $weight){
4023 $font_weights[$weight.$font_style] = $weight.$font_style;
4024 }
4025 }
4026
4027 foreach($font_weights as $fkey => $fvalue){
4028 $pagelayer->runtime_fonts[$font][$fkey] = $fvalue;
4029 }
4030
4031 }
4032
4033 function pagelayer_update_plugin_notice(){
4034 if(defined('SOFTACULOUS_PLUGIN_UPDATE_NOTICE')){
4035 return;
4036 }
4037
4038 $to_update_plugins = apply_filters('softaculous_plugin_update_notice', []);
4039
4040 if(empty($to_update_plugins)){
4041 return;
4042 }
4043
4044 /* 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 */
4045 $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>';
4046
4047 define('SOFTACULOUS_PLUGIN_UPDATE_NOTICE', true); // To make sure other plugins don't return a Notice
4048 echo '<div class="notice notice-info is-dismissible" id="pagelayer-plugin-update-notice">
4049 <p>'.$msg. '</p>
4050 </div>';
4051
4052 wp_register_script('pagelayer-update-notice', '', ['jquery'], '', true);
4053 wp_enqueue_script('pagelayer-update-notice');
4054 wp_add_inline_script('pagelayer-update-notice', 'jQuery("#pagelayer-plugin-update-notice").on("click", function(e){
4055 let target = jQuery(e.target);
4056
4057 if(!target.hasClass("notice-dismiss")){
4058 return;
4059 }
4060
4061 var data;
4062
4063 // Hide it
4064 jQuery("#pagelayer-plugin-update-notice").hide();
4065
4066 // Save this preference
4067 jQuery.post("'.admin_url('admin-ajax.php?action=pagelayer_close_update_notice').'&pagelayer_nonce='.wp_create_nonce('pagelayer_promo_nonce').'", data, function(response) {
4068 //alert(response);
4069 });
4070 });');
4071 }
4072
4073 function pagelayer_update_plugin_notice_filter($plugins = []){
4074 $plugins['pagelayer/pagelayer.php'] = 'Pagelayer';
4075 return $plugins;
4076 }
4077
4078 function pagelayer_is_comment_mode(){
4079
4080 if(file_exists(PAGELAYER_DIR.'/comment_mode.php') && !empty($_REQUEST['cmode'])){
4081 include_once(PAGELAYER_DIR.'/comment_mode.php');
4082 return true;
4083 }
4084
4085 return false;
4086 }
4087
4088 function pagelayer_esc_crlf($value){
4089
4090 // Remove CRLF to prevent header injection
4091 $value = str_replace(array("\r", "\n", "%0a", "%0d"), '', $value);
4092
4093 // Trim spaces
4094 $value = trim($value);
4095
4096 return $value;
4097 }