PluginProbe
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets / 4.5.6
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets v4.5.6
4.5.6 4.5.5 4.5.4 4.2.1 4.2.2 4.2.3 4.5.0 4.5.2 4.5.3 4.2.0 4.1.18 4.1.17 4.1.16 4.1.15 4.1.14 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.0.9 4.1.0 4.1.1 4.1.2 All 148 releases
← All changes | includes/controls/select-input/dynamic-select-input-module.php +46 -8 4.5.0 → 4.5.6 View file →
@@ -95,10 +95,17 @@
95 95 /**
96 96 * @return array|mixed
97 97 */
98 98 protected function getselecedIds() {
99 - // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified in getSelectInputData() before this helper runs.
100 - return isset($_POST['ids']) ? sanitize_text_field(wp_unslash($_POST['ids'])) : [];
99 + if ( ! check_ajax_referer( 'upk_dynamic_select', 'security', false ) ) {
100 + return [];
101 + }
102 +
103 + if ( ! isset( $_POST['ids'] ) ) {
104 + return [];
105 + }
106 +
107 + return array_values( array_filter( wp_parse_id_list( (array) wp_unslash( $_POST['ids'] ) ) ) );
101 108 }
102 109
103 110
104 111 /**
@@ -132,18 +139,26 @@
132 139 $args = [];
133 140
134 141 $args['post_status'] = 'publish';
135 142
136 - if ($this->getPostType()) {
137 - $args['post_type'] = $this->getPostType();
143 + $public_post_types = $this->getAllPublicPostTypes();
144 + $requested_post_type = $this->getPostType();
145 +
146 + // post_type comes straight from $_POST. Restrict it to the public post types this
147 + // control is meant to browse so it cannot be pointed at a private post type.
148 + if ($requested_post_type && in_array($requested_post_type, $public_post_types, true)) {
149 + $args['post_type'] = $requested_post_type;
138 150 } else {
139 - $args['post_type'] = $this->getAllPublicPostTypes();
151 + $args['post_type'] = $public_post_types;
140 152 }
153 +
141 154 if (!empty($include)) {
142 155 $args['post__in'] = $include;
143 - $args['posts_per_page'] = count($include);
156 + $args['posts_per_page'] = min(100, count($include));
144 157 } else {
145 - $args['posts_per_page'] = -1;
158 + // Never run this unbounded: it is reachable by any 'edit_posts' user and
159 + // -1 returns every published post of every public post type.
160 + $args['posts_per_page'] = 50;
146 161 }
147 162 if ($searchText) {
148 163 $args['s'] = $searchText;
149 164 }
@@ -203,8 +218,10 @@
203 218 $search_text = $this->getSearchQuery();
204 219 $taxonomies = $this->getAllPublicTaxonomies();
205 220 $include = $this->getselecedIds();
206 221
222 + $post_type = '';
223 +
207 224 if ($this->getPostType() == '_ultimate_post_kit_pro_related_post_type') {
208 225 $post_type = $this->getAllPublicPostTypes();
209 226 } elseif ($this->getPostType()) {
210 227 $post_type = $this->getPostType();
@@ -209,8 +226,12 @@
209 226 } elseif ($this->getPostType()) {
210 227 $post_type = $this->getPostType();
211 228 }
212 229
230 + if (empty($post_type)) {
231 + return [];
232 + }
233 +
213 234 $post_taxonomies = get_object_taxonomies($post_type);
214 235 $taxonomies = array_intersect($post_taxonomies, $taxonomies);
215 236 $data = [];
216 237
@@ -266,17 +287,34 @@
266 287
267 288 $args = [
268 289 'fields' => ['ID', 'display_name'],
269 290 'orderby' => 'display_name',
291 + // Always bound the result set. Without this an empty search returns every
292 + // user on the site, unpaged.
293 + 'number' => 20,
270 294 ];
271 295
296 + // This endpoint is only capability-gated on 'edit_posts', so a Contributor can
297 + // reach it. WordPress core restricts callers without 'list_users' to users who
298 + // have published something (see WP_REST_Users_Controller::get_items), so match
299 + // that restriction rather than exposing the full user table.
300 + if (!current_user_can('list_users')) {
301 + $args['has_published_posts'] = true;
302 + }
303 +
272 304 if (!empty($include)) {
273 305 $args['include'] = $include;
306 + // Resolving already-selected values needs room for all of them, but still
307 + // bounded so a long id list cannot be used to dump the table.
308 + $args['number'] = min(100, max(20, count($include)));
274 309 }
275 310
276 311 if ($search_text) {
277 - $args['number'] = 20;
278 312 $args['search'] = "*$search_text*";
313 + // WP_User_Query searches user_email when the term contains "@", which turns
314 + // this into an address oracle. Core strips user_email from the searchable
315 + // columns for callers without 'list_users'; do the same here.
316 + $args['search_columns'] = ['ID', 'user_login', 'user_nicename', 'display_name'];
279 317 }
280 318
281 319 $users = get_users($args);
282 320