| 1 |
<?php |
| 2 |
/** Native template backgrounds and signed contact forms. */ |
| 3 |
defined('ABSPATH') || exit; |
| 4 |
function bkbg_template_background($a){ |
| 5 |
$s=is_array($a['settings']??null)?$a['settings']:array();$type=$s['background_background']??'';$out=''; |
| 6 |
if($type==='slideshow'&&!empty($s['background_slideshow_gallery'])){ |
| 7 |
$effect=$s['background_slideshow_slide_transition']??'fade';if(!in_array($effect,array('fade','slide_right','slide_left','slide_up','slide_down'),true))$effect='fade'; |
| 8 |
$config=array('effect'=>$effect,'duration'=>max(1000,(int)($s['background_slideshow_slide_duration']??5000)),'transition'=>max(0,min(5000,(int)($s['background_slideshow_transition_duration']??500))),'loop'=>($s['background_slideshow_loop']??'yes')==='yes','kenBurns'=>($s['background_slideshow_ken_burns']??'')==='yes','zoomOut'=>($s['background_slideshow_ken_burns_zoom_direction']??'in')==='out'); |
| 9 |
$out='<div class="bkbg-tpl-background-slideshow bkbg-template-background-slides" aria-hidden="true" data-bkbg-slideshow="'.esc_attr(wp_json_encode($config)).'">'; |
| 10 |
foreach($s['background_slideshow_gallery'] as $i=>$image){$url=esc_url($image['url']??'');if(!$url)continue;$out.='<div class="bkbg-template-background-slide'.($i===0?' is-active':'').'"><div class="bkbg-tpl-background-slideshow__slide__image" style="background-image:url("'.$url.'")"></div></div>';} |
| 11 |
$out.='</div>'; |
| 12 |
}elseif($type==='video'){ |
| 13 |
$url=$s['background_video_link']??'';$url=esc_url($url);if($url&&preg_match('~\.(mp4|webm|ogg)(?:\?|$)~i',$url))$out='<div class="bkbg-tpl-background-video-container'.(($s['background_play_on_mobile']??'')==='yes'?'':' bkbg-tpl-hidden-mobile').'" aria-hidden="true"><video class="bkbg-tpl-background-video-hosted bkbg-template-background-video" src="'.$url.'" muted autoplay loop playsinline preload="metadata"></video></div>'; |
| 14 |
} |
| 15 |
return $out; |
| 16 |
} |
| 17 |
function bkbg_template_form_markup($body,$a,$fields){ |
| 18 |
// Prevent another installed CF7 plugin from attaching a second submit handler. |
| 19 |
$body=str_replace('wpcf7','bkbg-tpl-cf7',$body); |
| 20 |
$schema=array();foreach($a['behavior']['formFields']??array() as $f){$name=sanitize_key($f['name']??'');$type=$f['type']??'text';if(!$name||!in_array($type,array('text','email','tel','number','textarea','select'),true))continue;$schema[]=array('name'=>$name,'type'=>$type,'required'=>!empty($fields[$f['requiredField']??'']['value']));} |
| 21 |
if(!$schema)return $body; |
| 22 |
$config=array('fields'=>$schema,'subject'=>sanitize_text_field($a['behavior']['subject']??'Website contact form')); |
| 23 |
$token=base64_encode(wp_json_encode($config));$sig=hash_hmac('sha256',$token,wp_salt('auth')); |
| 24 |
$attrs=' data-bkbg-form="1" data-bkbg-endpoint="'.esc_url(rest_url('blockenberg/v1/template-contact')).'" data-bkbg-schema="'.esc_attr($token).'" data-bkbg-signature="'.esc_attr($sig).'" data-bkbg-success="'.esc_attr($a['behavior']['successMessage']??'Thank you! Your message has been sent.').'" data-bkbg-error="'.esc_attr($a['behavior']['errorMessage']??'Unable to send your message. Please try again.').'"'; |
| 25 |
$body=preg_replace('/<form\b/', '<form'.$attrs, $body,1); |
| 26 |
$extra='<label class="bkbg-template-form-honeypot" aria-hidden="true">Website<input type="text" name="bkbg_website" tabindex="-1" autocomplete="off"></label><div class="bkbg-template-form-result" role="status" aria-live="polite" hidden></div>'; |
| 27 |
return str_replace('</form>',$extra.'</form>',$body); |
| 28 |
} |
| 29 |
add_action('rest_api_init',function(){register_rest_route('blockenberg/v1','/template-contact',array('methods'=>'POST','permission_callback'=>'__return_true','callback'=>'bkbg_template_form_submit'));}); |
| 30 |
function bkbg_template_form_submit($request){ |
| 31 |
$data=$request->get_json_params();if(!is_array($data))return new WP_Error('invalid_form','Invalid form.',array('status'=>400)); |
| 32 |
$token=$data['schema']??'';$sig=$data['signature']??''; |
| 33 |
if(!is_string($token)||strlen($token)>12000||!is_string($sig)||!hash_equals(hash_hmac('sha256',$token,wp_salt('auth')),$sig))return new WP_Error('invalid_form','Invalid form.',array('status'=>400)); |
| 34 |
$config=json_decode(base64_decode($token,true),true);if(!is_array($config)||empty($config['fields']))return new WP_Error('invalid_form','Invalid form.',array('status'=>400)); |
| 35 |
if(!empty($data['website']))return rest_ensure_response(array('success'=>true)); |
| 36 |
$key='bkbg_tpl_form_'.hash('sha256',$_SERVER['REMOTE_ADDR']??'unknown');$count=(int)get_transient($key);if($count>=5)return new WP_Error('rate_limit','Please try again in a minute.',array('status'=>429));set_transient($key,$count+1,60); |
| 37 |
$values=is_array($data['values']??null)?$data['values']:array();$body='';$reply=''; |
| 38 |
foreach($config['fields'] as $field){$name=$field['name'];$raw=$values[$name]??'';if(!is_scalar($raw)||strlen((string)$raw)>10000)return new WP_Error('invalid_field','Invalid field.',array('status'=>400));$value=sanitize_textarea_field((string)$raw); |
| 39 |
if($field['required']&&trim($value)==='')return new WP_Error('required_field','Please complete all required fields.',array('status'=>400)); |
| 40 |
if($field['type']==='email'&&$value!==''){if(!is_email($value))return new WP_Error('invalid_email','Please enter a valid email address.',array('status'=>400));$reply=sanitize_email($value);} |
| 41 |
if($field['type']==='number'&&$value!==''&&!is_numeric($value))return new WP_Error('invalid_number','Please enter a valid number.',array('status'=>400)); |
| 42 |
$body.=$name.":\n".$value."\n\n"; |
| 43 |
} |
| 44 |
$headers=$reply?array('Reply-To: '.$reply):array();$ok=wp_mail(get_option('admin_email'),sanitize_text_field($config['subject']),$body,$headers); |
| 45 |
return $ok?rest_ensure_response(array('success'=>true)):new WP_Error('mail_failed','Unable to send your message.',array('status'=>500)); |
| 46 |
} |
| 47 |
|
| 48 |
/** Typed decorative SVG section boundaries. No arbitrary HTML is accepted. */ |
| 49 |
function bkbg_template_shapes($a){ |
| 50 |
$out=''; |
| 51 |
foreach(($a['shapeDividers']??array()) as $shape){ |
| 52 |
if(!is_array($shape)||!empty($shape['disabled']))continue; |
| 53 |
$position=($shape['position']??'')==='top'?'top':'bottom'; |
| 54 |
$view=preg_match('/^[0-9. ,\-]+$/',$shape['viewBox']??'')?$shape['viewBox']:'0 0 1000 100'; |
| 55 |
$color=sanitize_hex_color($shape['color']??'');$height=max(0,min(1000,(float)($shape['height']??0))); |
| 56 |
$out.='<div class="bkbg-tpl-shape bkbg-tpl-shape-'.$position.'" data-negative="'.esc_attr(($shape['negative']??'false')==='true'?'true':'false').'" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="'.esc_attr($view).'" preserveAspectRatio="none"'.($height?' style="height:'.$height.'px"':'').'>'; |
| 57 |
foreach(($shape['paths']??array()) as $path)$out.='<path class="'.esc_attr($path['classes']??'bkbg-tpl-shape-fill').'" d="'.esc_attr($path['d']??'').'"'.($color?' style="fill:'.esc_attr($color).'"':'').'></path>'; |
| 58 |
$out.='</svg></div>'; |
| 59 |
} |
| 60 |
return $out; |
| 61 |
} |
| 62 |
|