PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.2.1
Page Builder: Pagelayer – Drag and Drop website builder v2.2.1
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
← All changes | main/functions.php +3656 -133 0.9.52.2.1 View file →
@@ -41,20 +41,21 @@
41 41 global $pagelayer;
42 42
43 43 // Just so that we have something
44 44 $ip = _pagelayer_getip();
45 + $method = @$pagelayer->ip_method;
46 +
47 + $pagelayer->ip_method = (int) $method;
45 48
46 - $pagelayer['ip_method'] = (int) @$pagelayer['ip_method'];
47 -
48 49 if(isset($_SERVER["REMOTE_ADDR"])){
49 50 $ip = $_SERVER["REMOTE_ADDR"];
50 51 }
51 52
52 - if(isset($_SERVER["HTTP_X_FORWARDED_FOR"]) && @$pagelayer['ip_method'] == 1){
53 + if(isset($_SERVER["HTTP_X_FORWARDED_FOR"]) && $method == 1){
53 54 $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
54 55 }
55 56
56 - if(isset($_SERVER["HTTP_CLIENT_IP"]) && @$pagelayer['ip_method'] == 2){
57 + if(isset($_SERVER["HTTP_CLIENT_IP"]) && $method == 2){
57 58 $ip = $_SERVER["HTTP_CLIENT_IP"];
58 59 }
59 60
60 61 // Hacking fix for X-Forwarded-For
@@ -139,9 +140,9 @@
139 140
140 141 // For filling in posted values
141 142 function pagelayer_POSTval($name, $default = ''){
142 143
143 - return (!empty($_POST) ? (!isset($_POST[$name]) ? '' : $_POST[$name]) : $default);
144 + return (!empty($_POST) ? (!isset($_POST[$name]) ? '' : esc_html($_POST[$name])) : $default);
144 145
145 146 }
146 147
147 148 function pagelayer_POSTchecked($name, $default = false){
@@ -149,8 +150,15 @@
149 150 return (!empty($_POST) ? (isset($_POST[$name]) ? 'checked="checked"' : '') : (!empty($default) ? 'checked="checked"' : ''));
150 151
151 152 }
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 +
153 161 function pagelayer_POSTselect($name, $value, $default = false){
154 162
155 163 if(empty($_POST)){
156 164 if(!empty($default)){
@@ -167,19 +175,10 @@
167 175 }
168 176
169 177 function pagelayer_inputsec($string){
170 178
171 - if(!get_magic_quotes_gpc()){
179 + $string = addslashes($string);
172 180
173 - $string = addslashes($string);
174 -
175 - }else{
176 -
177 - $string = stripslashes($string);
178 - $string = addslashes($string);
179 -
180 - }
181 -
182 181 // This is to replace ` which can cause the command to be executed in exec()
183 182 $string = str_replace('`', '\`', $string);
184 183
185 184 return $string;
@@ -221,9 +220,9 @@
221 220 }
222 221 return false;
223 222 }
224 223
225 -// Reoort an error
224 +// Report an error
226 225 function pagelayer_report_error($error = array()){
227 226
228 227 if(empty($error)){
229 228 return true;
@@ -387,8 +386,12 @@
387 386
388 387 if(in_array($type, $pagelayer->settings['post_types'])){
389 388 return true;
390 389 }
390 +
391 + if($type == $pagelayer->builder['name']){
392 + return true;
393 + }
391 394
392 395 return false;
393 396
394 397 }
@@ -393,25 +396,62 @@
393 396
394 397 }
395 398
396 399 function pagelayer_shortlink($id){
397 - $link = wp_get_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 +
398 418 $link .= substr_count($link, '?') > 0 ? '' : '?';
399 419 return $link;
400 420 }
401 421
422 +// Pagelayer live link
423 +function pagelayer_livelink($id){
424 + return pagelayer_shortlink($id).'&pagelayer-live=1';
425 +}
426 +
402 427 // Are we in live mode ?
403 -function pagelayer_is_live(){
428 +function pagelayer_is_live(&$error = array()){
404 429
405 430 global $post;
406 431
407 432 // Are we seeing the post ?
408 433 if(!isset($post) || !isset($post->ID) || empty($post->ID)){
434 + $error[] = 'Post ID is missing or blank - '.@$post->ID;
409 435 return false;
410 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 + }
411 450
412 451 // Is it the live mode ?
413 452 if(pagelayer_optreq('pagelayer-live')){
453 + $error[] = 'pagelayer-live is missing';
414 454 return true;
415 455 }
416 456
417 457 return false;
@@ -418,12 +458,12 @@
418 458
419 459 }
420 460
421 461 // Are we in live IFRAME mode ?
422 -function pagelayer_is_live_iframe(){
462 +function pagelayer_is_live_iframe(&$error = array()){
423 463
424 464 // Are we seeing the post ?
425 - if(!pagelayer_is_live()){
465 + if(!pagelayer_is_live($error)){
426 466 return false;
427 467 }
428 468
429 469 // Is it the live mode ?
@@ -429,29 +469,95 @@
429 469 // Is it the live mode ?
430 470 if(pagelayer_optreq('pagelayer-iframe')){
431 471 return true;
432 472 }
473 +
474 + $error[] = 'pagelayer-iframe missing in GET';
433 475
434 476 return false;
435 477
436 478 }
437 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 +
438 515 // Can the current user edit the post ?
439 516 function pagelayer_user_can_edit($post = NULL){
440 517
441 - global $wp_the_query, $current_user;
518 + global $wp_the_query, $current_user, $pagelayer;
519 +
520 + $post = get_post($post);
442 521
443 - if(!isset($post) || empty($post) || $post === NULL){
444 - global $post;
522 + if(empty($post)){
523 + return false;
445 524 }
446 525
447 - wp_get_current_user();
448 -
449 - if(isset($post) && is_object($post) && isset($post->ID) && isset($post->post_author) && isset($current_user) && is_object($current_user) && isset($current_user->ID) && (current_user_can('edit_others_posts', $post->ID) || ($post->post_author == $current_user->ID))){
450 - return true;
526 + // No trash editing
527 + if(get_post_status($post->ID) === 'trash'){
528 + return false;
451 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 + }
452 558
453 - return false;
559 + return true;
454 560
455 561 }
456 562
457 563 // Language sting function
@@ -471,14 +577,81 @@
471 577 function pagelayer_icon_sources(){
472 578 return array();
473 579 }
474 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 +
475 639 // Loads the shortcodes
476 640 function pagelayer_load_shortcodes(){
477 -
478 - include_once(PAGELAYER_DIR.'/main/shortcode_functions.php');
479 - include_once(PAGELAYER_DIR.'/main/shortcodes.php');
480 -
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 +
481 654 // pQuery
482 655 include_once(PAGELAYER_DIR.'/lib/pquery/IQuery.php');
483 656 include_once(PAGELAYER_DIR.'/lib/pquery/gan_formatter.php');
484 657 include_once(PAGELAYER_DIR.'/lib/pquery/gan_node_html.php');
@@ -486,35 +659,80 @@
486 659 include_once(PAGELAYER_DIR.'/lib/pquery/gan_parser_html.php');
487 660 include_once(PAGELAYER_DIR.'/lib/pquery/gan_selector_html.php');
488 661 include_once(PAGELAYER_DIR.'/lib/pquery/gan_xml2array.php');
489 662 include_once(PAGELAYER_DIR.'/lib/pquery/pQuery.php');
663 +
664 + include_once(PAGELAYER_DIR.'/main/shortcode_functions.php');
490 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 +
491 671 // Apply filter to load custom widgets
492 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;
493 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');
494 716 }
495 717
496 718 // Add the shortcodes to the pagelayer list
497 719 function pagelayer_add_shortcode($tag, $params = array()){
498 720
499 - global $pagelayer;
500 -
501 - // Is there a handler function ?
502 - if(!empty($params['func'])){
721 + global $pagelayer, $post;
503 722
504 - if($tag == 'pl_row'){
505 - $inner_tag = 'pl_inner_row';
506 - add_shortcode($inner_tag, 'pagelayer_render_shortcode');
507 - }
508 -
509 - if($tag == 'pl_col'){
510 - $inner_tag = 'pl_inner_col';
511 - add_shortcode($inner_tag, 'pagelayer_render_shortcode');
512 - }
513 -
514 - add_shortcode($tag, 'pagelayer_render_shortcode');//$params['func']);
515 - //unset($params['func']);
723 + if($tag == 'pl_row'){
724 + $inner_tag = 'pl_inner_row';
725 + add_shortcode($inner_tag, 'pagelayer_render_shortcode');
516 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']);
517 735
518 736 // Is there a group ?
519 737 if(empty($params['group'])){
520 738 $params['group'] = 'misc';
@@ -524,12 +742,22 @@
524 742 $params['options'] = [
525 743 'ele_bg_styles' => __pl('ele_bg_styles'),
526 744 'ele_styles' => __pl('ele_styles'),
527 745 'border_styles' => __pl('border_styles'),
746 + 'font_style' => __pl('font_style'),
747 + 'position_styles' => __pl('position_styles'),
528 748 'animation_styles' => __pl('animation_styles'),
749 + 'motion_effects' => __pl('Motion Effects'),
529 750 'responsive_styles' => __pl('responsive_styles'),
751 + 'attributes' => __pl('attributes'),
530 752 'custom_styles' => __pl('custom_styles'),
531 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 + }
532 760
533 761 // Are the settings there which hold the params ?
534 762 if(empty($params['settings'])){
535 763 $params['settings'] = [
@@ -541,24 +769,152 @@
541 769 if(!empty($params['styles'])){
542 770 $params['settings'] = array_merge($params['settings'], $params['styles']);
543 771 unset($params['styles']);
544 772 }
545 -
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 +
546 795 // Insert the shortcode
547 796 $pagelayer->shortcodes[$tag] = $params;
548 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 +}
549 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);
550 867 }
551 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 +
552 886 // Returns the Image values
553 -function pagelayer_image($id){
554 -
887 +function pagelayer_image($id = 0){
888 +
889 + global $pagelayer;
890 +
555 891 $ret = [];
556 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 +
557 913 // External image ?
558 914 if(pagelayer_is_external_img($id)){
559 915
560 - $ret['full-url'] = $id;
916 + $ret['url'] = $id;
561 917
562 918 // Attachment
563 919 }elseif(!empty($id)){
564 920
@@ -567,8 +923,13 @@
567 923 $image = get_post($id);
568 924
569 925 // Is there an attachment which is an image ?
570 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 + }
571 932
572 933 $sizes = get_intermediate_image_sizes();
573 934 array_unshift($sizes, 'full');
574 935
@@ -581,28 +942,43 @@
581 942 $title = esc_attr($image->post_title);
582 943 $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
583 944 $alt = empty($alt) ? $image->post_excerpt : $alt;
584 945 $alt = empty($alt) ? $image->post_title : $alt;
585 - $alt = empty($alt) ? '' : trim(strip_tags($alt));
946 + $alt = empty($alt) ? '' : esc_attr(trim(strip_tags($alt)));
586 947 $link = get_attachment_link($id);
587 948 $caption = wp_get_attachment_caption($id);
588 - $caption = !empty($caption) ? $caption : '';
949 + $caption = !empty($caption) ? esc_attr($caption) : '';
589 950
590 - $ret['alt'] = $alt;
591 - $ret['title'] = $title;
592 - $ret['link'] = $link;
593 - $ret['caption'] = $caption;
951 + }
594 952
595 - }
953 + }
596 954
955 + // First preference to full url
956 + if(!empty($ret['full-url'])){
957 + $ret['url'] = $ret['full-url'];
597 958 }
598 959
599 960 // No image
600 - if(empty($ret['full-url'])){
601 - $ret['full-url'] = PAGELAYER_URL.'/images/default-image.png';
961 + if(empty($ret['url'])){
962 + $ret['url'] = PAGELAYER_URL.'/images/default-image.png';
602 963 }
603 964
604 - $ret['url'] = $ret['full-url'];
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 + }
605 981
606 982 return $ret;
607 983
608 984 }
@@ -621,8 +997,19 @@
621 997 return false;
622 998
623 999 }
624 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 +
625 1012 // Returns the attachment url
626 1013 function pagelayer_attachment($id){
627 1014
628 1015 $ret = [];
@@ -633,12 +1020,19 @@
633 1020 $ret['url'] = $id;
634 1021
635 1022 // Attachment
636 1023 }elseif(!empty($id)){
1024 +
1025 + // Need to export necessary media
1026 + if(!empty($pagelayer->export_mode)){
1027 + $pagelayer->media_to_export[] = $id;
1028 + }
637 1029
638 1030 $ret['url'] = wp_get_attachment_url($id);
639 1031
640 1032 }
1033 +
1034 + $ret = apply_filters('pagelayer_attachment', $ret);
641 1035
642 1036 return $ret;
643 1037
644 1038 }
@@ -644,14 +1038,20 @@
644 1038 }
645 1039
646 1040 // Convert the regular URL of a Video to a Embed URL
647 1041 // Todo : Check
648 -function pagelayer_video_url($source){
1042 +function pagelayer_video_url($source, $no_url = false){
649 1043
1044 + global $pagelayer;
1045 +
650 1046 if (!empty($source)) {
651 - $source = filter_var($source, FILTER_SANITIZE_URL);
1047 +
1048 + $source = esc_url( $source );
652 1049 $source = str_replace('&amp;', '&', $source);
653 1050 $url = parse_url($source);
1051 + $videoSite ='';
1052 + $videoId ='';
1053 + $vid_atts = [];
654 1054
655 1055 $youtubeRegExp = '/youtube\.com|youtu\.be/is';
656 1056 $vimeoRegExp = '/vimeo\.com/is';
657 1057
@@ -663,8 +1063,10 @@
663 1063
664 1064 switch ($videoSite) {
665 1065 case 'youtube':
666 1066
1067 + $pagelayer->append_yt_api = true;
1068 +
667 1069 if (preg_match('/youtube\.com/is', $source)) {
668 1070
669 1071 if (preg_match('/watch/is', $source)) {
670 1072 parse_str($url['query'], $parameters);
@@ -687,38 +1089,44 @@
687 1089 $videoId = $path[1];
688 1090 }
689 1091
690 1092 }
1093 +
1094 + $vid_atts['type'] = 'youtube';
1095 + $vid_atts['src'] = '//www.youtube.com/embed/'.$videoId;
1096 + $vid_atts['id'] = $videoId;
691 1097
692 - return '//youtube.com/embed/'.$videoId;
693 -
694 1098 break;
695 1099 case 'vimeo':
696 1100
697 1101 if (preg_match('/player\.vimeo\.com/is', $url['host']) && preg_match('/video/is', $url['path'])) {
698 - $path = explode('/', $url['path']);
699 -
700 - if (isset($path[2]) && !empty($path[2])) {
701 - $videoId = $path[2];
702 - }
703 -
1102 + $path = explode('video/', $source);
704 1103 } else if (preg_match('/vimeo\.com/is', $url['host'])) {
705 - $path = explode('/', $url['path']);
706 -
707 - if (isset($path[1]) && !empty($path[1])) {
708 - $videoId = $path[1];
709 - }
710 -
1104 + $path = explode('.com/', $source);
711 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;
712 1114
713 - return '//player.vimeo.com/video/'.$videoId;
714 -
715 1115 break;
716 1116 default:
1117 +
1118 + $vid_atts['type'] = 'local';
1119 + $vid_atts['src'] = $source;
1120 + $vid_atts['id'] = $videoId;
717 1121
718 - return $source;
719 -
720 1122 }
1123 +
1124 + if(!$no_url){
1125 + return $vid_atts['src'];
1126 + }
1127 +
1128 + return $vid_atts;
721 1129
722 1130 }
723 1131 }
724 1132
@@ -725,8 +1133,12 @@
725 1133
726 1134 // As per the JS specification
727 1135 function pagelayer_escapeHTML($str){
728 1136
1137 + if(is_null($str)){
1138 + return '';
1139 + }
1140 +
729 1141 $replace = [
730 1142 ']' => '&#93;',
731 1143 '[' => '&#91;',
732 1144 //'=' => '&#61;',
@@ -733,9 +1145,10 @@
733 1145 '<' => '&lt;',
734 1146 '>' => '&gt;',
735 1147 '"' => '&quot;',
736 1148 //'&' => '&amp;',
737 - '\'' => '&#39;'
1149 + '\'' => '&#39;',
1150 + '\\' => '&#92;'
738 1151 ];
739 1152
740 1153 $str = str_replace(array_keys($replace), array_values($replace), $str);
741 1154
@@ -743,8 +1156,13 @@
743 1156 }
744 1157
745 1158 // As per the JS specification
746 1159 function pagelayer_unescapeHTML($str){
1160 +
1161 + if(is_null($str)){
1162 + return '';
1163 + }
1164 +
747 1165 $replace = [
748 1166 '#93' => ']',
749 1167 '#91' => '[',
750 1168 //'#61' => '=',
@@ -751,9 +1169,10 @@
751 1169 'lt' => '<',
752 1170 'gt' => '>',
753 1171 'quot' => '"',
754 1172 //'amp' => '&',
755 - '#39' => '\''
1173 + '#39' => '\'',
1174 + '#92' => '\\'
756 1175 ];
757 1176
758 1177 foreach($replace as $k => $v){
759 1178 $str = str_replace('&'.$k.';', $v, $str);
@@ -760,8 +1179,693 @@
760 1179 }
761 1180 return $str;
762 1181 }
763 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 + // Keep a whitespace-preserved copy for the on* event-handler scan.
1276 + $orig = $data;
1277 +
1278 + $data = pagelayer_optimized_decode_entities($data);
1279 +
1280 + // Collapse all whitespace for pattern matching
1281 + $data = preg_split('/\s/', $data);
1282 + $data = implode('', $data);
1283 + //echo $data;
1284 +
1285 + if(preg_match('/["\']javascript\:/is', $data)){
1286 + return 'javascript';
1287 + }
1288 +
1289 + if(preg_match('/["\']vbscript\:/is', $data)){
1290 + return 'vbscript';
1291 + }
1292 +
1293 + if(preg_match('/\-moz\-binding\:/is', $data)){
1294 + return '-moz-binding';
1295 + }
1296 +
1297 + if(preg_match('/expression\(/is', $data)){
1298 + return 'expression';
1299 + }
1300 +
1301 + if(preg_match('/\<(iframe|frame|script|style|link|applet|embed|xml|svg|object|layer|ilayer|meta)/is', $data, $matches)){
1302 + return $matches[1];
1303 + }
1304 +
1305 + // Reject ANY on* event handler attribute. Per the HTML spec every attribute
1306 + // name beginning with "on" (optionally followed by a letter and word chars)
1307 + if(preg_match('/\bon(?:[a-z0-9-]*)?\s*=/i', $orig, $matches)){
1308 + return $matches[0];
1309 + }
1310 +
1311 + return;
1312 +
1313 +}
1314 +
1315 +// Check for XSS codes in our blocks array
1316 +function pagelayer_sanitize_blocks_save_pre($block){
1317 +
1318 + foreach($block as $k => $v){
1319 +
1320 + // Recurse on arrays
1321 + if(is_array($v)){
1322 + $block[$k] = pagelayer_sanitize_blocks_save_pre($v);
1323 +
1324 + // We dont support objects !
1325 + }elseif(is_object($v)){
1326 + $block[$k] = null;
1327 + // Strings
1328 + }else{
1329 +
1330 + if(is_string($v)){
1331 +
1332 + $v = wp_filter_post_kses($v);
1333 +
1334 + while(true){
1335 + $str = '"'.($v);
1336 + $found = pagelayer_xss_content($str);
1337 + //echo (string)$v.'--'.$found."\n";
1338 +
1339 + if(strlen($found) > 0){
1340 + // There is htmlentities?
1341 + if(strpos($v, $found) === false){
1342 + $v = '';
1343 + break;
1344 + }
1345 + $v = str_replace($found, '', $v);
1346 + }else{
1347 + break;
1348 + }
1349 +
1350 + }
1351 +
1352 + }
1353 +
1354 + $block[$k] = $v;
1355 + }
1356 +
1357 + }
1358 +
1359 + return $block;
1360 +}
1361 +
1362 +// Walk a parsed block tree and sanitize every Pagelayer block in it, at any depth
1363 +function pagelayer_sanitize_block_tree($block){
1364 +
1365 + $block_name = isset($block['blockName']) ? $block['blockName'] : '';
1366 +
1367 + // Is pagelayer block ? pagelayer_sanitize_blocks_save_pre() walks the
1368 + // whole subtree, so we are done for this branch
1369 + if(is_string($block_name) && 0 === strpos($block_name, 'pagelayer/')){
1370 + return pagelayer_sanitize_blocks_save_pre($block);
1371 + }
1372 +
1373 + // Any other block can still hold Pagelayer blocks inside it
1374 + if(!empty($block['innerBlocks']) && is_array($block['innerBlocks'])){
1375 + foreach($block['innerBlocks'] as $k => $inner){
1376 + $block['innerBlocks'][$k] = pagelayer_sanitize_block_tree($inner);
1377 + }
1378 + }
1379 +
1380 + return $block;
1381 +}
1382 +
1383 +// Check for XSS codes in our shortcode attributes
1384 +function pagelayer_sanitize_shortcode_atts($content){
1385 +
1386 + // Do we have something suspicious ?
1387 + $tmp_check = pagelayer_xss_content($content);
1388 + if(empty($tmp_check)){
1389 + return $content;
1390 + }
1391 +
1392 + pagelayer_load_shortcodes();
1393 +
1394 + preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER );
1395 +
1396 + $prefixes = ['pl_'];
1397 +
1398 + $prefixes = apply_filters( 'pagelayer_valid_shortcode_tag', $prefixes);
1399 +
1400 + foreach ($matches as $shortcode) {
1401 +
1402 + $shortcode_name = $shortcode[2];
1403 +
1404 + $vailid = false;
1405 +
1406 + foreach($prefixes as $prefix) {
1407 + if (strpos($shortcode_name, $prefix) === 0) {
1408 + $vailid = true;
1409 + break;
1410 + }
1411 + }
1412 +
1413 + if(!$vailid){
1414 + continue;
1415 + }
1416 +
1417 + $attrs = shortcode_parse_atts( $shortcode[3] );
1418 + $atts = ' ';
1419 +
1420 + foreach($attrs as $key => $value){
1421 +
1422 + // Skip if key contains XSS
1423 + if (!is_numeric($key) && strlen(pagelayer_xss_content($key . '=')) > 0) continue;
1424 +
1425 + $value = wp_filter_post_kses($value);
1426 +
1427 + // Skip if value contains XSS
1428 + if (strlen(pagelayer_xss_content('"' . $value)) > 0) continue;
1429 +
1430 + $atts .= is_numeric($key) ? $value . ' ' : $key . '="' . $value . '" ';
1431 +
1432 + }
1433 +
1434 + $new_shortcode = '[' . $shortcode_name . $atts . ']';
1435 +
1436 + if(!empty($shortcode[5])){
1437 + // Recurse into the inner content so nested shortcodes
1438 + $inner = pagelayer_sanitize_shortcode_atts($shortcode[5]);
1439 + $new_shortcode .= $inner.'[/' . $shortcode_name .']';
1440 + }
1441 +
1442 + // Replace the original shortcode with sanitized attributes
1443 + $content = str_replace($shortcode[0], $new_shortcode, $content);
1444 + }
1445 +
1446 + return $content;
1447 +}
1448 +
1449 +// Scan post content for XSS payloads and return a structured report.
1450 +function pagelayer_xss_scan_post($post_id = 0){
1451 + global $post;
1452 +
1453 + $report = ['found' => false, 'items' => []];
1454 +
1455 + if(empty($post_id)){
1456 + if(!empty($post->ID)){
1457 + $post_id = $post->ID;
1458 + }else{
1459 + return $report;
1460 + }
1461 + }
1462 +
1463 + $content = get_post_field('post_content', $post_id);
1464 + if(empty($content)){
1465 + return $report;
1466 + }
1467 +
1468 + // Scan the raw content (shortcodes are not yet expanded here, so we
1469 + // catch on*= attributes inside [pl_* ele_attributes="onclick=..."])
1470 + $found = pagelayer_xss_content($content);
1471 + if(strlen($found) > 0){
1472 + $report['found'] = true;
1473 + $report['items'][] = $found;
1474 + }
1475 +
1476 + return $report;
1477 +}
1478 +
1479 +// Determine whether the XSS warning should be shown for the current post/user.
1480 +function pagelayer_should_show_xss_warning($post_id = 0){
1481 + global $post;
1482 +
1483 + if(empty($post_id)){
1484 + if(!empty($post->ID)){
1485 + $post_id = $post->ID;
1486 + }else{
1487 + return false;
1488 + }
1489 + }
1490 +
1491 + // Rule 5: user already acknowledged — don't block again
1492 + $view_token = get_transient('pagelayer_xss_view_'.$post_id.'_'.get_current_user_id());
1493 + if(!empty($view_token) && isset($_GET['pl_xss_view']) && $_GET['pl_xss_view'] === $view_token){
1494 + return false;
1495 + }
1496 +
1497 + // Rule 2: the post must contain XSS
1498 + $scan = pagelayer_xss_scan_post($post_id);
1499 + if(empty($scan['found'])){
1500 + return false;
1501 + }
1502 +
1503 + // Rule 3: skip if the current user is the post author
1504 + $author_id = (int) get_post_field('post_author', $post_id);
1505 + $current_user_id = (int) get_current_user_id();
1506 + if($author_id > 0 && $author_id === $current_user_id){
1507 + return false;
1508 + }
1509 +
1510 + // Rule 4: skip if the post author has the JS/unfiltered_html capability.
1511 + // We check this by temporarily switching to the author's context.
1512 + $author_can_js = false;
1513 + if($author_id > 0){
1514 + $author_user = get_userdata($author_id);
1515 + if(!empty($author_user)){
1516 + $author_can_js = user_can($author_user, 'unfiltered_html');
1517 + if(!$author_can_js){
1518 + $author_can_js = pagelayer_user_can_add_js_content_for_user($author_user);
1519 + }
1520 + }
1521 + }
1522 + if($author_can_js){
1523 + return false;
1524 + }
1525 +
1526 + return true;
1527 +}
1528 +
1529 +// Check if a specific user (not the current user) can add JS content.
1530 +function pagelayer_user_can_add_js_content_for_user($user){
1531 + if(empty($user) || !($user instanceof WP_User)){
1532 + return false;
1533 + }
1534 +
1535 + if(user_can($user, 'unfiltered_html')){
1536 + return true;
1537 + }
1538 +
1539 + $pagelayer_js_permission = get_option('pagelayer_js_permission');
1540 + if(empty($pagelayer_js_permission) || empty($user->roles)){
1541 + return false;
1542 + }
1543 +
1544 + foreach($user->roles as $role){
1545 + if(in_array($role, $pagelayer_js_permission)){
1546 + return true;
1547 + }
1548 + }
1549 +
1550 + return false;
1551 +}
1552 +
1553 +// Render the XSS warning page that completely blocks content rendering.
1554 +function pagelayer_render_xss_warning_block($context = 'frontend'){
1555 + global $post;
1556 +
1557 + if(empty($post->ID)){
1558 + return;
1559 + }
1560 +
1561 + if(!pagelayer_should_show_xss_warning($post->ID)){
1562 + return;
1563 + }
1564 +
1565 + // Re-scan to get the items for display
1566 + $scan = pagelayer_xss_scan_post($post->ID);
1567 + if(empty($scan['found'])){
1568 + return;
1569 + }
1570 +
1571 + $items_html = '';
1572 + foreach($scan['items'] as $item){
1573 + $items_html .= '<div class="pagelayer-xss-item">'.htmlspecialchars($item, ENT_QUOTES, 'UTF-8').'</div>';
1574 + }
1575 +
1576 + // Generate a one-time view token so the admin can explicitly consent
1577 + $view_token = wp_generate_password(32, false);
1578 + set_transient('pagelayer_xss_view_'.$post->ID.'_'.get_current_user_id(), $view_token, 3600);
1579 +
1580 + // Build the "view page" URL with the consent token
1581 + $current_url = $_SERVER['REQUEST_URI'] ?? '/';
1582 + $separator = strpos($current_url, '?') !== false ? '&' : '?';
1583 + $view_url = htmlspecialchars($current_url.$separator.'pl_xss_view='.$view_token, ENT_QUOTES, 'UTF-8');
1584 +
1585 + // Build the edit link
1586 + $edit_link = pagelayer_livelink($post->ID);
1587 + $edit_link = htmlspecialchars($edit_link.$separator.'pl_xss_view='.$view_token, ENT_QUOTES, 'UTF-8');
1588 +
1589 + // Get author info for the warning message
1590 + $author_id = (int) get_post_field('post_author', $post->ID);
1591 + $author_name = '';
1592 + if($author_id > 0){
1593 + $author_data = get_userdata($author_id);
1594 + if(!empty($author_data)){
1595 + $author_name = $author_data->display_name;
1596 + }
1597 + }
1598 +
1599 + $warning_title = __pl('xss_warning_title');
1600 + $warning_body = $author_name
1601 + ? sprintf(__pl('xss_warning_body_author'), htmlspecialchars($author_name, ENT_QUOTES, 'UTF-8'))
1602 + : __pl('xss_warning_body');
1603 + $warning_items_label = __pl('xss_warning_items');
1604 + $view_btn = __pl('xss_warning_view_page');
1605 + $edit_btn = __pl('xss_warning_edit_post');
1606 + $warning_blocked = __pl('xss_warning_blocked');
1607 +
1608 + $dashboard_link = admin_url();
1609 + $go_dashboard = __pl('xss_warning_go_dashboard');
1610 +
1611 + // Output the warning page and die() — the malicious post content is
1612 + // NEVER sent to the browser, so inline <script>, <img onerror>, and
1613 + // <iframe onload> payloads cannot execute.
1614 + $status_code = ($context === 'editor') ? 200 : 403;
1615 + if(!headers_sent()){
1616 + status_header($status_code);
1617 + header('Content-Type: text/html; charset=utf-8');
1618 + }
1619 +
1620 + echo <<<HTML
1621 +<!DOCTYPE html>
1622 +<html lang="en">
1623 +<head>
1624 +<meta charset="utf-8">
1625 +<meta name="viewport" content="width=device-width, initial-scale=1">
1626 +<title>{$warning_title}</title>
1627 +<style>
1628 +*{ margin:0; padding:0; box-sizing:border-box; }
1629 +body{
1630 + background:#f0f0f1;
1631 + font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
1632 + display:flex;
1633 + align-items:center;
1634 + justify-content:center;
1635 + min-height:100vh;
1636 + padding:20px;
1637 +}
1638 +#pagelayer-xss-block-dialog{
1639 + background:#fff;
1640 + border-radius:8px;
1641 + max-width:640px;
1642 + width:100%;
1643 + max-height:90vh;
1644 + overflow-y:auto;
1645 + box-shadow:0 4px 24px rgba(0,0,0,0.15);
1646 +}
1647 +.pagelayer-xss-block-header{
1648 + background:#d63638;
1649 + color:#fff;
1650 + padding:20px 24px;
1651 + border-radius:8px 8px 0 0;
1652 + font-size:20px;
1653 + font-weight:700;
1654 + display:flex;
1655 + align-items:center;
1656 + gap:12px;
1657 +}
1658 +.pagelayer-xss-block-body{
1659 + padding:24px;
1660 + color:#1d2327;
1661 + font-size:14px;
1662 + line-height:1.6;
1663 +}
1664 +.pagelayer-xss-block-body p{
1665 + margin:0 0 14px 0;
1666 +}
1667 +.pagelayer-xss-blocked-tag{
1668 + display:inline-block;
1669 + background:#fff4f4;
1670 + border:1px solid #d63638;
1671 + color:#d63638;
1672 + padding:3px 10px;
1673 + border-radius:3px;
1674 + font-size:12px;
1675 + font-weight:600;
1676 + margin-bottom:14px;
1677 +}
1678 +.pagelayer-xss-items{
1679 + background:#fff4f4;
1680 + border:1px solid #d63638;
1681 + border-radius:4px;
1682 + padding:14px;
1683 + margin:14px 0;
1684 + max-height:220px;
1685 + overflow-y:auto;
1686 +}
1687 +.pagelayer-xss-item{
1688 + font-family:monospace;
1689 + font-size:12px;
1690 + padding:6px 8px;
1691 + border-bottom:1px solid #f5cccc;
1692 + word-break:break-all;
1693 + color:#b32d2e;
1694 +}
1695 +.pagelayer-xss-item:last-child{
1696 + border-bottom:none;
1697 +}
1698 +.pagelayer-xss-block-actions{
1699 + padding:18px 24px;
1700 + border-top:1px solid #dcdcde;
1701 + display:flex;
1702 + gap:12px;
1703 + flex-wrap:wrap;
1704 + border-radius:0 0 8px 8px;
1705 +}
1706 +.pagelayer-xss-btn-view{
1707 + background:#2271b1;
1708 + color:#fff;
1709 + border:none;
1710 + border-radius:4px;
1711 + padding:10px 24px;
1712 + font-size:14px;
1713 + cursor:pointer;
1714 + font-weight:600;
1715 + text-decoration:none;
1716 + display:inline-block;
1717 +}
1718 +.pagelayer-xss-btn-view:hover{
1719 + background:#135e96;
1720 +}
1721 +.pagelayer-xss-btn-edit{
1722 + background:#fff;
1723 + color:#2271b1;
1724 + border:1px solid #2271b1;
1725 + border-radius:4px;
1726 + padding:10px 24px;
1727 + font-size:14px;
1728 + cursor:pointer;
1729 + font-weight:600;
1730 + text-decoration:none;
1731 + display:inline-block;
1732 +}
1733 +.pagelayer-xss-btn-edit:hover{
1734 + background:#f0f6fc;
1735 +}
1736 +.pagelayer-xss-btn-dashboard{
1737 + background:transparent;
1738 + color:#646970;
1739 + border:none;
1740 + border-radius:4px;
1741 + padding:10px 16px;
1742 + font-size:13px;
1743 + cursor:pointer;
1744 + text-decoration:none;
1745 + display:inline-block;
1746 + margin-left:auto;
1747 +}
1748 +.pagelayer-xss-btn-dashboard:hover{
1749 + color:#1d2327;
1750 +}
1751 +</style>
1752 +</head>
1753 +<body>
1754 + <div id="pagelayer-xss-block-dialog">
1755 + <div class="pagelayer-xss-block-header">
1756 + <span style="font-size:28px;">&#9888;</span>
1757 + {$warning_title}
1758 + </div>
1759 + <div class="pagelayer-xss-block-body">
1760 + <span class="pagelayer-xss-blocked-tag">{$warning_blocked}</span>
1761 + <p>{$warning_body}</p>
1762 + <p style="font-weight:600; margin-bottom:6px;">{$warning_items_label}:</p>
1763 + <div class="pagelayer-xss-items">{$items_html}</div>
1764 + </div>
1765 + <div class="pagelayer-xss-block-actions">
1766 + <a href="{$view_url}" class="pagelayer-xss-btn-view">{$view_btn}</a>
1767 + <a href="{$edit_link}" class="pagelayer-xss-btn-edit">{$edit_btn}</a>
1768 + <a href="{$dashboard_link}" class="pagelayer-xss-btn-dashboard">{$go_dashboard}</a>
1769 + </div>
1770 + </div>
1771 +</body>
1772 +</html>
1773 +HTML;
1774 +
1775 + // CRITICAL: die() here ensures the malicious post content (the_content,
1776 + // do_shortcode output, block rendering) is NEVER sent to the browser.
1777 + // Without die(), WordPress would continue rendering the template and
1778 + // output the post body — including any <script>/<img onerror>/<iframe
1779 + // onload> payloads — which would execute even if hidden with CSS.
1780 + die();
1781 +}
1782 +
1783 +function pagelayer_getting_started_notice(){
1784 +
1785 + // Is Sitepad setup done?
1786 + $setup_done = get_option('sp_setup_done');
1787 +
1788 + if(defined('SITEPAD') && empty($setup_done)){
1789 + return;
1790 + }
1791 +
1792 + // If SitePad used custom BRAND SM
1793 + if(defined('BRAND_SM_CUSTOM')){
1794 + return;
1795 + }
1796 +
1797 + echo '
1798 +<script type="application/javascript">
1799 +jQuery(document).ready(function(){
1800 + jQuery("#pagelayer-getting-started-notice").click(function(e){
1801 +
1802 + if(jQuery(e.target).hasClass("notice-dismiss")){
1803 + var data;
1804 + jQuery("#pagelayer-getting-started-notice").hide();
1805 + // Save this preference
1806 + jQuery.post("'.admin_url('?pagelayer-getting-started=0&pagelayer_nonce='.wp_create_nonce("pagelayer_getting_started_nonce") ).'", data, function(response) {
1807 + //alert(response);
1808 + });
1809 + return false;
1810 + }
1811 +
1812 + });
1813 +});
1814 +</script>
1815 +
1816 + <div id="pagelayer-getting-started-notice" class="notice notice-success is-dismissible">
1817 + <p style="font-size: 14px; font-weight: 600">';
1818 + if(defined('SITEPAD')){
1819 +
1820 + 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.'.');
1821 +
1822 + }else{
1823 +
1824 + 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');
1825 +
1826 + }
1827 +
1828 + echo '</p>
1829 + </div>';
1830 +
1831 +}
1832 +
1833 +// Show Changelog promo
1834 +function pagelayer_show_changelog_notice(){
1835 +
1836 + // Is Sitepad setup done?
1837 + if(defined('SITEPAD')){
1838 + return;
1839 + }
1840 +
1841 + echo '
1842 +<script type="application/javascript">
1843 +jQuery(document).ready(function(){
1844 + jQuery("#pagelayer-changelog-notice").click(function(e){
1845 +
1846 + if(jQuery(e.target).hasClass("notice-dismiss")){
1847 + var data;
1848 + jQuery("#pagelayer-changelog-notice").hide();
1849 + // Save this preference
1850 + jQuery.post("'.admin_url('?pagelayer-changelog-notice=0&pagelayer_nonce='.wp_create_nonce("pagelayer_changelog_nonce") ).'", data, function(response) {
1851 + //alert(response);
1852 + });
1853 + return false;
1854 + }
1855 +
1856 + });
1857 +});
1858 +</script>
1859 +
1860 + <div id="pagelayer-changelog-notice" class="notice notice-info is-dismissible">
1861 + <p style="font-size: 14px; font-weight: 600">
1862 + <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') .'
1863 + </p>
1864 + </div>';
1865 +
1866 +}
1867 +
764 1868 // Show promo notice on dashboard
765 1869 function pagelayer_show_promo(){
766 1870
767 1871 global $pagelayer_promo_opts;
@@ -767,67 +1871,69 @@
767 1871 global $pagelayer_promo_opts;
768 1872 $opts = $pagelayer_promo_opts;
769 1873
770 1874 echo '<style>
771 -.pagelayer_promo_button {
772 -background-color: #4CAF50; /* Green */
773 -border: none;
774 -color: white;
775 -padding: 6px 10px;
776 -text-align: center;
777 -text-decoration: none;
778 -display: inline-block;
779 -font-size: 13px;
780 -margin: 4px 2px;
781 --webkit-transition-duration: 0.4s; /* Safari */
1875 +#pagelayer_promo a.pagelayer_promo_button {
1876 +background-color: #4CAF50 !important;
1877 +border: none !important;
1878 +color: white !important;
1879 +padding: 6px 10px !important;
1880 +text-align: center !important;
1881 +text-decoration: none !important;
1882 +display: inline-block !important;
1883 +font-size: 13px !important;
1884 +margin: 4px 2px !important;
1885 +-webkit-transition-duration: 0.4s;
782 1886 transition-duration: 0.4s;
783 -cursor: pointer;
1887 +cursor: pointer !important;
784 1888 }
785 -.pagelayer_promo_button:focus{
786 -border: none;
787 -color: white;
1889 +#pagelayer_promo a.pagelayer_promo_button:focus,
1890 +#pagelayer_promo a.pagelayer_promo_button:hover{
1891 +border: none !important;
1892 +color: white !important;
1893 +box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19) !important;
788 1894 }
789 -.pagelayer_promo_button1 {
790 -color: white;
791 -background-color: #4CAF50;
792 -border:3px solid #4CAF50;
1895 +#pagelayer_promo a.pagelayer_promo_buy {
1896 +color: white !important;
1897 +padding: 8px 12px !important;
1898 +font-size: 14px !important;
1899 +background-color: #4CAF50 !important;
793 1900 }
794 -.pagelayer_promo_button1:hover {
795 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
796 -color: white;
797 -border:3px solid #4CAF50;
1901 +#pagelayer_promo a.pagelayer_promo_button1 {
1902 +color: white !important;
1903 +background-color: #4CAF50 !important;
1904 +border:3px solid #4CAF50 !important;
798 1905 }
799 -.pagelayer_promo_button2 {
800 -color: white;
801 -background-color: #0085ba;
1906 +#pagelayer_promo a.pagelayer_promo_button1:hover {
1907 +border:3px solid #4CAF50 !important;
802 1908 }
803 -.pagelayer_promo_button2:hover {
804 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
805 -color: white;
1909 +#pagelayer_promo a.pagelayer_promo_button2 {
1910 +color: white !important;
1911 +background-color: #0085ba !important;
806 1912 }
807 -.pagelayer_promo_button3 {
808 -color: white;
809 -background-color: #365899;
1913 +#pagelayer_promo a.pagelayer_promo_button3 {
1914 +color: white !important;
1915 +background-color: #365899 !important;
810 1916 }
811 -.pagelayer_promo_button3:hover {
812 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
813 -color: white;
1917 +#pagelayer_promo a.pagelayer_promo_button4 {
1918 +color: white !important;
1919 +background-color: rgb(66, 184, 221) !important;
814 1920 }
815 -.pagelayer_promo_button4 {
816 -color: white;
817 -background-color: rgb(66, 184, 221);
1921 +#pagelayer_promo a.pagelayer_promo-close{
1922 +float:right !important;
1923 +text-decoration:none !important;
1924 +margin: 5px 10px 0px 0px !important;
1925 +color: #666 !important;
818 1926 }
819 -.pagelayer_promo_button4:hover {
820 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
821 -color: white;
1927 +#pagelayer_promo a.pagelayer_promo-close:hover{
1928 +color: red !important;
822 1929 }
823 -.pagelayer_promo-close{
824 -float:right;
825 -text-decoration:none;
826 -margin: 5px 10px 0px 0px;
1930 +#pagelayer_promo a:not(.pagelayer_promo_button):not(.pagelayer_promo-close) {
1931 +color: #4CAF50 !important;
1932 +text-decoration: underline !important;
827 1933 }
828 -.pagelayer_promo-close:hover{
829 -color: red;
1934 +#pagelayer_promo a:not(.pagelayer_promo_button):not(.pagelayer_promo-close):hover {
1935 +color: #3e8e41 !important;
830 1936 }
831 1937 </style>
832 1938 <script type="application/javascript">
833 1939 jQuery(document).ready(function(){
@@ -851,16 +1957,23 @@
851 1957 echo '<a href="'.$opts['website'].'"><img src="'.$opts['image'].'" style="float:left; margin:10px 20px 10px 10px" width="67" /></a>';
852 1958 }
853 1959
854 1960 echo '
855 - <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>
1961 + <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>
856 1962 <p>
1963 + '.(empty($opts['pro_url']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_buy" target="_blank" href="'.$opts['pro_url'].'">Buy Pagelayer Pro</a>').'
857 1964 '.(empty($opts['rating']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button2" target="_blank" href="'.$opts['rating'].'">Rate it 5★\'s</a>').'
858 1965 '.(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>').'
859 1966 '.(empty($opts['twitter']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button4" target="_blank" href="'.$opts['twitter'].'"><span class="dashicons dashicons-twitter"></span> Tweet</a>').'
860 1967 '.(empty($opts['website']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button4" target="_blank" href="'.$opts['website'].'">Visit our website</a>').'
861 1968 </p>
862 -</div>';
1969 + <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.';
1970 +
1971 + if(date('Ymd') <= 20200331){
1972 + 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>.';
1973 + }
1974 +
1975 +echo '</p></div>';
863 1976
864 1977 }
865 1978
866 1979 // Are we to show a promo ?
@@ -868,8 +1981,13 @@
868 1981
869 1982 global $pagelayer_promo_opts;
870 1983
871 1984 // There must be an interval
1985 + if(!current_user_can('activate_plugins')){
1986 + return false;
1987 + }
1988 +
1989 + // There must be an interval
872 1990 if(empty($opts['interval'])){
873 1991 return false;
874 1992 }
875 1993
@@ -896,8 +2014,475 @@
896 2014 }
897 2015
898 2016 }
899 2017
2018 +// Show the Pro notice
2019 +function pagelayer_show_pro_notice(){
2020 +
2021 + if(defined('PAGELAYER_PREMIUM')){
2022 + return;
2023 + }
2024 +
2025 + 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>';
2026 +
2027 +}
2028 +
2029 +// Show the Pro Div
2030 +function pagelayer_show_pro_div($head = '', $message = '', $admin_css = 1){
2031 +
2032 + if(defined('PAGELAYER_PREMIUM')){
2033 + return;
2034 + }
2035 +
2036 + if(basename(get_template_directory()) == 'popularfx'){
2037 + $pro_url = 'https://popularfx.com/pricing?from=pagelayer-plugin';
2038 + $pro_txt = 'PopularFX Pro';
2039 + }else{
2040 + $pro_url = PAGELAYER_PRO_PRICE_URL;
2041 + $pro_txt = 'Pagelayer Pro';
2042 + }
2043 +
2044 + if(!empty($admin_css)){
2045 + wp_enqueue_style( 'pagelayer-admin', PAGELAYER_CSS.'/pagelayer-admin.css', array(), PAGELAYER_VERSION);
2046 + }
2047 +
2048 + echo '<div class="pagelayer-pro-div">';
2049 +
2050 + if(!empty($head)){
2051 + echo '<h1 class="pagelayer-pro-head">'.$head.'</h1>';
2052 + }
2053 +
2054 + echo '<div class="pagelayer-pro-message">';
2055 +
2056 + if(empty($message)){
2057 +
2058 + 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.');
2059 +
2060 + }else{
2061 +
2062 + echo $message;
2063 + echo ' '.__('This feature is a part of <a href="'.$pro_url.'" target="_blank">'.$pro_txt.'</a>.');
2064 +
2065 + }
2066 +
2067 + echo '</div>
2068 + <center><a class="button-pagelayer" href="'.$pro_url.'" target="_blank" style="text-decoration: none;">'.sprintf(__('Upgrade to %s', 'pagelayer'), $pro_txt).'</a></center>
2069 + </div>';
2070 +
2071 +}
2072 +
2073 +// Bread Crumbs with links
2074 +function pagelayer_get_breadcrumb(){
2075 + global $post;
2076 +
2077 + // Home page
2078 + $ret = '<a href="'.home_url().'" rel="nofollow">{{home}}</a>';
2079 +
2080 + // Is Front page
2081 + if(is_front_page()){
2082 + return $ret;
2083 +
2084 + // Is search query
2085 + }elseif(is_search()){
2086 + $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><b class="pagelayer-breadcrumb-prefix" if="{{search_prefix}}">{{search_prefix}}</b>';
2087 + $ret .= '<em>';
2088 + $ret .= '<span>'.get_search_query().'</span>';
2089 + $ret .= '</em>';
2090 +
2091 + //Is category or single post
2092 + }elseif(is_category() || is_single()){
2093 +
2094 + $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
2095 + $categories = get_the_category();
2096 + $separator = ' ';
2097 + $output = '';
2098 + if(!empty($categories)){
2099 + $ret .= get_category_parents($categories[0], true, ' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b> ');
2100 + }
2101 + if(is_single()) {
2102 + /* if (empty($categories)){
2103 + $ret .= ' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b> ';
2104 + } */
2105 + $ret .= '<span>'.get_the_title().'</span>';
2106 + }
2107 +
2108 + // Is page
2109 + }elseif(is_page() ){
2110 + if(!empty($post->post_parent)){
2111 + $ancestors = array_reverse(get_post_ancestors( $post->ID ));
2112 + $page_on_front = get_option('page_on_front');
2113 +
2114 + foreach( $ancestors as $ancestor ){
2115 +
2116 + if($page_on_front == $ancestor){
2117 + continue;
2118 + }
2119 +
2120 + $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><a href="'.get_permalink($ancestor).'">'.get_the_title($ancestor).'</a>';
2121 + }
2122 +
2123 + $ret .=' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><span>'.get_the_title().'</span>';
2124 +
2125 + }else{
2126 + $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
2127 + $ret .= '<span>'.get_the_title().'</span>';
2128 + }
2129 + }else{
2130 + $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
2131 + $ret .= '<span>'.wp_title('', false ).'</span>';
2132 + }
2133 +
2134 + // wooCommerce Integration left
2135 +
2136 + return $ret;
2137 +}
2138 +
2139 +// Portfolio Posts
2140 +function pagelayer_widget_posts($args){
2141 +
2142 + $r = new \WP_Query($args);
2143 +
2144 + $ret = '';
2145 + if ( $r->have_posts() ){
2146 +
2147 + if($args['filter_by'] != 'none' && $args['post_type'] == 'post'){
2148 + $ret .= '<div class="pagelayer-postfolio-filter">';
2149 +
2150 + $data_filter = ( $args['filter_by'] == 'category' ? get_categories() : get_tags() );
2151 +
2152 + if(!empty($data_filter)){
2153 +
2154 + $ret .= '<div class="pagelayer-postfolio-btn" data-filter="all">'.__pl('All').'</div>';
2155 +
2156 + foreach($data_filter as $filter) {
2157 + $ret .= '<div class="pagelayer-postfolio-btn" data-filter="'.$filter->name.'">' . $filter->name . '</div>';
2158 + }
2159 +
2160 + }
2161 +
2162 + $ret .= '</div>';
2163 + }
2164 +
2165 + $ret .= '<div class="pagelayer-postfolio-container">';
2166 +
2167 + while ( $r->have_posts() ) : $r->the_post();
2168 + $post_meta = ( $args['filter_by'] == 'category' ? get_the_category() : get_the_tags() );
2169 + $meta_attr = '';
2170 + if($post_meta){
2171 +
2172 + $meta_array = array();
2173 + foreach( $post_meta as $meta ){
2174 + $meta_array[] = $meta->name;
2175 + }
2176 + $meta_attr .= ' data-category="'.implode(' ', $meta_array).'"';
2177 + }
2178 +
2179 + $ret .= '<div class="pagelayer-postfolio-thumb"'.(has_post_thumbnail() ? ' style="background:url('.get_the_post_thumbnail_url().')"' : ''). $meta_attr .'>';
2180 + $ret .= '<a href="'.esc_url( get_permalink() ).'" rel="bookmark">';
2181 + $ret .= '<div class="pagelayer-postfolio-content">';
2182 + $ret .= '<h4 class="pagelayer-entry-title">'.get_the_title().'</h4>';
2183 + $ret .= '</div></a></div>';
2184 +
2185 + endwhile;
2186 +
2187 + $ret .= '</div>';
2188 +
2189 + }
2190 +
2191 + return $ret;
2192 +}
2193 +
2194 +// List all available sizes of images registered on WordPress
2195 +function pagelayer_image_sizes(){
2196 +
2197 + $sizes = array();
2198 + $sizes = get_intermediate_image_sizes();
2199 + $ret = array();
2200 + foreach($sizes as $size){
2201 + $ret[$size] = __pl($size);
2202 + }
2203 +
2204 + return $ret;
2205 +}
2206 +
2207 +function pagelayer_remove_excerpt_more($more){
2208 + return '';
2209 +}
2210 +
2211 +function pagelayer_posts($params, $args = []){
2212 + global $post, $wp_query;
2213 +
2214 + if(isset($params['exc_length'])){
2215 + $exc_length = (int) $params['exc_length'];
2216 + add_filter( 'excerpt_length', function($length) use($exc_length){
2217 + return $exc_length;
2218 + }, 999 );
2219 + }
2220 +
2221 + // add_filter('excerpt_more', 'pagelayer_remove_excerpt_more', 999);
2222 +
2223 + // If args is empty
2224 + if(empty($args)){
2225 + $args = array(
2226 + 'post_type' => $params['post_type'],
2227 + 'posts_per_page' => $params['posts_per_page'],
2228 + 'order' => $params['order']
2229 + );
2230 +
2231 + if(!empty($params['paged'])){
2232 + $args['paged'] = $params['paged'];
2233 + }
2234 +
2235 + if (!empty($params['term']) || !empty($params['exc_term'])) {
2236 + $tax_query = [];
2237 +
2238 + if (!empty($params['term'])) {
2239 + $terms = explode(',', $params['term']);
2240 + $include = array_reduce($terms, function ($carry, $term) {
2241 + list($taxonomy, $slug, $id) = explode(':', $term);
2242 + $carry[$taxonomy][] = $slug;
2243 + return $carry;
2244 + }, []);
2245 +
2246 + $filters = array_filter([
2247 + isset($include['category']) ? [
2248 + 'taxonomy' => 'category',
2249 + 'field' => 'slug',
2250 + 'terms' => $include['category'],
2251 + 'include_children' => false,
2252 + ] : null,
2253 + isset($include['post_tag']) ? [
2254 + 'taxonomy' => 'post_tag',
2255 + 'field' => 'slug',
2256 + 'terms' => $include['post_tag'],
2257 + 'include_children' => false,
2258 + ] : null,
2259 + ]);
2260 +
2261 + if(!empty($filters)){
2262 + $tax_query[] = array_merge(['relation' => 'OR'], $filters);
2263 + }
2264 + }
2265 +
2266 + // Handle exclusions
2267 + if (!empty($params['exc_term'])) {
2268 + $terms = explode(',', $params['exc_term']);
2269 + $include = array_reduce($terms, function ($carry, $term) {
2270 + list($taxonomy, $slug, $id) = explode(':', $term);
2271 + $carry[$taxonomy][] = $slug;
2272 + return $carry;
2273 + }, []);
2274 +
2275 + $filters = array_filter([
2276 + isset($include['category']) ? [
2277 + 'taxonomy' => 'category',
2278 + 'field' => 'slug',
2279 + 'terms' => $include['category'],
2280 + 'operator' => 'NOT IN',
2281 + 'include_children' => false,
2282 + ] : null,
2283 + isset($include['post_tag']) ? [
2284 + 'taxonomy' => 'post_tag',
2285 + 'field' => 'slug',
2286 + 'terms' => $include['post_tag'],
2287 + 'operator' => 'NOT IN',
2288 + 'include_children' => false,
2289 + ] : null,
2290 + ]);
2291 +
2292 + if(!empty($filters)){
2293 + $tax_query[] = array_merge(['relation' => 'AND'], $filters);
2294 + }
2295 + }
2296 +
2297 + // Apply the combined tax_query
2298 + if(!empty($tax_query)){
2299 + $args['tax_query'] = array_merge(['relation' => 'AND'], $tax_query);
2300 + }
2301 + }
2302 +
2303 + if(!empty($params['author_name'])){
2304 + $author_name = explode(':', $params['author_name']);
2305 + $args['author_name'] = $author_name[0];
2306 + }
2307 +
2308 + if(!empty($params['exc_author'])){
2309 + $exc_author = explode(':', $params['exc_author']);
2310 + $args['author'] = '-'.$exc_author[1];
2311 + }
2312 +
2313 + if (!empty($params['offset'])) {
2314 + $args['offset'] = (int) $params['offset'];
2315 +
2316 + // Make Compatible for Infinite load
2317 + if(!empty($params['infinite_types']) && !empty($params['paged']) && $params['paged'] > 1 ){
2318 + $args['offset'] = $args['offset'] + (($params['paged'] - 1) * $params['posts_per_page']);
2319 + }
2320 + }
2321 +
2322 + if(!empty($params['ignore_sticky'])){
2323 + $args['ignore_sticky_posts'] = $params['ignore_sticky'];
2324 + }
2325 +
2326 + if(!empty($params['orderby'])){
2327 + $args['orderby'] = $params['orderby'];
2328 + }
2329 +
2330 + if(!empty($params['by_period'])){
2331 + $date_arg = array();
2332 + switch($params['by_period']){
2333 + case 'last_day':
2334 + $date_arg['day'] = date('j')-1;
2335 + break;
2336 + case 'last_week':
2337 + $date_arg['week'] = date('W')-1;
2338 + break;
2339 + case 'last_month':
2340 + $date_arg['month'] = date('n')-1;
2341 + break;
2342 + case 'last_year':
2343 + $date_arg['year'] = date('Y')-1;
2344 + break;
2345 + case 'custom':
2346 + $date_arg['before'] = $params['before_date'];
2347 + $date_arg['after'] = $params['after_date'];
2348 + break;
2349 + }
2350 + $args['date_query'] = array(
2351 + $date_arg
2352 + );
2353 + }
2354 + }
2355 + //pagelayer_print($args);
2356 +
2357 + // Only see published posts
2358 + $args['post_status'] = 'publish';
2359 +
2360 + $postsquery = new WP_Query($args);
2361 + $data = '';
2362 +
2363 + if(!wp_doing_ajax() && !empty($params['infinite_types'])){
2364 + $data.='<div class="pagelayer-post-max" data-max="'.$postsquery->max_num_pages.'"></div>';
2365 + }
2366 +
2367 + if(!$postsquery->have_posts()){
2368 + return '<h3>No posts found!</h3>';
2369 + }
2370 +
2371 + // To reset the post when the $wp_query->post is empty
2372 + $orig_post = $post;
2373 +
2374 + while($postsquery->have_posts()) : $postsquery->the_post();
2375 + $data .= '<div class="pagelayer-wposts-col">
2376 + <div class="pagelayer-wposts-post">
2377 + <div class="pagelayer-wposts-featured">';
2378 + $data .= '<a href="'. get_the_permalink() .'">';
2379 +
2380 + if(!empty($params['show_thumb'])){
2381 + $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>';
2382 + }
2383 + /* if($params['show_thumb'] && has_post_thumbnail( $postsquery->ID )){
2384 + $data .= get_the_post_thumbnail_url($postsquery->ID,$params['thumb_size']);
2385 + } */
2386 + $data .= '</a></div>
2387 + <div class="pagelayer-wposts-content">';
2388 +
2389 + if(!empty($params['show_title'])){
2390 + $data .= '<a href="'.esc_url( get_permalink() ).'" rel="bookmark"><div class="pagelayer-wposts-title">'. get_the_title().'</div></a>';
2391 + }
2392 +
2393 + $data .= '<div class="pagelayer-wposts-meta">';
2394 + $sep = '';
2395 + if(!empty($params['meta_sep'])){
2396 + $sep = ' <b class="pagelayer-wposts-sep">'.$params['meta_sep'].'</b> ';
2397 + }
2398 + if(!empty($params['author'])){
2399 + $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;
2400 + }
2401 + if(!empty($params['date'])){
2402 + $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;
2403 + }
2404 +
2405 + if(!empty($params['category'])){
2406 + $category = get_the_category();
2407 + $singlecategory = '';
2408 + foreach( $category as $cat ){
2409 + $singlecategory .= '<a href="' . get_tag_link( $cat->term_id ) . '">'. $cat->name .'</a>';
2410 + }
2411 +
2412 + if(!empty($singlecategory)){
2413 + $data .= '<span class="pagelayer-wposts-category">' . $singlecategory . '</span>'.$sep;
2414 + }
2415 +
2416 + }
2417 +
2418 + if(!empty($params['tags'])){
2419 + $tags = get_the_tags();
2420 + $singletag = '';
2421 + if(!empty($tags)){
2422 + foreach( $tags as $tag ){
2423 + $singletag .= '<a href="' . get_tag_link( $tag->term_id ) . '">'. $tag->name .'</a>';
2424 + }
2425 + if(!empty($singletag)){
2426 + $data .= '<span class="pagelayer-wposts-tags">'.$singletag.'</span>'.$sep;
2427 + }
2428 + }
2429 +
2430 + }
2431 +
2432 + if(!empty($params['comments']) && comments_open($postsquery->ID)){
2433 + $data .= '<span class="pagelayer-wposts-comments"><a href="' . esc_url( get_permalink() ) . '">' . esc_html(get_comments_number()).' '.__pl('comments').'</a></span>'.$sep;
2434 + }
2435 +
2436 + $data .= '</div>';
2437 +
2438 + if(!empty($params['show_content'])){
2439 + $data .= '<div class="pagelayer-wposts-excerpt">';
2440 +
2441 + if($params['show_content'] == 'excerpt'){
2442 + $post_excerpt = get_the_excerpt();
2443 + $trimmed_excerpt = !empty($params['exc_length']) ? wp_trim_words($post_excerpt, (int) $params['exc_length']) : $post_excerpt;
2444 + $data .= pagelayer_the_content($trimmed_excerpt);
2445 + } elseif ($params['show_content'] == 'full') {
2446 + $data .= pagelayer_the_content(get_the_content());
2447 + }
2448 + $data .= '</div>';
2449 + }
2450 +
2451 + if(!empty($params['show_more'])){
2452 + $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().'">';
2453 +
2454 + if($params['icon']){
2455 + $data .= '<i class="'.$params['icon'].' pagelayer-btn-icon"></i>';
2456 + }
2457 +
2458 + if($params['more']){
2459 + $data .= '<span class="pagelayer-btn-text">'.$params['more'].'</span>';
2460 + }
2461 +
2462 + if($params['icon']){
2463 + $data .= '<i class="'.$params['icon'].' pagelayer-btn-icon"></i>';
2464 + }
2465 +
2466 + $data .= '</a></div>';
2467 +
2468 + //$data .= '<a class="pagelayer-wposts-more" href="'. get_the_permalink().'">'.$params['more'].'</a>';
2469 + }
2470 +
2471 + //$data .= '<div class="pagelayer-wposts-date"><p>'.get_the_date().'</p></div>';
2472 + $data .= '</div></div></div>';
2473 + endwhile;
2474 +
2475 + // In the Gutenberg while adding new page the $wp_query->post was empty
2476 + if ( !isset( $wp_query ) || empty($wp_query->post) ) {
2477 + $GLOBALS['post'] = $orig_post;
2478 + }else{
2479 + wp_reset_postdata();
2480 + }
2481 +
2482 + return $data;
2483 +}
2484 +
900 2485 // Get Post Revision
901 2486 function pagelayer_get_post_revision_by_id($postID){
902 2487
903 2488 // Insert the post revision into the database
@@ -927,5 +2512,1943 @@
927 2512 $post_revisions[] = $post_tmp_data;
928 2513 }
929 2514
930 2515 return $post_revisions;
2516 +}
2517 +
2518 +// Gets author data
2519 +function pagelayer_author_data($postID){
2520 +
2521 + $authorID = get_post_field('post_author', $postID);
2522 + $data['display_name'] = get_the_author_meta( 'display_name' , $authorID );
2523 + $data['description'] = get_the_author_meta( 'description' , $authorID );
2524 + $data['user_url'] = get_author_posts_url( $authorID , '' );
2525 + $data['avatar'] = get_avatar_url( $authorID );
2526 +
2527 + return $data;
2528 +}
2529 +
2530 +// Posts Slider
2531 +function pagelayer_posts_slider($params){
2532 +
2533 + $args = array();
2534 +
2535 + if(isset($params['post']['post_type'])){
2536 + $args['post_type'] = $params['post']['post_type'];
2537 + }
2538 +
2539 + if(isset($params['post']['category'])){
2540 + $args['category_name'] = $params['post']['category'];
2541 + }
2542 +
2543 + if(isset($params['post']['tags'])){
2544 + $args['tag'] = $params['post']['tags'];
2545 + }
2546 +
2547 + if(isset($params['post']['order_by'])){
2548 + $args['orderby'] = $params['post']['order_by'];
2549 + }
2550 +
2551 + if(isset($params['post']['sort_order'])){
2552 + $args['order'] = $params['post']['sort_order'];
2553 + }
2554 +
2555 + if(isset($params['post']['post_count'])){
2556 + $args['posts_per_page'] = $params['post']['post_count'];
2557 + }
2558 +
2559 + $data = '';
2560 + $postsquery = new WP_Query($args);
2561 + if ( $postsquery->have_posts() ){
2562 + while ( $postsquery->have_posts() ) : $postsquery->the_post();
2563 + $data .= '<li class="pagelayer-posts-slider-col">
2564 + <div class="pagelayer-posts-slider-post">
2565 + <div class="pagelayer-posts-slider-featured-img">';
2566 + $data .= '<a href="'. get_the_permalink() .'">';
2567 + if(has_post_thumbnail( $postsquery->ID ) ){
2568 + if($params['post']['image_size'] == "full" || $params['post']['image_size'] == "custom" ){
2569 + $image = wp_get_attachment_image_src( get_post_thumbnail_id( $postsquery->ID ), 'single-post-thumbnail' );
2570 + $data .= '<img class="pagelayer-img" src="'.$image[0].'" class="pagelayer-posts-slider-img">';
2571 + }else if($params['post']['image_size'] == "thumbnail"){
2572 + $data .= get_the_post_thumbnail();
2573 + }
2574 + }
2575 + $data .= '</a></div>
2576 + <div class="pagelayer-posts-slider-content">';
2577 + $data .= '<p class="pagelayer-posts-slider-title">'. get_the_title().'</p>';
2578 + $data .= '<div class="pagelayer-posts-slider-excerpt">';
2579 + if($params['post']['show_excerpt'] == "true"){
2580 + if(has_excerpt()){
2581 + $excerpt = get_the_excerpt();
2582 + $data .= pagelayer_the_content($excerpt);
2583 + }
2584 + }
2585 + $data .= '</div>';
2586 + $data .= '<a class="pagelayer-posts-slider-link" href="'. get_the_permalink().'">Read More</a>';
2587 + $data .= '<div class="pagelayer-post-slider-date"><p>'.get_the_date().'</p></div>';
2588 + $data .= '</div></div></li>';
2589 + endwhile;
2590 + }
2591 + return $data;
2592 +}
2593 +
2594 +// Gets the site logo URLs
2595 +function pagelayer_site_logo(){
2596 +
2597 + if(get_theme_mod('custom_logo')){
2598 + $logo_id = get_theme_mod('custom_logo');
2599 + return pagelayer_image($logo_id);
2600 + }
2601 +
2602 + return NULL;
2603 +}
2604 +
2605 +// Create select options
2606 +function pagelayer_create_sel_options( $opt_array , $selected = ''){
2607 + $options = '';
2608 + foreach($opt_array as $x => $val){
2609 +
2610 + // Single item
2611 + if(is_string($opt_array[$x])){
2612 + $options .= pagelayer_sel_option($x, $val, $selected);
2613 +
2614 + // Groups
2615 + }else{
2616 +
2617 + if(array_key_exists('hide_drop', $opt_array[$x]) && !empty($opt_array[$x]['hide_drop'])){
2618 + continue;
2619 + }
2620 +
2621 + // If Label is there, then its a normal option
2622 + if(array_key_exists('label', $opt_array[$x])){
2623 + $options .= pagelayer_sel_option($x, $opt_array[$x]['label'], $selected);
2624 +
2625 + // Optgroups
2626 + } else{
2627 + $options .= '<optgroup label="'. $x .'">';
2628 + $options .= pagelayer_create_sel_options($opt_array[$x], $selected);
2629 + $options .= '</optgroup>';
2630 + }
2631 + }
2632 + }
2633 +
2634 + return $options;
2635 +}
2636 +
2637 +// Create option HTML
2638 +function pagelayer_sel_option($val, $lang, $selected){
2639 + return '<option value="'. $val .'" '. (($val != $selected) ? '' : 'selected="selected"') .' >'. $lang .'</option>';
2640 +}
2641 +
2642 +// Get values from multi-dimensional array by key
2643 +function pagelayer_multi_array_search(&$array, $key){
2644 +
2645 + if(!is_array($array)){
2646 + return false;
2647 + }
2648 +
2649 + foreach ($array as $k => $v) {
2650 +
2651 + if($k == $key){
2652 + return $v;
2653 + }
2654 +
2655 + if (is_array($v)) {
2656 + $found = pagelayer_multi_array_search($v, $key);
2657 + if(!empty($found)){
2658 + return $found;
2659 + }
2660 + }
2661 + }
2662 +
2663 + return false;
2664 +}
2665 +
2666 +function pagelayer_get_post_term(){
2667 +
2668 + $args = [
2669 + 'taxonomy' => array('category','post_tag'),
2670 + 'hide_empty' => false,
2671 + ];
2672 +
2673 + $terms = get_terms( $args );
2674 +
2675 + $ret = array();
2676 + foreach ( $terms as $term ) {
2677 + $ret[$term->taxonomy.':'.$term->slug.':'.$term->term_taxonomy_id] = $term->taxonomy .': '. $term->name;
2678 + }
2679 + //pagelayer_print($terms);die();
2680 + return $ret;
2681 +}
2682 +
2683 +function pagelayer_get_post_author(){
2684 +
2685 + $args = [
2686 + 'capability' => array( 'edit_posts' ),
2687 + 'fields' => [
2688 + 'ID',
2689 + 'display_name',
2690 + 'user_nicename',
2691 + ]
2692 + ];
2693 +
2694 + // Capability queries were only introduced in WP 5.9.
2695 + if( version_compare( $GLOBALS['wp_version'], '5.9-alpha', '<' ) ){
2696 + $args['who'] = 'authors';
2697 + unset( $args['capability'] );
2698 + }
2699 +
2700 + $authors = new \WP_User_Query( $args );
2701 +
2702 + $ret = array();
2703 + foreach ( $authors->get_results() as $author ) {
2704 + $ret[$author->user_nicename.':'.$author->ID] = $author->display_name;
2705 + }
2706 + //pagelayer_print($authors->get_results());die();
2707 + return $ret;
2708 +}
2709 +
2710 +// Gets the registered post types
2711 +function pagelayer_get_public_post_types( $args = [] ) {
2712 +
2713 + global $pagelayer;
2714 +
2715 + $post_type_args = [
2716 + 'public' => true,
2717 + ];
2718 +
2719 + $post_type_args = wp_parse_args( $post_type_args, $args );
2720 +
2721 + $_post_types = get_post_types( $post_type_args, 'objects' );
2722 +
2723 + $post_types = array();
2724 +
2725 + foreach ( $_post_types as $post_type => $object ) {
2726 +
2727 + if($post_type == $pagelayer->builder['name']){
2728 + continue;
2729 + }
2730 +
2731 + $post_types[ $post_type ] = $object->label;
2732 + }
2733 + //print_r($post_types);
2734 +
2735 + return $post_types;
2736 +}
2737 +
2738 +// Simply echo and dir
2739 +function pagelayer_json_output(&$done){
2740 +
2741 + echo json_encode($done);
2742 + wp_die();
2743 +
2744 +}
2745 +
2746 +// Get the current query for render the product
2747 +function pagelayer_shortcode_current_query($query_args, $atts, $type){
2748 + global $wp_query;
2749 +
2750 + if($type == 'pagelayer_current_query'){
2751 +
2752 + if ( ! is_page( wc_get_page_id( 'shop' ) ) ) {
2753 + $query_args = $wp_query->query_vars;
2754 + }
2755 +
2756 + add_action( "woocommerce_shortcode_before_{$type}_loop", function () {
2757 + wc_set_loop_prop( 'is_shortcode', false );
2758 + } );
2759 +
2760 + if(!empty($atts['paginate'])){
2761 + $page = get_query_var( 'paged', 1 );
2762 +
2763 + if( 1 < $page ) {
2764 + $query_args['paged'] = $page;
2765 + }
2766 + }
2767 +
2768 + // Always query only IDs
2769 + $query_args['fields'] = 'ids';
2770 +
2771 + }
2772 +
2773 + return $query_args;
2774 +}
2775 +
2776 +// Loads the tags which have parameters of a particular type
2777 +function pagelayer_get_prop_type($types){
2778 +
2779 + global $pagelayer;
2780 +
2781 + if(!is_array($types)){
2782 + $types = [$types];
2783 + }
2784 +
2785 + $ret = [];
2786 +
2787 + // Loop thru all shortcodes
2788 + foreach($pagelayer->shortcodes as $tag => $vvv){
2789 +
2790 + // Lets create the CSS, Classes, Attr. Also clean the dependent atts
2791 + foreach($pagelayer->tabs as $tab){
2792 +
2793 + if(empty($pagelayer->shortcodes[$tag][$tab])){
2794 + continue;
2795 + }
2796 +
2797 + foreach($pagelayer->shortcodes[$tag][$tab] as $section => $Lsection){
2798 +
2799 + $props = empty($pagelayer->shortcodes[$tag][$section]) ? @$pagelayer->styles[$section] : @$pagelayer->shortcodes[$tag][$section];
2800 +
2801 + //echo $tab.' - '.$section.' - <br>';
2802 +
2803 + if(empty($props)){
2804 + continue;
2805 + }
2806 +
2807 + // Loop all props
2808 + foreach($props as $prop => $param){
2809 +
2810 + // Load any attachment values
2811 + if(!in_array($param['type'], $types)){
2812 + continue;
2813 + }
2814 +
2815 + $ret[$tag][$prop] = $param['type'];
2816 +
2817 + }
2818 +
2819 + }
2820 +
2821 + }
2822 +
2823 + }
2824 +
2825 + //r_print($ret);die();
2826 +
2827 + return $ret;
2828 +
2829 +}
2830 +
2831 +function pagelayer_export_content($content){
2832 +
2833 + global $pagelayer;
2834 +
2835 + // Just call do_shortcode so we can get list of media files to export
2836 + //do_shortcode($content);
2837 +
2838 + $theme_url = preg_replace('/http(s?):\/\//is', '', get_stylesheet_directory_uri());
2839 +
2840 + $content = preg_replace('/http(s?):\/\/'.preg_quote($theme_url, '/').'/is', '{{theme_url}}', $content);
2841 +
2842 + // Remove unnecessary spaces
2843 + $content = preg_replace('/--\>\s*(?!<!--)/is', '-->', $content);
2844 +
2845 + // Replace links of the theme for images
2846 + $content = pagelayer_export_theme_links($content, get_stylesheet_directory_uri());
2847 +
2848 + ////////////////////
2849 + // Handle Link IDs
2850 + ////////////////////
2851 +
2852 + if(empty($pagelayer->e['link_tags'])){
2853 + $pagelayer->e['link_tags'] = pagelayer_get_prop_type('link');
2854 + //r_print($pagelayer->e['link_tags']);die();
2855 + }
2856 +
2857 + if(empty($pagelayer->e['media_tags'])){
2858 + $pagelayer->e['media_tags'] = pagelayer_get_prop_type(['image', 'video', 'audio', 'media', 'multi_image']);
2859 + //r_print($pagelayer->e['media_tags']);die();
2860 + }
2861 +
2862 + $parsed = parse_blocks($content);
2863 + //r_print($parsed);//die();
2864 +
2865 + $parsed = pagelayer_export_link_ids($parsed);
2866 +
2867 + // Export the media as well
2868 + $parsed = pagelayer_export_media($parsed);
2869 +
2870 + // Reserialize
2871 + $content = serialize_blocks($parsed);
2872 +
2873 + // We store in SP format
2874 + $content = str_replace('<!-- wp:pagelayer', '<!-- sp:pagelayer', $content);
2875 + $content = str_replace('<!-- /wp:pagelayer', '<!-- /sp:pagelayer', $content);
2876 +
2877 + // Just pass the content to
2878 + $content = pagelayer_export_extract_menu_ids($content);
2879 +
2880 + // Apply a filter
2881 + $content = apply_filters('pagelayer_export_content', $content);
2882 +
2883 + return $content;
2884 +
2885 +}
2886 +
2887 +// Export the menu IDs
2888 +function pagelayer_export_extract_menu_ids($content){
2889 +
2890 + global $pagelayer;
2891 +
2892 + // Any Menu ?
2893 + preg_match_all('/\[pl_wp_menu ([^\]]*)nav_list="(\d*)"([^\]]*)\]/is', $content, $matches);
2894 + //r_print($matches);
2895 +
2896 + if(!empty($matches[2])){
2897 +
2898 + foreach($matches[2] as $k => $v){
2899 + $v = (int)$v;
2900 + $pagelayer->export_menus[$v] = $v;
2901 + }
2902 + //r_print($pagelayer->export_menus);
2903 +
2904 + }
2905 +
2906 + // Also for block format
2907 + preg_match_all('/<!--\s+(?P<closer>\/)?sp:pagelayer\/pl_wp_menu\s+(?P<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*+)?}\s+)?(?P<void>\/)?-->/s', $content, $matches);
2908 +
2909 + if(!empty($matches['attrs'])){
2910 +
2911 + foreach($matches['attrs'] as $k => $v){
2912 + preg_match('/nav_list"\s*:\s*"(\d*)"/is', $v, $vmatch);
2913 +
2914 + if(!empty($vmatch[1])){
2915 + $vmatch[1] = (int)$vmatch[1];
2916 + $pagelayer->export_menus[$vmatch[1]] = $vmatch[1];
2917 + //r_print($pagelayer->export_menus);
2918 + }
2919 + }
2920 + }
2921 +
2922 + return $content;
2923 +
2924 +}
2925 +
2926 +function pagelayer_export_link_ids($parsed){
2927 +
2928 + global $pagelayer;
2929 +
2930 + foreach($parsed as $k => $v){
2931 +
2932 + if(!empty($v['innerBlocks'])){
2933 + $parsed[$k]['innerBlocks'] = pagelayer_export_link_ids($v['innerBlocks']);
2934 + }
2935 +
2936 + if(!preg_match('/pagelayer/is', $v['blockName'])){
2937 + continue;
2938 + }
2939 +
2940 + $tag = str_replace('pagelayer/', '', $v['blockName']);
2941 + //echo $tag;//die();
2942 +
2943 + // Is there a tag having a link prop
2944 + if(empty($pagelayer->e['link_tags'][$tag])){
2945 + continue;
2946 + }
2947 + //echo $tag;die();
2948 +
2949 + foreach($pagelayer->e['link_tags'][$tag] as $kk => $vv){
2950 + if(!empty($v['attrs'][$kk]) && is_numeric($v['attrs'][$kk])){
2951 + $linked = get_post($v['attrs'][$kk]);
2952 + if(!empty($linked->post_name)){
2953 + $parsed[$k]['attrs'][$kk] = '||link_id|'.$linked->post_type.'|'.$linked->post_name.'||';
2954 + }
2955 + //echo $tag;echo '-'.$kk;r_print($parsed[$k]['attrs']);die();
2956 + }
2957 + }
2958 +
2959 + }
2960 +
2961 + return $parsed;
2962 +
2963 +}
2964 +
2965 +// Replace theme links with theme_url
2966 +function pagelayer_export_theme_links($content, $link){
2967 +
2968 + global $sitepad;
2969 +
2970 + // Theme URL correction code
2971 + $theme_url = preg_replace('/http(s?):\/\//is', '', $link);
2972 +
2973 + $theme_urls[0] = 'http://'.$theme_url;
2974 + $theme_urls[1] = 'https://'.$theme_url;
2975 + $theme_urls[2] = $theme_url;
2976 + $theme_urls[3] = str_replace('/', '\\/', $theme_urls[0]);
2977 + $theme_urls[4] = str_replace('/', '\\/', $theme_urls[1]);
2978 + $theme_urls[5] = str_replace('/', '\\/', $theme_url);
2979 +
2980 + foreach($theme_urls as $k => $v){
2981 + $content = preg_replace_callback('/'.preg_quote($v, '/').'([^"]*)/is', 'pagelayer_export_theme_links_replacer', $content);
2982 + }
2983 +
2984 + $content = str_ireplace($theme_urls, '{{theme_url}}', $content);
2985 +
2986 + return $content;
2987 +}
2988 +
2989 +// This function is a part of pagelayer_export_theme_links
2990 +function pagelayer_export_theme_links_replacer($matches){
2991 + return '{{theme_url}}'.str_replace('\\/', '/', $matches[1]);
2992 +}
2993 +
2994 +// Export media
2995 +function pagelayer_export_media($parsed){
2996 +
2997 + global $pagelayer;
2998 +
2999 + foreach($parsed as $k => $v){
3000 +
3001 + if(!empty($v['innerBlocks'])){
3002 + $parsed[$k]['innerBlocks'] = pagelayer_export_media($v['innerBlocks']);
3003 + }
3004 +
3005 + if(!preg_match('/pagelayer/is', $v['blockName'])){
3006 + continue;
3007 + }
3008 +
3009 + $tag = str_replace('pagelayer/', '', $v['blockName']);
3010 + //echo $tag;//die();
3011 +
3012 + // Is there a tag having a link prop
3013 + if(empty($pagelayer->e['media_tags'][$tag])){
3014 + continue;
3015 + }
3016 + //echo $tag;die();
3017 +
3018 + foreach($pagelayer->e['media_tags'][$tag] as $kk => $vv){
3019 +
3020 + if(empty($v['attrs'][$kk])){
3021 + continue;
3022 + }
3023 +
3024 + $is_array = 0;
3025 +
3026 + // Is it an array
3027 + if(is_array($v['attrs'][$kk])){
3028 +
3029 + $ids = $v['attrs'][$kk];
3030 + $is_array = 1;
3031 +
3032 + // Is it of the format 1,2,3
3033 + }elseif(preg_match('/^((\d*)(,?))*$/is', $v['attrs'][$kk])){
3034 +
3035 + $ids = pagelayer_maybe_explode(',', $v['attrs'][$kk]);
3036 +
3037 + // Its a number or string
3038 + }else{
3039 +
3040 + // Is it our default image ?
3041 + if(preg_match('/pagelayer-pro\/images\/default-image.png$/is', $v['attrs'][$kk])){
3042 + $parsed[$k]['attrs'][$kk] = '';
3043 + continue;
3044 + }
3045 +
3046 + // It should be a number
3047 + if(!is_numeric($v['attrs'][$kk])){
3048 + continue;
3049 + }
3050 +
3051 + $ids = [$v['attrs'][$kk]];
3052 + }
3053 +
3054 + $ret = [];
3055 +
3056 + foreach($ids as $id){
3057 +
3058 + $file = pagelayer_export_media_files($id, $exp_img_url);
3059 +
3060 + // Did it export ?
3061 + if(empty($file) || !file_exists($file)){
3062 + continue;
3063 + }
3064 +
3065 + $ret[] = $exp_img_url;
3066 +
3067 + }
3068 +
3069 + $parsed[$k]['attrs'][$kk] = $is_array ? $ret : implode(',', $ret);
3070 + //echo $tag;echo '-'.$kk;r_print($parsed[$k]['attrs']);die();
3071 + }
3072 +
3073 + }
3074 +
3075 + return $parsed;
3076 +
3077 +}
3078 +
3079 +// Exports the media to the images folder of the current theme
3080 +function pagelayer_export_media_files($id, &$url = ''){
3081 +
3082 + $theme_dir = get_stylesheet_directory();
3083 + $image_dir = $theme_dir.'/images/';
3084 + @mkdir($image_dir);
3085 +
3086 + // Get the file path
3087 + $file = get_attached_file($id);
3088 +
3089 + if(empty($file) || !file_exists($file)){
3090 + return false;
3091 + }
3092 +
3093 + $dest_file = $image_dir.basename($file);
3094 +
3095 + // Copy the file
3096 + copy($file, $dest_file);
3097 +
3098 + // Replace the text
3099 + $url = '{{theme_url}}/images/'.basename($file);
3100 +
3101 + return $dest_file;
3102 +
3103 + //echo $content;
3104 +}
3105 +
3106 +// Insert a post which is a Pagelayer Post
3107 +function pagelayer_sanitize_content($content){
3108 +
3109 + if(empty($content)){
3110 + return $content;
3111 + }
3112 +
3113 + // Replace Vars
3114 + $template_vars = pagelayer_template_vars();
3115 +
3116 + foreach($template_vars as $key => $val){
3117 + $content = str_replace($key, $val, $content);
3118 + }
3119 +
3120 + if(defined('PAGELAYER_BLOCK_PREFIX') && PAGELAYER_BLOCK_PREFIX == 'wp'){
3121 + $content = str_replace('<!-- sp:pagelayer', '<!-- wp:pagelayer', $content);
3122 + $content = str_replace('<!-- /sp:pagelayer', '<!-- /wp:pagelayer', $content);
3123 + }
3124 +
3125 + return $content;
3126 +}
3127 +
3128 +// Insert a post which is a Pagelayer Post
3129 +function pagelayer_insert_content($post, &$ret){
3130 +
3131 + $post = apply_filters('pagelayer_start_insert_content', $post);
3132 +
3133 + $post['post_content'] = pagelayer_sanitize_content($post['post_content']);
3134 + //pagelayer_print($post);die();
3135 +
3136 + // Add slashes for safe insert
3137 + $post['post_content'] = wp_slash($post['post_content']);
3138 +
3139 + $post = apply_filters('pagelayer_pre_insert_content', $post);
3140 +
3141 + // Now insert / update the post
3142 + $ret = wp_insert_post($post);
3143 +
3144 + // Did we save the post ?
3145 + if(empty($ret) || is_wp_error($ret)){
3146 + return false;
3147 + }
3148 +
3149 + // Convert to pagelayer accessed post
3150 + if(!add_post_meta($ret, 'pagelayer-data', time(), true)){
3151 + update_post_meta($ret, 'pagelayer-data', time());
3152 + }
3153 +
3154 + return $ret;
3155 +
3156 +}
3157 +
3158 +// Gets the list of enabled fonts
3159 +function pagelayer_enabled_icons(){
3160 +
3161 + $stored_icons = get_option('pagelayer_icons_set');
3162 + if(empty($stored_icons)){
3163 + update_option('pagelayer_icons_set', ['font-awesome5']);
3164 + $stored_icons = get_option('pagelayer_icons_set');
3165 + }
3166 +
3167 + return $stored_icons;
3168 +
3169 +}
3170 +
3171 +// Prevent pro activate text for installer
3172 +function pagelayer_install_plugin_complete_actions($install_actions, $api, $plugin_file){
3173 +
3174 + if($plugin_file == PAGELAYER_PREMIUM_BASE){
3175 + return array();
3176 + }
3177 +
3178 + return $install_actions;
3179 +}
3180 +
3181 +// Handle hexa to rgba and also remove alpha which is ff
3182 +function pagelayer_hex8_to_rgba($val){
3183 +
3184 + // If opacity is ff then discard ff
3185 + if(preg_match('/^#([a-f0-9]{6})ff$/is', $val)){
3186 + return substr($val, 0, 7);
3187 + }
3188 +
3189 + // Lets handle the RGB+opacity
3190 + if(preg_match('/#([a-f0-9]{8})$/is', $val)){
3191 + $val = pagelayer_hex2rgba($val);
3192 + }
3193 +
3194 + return $val;
3195 +
3196 +}
3197 +
3198 +// Convert to RGBA from HEX
3199 +function pagelayer_hex2rgba($color){
3200 +
3201 + //Return if no color provided
3202 + if(empty($color)){
3203 + return;
3204 + }
3205 +
3206 + //Sanitize $color if "#" is provided
3207 + if ($color[0] == '#'){
3208 + $color = substr( $color, 1 );
3209 + }
3210 +
3211 + //Check if color has 6 or 3 characters and get values
3212 + if (strlen($color) == 8) {
3213 + $hex = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
3214 + $alpha = $color[6] . $color[7];
3215 + //$alpha = '';
3216 + } elseif (strlen($color) == 6) {
3217 + $hex = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
3218 + } elseif ( strlen( $color ) == 3 ) {
3219 + $hex = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
3220 + } else {
3221 + return;
3222 + }
3223 +
3224 + //Convert hexadec to rgb
3225 + $rgb = array_map('hexdec', $hex);
3226 +
3227 + //Check if opacity is set(rgba or rgb)
3228 + if($alpha){
3229 +
3230 + $alpha = number_format((float)hexdec($alpha) / 255, 2, '.', '');
3231 + //print_r($alpha);
3232 + if(abs($alpha) > 1){
3233 + $alpha = 1.0;
3234 + }
3235 + $output = 'rgba('.implode(",",$rgb).','.$alpha.')';
3236 + } else {
3237 + $output = 'rgb('.implode(",",$rgb).')';
3238 + }
3239 +
3240 + //Return rgb(a) color string
3241 + return $output;
3242 +}
3243 +
3244 +// Get social URLs
3245 +function pagelayer_get_social_urls(){
3246 +
3247 + $urls = array();
3248 +
3249 + $urls['facebook'] = get_option('pagelayer-facebook-url');
3250 + $urls['twitter'] = get_option('pagelayer-twitter-url');
3251 + $urls['instagram'] = get_option('pagelayer-instagram-url');
3252 + $urls['linkedin'] = get_option('pagelayer-linkedin-url');
3253 + $urls['youtube'] = get_option('pagelayer-youtube-url');
3254 + $urls['google'] = get_option('pagelayer-gplus-url');
3255 +
3256 + foreach($urls as $k => $v){
3257 +
3258 + if(empty($v)){
3259 + unset($urls[$k]);
3260 + continue;
3261 + }
3262 +
3263 + $urls[$k] = esc_url($v);
3264 + }
3265 +
3266 + return $urls;
3267 +}
3268 +
3269 +function pagelayer_get_option($opt){
3270 + $ret = get_option($opt);
3271 +
3272 + $opts = array(
3273 + 'pagelayer-address' => '1, My Address, My Street, New York City, NY, USA',
3274 + 'pagelayer-phone' => '+1234567890',
3275 + 'pagelayer-copyright' => '© '.date('Y').' '.get_option('blogname'),
3276 + 'pagelayer_cf_to_email' => 'contact@domain.com',
3277 + 'pagelayer_cf_success' => __pl('cf_success'),
3278 + 'pagelayer_cf_failed' => __pl('cf_failed'),
3279 + );
3280 +
3281 + if(empty($ret)){
3282 + return $opts[$opt];
3283 + }
3284 +
3285 + return wp_kses_post($ret);
3286 +}
3287 +
3288 +// Uploads an image / media
3289 +function pagelayer_upload_media($filename, $blob){
3290 +
3291 + if(empty($blob)){
3292 + return false;
3293 + }
3294 +
3295 + $md5 = md5($blob);
3296 +
3297 + // Do we have this image
3298 + $args = array(
3299 + 'post_type' => 'attachment',
3300 + 'post_status' => 'inherit',
3301 + 'meta_query' => array(
3302 + array(
3303 + 'key' => 'pagelayer_image_md5',
3304 + 'value' => $md5,
3305 + )
3306 + )
3307 + );
3308 +
3309 + $query = new WP_Query($args);
3310 +
3311 + // If we found the image, return
3312 + foreach($query->posts as $ck => $cv){
3313 + return $cv->ID;
3314 + }
3315 +
3316 + $upload = wp_upload_bits($filename, null, $blob);
3317 +
3318 + if( !empty( $upload['error'] ) ) {
3319 + return false;
3320 + }
3321 +
3322 + $file_path = $upload['file'];
3323 + $file_name = basename( $file_path );
3324 + $file_type = wp_check_filetype( $file_name, null );
3325 + $attachment_title = sanitize_file_name( pathinfo( $file_name, PATHINFO_FILENAME ) );
3326 + $wp_upload_dir = wp_upload_dir();
3327 +
3328 + $post_info = array(
3329 + 'guid' => $wp_upload_dir['url'] . '/' . $file_name,
3330 + 'post_mime_type'=> $file_type['type'],
3331 + 'post_title' => $attachment_title,
3332 + 'post_content' => '',
3333 + 'post_status' => 'inherit',
3334 + );
3335 +
3336 + $attach_id = wp_insert_attachment( $post_info, $file_path, $parent_post_id );
3337 + update_post_meta($attach_id, 'pagelayer_image_md5', $md5);
3338 +
3339 + $lib = ABSPATH . 'site-admin/includes/image.php';
3340 + $media = ABSPATH . 'site-admin/includes/media.php';
3341 + $media = file_exists($media) ? $media : ABSPATH . 'wp-admin/includes/media.php';
3342 + $lib = file_exists($lib) ? $lib : ABSPATH . 'wp-admin/includes/image.php';
3343 +
3344 + require_once($media);
3345 + require_once($lib);
3346 +
3347 + $attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
3348 + wp_update_attachment_metadata( $attach_id, $attach_data );
3349 +
3350 + return $attach_id;
3351 +
3352 +}
3353 +
3354 +// Show the notice of importing the active themes content
3355 +function pagelayer_theme_import_notices($return = false){
3356 +
3357 + $theme = wp_get_theme();
3358 +
3359 + $imported = get_option('pagelayer_theme_'.get_template().'_imported');
3360 + $show = 0;
3361 +
3362 + // We need to import the content
3363 + if(empty($imported) && is_admin() && current_user_can('switch_themes')){
3364 + $show = 1;
3365 + }
3366 +
3367 + $dismissed = get_option('pagelayer_theme_'.get_template().'_dismissed');
3368 +
3369 + // Is this dismissed
3370 + if($dismissed){
3371 + $show = 0;
3372 + }
3373 +
3374 + //$show = 1;
3375 +
3376 + // Is it the importer page ?
3377 + if(!empty($_REQUEST['page']) && $_REQUEST['page'] == 'pagelayer_import'){
3378 + $show = 0;
3379 + }
3380 +
3381 + // Show the message
3382 + if(!empty($show)){
3383 + $str = '
3384 +
3385 +<style>
3386 +.pagelayer_promo_button {
3387 +background-color: #4CAF50; /* Green */
3388 +border: none;
3389 +color: white;
3390 +padding: 6px 10px;
3391 +text-align: center;
3392 +text-decoration: none;
3393 +display: inline-block;
3394 +font-size: 13px;
3395 +margin: 4px 2px;
3396 +-webkit-transition-duration: 0.4s; /* Safari */
3397 +transition-duration: 0.4s;
3398 +cursor: pointer;
3399 +}
3400 +.pagelayer_promo_button:focus,
3401 +.pagelayer_promo_button:hover{
3402 +border: none;
3403 +color: white;
3404 +box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
3405 +color: white;
3406 +}
3407 +.pagelayer_promo_buy {
3408 +color: white;
3409 +padding: 8px 12px;
3410 +font-size: 14px;
3411 +}
3412 +.pagelayer_promo_button1 {
3413 +color: white;
3414 +background-color: #4CAF50;
3415 +border:3px solid #4CAF50;
3416 +}
3417 +.pagelayer_promo_button1:hover {
3418 +border:3px solid #4CAF50;
3419 +}
3420 +.pagelayer_promo_button2 {
3421 +color: white;
3422 +background-color: #0085ba;
3423 +}
3424 +.pagelayer_promo_button3 {
3425 +color: white;
3426 +background-color: #365899;
3427 +}
3428 +.pagelayer_promo_button4 {
3429 +color: white;
3430 +background-color: rgb(66, 184, 221);
3431 +}
3432 +.pagelayer_promo-close{
3433 +float:right;
3434 +text-decoration:none;
3435 +margin: 5px 10px 0px 0px;
3436 +}
3437 +.pagelayer_promo-close:hover{
3438 +color: red;
3439 +}
3440 +</style>
3441 +
3442 +<script type="application/javascript">
3443 + jQuery(document).ready(function(){
3444 + jQuery("#pagelayer_promo .pagelayer_promo-close").click(function(){
3445 + var data;
3446 + jQuery("#pagelayer_promo").hide();
3447 + // Save this preference
3448 + jQuery.post("'.admin_url('?pagelayer_promo=0').'", data, function(response) {
3449 + //alert(response);
3450 + });
3451 + });
3452 + });
3453 +</script>
3454 +
3455 +<div class="notice notice-success" id="pagelayer_promo" style="min-height:30px">
3456 + <a class="pagelayer_promo-close" href="javascript:" aria-label="Dismiss this Notice">
3457 + <span class="dashicons dashicons-dismiss"></span> Dismiss
3458 + </a>';
3459 +
3460 + $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>').'
3461 +
3462 +</div>';
3463 +
3464 + // Print it
3465 + if(empty($return)){
3466 + echo $str;
3467 + }else{
3468 + return $str;
3469 + }
3470 + }
3471 +
3472 +}
3473 +
3474 +// Parse the array variables
3475 +function pagelayer_replace_vars( $string, $array, $pre = '', $suf = ''){
3476 +
3477 + $array = (array) $array;
3478 +
3479 + foreach($array as $kk => $vv){
3480 +
3481 + if(is_array($vv)){
3482 + $vv = pagelayer_flat_join($vv);
3483 + }
3484 +
3485 + $string = str_replace($pre.$kk.$suf, $vv, $string);
3486 + }
3487 + return $string;
3488 +}
3489 +
3490 +// Add Attachment to the contact the email
3491 +function pagelayer_cf_email_attachment( &$phpmailer) {
3492 +
3493 + if ( ! empty( $_FILES ) ) {
3494 + foreach ( $_FILES as $attachment ) {
3495 +
3496 + if(empty($attachment['name'])){
3497 + continue;
3498 + }
3499 +
3500 + try {
3501 + $phpmailer->addAttachment($attachment['tmp_name'], $attachment['name'], $encoding = 'base64', $attachment['type'], $disposition = 'attachment');
3502 + } catch ( \Exception $e ) {
3503 + continue;
3504 + }
3505 + }
3506 + }
3507 +
3508 +}
3509 +
3510 +function pagelayer_array_flatten( $input ) {
3511 + if ( ! is_array( $input ) ) {
3512 + return array( $input );
3513 + }
3514 +
3515 + $output = array();
3516 +
3517 + foreach ( $input as $value ) {
3518 + $output = array_merge( $output, pagelayer_array_flatten( $value ) );
3519 + }
3520 +
3521 + return $output;
3522 +}
3523 +
3524 +function pagelayer_flat_join( $array ) {
3525 + $array = pagelayer_array_flatten( $array );
3526 + $output = array();
3527 +
3528 + foreach ( (array) $array as $value ) {
3529 + $output[] = trim( (string) $value );
3530 + }
3531 +
3532 + return implode( ', ', $output );
3533 +}
3534 +
3535 +// Verifies the Google Captcha
3536 +function pagelayer_captcha_verify(){
3537 +
3538 + // If secret key is not there, return
3539 + $captcha_secret = get_option('pagelayer_google_captcha_secret');
3540 +
3541 + if(empty($captcha_secret)){
3542 + return true;
3543 + }
3544 +
3545 + $response = !empty($_POST['g-recaptcha-response']) ? sanitize_text_field($_POST['g-recaptcha-response']) : '';
3546 +
3547 + $ip = pagelayer_getip();
3548 +
3549 + // Is the IP or response not there ?
3550 + if(empty($response) || empty($ip)){
3551 + return false;
3552 + }
3553 +
3554 + $url = 'https://www.google.com/recaptcha/api/siteverify';
3555 +
3556 + // Verify the post
3557 + $req = wp_remote_post($url, array(
3558 + 'timeout' => 20,
3559 + 'body' => array(
3560 + 'secret' => $captcha_secret,
3561 + 'response' => $response,
3562 + 'remoteip' => $ip
3563 + )
3564 + )
3565 + );
3566 +
3567 + // Was there an error posting ?
3568 + if(is_wp_error($req)){
3569 + return false;
3570 + }
3571 +
3572 + // Process the post response
3573 + $resp = wp_remote_retrieve_body($req);
3574 +
3575 + // Is the body valid
3576 + if(empty($resp)){
3577 + return false;
3578 + }
3579 +
3580 + $json = json_decode($resp, true);
3581 +
3582 + if(!empty($json['success']) && // for v2 and v3
3583 + (!isset($json['score']) || $json['score'] >= 0.5 && $json['action'] === 'submit') // For v3
3584 + ){
3585 + return true;
3586 + }
3587 +
3588 + return false;
3589 +}
3590 +
3591 +// Pagelayer serialize attributes
3592 +function pagelayer_serialize_attributes( $block_attributes ) {
3593 + $encoded_attributes = json_encode( $block_attributes, JSON_FORCE_OBJECT);
3594 + $encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes );
3595 + $encoded_attributes = preg_replace( '/</', '\\u003c', $encoded_attributes );
3596 + $encoded_attributes = preg_replace( '/>/', '\\u003e', $encoded_attributes );
3597 + // Regex: /\\"/
3598 + $encoded_attributes = preg_replace( '/\\\\"/', '\\u0022', $encoded_attributes );
3599 +
3600 + return $encoded_attributes;
3601 +}
3602 +
3603 +function pagelayer_enable_giver(){
3604 + global $pagelayer;
3605 + return !empty($pagelayer->settings['enable_giver']) && $pagelayer->settings['enable_giver'] == 1;
3606 +}
3607 +
3608 +function pagelayer_load_font_options(){
3609 + include_once(PAGELAYER_DIR.'/main/font-options.php');
3610 +}
3611 +
3612 +function pagelayer_is_utf8($str) {
3613 + return (bool) preg_match('//u', $str);
3614 +}
3615 +
3616 +// Create blank images
3617 +function pagelayer_create_blank_image($width, $height){
3618 +
3619 + $im = @imagecreate($width, $height);
3620 +
3621 + if(empty($im)){
3622 + return false;
3623 + }
3624 +
3625 + $background_color = imagecolorallocate($im, 220, 220, 220);
3626 + $text_color = imagecolorallocate($im, 110, 110, 110);
3627 + $string = $width.' x '.$height;
3628 + $font_size = 30;
3629 + $sx = ($width / 2) - (strlen($string) * $font_size / 2);
3630 + $sy = ($height / 2) - ($font_size / 2);
3631 + $font = realpath(PAGELAYER_DIR.'/fonts/OpenSans-BoldItalic.ttf');
3632 + imagettftext($im, $font_size, 0, $sx, $sy, $text_color, $font, $string);
3633 + ob_start();
3634 + imagepng($im);
3635 + imagedestroy($im);
3636 +
3637 + return ob_get_clean();
3638 +
3639 +}
3640 +
3641 +// Get category name by post type
3642 +function pagelayer_post_type_category($post_type){
3643 +
3644 + $taxonomies = get_object_taxonomies( $post_type, 'objects');
3645 +
3646 + foreach( $taxonomies as $key => $tax){
3647 + if(!empty($tax->hierarchical)){
3648 + return $key;
3649 + }
3650 + }
3651 +
3652 + return false;
3653 +
3654 +}
3655 +
3656 +// Get tag name by post type
3657 +function pagelayer_post_type_tag($post_type){
3658 +
3659 + $taxonomies = get_object_taxonomies( $post_type, 'objects');
3660 +
3661 + foreach( $taxonomies as $key => $tax){
3662 + if(!empty($tax->show_tagcloud) && empty($tax->hierarchical)){
3663 + return $key;
3664 + }
3665 + }
3666 + return false;
3667 +
3668 +}
3669 +
3670 +// Get checkboxes of post categories.
3671 +function pagelayer_post_cats($post, &$cat_name = ''){
3672 +
3673 + $ret = [];
3674 +
3675 + $cat_name = pagelayer_post_type_category($post->post_type);
3676 +
3677 + if(empty($cat_name)){
3678 + return $ret;
3679 + }
3680 +
3681 + include_once(ABSPATH.PAGELAYER_CMS_DIR_PREFIX.'-admin/includes/template.php');
3682 +
3683 + $args1 = array(
3684 + 'taxonomy' => $cat_name,
3685 + 'checked_ontop' => false,
3686 + 'echo' => false,
3687 + );
3688 +
3689 + $ret['with_checkbox'] = '<ul class="pagelayer-post-category" >'.wp_terms_checklist($post->ID, $args1 ).'</ul>';
3690 +
3691 + $args2 = array(
3692 + 'taxonomy' => $cat_name,
3693 + 'hierarchical' => true,
3694 + 'echo' => 0,
3695 + 'class' => 'pagelayer-add-cat',
3696 + 'name' => 'pagelayer_cat_parent',
3697 + 'style' => 'list',
3698 + 'hide_empty' => 0,
3699 + );
3700 +
3701 + $ret['without_checkbox'] = wp_dropdown_categories( $args2 );
3702 +
3703 + return $ret;
3704 +
3705 +}
3706 +
3707 +// Get checkboxes of post tags.
3708 +function pagelayer_post_tags($post, &$tag_name = ''){
3709 +
3710 + $ret = [];
3711 +
3712 + $tag_name = pagelayer_post_type_tag($post->post_type);
3713 +
3714 + if(empty($tag_name)){
3715 + return $ret;
3716 + }
3717 +
3718 + $ret['postTags'] = wp_get_post_terms( $post->ID, $tag_name );
3719 +
3720 + $ret['allTags'] = get_tags(array( 'hide_empty' => false, 'taxonomy' => $tag_name ));
3721 +
3722 + return $ret;
3723 +
3724 +}
3725 +
3726 +// Get users who can edit a particular post type
3727 +function pagelayer_post_authors_by_type($post_type){
3728 +
3729 + global $wp_post_types;
3730 +
3731 + if(empty($wp_post_types[$post_type])){
3732 + $users = get_users( array( 'role__in' => array( 'administrator' ) ) );
3733 + }else{
3734 + $req_role = $wp_post_types[$post_type]->cap->edit_posts;
3735 + $roles__in = [];
3736 + foreach( wp_roles()->roles as $role_slug => $role ){
3737 + if( ! empty( $role['capabilities'][$req_role] ) )
3738 + $roles__in[] = $role_slug;
3739 + }
3740 + $users = get_users( array( 'role__in' => $roles__in ) );
3741 + }
3742 +
3743 + $user_array = [];
3744 +
3745 + foreach ( $users as $user ) {
3746 + $user_array[$user->ID] = $user->display_name;
3747 + }
3748 +
3749 + return $user_array;
3750 +}
3751 +
3752 +function pagelayer_parent_post_prop($post){
3753 + global $wp_post_types;
3754 +
3755 + if(!empty($wp_post_types[$post->post_type]->hierarchical)){
3756 + return pagelayer_list_parents(0, 0, $post, []);
3757 + }else{
3758 + return [];
3759 + }
3760 +}
3761 +
3762 +function pagelayer_list_parents( $parent = 0, $level = 0, $post = null, $values=array('')){
3763 +
3764 + global $wpdb;
3765 +
3766 + $post = get_post( $post );
3767 +
3768 + $items = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_parent, post_title FROM $wpdb->posts
3769 + WHERE post_parent = %d
3770 + AND post_type = '".$post->post_type."'
3771 + AND post_status = 'publish'
3772 + ORDER BY menu_order", $parent ) );
3773 +
3774 + if ( !empty($items) ) {
3775 + foreach ( $items as $item ) {
3776 +
3777 + // A page cannot be its own parent.
3778 + if ( $post && $post->ID && (int) $item->ID === $post->ID ) {
3779 + continue;
3780 + }
3781 +
3782 + $pad = str_repeat( '-', $level );
3783 +
3784 + if(count($values)==0){
3785 + $values[] = '';
3786 + }
3787 +
3788 + $values[' '.$item->ID] = $pad.esc_html( $item->post_title );
3789 +
3790 + $values = pagelayer_list_parents($item->ID, $level + 1, $post, $values );
3791 + }
3792 + }
3793 +
3794 + return $values;
3795 +}
3796 +
3797 +// Maybe explode
3798 +function pagelayer_maybe_explode( $separator = ',', $string = '', $limit = PHP_INT_MAX ){
3799 +
3800 + if(is_array($string)){
3801 + return $string;
3802 + }
3803 +
3804 + return explode($separator, $string, $limit);
3805 +}
3806 +
3807 +// Maybe implode
3808 +function pagelayer_maybe_implode($array, $separator = ','){
3809 +
3810 + if(is_array($array)){
3811 + return @implode($separator, $array);
3812 + }
3813 +
3814 + if(is_null($array)){
3815 + return '';
3816 + }
3817 +
3818 + return $array;
3819 +
3820 +}
3821 +
3822 +// Sanitize text field or array
3823 +function pagelayer_sanitize_text_field($str) {
3824 +
3825 + if ( !is_object( $str ) && !is_array( $str ) ) {
3826 + return sanitize_text_field($str);
3827 + }
3828 +
3829 + if( is_array($str) ){
3830 + return array_map( 'pagelayer_sanitize_text_field', $str);
3831 + }
3832 +
3833 + return $str;
3834 +}
3835 +
3836 +// Sanitize posts data for WP_Query
3837 +function pagelayer_sanitize_posts_data($data, $only_allowed = true) {
3838 +
3839 + $allowed_keys = [
3840 + 'post_type', 'posts_per_page', 'order', 'orderby', 'paged',
3841 + 'filter_by', 'term', 'exc_term', 'cat', 'category_name',
3842 + 'tag', 'author', 'author_name', 'post__in', 'post__not_in',
3843 + 'include', 'exclude', 'search', 's', 'exact', 'sentence',
3844 + 'post_status', 'post_parent', 'offset',
3845 + 'posts_per_archive_page', 'page', 'ignore_sticky_posts'
3846 + ];
3847 +
3848 + $sanitized = [];
3849 +
3850 + foreach($data as $key => $value){
3851 + if($only_allowed && !in_array($key, $allowed_keys)) {
3852 + continue;
3853 + }
3854 +
3855 + $sanitized[$key] = pagelayer_sanitize_text_field($value);
3856 + }
3857 +
3858 + // Security: Restrict post_status to prevent information disclosure
3859 + // Only users who can read private posts or edit others' posts should be able to query non-public statuses
3860 + if(isset($sanitized['post_status'])){
3861 + $requested_status = $sanitized['post_status'];
3862 +
3863 + // If requesting something other than publish, verify permissions
3864 + if ($requested_status !== 'publish') {
3865 + // Check if the user has permission to read private posts or edit others' posts
3866 + // This prevents contributors from seeing titles of private posts they don't own.
3867 + if (!current_user_can('read_private_posts') && !current_user_can('edit_others_posts')) {
3868 + $sanitized['post_status'] = 'publish';
3869 + }
3870 + }
3871 + }else{
3872 + // Default to publish for safety if not specified
3873 + $sanitized['post_status'] = 'publish';
3874 + }
3875 +
3876 + if(isset($sanitized['posts_per_page'])){
3877 + $sanitized['posts_per_page'] = (int) $sanitized['posts_per_page'];
3878 + if ($sanitized['posts_per_page'] > 100) {
3879 + $sanitized['posts_per_page'] = 100;
3880 + }
3881 + }
3882 +
3883 + if(isset($sanitized['paged'])){
3884 + $sanitized['paged'] = (int) $sanitized['paged'];
3885 + }
3886 +
3887 + if(isset($sanitized['offset'])){
3888 + $sanitized['offset'] = (int) $sanitized['offset'];
3889 + }
3890 +
3891 + if(isset($sanitized['post__in']) && is_string($sanitized['post__in'])){
3892 + $sanitized['post__in'] = array_map('intval', explode(',', $sanitized['post__in']));
3893 + }
3894 +
3895 + if(isset($sanitized['post__not_in']) && is_string($sanitized['post__not_in'])){
3896 + $sanitized['post__not_in'] = array_map('intval', explode(',', $sanitized['post__not_in']));
3897 + }
3898 +
3899 + if(isset($sanitized['post_parent'])){
3900 + $sanitized['post_parent'] = (int) $sanitized['post_parent'];
3901 + }
3902 +
3903 + if(isset($sanitized['cat'])){
3904 + $sanitized['cat'] = (int) $sanitized['cat'];
3905 + }
3906 +
3907 + if(isset($sanitized['author'])){
3908 + $sanitized['author'] = (int) $sanitized['author'];
3909 + }
3910 +
3911 + return $sanitized;
3912 +}
3913 +
3914 +// Update nav menu item
3915 +function pagelayer_save_nav_menu_items($items){
3916 +
3917 + // Menu setting keys
3918 + $allowed_post = array('title' => 'post_title');
3919 + $allowed_meta = array('_pagelayer_content');
3920 +
3921 + foreach($items as $id => $values){
3922 +
3923 + $meta_input = array();
3924 + $id = (int) $id;
3925 + $post = get_post($id);
3926 +
3927 + // Post found ?
3928 + if(empty($post)){
3929 + continue;
3930 + }
3931 +
3932 + foreach($values as $kk => $vv){
3933 +
3934 + if(array_key_exists($kk, $allowed_post)){
3935 + $name = $allowed_post[$kk];
3936 + $post->$name = $vv;
3937 + }
3938 +
3939 + if(!in_array($kk, $allowed_meta)){
3940 + continue;
3941 + }
3942 +
3943 + $meta_input[$kk] = stripslashes_deep($vv);
3944 + }
3945 +
3946 + if(isset($meta_input['_pagelayer_content'])){
3947 + $meta_input['_pagelayer_content'] = base64_decode($meta_input['_pagelayer_content']);
3948 + }
3949 +
3950 + $post->meta_input = $meta_input;
3951 + wp_update_post($post);
3952 + }
3953 +}
3954 +
3955 +// Update customizer options
3956 +function pagelayer_save_customizer_options($customizer_options){
3957 + global $pagelayer;
3958 +
3959 + // To load customizer params array
3960 + if(empty($pagelayer->customizer_params)){
3961 + pagelayer_load_shortcodes();
3962 + }
3963 +
3964 + $customizer_options = apply_filters( 'pagelayer_save_customizer_options', $customizer_options );
3965 + $customizer_data = array();
3966 + $customizer_option_data = array();
3967 +
3968 + foreach($pagelayer->customizer_params as $ck => $cv){
3969 + foreach($pagelayer->screens as $sk => $sv){
3970 +
3971 + $screen = (!empty($sv) ? '_'.$sv : '');
3972 + $screen_key = $ck.$screen;
3973 +
3974 + // Save to pagelayer customizer mods
3975 + if( empty($cv['option']) ){
3976 + if( isset($customizer_options[$screen_key])){
3977 + $customizer_data[$screen_key] = $customizer_options[$screen_key];
3978 + }
3979 + continue;
3980 + }
3981 +
3982 + $option_key = $cv['option'].$screen;
3983 +
3984 + // Update option
3985 + if( isset($customizer_options[$screen_key] ) ) {
3986 + update_option( $option_key, $customizer_options[$screen_key]);
3987 + continue;
3988 + }
3989 +
3990 + delete_option($option_key);
3991 + }
3992 + }
3993 +
3994 + // Set Typography settings for global and current post type
3995 + $posttype=array(
3996 + '' => '', // Make this empty for global values
3997 + 'current' => $customizer_options['pagelayer_current_post_type']
3998 + );
3999 +
4000 + $typo = ['font-family', 'font-size', 'font-style', 'font-weight', 'font-variant', 'decoration-line', 'line-height', 'text-transform', 'text-spacing', 'word-spacing'];
4001 +
4002 + foreach($posttype as $type => $tv){
4003 +
4004 + foreach($pagelayer->css_settings as $set => $params){
4005 +
4006 + foreach($pagelayer->screens as $sk => $sv){
4007 +
4008 + $screen = (!empty($sv) ? '_'.$sv : '');
4009 + $post_type = (!empty($tv) ? '_'.$tv : '');
4010 + $post_key = (!empty($type) ? $type.'_' : '');
4011 + $post_key_set = $post_key.$set;
4012 +
4013 + // Create key as per customizer shortcode
4014 + $key = $post_key_set.$screen;
4015 +
4016 + // Create option keys for the global and current post type
4017 + $option_setting = empty($params['key']) ? 'pagelayer_'.$set.'_css'.$post_type : $params['key'].$post_type;
4018 +
4019 + $props = array(
4020 + 'color' => $post_key_set.'_color'.$screen,
4021 + 'padding' => $post_key_set.'_padding'.$screen,
4022 + 'margin' => $post_key_set.'_margin'.$screen,
4023 + 'background-color' => $post_key_set.'_background_color'.$screen,
4024 + );
4025 +
4026 + $globalsetting = array();
4027 +
4028 + // Set Typography
4029 + if(isset($customizer_options[$key])){
4030 + foreach($customizer_options[$key] as $k => $v){
4031 + if($v == 'Default' || empty($v)){
4032 + unset($customizer_options[$key][$k]);
4033 + }
4034 +
4035 + // For sidebar, width default should not be saved
4036 + if($set == 'sidebar' && $k == 'width' && $v == 20){
4037 + unset($customizer_options[$key][$k]);
4038 + }
4039 +
4040 + $globalsetting[$key][$typo[$k]] = $customizer_options[$key][$k];
4041 + unset($customizer_options[$key][$k]);
4042 + }
4043 + }
4044 +
4045 + // Set other props with typography
4046 + foreach($props as $pk => $pv){
4047 +
4048 + if(!isset($customizer_options[$pv])){
4049 + continue;
4050 + }
4051 +
4052 + $globalsetting[$key][$pk] = $customizer_options[$pv];
4053 + unset($customizer_options[$pv]);
4054 +
4055 + }
4056 +
4057 + // Are we to save ?
4058 + if(!empty($globalsetting[$key])){
4059 + update_option($option_setting.$screen, $globalsetting[$key]);
4060 + }else{
4061 + delete_option($option_setting.$screen);
4062 + }
4063 +
4064 + }
4065 +
4066 + }
4067 + }
4068 +
4069 + $customizer_data = apply_filters( 'pagelayer_customizer_options', $customizer_data, $customizer_options);
4070 +
4071 + update_option('pagelayer_customizer_mods', $customizer_data);
4072 +}
4073 +
4074 +// Get customizer options values
4075 +// return array to set customizer block attributes
4076 +function pagelayer_get_customizer_options(){
4077 + global $pagelayer, $post;
4078 +
4079 + $options = array();
4080 +
4081 + // To load customizer params array
4082 + if(empty($pagelayer->customizer_params)){
4083 + pagelayer_load_shortcodes();
4084 + }
4085 +
4086 + // Get values form options
4087 + foreach($pagelayer->customizer_params as $ck => $cv){
4088 +
4089 + if( empty($cv['option']) ){
4090 + continue;
4091 + }
4092 +
4093 + $screens = array('desktop' => '');
4094 +
4095 + if( !empty($cv['screen']) ){
4096 + $screens = $pagelayer->screens;
4097 + }
4098 +
4099 + foreach($screens as $sk => $sv){
4100 +
4101 + $screen = (!empty($sv) ? '_'.$sv : '');
4102 + $screen_key = $cv['option'].$screen;
4103 + $screen_ck = $ck.$screen;
4104 +
4105 + // Get option value
4106 + $c_option = get_option($screen_key);
4107 +
4108 + if(empty($c_option)){
4109 + continue;
4110 + }
4111 +
4112 + $options[$screen_ck] = $c_option;
4113 + }
4114 + }
4115 +
4116 +
4117 + // Get values from pagelayer mods
4118 + $mods = get_option('pagelayer_customizer_mods');
4119 +
4120 + if(!empty($mods)){
4121 + $options = array_merge($options, $mods);
4122 + }
4123 +
4124 + $posttype=array(
4125 + '' => '',
4126 + 'current' => $post->post_type
4127 + );
4128 +
4129 + $typo = ['font-family', 'font-size', 'font-style', 'font-weight', 'font-variant', 'decoration-line', 'line-height', 'text-transform', 'text-spacing', 'word-spacing'];
4130 +
4131 + foreach($posttype as $type => $tv){
4132 +
4133 + foreach($pagelayer->css_settings as $set => $params){
4134 +
4135 + foreach($pagelayer->screens as $sk => $sv){
4136 +
4137 + $screen = (!empty($sv) ? '_'.$sv : '');
4138 + $postprefix = (!empty($tv) ? '_'.$tv : '');
4139 + $postk = (!empty($type) ? $type.'_' : '');
4140 + $post_key_set = $postk.$set;
4141 +
4142 + // Create key as per customizer shortcode
4143 + $key = $post_key_set.$screen;
4144 +
4145 + // Create option keys for the global and current post type
4146 + $setting = empty($params['key']) ? 'pagelayer_'.$set.'_css'.$postprefix : $params['key'].$postprefix;
4147 +
4148 + $props = array(
4149 + 'color' => $post_key_set.'_color'.$screen,
4150 + 'padding' => $post_key_set.'_padding'.$screen,
4151 + 'margin' => $post_key_set.'_margin'.$screen,
4152 + 'background-color' => $post_key_set.'_background_color'.$screen,
4153 + );
4154 +
4155 + $optarray = get_option($setting.$screen);
4156 +
4157 + if(!empty($optarray)){
4158 +
4159 + // Get Typography
4160 + foreach($typo as $tk => $tv){
4161 +
4162 + $tval = '';
4163 +
4164 + if(isset($optarray[$tv])){
4165 + $tval = $optarray[$tv];
4166 + }
4167 +
4168 + $options[$key][$tk] = $tval;
4169 + }
4170 +
4171 + foreach($props as $pk => $pv){
4172 + if(empty( $optarray[$pk])){
4173 + continue;
4174 + }
4175 +
4176 + $options[$pv] = $optarray[$pk];
4177 + }
4178 + }
4179 + }
4180 + }
4181 + }
4182 +
4183 + $options = apply_filters( 'pagelayer_get_customizer_options', $options);
4184 +
4185 + return $options;
4186 +}
4187 +
4188 +// Sanitize style props for colors and fons
4189 +function pagelayer_load_global_palette(){
4190 + global $pagelayer;
4191 +
4192 + // Default global colors
4193 + $pagelayer->global_colors = array(
4194 + 'primary' => array(
4195 + 'title' => 'Primary',
4196 + 'value' => '#007bff',
4197 + ),
4198 + 'secondary' => array(
4199 + 'title' => 'Secondary',
4200 + 'value' => '#6c757d',
4201 + ),
4202 + 'text' => array(
4203 + 'title' => 'Text',
4204 + 'value' => '#1d1d1d',
4205 + ),
4206 + 'accent' => array(
4207 + 'title' => 'Accent',
4208 + 'value' => '#61ce70',
4209 + ),
4210 + );
4211 +
4212 + // Global color
4213 + $global_color = get_option('pagelayer_global_colors');
4214 +
4215 + if(!empty($global_color)){
4216 + $pagelayer->global_colors = json_decode($global_color, true);
4217 + }
4218 +
4219 + // Default global fonts
4220 + $pagelayer->global_fonts = array(
4221 + 'primary' => array(
4222 + 'title' => 'Primary',
4223 + 'value' => $pagelayer->default_font_styles(),
4224 + ),
4225 + 'secondary' => array(
4226 + 'title' => 'Secondary',
4227 + 'value' => $pagelayer->default_font_styles(array('font-family' => 'Roboto')),
4228 + ),
4229 + 'text' => array(
4230 + 'title' => 'Text',
4231 + 'value' => $pagelayer->default_font_styles(array('font-family' => 'Montserrat')),
4232 + ),
4233 + 'accent' => array(
4234 + 'title' => 'Accent',
4235 + 'value' => $pagelayer->default_font_styles(array('font-family' => 'Poppins')),
4236 + ),
4237 + );
4238 +
4239 + // Global font
4240 + $global_font = get_option('pagelayer_global_fonts');
4241 +
4242 + if(!empty($global_font)){
4243 + $pagelayer->global_fonts = json_decode($global_font, true);
4244 + }
4245 +}
4246 +
4247 +// Get global colors
4248 +function pagelayer_sanitize_global_color($val){
4249 + global $pagelayer;
4250 +
4251 + if(!is_string($val) || $val[0] != '$'){
4252 + return $val;
4253 + }
4254 +
4255 + $gkey = substr($val, 1);
4256 + $gcolor = isset($pagelayer->global_colors[$gkey]) ? $gkey : 'primary';
4257 + $val = 'var(--pagelayer-color-'.$gcolor.')';
4258 +
4259 + return $val;
4260 +}
4261 +
4262 +// Sanitize style props for colors and fons
4263 +function pagelayer_sanitize_global_style($val, $val_desk = '', $mode = 'desktop'){
4264 + global $pagelayer;
4265 +
4266 + // Sanitize Global background color
4267 + if( !empty($val['background-color']) && $val['background-color'][0] == '$'){
4268 + $val['background-color'] = pagelayer_sanitize_global_color($val['background-color']);
4269 + }
4270 +
4271 + // Sanitize Global color
4272 + if( !empty($val['color']) && $val['color'][0] == '$'){
4273 + $val['color'] = pagelayer_sanitize_global_color($val['color']);
4274 + }
4275 +
4276 + // Not set global for typo
4277 + if(empty($val['global-font']) && empty($val_desk['global-font'])){
4278 + return $val;
4279 + }
4280 +
4281 + $_desk_global = false;
4282 +
4283 + if(empty($val['global-font'])){
4284 + $font_key = @$val_desk['global-font'];
4285 + $_desk_global = true;
4286 + }else{
4287 + $font_key = $val['global-font'];
4288 + unset($val['global-font']);
4289 + }
4290 +
4291 + if(empty($font_key)){
4292 + return $val;
4293 + }
4294 +
4295 + if(!isset($pagelayer->global_fonts[$font_key])){
4296 + $font_key = 'primary';
4297 + }
4298 +
4299 + $_val = [];
4300 +
4301 + // Apply global typo
4302 + foreach($pagelayer->typo_props as $typo_key){
4303 +
4304 + if(!empty($val[$typo_key])){
4305 + continue;
4306 + }
4307 +
4308 + $global_val = $pagelayer->global_fonts[$font_key]['value'];
4309 +
4310 + 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') ){
4311 + continue;
4312 + }
4313 +
4314 + $_val[$typo_key] = 'var(--pagelayer-font-'.$font_key.'-'.$typo_key.')';
4315 + }
4316 +
4317 + // This array contains other values like margin padding so we merge the array
4318 + $val = empty($val) ? array() : $val;
4319 + $val = array_merge($val, $_val);
4320 + return $val;
4321 +}
4322 +
4323 +//Check an empty array
4324 +function pagelayer_is_empty_array($arr){
4325 +
4326 + foreach ($arr as $key => $value) {
4327 + if (trim($value) !== '') return false;
4328 + }
4329 +
4330 + return true;
4331 +}
4332 +
4333 +// Pagelayer load font family
4334 +function pagelayer_load_font_family($font, $font_weight='', $font_style=''){
4335 + global $pagelayer;
4336 +
4337 + // Load global fonts
4338 + if(strripos($font, 'var(') !== false){
4339 + $matches = [];
4340 + preg_match('/(var\(--pagelayer-font-)(\w+)(-font-family\))/i', $font, $matches);
4341 + $font_key = @$matches[2];
4342 + $font = @$pagelayer->global_fonts[$font_key]['value']['font-family'];
4343 + }
4344 +
4345 + // Load global fonts weight
4346 + if(!empty($font_weight) && strripos($font_weight, 'var(') !== false){
4347 + $matches = [];
4348 + preg_match('/(var\(--pagelayer-font-)(\w+)(-font-weight\))/i', $font_weight, $matches);
4349 + $font_key = @$matches[2];
4350 +
4351 + // Convert in string
4352 + $font_weight = @$pagelayer->global_fonts[$font_key]['value']['font-weight'];
4353 + }
4354 +
4355 + // Load global fonts style
4356 + if(!empty($font_style) && strripos($font_style, 'var(') !== false){
4357 + $matches = [];
4358 + preg_match('/(var\(--pagelayer-font-)(\w+)(-font-style\))/i', $font_style, $matches);
4359 + $font_key = @$matches[2];
4360 +
4361 + // Convert in string
4362 + $font_style = @$pagelayer->global_fonts[$font_key]['value']['font-style'];
4363 + }
4364 +
4365 + if(empty($font)){
4366 + return;
4367 + }
4368 +
4369 + $font_weights = array('400' =>'400');
4370 + $font_style = empty($font_style) ? 'normal' : $font_style;
4371 + $font_style = in_array($font_style, ['italic', 'oblique']) ? 'i' : '';
4372 +
4373 + if(!empty($font_weight)){
4374 +
4375 + if(!is_array($font_weight)){
4376 + $font_weight = array($font_weight);
4377 + }
4378 +
4379 + foreach($font_weight as $weight){
4380 + $font_weights[$weight.$font_style] = $weight.$font_style;
4381 + }
4382 + }
4383 +
4384 + foreach($font_weights as $fkey => $fvalue){
4385 + $pagelayer->runtime_fonts[$font][$fkey] = $fvalue;
4386 + }
4387 +
4388 +}
4389 +
4390 +function pagelayer_update_plugin_notice(){
4391 + if(defined('SOFTACULOUS_PLUGIN_UPDATE_NOTICE')){
4392 + return;
4393 + }
4394 +
4395 + $to_update_plugins = apply_filters('softaculous_plugin_update_notice', []);
4396 +
4397 + if(empty($to_update_plugins)){
4398 + return;
4399 + }
4400 +
4401 + /* 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 */
4402 + $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>';
4403 +
4404 + define('SOFTACULOUS_PLUGIN_UPDATE_NOTICE', true); // To make sure other plugins don't return a Notice
4405 + echo '<div class="notice notice-info is-dismissible" id="pagelayer-plugin-update-notice">
4406 + <p>'.$msg. '</p>
4407 + </div>';
4408 +
4409 + wp_register_script('pagelayer-update-notice', '', ['jquery'], '', true);
4410 + wp_enqueue_script('pagelayer-update-notice');
4411 + wp_add_inline_script('pagelayer-update-notice', 'jQuery("#pagelayer-plugin-update-notice").on("click", function(e){
4412 + let target = jQuery(e.target);
4413 +
4414 + if(!target.hasClass("notice-dismiss")){
4415 + return;
4416 + }
4417 +
4418 + var data;
4419 +
4420 + // Hide it
4421 + jQuery("#pagelayer-plugin-update-notice").hide();
4422 +
4423 + // Save this preference
4424 + jQuery.post("'.admin_url('admin-ajax.php?action=pagelayer_close_update_notice').'&pagelayer_nonce='.wp_create_nonce('pagelayer_promo_nonce').'", data, function(response) {
4425 + //alert(response);
4426 + });
4427 + });');
4428 +}
4429 +
4430 +function pagelayer_update_plugin_notice_filter($plugins = []){
4431 + $plugins['pagelayer/pagelayer.php'] = 'Pagelayer';
4432 + return $plugins;
4433 +}
4434 +
4435 +function pagelayer_is_comment_mode(){
4436 +
4437 + if(file_exists(PAGELAYER_DIR.'/comment_mode.php') && !empty($_REQUEST['cmode'])){
4438 + include_once(PAGELAYER_DIR.'/comment_mode.php');
4439 + return true;
4440 + }
4441 +
4442 + return false;
4443 +}
4444 +
4445 +function pagelayer_esc_crlf($value){
4446 +
4447 + // Remove CRLF to prevent header injection
4448 + $value = str_replace(array("\r", "\n", "%0a", "%0d"), '', $value);
4449 +
4450 + // Trim spaces
4451 + $value = trim($value);
4452 +
4453 + return $value;
931 4454 }