PluginProbe
Block Animations, Motion & Scroll Effects – Ghost Kit / 3.4.1
Block Animations, Motion & Scroll Effects – Ghost Kit v3.4.1
3.7.2 3.7.1 3.7.0 3.6.1 trunk 1.6.3 2.25.0 3.3.0 3.3.1 3.3.2 3.3.3 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.6.0
ghostkit / gutenberg / blocks / form / block.php

block.php in Block Animations, Motion & Scroll Effects – Ghost Kit 3.4.1, at gutenberg/blocks/form/block.php

599 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Form block.
4 *
5 * @package ghostkit
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 require_once ghostkit()->plugin_path . 'gutenberg/blocks/form/field-attributes/index.php';
13 require_once ghostkit()->plugin_path . 'gutenberg/blocks/form/field-label/index.php';
14 require_once ghostkit()->plugin_path . 'gutenberg/blocks/form/field-description/index.php';
15
16 /**
17 * Class GhostKit_Form_Block
18 */
19 class GhostKit_Form_Block {
20 /**
21 * Unique ID.
22 *
23 * @var integer
24 */
25 public $form_id = 0;
26
27 /**
28 * Form post data after submit.
29 *
30 * @var array
31 */
32 public $form_post_data = array();
33
34 /**
35 * Default form block attribute values.
36 *
37 * @var array
38 */
39 public $default_attrs = array();
40
41 /**
42 * GhostKit_Form_Block constructor.
43 */
44 public function __construct() {
45 add_action( 'template_redirect', array( $this, 'get_post_data' ) );
46 add_action( 'wp_footer', array( $this, 'reset_post_data' ) );
47
48 add_action( 'init', array( $this, 'init' ) );
49
50 add_action( 'gkt_assets_store', array( $this, 'assets_store' ) );
51
52 add_action( 'gkt_form_email_before_send', array( $this, 'mail_before_send' ) );
53 add_action( 'gkt_form_email_after_send', array( $this, 'mail_after_send' ) );
54
55 add_filter( 'render_block', array( $this, 'maybe_submit_form' ), 10, 2 );
56 }
57
58 /**
59 * Save post data and redirect after form submitted.
60 */
61 public function get_post_data() {
62 // phpcs:disable
63 if ( ! is_admin() && isset( $_POST['ghostkit_form_id'] ) ) {
64 $this->form_post_data = $_POST;
65 }
66 // phpcs:enable
67 }
68
69 /**
70 * Reset post data.
71 */
72 public function reset_post_data() {
73 if ( ! empty( $this->form_post_data ) ) {
74 $this->form_post_data = array();
75 }
76 }
77
78 /**
79 * Init.
80 */
81 public function init() {
82 $from_email = '';
83 $admin_email = get_option( 'admin_email' );
84 $blogname = get_option( 'blogname' );
85
86 // phpcs:ignore
87 if ( isset( $_SERVER[ 'SERVER_NAME' ] ) ) {
88 // phpcs:ignore
89 $sitename = strtolower( $_SERVER[ 'SERVER_NAME' ] );
90 } else {
91 $site_url = site_url();
92 $site_url_parts = wp_parse_url( $site_url );
93 $sitename = $site_url_parts['host'];
94 }
95
96 if ( substr( $sitename, 0, 4 ) === 'www.' ) {
97 $sitename = substr( $sitename, 4 );
98 }
99
100 if ( strpbrk( $admin_email, '@' ) === '@' . $sitename ) {
101 $from_email = $admin_email;
102 } else {
103 $from_email = 'wordpress@' . $sitename;
104 }
105
106 $this->default_attrs = array(
107 'mailAllow' => true,
108 'mailTo' => $admin_email,
109 'mailSubject' => $blogname . ' "{field_subject}"',
110 'mailFrom' => '"' . $blogname . '" <' . $from_email . '>',
111 'mailReplyTo' => '{field_email}',
112 'mailMessage' => '{all_fields}',
113 'confirmationType' => 'message',
114 'confirmationMessage' => esc_html__( 'Thank you for contacting us! We will be in touch with you shortly.', 'ghostkit' ),
115 );
116
117 register_block_type_from_metadata(
118 dirname( __FILE__ ),
119 array(
120 'render_callback' => array( $this, 'block_render' ),
121 'attributes' => array(
122 'mailAllow' => array(
123 'type' => 'boolean',
124 'default' => $this->default_attrs['mailAllow'],
125 ),
126 'mailTo' => array(
127 'type' => 'string',
128 'default' => $this->default_attrs['mailTo'],
129 ),
130 'mailSubject' => array(
131 'type' => 'string',
132 'default' => $this->default_attrs['mailSubject'],
133 ),
134 'mailFrom' => array(
135 'type' => 'string',
136 'default' => $this->default_attrs['mailFrom'],
137 ),
138 'mailReplyTo' => array(
139 'type' => 'string',
140 'default' => $this->default_attrs['mailReplyTo'],
141 ),
142 'mailMessage' => array(
143 'type' => 'string',
144 'default' => $this->default_attrs['mailMessage'],
145 ),
146
147 'confirmationType' => array(
148 'type' => 'string',
149 'default' => $this->default_attrs['confirmationType'],
150 ),
151 'confirmationMessage' => array(
152 'type' => 'string',
153 'default' => $this->default_attrs['confirmationMessage'],
154 ),
155 'confirmationRedirect' => array(
156 'type' => 'string',
157 ),
158
159 'className' => array(
160 'type' => 'string',
161 ),
162 ),
163 )
164 );
165 }
166
167 /**
168 * Register gutenberg block output
169 *
170 * @param array $attributes - block attributes.
171 * @param string $inner_blocks - inner blocks.
172 *
173 * @return string
174 */
175 public function block_render( $attributes, $inner_blocks ) {
176 $class = 'ghostkit-form';
177
178 if ( isset( $attributes['className'] ) ) {
179 $class .= ' ' . $attributes['className'];
180 }
181
182 $form_slug = 'ghostkit_form_' . $this->form_id;
183 $form_id = 'gkt_form_' . hash( 'crc32b', $form_slug );
184
185 $this->form_id += 1;
186
187 $url = add_query_arg( array() );
188 $frag = strstr( $url, '#' );
189
190 if ( $frag ) {
191 $url = substr( $url, 0, -strlen( $frag ) );
192 }
193
194 $url .= '#' . $form_id;
195
196 // Add unique slug to id and for attributes.
197 $inner_blocks = str_replace( 'id="', 'id="' . $form_id . '_', $inner_blocks );
198 $inner_blocks = str_replace( 'for="', 'for="' . $form_id . '_', $inner_blocks );
199
200 // Google reCaptcha.
201 $recaptcha_site_key = get_option( 'ghostkit_google_recaptcha_api_site_key' );
202 $recaptcha_secret_key = get_option( 'ghostkit_google_recaptcha_api_secret_key' );
203
204 ob_start();
205 // Honeypot protection.
206 ?>
207 <input aria-label="<?php echo esc_attr__( 'Verify your Email', 'ghostkit' ); ?>" type="email" name="ghostkit_verify_email" autocomplete="off" placeholder="<?php echo esc_attr__( 'Email', 'ghostkit' ); ?>" tabindex="-1">
208 <?php
209
210 // Add `__` prefix to prevent conflict with form id attribute duplicate.
211 wp_nonce_field( 'ghostkit_form', '__' . $form_id );
212 ?>
213 <input type="hidden" name="ghostkit_form_id" value="<?php echo esc_attr( $form_id ); ?>">
214 <?php
215 if ( $recaptcha_site_key && $recaptcha_secret_key ) {
216 ?>
217 <input type="hidden" name="ghostkit_form_google_recaptcha" />
218 <?php
219 }
220
221 $output = $inner_blocks . ob_get_clean();
222
223 $wrapper_attributes = get_block_wrapper_attributes(
224 array(
225 'method' => 'POST',
226 'name' => 'ghostkit-form',
227 'action' => esc_url( $url ),
228 'class' => $class,
229 'id' => $form_id,
230 )
231 );
232
233 return sprintf( '<form %1$s>%2$s</form>', $wrapper_attributes, $output );
234 }
235
236 /**
237 * Submit form and replace Form block output.
238 *
239 * @param string $block_content - block content.
240 * @param array $block - block attributes.
241 *
242 * @return string
243 */
244 public function maybe_submit_form( $block_content, $block ) {
245 if ( ! isset( $block['blockName'] ) || 'ghostkit/form' !== $block['blockName'] ) {
246 return $block_content;
247 }
248
249 $form_id = '';
250
251 preg_match( '/<input type="hidden" name="ghostkit_form_id" value="(\w+)"/', $block_content, $parse_form_id );
252
253 if ( $parse_form_id && isset( $parse_form_id[1] ) && $parse_form_id[1] ) {
254 $form_id = $parse_form_id[1];
255 }
256
257 if ( ! $form_id ) {
258 return $block_content;
259 }
260
261 $attributes = array_merge(
262 $this->default_attrs,
263 $block['attrs']
264 );
265
266 $class = 'ghostkit-form';
267
268 if ( isset( $attributes['className'] ) ) {
269 $class .= ' ' . $attributes['className'];
270 }
271
272 $success = false;
273 $errors = array();
274 $new_content = '';
275
276 // Form send.
277 if ( isset( $this->form_post_data[ '__' . $form_id ] ) ) {
278 $nonce = sanitize_text_field( wp_unslash( $this->form_post_data[ '__' . $form_id ] ) );
279
280 if ( wp_verify_nonce( $nonce, 'ghostkit_form' ) ) {
281 // check for honeypot.
282 if ( ! $this->verify_honeypot() ) {
283 $errors[] = esc_html__( 'Your actions look suspicious, the form was not submitted.', 'ghostkit' );
284 }
285
286 // validate Google reCaptcha.
287 if ( ! $this->verify_recaptcha() ) {
288 $errors[] = esc_html__( 'Google reCaptcha form verification failed.', 'ghostkit' );
289 }
290
291 if ( ! count( $errors ) ) {
292 $success = true;
293
294 if ( $attributes['mailAllow'] ) {
295 do_action( 'gkt_form_email_before_send', $form_id, $attributes );
296
297 $success = $this->process_mail( $attributes );
298
299 do_action( 'gkt_form_email_after_send', $form_id, $attributes );
300 }
301
302 if ( ! $success ) {
303 $error = error_get_last();
304 $errors[] = isset( $error['message'] ) ? $error['message'] : esc_html__( 'Something went wrong while trying to send the form.', 'ghostkit' );
305 }
306 }
307 } else {
308 $errors[] = esc_html__( 'Something went wrong while trying to send the form.', 'ghostkit' );
309 }
310
311 $this->reset_post_data();
312 }
313
314 // Form submit errors.
315 if ( ! empty( $errors ) ) {
316 ob_start();
317 ?>
318 <div class="ghostkit-alert ghostkit-alert-form ghostkit-alert-form-error"><div class="ghostkit-alert-content">
319 <?php
320 foreach ( $errors as $error ) {
321 echo '<p>' . esc_html( $error ) . '</p>';
322 }
323 ?>
324 </div></div>
325 <?php
326 $new_content = ob_get_clean();
327
328 // Form submit success.
329 } elseif ( $success ) {
330 ob_start();
331 if ( 'redirect' === $attributes['confirmationType'] ) {
332 ?>
333 <div class="ghostkit-alert ghostkit-alert-form ghostkit-alert-form-success"><div class="ghostkit-alert-content"><p>
334 <?php
335 echo wp_kses_post(
336 sprintf(
337 // translators: %s - redirect link.
338 __( 'Your form is successfully submitted. Redirecting to %s...', 'ghostkit' ),
339 '<a href="' . esc_url( $attributes['confirmationRedirect'] ) . '">' . esc_url( $attributes['confirmationRedirect'] ) . '</a>'
340 )
341 );
342 ?>
343 </p></div></div>
344 <script>
345 setTimeout( () => {
346 window.location.href = "<?php echo esc_url( $attributes['confirmationRedirect'] ); ?>";
347 }, 3000 );
348 </script>
349 <?php
350 } else {
351 ?>
352 <div class="ghostkit-alert ghostkit-alert-form ghostkit-alert-form-success"><div class="ghostkit-alert-content"><p>
353 <?php echo wp_kses_post( $attributes['confirmationMessage'] ); ?>
354 </p></div></div>
355 <?php
356 }
357 $new_content = ob_get_clean();
358 }
359
360 if ( $new_content ) {
361 ob_start();
362 ?>
363 <div class="<?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $form_id ); ?>">
364 <?php echo $new_content; // phpcs:ignore ?>
365 </div>
366 <?php
367
368 $this->remove_hash_from_address_bar();
369
370 return ob_get_clean();
371 }
372
373 return $block_content;
374 }
375
376 /**
377 * Add Alert block assets.
378 *
379 * @param string $name - asset name.
380 */
381 public function assets_store( $name ) {
382 if ( 'ghostkit-block-form' === $name ) {
383 GhostKit_Assets::store_used_assets( 'ghostkit-block-alert', true, 'style' );
384 GhostKit_Assets::store_used_assets( 'ghostkit-block-alert', true, 'script' );
385 GhostKit_Assets::store_used_assets( 'ghostkit-block-button', true, 'style' );
386 GhostKit_Assets::store_used_assets( 'ghostkit-block-button', true, 'script' );
387 }
388 }
389
390 /**
391 * Verify Honeypot Field.
392 *
393 * @return bool
394 */
395 private function verify_honeypot() {
396 if ( ! empty( $this->form_post_data['ghostkit_verify_email'] ) ) {
397 return false;
398 }
399
400 return true;
401 }
402
403 /**
404 * Verify Google reCaptcha.
405 *
406 * @return bool
407 */
408 private function verify_recaptcha() {
409 $recaptcha_secret_key = get_option( 'ghostkit_google_recaptcha_api_secret_key' );
410 $recaptcha_site_key = get_option( 'ghostkit_google_recaptcha_api_site_key' );
411
412 // no captcha enabled.
413 if ( ! $recaptcha_secret_key || ! $recaptcha_site_key ) {
414 return true;
415 }
416
417 if ( ! isset( $this->form_post_data['ghostkit_form_google_recaptcha'] ) ) {
418 return false;
419 }
420
421 $token = sanitize_text_field( wp_unslash( $this->form_post_data['ghostkit_form_google_recaptcha'] ) );
422
423 // empty token.
424 if ( ! $token ) {
425 return false;
426 }
427
428 $verify_token_request = wp_remote_post(
429 'https://www.google.com/recaptcha/api/siteverify',
430 array(
431 'timeout' => 30,
432 'body' => array(
433 'secret' => $recaptcha_secret_key,
434 'response' => $token,
435 ),
436 )
437 );
438
439 if ( is_wp_error( $verify_token_request ) ) {
440 return false;
441 }
442
443 $response = wp_remote_retrieve_body( $verify_token_request );
444
445 if ( is_wp_error( $response ) ) {
446 return false;
447 }
448
449 $response = json_decode( $response, true );
450
451 $threshold = apply_filters( 'gkt_recaptcha_threshold', 0.5 );
452 $verified = isset( $response['success'] ) && $response['success'] && 'ghostkit' === $response['action'] && $response['score'] >= $threshold;
453
454 $verified = apply_filters( 'gkt_recaptcha_verify_response', $verified, $response );
455
456 return $verified;
457 }
458
459 /**
460 * Remove hash from address bar when form submitted.
461 * It will solve the problem when you can submit the submitted form data again after page refresh.
462 */
463 public function remove_hash_from_address_bar() {
464 ?>
465 <script type="text/javascript">
466 (function() {
467 if ( window.history.replaceState && window.location.hash ) {
468 const $id = window.location.hash.substring( 1 );
469 const $form = $id ? document.getElementById( $id ) : false;
470
471 window.history.replaceState( null, null, ' ' );
472
473 if ( $form ) {
474 $form.scrollIntoView(true);
475 }
476 }
477 })();
478 </script>
479 <?php
480 }
481
482 /**
483 * Template string with POST data.
484 *
485 * @param string $string - string for template.
486 *
487 * @return string
488 */
489 public function template( $string ) {
490 $all_fields = '';
491
492 // phpcs:ignore
493 foreach ( (array) $this->form_post_data as $name => $val ) {
494 if ( is_array( $val ) && isset( $val['value'] ) ) {
495 $sanitized_label = isset( $val['label'] ) ? sanitize_text_field( wp_unslash( $val['label'] ) ) : '';
496 $sanitized_val = '';
497
498 if ( is_array( $val['value'] ) ) {
499 foreach ( $val['value'] as $val ) {
500 $sanitized_val .= '<li>' . sanitize_textarea_field( wp_unslash( $val ) ) . '</li>';
501 }
502 $sanitized_val = '<ul>' . $sanitized_val . '</ul>';
503 } else {
504 $sanitized_val = sanitize_textarea_field( wp_unslash( $val['value'] ) );
505
506 // Name field support.
507 if ( isset( $val['middle'] ) ) {
508 $sanitized_val .= ' ' . sanitize_textarea_field( wp_unslash( $val['middle'] ) );
509 }
510 if ( isset( $val['last'] ) ) {
511 $sanitized_val .= ' ' . sanitize_textarea_field( wp_unslash( $val['last'] ) );
512 }
513 }
514
515 $string = str_replace( "{{$name}}", $sanitized_val, $string );
516
517 $all_fields .= '
518 <table role="presentation" border="0" cellpadding="0" cellspacing="0" class="field-row"><tbody>
519 <tr><td class="field-row-label">' . ( $sanitized_label ? ( '<strong>' . $sanitized_label . '</strong>' ) : '' ) . '</td></tr>
520 <tr><td class="field-row-value">' . wpautop( $sanitized_val ) . '</td></tr>
521 </tbody></table>
522 ';
523 }
524 }
525
526 $string = str_replace( '{all_fields}', $all_fields, $string );
527
528 return $string;
529 }
530
531 /**
532 * Process email using wp_mail function.
533 *
534 * @param array $attributes - Form block attributes.
535 *
536 * @return boolean
537 */
538 public function process_mail( $attributes ) {
539 // Template all attributes.
540 foreach ( $attributes as $k => $attr ) {
541 if ( is_string( $attr ) ) {
542 $attributes[ $k ] = $this->template( $attr );
543 }
544 }
545
546 // Prepare headers.
547 $headers = array(
548 'Content-Type: text/html; charset=utf-8',
549 "From: {$attributes['mailFrom']}",
550 "Return-Path: {$attributes['mailTo']}",
551 "Reply-To: {$attributes['mailReplyTo']}",
552 );
553
554 // Prepare message.
555 $message = $this->get_mail_html( $attributes );
556
557 return wp_mail( $attributes['mailTo'], $attributes['mailSubject'], $message, $headers );
558 }
559
560 /**
561 * Get mail HTML template.
562 *
563 * @param array $attributes - From block attributes.
564 *
565 * @return string
566 */
567 public function get_mail_html( $attributes ) {
568 ob_start();
569
570 include ghostkit()->plugin_path . 'gutenberg/blocks/form/mail-template/index.php';
571
572 return ob_get_clean();
573 }
574
575 /**
576 * Mail before send.
577 */
578 public function mail_before_send() {
579 add_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
580 }
581
582 /**
583 * Mail after send.
584 */
585 public function mail_after_send() {
586 remove_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
587 }
588
589 /**
590 * Change wp_mail content type to HTML.
591 *
592 * @return string
593 */
594 public function get_content_type() {
595 return 'text/html';
596 }
597 }
598 new GhostKit_Form_Block();
599