PluginProbe ʕ •ᴥ•ʔ
Kirki – Freeform Page Builder, Website Builder & Customizer / 6.2.1
Kirki – Freeform Page Builder, Website Builder & Customizer v6.2.1
6.2.1 6.2.0 6.1.1 6.1.0 6.0.14 6.0.13 6.0.12 6.0.11 6.0.10 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.19 4.0.20 4.0.21 4.0.22 4.0.23 4.0.24 4.1 4.2.0 5.0.0 5.1.0 5.1.1 5.2.0 5.2.1 5.2.2 5.2.3 6.0.0 trunk 3.0.40 3.0.41 3.0.42 3.0.43 3.0.44 3.0.45 3.1.0 3.1.1 3.1.2
kirki / ComponentLibrary / controller / CompLibFormHandler.php
kirki / ComponentLibrary / controller Last commit date
CompLibFormHandler.php 3 days ago ElementGenerator.php 3 days ago ShowUserMetadata.php 3 months ago
CompLibFormHandler.php
649 lines
1 <?php
2
3 namespace KirkiComponentLib\Controller;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit; // Exit if accessed directly.
7 }
8
9 use Kirki\Ajax\Page;
10 use Kirki\HelperFunctions;
11 use WP_REST_Server;
12 use WP_REST_Controller;
13 use WP_REST_Response;
14
15 class CompLibFormHandler extends WP_REST_Controller {
16
17 protected $namespace = KIRKI_COMPONENT_LIBRARY_APP_PREFIX . '/v1';
18
19 public function __construct() {
20 $this->init_rest_api_endpoint( 'kirki-login', WP_REST_Server::CREATABLE, array( $this, 'handle_login' ), array( $this, 'guest_permissions_check' ) );
21 $this->init_rest_api_endpoint( 'kirki-register', WP_REST_Server::CREATABLE, array( $this, 'handle_register' ), array( $this, 'guest_permissions_check' ) );
22 $this->init_rest_api_endpoint( 'kirki-forgot-password', WP_REST_Server::CREATABLE, array( $this, 'handle_forgot_password' ), array( $this, 'guest_permissions_check' ) );
23 $this->init_rest_api_endpoint( 'kirki-change-password', WP_REST_Server::CREATABLE, array( $this, 'handle_change_password' ), array( $this, 'guest_permissions_check' ) );
24 $this->init_rest_api_endpoint( 'kirki-retrieve-username', WP_REST_Server::CREATABLE, array( $this, 'handle_retrieve_username' ), array( $this, 'guest_permissions_check' ) );
25 $this->init_rest_api_endpoint( 'kirki-comment', WP_REST_Server::CREATABLE, array( $this, 'handle_post_comment' ), array( $this, 'comment_permissions_check' ) );
26 }
27
28 public function init_rest_api_endpoint( $endpoint, $methods, $callback, $permission_callback = null ) {
29 add_action(
30 'rest_api_init',
31 function () use ( $endpoint, $methods, $callback, $permission_callback ) {
32 register_rest_route(
33 $this->namespace,
34 '/' . $endpoint,
35 array(
36 array(
37 'methods' => $methods,
38 'callback' => $callback,
39 'permission_callback' => $permission_callback ? $permission_callback : array( $this, 'get_item_permissions_check' ),
40 'args' => $this->get_endpoint_args_for_item_schema( $methods ),
41 ),
42 'schema' => array( $this, 'get_item_schema' ),
43 )
44 );
45 }
46 );
47 }
48
49 public function get_item_permissions_check( $request ) {
50 return true;
51 }
52
53 public function guest_permissions_check( $request ) {
54 return true;
55 }
56
57 public function comment_permissions_check( $request ) {
58 if ( ! is_user_logged_in() && get_option( 'default_comment_status' ) !== 'open' ) {
59 return new \WP_Error(
60 'rest_forbidden',
61 __( 'You must be logged in to post comments.' ),
62 array( 'status' => 401 )
63 );
64 }
65 return true;
66 }
67
68 private function wp_unique_username( $username, $suffix = 1 ) {
69 $original_username = $username;
70 while ( username_exists( $username ) ) {
71 $username = sprintf( '%s_%d', $original_username, $suffix++ );
72 }
73 return $username;
74 }
75
76 private function validate_meta_field( $field_name ) {
77 $allowed_meta_fields = apply_filters( 'kirki_allowed_registration_meta_fields', array(
78 'first_name',
79 'last_name',
80 'phone',
81 'company',
82 'address',
83 'city',
84 'state',
85 'country',
86 'zip',
87 ) );
88
89 if ( ! in_array( $field_name, $allowed_meta_fields, true ) ) {
90 return false;
91 }
92
93 if ( preg_match( '/[^a-z0-9_-]/i', $field_name ) ) {
94 return false;
95 }
96
97 return true;
98 }
99
100 /**
101 * Verify that the submitted emailSubject + emailBody were signed by the server
102 * at page-render time and have not been tampered with.
103 *
104 * IMPORTANT: $body_raw must be the raw JSON string as received from the request —
105 * never a re-encoded array. Re-encoding can produce different output than the
106 * original wp_json_encode() call, breaking the HMAC comparison.
107 *
108 * @param string $subject The email subject string.
109 * @param string $body_raw The raw emailBody JSON string from the request.
110 * @param string $signature The HMAC signature to verify against.
111 * @return bool
112 */
113 private function verify_email_template_signature( $subject, $body_raw, $signature ) {
114 if ( empty( $signature ) ) {
115 return false;
116 }
117
118 // Use the raw string directly — same as what was signed in ElementGenerator.
119 // Do NOT json_decode then re-encode here.
120 $payload = $subject . '|' . $body_raw;
121 $secret = AUTH_KEY . AUTH_SALT;
122 $expected = hash_hmac( 'sha256', $payload, $secret );
123
124 return hash_equals( $expected, $signature );
125 }
126
127 /**
128 * Build the email body from a verified emailBody definition.
129 * Chip values are resolved from a fixed server-controlled map.
130 *
131 * @param array $email_body_array
132 * @param array $chip_data
133 * @return string
134 */
135 private function build_email_body( array $email_body_array, array $chip_data ) {
136 $email_body = '';
137 foreach ( $email_body_array as $body_data ) {
138 if ( ! isset( $body_data['type'], $body_data['value'] ) ) {
139 continue;
140 }
141 if ( $body_data['type'] === 'text' ) {
142 $email_body .= $body_data['value'];
143 } elseif ( $body_data['type'] === 'chip' && isset( $chip_data[ $body_data['value'] ] ) ) {
144 $email_body .= $chip_data[ $body_data['value'] ];
145 }
146 }
147 return $email_body;
148 }
149
150 public function handle_post_comment( $request ) {
151 $form_data = $request->get_body_params();
152 $transient_name = $this->validate_nonce( 'kirki-comment' ); // note: typo fix from $transiet_name
153
154 // FIX 3: decode entities *before* sanitising. sanitize_text_field() strips
155 // tags but leaves entity-encoded markup (`&lt;script&gt;`) intact, which is
156 // how markup used to survive the write and reach the renderer.
157 $comment = isset( $form_data['comment'] ) ? sanitize_text_field( html_entity_decode( (string) $form_data['comment'], ENT_QUOTES | ENT_HTML5, 'UTF-8' ) ) : '';
158 $post_id = isset( $form_data['post_id'] ) ? absint( $form_data['post_id'] ) : 0;
159 $comment_parent = isset( $form_data['comment_parent'] ) ? absint( $form_data['comment_parent'] ) : 0;
160 $user_id = get_current_user_id();
161 $user = $user_id ? get_user_by( 'ID', $user_id ) : null;
162
163 // Resolve author identity.
164 if ( $user ) {
165 $name = $user->get( 'display_name' );
166 $email = $user->get( 'user_email' );
167 } else {
168 // Anonymous commenter: require name + valid email supplied in the form.
169 $name = isset( $form_data['name'] ) ? sanitize_text_field( html_entity_decode( (string) $form_data['name'], ENT_QUOTES | ENT_HTML5, 'UTF-8' ) ) : '';
170 $email = isset( $form_data['email'] ) ? sanitize_email( $form_data['email'] ) : '';
171
172 if ( empty( $name ) || empty( $email ) || ! is_email( $email ) ) {
173 return new WP_REST_Response(
174 array( 'message' => 'Name and a valid email address are required.' ),
175 400
176 );
177 }
178 }
179
180 $existing_comment_id = isset( $form_data['comment_id'] ) ? absint( $form_data['comment_id'] ) : 0;
181 $is_edit = $existing_comment_id !== 0;
182 $collection_type = isset( $form_data['collection_type'] ) ? sanitize_text_field( $form_data['collection_type'] ) : '';
183
184 // -----------------------------------------------------------------------
185 // EDIT PATH
186 // -----------------------------------------------------------------------
187 if ( $is_edit ) {
188 // FIX 1: Editing always requires an authenticated session.
189 if ( ! is_user_logged_in() ) {
190 return new WP_REST_Response(
191 array( 'message' => 'You must be logged in to edit a comment.' ),
192 401
193 );
194 }
195
196 $existing_comment = get_comment( $existing_comment_id );
197
198 if ( ! $existing_comment ) {
199 return new WP_REST_Response(
200 array( 'message' => 'Comment not found.' ),
201 404
202 );
203 }
204
205 // FIX 1 (cont.): strict ownership — user_id 0 must never match.
206 $is_owner = ( $user_id !== 0 && (int) $existing_comment->user_id === $user_id );
207 $is_moderator = current_user_can( 'moderate_comments' );
208
209 if ( ! $is_owner && ! $is_moderator ) {
210 return new WP_REST_Response(
211 array( 'message' => 'You are not authorized to edit this comment.' ),
212 403
213 );
214 }
215
216 $date = current_time( 'mysql' );
217
218 // FIX 3 (cont.): go through wp_update_comment() instead of a raw
219 // $wpdb->update(), so the same kses/comment filters that guard
220 // wp_new_comment() also guard edits.
221 $updated = wp_update_comment(
222 array(
223 'comment_ID' => $existing_comment_id,
224 'comment_content' => $comment,
225 'comment_date' => $date,
226 'comment_date_gmt' => get_gmt_from_date( $date ),
227 ),
228 true
229 );
230
231 if ( is_wp_error( $updated ) ) {
232 return new WP_REST_Response(
233 array( 'message' => $updated->get_error_message() ),
234 400
235 );
236 }
237
238 apply_filters(
239 'kirki_comment_added-' . $collection_type,
240 array(
241 'comment_ID' => $existing_comment_id,
242 'user_id' => $user_id,
243 'form_data' => $form_data,
244 )
245 );
246
247 delete_transient( $transient_name );
248 return new WP_REST_Response( array( 'message' => 'Comment updated.' ), 200 );
249 }
250
251 // -----------------------------------------------------------------------
252 // INSERT PATH
253 // -----------------------------------------------------------------------
254
255 // FIX 2: Build the comment array without hardcoding comment_approved=1,
256 // then route through wp_new_comment() so WordPress moderation, spam
257 // filters (Akismet, etc.), and flood checks all apply normally.
258 $comment_data = array(
259 'comment_post_ID' => $post_id,
260 'user_id' => $user_id,
261 'comment_author' => $name,
262 'comment_author_email' => $email,
263 'comment_author_IP' => isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '',
264 'comment_agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '',
265 'comment_content' => $comment,
266 'comment_parent' => $comment_parent,
267 );
268
269 $comment_data = apply_filters( 'kirki_comment-' . $collection_type, $comment_data );
270
271 // wp_new_comment() runs duplicate/flood/spam checks, fires hooks, and
272 // respects the site's moderation settings.
273 $comment_id = wp_new_comment( $comment_data, true ); // true = return WP_Error on failure
274
275 if ( is_wp_error( $comment_id ) ) {
276 return new WP_REST_Response(
277 array( 'message' => $comment_id->get_error_message() ),
278 400
279 );
280 }
281
282 if ( ! $comment_id ) {
283 return new WP_REST_Response(
284 array( 'message' => 'Failed to add comment.' ),
285 400
286 );
287 }
288
289 apply_filters(
290 'kirki_comment_added-' . $collection_type,
291 array(
292 'comment_ID' => $comment_id,
293 'user_id' => $user_id,
294 'form_data' => $form_data,
295 )
296 );
297
298 delete_transient( $transient_name );
299 return new WP_REST_Response( array( 'message' => 'Comment added.' ), 200 );
300 }
301
302
303
304 public function handle_login( $request ) {
305 $form_data = $request->get_body_params();
306 $transiet_name = $this->validate_nonce( 'kirki-login' );
307
308 $username = isset( $form_data['username'] ) ? sanitize_text_field( $form_data['username'] ) : '';
309 $password = isset( $form_data['password'] ) ? sanitize_text_field( $form_data['password'] ) : '';
310 $email = isset( $form_data['email'] ) ? sanitize_email( $form_data['email'] ) : '';
311
312 if ( strlen( $username ) === 0 && isset( $form_data['email'] ) && strlen( $email ) > 0 ) {
313 $user = get_user_by( 'email', $email );
314 if ( $user ) {
315 $username = $user->get( 'user_login' );
316 } else {
317 $response = array(
318 'message' => 'Invalid username or password',
319 );
320 return new WP_REST_Response( $response, 401 );
321 }
322 }
323
324 if (
325 isset( $username ) && strlen( $username ) > 0 &&
326 isset( $password ) && strlen( $password ) > 0
327 ) {
328 $user = wp_signon(
329 array(
330 'user_login' => $username,
331 'user_password' => $password,
332 'remember' => true,
333 )
334 );
335
336 if ( is_wp_error( $user ) ) {
337 $response = array(
338 'message' => 'Invalid username or password',
339 );
340 return new WP_REST_Response( $response, 401 );
341 }
342 $response = array(
343 'message' => 'User logged in',
344 'user' => array(
345 'username' => $user->get( 'user_login' ),
346 'id' => $user->get( 'ID' ),
347 'display_name' => $user->get( 'display_name' ),
348 'email' => $user->get( 'user_email' ),
349 'user_type' => $user->get( 'user_type' ),
350 ),
351 );
352 delete_transient( $transiet_name );
353 return new WP_REST_Response( $response, 200 );
354 }
355 $response = array(
356 'message' => 'Invalid form data',
357 );
358 return new WP_REST_Response( $response, 400 );
359 }
360
361 public function handle_register( $request ) {
362 $can_register = get_option( 'users_can_register' );
363 if ( $can_register !== '1' ) {
364 $response = array(
365 'message' => 'User not allowed to register',
366 );
367 return new WP_REST_Response( $response, 500 );
368 };
369
370 $form_data = $request->get_body_params();
371 $transiet_name = $this->validate_nonce( 'kirki-register' );
372
373 $username = isset( $form_data['username'] ) ? sanitize_text_field( $form_data['username'] ) : '';
374 $email = isset( $form_data['email'] ) ? sanitize_email( $form_data['email'] ) : '';
375 $password = isset( $form_data['password'] ) ? sanitize_text_field( $form_data['password'] ) : '';
376
377 if ( strlen( $email ) > 0 && strlen( $username ) === 0 ) {
378 preg_match( '/^(.*?)@/', $email, $matches );
379 $username = $this->wp_unique_username( $matches[1] );
380 }
381
382 $user_data = array(
383 'user_login' => $username,
384 'user_email' => $email,
385 'user_pass' => $password,
386 'meta_input' => array(),
387 );
388
389 foreach ( $form_data as $name => $value ) {
390 if ( $name !== 'username' && $name !== 'email' && $name !== 'password' && $name !== 'confirm_password' ) {
391 if ( $this->validate_meta_field( $name ) ) {
392 $user_data['meta_input'][ KIRKI_COMPONENT_LIBRARY_APP_PREFIX . '_' . $name ] = sanitize_text_field( $value );
393 }
394 }
395 }
396
397 if (
398 isset( $username ) && strlen( $username ) > 0
399 && isset( $email ) && strlen( $email ) > 0 &&
400 isset( $password ) && strlen( $password ) > 0
401 ) {
402 $id = wp_insert_user( $user_data );
403
404 if ( is_wp_error( $id ) ) {
405 $response = array(
406 'message' => $id->errors[ array_key_first( $id->errors ) ],
407 );
408 return new WP_REST_Response( $response, 500 );
409 }
410
411 wp_new_user_notification( $id, null, 'both' );
412 $response = array(
413 'message' => 'User created',
414 'user_id' => $id,
415 );
416 delete_transient( $transiet_name );
417 return new WP_REST_Response( $response, 200 );
418 }
419 $response = array(
420 'message' => 'Invalid form data',
421 );
422 return new WP_REST_Response( $response, 400 );
423 }
424
425 public function handle_forgot_password( $request ) {
426 $form_data = $request->get_body_params();
427 $transiet_name = $this->validate_nonce( 'kirki-forgot-password' );
428
429 $email = isset( $form_data['email'] ) ? sanitize_email( $form_data['email'] ) : '';
430 $username = isset( $form_data['username'] ) ? sanitize_text_field( $form_data['username'] ) : '';
431
432 if ( strlen( $username ) === 0 && isset( $form_data['email'] ) && strlen( $email ) > 0 ) {
433 $user = get_user_by( 'email', $email );
434
435 if ( ! $user ) {
436 return new WP_REST_Response( array( 'message' => 'If an account exists with this email, you will receive a password reset link.' ), 200 );
437 }
438
439 $username = $user->get( 'user_login' );
440 }
441
442 if ( empty( $username ) ) {
443 return new WP_REST_Response( array( 'message' => 'Invalid request' ), 400 );
444 }
445
446 if ( isset( $username ) && strlen( $username ) > 0 ) {
447 $user = get_user_by( 'login', $username );
448
449 if ( ! $user ) {
450 $response = array(
451 'message' => 'If an account exists with this information, you will receive a password reset link.',
452 );
453 return new WP_REST_Response( $response, 200 );
454 }
455
456 $user_email = $user->get( 'user_email' );
457 if($email !== $user_email) {
458 $response = array(
459 'message' => 'If an account exists with this information, you will receive a password reset link.',
460 );
461 return new WP_REST_Response( $response, 200 );
462 }
463 $email = $user_email;
464
465 $key = get_password_reset_key( $user );
466 if ( is_wp_error( $key ) ) {
467 $response = array(
468 'message' => $key->get_error_message(),
469 );
470 return new WP_REST_Response( $response, 500 );
471 }
472
473 // Prepare email content.
474 $url = HelperFunctions::get_utility_page_url( Page::TYPE_FORGOT_PASSWORD );
475
476 $username = $user->user_login;
477 $chip_data = array(
478 'username' => $username,
479 'email' => $email,
480 'displayname' => $user->display_name,
481 'sitename' => get_bloginfo( 'name' ),
482 'reset_link' => "$url?action=rp&key=$key&login=" . rawurlencode( $username ),
483 );
484
485 $email_subject = isset( $form_data['emailSubject'] ) ? $form_data['emailSubject'] : '';
486 $email_body_raw = isset( $form_data['emailBody'] ) ? $form_data['emailBody'] : '[]';
487 $email_signature = isset( $form_data['emailSignature'] ) ? $form_data['emailSignature'] : '';
488
489 if ( ! $this->verify_email_template_signature( $email_subject, $email_body_raw, $email_signature ) ) {
490 wp_send_json_error( array( 'message' => 'Invalid request' ), 400 );
491 exit;
492 }
493
494 $email_body_array = json_decode( $email_body_raw, true );
495 if ( ! is_array( $email_body_array ) ) {
496 $email_body_array = array();
497 }
498
499 $email_body = $this->build_email_body( $email_body_array, $chip_data );
500
501 $email_body = nl2br( $email_body );
502
503 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
504
505 // Send custom email.
506 apply_filters( 'kirki_element_smtp', '' );
507 $sent = wp_mail( $email, sanitize_text_field( $email_subject ), $email_body, $headers );
508
509 if ( $sent ) {
510 $response = array(
511 'message' => 'Email sent',
512 );
513 delete_transient( $transiet_name );
514 return new WP_REST_Response( $response, 200 );
515 } else {
516 $response = array(
517 'message' => 'Failed to send email',
518 );
519 return new WP_REST_Response( $response, 500 );
520 }
521 }
522
523 $response = array(
524 'message' => 'Invalid request',
525 );
526 return new WP_REST_Response( $response, 400 );
527 }
528
529 public function handle_change_password( $request ) {
530 $form_data = $request->get_body_params();
531 $transiet_name = $this->validate_nonce( 'kirki-change-password' );
532
533 $username = isset( $form_data['username'] ) ? sanitize_text_field( $form_data['username'] ) : '';
534 $reset_key = isset( $form_data['reset_key'] ) ? sanitize_text_field( $form_data['reset_key'] ) : '';
535 $new_password = isset( $form_data['new_password'] ) ? sanitize_text_field( $form_data['new_password'] ) : '';
536 $confirm_password = isset( $form_data['confirm_password'] ) ? sanitize_text_field( $form_data['confirm_password'] ) : '';
537
538 if ( empty( $reset_key ) || empty( $username ) || empty( $new_password ) || empty( $confirm_password ) ) {
539 wp_send_json_error( array( 'message' => 'Invalid request.' ), 400 );
540 exit;
541 }
542
543 if ( $new_password !== $confirm_password ) {
544 wp_send_json_error( array( 'message' => 'Passwords do not match.' ), 400 );
545 exit;
546 }
547
548 $user = check_password_reset_key( $reset_key, $username );
549
550 if ( is_wp_error( $user ) ) {
551 wp_send_json_error( array( 'message' => $user->get_error_message() ), 400 );
552 exit;
553 }
554
555 wp_set_password( $new_password, $user->ID );
556 delete_transient( $transiet_name );
557 wp_send_json_success( array( 'message' => 'Password reset successfully.' ) );
558 exit;
559 }
560
561 public function handle_retrieve_username( $request ) {
562 $form_data = $request->get_body_params();
563 $transiet_name = $this->validate_nonce( 'kirki-retrieve-username' );
564
565 $email = isset( $form_data['email'] ) ? sanitize_email( $form_data['email'] ) : '';
566
567 if ( empty( $email ) || ! is_email( $email ) ) {
568 wp_send_json_error( array( 'message' => 'Invalid email address.' ), 400 );
569 exit;
570 }
571
572 $user = get_user_by( 'email', $email );
573
574 if ( ! $user ) {
575 wp_send_json_success( array( 'message' => 'If an account exists with this email, you will receive your username.' ) );
576 exit;
577 }
578
579 $username = $user->user_login;
580 $chip_data = array(
581 'username' => $username,
582 'email' => $email,
583 'displayname' => $user->display_name,
584 'sitename' => get_bloginfo( 'name' ),
585 );
586
587 $email_subject = isset( $form_data['emailSubject'] ) ? $form_data['emailSubject'] : '';
588 $email_body_raw = isset( $form_data['emailBody'] ) ? $form_data['emailBody'] : '[]';
589 $email_signature = isset( $form_data['emailSignature'] ) ? $form_data['emailSignature'] : '';
590
591 if ( ! $this->verify_email_template_signature( $email_subject, $email_body_raw, $email_signature ) ) {
592 wp_send_json_error( array( 'message' => 'Invalid request' ), 400 );
593 exit;
594 }
595
596 $email_body_array = json_decode( $email_body_raw, true );
597 if ( ! is_array( $email_body_array ) ) {
598 $email_body_array = array();
599 }
600
601 $email_body = $this->build_email_body( $email_body_array, $chip_data );
602
603 $email_body = nl2br( $email_body );
604
605 $headers = array( 'Content-Type: text/html; charset=UTF-8' );
606
607 apply_filters( 'kirki_element_smtp', '' );
608 $email_sent = wp_mail( $email, sanitize_text_field( $email_subject ), $email_body, $headers );
609
610 if ( ! $email_sent ) {
611 wp_send_json_error( array( 'message' => 'Failed to send email. Please try again later.' ), 500 );
612 exit;
613 }
614
615 delete_transient( $transiet_name );
616 wp_send_json_success( array( 'message' => 'Username sent to your email address.' ) );
617 exit;
618 }
619
620 /**
621 * Validate the nonce from the request header and return true on success.
622 * Exits with an error response on failure.
623 *
624 * @param string $element_name
625 * @return true
626 */
627 public function validate_nonce( $element_name ) {
628 $nonce = isset( $_SERVER['HTTP_X_WP_ELEMENT_NONCE'] )
629 ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_ELEMENT_NONCE'] ) )
630 : null;
631
632 if ( ! $nonce ) {
633 wp_send_json_error( 'Missing nonce', 400 );
634 exit;
635 }
636
637 $action = KIRKI_COMPONENT_LIBRARY_APP_PREFIX . '_' . $element_name;
638
639 if ( ! wp_verify_nonce( $nonce, $action ) ) {
640 wp_send_json_error( 'Not authorized', 400 );
641 exit;
642 }
643
644 return true;
645 }
646 }
647
648 new CompLibFormHandler();
649