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 | modules/alex-grid/module.php +44 -59 4.1.2 → 4.5.6 View file →
@@ -32,11 +32,17 @@
32 32 return $widgets;
33 33 }
34 34
35 35 public function callback_ajax_loadmore_posts() {
36 + // Verify the front-end nonce (sent by UltimatePostKitConfig.nonce) before
37 + // processing this public load-more request.
38 + if ( ! check_ajax_referer( 'upk-site', 'nonce', false ) ) {
39 + wp_send_json_error( array( 'message' => esc_html__( 'Security check failed.', 'ultimate-post-kit' ) ), 403 );
40 + }
36 41
42 +
37 43 // Security: Verify nonce
38 - if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'upk-site' ) ) {
44 + if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'upk-site' ) ) {
39 45 wp_send_json_error( [ 'message' => esc_html__( 'Security verification failed', 'ultimate-post-kit' ) ], 403 );
40 46 wp_die();
41 47 }
42 48
@@ -45,50 +51,33 @@
45 51 if ( isset( $_POST['settings'] ) && is_array( $_POST['settings'] ) ) {
46 52 $settings = map_deep( wp_unslash( $_POST['settings'] ), 'sanitize_text_field' );
47 53 }
48 54
49 - $post_type = $settings['post_source'] ?? 'post';
50 -
51 - // Security: Enforce query limits to prevent DoS
52 - $per_page = isset( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : 6;
53 - $per_page = min( $per_page, 50 ); // Maximum 50 posts per request
54 - $offset = isset( $_POST['offset'] ) ? absint( $_POST['offset'] ) : 0;
55 - $offset = min( $offset, 1000 ); // Maximum offset of 1000
56 -
57 - // Security: Whitelist allowed post types
58 - $allowed_post_types = [ 'post', 'page' ];
59 - $allowed_post_types = apply_filters( 'upk_alex_grid_allowed_post_types', $allowed_post_types );
60 - $post_type = in_array( $post_type, $allowed_post_types, true ) ? $post_type : 'post';
61 -
62 - // Security: Whitelist orderby values
63 - $allowed_orderby = [ 'date', 'title', 'modified', 'rand', 'comment_count', 'menu_order' ];
64 - $posts_orderby = isset( $settings['posts_orderby'] ) && in_array( $settings['posts_orderby'], $allowed_orderby, true ) ? $settings['posts_orderby'] : 'date';
65 -
66 - // Security: Whitelist order values
67 - $posts_order = isset( $settings['posts_order'] ) && in_array( strtoupper( $settings['posts_order'] ), [ 'ASC', 'DESC' ], true ) ? strtoupper( $settings['posts_order'] ) : 'DESC';
68 -
69 - $settings = array_merge(
55 + // NOTE: the request-derived values below are NOT the ones the query is built from.
56 + // query_args() is declared without parameters and re-reads $_POST['settings']
57 + // itself, so anything merged into $settings here is discarded. The query is
58 + // constrained inside query_args(): post_status is pinned to 'publish', per_page
59 + // is clamped to 1..100, and post_type is restricted to publicly visible post
60 + // types by ultimate_post_kit_sanitize_public_post_type(). The defaults are kept
61 + // only so the render loop below has the keys it expects.
62 + $settings = array_merge(
70 63 [
71 - 'posts_source' => $post_type,
72 - 'posts_orderby' => $posts_orderby,
73 - 'posts_order' => $posts_order,
64 + 'posts_source' => 'post',
65 + 'posts_orderby' => 'date',
66 + 'posts_order' => 'DESC',
74 67 'posts_ignore_sticky_posts' => 'no',
75 68 'posts_only_with_featured_image' => 'no',
76 69 'posts_select_date' => '',
77 70 'posts_exclude_by' => [],
78 71 'posts_include_by' => [],
79 - 'posts_per_page' => $per_page,
80 - 'posts_offset' => $offset,
81 72 ],
82 73 $settings
83 74 );
84 -
75 +
76 + // Fill display flags the request may have omitted (see trait) before the render loop reads them.
77 + $settings = array_merge( $this->loadmore_display_defaults(), $settings );
78 +
85 79 $ajaxposts = $this->query_args( $settings );
86 -
87 - // Security: Override post_status to ensure only published posts are shown
88 - if ( ! current_user_can( 'edit_posts' ) ) {
89 - $ajaxposts->query_vars['post_status'] = 'publish';
90 - }
91 80
92 81 ob_start();
93 82 $found_posts = false;
94 83
@@ -100,18 +89,16 @@
100 89 $title = get_the_title();
101 90 $post_link = esc_url(get_permalink());
102 91 $image_src = wp_get_attachment_image_url(get_post_thumbnail_id(), 'large');
103 92 $image_src = $image_src ? esc_url($image_src) : esc_url(\Elementor\Utils::get_placeholder_image_src());
104 - $category = wp_kses_post(upk_get_category($post_type));
93 + $category = wp_kses_post(upk_get_category($settings['posts_source'] ?? 'post'));
105 94 $author_url = esc_url(get_author_posts_url(get_the_author_meta('ID')));
106 95 $author_name = esc_html(get_the_author());
107 96 $title_tag = Utils::get_valid_html_tag($settings['title_tags'] );
108 97
109 - $onclick = '';
110 - if (!empty($settings['global_link']) && $settings['global_link'] === 'yes') {
111 - $onclick = ' onclick="window.open(\'' . $post_link . '\', \'_self\')"';
112 - }
113 -
98 + $meta_separator = isset( $settings['meta_separator'] ) ? $settings['meta_separator'] : '|';
99 +
100 +
114 101 $date = '';
115 102 if (!empty($settings['human_diff_time']) && $settings['human_diff_time'] === 'yes') {
116 103 $date = ultimate_post_kit_post_time_diff(($settings['human_diff_time_short'] === 'yes') ? 'short' : '');
117 104 } else {
@@ -132,11 +119,11 @@
132 119
133 120 $post_format_icon = isset($format_icons[get_post_format()]) ? $format_icons[get_post_format()] : 'upk-icon-post';
134 121
135 122 ?>
136 - <div <?php echo $onclick; ?> class="upk-item">
123 + <div <?php if ( ! empty( $settings['global_link'] ) && $settings['global_link'] === 'yes' ) { printf( 'onclick="window.open(\'%s\', \'_self\')"', esc_url( $post_link ) ); } ?> class="upk-item">
137 124 <div class="upk-image-wrap">
138 - <img class="upk-img" src="<?php echo $image_src; ?>" alt="<?php echo esc_attr($title); ?>">
125 + <img class="upk-img" src="<?php echo esc_url( $image_src ); ?>" alt="<?php echo esc_attr($title); ?>">
139 126
140 127 <?php if (
141 128 $settings['show_author'] === 'yes' ||
142 129 $settings['show_date'] === 'yes' ||
@@ -150,27 +137,25 @@
150 137
151 138 <div>
152 139 <?php if ($settings['show_author'] === 'yes') : ?>
153 140 <div class="upk-author-name">
154 - <a href="<?php echo $author_url; ?>"><?php echo $author_name; ?></a>
141 + <a href="<?php echo esc_url( $author_url ); ?>"><?php echo esc_html( $author_name ); ?></a>
155 142 </div>
156 143 <?php endif; ?>
157 144
158 145 <div class="upk-flex upk-flex-middle upk-date-reading-wrap">
159 - <?php if ($settings['show_date'] === 'yes') : ?>
160 - <div data-separator="<?php echo esc_attr($settings['meta_separator']); ?>">
161 - <div class="upk-date"><?php echo $date; ?></div>
162 - <?php if ($settings['show_time'] === 'yes') : ?>
163 - <div class="upk-post-time">
164 - <i class="upk-icon-clock" aria-hidden="true"></i><?php echo esc_html(get_the_time()); ?>
165 - </div>
166 - <?php endif; ?>
167 - </div>
146 + <?php if ( $settings['show_date'] === 'yes' ) : ?>
147 + <div class="upk-date"><?php echo esc_html( $date ); ?></div>
148 + <?php if ( $settings['show_time'] === 'yes' ) : ?>
149 + <div class="upk-post-time" data-separator="<?php echo esc_attr( $meta_separator ); ?>">
150 + <i class="upk-icon-clock" aria-hidden="true"></i><?php echo esc_html( get_the_time() ); ?>
151 + </div>
152 + <?php endif; ?>
168 153 <?php endif; ?>
169 -
170 - <?php if (function_exists('_is_upk_pro_activated') && _is_upk_pro_activated() && $settings['show_reading_time'] === 'yes') : ?>
171 - <div class="upk-reading-time" data-separator="<?php echo esc_attr($settings['meta_separator']); ?>">
172 - <?php echo ultimate_post_kit_reading_time(get_the_content(), $settings['avg_reading_speed'], $settings['hide_seconds'] ?? 'no', $settings['hide_minutes'] ?? 'no'); ?>
154 +
155 + <?php if ( function_exists( '_is_upk_pro_activated' ) && _is_upk_pro_activated() && $settings['show_reading_time'] === 'yes' ) : ?>
156 + <div class="upk-reading-time" data-separator="<?php echo esc_attr( $meta_separator ); ?>">
157 + <?php echo wp_kses_post( ultimate_post_kit_reading_time( get_the_content(), $settings['avg_reading_speed'], $settings['hide_seconds'] ?? 'no', $settings['hide_minutes'] ?? 'no' ) ); ?>
173 158 </div>
174 159 <?php endif; ?>
175 160 </div>
176 161 </div>
@@ -178,9 +163,9 @@
178 163 <?php endif; ?>
179 164
180 165 <?php if ($settings['show_post_format'] === 'yes') : ?>
181 166 <div class="upk-post-format">
182 - <a href="<?php echo $post_link; ?>">
167 + <a href="<?php echo esc_url( $post_link ); ?>">
183 168 <i class="<?php echo esc_attr($post_format_icon); ?>" aria-hidden="true"></i>
184 169 </a>
185 170 </div>
186 171 <?php endif; ?>
@@ -188,15 +173,15 @@
188 173
189 174 <div class="upk-content-wrap">
190 175 <div class="upk-content">
191 176 <?php if ($settings['show_category'] === 'yes') : ?>
192 - <div class="upk-category"><?php echo $category; ?></div>
177 + <div class="upk-category"><?php echo wp_kses_post( $category ); ?></div>
193 178 <?php endif; ?>
194 179
195 180 <?php if ($settings['show_title'] === 'yes') : ?>
196 181 <<?php echo esc_attr( $title_tag ); ?> class="upk-title">
197 182 <a class="title-animation-<?php echo esc_attr($settings['title_style']); ?>"
198 - href="<?php echo $post_link; ?>"
183 + href="<?php echo esc_url( $post_link ); ?>"
199 184 title="<?php echo esc_attr($title); ?>"
200 185 <?php echo $settings['upk_link_new_tab'] === 'yes' ? 'target="_blank"' : ''; ?>
201 186 >
202 187 <?php echo esc_html($title); ?>
@@ -206,9 +191,9 @@
206 191 </div>
207 192
208 193 <?php if ($settings['show_readmore'] === 'yes') : ?>
209 194 <div class="upk-button-wrap">
210 - <a href="<?php echo $post_link; ?>"
195 + <a href="<?php echo esc_url( $post_link ); ?>"
211 196 class="upk-readmore"
212 197 target="<?php echo ($settings['upk_link_new_tab'] === 'yes') ? '_blank' : '_self'; ?>">
213 198 <span class="upk-readmore-icon"><span></span></span>
214 199 </a>