PluginProbe
Page Builder: Pagelayer – Drag and Drop website builder / 2.2.0
Page Builder: Pagelayer – Drag and Drop website builder v2.2.0
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 +3031 -231 1.0.22.2.0 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,9 +396,26 @@
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
@@ -404,19 +424,34 @@
404 424 return pagelayer_shortlink($id).'&pagelayer-live=1';
405 425 }
406 426
407 427 // Are we in live mode ?
408 -function pagelayer_is_live(){
428 +function pagelayer_is_live(&$error = array()){
409 429
410 430 global $post;
411 431
412 432 // Are we seeing the post ?
413 433 if(!isset($post) || !isset($post->ID) || empty($post->ID)){
434 + $error[] = 'Post ID is missing or blank - '.@$post->ID;
414 435 return false;
415 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 + }
416 450
417 451 // Is it the live mode ?
418 452 if(pagelayer_optreq('pagelayer-live')){
453 + $error[] = 'pagelayer-live is missing';
419 454 return true;
420 455 }
421 456
422 457 return false;
@@ -423,12 +458,12 @@
423 458
424 459 }
425 460
426 461 // Are we in live IFRAME mode ?
427 -function pagelayer_is_live_iframe(){
462 +function pagelayer_is_live_iframe(&$error = array()){
428 463
429 464 // Are we seeing the post ?
430 - if(!pagelayer_is_live()){
465 + if(!pagelayer_is_live($error)){
431 466 return false;
432 467 }
433 468
434 469 // Is it the live mode ?
@@ -434,29 +469,95 @@
434 469 // Is it the live mode ?
435 470 if(pagelayer_optreq('pagelayer-iframe')){
436 471 return true;
437 472 }
473 +
474 + $error[] = 'pagelayer-iframe missing in GET';
438 475
439 476 return false;
440 477
441 478 }
442 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 +
443 515 // Can the current user edit the post ?
444 516 function pagelayer_user_can_edit($post = NULL){
445 517
446 - global $wp_the_query, $current_user;
518 + global $wp_the_query, $current_user, $pagelayer;
519 +
520 + $post = get_post($post);
447 521
448 - if(!isset($post) || empty($post) || $post === NULL){
449 - global $post;
522 + if(empty($post)){
523 + return false;
450 524 }
451 525
452 - wp_get_current_user();
453 -
454 - 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))){
455 - return true;
526 + // No trash editing
527 + if(get_post_status($post->ID) === 'trash'){
528 + return false;
456 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 + }
457 558
458 - return false;
559 + return true;
459 560
460 561 }
461 562
462 563 // Language sting function
@@ -476,17 +577,81 @@
476 577 function pagelayer_icon_sources(){
477 578 return array();
478 579 }
479 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 +
480 639 // Loads the shortcodes
481 640 function pagelayer_load_shortcodes(){
482 -
483 - include_once(PAGELAYER_DIR.'/main/shortcode_functions.php');
484 - if(defined('PAGELAYER_PREMIUM')){
485 - include_once(PAGELAYER_DIR.'/main/premium_functions.php');
641 + global $pagelayer, $post;
642 +
643 + if(!empty($pagelayer->shortcode_loaded)){
644 + return;
486 645 }
487 - include_once(PAGELAYER_DIR.'/main/shortcodes.php');
488 -
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 +
489 654 // pQuery
490 655 include_once(PAGELAYER_DIR.'/lib/pquery/IQuery.php');
491 656 include_once(PAGELAYER_DIR.'/lib/pquery/gan_formatter.php');
492 657 include_once(PAGELAYER_DIR.'/lib/pquery/gan_node_html.php');
@@ -494,35 +659,80 @@
494 659 include_once(PAGELAYER_DIR.'/lib/pquery/gan_parser_html.php');
495 660 include_once(PAGELAYER_DIR.'/lib/pquery/gan_selector_html.php');
496 661 include_once(PAGELAYER_DIR.'/lib/pquery/gan_xml2array.php');
497 662 include_once(PAGELAYER_DIR.'/lib/pquery/pQuery.php');
663 +
664 + include_once(PAGELAYER_DIR.'/main/shortcode_functions.php');
498 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 +
499 671 // Apply filter to load custom widgets
500 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;
501 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');
502 716 }
503 717
504 718 // Add the shortcodes to the pagelayer list
505 719 function pagelayer_add_shortcode($tag, $params = array()){
506 720
507 - global $pagelayer;
508 -
509 - // Is there a handler function ?
510 - if(!empty($params['func'])){
721 + global $pagelayer, $post;
511 722
512 - if($tag == 'pl_row'){
513 - $inner_tag = 'pl_inner_row';
514 - add_shortcode($inner_tag, 'pagelayer_render_shortcode');
515 - }
516 -
517 - if($tag == 'pl_col'){
518 - $inner_tag = 'pl_inner_col';
519 - add_shortcode($inner_tag, 'pagelayer_render_shortcode');
520 - }
521 -
522 - add_shortcode($tag, 'pagelayer_render_shortcode');//$params['func']);
523 - //unset($params['func']);
723 + if($tag == 'pl_row'){
724 + $inner_tag = 'pl_inner_row';
725 + add_shortcode($inner_tag, 'pagelayer_render_shortcode');
524 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']);
525 735
526 736 // Is there a group ?
527 737 if(empty($params['group'])){
528 738 $params['group'] = 'misc';
@@ -532,11 +742,14 @@
532 742 $params['options'] = [
533 743 'ele_bg_styles' => __pl('ele_bg_styles'),
534 744 'ele_styles' => __pl('ele_styles'),
535 745 'border_styles' => __pl('border_styles'),
746 + 'font_style' => __pl('font_style'),
536 747 'position_styles' => __pl('position_styles'),
537 748 'animation_styles' => __pl('animation_styles'),
749 + 'motion_effects' => __pl('Motion Effects'),
538 750 'responsive_styles' => __pl('responsive_styles'),
751 + 'attributes' => __pl('attributes'),
539 752 'custom_styles' => __pl('custom_styles'),
540 753 ];
541 754
542 755 if(!empty($params['skip_props_cat'])){
@@ -575,26 +788,133 @@
575 788 }
576 789 }
577 790 }
578 791 //die();*/
579 -
792 +
793 + $params = apply_filters( 'pagelayer_shortcode_params', $params, $tag );
794 +
580 795 // Insert the shortcode
581 796 $pagelayer->shortcodes[$tag] = $params;
582 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 +}
583 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);
584 867 }
585 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 +
586 886 // Returns the Image values
587 -function pagelayer_image($id){
887 +function pagelayer_image($id = 0){
588 888
589 889 global $pagelayer;
590 890
591 891 $ret = [];
592 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 +
593 913 // External image ?
594 914 if(pagelayer_is_external_img($id)){
595 915
596 - $ret['full-url'] = $id;
916 + $ret['url'] = $id;
597 917
598 918 // Attachment
599 919 }elseif(!empty($id)){
600 920
@@ -622,30 +942,43 @@
622 942 $title = esc_attr($image->post_title);
623 943 $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
624 944 $alt = empty($alt) ? $image->post_excerpt : $alt;
625 945 $alt = empty($alt) ? $image->post_title : $alt;
626 - $alt = empty($alt) ? '' : trim(strip_tags($alt));
946 + $alt = empty($alt) ? '' : esc_attr(trim(strip_tags($alt)));
627 947 $link = get_attachment_link($id);
628 948 $caption = wp_get_attachment_caption($id);
629 - $caption = !empty($caption) ? $caption : '';
949 + $caption = !empty($caption) ? esc_attr($caption) : '';
630 950
631 - $ret['alt'] = $alt;
632 - $ret['title'] = $title;
633 - $ret['link'] = $link;
634 - $ret['caption'] = $caption;
951 + }
635 952
636 - }
953 + }
637 954
955 + // First preference to full url
956 + if(!empty($ret['full-url'])){
957 + $ret['url'] = $ret['full-url'];
638 958 }
639 959
640 960 // No image
641 - if(empty($ret['full-url'])){
642 - $ret['full-url'] = PAGELAYER_URL.'/images/default-image.png';
961 + if(empty($ret['url'])){
962 + $ret['url'] = PAGELAYER_URL.'/images/default-image.png';
643 963 }
644 964
645 - $ret['url'] = $ret['full-url'];
965 + // Extract filename without extension
966 + $filename = pathinfo($ret['url'], PATHINFO_FILENAME);
646 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 +
647 976 $ret = apply_filters('pagelayer_image', $ret);
977 +
978 + if(pagelayer_is_default_img($ret['url'])){
979 + $ret['no-image-set'] = 1;
980 + }
648 981
649 982 return $ret;
650 983
651 984 }
@@ -664,8 +997,19 @@
664 997 return false;
665 998
666 999 }
667 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 +
668 1012 // Returns the attachment url
669 1013 function pagelayer_attachment($id){
670 1014
671 1015 $ret = [];
@@ -694,15 +1038,20 @@
694 1038 }
695 1039
696 1040 // Convert the regular URL of a Video to a Embed URL
697 1041 // Todo : Check
698 -function pagelayer_video_url($source){
1042 +function pagelayer_video_url($source, $no_url = false){
699 1043
1044 + global $pagelayer;
1045 +
700 1046 if (!empty($source)) {
701 - $source = filter_var($source, FILTER_SANITIZE_URL);
1047 +
1048 + $source = esc_url( $source );
702 1049 $source = str_replace('&amp;', '&', $source);
703 1050 $url = parse_url($source);
704 1051 $videoSite ='';
1052 + $videoId ='';
1053 + $vid_atts = [];
705 1054
706 1055 $youtubeRegExp = '/youtube\.com|youtu\.be/is';
707 1056 $vimeoRegExp = '/vimeo\.com/is';
708 1057
@@ -714,8 +1063,10 @@
714 1063
715 1064 switch ($videoSite) {
716 1065 case 'youtube':
717 1066
1067 + $pagelayer->append_yt_api = true;
1068 +
718 1069 if (preg_match('/youtube\.com/is', $source)) {
719 1070
720 1071 if (preg_match('/watch/is', $source)) {
721 1072 parse_str($url['query'], $parameters);
@@ -738,38 +1089,44 @@
738 1089 $videoId = $path[1];
739 1090 }
740 1091
741 1092 }
1093 +
1094 + $vid_atts['type'] = 'youtube';
1095 + $vid_atts['src'] = '//www.youtube.com/embed/'.$videoId;
1096 + $vid_atts['id'] = $videoId;
742 1097
743 - return '//youtube.com/embed/'.$videoId;
744 -
745 1098 break;
746 1099 case 'vimeo':
747 1100
748 1101 if (preg_match('/player\.vimeo\.com/is', $url['host']) && preg_match('/video/is', $url['path'])) {
749 - $path = explode('/', $url['path']);
750 -
751 - if (isset($path[2]) && !empty($path[2])) {
752 - $videoId = $path[2];
753 - }
754 -
1102 + $path = explode('video/', $source);
755 1103 } else if (preg_match('/vimeo\.com/is', $url['host'])) {
756 - $path = explode('/', $url['path']);
757 -
758 - if (isset($path[1]) && !empty($path[1])) {
759 - $videoId = $path[1];
760 - }
761 -
1104 + $path = explode('.com/', $source);
762 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;
763 1114
764 - return '//player.vimeo.com/video/'.$videoId;
765 -
766 1115 break;
767 1116 default:
1117 +
1118 + $vid_atts['type'] = 'local';
1119 + $vid_atts['src'] = $source;
1120 + $vid_atts['id'] = $videoId;
768 1121
769 - return $source;
770 -
771 1122 }
1123 +
1124 + if(!$no_url){
1125 + return $vid_atts['src'];
1126 + }
1127 +
1128 + return $vid_atts;
772 1129
773 1130 }
774 1131 }
775 1132
@@ -776,8 +1133,12 @@
776 1133
777 1134 // As per the JS specification
778 1135 function pagelayer_escapeHTML($str){
779 1136
1137 + if(is_null($str)){
1138 + return '';
1139 + }
1140 +
780 1141 $replace = [
781 1142 ']' => '&#93;',
782 1143 '[' => '&#91;',
783 1144 //'=' => '&#61;',
@@ -784,9 +1145,10 @@
784 1145 '<' => '&lt;',
785 1146 '>' => '&gt;',
786 1147 '"' => '&quot;',
787 1148 //'&' => '&amp;',
788 - '\'' => '&#39;'
1149 + '\'' => '&#39;',
1150 + '\\' => '&#92;'
789 1151 ];
790 1152
791 1153 $str = str_replace(array_keys($replace), array_values($replace), $str);
792 1154
@@ -794,8 +1156,13 @@
794 1156 }
795 1157
796 1158 // As per the JS specification
797 1159 function pagelayer_unescapeHTML($str){
1160 +
1161 + if(is_null($str)){
1162 + return '';
1163 + }
1164 +
798 1165 $replace = [
799 1166 '#93' => ']',
800 1167 '#91' => '[',
801 1168 //'#61' => '=',
@@ -802,9 +1169,10 @@
802 1169 'lt' => '<',
803 1170 'gt' => '>',
804 1171 'quot' => '"',
805 1172 //'amp' => '&',
806 - '#39' => '\''
1173 + '#39' => '\'',
1174 + '#92' => '\\'
807 1175 ];
808 1176
809 1177 foreach($replace as $k => $v){
810 1178 $str = str_replace('&'.$k.';', $v, $str);
@@ -811,8 +1179,693 @@
811 1179 }
812 1180 return $str;
813 1181 }
814 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 +
815 1868 // Show promo notice on dashboard
816 1869 function pagelayer_show_promo(){
817 1870
818 1871 global $pagelayer_promo_opts;
@@ -818,67 +1871,69 @@
818 1871 global $pagelayer_promo_opts;
819 1872 $opts = $pagelayer_promo_opts;
820 1873
821 1874 echo '<style>
822 -.pagelayer_promo_button {
823 -background-color: #4CAF50; /* Green */
824 -border: none;
825 -color: white;
826 -padding: 6px 10px;
827 -text-align: center;
828 -text-decoration: none;
829 -display: inline-block;
830 -font-size: 13px;
831 -margin: 4px 2px;
832 --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;
833 1886 transition-duration: 0.4s;
834 -cursor: pointer;
1887 +cursor: pointer !important;
835 1888 }
836 -.pagelayer_promo_button:focus{
837 -border: none;
838 -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;
839 1894 }
840 -.pagelayer_promo_button1 {
841 -color: white;
842 -background-color: #4CAF50;
843 -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;
844 1900 }
845 -.pagelayer_promo_button1:hover {
846 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
847 -color: white;
848 -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;
849 1905 }
850 -.pagelayer_promo_button2 {
851 -color: white;
852 -background-color: #0085ba;
1906 +#pagelayer_promo a.pagelayer_promo_button1:hover {
1907 +border:3px solid #4CAF50 !important;
853 1908 }
854 -.pagelayer_promo_button2:hover {
855 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
856 -color: white;
1909 +#pagelayer_promo a.pagelayer_promo_button2 {
1910 +color: white !important;
1911 +background-color: #0085ba !important;
857 1912 }
858 -.pagelayer_promo_button3 {
859 -color: white;
860 -background-color: #365899;
1913 +#pagelayer_promo a.pagelayer_promo_button3 {
1914 +color: white !important;
1915 +background-color: #365899 !important;
861 1916 }
862 -.pagelayer_promo_button3:hover {
863 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
864 -color: white;
1917 +#pagelayer_promo a.pagelayer_promo_button4 {
1918 +color: white !important;
1919 +background-color: rgb(66, 184, 221) !important;
865 1920 }
866 -.pagelayer_promo_button4 {
867 -color: white;
868 -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;
869 1926 }
870 -.pagelayer_promo_button4:hover {
871 -box-shadow: 0 6px 8px 0 rgba(0,0,0,0.24), 0 9px 25px 0 rgba(0,0,0,0.19);
872 -color: white;
1927 +#pagelayer_promo a.pagelayer_promo-close:hover{
1928 +color: red !important;
873 1929 }
874 -.pagelayer_promo-close{
875 -float:right;
876 -text-decoration:none;
877 -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;
878 1933 }
879 -.pagelayer_promo-close:hover{
880 -color: red;
1934 +#pagelayer_promo a:not(.pagelayer_promo_button):not(.pagelayer_promo-close):hover {
1935 +color: #3e8e41 !important;
881 1936 }
882 1937 </style>
883 1938 <script type="application/javascript">
884 1939 jQuery(document).ready(function(){
@@ -904,14 +1959,21 @@
904 1959
905 1960 echo '
906 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>
907 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>').'
908 1964 '.(empty($opts['rating']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button2" target="_blank" href="'.$opts['rating'].'">Rate it 5★\'s</a>').'
909 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>').'
910 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>').'
911 1967 '.(empty($opts['website']) ? '' : '<a class="pagelayer_promo_button pagelayer_promo_button4" target="_blank" href="'.$opts['website'].'">Visit our website</a>').'
912 1968 </p>
913 -</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>';
914 1976
915 1977 }
916 1978
917 1979 // Are we to show a promo ?
@@ -919,8 +1981,13 @@
919 1981
920 1982 global $pagelayer_promo_opts;
921 1983
922 1984 // There must be an interval
1985 + if(!current_user_can('activate_plugins')){
1986 + return false;
1987 + }
1988 +
1989 + // There must be an interval
923 1990 if(empty($opts['interval'])){
924 1991 return false;
925 1992 }
926 1993
@@ -947,10 +2014,66 @@
947 2014 }
948 2015
949 2016 }
950 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 +
951 2073 // Bread Crumbs with links
952 2074 function pagelayer_get_breadcrumb(){
2075 + global $post;
953 2076
954 2077 // Home page
955 2078 $ret = '<a href="'.home_url().'" rel="nofollow">{{home}}</a>';
956 2079
@@ -961,9 +2084,9 @@
961 2084 // Is search query
962 2085 }elseif(is_search()){
963 2086 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b><b class="pagelayer-breadcrumb-prefix" if="{{search_prefix}}">{{search_prefix}}</b>';
964 2087 $ret .= '<em>';
965 - $ret .= get_search_query();
2088 + $ret .= '<span>'.get_search_query().'</span>';
966 2089 $ret .= '</em>';
967 2090
968 2091 //Is category or single post
969 2092 }elseif(is_category() || is_single()){
@@ -978,18 +2101,35 @@
978 2101 if(is_single()) {
979 2102 /* if (empty($categories)){
980 2103 $ret .= ' <b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b> ';
981 2104 } */
982 - $ret .= get_the_title();
2105 + $ret .= '<span>'.get_the_title().'</span>';
983 2106 }
984 2107
985 2108 // Is page
986 - }elseif(is_page()){
987 - $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
988 - $ret .= get_the_title();
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 + }
989 2129 }else{
990 2130 $ret .= '<b class="pagelayer-breadcrumb-sep" if="{{separator}}">{{separator}}</b>';
991 - $ret .= wp_title('', false );
2131 + $ret .= '<span>'.wp_title('', false ).'</span>';
992 2132 }
993 2133
994 2134 // wooCommerce Integration left
995 2135
@@ -1063,10 +2203,24 @@
1063 2203
1064 2204 return $ret;
1065 2205 }
1066 2206
2207 +function pagelayer_remove_excerpt_more($more){
2208 + return '';
2209 +}
2210 +
1067 2211 function pagelayer_posts($params, $args = []){
2212 + global $post, $wp_query;
1068 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 +
1069 2223 // If args is empty
1070 2224 if(empty($args)){
1071 2225 $args = array(
1072 2226 'post_type' => $params['post_type'],
@@ -1072,52 +2226,98 @@
1072 2226 'post_type' => $params['post_type'],
1073 2227 'posts_per_page' => $params['posts_per_page'],
1074 2228 'order' => $params['order']
1075 2229 );
1076 -
1077 - if($params['exc_length']){
1078 - $exc_length = (int) $params['exc_length'];
1079 - add_filter( 'excerpt_length', function($length) use($exc_length){
1080 - return $exc_length;
1081 - }, 999 );
2230 +
2231 + if(!empty($params['paged'])){
2232 + $args['paged'] = $params['paged'];
1082 2233 }
1083 2234
1084 - if($params['term']){
2235 + if (!empty($params['term']) || !empty($params['exc_term'])) {
2236 + $tax_query = [];
1085 2237
1086 - $term = explode(':', $params['term']);
1087 - //pagelayer_print($term);
1088 - if($term[0] == 'category'){
1089 - $args['category_name'] = $term[1];
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 + }
1090 2264 }
1091 - if($term[0] == 'post_tag'){
1092 - $args['tag'] = $term[1];
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 + }
1093 2295 }
1094 - }
1095 2296
1096 - if($params['exc_term']){
1097 -
1098 - $term = explode(':', $params['exc_term']);
1099 - //pagelayer_print($term);
1100 - if($term[0] == 'category'){
1101 - $args['category__not_in'] = $term[2];
2297 + // Apply the combined tax_query
2298 + if(!empty($tax_query)){
2299 + $args['tax_query'] = array_merge(['relation' => 'AND'], $tax_query);
1102 2300 }
1103 - if($term[0] == 'post_tag'){
1104 - $args['tag__not_in'] = $term[2];
1105 - }
1106 2301 }
1107 2302
1108 - if($params['author_name']){
2303 + if(!empty($params['author_name'])){
1109 2304 $author_name = explode(':', $params['author_name']);
1110 2305 $args['author_name'] = $author_name[0];
1111 2306 }
1112 2307
1113 - if($params['exc_author']){
2308 + if(!empty($params['exc_author'])){
1114 2309 $exc_author = explode(':', $params['exc_author']);
1115 2310 $args['author'] = '-'.$exc_author[1];
1116 2311 }
1117 2312
1118 - if(!empty($params['offset'])){
1119 - $args['offset'] = $params['offset'];
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 + }
1120 2320 }
1121 2321
1122 2322 if(!empty($params['ignore_sticky'])){
1123 2323 $args['ignore_sticky_posts'] = $params['ignore_sticky'];
@@ -1126,9 +2326,9 @@
1126 2326 if(!empty($params['orderby'])){
1127 2327 $args['orderby'] = $params['orderby'];
1128 2328 }
1129 2329
1130 - if($params['by_period']){
2330 + if(!empty($params['by_period'])){
1131 2331 $date_arg = array();
1132 2332 switch($params['by_period']){
1133 2333 case 'last_day':
1134 2334 $date_arg['day'] = date('j')-1;
@@ -1153,15 +2353,25 @@
1153 2353 }
1154 2354 }
1155 2355 //pagelayer_print($args);
1156 2356
2357 + // Only see published posts
2358 + $args['post_status'] = 'publish';
2359 +
1157 2360 $postsquery = new WP_Query($args);
1158 2361 $data = '';
1159 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 +
1160 2367 if(!$postsquery->have_posts()){
1161 - return '<h3>Something went wrong, Please give proper inputs!</h3>';
2368 + return '<h3>No posts found!</h3>';
1162 2369 }
1163 2370
2371 + // To reset the post when the $wp_query->post is empty
2372 + $orig_post = $post;
2373 +
1164 2374 while($postsquery->have_posts()) : $postsquery->the_post();
1165 2375 $data .= '<div class="pagelayer-wposts-col">
1166 2376 <div class="pagelayer-wposts-post">
1167 2377 <div class="pagelayer-wposts-featured">';
@@ -1166,10 +2376,10 @@
1166 2376 <div class="pagelayer-wposts-post">
1167 2377 <div class="pagelayer-wposts-featured">';
1168 2378 $data .= '<a href="'. get_the_permalink() .'">';
1169 2379
1170 - if(isset($params['show_thumb']) && has_post_thumbnail( $postsquery->ID )){
1171 - $data .= '<div class="pagelayer-wposts-thumb"'.(has_post_thumbnail() ? ' style="background:url('.get_the_post_thumbnail_url($postsquery->ID,$params['thumb_size']).')"' : '').'></div>';
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>';
1172 2382 }
1173 2383 /* if($params['show_thumb'] && has_post_thumbnail( $postsquery->ID )){
1174 2384 $data .= get_the_post_thumbnail_url($postsquery->ID,$params['thumb_size']);
1175 2385 } */
@@ -1175,32 +2385,38 @@
1175 2385 } */
1176 2386 $data .= '</a></div>
1177 2387 <div class="pagelayer-wposts-content">';
1178 2388
1179 - if(isset($params['show_title'])){
2389 + if(!empty($params['show_title'])){
1180 2390 $data .= '<a href="'.esc_url( get_permalink() ).'" rel="bookmark"><div class="pagelayer-wposts-title">'. get_the_title().'</div></a>';
1181 2391 }
1182 2392
1183 2393 $data .= '<div class="pagelayer-wposts-meta">';
1184 2394 $sep = '';
1185 - if(isset($params['meta_sep'])){
1186 - $sep = '<b class="pagelayer-wposts-sep">'.$params['meta_sep'].'</b>';
2395 + if(!empty($params['meta_sep'])){
2396 + $sep = ' <b class="pagelayer-wposts-sep">'.$params['meta_sep'].'</b> ';
1187 2397 }
1188 - if(isset($params['author'])){
2398 + if(!empty($params['author'])){
1189 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;
1190 2400 }
1191 - if(isset($params['date'])){
1192 - $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;
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;
1193 2403 }
1194 - if(isset($params['category'])){
2404 +
2405 + if(!empty($params['category'])){
1195 2406 $category = get_the_category();
1196 2407 $singlecategory = '';
1197 2408 foreach( $category as $cat ){
1198 2409 $singlecategory .= '<a href="' . get_tag_link( $cat->term_id ) . '">'. $cat->name .'</a>';
1199 2410 }
1200 - $data .= '<span class="pagelayer-wposts-category">' . $singlecategory . '</span>'.$sep;
2411 +
2412 + if(!empty($singlecategory)){
2413 + $data .= '<span class="pagelayer-wposts-category">' . $singlecategory . '</span>'.$sep;
2414 + }
2415 +
1201 2416 }
1202 - if(isset($params['tags'])){
2417 +
2418 + if(!empty($params['tags'])){
1203 2419 $tags = get_the_tags();
1204 2420 $singletag = '';
1205 2421 if(!empty($tags)){
1206 2422 foreach( $tags as $tag ){
@@ -1211,26 +2427,46 @@
1211 2427 }
1212 2428 }
1213 2429
1214 2430 }
1215 - if(isset($params['comments'])){
1216 - $data .= '<span class="pagelayer-wposts-comments"><i class="far fa-comment" /><a href="' . esc_url( get_permalink() ) . '">' . esc_html(get_comments_number()) . '</a></span>'.$sep;
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;
1217 2434 }
1218 2435
1219 2436 $data .= '</div>';
1220 2437
1221 - if(isset($params['show_content'])){
2438 + if(!empty($params['show_content'])){
1222 2439 $data .= '<div class="pagelayer-wposts-excerpt">';
1223 - if($params['show_content'] == 'excerpt'){
1224 - $data .= do_shortcode(get_the_excerpt());
1225 - }elseif($params['show_content'] == 'full'){
1226 - $data .= do_shortcode(get_the_content());
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());
1227 2447 }
1228 2448 $data .= '</div>';
1229 2449 }
1230 2450
1231 - if(isset($params['show_more'])){
1232 - $data .= '<a class="pagelayer-wposts-more" href="'. get_the_permalink().'">'.$params['more'].'</a>';
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>';
1233 2469 }
1234 2470
1235 2471 //$data .= '<div class="pagelayer-wposts-date"><p>'.get_the_date().'</p></div>';
1236 2472 $data .= '</div></div></div>';
@@ -1235,8 +2471,15 @@
1235 2471 //$data .= '<div class="pagelayer-wposts-date"><p>'.get_the_date().'</p></div>';
1236 2472 $data .= '</div></div></div>';
1237 2473 endwhile;
1238 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 +
1239 2482 return $data;
1240 2483 }
1241 2484
1242 2485 // Get Post Revision
@@ -1335,9 +2578,9 @@
1335 2578 $data .= '<div class="pagelayer-posts-slider-excerpt">';
1336 2579 if($params['post']['show_excerpt'] == "true"){
1337 2580 if(has_excerpt()){
1338 2581 $excerpt = get_the_excerpt();
1339 - $data .= do_shortcode($excerpt);
2582 + $data .= pagelayer_the_content($excerpt);
1340 2583 }
1341 2584 }
1342 2585 $data .= '</div>';
1343 2586 $data .= '<a class="pagelayer-posts-slider-link" href="'. get_the_permalink().'">Read More</a>';
@@ -1370,8 +2613,12 @@
1370 2613
1371 2614 // Groups
1372 2615 }else{
1373 2616
2617 + if(array_key_exists('hide_drop', $opt_array[$x]) && !empty($opt_array[$x]['hide_drop'])){
2618 + continue;
2619 + }
2620 +
1374 2621 // If Label is there, then its a normal option
1375 2622 if(array_key_exists('label', $opt_array[$x])){
1376 2623 $options .= pagelayer_sel_option($x, $opt_array[$x]['label'], $selected);
1377 2624
@@ -1435,9 +2682,9 @@
1435 2682
1436 2683 function pagelayer_get_post_author(){
1437 2684
1438 2685 $args = [
1439 - 'who' => 'authors',
2686 + 'capability' => array( 'edit_posts' ),
1440 2687 'fields' => [
1441 2688 'ID',
1442 2689 'display_name',
1443 2690 'user_nicename',
@@ -1442,8 +2689,14 @@
1442 2689 'display_name',
1443 2690 'user_nicename',
1444 2691 ]
1445 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 + }
1446 2699
1447 2700 $authors = new \WP_User_Query( $args );
1448 2701
1449 2702 $ret = array();
@@ -1519,10 +2772,67 @@
1519 2772
1520 2773 return $query_args;
1521 2774 }
1522 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 +
1523 2831 function pagelayer_export_content($content){
1524 -
2832 +
2833 + global $pagelayer;
2834 +
1525 2835 // Just call do_shortcode so we can get list of media files to export
1526 2836 //do_shortcode($content);
1527 2837
1528 2838 $theme_url = preg_replace('/http(s?):\/\//is', '', get_stylesheet_directory_uri());
@@ -1528,8 +2838,46 @@
1528 2838 $theme_url = preg_replace('/http(s?):\/\//is', '', get_stylesheet_directory_uri());
1529 2839
1530 2840 $content = preg_replace('/http(s?):\/\/'.preg_quote($theme_url, '/').'/is', '{{theme_url}}', $content);
1531 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 +
1532 2880 // Apply a filter
1533 2881 $content = apply_filters('pagelayer_export_content', $content);
1534 2882
1535 2883 return $content;
@@ -1535,22 +2883,262 @@
1535 2883 return $content;
1536 2884
1537 2885 }
1538 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 +
1539 3106 // Insert a post which is a Pagelayer Post
1540 -function pagelayer_insert_content($post, &$ret){
3107 +function pagelayer_sanitize_content($content){
1541 3108
3109 + if(empty($content)){
3110 + return $content;
3111 + }
3112 +
1542 3113 // Replace Vars
1543 3114 $template_vars = pagelayer_template_vars();
3115 +
1544 3116 foreach($template_vars as $key => $val){
1545 - $post['post_content'] = str_replace($key, $val, $post['post_content']);
3117 + $content = str_replace($key, $val, $content);
1546 3118 }
1547 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']);
1548 3134 //pagelayer_print($post);die();
1549 3135
1550 3136 // Add slashes for safe insert
1551 3137 $post['post_content'] = wp_slash($post['post_content']);
1552 3138
3139 + $post = apply_filters('pagelayer_pre_insert_content', $post);
3140 +
1553 3141 // Now insert / update the post
1554 3142 $ret = wp_insert_post($post);
1555 3143
1556 3144 // Did we save the post ?
@@ -1579,76 +3167,1288 @@
1579 3167 return $stored_icons;
1580 3168
1581 3169 }
1582 3170
1583 -// Install the Pro version
1584 -function pagelayer_install_pro(){
3171 +// Prevent pro activate text for installer
3172 +function pagelayer_install_plugin_complete_actions($install_actions, $api, $plugin_file){
1585 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(){
1586 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){
1587 3618
1588 - // Include the necessary stuff
1589 - include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
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 +}
1590 3640
1591 - // Includes necessary for Plugin_Upgrader and Plugin_Installer_Skin
1592 - include_once( ABSPATH . 'wp-admin/includes/file.php' );
1593 - include_once( ABSPATH . 'wp-admin/includes/misc.php' );
1594 - include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
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 +}
1595 3655
1596 - // Filter to prevent the activate text
1597 - add_filter('install_plugin_complete_actions', 'pagelayer_install_plugin_complete_actions', 10, 3);
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 +}
1598 3669
1599 - $upgrader = new Plugin_Upgrader( new Plugin_Installer_Skin( ) );
1600 - $installed = $upgrader->install(PAGELAYER_API.'download.php?version=latest&license='.$pagelayer->license['license']);
3670 +// Get checkboxes of post categories.
3671 +function pagelayer_post_cats($post, &$cat_name = ''){
1601 3672
1602 - if ( !is_wp_error( $installed ) && $installed ) {
1603 - echo 'Activating Pagelayer Pro !';
1604 - $activate = activate_plugin(PAGELAYER_PRO_BASE);
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>';
1605 3690
1606 - if ( is_null($activate) ) {
1607 - echo '<div id="message" class="updated"><p>'. __('Done! Pagelayer Pro is now installed and activated.', 'pagelayer'). '</p></div><br />';
1608 - echo '<br><br><b>Done! Pagelayer Pro is now installed and activated.</b>';
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;
1609 3739 }
3740 + $users = get_users( array( 'role__in' => $roles__in ) );
1610 3741 }
1611 3742
1612 - return $installed;
3743 + $user_array = [];
1613 3744
3745 + foreach ( $users as $user ) {
3746 + $user_array[$user->ID] = $user->display_name;
3747 + }
3748 +
3749 + return $user_array;
1614 3750 }
1615 3751
1616 -// Prevent pro activate text for installer
1617 -function pagelayer_install_plugin_complete_actions($install_actions, $api, $plugin_file){
3752 +function pagelayer_parent_post_prop($post){
3753 + global $wp_post_types;
1618 3754
1619 - if($plugin_file == PAGELAYER_PRO_BASE){
1620 - return array();
3755 + if(!empty($wp_post_types[$post->post_type]->hierarchical)){
3756 + return pagelayer_list_parents(0, 0, $post, []);
3757 + }else{
3758 + return [];
1621 3759 }
3760 +}
3761 +
3762 +function pagelayer_list_parents( $parent = 0, $level = 0, $post = null, $values=array('')){
1622 3763
1623 - return $install_actions;
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;
1624 3795 }
1625 3796
1626 -// Load license data
1627 -function pagelayer_load_license(){
3797 +// Maybe explode
3798 +function pagelayer_maybe_explode( $separator = ',', $string = '', $limit = PHP_INT_MAX ){
1628 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){
1629 3957 global $pagelayer;
1630 3958
1631 - // Load license
1632 - $pagelayer->license = get_option('pagelayer_license');
3959 + // To load customizer params array
3960 + if(empty($pagelayer->customizer_params)){
3961 + pagelayer_load_shortcodes();
3962 + }
1633 3963
1634 - // Update license details as well
1635 - if(!empty($pagelayer->license) && (time() - @$pagelayer->license['last_update']) >= 86400){
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){
1636 4003
1637 - $resp = wp_remote_get(PAGELAYER_API.'license.php?license='.$pagelayer->license['license']);
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){
1638 4088
1639 - // Did we get a response ?
1640 - if(is_array($resp)){
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){
1641 4100
1642 - $tosave = json_decode($resp['body'], true);
4101 + $screen = (!empty($sv) ? '_'.$sv : '');
4102 + $screen_key = $cv['option'].$screen;
4103 + $screen_ck = $ck.$screen;
1643 4104
1644 - // Is it the license ?
1645 - if(!empty($tosave['license'])){
1646 - $tosave['last_update'] = time();
1647 - update_option('pagelayer_license', $tosave);
4105 + // Get option value
4106 + $c_option = get_option($screen_key);
4107 +
4108 + if(empty($c_option)){
4109 + continue;
1648 4110 }
1649 4111
4112 + $options[$screen_ck] = $c_option;
1650 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.')';
1651 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']);
1652 4269 }
1653 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;
1654 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;
4454 +}