PluginProbe
Block Animations, Motion & Scroll Effects – Ghost Kit / 3.7.2
Block Animations, Motion & Scroll Effects – Ghost Kit v3.7.2
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.7.2, at gutenberg/blocks/form/block.php

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