Skip to content

Commit 77e55ca

Browse files
committed
Final version bump to v5.2.4 for public release.
1 parent d7189a6 commit 77e55ca

40 files changed

Lines changed: 1481 additions & 976 deletions

CHANGELOG.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
= 5.2.4 - 25/06/2026 =
2+
* Enhance - User role overwritten on new membership assignment.
3+
* Enhance - Add customizable membership registration success message in settings.
4+
* Fix - Duplicate variable.
5+
* Fix - Invoice dynamic content not translatable.
6+
* Fix - Missing users in user registration members section.
7+
* Fix - Validation of key while saving the stripe payment settings.
8+
* Fix - My Account payment tab pulling footer content inside the tab area.
9+
* Fix - Address incomplete PayPal setup error when adding PayPal for old user.
10+
* Fix - hCaptcha enabled on registration form blocks users from completing signup.
11+
* Fix - Reset content button not working in the prevent concurrent login email template.
12+
* Fix - New Member Registered email not sent when Admin Approval Request email is enabled.
13+
* Fix - Harden membership coupon apply paths against PHP 8 TypeError (free membership module).
14+
* Fix - File upload attachments not updating correctly when admin edits another user's profile.
15+
* Fix - Registration failure causes missing member records and prevents Stripe payment processing.
16+
17+
118
= 5.2.3 - 23/06/2026 =
219
* Fix - validation for receiver email and payment amount in PayPal IPN handling.
320
* Fix - Selected membership tier during registration missed proper validation, allowing assignment of off-form membership tiers.

