PluginProbe
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder / 3.1.4
Ultimate Store Kit – Store Builder Addons for Elementor, WooCommerce Store Builder, EDD Store Builder v3.1.4
3.1.4 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.0.7 3.0.5 3.0.4 3.0.3 3.0.2 trunk 1.5.0 1.5.1 1.5.2 1.6.1 1.6.2 1.6.3 1.6.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 All 93 releases
← All changes | includes/builder/builder-cpt.php +71 -37 3.0.73.1.4 View file →
@@ -45,16 +45,22 @@
45 45 global $wpdb;
46 46
47 47 $postType = Meta::POST_TYPE;
48 48
49 - $query = $wpdb->get_results("SELECT {$wpdb->posts}.ID,{$wpdb->posts}.post_type, {$wpdb->posts}.post_status, {$wpdb->postmeta}.meta_value as template_type
50 -FROM $wpdb->posts
51 - LEFT JOIN $wpdb->postmeta
52 - ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID
53 -WHERE 1=1
54 -AND {$wpdb->posts}.post_type ='{$postType}'
55 -AND {$wpdb->postmeta}.meta_key ='_ultimate_store_kit_template_type'
56 -ORDER BY {$wpdb->posts}.post_date DESC");
49 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Rebuilds the template cache; this is the call that populates it.
50 + $query = $wpdb->get_results($wpdb->prepare(
51 + "SELECT {$wpdb->posts}.ID, {$wpdb->posts}.post_type, {$wpdb->posts}.post_status, {$wpdb->postmeta}.meta_value as template_type
52 + FROM {$wpdb->posts}
53 + LEFT JOIN {$wpdb->postmeta}
54 + ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID
55 + WHERE 1=1
56 + AND {$wpdb->posts}.post_type = %s
57 + AND {$wpdb->postmeta}.meta_key = %s
58 + ORDER BY {$wpdb->posts}.post_date DESC",
59 + $postType,
60 + '_ultimate_store_kit_template_type'
61 + ));
62 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
57 63
58 64 foreach ($query as $q) {
59 65 if (! $q->template_type) {
60 66 continue;
@@ -59,14 +65,12 @@
59 65 if (! $q->template_type) {
60 66 continue;
61 67 }
62 68
63 - $optionKey = Meta::TEMPLATE_ID . $q->template_type;
64 -
65 69 if ($q->post_status == 'publish') {
66 - update_option($optionKey, $q->ID);
70 + Meta::update_template_option($q->template_type, $q->ID);
67 71 } else {
68 - delete_option($optionKey, $q->ID);
72 + Meta::delete_template_option($q->template_type);
69 73 }
70 74 }
71 75 }
72 76
@@ -75,9 +79,9 @@
75 79 return;
76 80 }
77 81
78 82 if ($template = get_post_meta($postId, Meta::TEMPLATE_TYPE, true)) {
79 - delete_option(Meta::TEMPLATE_ID . $template);
83 + Meta::delete_template_option($template);
80 84 }
81 85 }
82 86
83 87 public function post_row_actions_filter($actions, $post) {
@@ -143,9 +147,12 @@
143 147 return array_slice($actions, 0, 1, true) + ['usk-edit-action' => $editActionLink] + array_slice($actions, 1, null, true);
144 148 }
145 149
146 150 public function set_post_columns($columns) {
147 - return array_slice($columns, 0, 2, true) + ['template_type' => 'Type', 'is_enabled' => 'Status'] + array_slice($columns, 2, null, true);
151 + return array_slice($columns, 0, 2, true) + [
152 + 'template_type' => esc_html__('Type', 'ultimate-store-kit'),
153 + 'is_enabled' => esc_html__('Status', 'ultimate-store-kit')
154 + ] + array_slice($columns, 2, null, true);
148 155 }
149 156
150 157 public function set_custom_column_value($column, $post_id) {
151 158 $templateType = get_post_meta(
@@ -156,13 +163,17 @@
156 163
157 164 switch ($column) {
158 165 case 'template_type':
159 166 $postType = Builder_Template_Helper::getTemplatePostTypeByIndex($templateType);
160 - $postTypeLabel = isset($postType->name) ? ' <strong>-- ' . ucwords($postType->name) . '</strong>' : '';
161 - echo Builder_Template_Helper::getTemplateByIndex($templateType) . $postTypeLabel;
167 + echo esc_html(Builder_Template_Helper::getTemplateByIndex($templateType));
168 + if (isset($postType->name)) {
169 + echo ' <strong>-- ' . esc_html(ucwords($postType->name)) . '</strong>';
170 + }
162 171 break;
163 172 case 'is_enabled':
164 - echo (Builder_Template_Helper::getTemplateId($templateType) == $post_id ? 'Active' : 'Inactive');
173 + echo Builder_Template_Helper::getTemplateId($templateType) == $post_id
174 + ? esc_html__('Active', 'ultimate-store-kit')
175 + : esc_html__('Inactive', 'ultimate-store-kit');
165 176 break;
166 177 }
167 178 }
168 179
@@ -172,9 +183,10 @@
172 183 if ($typenow !== Meta::POST_TYPE) {
173 184 return;
174 185 }
175 186
176 - $selected = isset($_GET['type']) ? sanitize_key($_GET['type']) : '';
187 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin list-table filter; the value only re-selects the current dropdown option.
188 + $selected = isset($_GET['type']) ? sanitize_text_field(wp_unslash($_GET['type'])) : '';
177 189 ?>
178 190 <select name="type" id="type">
179 191 <option value="all" <?php
180 192 selected('all', $selected); ?>><?php
@@ -235,8 +247,9 @@
235 247 if ($typenow !== Meta::POST_TYPE) {
236 248 return;
237 249 }
238 250
251 + // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.DB.SlowDBQuery -- Admin list-table filter; the value only narrows the query that is already running.
239 252 if (
240 253 'edit.php' == $pagenow
241 254 && isset($_GET['type'])
242 255 && $_GET['type'] != ''
@@ -241,12 +254,17 @@
241 254 && isset($_GET['type'])
242 255 && $_GET['type'] != ''
243 256 && $_GET['type'] != 'all'
244 257 ) {
245 - $query->query_vars['meta_key'] = Meta::TEMPLATE_TYPE;
246 - $query->query_vars['meta_value'] = sanitize_key($_GET['type']);
247 - $query->query_vars['meta_compare'] = '=';
258 + $requested_type = sanitize_text_field(wp_unslash($_GET['type']));
259 +
260 + if (Builder_Template_Helper::getTemplateByIndex($requested_type)) {
261 + $query->query_vars['meta_key'] = Meta::TEMPLATE_TYPE;
262 + $query->query_vars['meta_value'] = $requested_type;
263 + $query->query_vars['meta_compare'] = '=';
264 + }
248 265 }
266 + // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.DB.SlowDBQuery
249 267 }
250 268
251 269
252 270 public function create_builder_template() {
@@ -254,20 +272,34 @@
254 272 if (! current_user_can('manage_options')) {
255 273 wp_send_json_error(['success' => false, 'errors_arr' => ['permission' => 'Permission denied']], 403);
256 274 }
257 275
258 - parse_str($_POST['data'], $data);
276 + $data = [];
277 + // The form arrives as one serialized string, so it is unslashed before parsing
278 + // and every field is sanitized individually below — parse_str itself does not
279 + // sanitize anything.
280 + if (isset($_POST['data'])) {
281 + parse_str(wp_unslash($_POST['data']), $data); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Serialized form string; every parsed field is sanitized individually below.
282 + }
259 283
260 - if (! wp_verify_nonce($data['nonce'], 'usk-builder')) {
284 + $nonce = isset($data['nonce']) ? sanitize_text_field($data['nonce']) : '';
285 +
286 + if (! wp_verify_nonce($nonce, 'usk-builder')) {
261 287 wp_send_json_error(['success' => false, 'errors_arr' => ['nonce' => 'Invalid nonce']], 403);
262 288 }
263 289
264 - $templateId = isset($data['template_id']) ? trim($data['template_id']) : '';
265 - $name = isset($data['template_name']) ? trim($data['template_name']) : '';
266 - $type = isset($data['template_type']) ? trim($data['template_type']) : '';
267 - $editWith = isset($data['edit_with']) ? trim($data['edit_with']) : 'elementor'; //gutenberg
290 + $templateId = isset($data['template_id']) ? absint($data['template_id']) : 0;
291 + $name = isset($data['template_name']) ? sanitize_text_field($data['template_name']) : '';
292 + $type = isset($data['template_type']) ? sanitize_text_field($data['template_type']) : '';
293 + $editWith = isset($data['edit_with']) ? sanitize_key($data['edit_with']) : 'elementor'; //gutenberg
268 294 $isEnabled = (isset($data['template_status']) && $data['template_status']) == 1 ? 1 : 0;
269 295
296 + // Only these two editors are ever handled below, and the value ends up in a
297 + // redirect URL, so anything else falls back to the default.
298 + if (! in_array($editWith, ['elementor', 'gutenberg'], true)) {
299 + $editWith = 'elementor';
300 + }
301 +
270 302 $errors = [];
271 303
272 304 if (empty($name)) {
273 305 $errors['template_name'] = 'Field is required';
@@ -307,14 +339,13 @@
307 339 }
308 340
309 341 $post_id = wp_insert_post($page_data);
310 342
311 - $enabledTemplate = strtolower(Meta::TEMPLATE_ID . $type);
312 343 if ($isEnabled == 1) {
313 - update_option($enabledTemplate, $post_id);
344 + Meta::update_template_option($type, $post_id);
314 345 } else {
315 - if (get_option($enabledTemplate) == $post_id) {
316 - delete_option($enabledTemplate);
346 + if (Meta::get_template_option($type) == $post_id) {
347 + Meta::delete_template_option($type);
317 348 }
318 349 }
319 350
320 351
@@ -351,9 +382,11 @@
351 382 if (! current_user_can('manage_options')) {
352 383 wp_send_json_error(['success' => false, 'errors_arr' => ['permission' => 'Permission denied']], 403);
353 384 }
354 385
355 - if (! wp_verify_nonce($_REQUEST['nonce'], 'ultimate_store_kit_builder_nonce')) {
386 + $nonce = isset($_REQUEST['nonce']) ? sanitize_text_field(wp_unslash($_REQUEST['nonce'])) : '';
387 +
388 + if (! wp_verify_nonce($nonce, 'ultimate_store_kit_builder_nonce')) {
356 389 wp_send_json_error(['success' => false, 'errors_arr' => ['nonce' => 'Invalid nonce']], 403);
357 390 }
358 391
359 392 if (isset($_REQUEST['template_id']) && ! empty($_REQUEST['template_id'])) {
@@ -364,10 +397,9 @@
364 397 $meta = get_post_meta($templateData->ID);
365 398
366 399
367 400 $templateType = isset($meta[Meta::TEMPLATE_TYPE][0]) ? $meta[Meta::TEMPLATE_TYPE][0] : '';
368 - $enabledTemplate = strtolower(Meta::TEMPLATE_ID . $templateType);
369 - $enabledTemplate = get_option($enabledTemplate);
401 + $enabledTemplate = Meta::get_template_option($templateType);
370 402
371 403 wp_send_json_success([
372 404 'id' => $templateData->ID,
373 405 'name' => $templateData->post_title,
@@ -389,9 +421,9 @@
389 421 $screen = get_current_screen();
390 422
391 423 if (is_object($screen) && Meta::POST_TYPE == $screen->post_type) {
392 424 wp_enqueue_style('ultimate-store-kit-builder', BDTUSK_ASSETS_URL . 'admin/others/css/ultimate-builder.css', [], BDTUSK_VER);
393 - wp_enqueue_script('ultimate-store-kit-builder', BDTUSK_ASSETS_URL . 'admin/others/js/ultimate-builder.js', ['jquery', 'wp-i18n'], BDTUSK_VER);
425 + wp_enqueue_script('ultimate-store-kit-builder', BDTUSK_ASSETS_URL . 'admin/others/js/ultimate-builder.js', ['jquery', 'wp-i18n'], BDTUSK_VER, true);
394 426 wp_set_script_translations('ultimate-store-kit-builder', 'ultimate-store-kit');
395 427
396 428 wp_localize_script('ultimate-store-kit-builder', 'UltimateStoreKitConfigBuilder', [
397 429 'ajaxurl' => admin_url('admin-ajax.php'),
@@ -466,10 +498,12 @@
466 498 /**
467 499 * Simple fix for WPML and Elementor integration
468 500 */
469 501 public function fix_wpml_elementor_data() {
470 - if (isset($_REQUEST['post']) && get_post_type($_REQUEST['post']) === Meta::POST_TYPE) {
471 - $post_id = (int) $_REQUEST['post'];
502 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reads the post being edited so WPML/Elementor metadata can be normalised.
503 + $post_id = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : 0;
504 +
505 + if ($post_id && get_post_type($post_id) === Meta::POST_TYPE) {
472 506 $meta_data = get_post_meta($post_id, '_elementor_data', true);
473 507
474 508 // If metadata exists but is in array format, convert it to JSON string
475 509 if (is_array($meta_data)) {