diff --git a/assets/admin-editor.js b/assets/admin-editor.js
index 6147a8c..d1546a2 100644
--- a/assets/admin-editor.js
+++ b/assets/admin-editor.js
@@ -306,6 +306,9 @@ jQuery(document).ready(function ($) {
// Append the rendered HTML
$(".result-value-output").html(html);
+ // Sync type-button-link visibility for initial render
+ $(".result-value-output .output-type").trigger("change");
+
// You can call other functions after the template is rendered
append_fields_to_preview();
},
diff --git a/assets/public.js b/assets/public.js
index 425afae..6e2b406 100644
--- a/assets/public.js
+++ b/assets/public.js
@@ -22,35 +22,26 @@ jQuery(document).ready(function ($) {
var recaptchaToken = thisChecker.find('input[name="recaptcha_token"]').val();
if (recaptchaToken) {
baseData.recaptcha_token = recaptchaToken;
- console.log("Security: reCAPTCHA token added to request");
- } else {
- console.log("Security: No reCAPTCHA token found");
}
-
+
// Add Turnstile token if present
var turnstileToken = thisChecker.find('input[name="turnstile_token"]').val();
if (turnstileToken) {
baseData.turnstile_token = turnstileToken;
- console.log("Security: Turnstile token added to request");
- } else {
- console.log("Security: No Turnstile token found");
}
-
+
// Add honeypot field (should be empty)
var hpInput = thisChecker.find('input[data-hp-field="1"]');
if (hpInput.length) {
baseData.honeypot_name = hpInput.attr('name');
baseData.honeypot_value = hpInput.val() || "";
- console.log("Security: Honeypot field added (value: " + (hpInput.val() === "" ? "empty" : "filled") + ")");
} else {
var legacyHp = thisChecker.find('input[name="website_url_hp"]').val();
if (typeof legacyHp !== 'undefined') {
baseData.website_url_hp = legacyHp || "";
- console.log("Security: Honeypot field added (legacy value: " + (legacyHp === "" ? "empty" : "filled") + ")");
}
}
- console.log("Security: AJAX data prepared", baseData);
return baseData;
}
@@ -62,18 +53,18 @@ jQuery(document).ready(function ($) {
function handleAjaxError(xhr, checkerId) {
var thisChecker = $("#checker-" + checkerId);
var response = xhr.responseJSON;
-
+
// WordPress wp_send_json_error format: {success: false, data: {message: "...", type: "..."}}
if (response && response.data) {
var errorType = response.data.type || 'error';
var errorMessage = response.data.message || 'An error occurred';
-
+
// Handle nonce expiry - prompt page refresh
if (errorType === 'nonce_expired') {
showSecurityError(checkerId, errorMessage, true);
return;
}
-
+
// Handle CAPTCHA errors
if (errorType === 'recaptcha' || errorType === 'turnstile') {
showSecurityError(checkerId, errorMessage, false);
@@ -81,19 +72,19 @@ jQuery(document).ready(function ($) {
resetCaptchaWidget(checkerId, errorType);
return;
}
-
+
// Handle rate limit with enhanced message
if (errorType === 'rate_limit') {
showSecurityError(checkerId, errorMessage, false);
return;
}
-
+
// Handle honeypot trigger (silent fail for bots)
if (errorType === 'honeypot') {
showSecurityError(checkerId, errorMessage, false);
return;
}
-
+
// Generic error
showSecurityError(checkerId, errorMessage, false);
} else if (response && response.message) {
@@ -199,12 +190,12 @@ jQuery(document).ready(function ($) {
function refreshRecaptchaToken(checkerId) {
return new Promise(function(resolve, reject) {
var thisChecker = $("#checker-" + checkerId);
-
+
if (typeof grecaptcha === 'undefined' || !window.checkerRecaptcha) {
resolve(); // No reCAPTCHA configured
return;
}
-
+
grecaptcha.ready(function() {
grecaptcha.execute(window.checkerRecaptcha.siteKey, {
action: window.checkerRecaptcha.action || 'submit'
@@ -217,7 +208,6 @@ jQuery(document).ready(function ($) {
tokenInput.val(token).attr('data-timestamp', Date.now().toString());
resolve();
}).catch(function(error) {
- console.error('reCAPTCHA refresh error:', error);
reject(error);
});
});
@@ -246,19 +236,33 @@ jQuery(document).ready(function ($) {
}
function ensureCaptchaReady(checkerId) {
- // If reCAPTCHA is configured, always refresh/generate a token (it will create the hidden input if missing)
+ var thisChecker = $("#checker-" + checkerId);
+
+ // If reCAPTCHA is configured, check if we need to refresh the token
if (window.checkerRecaptcha) {
+ var tokenInput = thisChecker.find('input[name="recaptcha_token"]');
+ var hasToken = tokenInput.length && tokenInput.val();
+
+ // Check token age
+ if (hasToken) {
+ var tokenAge = Date.now() - parseInt(tokenInput.attr('data-timestamp') || '0');
+ // Token is valid for 2 minutes, use it if it's less than 90 seconds old
+ if (tokenAge < 90000) {
+ return Promise.resolve();
+ }
+ }
+
return waitForRecaptcha()
.then(function() {
return refreshRecaptchaToken(checkerId);
})
.catch(function(err) {
- return Promise.reject(err);
+ var errorMsg = err ? err.message : "reCAPTCHA verification failed";
+ return Promise.reject(new Error(errorMsg));
});
}
// Refresh Turnstile if stale
- var thisChecker = $("#checker-" + checkerId);
var turnstileInput = thisChecker.find('input[name="turnstile_token"]');
if (turnstileInput.length && turnstileInput.val()) {
var ts = parseInt(turnstileInput.attr("data-timestamp") || "0");
@@ -271,19 +275,23 @@ jQuery(document).ready(function ($) {
turnstileInput.val("");
}
}
+
return Promise.resolve();
}
- function waitForRecaptcha(timeoutMs = 5000) {
+ function waitForRecaptcha(timeoutMs = 10000) {
return new Promise(function(resolve, reject) {
var start = Date.now();
+
(function check() {
if (typeof grecaptcha !== "undefined" && typeof grecaptcha.ready === "function") {
return resolve();
}
+
if (Date.now() - start > timeoutMs) {
- return reject(new Error("reCAPTCHA script not loaded"));
+ return reject(new Error("reCAPTCHA script failed to load. Please check your internet connection or try disabling reCAPTCHA."));
}
+
setTimeout(check, 200);
})();
});
@@ -309,10 +317,9 @@ jQuery(document).ready(function ($) {
loadAllData(checkerId, settings, true); // true = initial load
}
- // Preload captcha tokens to surface badge and avoid first-click delays
- ensureCaptchaReady(checkerId).catch(function(err){
- console.warn("Captcha preload failed", err);
- showSecurityError(checkerId, checkerSecurity.i18n ? checkerSecurity.i18n.security_error : "Security validation failed.", false);
+ // Preload reCAPTCHA token on page load (improves score by showing natural browsing behavior)
+ ensureCaptchaReady(checkerId).catch(function(){
+ // Silently fail on preload - will retry on submit
});
}
});
@@ -585,10 +592,16 @@ jQuery(document).ready(function ($) {
var button_text = escapeHtml(outputSetting.button_text || "Click");
var bg_color = escapeHtml(outputSetting.bg_color || "#333333");
var text_color = escapeHtml(outputSetting.text_color || "#ffffff");
+ var empty_fallback = escapeHtml(outputSetting.empty_fallback || "");
var safeQ = escapeHtml(q);
var safeVal = escapeHtml(r);
+ var isEmpty = !r || String(r).trim() === "";
- if (type == "link_button") {
+ if (isEmpty && empty_fallback) {
+ safeVal = empty_fallback;
+ } else if (isEmpty) {
+ safeVal = "";
+ } else if (type == "link_button") {
safeVal =
'' +
- button_text +
+ '" target="_blank" rel="noopener" style="background-color: ' +
+ escapeHtml(bg_color) +
+ "; color: " +
+ escapeHtml(text_color) +
+ ';">' +
+ escapeHtml(button_text) +
"";
} else if (type == "whatsapp_button") {
r =
'' +
- button_text +
+ '" target="_blank" rel="noopener" style="background-color: ' +
+ escapeHtml(bg_color) +
+ "; color: " +
+ escapeHtml(text_color) +
+ ';">' +
+ escapeHtml(button_text) +
"";
} else if (type == "image") {
r =
'
';
+ } else if (type == "text") {
+ r = escapeHtml(r);
}
resultDiv += "
";
resultDiv +=
@@ -1308,7 +1371,7 @@ jQuery(document).ready(function ($) {
'px;">";
resultDiv +=
'| ' +
- prefix +
+ escapeHtml(prefix || "") +
r +
" | ";
resultDiv += "
";
@@ -1358,49 +1421,76 @@ jQuery(document).ready(function ($) {
var prefix = "";
var type = "";
var button_text = "";
+ var empty_fallback = "";
var hidden = "no";
+ var bg_color = "#333333";
+ var text_color = "#ffffff";
$.each(res.output, function (o, p) {
if (q == p.key) {
prefix = p.prefix;
type = p.type;
button_text = p.button_text;
+ if ("empty_fallback" in p) {
+ empty_fallback = p.empty_fallback;
+ }
if ("hide" in p) {
hidden = p.hide;
}
+ if ("bg_color" in p) {
+ bg_color = p.bg_color;
+ }
+ if ("text_color" in p) {
+ text_color = p.text_color;
+ }
}
});
if (hidden == "yes") {
return;
}
- if (type == "link_button") {
+ var isEmpty = !r || String(r).trim() === "";
+ if (isEmpty && empty_fallback) {
+ r = escapeHtml(empty_fallback);
+ } else if (isEmpty) {
+ r = "";
+ } else if (type == "link_button") {
r =
'' +
- button_text +
+ '" target="_blank" rel="noopener" style="background-color: ' +
+ escapeHtml(bg_color) +
+ "; color: " +
+ escapeHtml(text_color) +
+ ';">' +
+ escapeHtml(button_text) +
"";
} else if (type == "whatsapp_button") {
r =
'' +
- button_text +
+ '" target="_blank" rel="noopener" style="background-color: ' +
+ escapeHtml(bg_color) +
+ "; color: " +
+ escapeHtml(text_color) +
+ ';">' +
+ escapeHtml(button_text) +
"";
} else if (type == "image") {
r =
'
';
+ } else if (type == "text") {
+ r = escapeHtml(r);
}
resultDiv +=
@@ -1413,13 +1503,13 @@ jQuery(document).ready(function ($) {
'";
resultDiv +=
'' +
- prefix +
+ escapeHtml(prefix || "") +
r +
"
";
resultDiv += "";
@@ -1466,49 +1556,76 @@ jQuery(document).ready(function ($) {
var prefix = "";
var type = "";
var button_text = "";
+ var empty_fallback = "";
var hidden = "no";
+ var bg_color = "#333333";
+ var text_color = "#ffffff";
$.each(res.output, function (o, p) {
if (q == p.key) {
prefix = p.prefix;
type = p.type;
button_text = p.button_text;
+ if ("empty_fallback" in p) {
+ empty_fallback = p.empty_fallback;
+ }
if ("hide" in p) {
hidden = p.hide;
}
+ if ("bg_color" in p) {
+ bg_color = p.bg_color;
+ }
+ if ("text_color" in p) {
+ text_color = p.text_color;
+ }
}
});
if (hidden == "yes") {
return;
}
- if (type == "link_button") {
+ var isEmpty = !r || String(r).trim() === "";
+ if (isEmpty && empty_fallback) {
+ r = escapeHtml(empty_fallback);
+ } else if (isEmpty) {
+ r = "";
+ } else if (type == "link_button") {
r =
'' +
- button_text +
+ '" target="_blank" rel="noopener" style="background-color: ' +
+ escapeHtml(bg_color) +
+ "; color: " +
+ escapeHtml(text_color) +
+ ';">' +
+ escapeHtml(button_text) +
"";
} else if (type == "whatsapp_button") {
r =
'' +
- button_text +
+ '" target="_blank" rel="noopener" style="background-color: ' +
+ escapeHtml(bg_color) +
+ "; color: " +
+ escapeHtml(text_color) +
+ ';">' +
+ escapeHtml(button_text) +
"";
} else if (type == "image") {
r =
'
';
+ } else if (type == "text") {
+ r = escapeHtml(r);
}
resultDiv +=
'' +
- prefix +
+ escapeHtml(prefix || "") +
r +
" | ";
});
@@ -1614,6 +1731,7 @@ jQuery(document).ready(function ($) {
var prefix = "";
var type = "";
var button_text = "";
+ var empty_fallback = "";
var hidden = "no";
var bg_color = "#cccccc";
var text_color = "#000000";
@@ -1622,6 +1740,9 @@ jQuery(document).ready(function ($) {
prefix = p.prefix;
type = p.type;
button_text = p.button_text;
+ if ("empty_fallback" in p) {
+ empty_fallback = p.empty_fallback;
+ }
if ("hide" in p) {
hidden = p.hide;
}
@@ -1636,35 +1757,42 @@ jQuery(document).ready(function ($) {
if (hidden == "yes") {
return;
}
- if (type == "link_button") {
+ var isEmpty = !r || String(r).trim() === "";
+ if (isEmpty && empty_fallback) {
+ r = escapeHtml(empty_fallback);
+ } else if (isEmpty) {
+ r = "";
+ } else if (type == "link_button") {
r =
'' +
- button_text +
+ escapeHtml(button_text) +
"";
} else if (type == "whatsapp_button") {
r =
'' +
- button_text +
+ escapeHtml(button_text) +
"";
} else if (type == "image") {
r =
'
';
+ } else if (type == "text") {
+ r = escapeHtml(r);
}
resultDiv +=
`` +
- q +
+ escapeHtml(q) +
`
` +
- prefix +
+ escapeHtml(prefix || "") +
r +
`
`;
@@ -1706,11 +1834,20 @@ jQuery(document).ready(function ($) {
ensureCaptchaReady($id)
.then(function() {
+ // Double-check that reCAPTCHA token exists before proceeding
+ if (window.checkerRecaptcha) {
+ var tokenInput = this_checker.find('input[name="recaptcha_token"]');
+ if (!tokenInput.val()) {
+ showSecurityError($id, checkerSecurity.i18n ? checkerSecurity.i18n.recaptcha_failed : "reCAPTCHA verification failed. Please try again.", false);
+ $this.text($this.attr("data-btn-text")).prop("disabled", false);
+ return;
+ }
+ }
performSearch();
})
- .catch(function(err) {
- console.error("Captcha refresh failed", err);
- showSecurityError($id, checkerSecurity.i18n ? checkerSecurity.i18n.security_error : "Security validation failed.", false);
+ .catch(function() {
+ showSecurityError($id, checkerSecurity.i18n ? checkerSecurity.i18n.recaptcha_failed : "reCAPTCHA verification failed. Please try again.", false);
+ $this.text($this.attr("data-btn-text")).prop("disabled", false);
});
}
}
diff --git a/dw-sheet-data-checker-pro.php b/dw-sheet-data-checker-pro.php
index 027ca5e..545b764 100644
--- a/dw-sheet-data-checker-pro.php
+++ b/dw-sheet-data-checker-pro.php
@@ -2,7 +2,7 @@
/**
* Plugin Name: Sheet Data Checker Pro
* Description: Check data from Google Sheet with customizable filter form
- * Version: 1.4.5
+ * Version: 1.4.10
* Plugin URI: https://dwindi.com/sheet-data-checker
* Author: Dwindi Ramadhana
* Author URI: https://facebook.com/dwindi.ramadhana
@@ -35,7 +35,7 @@ if ( ! defined( 'SHEET_CHECKER_PRO_BASENAME' ) ) {
}
if ( ! defined( 'SHEET_CHECKER_PRO_VERSION' ) ) {
- define( 'SHEET_CHECKER_PRO_VERSION', '1.4.5' );
+ define( 'SHEET_CHECKER_PRO_VERSION', '1.4.10' );
}
if ( ! defined( 'SHEET_CHECKER_PRO_URL' ) ) {
diff --git a/includes/class-Security.php b/includes/class-Security.php
index 3888270..925b0a5 100644
--- a/includes/class-Security.php
+++ b/includes/class-Security.php
@@ -127,7 +127,7 @@ class CHECKER_SECURITY {
$secret_key_raw = isset($checker['security']['recaptcha']['secret_key']) ? $checker['security']['recaptcha']['secret_key'] : '';
$secret_key = trim((string) $secret_key_raw);
- $min_score_raw = isset($checker['security']['recaptcha']['min_score']) ? $checker['security']['recaptcha']['min_score'] : 0.5;
+ $min_score_raw = isset($checker['security']['recaptcha']['min_score']) ? $checker['security']['recaptcha']['min_score'] : 0.3;
if (is_string($min_score_raw)) {
$min_score_raw = str_replace(',', '.', $min_score_raw);
}
@@ -199,15 +199,12 @@ class CHECKER_SECURITY {
}
if ($score < $min_score) {
- error_log("Sheet Data Checker: reCAPTCHA score too low - Score: {$score}, Min: {$min_score}");
return [
'success' => false,
'score' => $score,
- 'message' => 'reCAPTCHA score too low. Please try again.'
+ 'message' => "reCAPTCHA score too low ({$score}). Please try again."
];
}
-
- error_log("Sheet Data Checker: reCAPTCHA verification SUCCESS - Score: {$score}, Action: {$response_action}");
return [
'success' => true,
diff --git a/includes/class-Sheet-Data-Checker-Pro.php b/includes/class-Sheet-Data-Checker-Pro.php
index 7a441f2..aff6f2b 100644
--- a/includes/class-Sheet-Data-Checker-Pro.php
+++ b/includes/class-Sheet-Data-Checker-Pro.php
@@ -504,6 +504,7 @@ class SHEET_DATA_CHECKER_PRO
'type' => isset($checker['output'][$id]['type']) ? $checker['output'][$id]['type'] : 'text',
'button_text' => isset($checker['output'][$id]['button_text']) ? $checker['output'][$id]['button_text'] : '',
'prefix' => isset($checker['output'][$id]['prefix']) ? $checker['output'][$id]['prefix'] : '',
+ 'empty_fallback' => isset($checker['output'][$id]['empty_fallback']) ? $checker['output'][$id]['empty_fallback'] : '',
'bg_color' => isset($checker['output'][$id]['bg_color']) ? $checker['output'][$id]['bg_color'] : '#cccccc',
'text_color' => isset($checker['output'][$id]['text_color']) ? $checker['output'][$id]['text_color'] : '#000000',
'display' => isset($checker['result']['display']) && $checker['result']['display'] == 'card'
diff --git a/includes/helpers/class-Captcha-Helper.php b/includes/helpers/class-Captcha-Helper.php
index 8a34129..72f4489 100644
--- a/includes/helpers/class-Captcha-Helper.php
+++ b/includes/helpers/class-Captcha-Helper.php
@@ -60,7 +60,8 @@ class CHECKER_CAPTCHA_HELPER {
}
} elseif ($recaptcha_enabled) {
$site_key = $checker['security']['recaptcha']['site_key'] ?? '';
- $action = $checker['security']['recaptcha']['action'] ?? 'checker_validate';
+ // Default action must match JavaScript default ('submit') to avoid score penalties
+ $action = $checker['security']['recaptcha']['action'] ?? 'submit';
$hide_badge = $checker['security']['recaptcha']['hide_badge'] ?? 'no';
if ($site_key) {
@@ -87,101 +88,31 @@ class CHECKER_CAPTCHA_HELPER {
true
);
- // Pass settings to JavaScript
+ // Pass settings to JavaScript - let public.js handle token generation
wp_add_inline_script(
'google-recaptcha-v3',
'
document.addEventListener("DOMContentLoaded", function() {
- console.log("[CAPTCHA Debug] DOMContentLoaded - checking for grecaptcha...");
- console.log("[CAPTCHA Debug] grecaptcha available:", typeof grecaptcha !== "undefined");
-
if (typeof grecaptcha !== "undefined") {
- console.log("[CAPTCHA Debug] reCAPTCHA v3 detected, initializing...");
-
- // Store reCAPTCHA settings globally
+ // Store reCAPTCHA settings globally for public.js to use
window.checkerRecaptcha = {
siteKey: "' . esc_js($site_key) . '",
action: "' . esc_js($action) . '"
};
-
- console.log("[CAPTCHA Debug] reCAPTCHA settings:", window.checkerRecaptcha);
' . ($hide_badge ? '
// Hide reCAPTCHA badge
var style = document.createElement("style");
style.innerHTML = ".grecaptcha-badge { display: none !important; }";
document.head.appendChild(style);
- console.log("[CAPTCHA Debug] reCAPTCHA badge hidden");
' : '
// Ensure badge is visible
var style = document.createElement("style");
style.innerHTML = ".grecaptcha-badge { visibility: visible !important; opacity: 1 !important; display: block !important; }";
document.head.appendChild(style);
') . '
-
- // Initialize reCAPTCHA for all checker forms
- initRecaptchaForForms();
- console.log("[CAPTCHA Debug] reCAPTCHA initialization complete");
- } else {
- console.error("[CAPTCHA Debug] grecaptcha NOT available - script may not have loaded");
}
- });
-
- function initRecaptchaForForms() {
- var forms = document.querySelectorAll(".dw-checker-container form");
- forms.forEach(function(form) {
- var searchButton = form.querySelector(".search-button");
- if (!searchButton) return;
-
- // Generate token when search button is clicked
- searchButton.addEventListener("click", function(e) {
- var tokenInput = form.querySelector("input[name=recaptcha_token]");
-
- // If token already exists and is recent (less than 2 minutes old), don\'t regenerate
- if (tokenInput && tokenInput.value && tokenInput.dataset.timestamp) {
- var tokenAge = Date.now() - parseInt(tokenInput.dataset.timestamp);
- if (tokenAge < 120000) { // 2 minutes
- console.log("reCAPTCHA: Using existing token (age: " + Math.floor(tokenAge/1000) + "s)");
- return; // Let the click proceed with existing token
- }
- }
-
- // Prevent default to wait for token generation
- var hasToken = tokenInput && tokenInput.value;
- if (!hasToken) {
- e.preventDefault();
- e.stopImmediatePropagation();
-
- console.log("reCAPTCHA: Generating new token...");
-
- // Generate new token
- grecaptcha.ready(function() {
- grecaptcha.execute(
- window.checkerRecaptcha.siteKey,
- {action: window.checkerRecaptcha.action}
- ).then(function(token) {
- console.log("reCAPTCHA: Token generated successfully");
- // Add or update token in hidden input
- if (!tokenInput) {
- tokenInput = document.createElement("input");
- tokenInput.type = "hidden";
- tokenInput.name = "recaptcha_token";
- form.appendChild(tokenInput);
- }
- tokenInput.value = token;
- tokenInput.dataset.timestamp = Date.now().toString();
-
- // Trigger the search button click again
- searchButton.click();
- }).catch(function(error) {
- console.error("reCAPTCHA error:", error);
- alert("reCAPTCHA verification failed. Please refresh the page.");
- });
- });
- }
- }, true); // Use capture phase to run before other click handlers
- });
- }'
+ });'
);
}
@@ -208,24 +139,16 @@ class CHECKER_CAPTCHA_HELPER {
'cloudflare-turnstile',
'
window.onloadTurnstileCallback = function() {
- console.log("[CAPTCHA Debug] Turnstile callback triggered");
-
// Store Turnstile settings globally
window.checkerTurnstile = {
siteKey: "' . esc_js($site_key) . '",
theme: "' . esc_js($theme) . '",
size: "' . esc_js($size) . '"
};
-
- console.log("[CAPTCHA Debug] Turnstile settings:", window.checkerTurnstile);
// Initialize Turnstile for all checker forms
initTurnstileForForms();
- console.log("[CAPTCHA Debug] Turnstile initialization complete");
};
-
- // Also log when script loads
- console.log("[CAPTCHA Debug] Turnstile script loading...");
function initTurnstileForForms() {
var forms = document.querySelectorAll(".dw-checker-container form");
@@ -244,7 +167,6 @@ class CHECKER_CAPTCHA_HELPER {
}
// Render Turnstile widget
- console.log("Turnstile: Initializing widget");
turnstile.render(container, {
sitekey: window.checkerTurnstile.siteKey,
theme: window.checkerTurnstile.theme,
@@ -264,10 +186,10 @@ class CHECKER_CAPTCHA_HELPER {
console.log("Turnstile: Token stored in form");
},
"error-callback": function(error) {
- console.error("Turnstile error:", error);
+ // Silently handle errors
},
"expired-callback": function() {
- console.warn("Turnstile: Token expired, please complete challenge again");
+ // Reset expired token
var input = form.querySelector("input[name=turnstile_token]");
if (input) {
input.value = "";
diff --git a/templates/editor/js-template-setting-output.php b/templates/editor/js-template-setting-output.php
index 0970604..424aeb7 100644
--- a/templates/editor/js-template-setting-output.php
+++ b/templates/editor/js-template-setting-output.php
@@ -23,32 +23,36 @@
-
{{/each}}