PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.83
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.83
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 51.1.46 All 39 releases
← All changes | includes/widgets/Dynamic_Posts_Grid/script.js +67 -16 51.1.4451.1.83 View file →
@@ -20,8 +20,35 @@
20 20 const widgetMode = $wrapper.data('widget-mode');
21 21 const isPro = widgetMode === 'custom_cpt';
22 22
23 23 const gridHandler = {
24 + // Sanitize HTML using DOMPurify for XSS protection
25 + sanitizeHtml(value) {
26 + if (typeof DOMPurify !== 'undefined') {
27 + return DOMPurify.sanitize(String(value), {ALLOWED_TAGS: [], ALLOWED_ATTR: []});
28 + }
29 + // Fallback
30 + return String(value)
31 + .replace(/&/g, "&")
32 + .replace(/</g, "&lt;")
33 + .replace(/>/g, "&gt;")
34 + .replace(/"/g, "&quot;")
35 + .replace(/'/g, "&#039;");
36 + },
37 +
38 + normalizeSafeUrl(rawUrl, allowedProtocols = ["http:", "https:"]) {
39 + if (!rawUrl || typeof rawUrl !== "string") return null;
40 + try {
41 + const url = new URL(rawUrl, window.location.href);
42 + if (allowedProtocols.includes(url.protocol)) {
43 + return url.href;
44 + }
45 + } catch (e) {
46 + // ignore
47 + }
48 + return null;
49 + },
50 +
24 51 init() {
25 52 this.wrapper = $scope.find('.king-addons-dpg-wrapper');
26 53 this.grid = $scope.find('.king-addons-dpg-grid');
27 54 this.filterBar = $scope.find('.king-addons-dpg-filter-bar');
@@ -123,10 +150,12 @@
123 150 const postLink = $(e.currentTarget).find('.king-addons-dpg-title a');
124 151 if (postLink.length > 0) {
125 152 const postUrl = postLink.attr('href');
126 153 if (postUrl) {
127 - // Navigate to post
128 - window.location.href = postUrl;
154 + const safePostUrl = this.normalizeSafeUrl(postUrl);
155 + if (safePostUrl) {
156 + window.location.href = safePostUrl;
157 + }
129 158 }
130 159 }
131 160 });
132 161
@@ -163,9 +192,9 @@
163 192 const url = $button.data('url');
164 193 const title = $button.data('title') || '';
165 194
166 195 if (!url) {
167 - console.warn('No URL provided for action button');
196 + // console.warn('No URL provided for action button');
168 197 return;
169 198 }
170 199
171 200 switch (action) {
@@ -183,8 +212,13 @@
183 212 });
184 213 },
185 214
186 215 openImageLightbox(url, title) {
216 + const safeUrl = this.normalizeSafeUrl(url);
217 + if (!safeUrl) {
218 + return;
219 + }
220 +
187 221 // Prevent multiple lightboxes from opening simultaneously
188 222 if ($('.lg-backdrop, .lg-outer, .king-addons-dpg-lightbox-temp, [data-lg-uid]').length > 0) {
189 223 return;
190 224 }
@@ -198,10 +232,10 @@
198 232 $('.king-addons-dpg-lightbox-temp').remove();
199 233
200 234 // Create array with single image item for LightGallery
201 235 const galleryItems = [{
202 - src: url,
203 - subHtml: title || ''
236 + src: safeUrl,
237 + subHtml: title ? '<div>' + this.sanitizeHtml(title) + '</div>' : ''
204 238 }];
205 239
206 240 // Initialize LightGallery directly with dynamic gallery
207 241 if (typeof $.fn.lightGallery !== 'undefined') {
@@ -230,10 +264,10 @@
230 264 $tempDiv.remove();
231 265 }, 100);
232 266 });
233 267 } else {
234 - console.error('LightGallery not available');
235 - window.open(url, '_blank');
268 + // console.error('LightGallery not available');
269 + window.open(safeUrl, '_blank');
236 270 }
237 271 },
238 272
239 273 openVideoLightbox(url, title) {
@@ -238,10 +272,13 @@
238 272
239 273 openVideoLightbox(url, title) {
240 274 // Check if LightGallery is available
241 275 if (typeof $.fn.lightGallery === 'undefined') {
242 - console.warn('LightGallery not loaded, opening video in new tab');
243 - window.open(url, '_blank');
276 + // console.warn('LightGallery not loaded, opening video in new tab');
277 + const safeUrl = this.normalizeSafeUrl(url);
278 + if (safeUrl) {
279 + window.open(safeUrl, '_blank');
280 + }
244 281 return;
245 282 }
246 283
247 284 // For old LightGallery v1.6.12, let's create a manual video popup
@@ -248,13 +285,18 @@
248 285 this.createYouTubePopup(url, title);
249 286 },
250 287
251 288 createYouTubePopup(url, title) {
289 + const safeUrl = this.normalizeSafeUrl(url);
290 + if (!safeUrl) {
291 + return;
292 + }
293 +
252 294 // Process YouTube URL to get video ID
253 - const videoId = this.getYouTubeVideoId(url);
295 + const videoId = this.getYouTubeVideoId(safeUrl);
254 296 if (!videoId) {
255 - console.warn('Invalid YouTube URL');
256 - window.open(url, '_blank');
297 + // console.warn('Invalid YouTube URL');
298 + window.open(safeUrl, '_blank');
257 299 return;
258 300 }
259 301
260 302 // Create manual video popup similar to LightGallery structure
@@ -416,9 +458,9 @@
416 458 success: (response) => {
417 459 this.handleFilterResponse(response);
418 460 },
419 461 error: (xhr, status, error) => {
420 - console.error('Dynamic Posts Grid AJAX Error:', error);
462 + // console.error('Dynamic Posts Grid AJAX Error:', error);
421 463 this.hideLoading();
422 464 this.isLoading = false;
423 465 }
424 466 });
@@ -459,9 +501,9 @@
459 501 success: (response) => {
460 502 this.handleLoadMoreResponse(response);
461 503 },
462 504 error: (xhr, status, error) => {
463 - console.error('Dynamic Posts Grid Load More Error:', error);
505 + // console.error('Dynamic Posts Grid Load More Error:', error);
464 506 this.hideLoading();
465 507 this.isLoading = false;
466 508 this.currentPage--; // Revert page increment on error
467 509 }
@@ -559,11 +601,20 @@
559 601 if (!conf) return;
560 602
561 603 const $iconWrap = $card.find('.king-addons-dpg-icon');
562 604 if (conf.icon_type === 'image' && conf.image_url) {
563 - $iconWrap.html('<img src="' + conf.image_url + '" alt="' + postType + '" />');
605 + const safeImgUrl = this.normalizeSafeUrl(conf.image_url);
606 + if (!safeImgUrl) return;
607 + $iconWrap.empty().append(
608 + $("<img />", {
609 + src: safeImgUrl,
610 + alt: String(postType || ""),
611 + })
612 + );
564 613 } else if (conf.icon_class) {
565 - $iconWrap.html('<i class="' + conf.icon_class + '"></i>');
614 + $iconWrap.empty().append(
615 + $("<i />").addClass(String(conf.icon_class || ""))
616 + );
566 617 }
567 618 });
568 619 },
569 620