assets/js/admin/form-modal.js

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// Sweetalert modal popup on reset content clicked.
1919
$(document).on("click", ".ur-reset-content-button", function (event) {
2020
event.preventDefault();
21+
var editorIdFromButton = $(this).data("editor");
2122
Swal.fire({
2223
title: "Reset to Default",
2324
text: "Are you sure you want to reset the email content to the default?",
@@ -31,28 +32,61 @@
3132
var params = new URLSearchParams(window.location.search);
3233
var section = params.get("section");
3334
if (section) {
34-
var selector = section.replace(
35+
var baseSelector = section.replace(
3536
/^ur_settings_/,
3637
"user_registration_"
3738
);
38-
var editor =
39-
typeof tinymce !== "undefined"
40-
? tinymce.get(selector)
41-
: null;
39+
// Resolve the actual editor/textarea id. Prefer the
40+
// data-editor attribute on the button, then fall back
41+
// to the base selector (existing emails), then to the
42+
// base + "_content" (newer emails like prevent
43+
// concurrent login).
44+
var candidates = [];
45+
if (editorIdFromButton) {
46+
candidates.push(editorIdFromButton);
47+
}
48+
candidates.push(baseSelector);
49+
candidates.push(baseSelector + "_content");
50+
51+
var selector = null;
52+
var editor = null;
53+
for (var i = 0; i < candidates.length; i++) {
54+
var candidate = candidates[i];
55+
var candidateEditor =
56+
typeof tinymce !== "undefined"
57+
? tinymce.get(candidate)
58+
: null;
59+
if (candidateEditor) {
60+
selector = candidate;
61+
editor = candidateEditor;
62+
break;
63+
}
64+
if ($("textarea#" + candidate).length) {
65+
selector = candidate;
66+
break;
67+
}
68+
}
69+
70+
if (!selector) {
71+
return;
72+
}
73+
74+
var defaultContent =
75+
user_registration_email_settings &&
76+
user_registration_email_settings[section];
77+
if (typeof defaultContent === "undefined") {
78+
return;
79+
}
80+
4281
if (editor && !editor.isHidden()) {
43-
var content = user_registration_email_settings[
44-
section
45-
]
82+
var content = defaultContent
4683
.replace(/\n\n/g, "<br>")
4784
.replace(/\t/g, "");
4885
editor.setContent(content);
4986
} else {
5087
var $textarea = $("textarea#" + selector);
5188
if ($textarea.length) {
52-
var content = user_registration_email_settings[
53-
section
54-
].replace(/\t/g, "");
55-
$textarea.val(content);
89+
$textarea.val(defaultContent.replace(/\t/g, ""));
5690
}
5791
}
5892
}

assets/js/admin/form-modal.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/js/admin/settings.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,27 @@
17481748
section_data[name] = value;
17491749
});
17501750

1751+
if ( setting_id === "stripe" ) {
1752+
var testPubKey = section_data["user_registration_stripe_test_publishable_key"] || "";
1753+
var livePubKey = section_data["user_registration_stripe_live_publishable_key"] || "";
1754+
1755+
if ( testPubKey && testPubKey.indexOf( "pk_test_" ) !== 0 ) {
1756+
$this.find( ".ur-spinner" ).remove();
1757+
show_failure_message(
1758+
user_registration_settings_params.i18n.invalid_stripe_test_publishable_key
1759+
);
1760+
return;
1761+
}
1762+
1763+
if ( livePubKey && livePubKey.indexOf( "pk_live_" ) !== 0 ) {
1764+
$this.find( ".ur-spinner" ).remove();
1765+
show_failure_message(
1766+
user_registration_settings_params.i18n.invalid_stripe_live_publishable_key
1767+
);
1768+
return;
1769+
}
1770+
}
1771+
17511772
update_payment_section_settings(
17521773
setting_id,
17531774
section_data,

assets/js/admin/settings.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/js/frontend/user-registration-recaptcha.js

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,24 @@ var createDedicatedHcaptchaLoader = function() {
7373
return 'hcaptcha-loading';
7474
},
7575
reset: function(widgetId) {
76-
if (window.hcaptcha && window.hcaptcha.reset) {
77-
window.hcaptcha.reset(widgetId);
78-
}
76+
// widgetId is a string placeholder ('hcaptcha-loading') until the
77+
// real widget has rendered; resetting with it throws and aborts
78+
// submission, so only reset a real (numeric) widget id and never throw.
79+
try {
80+
if (window.hcaptcha && window.hcaptcha.reset && typeof widgetId !== 'string') {
81+
window.hcaptcha.reset(widgetId);
82+
}
83+
} catch (e) {}
7984
},
8085
execute: function(siteKey, options) {
81-
if (window.hcaptcha && window.hcaptcha.execute) {
82-
window.hcaptcha.execute(siteKey, options);
83-
}
86+
try {
87+
if (window.hcaptcha && window.hcaptcha.execute) {
88+
window.hcaptcha.execute(siteKey, options);
89+
}
90+
} catch (e) {}
8491
},
8592
getResponse: function(widgetId) {
86-
if (window.hcaptcha && window.hcaptcha.getResponse) {
93+
if (window.hcaptcha && window.hcaptcha.getResponse && typeof widgetId !== 'string') {
8794
return window.hcaptcha.getResponse(widgetId);
8895
}
8996
return '';
@@ -140,17 +147,23 @@ var createDedicatedRecaptchaLoader = function() {
140147
return 'recaptcha-loading';
141148
},
142149
reset: function(widgetId) {
143-
if (window.grecaptcha && window.grecaptcha.reset) {
144-
window.grecaptcha.reset(widgetId);
145-
}
150+
// Skip the 'recaptcha-loading' placeholder id and never throw, so a
151+
// captcha reset can't abort form submission.
152+
try {
153+
if (window.grecaptcha && window.grecaptcha.reset && typeof widgetId !== 'string') {
154+
window.grecaptcha.reset(widgetId);
155+
}
156+
} catch (e) {}
146157
},
147158
execute: function(siteKey, options) {
148-
if (window.grecaptcha && window.grecaptcha.execute) {
149-
window.grecaptcha.execute(siteKey, options);
150-
}
159+
try {
160+
if (window.grecaptcha && window.grecaptcha.execute) {
161+
window.grecaptcha.execute(siteKey, options);
162+
}
163+
} catch (e) {}
151164
},
152165
getResponse: function(widgetId) {
153-
if (window.grecaptcha && window.grecaptcha.getResponse) {
166+
if (window.grecaptcha && window.grecaptcha.getResponse && typeof widgetId !== 'string') {
154167
return window.grecaptcha.getResponse(widgetId);
155168
}
156169
return '';
@@ -288,6 +301,12 @@ var backupOriginalGlobals = function() {
288301
// Function to load fresh reCAPTCHA when all backups are hCaptcha
289302
var freshRecaptchaLoading = false;
290303
var loadFreshRecaptcha = function() {
304+
// Only pull in Google reCAPTCHA when it is actually the configured captcha.
305+
// Loading it on an hCaptcha-only form adds a second SDK whose compat shim
306+
// then conflicts on window.grecaptcha. (Both v2 and v3 use ur_recaptcha_code.)
307+
if (typeof ur_recaptcha_code === 'undefined' || !ur_recaptcha_code.site_key) {
308+
return;
309+
}
291310
if (typeof window.ur_fresh_grecaptcha === 'undefined' && !freshRecaptchaLoading) {
292311
freshRecaptchaLoading = true;
293312
var script = document.createElement('script');
@@ -397,10 +416,12 @@ var protectGrecaptcha = function() {
397416
}
398417
});
399418

419+
// Keep this writable/configurable: locking it down makes hCaptcha's
420+
// grecaptcha compat shim throw "Cannot assign to read only property".
400421
Object.defineProperty(window, 'grecaptcha', {
401422
value: grecaptchaProxy,
402-
writable: false,
403-
configurable: false
423+
writable: true,
424+
configurable: true
404425
});
405426
} catch (e) {
406427
// Silent fail

assets/js/frontend/user-registration-recaptcha.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/js/frontend/user-registration.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,7 @@
11601160
var captchaResponse = "";
11611161
var registration_language = "";
11621162
if (
1163-
"hcaptcha" ===
1163+
"hCaptcha" ===
11641164
user_registration_params.recaptcha_type
11651165
) {
11661166
captchaResponse = $this

assets/js/frontend/user-registration.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

includes/admin/class-ur-admin-settings.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ function initMultiselectV2() {
258258
'pro_install_popup_title' => esc_html__( 'Install User Registration & Membership Pro to Unlock All Features', 'user-registration' ),
259259
'will_install_and_activate_pro_text' => esc_html__( 'This will automatically install and activate the User Registration & Membership Pro Plugin for you.', 'user-registration' ),
260260
'installing_plugin_text' => esc_html__( 'Installing Plugin', 'user-registration' ),
261+
'invalid_stripe_test_publishable_key' => esc_html__( 'Invalid Stripe test publishable key. It must start with pk_test_.', 'user-registration' ),
262+
'invalid_stripe_live_publishable_key' => esc_html__( 'Invalid Stripe live publishable key. It must start with pk_live_.', 'user-registration' ),
261263
'pro_activated_success_title' => esc_html__( 'Success!', 'user-registration' ),
262264
'pro_activated_success_text' => esc_html__( 'URM Pro has been successfully installed and activated. You now have access to all premium features!', 'user-registration' ),
263265
'continue_to_dashboard_text' => esc_html__( 'Continue to dashboard', 'user-registration' ),

0 commit comments

Comments
 (0)