PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.81
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.81
51.1.86 51.1.84 51.1.85 51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 All 40 releases
king-addons / includes / widgets / Form_Builder / helpers / Create_Submission.php

Create_Submission.php in King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder 51.1.81, at includes/widgets/Form_Builder/helpers/Create_Submission.php

225 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace King_Addons;
4
5 if (!defined('ABSPATH')) {
6 exit;
7 }
8
9 /**
10 * Stores Form Builder submissions from the public AJAX endpoint.
11 */
12 class Create_Submission
13 {
14
15 /**
16 * Registers submission AJAX hooks and admin meta updates.
17 */
18 public function __construct()
19 {
20 add_action('wp_ajax_king_addons_form_builder_submissions', [$this, 'add_to_submissions']);
21 add_action('wp_ajax_nopriv_king_addons_form_builder_submissions', [$this, 'add_to_submissions']);
22 add_action('save_post', [$this, 'update_submissions_post_meta']);
23 }
24
25 /**
26 * Creates a submission post from a public form request.
27 *
28 * Guests are allowed when the nonce is valid and the submitted page ID
29 * belongs to a published Form Builder source page.
30 *
31 * @return void
32 */
33 public function add_to_submissions()
34 {
35
36 $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
37
38 if (!wp_verify_nonce($nonce, 'king-addons-js')) {
39 wp_send_json_error(array(
40 'message' => esc_html__('Security check failed.', 'king-addons'),
41 ));
42 }
43
44 Form_Builder_Security::guard_spam();
45
46 $sanitized_form_page_id = absint($_POST['form_page_id'] ?? 0);
47 if (!Form_Builder_Security::is_valid_submission_page($sanitized_form_page_id)) {
48 wp_send_json_error(array(
49 'message' => esc_html__('Insufficient permissions.', 'king-addons'),
50 ));
51 }
52
53 $sanitized_form_name = sanitize_text_field(wp_unslash($_POST['form_name'] ?? ''));
54 $form_content = isset($_POST['form_content']) && is_array($_POST['form_content']) ? wp_unslash($_POST['form_content']) : [];
55 $sanitized_form_id = sanitize_key(wp_unslash($_POST['form_id'] ?? ''));
56 $sanitized_form_page = sanitize_text_field(wp_unslash($_POST['form_page'] ?? ''));
57
58 $post_id = self::insert_submission([
59 'form_name' => $sanitized_form_name,
60 'form_id' => $sanitized_form_id,
61 'form_page' => $sanitized_form_page,
62 'form_page_id' => $sanitized_form_page_id,
63 'form_content' => $form_content,
64 ]);
65
66 if ($post_id) {
67 wp_send_json_success(array(
68 'action' => 'king_addons_form_builder_submissions',
69 'post_id' => $post_id,
70 'message' => esc_html__('Submission created successfully', 'king-addons'),
71 'status' => 'success'
72 // Security fix: Removed unsanitized form_content from response to prevent XSS
73 ));
74 } else {
75 wp_send_json_success(array(
76 'action' => 'king_addons_form_builder_submissions',
77 'post_id' => $post_id,
78 'message' => esc_html__('Submit action failed', 'king-addons'),
79 'status' => 'error'
80 ));
81 }
82 }
83
84 /**
85 * Insert a Form Builder submission from already-sanitized request pieces.
86 *
87 * @param array<string,mixed> $args {
88 * @type string $form_name
89 * @type string $form_id
90 * @type string $form_page
91 * @type int $form_page_id
92 * @type array $form_content
93 * }
94 *
95 * @return int Submission post ID, or 0.
96 */
97 public static function insert_submission(array $args): int
98 {
99 $form_name = sanitize_text_field((string) ($args['form_name'] ?? ''));
100 $form_id = sanitize_key((string) ($args['form_id'] ?? ''));
101 $form_page = sanitize_text_field((string) ($args['form_page'] ?? ''));
102 $form_page_id = absint($args['form_page_id'] ?? 0);
103 $form_content = isset($args['form_content']) && is_array($args['form_content']) ? $args['form_content'] : [];
104
105 $post_id = wp_insert_post([
106 'post_status' => 'publish',
107 'post_type' => 'king-addons-fb-sub',
108 'post_title' => $form_name
109 ? $form_name . ' - ' . current_time('mysql')
110 : current_time('mysql'),
111 ]);
112
113 if (!$post_id || is_wp_error($post_id)) {
114 return 0;
115 }
116
117 $post_id = (int) $post_id;
118
119 foreach ($form_content as $key => $value) {
120 if (!is_array($value) || count($value) < 3) {
121 continue;
122 }
123
124 $sanitized_key = sanitize_key((string) $key);
125 if ('' === $sanitized_key) {
126 continue;
127 }
128
129 update_post_meta($post_id, $sanitized_key, [
130 sanitize_text_field((string) $value[0]),
131 self::sanitize_field_value($value[1]),
132 sanitize_text_field((string) $value[2]),
133 ]);
134 }
135
136 update_post_meta($post_id, 'king_addons_form_name', $form_name);
137 update_post_meta($post_id, 'king_addons_form_id', $form_id);
138 update_post_meta($post_id, 'king_addons_form_page', $form_page);
139 update_post_meta($post_id, 'king_addons_form_page_id', $form_page_id);
140 $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_textarea_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '';
141 update_post_meta($post_id, 'king_addons_user_agent', $user_agent);
142 update_post_meta($post_id, 'king_addons_user_ip', Core::getClientIP());
143
144 return $post_id;
145 }
146
147 /**
148 * Saves admin edits to an existing submission.
149 *
150 * @param int $post_id Submission post ID.
151 * @return void
152 */
153 public function update_submissions_post_meta($post_id)
154 {
155 // Security fix: Validate nonce and capabilities
156 if (!current_user_can('edit_post', $post_id)) {
157 return;
158 }
159
160 if (isset($_POST['king_addons_submission_changes']) && !empty($_POST['king_addons_submission_changes'])) {
161 // Security fix: Sanitize JSON input and validate structure
162 $raw_changes = sanitize_textarea_field(stripslashes($_POST['king_addons_submission_changes']));
163 $changes = json_decode($raw_changes, true);
164
165 if (!is_array($changes)) {
166 return; // Invalid JSON structure
167 }
168
169 foreach ($changes as $key => $value) {
170 // Security fix: Validate and sanitize keys and values
171 $sanitized_key = sanitize_key($key);
172 if (empty($sanitized_key)) {
173 continue; // Skip invalid keys
174 }
175
176 // Sanitize values based on type
177 if (is_array($value)) {
178 $sanitized_value = array_map('sanitize_text_field', $value);
179 } else {
180 $sanitized_value = sanitize_text_field($value);
181 }
182
183 update_post_meta($post_id, $sanitized_key, $sanitized_value);
184 }
185 }
186 }
187
188 /**
189 * Sanitize a submitted field value.
190 *
191 * Radio and checkbox groups arrive as rows of [value, checked, name, id].
192 * A flat array_map(sanitize_text_field) turns each row into an empty
193 * string, so the saved submission lost what the visitor actually picked.
194 *
195 * @param mixed $raw Raw value from form_content.
196 *
197 * @return string|array<int,string>
198 */
199 private static function sanitize_field_value($raw)
200 {
201 if (!is_array($raw)) {
202 return sanitize_text_field((string) $raw);
203 }
204
205 if (isset($raw[0]) && is_array($raw[0])) {
206 $picked = [];
207 foreach ($raw as $row) {
208 if (!is_array($row)) {
209 continue;
210 }
211 $option = sanitize_text_field((string) ($row[0] ?? ''));
212 $checked = !empty($row[1]) && 'false' !== (string) $row[1] && '0' !== (string) $row[1];
213 if ($checked && '' !== $option) {
214 $picked[] = $option;
215 }
216 }
217
218 return implode(', ', $picked);
219 }
220
221 return array_values(array_map('sanitize_text_field', $raw));
222 }
223 }
224
225 new Create_Submission();