From 58c53ca1795dc3aab013c5d586e165b7bdf63f84 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 30 Jun 2023 01:34:08 +0300 Subject: [PATCH 01/11] - updated versions; --- README.md | 2 +- readme.txt | 7 +++++++ ultimate-member.php | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 95c67922..6c5de17f 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ GNU Version 2 or Any Later Version ## Releases -[Official Release Version: 2.6.6](https://github.com/ultimatemember/ultimatemember/releases/tag/2.6.6). +[Official Release Version: 2.6.7](https://github.com/ultimatemember/ultimatemember/releases/tag/2.6.7). ## Changelog diff --git a/readme.txt b/readme.txt index 06f8c613..c7031699 100644 --- a/readme.txt +++ b/readme.txt @@ -163,6 +163,13 @@ No, you do not need to use our plugin’s login or registration pages and can us * To learn more about version 2.1 please see this [docs](https://docs.ultimatemember.com/article/1512-upgrade-2-1-0) * UM2.1+ is a significant update to the Member Directories' code base from 2.0.x. Please make sure you take a full-site backup with restore point before updating the plugin += 2.6.7: July xx, 2023 = + +* Bugfixes: + + - Fixed: A privilege escalation vulnerability used through UM Forms. Known in the wild that vulnerability allowed strangers to create administrator-level WordPress users. Please update immediately and check all administrator-level users on your website. + - Fixed: Displaying fields on Account page > Privacy > Member directory settings + = 2.6.6: June 29, 2023 = * Bugfixes: diff --git a/ultimate-member.php b/ultimate-member.php index 11466c42..7bf23571 100644 --- a/ultimate-member.php +++ b/ultimate-member.php @@ -3,7 +3,7 @@ Plugin Name: Ultimate Member Plugin URI: http://ultimatemember.com/ Description: The easiest way to create powerful online communities and beautiful user profiles with WordPress -Version: 2.6.6 +Version: 2.6.7-alpha Author: Ultimate Member Author URI: http://ultimatemember.com/ Text Domain: ultimate-member From 71f236069434d144d4d9af0766de1b0040055cf1 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 30 Jun 2023 15:56:30 +0300 Subject: [PATCH 02/11] - review login form and submission data. optimized submission; --- includes/core/class-form.php | 372 +++++++++++++++++----------- includes/core/class-login.php | 85 +++---- includes/core/um-actions-form.php | 280 ++++++++++----------- includes/core/um-actions-login.php | 156 ++++++------ includes/core/um-filters-fields.php | 47 ++-- includes/core/um-filters-login.php | 12 +- 6 files changed, 504 insertions(+), 448 deletions(-) diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 76ce15f8..5ae5f373 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -55,6 +55,15 @@ if ( ! class_exists( 'um\core\Form' ) ) { */ public $all_fields = array(); + /** + * Whitelisted usermeta that can be stored when UM Form is submitted. + * + * @since 2.6.7 + * + * @var array + */ + private $usermeta_whitelist = array(); + /** * Form constructor. */ @@ -401,7 +410,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { } else { $http_post = 'POST'; } - + // Handles Register, Profile and Login forms. if ( $http_post && ! is_admin() && isset( $_POST['form_id'] ) && is_numeric( $_POST['form_id'] ) ) { $this->form_id = absint( $_POST['form_id'] ); @@ -414,185 +423,268 @@ if ( ! class_exists( 'um\core\Form' ) ) { return; } - $this->form_data = UM()->query()->post_data( $this->form_id ); + // Verified that form_id is right and UM form is published. Then get form data. + + $this->form_data = UM()->query()->post_data( $this->form_id ); + + // Checking the form custom fields. Form without custom fields is invalid. + if ( ! array_key_exists( 'mode', $this->form_data ) ) { + return; + } + + // Checking the form custom fields. Form without custom fields is invalid. + if ( ! array_key_exists( 'custom_fields', $this->form_data ) ) { + return; + } + + $custom_fields = maybe_unserialize( $this->form_data['custom_fields'] ); + if ( ! is_array( $custom_fields ) || empty( $custom_fields ) ) { + return; + } + + $field_types_without_metakey = UM()->builtin()->get_fields_without_metakey(); + foreach ( $custom_fields as $cf_k => $cf_data ) { + if ( ! array_key_exists( 'type', $cf_data ) || in_array( $cf_data['type'], $field_types_without_metakey, true ) ) { + unset( $custom_fields[ $cf_k ] ); + } + if ( ! array_key_exists( 'metakey', $cf_data ) || empty( $cf_data['metakey'] ) ) { + unset( $custom_fields[ $cf_k ] ); + } + } + $cf_metakeys = array_column( $custom_fields, 'metakey' ); + $all_cf_metakeys = $cf_metakeys; + + // The '_um_last_login' cannot be updated through UM form. + $cf_metakeys = array_values( array_diff( $cf_metakeys, array( 'role_select', 'role_radio', 'role', '_um_last_login' ) ) ); + if ( 'register' === $this->form_data['mode'] ) { + $cf_metakeys[] = 'submitted'; + } /** - * UM hook + * Fires before UM login, registration or profile form submission. * - * @type action - * @title um_before_submit_form_post - * @description Before submit form - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_before_submit_form_post', 'function_name', 10, 1 ); - * @example - * form() class instance. Since 2.6.7 + * + * @example Make any custom action before UM login, registration or profile form submission. + * function my_custom_before_submit_form_post( $um_form_obj ) { * // your code here * } - * ?> + * add_action( 'um_before_submit_form_post', 'my_custom_before_submit_form_post' ); */ - do_action( 'um_before_submit_form_post' ); + do_action( 'um_before_submit_form_post', $this ); /* save entire form as global */ /** - * UM hook + * Filters $_POST submitted data by the UM login, registration or profile form. * - * @type filter - * @title um_submit_post_form - * @description Change submitted data on form submit - * @input_vars - * [{"var":"$data","type":"array","desc":"Submitted data"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * Extends $_POST data. + * function my_submit_post_form( $_post ) { + * $_post['some_key'] = 'some value'; + * return $_post; * } - * ?> + * add_filter( 'um_submit_post_form', 'my_submit_post_form' ); */ $this->post_form = apply_filters( 'um_submit_post_form', wp_unslash( $_POST ) ); + // Validate form submission by honeypot. if ( isset( $this->post_form[ UM()->honeypot ] ) && '' !== $this->post_form[ UM()->honeypot ] ) { + // High level escape if hacking. wp_die( esc_html__( 'Hello, spam bot!', 'ultimate-member' ) ); } - $this->post_form = $this->beautify( $this->post_form ); - $this->post_form = $this->sanitize( $this->post_form ); - $this->post_form['submitted'] = $this->post_form; - - $this->post_form = array_merge( $this->form_data, $this->post_form ); + $this->post_form = $this->beautify( $this->post_form ); + // Validate and filter 'role' submitted data to avoid handling roles with admin privileges. // Remove role from post_form at first if role ! empty and there aren't custom fields with role name - if ( ! empty( $_POST['role'] ) ) { - if ( ! isset( $this->form_data['custom_fields'] ) || ! strstr( $this->form_data['custom_fields'], 'role_' ) ) { + $maybe_set_default_role = true; + if ( array_key_exists( 'role', $this->post_form ) ) { + if ( 'login' === $this->form_data['mode'] ) { unset( $this->post_form['role'] ); - unset( $this->post_form['submitted']['role'] ); - } - } - - // Secure sanitize of the submitted data - if ( ! empty( $this->post_form ) ) { - $this->post_form = $this->clean_submitted_data( $this->post_form ); - } - if ( ! empty( $this->post_form['submitted'] ) ) { - $this->post_form['submitted'] = $this->clean_submitted_data( $this->post_form['submitted'] ); - } - - // set default role from settings on registration form - if ( isset( $this->post_form['mode'] ) && 'register' === $this->post_form['mode'] ) { - $role = $this->assigned_role( $this->form_id ); - $this->post_form['role'] = $role; - } - - if ( isset( $this->form_data['custom_fields'] ) && strstr( $this->form_data['custom_fields'], 'role_' ) ) { // Secure selected role - - if ( ! empty( $_POST['role'] ) ) { - $custom_field_roles = $this->custom_field_roles( $this->form_data['custom_fields'] ); - - if ( ! empty( $custom_field_roles ) ) { - if ( is_array( $_POST['role'] ) ) { - $role = current( $_POST['role'] ); - $role = sanitize_key( $role ); - } else { - $role = sanitize_key( $_POST['role'] ); - } - - global $wp_roles; - $exclude_roles = array_diff( array_keys( $wp_roles->roles ), UM()->roles()->get_editable_user_roles() ); - - if ( ! empty( $role ) && - ( ! in_array( $role, $custom_field_roles, true ) || in_array( $role, $exclude_roles, true ) ) ) { - wp_die( esc_html__( 'This is not possible for security reasons.', 'ultimate-member' ) ); - } - - $this->post_form['role'] = $role; - $this->post_form['submitted']['role'] = $role; - } else { + } else { + $form_has_role_field = count( array_intersect( $all_cf_metakeys, array( 'role_select', 'role_radio' ) ) ) > 0; + if ( ! $form_has_role_field ) { unset( $this->post_form['role'] ); - unset( $this->post_form['submitted']['role'] ); + } else { + $custom_field_roles = $this->custom_field_roles( $this->form_data['custom_fields'] ); + if ( ! empty( $custom_field_roles ) ) { + if ( is_array( $this->post_form['role'] ) ) { + $role = current( $this->post_form['role'] ); + $role = sanitize_key( $role ); + } else { + $role = sanitize_key( $this->post_form['role'] ); + } + + global $wp_roles; + $exclude_roles = array_diff( array_keys( $wp_roles->roles ), UM()->roles()->get_editable_user_roles() ); + + if ( ! empty( $role ) && + ( ! in_array( $role, $custom_field_roles, true ) || in_array( $role, $exclude_roles, true ) ) ) { + // High level escape if hacking. + wp_die( esc_html__( 'This is not possible for security reasons.', 'ultimate-member' ) ); + } - // set default role for registration form if custom field hasn't proper value - if ( isset( $this->post_form['mode'] ) && 'register' === $this->post_form['mode'] ) { - $role = $this->assigned_role( $this->form_id ); $this->post_form['role'] = $role; + $maybe_set_default_role = false; } } } } - /** - * UM hook - * - * @type filter - * @title um_submit_form_data - * @description Change submitted data on form submit - * @input_vars - * [{"var":"$data","type":"array","desc":"Submitted data"}, - * {"var":"$mode","type":"string","desc":"Form mode"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * - */ - $this->post_form = apply_filters( 'um_submit_form_data', $this->post_form, $this->post_form['mode'] ); + $this->post_form = $this->sanitize( $this->post_form ); + $this->post_form['submitted'] = $this->post_form; + // Set default role from settings on registration form. It has been made after defined 'submitted' because predefined role isn't a submitted field. + if ( $maybe_set_default_role && 'register' === $this->form_data['mode'] ) { + $role = $this->assigned_role( $this->form_id ); + $this->post_form['role'] = $role; + } + + // @todo REMOVE THAT !!! AND SEPARATE FORM DATA AND SUBMISSION DATA. MAY AFFECT TO EXTENSIONS + $this->post_form = array_merge( $this->form_data, $this->post_form ); + + // Remove role from post_form at first if role ! empty and there aren't custom fields with role name +// if ( ! empty( $this->post_form['role'] ) ) { +// if ( ! strstr( $this->form_data['custom_fields'], 'role_' ) ) { +// unset( $this->post_form['role'] ); +// //unset( $this->post_form['submitted']['role'] ); +// } +// } + + // Secure sanitize of the submitted data +// if ( ! empty( $this->post_form ) ) { +// $this->post_form = $this->clean_submitted_data( $this->post_form ); +// } +// if ( ! empty( $this->post_form['submitted'] ) ) { +// $this->post_form['submitted'] = $this->clean_submitted_data( $this->post_form['submitted'] ); +// } + + + +// if ( isset( $this->form_data['custom_fields'] ) && strstr( $this->form_data['custom_fields'], 'role_' ) ) { // Secure selected role +// if ( ! empty( $_POST['role'] ) ) { +// $custom_field_roles = $this->custom_field_roles( $this->form_data['custom_fields'] ); +// +// if ( ! empty( $custom_field_roles ) ) { +// if ( is_array( $_POST['role'] ) ) { +// $role = current( $_POST['role'] ); +// $role = sanitize_key( $role ); +// } else { +// $role = sanitize_key( $_POST['role'] ); +// } +// +// global $wp_roles; +// $exclude_roles = array_diff( array_keys( $wp_roles->roles ), UM()->roles()->get_editable_user_roles() ); +// +// if ( ! empty( $role ) && +// ( ! in_array( $role, $custom_field_roles, true ) || in_array( $role, $exclude_roles, true ) ) ) { +// wp_die( esc_html__( 'This is not possible for security reasons.', 'ultimate-member' ) ); +// } +// +// $this->post_form['role'] = $role; +// $this->post_form['submitted']['role'] = $role; +// } else { +// unset( $this->post_form['role'] ); +// unset( $this->post_form['submitted']['role'] ); +// +// // set default role for registration form if custom field hasn't proper value +// if ( 'register' === $this->form_data['mode'] ) { +// $role = $this->assigned_role( $this->form_id ); +// $this->post_form['role'] = $role; +// } +// } +// } +// } + + /** + * Filters $_POST submitted data by the UM login, registration or profile form. + * It's un-slashed by `wp_unslash()`, beautified and sanitized. `role` attribute is filtered by possible role. + * `submitted` key is added by code and contains summary of submission. + * + * Internal Ultimate Member callbacks (Priority -> Callback name -> Excerpt): + * 9 - `um_submit_form_data_trim_fields()` maybe over-functionality and can be removed. + * 10 - `um_submit_form_data_role_fields()` important for conditional logic based on role fields in form. + * + * @param {array} $_post Submitted data. + * @param {string} $mode Form mode. login||register||profile + * @param {array} $all_cf_metakeys Form's metakeys. Since 2.6.7. + * + * @return {array} Submitted data. + * + * @since 1.3.x + * @hook um_submit_form_data + * + * @example Extends UM form submitted data. + * function my_submit_form_data( $_post, $mode, $all_cf_metakeys ) { + * $_post['some_key'] = 'some value'; + * return $_post; + * } + * add_filter( 'um_submit_form_data', 'my_submit_form_data', 10, 3 ); + */ + $this->post_form = apply_filters( 'um_submit_form_data', $this->post_form, $this->form_data['mode'], $all_cf_metakeys ); /* Continue based on form mode - pre-validation */ - /** - * UM hook + * Fires for validation UM login, registration or profile form submission. * - * @type action - * @title um_submit_form_errors_hook - * @description Action on submit form - * @input_vars - * [{"var":"$post","type":"int","desc":"Post data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_submit_form_errors_hook()` All form validation handlers. + * 20 - `um_recaptcha_validate()` reCAPTCHA form validation handlers. um-recaptcha extension. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook + * + * @param {array} $post $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any common validation action here. + * function my_custom_before_submit_form_post( $post, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook', 'my_custom_submit_form_errors_hook', 10, 2 ); */ - do_action( 'um_submit_form_errors_hook', $this->post_form ); + do_action( 'um_submit_form_errors_hook', $this->post_form, $this->form_data ); + if ( 'login' !== $this->form_data['mode'] ) { + var_dump( $this->post_form ); + var_dump( $this->form_data ); + var_dump( '------------------------------------------------------------' ); + var_dump( $all_cf_metakeys ); + var_dump( $cf_metakeys ); + exit; + } + /* Continue based on form mode - store data. */ /** - * UM hook + * Fires for make main actions on UM login, registration or profile form submission. * - * @type action - * @title um_submit_form_{$mode} - * @description Action on submit form - * @input_vars - * [{"var":"$post","type":"int","desc":"Post data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_{$mode}', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * ### um_submit_form_login: + * * 1 - `UM()->login()->verify_nonce()` Verify nonce. + * * 10 - `um_submit_form_login()` Login form main handler. + * ### um_submit_form_register: + * ### um_submit_form_profile: + * + * @since 1.3.x + * @hook um_submit_form_errors_hook + * + * @param {array} $post $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any custom action. + * function my_custom_before_submit_form_post( $post, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook', 'my_custom_submit_form_errors_hook', 10, 2 ); */ - do_action( "um_submit_form_{$this->post_form['mode']}", $this->post_form ); + do_action( "um_submit_form_{$this->post_form['mode']}", $this->post_form, $this->form_data ); } } @@ -716,7 +808,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { ) ), ' /' - ); + ); } } } diff --git a/includes/core/class-login.php b/includes/core/class-login.php index b825c759..115afbee 100644 --- a/includes/core/class-login.php +++ b/includes/core/class-login.php @@ -1,13 +1,12 @@ - * @example - * + * @param {bool} $allow_nonce Is allowed verify nonce on login. By default, allowed = `true`. + * @param {array} $form_data Form's metakeys. Since 2.6.7. + * + * @return {bool} Is allowed verify. + * + * @since 2.0 + * @hook um_login_allow_nonce_verification + * + * @example Disable verifying nonce on the login page. + * add_filter( 'um_login_allow_nonce_verification', '__return_false' ); */ - $allow_nonce_verification = apply_filters( 'um_login_allow_nonce_verification', true ); - - if ( ! $allow_nonce_verification ) { - return $args; + $allow_nonce_verification = apply_filters( 'um_login_allow_nonce_verification', true, $form_data ); + if ( ! $allow_nonce_verification ) { + return; } - if ( ! wp_verify_nonce( $args['_wpnonce'], 'um_login_form' ) || empty( $args['_wpnonce'] ) || ! isset( $args['_wpnonce'] ) ) { - $url = apply_filters( 'um_login_invalid_nonce_redirect_url', add_query_arg( [ 'err' => 'invalid_nonce' ] ) ); - exit( wp_redirect( $url ) ); + if ( empty( $args['_wpnonce'] ) || ! wp_verify_nonce( $args['_wpnonce'], 'um_login_form' ) ) { + $url = apply_filters( 'um_login_invalid_nonce_redirect_url', add_query_arg( array( 'err' => 'invalid_nonce' ) ) ); + wp_safe_redirect( $url ); + exit; } - - return $args; } - } - -} \ No newline at end of file +} diff --git a/includes/core/um-actions-form.php b/includes/core/um-actions-form.php index 25c2a3e2..54e180ba 100644 --- a/includes/core/um-actions-form.php +++ b/includes/core/um-actions-form.php @@ -1,12 +1,14 @@ -options()->get( 'blocked_emails' ); if ( ! $emails ) { return; @@ -15,41 +17,39 @@ function um_submit_form_errors_hook__blockedemails( $args ) { $emails = strtolower( $emails ); $emails = array_map( 'rtrim', explode( "\n", $emails ) ); - if ( isset( $args['user_email'] ) && is_email( $args['user_email'] ) ) { - if ( in_array( strtolower( $args['user_email'] ), $emails ) ) { + if ( isset( $submitted_data['user_email'] ) && is_email( $submitted_data['user_email'] ) ) { + if ( in_array( strtolower( $submitted_data['user_email'] ), $emails ) ) { exit( wp_redirect( esc_url( add_query_arg( 'err', 'blocked_email' ) ) ) ); } - $domain = explode( '@', $args['user_email'] ); - $check_domain = str_replace( $domain[0], '*', $args['user_email'] ); + $domain = explode( '@', $submitted_data['user_email'] ); + $check_domain = str_replace( $domain[0], '*', $submitted_data['user_email'] ); if ( in_array( strtolower( $check_domain ), $emails ) ) { exit( wp_redirect( esc_url( add_query_arg( 'err', 'blocked_domain' ) ) ) ); } } - if ( isset( $args['username'] ) && is_email( $args['username'] ) ) { - if ( in_array( strtolower( $args['username'] ), $emails ) ) { + if ( isset( $submitted_data['username'] ) && is_email( $submitted_data['username'] ) ) { + if ( in_array( strtolower( $submitted_data['username'] ), $emails ) ) { exit( wp_redirect( esc_url( add_query_arg( 'err', 'blocked_email' ) ) ) ); } - $domain = explode( '@', $args['username'] ); - $check_domain = str_replace( $domain[0], '*', $args['username'] ); + $domain = explode( '@', $submitted_data['username'] ); + $check_domain = str_replace( $domain[0], '*', $submitted_data['username'] ); if ( in_array( strtolower( $check_domain ), $emails ) ) { exit( wp_redirect( esc_url( add_query_arg( 'err', 'blocked_domain' ) ) ) ); } } } -add_action( 'um_submit_form_errors_hook__blockedemails', 'um_submit_form_errors_hook__blockedemails', 10 ); +add_action( 'um_submit_form_errors_hook__blockedemails', 'um_submit_form_errors_hook__blockedemails' ); /** - * Error handling: blocked IPs - * - * @param $args + * Error handling: blocked IPs. */ -function um_submit_form_errors_hook__blockedips( $args ) { +function um_submit_form_errors_hook__blockedips() { $ips = UM()->options()->get( 'blocked_ips' ); if ( ! $ips ) { return; @@ -65,7 +65,7 @@ function um_submit_form_errors_hook__blockedips( $args ) { } } } -add_action( 'um_submit_form_errors_hook__blockedips', 'um_submit_form_errors_hook__blockedips', 10 ); +add_action( 'um_submit_form_errors_hook__blockedips', 'um_submit_form_errors_hook__blockedips' ); /** @@ -79,8 +79,6 @@ function um_submit_form_errors_hook__blockedwords( $args ) { return; } - $form_id = $args['form_id']; - $mode = $args['mode']; $fields = unserialize( $args['custom_fields'] ); $words = strtolower( $words ); @@ -99,155 +97,137 @@ add_action( 'um_submit_form_errors_hook__blockedwords', 'um_submit_form_errors_h /** - * Error handling + * UM login|register|profile form error handling. * - * @param $args + * @param array $submitted_data + * @param array $form_data */ -function um_submit_form_errors_hook( $args ) { - $mode = $args['mode']; +function um_submit_form_errors_hook( $submitted_data, $form_data ) { + $mode = $form_data['mode']; /** - * UM hook + * Fires for validation blocked IPs when UM login, registration or profile form has been submitted. * - * @type action - * @title um_submit_form_errors_hook__blockedips - * @description Submit form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook__blockedips', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_submit_form_errors_hook__blockedips()` Native validation handlers. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook__blockedips + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any common validation action here. + * function my_submit_form_errors_hook__blockedips( $post, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook__blockedips', 'my_submit_form_errors_hook__blockedips', 10, 2 ); */ - do_action( 'um_submit_form_errors_hook__blockedips', $args ); - - + do_action( 'um_submit_form_errors_hook__blockedips', $submitted_data, $form_data ); /** - * UM hook + * Fires for validation blocked email addresses when UM login, registration or profile form has been submitted. * - * @type action - * @title um_submit_form_errors_hook__blockedemails - * @description Submit form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook__blockedemails', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_submit_form_errors_hook__blockedemails()` Native validation handlers. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook__blockedemails + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any common validation action here. + * function my_submit_form_errors_hook__blockedemails( $post, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook__blockedemails', 'my_submit_form_errors_hook__blockedemails', 10, 2 ); */ - do_action( 'um_submit_form_errors_hook__blockedemails', $args ); - - if ( $mode == 'register' ) { - + do_action( 'um_submit_form_errors_hook__blockedemails', $submitted_data, $form_data ); + if ( 'login' === $mode ) { /** - * UM hook + * Fires for login form validation when it has been submitted. * - * @type action - * @title um_submit_form_errors_hook__registration - * @description Submit registration form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook__registration', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_submit_form_errors_hook_login()` Native login validation handlers. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook_login + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any common validation action here. + * function my_submit_form_errors_hook_login( $post, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook_login', 'my_submit_form_errors_hook_login', 10, 2 ); */ - do_action( 'um_submit_form_errors_hook__registration', $args ); - - } elseif ( $mode == 'profile' ) { - - + do_action( 'um_submit_form_errors_hook_login', $submitted_data, $form_data ); /** - * UM hook + * Fires for login form validation when it has been submitted. * - * @type action - * @title um_submit_form_errors_hook__registration - * @description Submit registration form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook__registration', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 9999 - `um_submit_form_errors_hook_logincheck()` Native login validation handlers. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook_logincheck + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any common validation action here. + * function my_submit_form_errors_hook_logincheck( $post, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook_logincheck', 'my_submit_form_errors_hook_logincheck', 10, 2 ); */ - do_action( 'um_submit_form_errors_hook__profile', $args ); - - } elseif ( $mode == 'login' ) { - - - /** - * UM hook - * - * @type action - * @title um_submit_form_errors_hook_login - * @description Submit login form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook_login', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_submit_form_errors_hook_login', $args ); - - - /** - * UM hook - * - * @type action - * @title um_submit_form_errors_hook_logincheck - * @description Submit login form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook_logincheck', 'function_name', 10, 1 ); - * @example - * - */ - do_action( 'um_submit_form_errors_hook_logincheck', $args ); - - } - - - if ( $mode != 'login' ) { - + do_action( 'um_submit_form_errors_hook_logincheck', $submitted_data, $form_data ); + // ------ Reviewed. --------- // + } else { + if ( 'register' === $mode ) { + /** + * UM hook + * + * @type action + * @title um_submit_form_errors_hook__registration + * @description Submit registration form validation + * @input_vars + * [{"var":"$args","type":"array","desc":"Form Arguments"}] + * @change_log + * ["Since: 2.0"] + * @usage add_action( 'um_submit_form_errors_hook__registration', 'function_name', 10, 1 ); + * @example + * + */ + do_action( 'um_submit_form_errors_hook__registration', $submitted_data, $form_data ); + } elseif ( 'profile' === $mode ) { + /** + * UM hook + * + * @type action + * @title um_submit_form_errors_hook__registration + * @description Submit registration form validation + * @input_vars + * [{"var":"$args","type":"array","desc":"Form Arguments"}] + * @change_log + * ["Since: 2.0"] + * @usage add_action( 'um_submit_form_errors_hook__registration', 'function_name', 10, 1 ); + * @example + * + */ + do_action( 'um_submit_form_errors_hook__profile', $submitted_data, $form_data ); + } /** * UM hook @@ -268,9 +248,7 @@ function um_submit_form_errors_hook( $args ) { * } * ?> */ - do_action( 'um_submit_form_errors_hook__blockedwords', $args ); - - + do_action( 'um_submit_form_errors_hook__blockedwords', $submitted_data, $form_data ); /** * UM hook * @@ -290,12 +268,10 @@ function um_submit_form_errors_hook( $args ) { * } * ?> */ - do_action( 'um_submit_form_errors_hook_', $args ); - + do_action( 'um_submit_form_errors_hook_', $submitted_data, $form_data ); } - } -add_action( 'um_submit_form_errors_hook', 'um_submit_form_errors_hook', 10 ); +add_action( 'um_submit_form_errors_hook', 'um_submit_form_errors_hook', 10, 2 ); /** diff --git a/includes/core/um-actions-login.php b/includes/core/um-actions-login.php index dbf019ea..de777c93 100644 --- a/includes/core/um-actions-login.php +++ b/includes/core/um-actions-login.php @@ -4,57 +4,51 @@ if ( ! defined( 'ABSPATH' ) ) { } /** - * Error procesing hook for login + * Error processing hook for login. * - * @param $args + * @param $submitted_data */ -function um_submit_form_errors_hook_login( $args ) { - $is_email = false; +function um_submit_form_errors_hook_login( $submitted_data ) { + $user_password = $submitted_data['user_password']; - $form_id = $args['form_id']; - $mode = $args['mode']; - $user_password = $args['user_password']; - - if ( isset( $args['username'] ) && $args['username'] == '' ) { + if ( isset( $submitted_data['username'] ) && $submitted_data['username'] == '' ) { UM()->form()->add_error( 'username', __( 'Please enter your username or email', 'ultimate-member' ) ); } - if ( isset( $args['user_login'] ) && $args['user_login'] == '' ) { + if ( isset( $submitted_data['user_login'] ) && $submitted_data['user_login'] == '' ) { UM()->form()->add_error( 'user_login', __( 'Please enter your username', 'ultimate-member' ) ); } - if ( isset( $args['user_email'] ) && $args['user_email'] == '' ) { + if ( isset( $submitted_data['user_email'] ) && $submitted_data['user_email'] == '' ) { UM()->form()->add_error( 'user_email', __( 'Please enter your email', 'ultimate-member' ) ); } - if ( isset( $args['username'] ) ) { - $authenticate = $args['username']; + if ( isset( $submitted_data['username'] ) ) { + $authenticate = $submitted_data['username']; $field = 'username'; - if ( is_email( $args['username'] ) ) { - $is_email = true; - $data = get_user_by('email', $args['username'] ); + if ( is_email( $submitted_data['username'] ) ) { + $data = get_user_by('email', $submitted_data['username'] ); $user_name = isset( $data->user_login ) ? $data->user_login : null; } else { - $user_name = $args['username']; + $user_name = $submitted_data['username']; } - } elseif ( isset( $args['user_email'] ) ) { - $authenticate = $args['user_email']; + } elseif ( isset( $submitted_data['user_email'] ) ) { + $authenticate = $submitted_data['user_email']; $field = 'user_email'; - $is_email = true; - $data = get_user_by('email', $args['user_email'] ); + $data = get_user_by('email', $submitted_data['user_email'] ); $user_name = isset( $data->user_login ) ? $data->user_login : null; } else { $field = 'user_login'; - $user_name = $args['user_login']; - $authenticate = $args['user_login']; + $user_name = $submitted_data['user_login']; + $authenticate = $submitted_data['user_login']; } - if ( $args['user_password'] == '' ) { + if ( $submitted_data['user_password'] == '' ) { UM()->form()->add_error( 'user_password', __( 'Please enter your password', 'ultimate-member' ) ); } $user = get_user_by( 'login', $user_name ); - if ( $user && wp_check_password( $args['user_password'], $user->data->user_pass, $user->ID ) ) { + if ( $user && wp_check_password( $submitted_data['user_password'], $user->data->user_pass, $user->ID ) ) { UM()->login()->auth_id = username_exists( $user_name ); } else { UM()->form()->add_error( 'user_password', __( 'Password is incorrect. Please try again.', 'ultimate-member' ) ); @@ -67,7 +61,7 @@ function um_submit_form_errors_hook_login( $args ) { // see WP function wp_authenticate() $ignore_codes = array( 'empty_username', 'empty_password' ); - $user = apply_filters( 'authenticate', null, $authenticate, $args['user_password'] ); + $user = apply_filters( 'authenticate', null, $authenticate, $submitted_data['user_password'] ); if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) { if ( ! empty( $third_party_codes ) && in_array( $user->get_error_code(), $third_party_codes ) ) { UM()->form()->add_error( $user->get_error_code(), $user->get_error_message() ); @@ -76,7 +70,7 @@ function um_submit_form_errors_hook_login( $args ) { } } - $user = apply_filters( 'wp_authenticate_user', $user, $args['user_password'] ); + $user = apply_filters( 'wp_authenticate_user', $user, $submitted_data['user_password'] ); if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) { if ( ! empty( $third_party_codes ) && in_array( $user->get_error_code(), $third_party_codes ) ) { UM()->form()->add_error( $user->get_error_code(), $user->get_error_message() ); @@ -90,7 +84,7 @@ function um_submit_form_errors_hook_login( $args ) { do_action( 'wp_login_failed', $user_name, UM()->form()->get_wp_error() ); } } -add_action( 'um_submit_form_errors_hook_login', 'um_submit_form_errors_hook_login', 10 ); +add_action( 'um_submit_form_errors_hook_login', 'um_submit_form_errors_hook_login' ); /** @@ -123,13 +117,13 @@ function um_display_login_errors( $args ) { } add_action( 'um_before_login_fields', 'um_display_login_errors' ); - /** - * Login checks thru the frontend login + * Login checks through the frontend login * - * @param $args + * @param array $submitted_data + * @param array $form_data */ -function um_submit_form_errors_hook_logincheck( $args ) { +function um_submit_form_errors_hook_logincheck( $submitted_data, $form_data ) { // Logout if logged in if ( is_user_logged_in() ) { wp_logout(); @@ -140,25 +134,23 @@ function um_submit_form_errors_hook_logincheck( $args ) { $status = um_user( 'account_status' ); // account status switch ( $status ) { - - // If user can't login to site... + // If user can't log in to site... case 'inactive': case 'awaiting_admin_review': case 'awaiting_email_confirmation': case 'rejected': - um_reset_user(); - exit( wp_redirect( add_query_arg( 'err', esc_attr( $status ), UM()->permalinks()->get_current_url() ) ) ); - break; - + um_reset_user(); + wp_safe_redirect( add_query_arg( 'err', esc_attr( $status ), UM()->permalinks()->get_current_url() ) ); + exit; } - if ( isset( $args['form_id'] ) && $args['form_id'] == UM()->shortcodes()->core_login_form() && UM()->form()->errors && ! isset( $_POST[ UM()->honeypot ] ) ) { - exit( wp_redirect( um_get_core_page( 'login' ) ) ); + if ( isset( $form_data['form_id'] ) && absint( $form_data['form_id'] ) === absint( UM()->shortcodes()->core_login_form() ) && UM()->form()->errors && ! isset( $_POST[ UM()->honeypot ] ) ) { + wp_safe_redirect( um_get_core_page( 'login' ) ); + exit; } } -add_action( 'um_submit_form_errors_hook_logincheck', 'um_submit_form_errors_hook_logincheck', 9999 ); - +add_action( 'um_submit_form_errors_hook_logincheck', 'um_submit_form_errors_hook_logincheck', 9999, 2 ); /** * Store last login timestamp @@ -192,13 +184,13 @@ function um_store_lastlogin_timestamp_( $login ) { add_action( 'wp_login', 'um_store_lastlogin_timestamp_' ); /** - * Login user process + * Login user process. * - * @param array $args + * @param array $submitted_data */ -function um_user_login( $args ) { +function um_user_login( $submitted_data ) { // phpcs:disable WordPress.Security.NonceVerification -- already verified here - $rememberme = ( isset( $_REQUEST['rememberme'], $args['rememberme'] ) && 1 === (int) $args['rememberme'] ) ? 1 : 0; + $rememberme = ( isset( $_REQUEST['rememberme'], $submitted_data['rememberme'] ) && 1 === (int) $submitted_data['rememberme'] ) ? 1 : 0; // @todo check using the 'deny_admin_frontend_login' option if ( false !== strrpos( um_user( 'wp_roles' ), 'administrator' ) && ( ! isset( $_GET['provider'] ) && UM()->options()->get( 'deny_admin_frontend_login' ) ) ) { @@ -224,8 +216,8 @@ function um_user_login( $args ) { do_action( 'um_on_login_before_redirect', um_user( 'ID' ) ); // Priority redirect from $_GET attribute. - if ( ! empty( $args['redirect_to'] ) ) { - wp_safe_redirect( $args['redirect_to'] ); + if ( ! empty( $submitted_data['redirect_to'] ) ) { + wp_safe_redirect( $submitted_data['redirect_to'] ); exit; } @@ -277,56 +269,52 @@ add_action( 'um_user_login', 'um_user_login' ); /** * Form processing * - * @param $args + * @param array $submitted_data + * @param array $form_data */ -function um_submit_form_login( $args ) { - +function um_submit_form_login( $submitted_data, $form_data ) { if ( ! isset( UM()->form()->errors ) ) { /** - * UM hook + * Fires after successful submit login form. * - * @type action - * @title um_user_login - * @description Hook that runs after successful submit login form - * @input_vars - * [{"var":"$args","type":"array","desc":"Form data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_user_login', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * * 10 - `um_user_login()` Login form main handler. + * + * @since 1.3.x + * @hook um_user_login + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any custom login action if submission is valid. + * function my_user_login( $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_user_login', 'my_user_login', 10, 2 ); */ - do_action( 'um_user_login', $args ); + do_action( 'um_user_login', $submitted_data, $form_data ); } - /** - * UM hook + * Fires after submit login form. * - * @type action - * @title um_user_login_extra_hook - * @description Hook that runs after successful submit login form - * @input_vars - * [{"var":"$args","type":"array","desc":"Form data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_user_login_extra_hook', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * * 10 - um-messaging. + * + * @since 1.3.x + * @hook um_user_login_extra_hook + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any custom login action. + * function my_user_login_extra( $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_user_login_extra_hook', 'my_user_login_extra', 10, 2 ); */ - do_action( 'um_user_login_extra_hook', $args ); + do_action( 'um_user_login_extra_hook', $submitted_data, $form_data ); } -add_action( 'um_submit_form_login', 'um_submit_form_login', 10 ); - +add_action( 'um_submit_form_login', 'um_submit_form_login', 10, 2 ); /** * Show the submit button diff --git a/includes/core/um-filters-fields.php b/includes/core/um-filters-fields.php index 2bf8bb6d..12101d31 100644 --- a/includes/core/um-filters-fields.php +++ b/includes/core/um-filters-fields.php @@ -898,12 +898,13 @@ add_filter( 'um_profile_field_filter_hook__', 'um_profile_field_filter_xss_valid /** * Trim All form POST submitted data * + * @todo Maybe deprecate because data is sanitized in earlier code and trim included to `sanitize_text_field()`. Need testing and confirmation. + * * @param $post_form - * @param $mode * * @return mixed */ -function um_submit_form_data_trim_fields( $post_form, $mode ) { +function um_submit_form_data_trim_fields( $post_form ) { foreach ( $post_form as $key => $field ) { if ( is_string( $field ) ) { $post_form[ $key ] = trim( $field ); @@ -912,30 +913,44 @@ function um_submit_form_data_trim_fields( $post_form, $mode ) { return $post_form; } -add_filter( 'um_submit_form_data', 'um_submit_form_data_trim_fields', 9, 2 ); +add_filter( 'um_submit_form_data', 'um_submit_form_data_trim_fields', 9, 1 ); /** - * add role_select and role_radio to the $post_form - * It is necessary for that if on these fields the conditional logic - * @param $post_form array - * @param $mode + * Add `role_select` and `role_radio` to the $post_form + * It is necessary for that if on these fields the conditional logic. * - * @return $post_form - * @uses hook filters: um_submit_form_data + * @param array $post_form + * @param string $mode + * @param array $all_cf_metakeys + * + * @return array */ -function um_submit_form_data_role_fields( $post_form, $mode ) { - $custom_fields = unserialize( $post_form['custom_fields'] ); - if ( ! empty( $post_form['role'] ) && array_key_exists( 'role_select', $custom_fields ) ) { - $post_form['role_select'] = $post_form['role']; +function um_submit_form_data_role_fields( $post_form, $mode, $all_cf_metakeys ) { + if ( 'login' === $mode ) { + return $post_form; } - if (! empty( $post_form['role'] ) && array_key_exists( 'role_radio', $custom_fields ) ) { - $post_form['role_radio'] = $post_form['role']; + + if ( ! array_key_exists( 'role', $post_form ) ) { + return $post_form; + } + + $role_fields = array( 'role_select', 'role_radio' ); + + $form_has_role_field = count( array_intersect( $all_cf_metakeys, $role_fields ) ) > 0; + if ( ! $form_has_role_field ) { + return $post_form; + } + + foreach ( $role_fields as $role_field ) { + if ( in_array( $role_field, $all_cf_metakeys, true ) ) { + $post_form[ $role_field ] = $post_form['role']; + } } return $post_form; } -add_filter( 'um_submit_form_data', 'um_submit_form_data_role_fields', 10, 2 ); +add_filter( 'um_submit_form_data', 'um_submit_form_data_role_fields', 10, 3 ); /** diff --git a/includes/core/um-filters-login.php b/includes/core/um-filters-login.php index 185ad9b8..18af141c 100644 --- a/includes/core/um-filters-login.php +++ b/includes/core/um-filters-login.php @@ -43,8 +43,10 @@ add_filter( 'login_message', 'um_custom_wp_err_messages' ); */ function um_wp_form_errors_hook_ip_test( $user, $username, $password ) { if ( ! empty( $username ) ) { - do_action( 'um_submit_form_errors_hook__blockedips', array() ); - do_action( 'um_submit_form_errors_hook__blockedemails', array( 'username' => $username ) ); + /** This action is documented in includes/core/um-actions-form.php */ + do_action( 'um_submit_form_errors_hook__blockedips', array(), null ); + /** This action is documented in includes/core/um-actions-form.php */ + do_action( 'um_submit_form_errors_hook__blockedemails', array( 'username' => $username ), null ); } return $user; @@ -53,7 +55,7 @@ add_filter( 'authenticate', 'um_wp_form_errors_hook_ip_test', 10, 3 ); /** - * Login checks thru the wordpress admin login + * Login checks through the WordPress admin login. * * @param $user * @param $username @@ -93,8 +95,8 @@ add_filter( 'authenticate', 'um_wp_form_errors_hook_logincheck', 50, 3 ); /** * Change lost password url in UM Login form - * @param string $lostpassword_url - * @return string + * @param string $lostpassword_url + * @return string */ function um_lostpassword_url( $lostpassword_url ) { From 246de13726647d1241336096ee79ae55c186927d Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 30 Jun 2023 16:58:12 +0300 Subject: [PATCH 03/11] - finished with UM Forms validations; --- includes/core/class-form.php | 8 + includes/core/um-actions-form.php | 1118 ++++++++++++------------- includes/core/um-actions-profile.php | 14 +- includes/core/um-actions-register.php | 11 +- 4 files changed, 583 insertions(+), 568 deletions(-) diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 5ae5f373..7a55db89 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -456,6 +456,13 @@ if ( ! class_exists( 'um\core\Form' ) ) { // The '_um_last_login' cannot be updated through UM form. $cf_metakeys = array_values( array_diff( $cf_metakeys, array( 'role_select', 'role_radio', 'role', '_um_last_login' ) ) ); + // Column names from wp_users table. + $cf_metakeys = array_values( array_diff( $cf_metakeys, UM()->user()->update_user_keys ) ); + // Remove restricted fields when edit profile. + if ( 'profile' === $this->form_data['mode'] ) { + $cf_metakeys = array_values( array_diff( $cf_metakeys, UM()->fields()->get_restricted_fields_for_edit() ) ); + } + // Add required usermeta for register. if ( 'register' === $this->form_data['mode'] ) { $cf_metakeys[] = 'submitted'; } @@ -659,6 +666,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { var_dump( '------------------------------------------------------------' ); var_dump( $all_cf_metakeys ); var_dump( $cf_metakeys ); + var_dump( UM()->form()->errors ); exit; } /* Continue based on form mode - store data. */ diff --git a/includes/core/um-actions-form.php b/includes/core/um-actions-form.php index 54e180ba..ab08f406 100644 --- a/includes/core/um-actions-form.php +++ b/includes/core/um-actions-form.php @@ -67,34 +67,40 @@ function um_submit_form_errors_hook__blockedips() { } add_action( 'um_submit_form_errors_hook__blockedips', 'um_submit_form_errors_hook__blockedips' ); - /** * Error handling: blocked words during sign up * - * @param $args + * @todo change the hook after checking that conditions inside this callback can be run only while registration. + * + * @param array $submitted_data + * @param array $form_data */ -function um_submit_form_errors_hook__blockedwords( $args ) { +function um_submit_form_errors_hook__blockedwords( $submitted_data, $form_data ) { $words = UM()->options()->get( 'blocked_words' ); if ( empty( $words ) ) { return; } - $fields = unserialize( $args['custom_fields'] ); + $fields = maybe_unserialize( $form_data['custom_fields'] ); + if ( empty( $fields ) || ! is_array( $fields ) ) { + return; + } $words = strtolower( $words ); $words = array_map( 'rtrim', explode( "\n", $words ) ); - if ( ! empty( $fields ) && is_array( $fields ) ) { - foreach ( $fields as $key => $array ) { - if ( isset( $array['validate'] ) && in_array( $array['validate'], array( 'unique_username', 'unique_email', 'unique_username_or_email' ) ) ) { - if ( ! UM()->form()->has_error( $key ) && isset( $args[ $key ] ) && in_array( strtolower( $args[ $key ] ), $words ) ) { - UM()->form()->add_error( $key, __( 'You are not allowed to use this word as your username.', 'ultimate-member' ) ); - } + foreach ( $fields as $key => $array ) { + if ( isset( $array['validate'] ) && in_array( $array['validate'], array( 'unique_username', 'unique_email', 'unique_username_or_email' ), true ) ) { + if ( UM()->form()->has_error( $key ) ) { + continue; + } + + if ( array_key_exists( $key, $submitted_data ) && in_array( strtolower( $submitted_data[ $key ] ), $words, true ) ) { + UM()->form()->add_error( $key, __( 'You are not allowed to use this word as your username.', 'ultimate-member' ) ); } } } } -add_action( 'um_submit_form_errors_hook__blockedwords', 'um_submit_form_errors_hook__blockedwords', 10 ); - +add_action( 'um_submit_form_errors_hook__blockedwords', 'um_submit_form_errors_hook__blockedwords', 10, 2 ); /** * UM login|register|profile form error handling. @@ -117,7 +123,7 @@ function um_submit_form_errors_hook( $submitted_data, $form_data ) { * @param {array} $submitted_data $_POST Submission array. * @param {array} $form_data UM form data. Since 2.6.7 * - * @example Make any common validation action here. + * @example Make any common validation action when login, registation or profile form is submitted. * function my_submit_form_errors_hook__blockedips( $post, $form_data ) { * // your code here * } @@ -136,7 +142,7 @@ function um_submit_form_errors_hook( $submitted_data, $form_data ) { * @param {array} $submitted_data $_POST Submission array. * @param {array} $form_data UM form data. Since 2.6.7 * - * @example Make any common validation action here. + * @example Make any common validation action when login, registation or profile form is submitted. * function my_submit_form_errors_hook__blockedemails( $post, $form_data ) { * // your code here * } @@ -157,7 +163,7 @@ function um_submit_form_errors_hook( $submitted_data, $form_data ) { * @param {array} $submitted_data $_POST Submission array. * @param {array} $form_data UM form data. Since 2.6.7 * - * @example Make any common validation action here. + * @example Make any validation action when login form is submitted. * function my_submit_form_errors_hook_login( $post, $form_data ) { * // your code here * } @@ -176,97 +182,92 @@ function um_submit_form_errors_hook( $submitted_data, $form_data ) { * @param {array} $submitted_data $_POST Submission array. * @param {array} $form_data UM form data. Since 2.6.7 * - * @example Make any common validation action here. + * @example Make any validation action when login form is submitted. * function my_submit_form_errors_hook_logincheck( $post, $form_data ) { * // your code here * } * add_action( 'um_submit_form_errors_hook_logincheck', 'my_submit_form_errors_hook_logincheck', 10, 2 ); */ do_action( 'um_submit_form_errors_hook_logincheck', $submitted_data, $form_data ); - // ------ Reviewed. --------- // } else { if ( 'register' === $mode ) { /** - * UM hook + * Fires for registration form validation when it has been submitted. * - * @type action - * @title um_submit_form_errors_hook__registration - * @description Submit registration form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook__registration', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_submit_form_errors_hook__registration()` Native registration validation handlers. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook__registration + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any validation action when registration form submitted. + * function my_submit_form_errors_hook__registration( $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook__registration', 'my_submit_form_errors_hook__registration', 10, 2 ); */ do_action( 'um_submit_form_errors_hook__registration', $submitted_data, $form_data ); } elseif ( 'profile' === $mode ) { /** - * UM hook + * Fires for profile form validation when it has been submitted. * - * @type action - * @title um_submit_form_errors_hook__registration - * @description Submit registration form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook__registration', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 1 - `um_profile_validate_nonce()` Validate nonce. + * + * @since 2.0 + * @hook um_submit_form_errors_hook__profile + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any validation action when profile form submitted. + * function my_submit_form_errors_hook__profile( $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook__profile', 'my_submit_form_errors_hook__profile', 10, 2 ); */ do_action( 'um_submit_form_errors_hook__profile', $submitted_data, $form_data ); } /** - * UM hook + * Fires for registration and profile forms validation when it has been submitted. * - * @type action - * @title um_submit_form_errors_hook__blockedwords - * @description Submit form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook__blockedwords', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_submit_form_errors_hook__blockedwords()` Validate username and email from blocked words. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook__blockedwords + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any validation action when registration or profile form submitted. + * function my_submit_form_errors_hook__blockedwords( $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook__blockedwords', 'my_submit_form_errors_hook__blockedwords', 10, 2 ); */ do_action( 'um_submit_form_errors_hook__blockedwords', $submitted_data, $form_data ); /** - * UM hook + * Fires for registration and profile forms validation when it has been submitted. * - * @type action - * @title um_submit_form_errors_hook_ - * @description Submit form validation - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_submit_form_errors_hook_', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_submit_form_errors_hook_()` Run field validations. + * + * @since 1.3.x + * @hook um_submit_form_errors_hook_ + * + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any validation action when registration or profile form submitted. + * function my_submit_form_errors_hook( $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_submit_form_errors_hook_', 'my_submit_form_errors_hook', 10, 2 ); */ do_action( 'um_submit_form_errors_hook_', $submitted_data, $form_data ); } @@ -279,12 +280,12 @@ add_action( 'um_submit_form_errors_hook', 'um_submit_form_errors_hook', 10, 2 ); * @staticvar int $counter * @param array $condition * @param array $fields - * @param array $args + * @param array $submitted_data * @param boolean $reset * @return boolean * @throws Exception */ -function um_check_conditions_on_submit( $condition, $fields, $args, $reset = false ) { +function um_check_conditions_on_submit( $condition, $fields, $submitted_data, $reset = false ) { static $counter = 0; if ( $reset ) { $counter = 0; @@ -293,7 +294,7 @@ function um_check_conditions_on_submit( $condition, $fields, $args, $reset = fal list( $visibility, $parent_key, $op, $parent_value ) = $condition; - if ( ! isset( $args[ $parent_key ] ) ) { + if ( ! isset( $submitted_data[ $parent_key ] ) ) { $continue = true; return $continue; } @@ -301,7 +302,7 @@ function um_check_conditions_on_submit( $condition, $fields, $args, $reset = fal if ( ! empty( $fields[ $parent_key ]['conditions'] ) ) { foreach ( $fields[ $parent_key ]['conditions'] as $parent_condition ) { if ( 64 > $counter++ ) { - $continue = um_check_conditions_on_submit( $parent_condition, $fields, $args ); + $continue = um_check_conditions_on_submit( $parent_condition, $fields, $submitted_data ); } else { throw new Exception( 'Endless recursion in the function ' . __FUNCTION__, 512 ); } @@ -311,7 +312,7 @@ function um_check_conditions_on_submit( $condition, $fields, $args, $reset = fal } } - $cond_value = ( $fields[ $parent_key ]['type'] == 'radio' ) ? $args[ $parent_key ][0] : $args[ $parent_key ]; + $cond_value = ( $fields[ $parent_key ]['type'] == 'radio' ) ? $submitted_data[ $parent_key ][0] : $submitted_data[ $parent_key ]; if ( $visibility == 'hide' ) { if ( $op == 'empty' ) { @@ -384,540 +385,539 @@ function um_check_conditions_on_submit( $condition, $fields, $args, $reset = fal return $continue; } - /** * Error processing hook : standard * - * @param $args + * @param array $submitted_data + * @param array $form_data */ -function um_submit_form_errors_hook_( $args ) { - $form_id = $args['form_id']; - $mode = $args['mode']; - $fields = unserialize( $args['custom_fields'] ); +function um_submit_form_errors_hook_( $submitted_data, $form_data ) { + $form_id = $form_data['form_id']; + $mode = $form_data['mode']; - $um_profile_photo = um_profile('profile_photo'); - if ( get_post_meta( $form_id, '_um_profile_photo_required', true ) && ( empty( $args['profile_photo'] ) && empty( $um_profile_photo ) ) ) { - UM()->form()->add_error('profile_photo', __( 'Profile Photo is required.', 'ultimate-member' ) ); + $fields = maybe_unserialize( $form_data['custom_fields'] ); + if ( empty( $fields ) || ! is_array( $fields ) ) { + return; } - if ( ! empty( $fields ) ) { - $can_edit = false; - $current_user_roles = array(); - if ( is_user_logged_in() ) { - if ( array_key_exists( 'user_id', $args ) ) { - $can_edit = UM()->roles()->um_current_user_can( 'edit', $args['user_id'] ); - } + $um_profile_photo = um_profile( 'profile_photo' ); + if ( empty( $submitted_data['profile_photo'] ) && empty( $um_profile_photo ) && get_post_meta( $form_id, '_um_profile_photo_required', true ) ) { + UM()->form()->add_error( 'profile_photo', __( 'Profile Photo is required.', 'ultimate-member' ) ); + } - um_fetch_user( get_current_user_id() ); - $current_user_roles = um_user( 'roles' ); - um_reset_user(); + $can_edit = false; + $current_user_roles = array(); + if ( is_user_logged_in() ) { + if ( array_key_exists( 'user_id', $submitted_data ) ) { + $can_edit = UM()->roles()->um_current_user_can( 'edit', $submitted_data['user_id'] ); } - foreach ( $fields as $key => $array ) { + um_fetch_user( get_current_user_id() ); + $current_user_roles = um_user( 'roles' ); + um_reset_user(); + } - if ( 'profile' === $mode ) { - $restricted_fields = UM()->fields()->get_restricted_fields_for_edit(); - if ( is_array( $restricted_fields ) && in_array( $key, $restricted_fields ) ) { - continue; - } - } + foreach ( $fields as $key => $array ) { - $can_view = true; - if ( isset( $array['public'] ) && 'register' !== $mode ) { - - switch ( $array['public'] ) { - case '1': // Everyone - break; - case '2': // Members - if ( ! is_user_logged_in() ) { - $can_view = false; - } - break; - case '-1': // Only visible to profile owner and admins - if ( ! is_user_logged_in() ) { - $can_view = false; - } elseif ( $args['user_id'] != get_current_user_id() && ! $can_edit ) { - $can_view = false; - } - break; - case '-2': // Only specific member roles - if ( ! is_user_logged_in() ) { - $can_view = false; - } elseif ( ! empty( $array['roles'] ) && count( array_intersect( $current_user_roles, $array['roles'] ) ) <= 0 ) { - $can_view = false; - } - break; - case '-3': // Only visible to profile owner and specific roles - if ( ! is_user_logged_in() ) { - $can_view = false; - } elseif ( $args['user_id'] != get_current_user_id() && ! empty( $array['roles'] ) && count( array_intersect( $current_user_roles, $array['roles'] ) ) <= 0 ) { - $can_view = false; - } - break; - default: - $can_view = apply_filters( 'um_can_view_field_custom', $can_view, $array ); - break; - } - - } - - $can_view = apply_filters( 'um_can_view_field', $can_view, $array ); - - if ( ! $can_view ) { + if ( 'profile' === $mode ) { + $restricted_fields = UM()->fields()->get_restricted_fields_for_edit(); + if ( is_array( $restricted_fields ) && in_array( $key, $restricted_fields, true ) ) { continue; } + } - /** - * UM hook - * - * @type filter - * @title um_get_custom_field_array - * @description Extend custom field data on submit form error - * @input_vars - * [{"var":"$array","type":"array","desc":"Field data"}, - * {"var":"$fields","type":"array","desc":"All fields"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * - */ - $array = apply_filters( 'um_get_custom_field_array', $array, $fields ); + $can_view = true; + if ( isset( $array['public'] ) && 'register' !== $mode ) { - if ( ! empty( $array['conditions'] ) ) { - try { - foreach ( $array['conditions'] as $condition ) { - $continue = um_check_conditions_on_submit( $condition, $fields, $args, true ); - if ( $continue === true ) { - continue 2; - } + switch ( $array['public'] ) { + case '1': // Everyone + break; + case '2': // Members + if ( ! is_user_logged_in() ) { + $can_view = false; } - } catch ( Exception $e ) { - UM()->form()->add_error( $key, sprintf( __( '%s - wrong conditions.', 'ultimate-member' ), $array['title'] ) ); - $notice = '
' . sprintf( __( '%s - wrong conditions.', 'ultimate-member' ), $array['title'] ) . '
'; - add_action( 'um_after_profile_fields', function() use ( $notice ) { - echo $notice; - }, 900 ); + break; + case '-1': // Only visible to profile owner and admins + if ( ! is_user_logged_in() ) { + $can_view = false; + } elseif ( $submitted_data['user_id'] != get_current_user_id() && ! $can_edit ) { + $can_view = false; + } + break; + case '-2': // Only specific member roles + if ( ! is_user_logged_in() ) { + $can_view = false; + } elseif ( ! empty( $array['roles'] ) && count( array_intersect( $current_user_roles, $array['roles'] ) ) <= 0 ) { + $can_view = false; + } + break; + case '-3': // Only visible to profile owner and specific roles + if ( ! is_user_logged_in() ) { + $can_view = false; + } elseif ( $submitted_data['user_id'] != get_current_user_id() && ! empty( $array['roles'] ) && count( array_intersect( $current_user_roles, $array['roles'] ) ) <= 0 ) { + $can_view = false; + } + break; + default: + $can_view = apply_filters( 'um_can_view_field_custom', $can_view, $array ); + break; + } + } + + $can_view = apply_filters( 'um_can_view_field', $can_view, $array ); + + if ( ! $can_view ) { + continue; + } + + /** + * UM hook + * + * @type filter + * @title um_get_custom_field_array + * @description Extend custom field data on submit form error + * @input_vars + * [{"var":"$array","type":"array","desc":"Field data"}, + * {"var":"$fields","type":"array","desc":"All fields"}] + * @change_log + * ["Since: 2.0"] + * @usage + * + * @example + * + */ + $array = apply_filters( 'um_get_custom_field_array', $array, $fields ); + + if ( ! empty( $array['conditions'] ) ) { + try { + foreach ( $array['conditions'] as $condition ) { + $continue = um_check_conditions_on_submit( $condition, $fields, $submitted_data, true ); + if ( $continue === true ) { + continue 2; + } + } + } catch ( Exception $e ) { + UM()->form()->add_error( $key, sprintf( __( '%s - wrong conditions.', 'ultimate-member' ), $array['title'] ) ); + $notice = '
' . sprintf( __( '%s - wrong conditions.', 'ultimate-member' ), $array['title'] ) . '
'; + add_action( 'um_after_profile_fields', function() use ( $notice ) { + echo $notice; + }, 900 ); + } + } + + if ( isset( $array['type'] ) && $array['type'] == 'checkbox' && isset( $array['required'] ) && $array['required'] == 1 && ! isset( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, sprintf( __( '%s is required.', 'ultimate-member' ), $array['title'] ) ); + } + + if ( isset( $array['type'] ) && $array['type'] == 'radio' && isset( $array['required'] ) && $array['required'] == 1 && ! isset( $submitted_data[ $key ] ) && ! in_array( $key, array( 'role_radio', 'role_select' ) ) ) { + UM()->form()->add_error( $key, sprintf( __( '%s is required.', 'ultimate-member'), $array['title'] ) ); + } + + if ( isset( $array['type'] ) && $array['type'] == 'multiselect' && isset( $array['required'] ) && $array['required'] == 1 && ! isset( $submitted_data[ $key ] ) && ! in_array( $key, array( 'role_radio', 'role_select' ) ) ) { + UM()->form()->add_error( $key, sprintf( __( '%s is required.', 'ultimate-member' ), $array['title'] ) ); + } + + /* WordPress uses the default user role if the role wasn't chosen in the registration form. That is why we should use submitted data to validate fields Roles (Radio) and Roles (Dropdown). */ + if ( in_array( $key, array( 'role_radio', 'role_select' ) ) && isset( $array['required'] ) && $array['required'] == 1 && empty( UM()->form()->post_form['submitted']['role'] ) ) { + UM()->form()->add_error( 'role', __( 'Please specify account type.', 'ultimate-member' ) ); + UM()->form()->post_form[ $key ] = ''; + } + + /** + * UM hook + * + * @type action + * @title um_add_error_on_form_submit_validation + * @description Submit form validation + * @input_vars + * [{"var":"$field","type":"array","desc":"Field Data"}, + * {"var":"$key","type":"string","desc":"Field Key"}, + * {"var":"$args","type":"array","desc":"Form Arguments"}] + * @change_log + * ["Since: 2.0"] + * @usage add_action( 'um_add_error_on_form_submit_validation', 'function_name', 10, 3 ); + * @example + * + */ + do_action( 'um_add_error_on_form_submit_validation', $array, $key, $submitted_data ); + + if ( ! empty( $array['required'] ) ) { + if ( ! isset( $submitted_data[ $key ] ) || $submitted_data[ $key ] == '' || $submitted_data[ $key ] == 'empty_file' ) { + if ( empty( $array['label'] ) ) { + UM()->form()->add_error( $key, __( 'This field is required', 'ultimate-member' ) ); + } else { + UM()->form()->add_error( $key, sprintf( __( '%s is required', 'ultimate-member' ), $array['label'] ) ); } } + } - if ( isset( $array['type'] ) && $array['type'] == 'checkbox' && isset( $array['required'] ) && $array['required'] == 1 && ! isset( $args[ $key ] ) ) { - UM()->form()->add_error( $key, sprintf( __( '%s is required.', 'ultimate-member' ), $array['title'] ) ); + if ( ! isset( $submitted_data[ $key ] ) ) { + continue; + } + + if ( isset( $array['max_words'] ) && $array['max_words'] > 0 ) { + if ( str_word_count( $submitted_data[ $key ], 0, "éèàôù" ) > $array['max_words'] ) { + UM()->form()->add_error( $key, sprintf( __( 'You are only allowed to enter a maximum of %s words', 'ultimate-member' ), $array['max_words'] ) ); } + } - if ( isset( $array['type'] ) && $array['type'] == 'radio' && isset( $array['required'] ) && $array['required'] == 1 && ! isset( $args[ $key ] ) && ! in_array( $key, array( 'role_radio', 'role_select' ) ) ) { - UM()->form()->add_error( $key, sprintf( __( '%s is required.', 'ultimate-member'), $array['title'] ) ); - } - - if ( isset( $array['type'] ) && $array['type'] == 'multiselect' && isset( $array['required'] ) && $array['required'] == 1 && ! isset( $args[ $key ] ) && ! in_array( $key, array( 'role_radio', 'role_select' ) ) ) { - UM()->form()->add_error( $key, sprintf( __( '%s is required.', 'ultimate-member' ), $array['title'] ) ); - } - - /* WordPress uses the default user role if the role wasn't chosen in the registration form. That is why we should use submitted data to validate fields Roles (Radio) and Roles (Dropdown). */ - if ( in_array( $key, array( 'role_radio', 'role_select' ) ) && isset( $array['required'] ) && $array['required'] == 1 && empty( UM()->form()->post_form['submitted']['role'] ) ) { - UM()->form()->add_error( 'role', __( 'Please specify account type.', 'ultimate-member' ) ); - UM()->form()->post_form[ $key ] = ''; - } - - /** - * UM hook - * - * @type action - * @title um_add_error_on_form_submit_validation - * @description Submit form validation - * @input_vars - * [{"var":"$field","type":"array","desc":"Field Data"}, - * {"var":"$key","type":"string","desc":"Field Key"}, - * {"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_add_error_on_form_submit_validation', 'function_name', 10, 3 ); - * @example - * - */ - do_action( 'um_add_error_on_form_submit_validation', $array, $key, $args ); - - if ( ! empty( $array['required'] ) ) { - if ( ! isset( $args[ $key ] ) || $args[ $key ] == '' || $args[ $key ] == 'empty_file' ) { - if ( empty( $array['label'] ) ) { - UM()->form()->add_error( $key, __( 'This field is required', 'ultimate-member' ) ); - } else { - UM()->form()->add_error( $key, sprintf( __( '%s is required', 'ultimate-member' ), $array['label'] ) ); - } + if ( isset( $array['min_chars'] ) && $array['min_chars'] > 0 ) { + if ( $submitted_data[ $key ] && mb_strlen( $submitted_data[ $key ] ) < $array['min_chars'] ) { + if ( empty( $array['label'] ) ) { + UM()->form()->add_error( $key, sprintf( __( 'This field must contain at least %s characters', 'ultimate-member' ), $array['min_chars'] ) ); + } else { + UM()->form()->add_error( $key, sprintf( __( 'Your %s must contain at least %s characters', 'ultimate-member' ), $array['label'], $array['min_chars'] ) ); } } + } - if ( isset( $args[ $key ] ) ) { + if ( isset( $array['max_chars'] ) && $array['max_chars'] > 0 ) { + if ( $submitted_data[ $key ] && mb_strlen( $submitted_data[ $key ] ) > $array['max_chars'] ) { + if ( empty( $array['label'] ) ) { + UM()->form()->add_error( $key, sprintf( __( 'This field must contain less than %s characters', 'ultimate-member' ), $array['max_chars'] ) ); + } else { + UM()->form()->add_error( $key, sprintf( __( 'Your %s must contain less than %s characters', 'ultimate-member' ), $array['label'], $array['max_chars'] ) ); + } + } + } - if ( isset( $array['max_words'] ) && $array['max_words'] > 0 ) { - if ( str_word_count( $args[ $key ], 0, "éèàôù" ) > $array['max_words'] ) { - UM()->form()->add_error( $key, sprintf( __( 'You are only allowed to enter a maximum of %s words', 'ultimate-member' ), $array['max_words'] ) ); - } + if ( isset( $array['type'] ) && $array['type'] == 'textarea' && UM()->profile()->get_show_bio_key( $submitted_data ) !== $key ) { + if ( ! isset( $array['html'] ) || $array['html'] == 0 ) { + if ( wp_strip_all_tags( $submitted_data[ $key ] ) != trim( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'You can not use HTML tags here', 'ultimate-member' ) ); + } + } + } + + if ( isset( $array['force_good_pass'] ) && $array['force_good_pass'] && ! empty( $submitted_data['user_password'] ) ) { + if ( isset( $submitted_data['user_login'] ) && strpos( strtolower( $submitted_data['user_login'] ), strtolower( $submitted_data['user_password'] ) ) > -1 ) { + UM()->form()->add_error( 'user_password', __( 'Your password cannot contain the part of your username', 'ultimate-member' )); + } + + if ( isset( $submitted_data['user_email'] ) && strpos( strtolower( $submitted_data['user_email'] ), strtolower( $submitted_data['user_password'] ) ) > -1 ) { + UM()->form()->add_error( 'user_password', __( 'Your password cannot contain the part of your email address', 'ultimate-member' )); + } + + if ( ! UM()->validation()->strong_pass( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Your password must contain at least one lowercase letter, one capital letter and one number', 'ultimate-member' ) ); + } + } + + if ( ! empty( $array['force_confirm_pass'] ) ) { + if ( ! array_key_exists( 'confirm_' . $key, $submitted_data ) && ! UM()->form()->has_error( $key ) ) { + UM()->form()->add_error( 'confirm_' . $key, __( 'Please confirm your password', 'ultimate-member' ) ); + } else { + if ( '' === $submitted_data[ 'confirm_' . $key ] && ! UM()->form()->has_error( $key ) ) { + UM()->form()->add_error( 'confirm_' . $key, __( 'Please confirm your password', 'ultimate-member' ) ); + } + if ( $submitted_data[ 'confirm_' . $key ] !== $submitted_data[ $key ] && ! UM()->form()->has_error( $key ) ) { + UM()->form()->add_error( 'confirm_' . $key, __( 'Your passwords do not match', 'ultimate-member' ) ); + } + } + } + + if ( isset( $array['min_selections'] ) && $array['min_selections'] > 0 ) { + if ( ( ! isset( $submitted_data[ $key ] ) ) || ( isset( $submitted_data[ $key ] ) && is_array( $submitted_data[ $key ] ) && count( $submitted_data[ $key ] ) < $array['min_selections'] ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please select at least %s choices', 'ultimate-member' ), $array['min_selections'] ) ); + } + } + + if ( isset( $array['max_selections'] ) && $array['max_selections'] > 0 ) { + if ( isset( $submitted_data[ $key ] ) && is_array( $submitted_data[ $key ] ) && count( $submitted_data[ $key ] ) > $array['max_selections'] ) { + UM()->form()->add_error( $key, sprintf( __( 'You can only select up to %s choices', 'ultimate-member' ), $array['max_selections'] ) ); + } + } + + if ( isset( $array['min'] ) && is_numeric( $submitted_data[ $key ] ) ) { + if ( isset( $submitted_data[ $key ] ) && $submitted_data[ $key ] < $array['min'] ) { + UM()->form()->add_error( $key, sprintf( __( 'Minimum number limit is %s', 'ultimate-member' ), $array['min'] ) ); + } + } + + if ( isset( $array['max'] ) && is_numeric( $submitted_data[ $key ] ) ) { + if ( isset( $submitted_data[ $key ] ) && $submitted_data[ $key ] > $array['max'] ) { + UM()->form()->add_error( $key, sprintf( __( 'Maximum number limit is %s', 'ultimate-member' ), $array['max'] ) ); + } + } + + if ( empty( $array['validate'] ) ) { + continue; + } + + switch ( $array['validate'] ) { + + case 'custom': + $custom = $array['custom_validate']; + /** + * UM hook + * + * @type action + * @title um_custom_field_validation_{$custom} + * @description Submit form validation for custom field + * @input_vars + * [{"var":"$key","type":"string","desc":"Field Key"}, + * {"var":"$field","type":"array","desc":"Field Data"}, + * {"var":"$args","type":"array","desc":"Form Arguments"}] + * @change_log + * ["Since: 2.0"] + * @usage add_action( 'um_custom_field_validation_{$custom}', 'function_name', 10, 3 ); + * @example + * + */ + do_action( "um_custom_field_validation_{$custom}", $key, $array, $submitted_data ); + break; + + case 'numeric': + if ( $submitted_data[ $key ] && ! is_numeric( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Please enter numbers only in this field', 'ultimate-member' ) ); + } + break; + + case 'phone_number': + if ( ! UM()->validation()->is_phone_number( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Please enter a valid phone number', 'ultimate-member' ) ); + } + break; + + case 'youtube_url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'youtube.com' ) && ! UM()->validation()->is_url( $submitted_data[ $key ], 'youtu.be' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'spotify_url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'open.spotify.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'telegram_url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 't.me' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'soundcloud_url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'soundcloud.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL','ultimate-member'), $array['label'] ) ); + } + break; + + case 'facebook_url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'facebook.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'twitter_url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'twitter.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'instagram_url': + + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'instagram.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'linkedin_url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'linkedin.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'discord': + if ( ! UM()->validation()->is_discord_id( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Please enter a valid Discord ID', 'ultimate-member' ) ); + } + break; + + case 'tiktok_url': + + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'tiktok.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'twitch_url': + + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'twitch.tv' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'reddit_url': + + if ( ! UM()->validation()->is_url( $submitted_data[ $key ], 'reddit.com' ) ) { + UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); + } + break; + + case 'url': + if ( ! UM()->validation()->is_url( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Please enter a valid URL', 'ultimate-member' ) ); + } + break; + + case 'unique_username': + + if ( $submitted_data[ $key ] == '' ) { + UM()->form()->add_error( $key, __( 'You must provide a username', 'ultimate-member' ) ); + } elseif ( $mode == 'register' && username_exists( sanitize_user( $submitted_data[ $key ] ) ) ) { + UM()->form()->add_error( $key, __( 'The username you entered is incorrect', 'ultimate-member' ) ); + } elseif ( is_email( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Username cannot be an email', 'ultimate-member' ) ); + } elseif ( ! UM()->validation()->safe_username( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Your username contains invalid characters', 'ultimate-member' ) ); } - if ( isset( $array['min_chars'] ) && $array['min_chars'] > 0 ) { - if ( $args[ $key ] && mb_strlen( $args[ $key ] ) < $array['min_chars'] ) { - if ( empty( $array['label'] ) ) { - UM()->form()->add_error( $key, sprintf( __( 'This field must contain at least %s characters', 'ultimate-member' ), $array['min_chars'] ) ); - } else { - UM()->form()->add_error( $key, sprintf( __( 'Your %s must contain at least %s characters', 'ultimate-member' ), $array['label'], $array['min_chars'] ) ); - } - } + break; + + case 'unique_username_or_email': + + if ( $submitted_data[ $key ] == '' ) { + UM()->form()->add_error( $key, __( 'You must provide a username or email', 'ultimate-member' ) ); + } elseif ( $mode == 'register' && username_exists( sanitize_user( $submitted_data[ $key ] ) ) ) { + UM()->form()->add_error( $key, __( 'The username you entered is incorrect', 'ultimate-member' ) ); + } elseif ( $mode == 'register' && email_exists( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); + } elseif ( ! UM()->validation()->safe_username( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Your username contains invalid characters', 'ultimate-member' ) ); } - if ( isset( $array['max_chars'] ) && $array['max_chars'] > 0 ) { - if ( $args[ $key ] && mb_strlen( $args[ $key ] ) > $array['max_chars'] ) { - if ( empty( $array['label'] ) ) { - UM()->form()->add_error( $key, sprintf( __( 'This field must contain less than %s characters', 'ultimate-member' ), $array['max_chars'] ) ); - } else { - UM()->form()->add_error( $key, sprintf( __( 'Your %s must contain less than %s characters', 'ultimate-member' ), $array['label'], $array['max_chars'] ) ); - } - } - } + break; - if ( isset( $array['type'] ) && $array['type'] == 'textarea' && UM()->profile()->get_show_bio_key( $args ) !== $key ) { - if ( ! isset( $array['html'] ) || $array['html'] == 0 ) { - if ( wp_strip_all_tags( $args[ $key ] ) != trim( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'You can not use HTML tags here', 'ultimate-member' ) ); - } - } - } + case 'unique_email': - if ( isset( $array['force_good_pass'] ) && $array['force_good_pass'] && ! empty( $args['user_password'] ) ) { - if ( isset( $args['user_login'] ) && strpos( strtolower( $args['user_login'] ), strtolower( $args['user_password'] ) ) > -1 ) { - UM()->form()->add_error( 'user_password', __( 'Your password cannot contain the part of your username', 'ultimate-member' )); + $submitted_data[ $key ] = trim( $submitted_data[ $key ] ); + + if ( in_array( $key, array( 'user_email' ) ) ) { + + if ( ! isset( $submitted_data['user_id'] ) ){ + $submitted_data['user_id'] = um_get_requested_user(); } - if ( isset( $args['user_email'] ) && strpos( strtolower( $args['user_email'] ), strtolower( $args['user_password'] ) ) > -1 ) { - UM()->form()->add_error( 'user_password', __( 'Your password cannot contain the part of your email address', 'ultimate-member' )); + $email_exists = email_exists( $submitted_data[ $key ] ); + + if ( $submitted_data[ $key ] == '' && in_array( $key, array( 'user_email' ) ) ) { + UM()->form()->add_error( $key, __( 'You must provide your email', 'ultimate-member' ) ); + } elseif ( in_array( $mode, array( 'register' ) ) && $email_exists ) { + UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); + } elseif ( in_array( $mode, array( 'profile' ) ) && $email_exists && $email_exists != $submitted_data['user_id'] ) { + UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); + } elseif ( ! is_email( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member') ); + } elseif ( ! UM()->validation()->safe_username( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'Your email contains invalid characters', 'ultimate-member' ) ); } - if ( ! UM()->validation()->strong_pass( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Your password must contain at least one lowercase letter, one capital letter and one number', 'ultimate-member' ) ); - } - } + } else { - if ( ! empty( $array['force_confirm_pass'] ) ) { - if ( ! array_key_exists( 'confirm_' . $key, $args ) && ! UM()->form()->has_error( $key ) ) { - UM()->form()->add_error( 'confirm_' . $key, __( 'Please confirm your password', 'ultimate-member' ) ); - } else { - if ( '' === $args[ 'confirm_' . $key ] && ! UM()->form()->has_error( $key ) ) { - UM()->form()->add_error( 'confirm_' . $key, __( 'Please confirm your password', 'ultimate-member' ) ); - } - if ( $args[ 'confirm_' . $key ] !== $args[ $key ] && ! UM()->form()->has_error( $key ) ) { - UM()->form()->add_error( 'confirm_' . $key, __( 'Your passwords do not match', 'ultimate-member' ) ); - } - } - } + if ( $submitted_data[ $key ] != '' && ! is_email( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); + } elseif ( $submitted_data[ $key ] != '' && email_exists( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); + } elseif ( $submitted_data[ $key ] != '' ) { - if ( isset( $array['min_selections'] ) && $array['min_selections'] > 0 ) { - if ( ( ! isset( $args[ $key ] ) ) || ( isset( $args[ $key ] ) && is_array( $args[ $key ] ) && count( $args[ $key ] ) < $array['min_selections'] ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please select at least %s choices', 'ultimate-member' ), $array['min_selections'] ) ); - } - } + $users = get_users( 'meta_value=' . $submitted_data[ $key ] ); - if ( isset( $array['max_selections'] ) && $array['max_selections'] > 0 ) { - if ( isset( $args[ $key ] ) && is_array( $args[ $key ] ) && count( $args[ $key ] ) > $array['max_selections'] ) { - UM()->form()->add_error( $key, sprintf( __( 'You can only select up to %s choices', 'ultimate-member' ), $array['max_selections'] ) ); - } - } - - if ( isset( $array['min'] ) && is_numeric( $args[ $key ] ) ) { - if ( isset( $args[ $key ] ) && $args[ $key ] < $array['min'] ) { - UM()->form()->add_error( $key, sprintf( __( 'Minimum number limit is %s', 'ultimate-member' ), $array['min'] ) ); - } - } - - if ( isset( $array['max'] ) && is_numeric( $args[ $key ] ) ) { - if ( isset( $args[ $key ] ) && $args[ $key ] > $array['max'] ) { - UM()->form()->add_error( $key, sprintf( __( 'Maximum number limit is %s', 'ultimate-member' ), $array['max'] ) ); - } - } - - if ( ! empty( $array['validate'] ) ) { - - switch( $array['validate'] ) { - - case 'custom': - $custom = $array['custom_validate']; - /** - * UM hook - * - * @type action - * @title um_custom_field_validation_{$custom} - * @description Submit form validation for custom field - * @input_vars - * [{"var":"$key","type":"string","desc":"Field Key"}, - * {"var":"$field","type":"array","desc":"Field Data"}, - * {"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_custom_field_validation_{$custom}', 'function_name', 10, 3 ); - * @example - * - */ - do_action( "um_custom_field_validation_{$custom}", $key, $array, $args ); - break; - - case 'numeric': - if ( $args[ $key ] && ! is_numeric( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Please enter numbers only in this field', 'ultimate-member' ) ); - } - break; - - case 'phone_number': - if ( ! UM()->validation()->is_phone_number( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Please enter a valid phone number', 'ultimate-member' ) ); - } - break; - - case 'youtube_url': - if ( ! UM()->validation()->is_url( $args[ $key ], 'youtube.com' ) && ! UM()->validation()->is_url( $args[ $key ], 'youtu.be' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'spotify_url': - if ( ! UM()->validation()->is_url( $args[ $key ], 'open.spotify.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'telegram_url': - if ( ! UM()->validation()->is_url( $args[ $key ], 't.me' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'soundcloud_url': - if ( ! UM()->validation()->is_url( $args[ $key ], 'soundcloud.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL','ultimate-member'), $array['label'] ) ); - } - break; - - case 'facebook_url': - if ( ! UM()->validation()->is_url( $args[ $key ], 'facebook.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'twitter_url': - if ( ! UM()->validation()->is_url( $args[ $key ], 'twitter.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'instagram_url': - - if ( ! UM()->validation()->is_url( $args[ $key ], 'instagram.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'linkedin_url': - if ( ! UM()->validation()->is_url( $args[ $key ], 'linkedin.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'discord': - if ( ! UM()->validation()->is_discord_id( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Please enter a valid Discord ID', 'ultimate-member' ) ); - } - break; - - case 'tiktok_url': - - if ( ! UM()->validation()->is_url( $args[ $key ], 'tiktok.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'twitch_url': - - if ( ! UM()->validation()->is_url( $args[ $key ], 'twitch.tv' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'reddit_url': - - if ( ! UM()->validation()->is_url( $args[ $key ], 'reddit.com' ) ) { - UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s profile URL', 'ultimate-member' ), $array['label'] ) ); - } - break; - - case 'url': - if ( ! UM()->validation()->is_url( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Please enter a valid URL', 'ultimate-member' ) ); - } - break; - - case 'unique_username': - - if ( $args[ $key ] == '' ) { - UM()->form()->add_error( $key, __( 'You must provide a username', 'ultimate-member' ) ); - } elseif ( $mode == 'register' && username_exists( sanitize_user( $args[ $key ] ) ) ) { - UM()->form()->add_error( $key, __( 'The username you entered is incorrect', 'ultimate-member' ) ); - } elseif ( is_email( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Username cannot be an email', 'ultimate-member' ) ); - } elseif ( ! UM()->validation()->safe_username( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Your username contains invalid characters', 'ultimate-member' ) ); - } - - break; - - case 'unique_username_or_email': - - if ( $args[ $key ] == '' ) { - UM()->form()->add_error( $key, __( 'You must provide a username or email', 'ultimate-member' ) ); - } elseif ( $mode == 'register' && username_exists( sanitize_user( $args[ $key ] ) ) ) { - UM()->form()->add_error( $key, __( 'The username you entered is incorrect', 'ultimate-member' ) ); - } elseif ( $mode == 'register' && email_exists( $args[ $key ] ) ) { + foreach ( $users as $user ) { + if ( $user->ID != $submitted_data['user_id'] ) { UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); - } elseif ( ! UM()->validation()->safe_username( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Your username contains invalid characters', 'ultimate-member' ) ); } - - break; - - case 'unique_email': - - $args[ $key ] = trim( $args[ $key ] ); - - if ( in_array( $key, array( 'user_email' ) ) ) { - - if ( ! isset( $args['user_id'] ) ){ - $args['user_id'] = um_get_requested_user(); - } - - $email_exists = email_exists( $args[ $key ] ); - - if ( $args[ $key ] == '' && in_array( $key, array( 'user_email' ) ) ) { - UM()->form()->add_error( $key, __( 'You must provide your email', 'ultimate-member' ) ); - } elseif ( in_array( $mode, array( 'register' ) ) && $email_exists ) { - UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); - } elseif ( in_array( $mode, array( 'profile' ) ) && $email_exists && $email_exists != $args['user_id'] ) { - UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); - } elseif ( ! is_email( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member') ); - } elseif ( ! UM()->validation()->safe_username( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'Your email contains invalid characters', 'ultimate-member' ) ); - } - - } else { - - if ( $args[ $key ] != '' && ! is_email( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); - } elseif ( $args[ $key ] != '' && email_exists( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); - } elseif ( $args[ $key ] != '' ) { - - $users = get_users( 'meta_value=' . $args[ $key ] ); - - foreach ( $users as $user ) { - if ( $user->ID != $args['user_id'] ) { - UM()->form()->add_error( $key, __( 'The email you entered is incorrect', 'ultimate-member' ) ); - } - } - - } - - } - - break; - - case 'is_email': - - $args[ $key ] = trim( $args[ $key ] ); - - if ( $args[ $key ] != '' && ! is_email( $args[ $key ] ) ) { - UM()->form()->add_error( $key, __( 'This is not a valid email', 'ultimate-member' ) ); - } - - break; - - case 'unique_value': - - if ( $args[ $key ] != '' ) { - - $args_unique_meta = array( - 'meta_key' => $key, - 'meta_value' => $args[ $key ], - 'compare' => '=', - 'exclude' => array( $args['user_id'] ), - ); - - $meta_key_exists = get_users( $args_unique_meta ); - - if ( $meta_key_exists ) { - UM()->form()->add_error( $key , __( 'You must provide a unique value', 'ultimate-member' ) ); - } - } - break; - - case 'alphabetic': - - if ( $args[ $key ] != '' ) { - - if ( ! preg_match( '/^\p{L}+$/u', str_replace( ' ', '', $args[ $key ] ) ) ) { - UM()->form()->add_error( $key, __( 'You must provide alphabetic letters', 'ultimate-member' ) ); - } - - } - - break; - - case 'lowercase': - - if ( $args[ $key ] != '' ) { - - if ( ! ctype_lower( str_replace(' ', '', $args[ $key ] ) ) ) { - UM()->form()->add_error( $key , __( 'You must provide lowercase letters.', 'ultimate-member' ) ); - } - } - - break; + } } } - } + break; - if ( isset( $args['description'] ) ) { - $max_chars = UM()->options()->get( 'profile_bio_maxchars' ); - $profile_show_bio = UM()->options()->get( 'profile_show_bio' ); + case 'is_email': - if ( $profile_show_bio ) { - if ( mb_strlen( str_replace( array( "\r\n", "\n", "\r\t", "\t" ), ' ', $args['description'] ) ) > $max_chars && $max_chars ) { - UM()->form()->add_error( 'description', sprintf( __( 'Your user description must contain less than %s characters', 'ultimate-member' ), $max_chars ) ); + $submitted_data[ $key ] = trim( $submitted_data[ $key ] ); + + if ( $submitted_data[ $key ] != '' && ! is_email( $submitted_data[ $key ] ) ) { + UM()->form()->add_error( $key, __( 'This is not a valid email', 'ultimate-member' ) ); + } + + break; + + case 'unique_value': + + if ( $submitted_data[ $key ] != '' ) { + + $args_unique_meta = array( + 'meta_key' => $key, + 'meta_value' => $submitted_data[ $key ], + 'compare' => '=', + 'exclude' => array( $submitted_data['user_id'] ), + ); + + $meta_key_exists = get_users( $args_unique_meta ); + + if ( $meta_key_exists ) { + UM()->form()->add_error( $key , __( 'You must provide a unique value', 'ultimate-member' ) ); + } + } + break; + + case 'alphabetic': + + if ( $submitted_data[ $key ] != '' ) { + + if ( ! preg_match( '/^\p{L}+$/u', str_replace( ' ', '', $submitted_data[ $key ] ) ) ) { + UM()->form()->add_error( $key, __( 'You must provide alphabetic letters', 'ultimate-member' ) ); + } + + } + + break; + + case 'lowercase': + + if ( $submitted_data[ $key ] != '' ) { + + if ( ! ctype_lower( str_replace(' ', '', $submitted_data[ $key ] ) ) ) { + UM()->form()->add_error( $key , __( 'You must provide lowercase letters.', 'ultimate-member' ) ); } } - } + break; - } // end if ( isset in args array ) - } + } + + if ( isset( $submitted_data['description'] ) ) { + $max_chars = UM()->options()->get( 'profile_bio_maxchars' ); + $profile_show_bio = UM()->options()->get( 'profile_show_bio' ); + + if ( $profile_show_bio ) { + if ( mb_strlen( str_replace( array( "\r\n", "\n", "\r\t", "\t" ), ' ', $submitted_data['description'] ) ) > $max_chars && $max_chars ) { + UM()->form()->add_error( 'description', sprintf( __( 'Your user description must contain less than %s characters', 'ultimate-member' ), $max_chars ) ); + } + } + } + } // end if ( isset in args array ) } -add_action( 'um_submit_form_errors_hook_', 'um_submit_form_errors_hook_', 10 ); +add_action( 'um_submit_form_errors_hook_', 'um_submit_form_errors_hook_', 10, 2 ); /** diff --git a/includes/core/um-actions-profile.php b/includes/core/um-actions-profile.php index 5d3328c5..f2512b0b 100644 --- a/includes/core/um-actions-profile.php +++ b/includes/core/um-actions-profile.php @@ -586,16 +586,18 @@ add_action( 'um_user_edit_profile', 'um_user_edit_profile', 10 ); /** - * @param array $post_form + * Validate nonce when profile form submit. + * + * @param array $submitted_data */ -function um_profile_validate_nonce( $post_form ) { - $user_id = isset( $post_form['user_id'] ) ? $post_form['user_id'] : ''; - $nonce = isset( $post_form['profile_nonce'] ) ? $post_form['profile_nonce'] : ''; +function um_profile_validate_nonce( $submitted_data ) { + $user_id = isset( $submitted_data['user_id'] ) ? $submitted_data['user_id'] : ''; + $nonce = isset( $submitted_data['profile_nonce'] ) ? $submitted_data['profile_nonce'] : ''; if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'um-profile-nonce' . $user_id ) ) { - wp_die( __( 'This is not possible for security reasons.', 'ultimate-member' ) ); + wp_die( esc_html__( 'This is not possible for security reasons.', 'ultimate-member' ) ); } } -add_action( 'um_submit_form_errors_hook__profile', 'um_profile_validate_nonce', 10, 1 ); +add_action( 'um_submit_form_errors_hook__profile', 'um_profile_validate_nonce', 1 ); add_filter( 'um_user_pre_updating_files_array', array( UM()->validation(), 'validate_files' ), 10, 1 ); diff --git a/includes/core/um-actions-register.php b/includes/core/um-actions-register.php index 3bf016ce..9d35811e 100644 --- a/includes/core/um-actions-register.php +++ b/includes/core/um-actions-register.php @@ -267,13 +267,18 @@ function um_check_user_status( $user_id, $args ) { } add_action( 'um_registration_complete', 'um_check_user_status', 100, 2 ); -function um_submit_form_errors_hook__registration( $args ) { +/** + * Validate user password field on registration. + * + * @param array $submitted_data + */ +function um_submit_form_errors_hook__registration( $submitted_data ) { // Check for "\" in password. - if ( array_key_exists( 'user_password', $args ) && false !== strpos( wp_unslash( trim( $args['user_password'] ) ), '\\' ) ) { + if ( array_key_exists( 'user_password', $submitted_data ) && false !== strpos( wp_unslash( trim( $submitted_data['user_password'] ) ), '\\' ) ) { UM()->form()->add_error( 'user_password', __( 'Passwords may not contain the character "\\".', 'ultimate-member' ) ); } } -add_action( 'um_submit_form_errors_hook__registration', 'um_submit_form_errors_hook__registration', 10, 1 ); +add_action( 'um_submit_form_errors_hook__registration', 'um_submit_form_errors_hook__registration' ); /** * Registration form submit handler. From 7fafa3a4b33cdba622a555f4e57a9d0f46299a23 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 30 Jun 2023 21:55:59 +0300 Subject: [PATCH 04/11] - fix for registration form; --- includes/core/class-form.php | 59 ++++- includes/core/class-gdpr.php | 72 ++--- includes/core/class-login.php | 1 + includes/core/class-register.php | 72 ++--- includes/core/class-user.php | 142 ++++------ includes/core/class-validation.php | 13 +- includes/core/um-actions-account.php | 1 + includes/core/um-actions-profile.php | 49 ++-- includes/core/um-actions-register.php | 367 +++++++++++++------------- 9 files changed, 373 insertions(+), 403 deletions(-) diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 7a55db89..41fe3550 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -62,7 +62,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { * * @var array */ - private $usermeta_whitelist = array(); + public $usermeta_whitelist = array(); /** * Form constructor. @@ -393,7 +393,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { */ public function clean_submitted_data( $submitted ) { foreach ( $submitted as $metakey => $value ) { - if ( UM()->user()->is_metakey_banned( $metakey ) ) { + if ( UM()->user()->is_metakey_banned( $metakey/*, 'submission'*/ ) ) { unset( $submitted[ $metakey ] ); } } @@ -442,11 +442,19 @@ if ( ! class_exists( 'um\core\Form' ) ) { return; } + $ignore_keys = array(); + $field_types_without_metakey = UM()->builtin()->get_fields_without_metakey(); foreach ( $custom_fields as $cf_k => $cf_data ) { if ( ! array_key_exists( 'type', $cf_data ) || in_array( $cf_data['type'], $field_types_without_metakey, true ) ) { unset( $custom_fields[ $cf_k ] ); } + + if ( ! array_key_exists( 'type', $cf_data ) || 'password' === $cf_data['type'] ) { + $ignore_keys[] = $cf_k; + $ignore_keys[] = 'confirm_' . $cf_k; + } + if ( ! array_key_exists( 'metakey', $cf_data ) || empty( $cf_data['metakey'] ) ) { unset( $custom_fields[ $cf_k ] ); } @@ -455,18 +463,46 @@ if ( ! class_exists( 'um\core\Form' ) ) { $all_cf_metakeys = $cf_metakeys; // The '_um_last_login' cannot be updated through UM form. - $cf_metakeys = array_values( array_diff( $cf_metakeys, array( 'role_select', 'role_radio', 'role', '_um_last_login' ) ) ); - // Column names from wp_users table. - $cf_metakeys = array_values( array_diff( $cf_metakeys, UM()->user()->update_user_keys ) ); + $cf_metakeys = array_values( array_diff( $cf_metakeys, array( 'role_select', 'role_radio', 'role', '_um_last_login', 'user_pass', 'user_password', 'confirm_user_password' ) ) ); + if ( ! empty( $ignore_keys ) ) { + $cf_metakeys = array_values( array_diff( $cf_metakeys, $ignore_keys ) ); + } // Remove restricted fields when edit profile. if ( 'profile' === $this->form_data['mode'] ) { + // Column names from wp_users table. + $cf_metakeys = array_values( array_diff( $cf_metakeys, array( 'user_login' ) ) ); + // Hidden for edit fields $cf_metakeys = array_values( array_diff( $cf_metakeys, UM()->fields()->get_restricted_fields_for_edit() ) ); } // Add required usermeta for register. if ( 'register' === $this->form_data['mode'] ) { - $cf_metakeys[] = 'submitted'; + $cf_metakeys[] = 'form_id'; + $cf_metakeys[] = 'timestamp'; } + /** + * Filters whitelisted usermeta keys that can be stored inside DB after UM Form submission. + * + * @param {array} $whitelisted_metakeys Whitelisted usermeta keys. + * @param {array} $form_data UM form data. + * + * @return {array} Whitelisted usermeta keys. + * + * @since 2.6.7 + * @hook um_whitelisted_metakeys + * + * @example Extends whitelisted usermeta keys. + * function my_um_whitelisted_metakeys( $metakeys, $form_data ) { + * $metakeys[] = 'some_key'; + * return $metakeys; + * } + * add_filter( 'um_whitelisted_metakeys', 'my_um_whitelisted_metakeys', 10, 2 ); + */ + $cf_metakeys = apply_filters( 'um_whitelisted_metakeys', $cf_metakeys, $this->form_data ); + + // Important variable to prevent save unnecessary data to wp_usermeta. + $this->usermeta_whitelist = $cf_metakeys; + /** * Fires before UM login, registration or profile form submission. * @@ -558,7 +594,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { } // @todo REMOVE THAT !!! AND SEPARATE FORM DATA AND SUBMISSION DATA. MAY AFFECT TO EXTENSIONS - $this->post_form = array_merge( $this->form_data, $this->post_form ); + //$this->post_form = array_merge( $this->form_data, $this->post_form ); // Remove role from post_form at first if role ! empty and there aren't custom fields with role name // if ( ! empty( $this->post_form['role'] ) ) { @@ -660,7 +696,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { * add_action( 'um_submit_form_errors_hook', 'my_custom_submit_form_errors_hook', 10, 2 ); */ do_action( 'um_submit_form_errors_hook', $this->post_form, $this->form_data ); - if ( 'login' !== $this->form_data['mode'] ) { + if ( 'profile' === $this->form_data['mode'] ) { var_dump( $this->post_form ); var_dump( $this->form_data ); var_dump( '------------------------------------------------------------' ); @@ -678,7 +714,12 @@ if ( ! class_exists( 'um\core\Form' ) ) { * * 1 - `UM()->login()->verify_nonce()` Verify nonce. * * 10 - `um_submit_form_login()` Login form main handler. * ### um_submit_form_register: + * * 1 - `UM()->register()->verify_nonce()` Verify nonce. + * * 9 - `UM()->agreement_validation()` GDPR Agreement. + * * 9 - `UM()->terms_conditions()->agreement_validation()` Terms & Conditions Agreement. + * * 10 - `um_submit_form_register()` Register form main handler. * ### um_submit_form_profile: + * * 10 - `um_submit_form_profile()` Profile form main handler. * * @since 1.3.x * @hook um_submit_form_errors_hook @@ -692,7 +733,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { * } * add_action( 'um_submit_form_errors_hook', 'my_custom_submit_form_errors_hook', 10, 2 ); */ - do_action( "um_submit_form_{$this->post_form['mode']}", $this->post_form, $this->form_data ); + do_action( "um_submit_form_{$this->form_data['mode']}", $this->post_form, $this->form_data ); } } diff --git a/includes/core/class-gdpr.php b/includes/core/class-gdpr.php index 28be93ca..21397af4 100644 --- a/includes/core/class-gdpr.php +++ b/includes/core/class-gdpr.php @@ -1,71 +1,78 @@ form()->add_error( 'use_gdpr_agreement', isset( $args['use_gdpr_error_text'] ) ? $args['use_gdpr_error_text'] : '' ); + if ( $gdpr_enabled && ! isset( $submitted_data['submitted']['use_gdpr_agreement'] ) ) { + UM()->form()->add_error( 'use_gdpr_agreement', $use_gdpr_error_text ); } } + /** + * @param array $metakeys + * @param array $form_data + */ + public function extend_whitelisted( $metakeys, $form_data ) { + $gdpr_enabled = get_post_meta( $form_data['form_id'], '_um_register_use_gdpr', true ); + if ( ! empty( $gdpr_enabled ) ) { + $metakeys[] = 'use_gdpr_agreement'; + } + return $metakeys; + } /** * @param $submitted - * @param $args * * @return mixed */ - function add_agreement_date( $submitted, $args ) { + public function add_agreement_date( $submitted ) { if ( isset( $submitted['use_gdpr_agreement'] ) ) { $submitted['use_gdpr_agreement'] = time(); } @@ -73,21 +80,18 @@ if ( ! class_exists( 'um\core\GDPR' ) ) { return $submitted; } - /** * @param $submitted * * @return mixed */ - function email_registration_data( $submitted ) { + public function email_registration_data( $submitted ) { if ( ! empty( $submitted['use_gdpr_agreement'] ) ) { - $submitted['GDPR Applied'] = date( "d M Y H:i", $submitted['use_gdpr_agreement'] ); + $submitted['GDPR Applied'] = wp_date( get_option( 'date_format', 'Y-m-d' ) . ' ' . get_option( 'time_format', 'H:i:s' ), $submitted['use_gdpr_agreement'] ); unset( $submitted['use_gdpr_agreement'] ); } return $submitted; } - } - -} \ No newline at end of file +} diff --git a/includes/core/class-login.php b/includes/core/class-login.php index 115afbee..10e857f7 100644 --- a/includes/core/class-login.php +++ b/includes/core/class-login.php @@ -61,6 +61,7 @@ if ( ! class_exists( 'um\core\Login' ) ) { } if ( empty( $args['_wpnonce'] ) || ! wp_verify_nonce( $args['_wpnonce'], 'um_login_form' ) ) { + // @todo add hookdocs $url = apply_filters( 'um_login_invalid_nonce_redirect_url', add_query_arg( array( 'err' => 'invalid_nonce' ) ) ); wp_safe_redirect( $url ); exit; diff --git a/includes/core/class-register.php b/includes/core/class-register.php index 4e42938c..833c2b28 100644 --- a/includes/core/class-register.php +++ b/includes/core/class-register.php @@ -1,29 +1,26 @@ - * @example - * + * @param {bool} $allow_nonce Is allowed verify nonce on register. By default, allowed = `true`. + * @param {array} $form_data Form's metakeys. Since 2.6.7. + * + * @return {bool} Is allowed verify. + * + * @since 2.0 + * @hook um_register_allow_nonce_verification + * + * @example Disable verifying nonce on the register page. + * add_filter( 'um_login_allow_nonce_verification', '__return_false' ); */ - $allow_nonce_verification = apply_filters( 'um_register_allow_nonce_verification', true ); - - if ( ! $allow_nonce_verification ) { - return $args; + $allow_nonce_verification = apply_filters( 'um_register_allow_nonce_verification', true, $form_data ); + if ( ! $allow_nonce_verification ) { + return; } - if ( ! wp_verify_nonce( $args['_wpnonce'], 'um_register_form' ) || empty( $args['_wpnonce'] ) || ! isset( $args['_wpnonce'] ) ) { - $url = apply_filters( 'um_register_invalid_nonce_redirect_url', add_query_arg( [ 'err' => 'invalid_nonce' ] ) ); - exit( wp_redirect( $url ) ); + if ( empty( $args['_wpnonce'] ) || ! wp_verify_nonce( $args['_wpnonce'], 'um_register_form' ) ) { + // @todo add hookdocs + $url = apply_filters( 'um_register_invalid_nonce_redirect_url', add_query_arg( array( 'err' => 'invalid_nonce' ) ) ); + wp_safe_redirect( $url ); + exit; } - - return $args; } - } -} \ No newline at end of file +} diff --git a/includes/core/class-user.php b/includes/core/class-user.php index 926433e5..28ee975e 100644 --- a/includes/core/class-user.php +++ b/includes/core/class-user.php @@ -175,7 +175,7 @@ if ( ! class_exists( 'um\core\User' ) ) { * @param string $meta_key Usermeta key. * @return bool */ - public function is_metakey_banned( $meta_key ) { + public function is_metakey_banned( $meta_key, $context = '' ) { $is_banned = false; foreach ( $this->banned_keys as $ban ) { if ( is_numeric( $meta_key ) || false !== stripos( $meta_key, $ban ) || false !== stripos( remove_accents( $meta_key ), $ban ) ) { @@ -184,6 +184,10 @@ if ( ! class_exists( 'um\core\User' ) ) { } } + if ( ! $is_banned && 'submission' === $context && ! in_array( $meta_key, UM()->form()->usermeta_whitelist, true ) ) { + $is_banned = true; + } + return $is_banned; } @@ -192,9 +196,9 @@ if ( ! class_exists( 'um\core\User' ) ) { * * @since 2.6.4 * - * @param null|bool $check Whether to allow updating metadata for the given type. - * @param int $object_id ID of the object metadata is for. - * @param string $meta_key Metadata key. + * @param null|bool $check Whether to allow updating metadata for the given type. + * @param int $object_id ID of the object metadata is for. + * @param string $meta_key Metadata key. * * @return null|bool */ @@ -203,7 +207,7 @@ if ( ! class_exists( 'um\core\User' ) ) { return $check; } - if ( $this->is_metakey_banned( $meta_key ) ) { + if ( $this->is_metakey_banned( $meta_key, 'submission' ) ) { $check = false; } @@ -854,28 +858,8 @@ if ( ! class_exists( 'um\core\User' ) ) { UM()->user()->profile['role'] = sanitize_key( $_POST['um-role'] ); UM()->user()->update_usermeta_info( 'role' ); } - - /** - * UM hook - * - * @type action - * @title um_user_register - * @description Action on user registration - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}, - * {"var":"$submitted","type":"array","desc":"Registration form submitted"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_user_register', 'function_name', 10, 2 ); - * @example - * - */ - do_action( 'um_user_register', $user_id, $_POST ); + /** This action is documented in ultimate-member/includes/common/um-actions-register.php */ + do_action( 'um_user_register', $user_id, $_POST, null ); } delete_transient( 'um_count_users_unassigned' ); @@ -1363,15 +1347,14 @@ if ( ! class_exists( 'um\core\User' ) ) { } - /** * Set user's registration details * * @param array $submitted * @param array $args + * @param array $form_data */ - function set_registration_details( $submitted, $args ) { - + public function set_registration_details( $submitted, $args, $form_data ) { if ( isset( $submitted['user_pass'] ) ) { unset( $submitted['user_pass'] ); } @@ -1387,7 +1370,7 @@ if ( ! class_exists( 'um\core\User' ) ) { //remove all password field values from submitted details $password_fields = array(); foreach ( $submitted as $k => $v ) { - if ( UM()->fields()->get_field_type( $k ) == 'password' ) { + if ( 'password' === UM()->fields()->get_field_type( $k ) ) { $password_fields[] = $k; $password_fields[] = 'confirm_' . $k; } @@ -1397,81 +1380,67 @@ if ( ! class_exists( 'um\core\User' ) ) { unset( $submitted[ $pw_field ] ); } - /** - * UM hook + * Filters submitted data before save usermeta "submitted" on registration process. * - * @type filter - * @title um_before_save_filter_submitted - * @description Change submitted data before save usermeta "submitted" on registration process - * @input_vars - * [{"var":"$submitted","type":"array","desc":"Submitted data"}, - * {"var":"$args","type":"array","desc":"Form Args"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * Change submitted data before save usermeta "submitted" on registration process. + * function my_before_save_filter_submitted( $submitted, $form_submitted_data, $form_data ) { * // your code here * return $submitted; * } - * ?> + * add_filter( 'um_before_save_filter_submitted', 'my_before_save_filter_submitted', 10, 3 ); */ - $submitted = apply_filters( 'um_before_save_filter_submitted', $submitted, $args ); + $submitted = apply_filters( 'um_before_save_filter_submitted', $submitted, $args, $form_data ); /** - * UM hook + * Fires before save registration details to the user. * - * @type action - * @title um_before_save_registration_details - * @description Action on user registration before save details - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}, - * {"var":"$submitted","type":"array","desc":"Registration form submitted"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_before_save_registration_details', 'function_name', 10, 2 ); - * @example - * Make any custom action before save registration details to the user. + * function my_before_save_registration_details( $user_id, $submitted_data ) { * // your code here * } - * ?> + * add_action( 'um_before_save_registration_details', 'my_before_save_registration_details', 10, 2 ); */ do_action( 'um_before_save_registration_details', $this->id, $submitted ); update_user_meta( $this->id, 'submitted', $submitted ); $this->update_profile( $submitted ); + /** - * UM hook + * Fires after save registration details to the user. * - * @type action - * @title um_after_save_registration_details - * @description Action on user registration after save details - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}, - * {"var":"$submitted","type":"array","desc":"Registration form submitted"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_after_save_registration_details', 'function_name', 10, 2 ); - * @example - * Make any custom action after save registration details to the user. + * function my_after_save_registration_details( $user_id, $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_after_save_registration_details', 'my_after_save_registration_details', 10, 3 ); */ - do_action( 'um_after_save_registration_details', $this->id, $submitted ); - + do_action( 'um_after_save_registration_details', $this->id, $submitted, $form_data ); } - /** * Set last login for new registered users */ @@ -2177,9 +2146,8 @@ if ( ! class_exists( 'um\core\User' ) ) { * add_filter( 'um_before_update_profile', 'my_custom_before_update_profile', 10, 2 ); */ $changes = apply_filters( 'um_before_update_profile', $changes, $args['ID'] ); - foreach ( $changes as $key => $value ) { - if ( $this->is_metakey_banned( $key ) ) { + if ( $this->is_metakey_banned( $key, 'submission' ) ) { continue; } @@ -2194,9 +2162,11 @@ if ( ! class_exists( 'um\core\User' ) ) { } } + $this->updating_process = false; + // update user if ( count( $args ) > 1 ) { - //if isset roles argument validate role to properly for security reasons + // If isset roles argument validate role to properly for security reasons if ( isset( $args['role'] ) ) { global $wp_roles; @@ -2208,10 +2178,8 @@ if ( ! class_exists( 'um\core\User' ) ) { wp_update_user( $args ); } - $this->updating_process = false; } - /** * User exists by meta key and value * diff --git a/includes/core/class-validation.php b/includes/core/class-validation.php index 9a5c54b2..dcef592e 100644 --- a/includes/core/class-validation.php +++ b/includes/core/class-validation.php @@ -33,7 +33,7 @@ if ( ! class_exists( 'um\core\Validation' ) ) { */ public function __construct() { add_filter( 'um_user_pre_updating_files_array', array( $this, 'validate_files' ), 10, 1 ); - add_filter( 'um_before_save_filter_submitted', array( $this, 'validate_fields_values' ), 10, 2 ); + add_filter( 'um_before_save_filter_submitted', array( $this, 'validate_fields_values' ), 10, 3 ); } @@ -56,13 +56,8 @@ if ( ! class_exists( 'um\core\Validation' ) ) { return $files; } - - - function validate_fields_values( $changes, $args ) { - $fields = array(); - if ( ! empty( $args['custom_fields'] ) ) { - $fields = unserialize( $args['custom_fields'] ); - } + public function validate_fields_values( $changes, $args, $form_data ) { + $fields = maybe_unserialize( $form_data['custom_fields'] ); foreach ( $changes as $key => $value ) { if ( ! isset( $fields[ $key ] ) ) { @@ -124,13 +119,11 @@ if ( ! class_exists( 'um\core\Validation' ) ) { $value = array_map( 'stripslashes', array_map( 'trim', $value ) ); $changes[ $key ] = array_intersect( $value, array_map( 'trim', $fields[ $key ]['options'] ) ); } - } return $changes; } - /** * Removes html from any string * diff --git a/includes/core/um-actions-account.php b/includes/core/um-actions-account.php index 44ef426d..350d44cf 100644 --- a/includes/core/um-actions-account.php +++ b/includes/core/um-actions-account.php @@ -540,6 +540,7 @@ add_action( 'um_before_account_notifications', 'um_before_account_notifications' */ function um_after_user_account_updated_permalink( $user_id, $changes ) { if ( isset( $changes['first_name'] ) || isset( $changes['last_name'] ) ) { + /** This action is documented in ultimate-member/includes/core/um-actions-register.php */ do_action( 'um_update_profile_full_name', $user_id, $changes ); } } diff --git a/includes/core/um-actions-profile.php b/includes/core/um-actions-profile.php index f2512b0b..2e5ba747 100644 --- a/includes/core/um-actions-profile.php +++ b/includes/core/um-actions-profile.php @@ -184,10 +184,11 @@ add_action( 'um_profile_content_main', 'um_profile_content_main' ); * Update user's profile * * @param array $args + * @param array $form_data */ -function um_user_edit_profile( $args ) { +function um_user_edit_profile( $args, $form_data ) { $to_update = null; - $files = array(); + $files = array(); $user_id = null; if ( isset( $args['user_id'] ) ) { @@ -225,9 +226,8 @@ function um_user_edit_profile( $args ) { */ do_action( 'um_user_before_updating_profile', $userinfo ); - if ( ! empty( $args['custom_fields'] ) ) { - $fields = apply_filters( 'um_user_edit_profile_fields', unserialize( $args['custom_fields'] ), $args ); - } + $fields = maybe_unserialize( $form_data['custom_fields'] ); + $fields = apply_filters( 'um_user_edit_profile_fields', $fields, $args, $form_data ); // loop through fields if ( ! empty( $fields ) ) { @@ -375,7 +375,6 @@ function um_user_edit_profile( $args ) { $to_update[ $description_key ] = $args['submitted'][ $description_key ]; } - // Secure selected role if ( is_admin() ) { @@ -554,26 +553,7 @@ function um_user_edit_profile( $args ) { */ do_action( 'um_user_after_updating_profile', $to_update, $user_id, $args ); - /** - * UM hook - * - * @type action - * @title um_update_profile_full_name - * @description On update user profile change full name - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}, - * {"var":"$args","type":"array","desc":"Form data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_update_profile_full_name', 'function_name', 10, 2 ); - * @example - * - */ + /** This action is documented in ultimate-member/includes/core/um-actions-register.php */ do_action( 'um_update_profile_full_name', $user_id, $to_update ); if ( ! isset( $args['is_signup'] ) ) { @@ -582,7 +562,7 @@ function um_user_edit_profile( $args ) { exit( wp_redirect( um_edit_my_profile_cancel_uri( $url ) ) ); } } -add_action( 'um_user_edit_profile', 'um_user_edit_profile', 10 ); +add_action( 'um_user_edit_profile', 'um_user_edit_profile', 10, 2 ); /** @@ -601,7 +581,7 @@ add_action( 'um_submit_form_errors_hook__profile', 'um_profile_validate_nonce', add_filter( 'um_user_pre_updating_files_array', array( UM()->validation(), 'validate_files' ), 10, 1 ); -add_filter( 'um_before_save_filter_submitted', array( UM()->validation(), 'validate_fields_values' ), 10, 2 ); +add_filter( 'um_before_save_filter_submitted', array( UM()->validation(), 'validate_fields_values' ), 10, 3 ); /** * Leave roles for User, which are not in the list of update profile (are default WP or 3rd plugins roles) @@ -1542,15 +1522,16 @@ add_action( 'um_main_profile_fields', 'um_add_profile_fields', 100 ); /** * Form processing * - * @param $args + * @param array $args + * @param array $form_data */ -function um_submit_form_profile( $args ) { +function um_submit_form_profile( $args, $form_data ) { if ( isset( UM()->form()->errors ) ) { return; } - UM()->fields()->set_mode = 'profile'; - UM()->fields()->editing = true; + UM()->fields()->set_mode = 'profile'; + UM()->fields()->editing = true; if ( ! empty( $args['submitted'] ) ) { $args['submitted'] = UM()->form()->clean_submitted_data( $args['submitted'] ); @@ -1575,9 +1556,9 @@ function um_submit_form_profile( $args ) { * } * ?> */ - do_action( 'um_user_edit_profile', $args ); + do_action( 'um_user_edit_profile', $args, $form_data ); } -add_action( 'um_submit_form_profile', 'um_submit_form_profile', 10 ); +add_action( 'um_submit_form_profile', 'um_submit_form_profile', 10, 2 ); /** diff --git a/includes/core/um-actions-register.php b/includes/core/um-actions-register.php index 9d35811e..d70f0ada 100644 --- a/includes/core/um-actions-register.php +++ b/includes/core/um-actions-register.php @@ -6,124 +6,121 @@ if ( ! defined( 'ABSPATH' ) ) { /** * Account automatically approved. * - * @param int $user_id - * @param array $args + * @param int $user_id */ -function um_post_registration_approved_hook( $user_id, $args ) { +function um_post_registration_approved_hook( $user_id ) { um_fetch_user( $user_id ); UM()->user()->approve(); } -add_action( 'um_post_registration_approved_hook', 'um_post_registration_approved_hook', 10, 2 ); +add_action( 'um_post_registration_approved_hook', 'um_post_registration_approved_hook' ); /** * Account needs email validation. * - * @param int $user_id - * @param array $args + * @param int $user_id */ -function um_post_registration_checkmail_hook( $user_id, $args ) { +function um_post_registration_checkmail_hook( $user_id ) { um_fetch_user( $user_id ); UM()->user()->email_pending(); } -add_action( 'um_post_registration_checkmail_hook', 'um_post_registration_checkmail_hook', 10, 2 ); +add_action( 'um_post_registration_checkmail_hook', 'um_post_registration_checkmail_hook' ); /** * Account needs admin review. * - * @param int $user_id - * @param array $args + * @param int $user_id */ -function um_post_registration_pending_hook( $user_id, $args ) { +function um_post_registration_pending_hook( $user_id ) { um_fetch_user( $user_id ); UM()->user()->pending(); } -add_action( 'um_post_registration_pending_hook', 'um_post_registration_pending_hook', 10, 2 ); +add_action( 'um_post_registration_pending_hook', 'um_post_registration_pending_hook' ); /** - * After insert a new user - * run at frontend and backend + * After insert a new user run at frontend and backend. * - * @param $user_id - * @param $args + * @param int|WP_Error $user_id + * @param array $args + * @param null|array $form_data It's null in case when posted from wp-admin > Add user */ -function um_after_insert_user( $user_id, $args ) { - if ( empty( $user_id ) || ( is_object( $user_id ) && is_a( $user_id, 'WP_Error' ) ) ) { +function um_after_insert_user( $user_id, $args, $form_data = null ) { + if ( empty( $user_id ) || is_wp_error( $user_id ) ) { return; } + // Set usermeta from submission. um_fetch_user( $user_id ); if ( ! empty( $args['submitted'] ) ) { - UM()->user()->set_registration_details( $args['submitted'], $args ); + // It's only frontend case. + UM()->user()->set_registration_details( $args['submitted'], $args, $form_data ); } + // Set user status. $status = um_user( 'status' ); if ( empty( $status ) ) { um_fetch_user( $user_id ); $status = um_user( 'status' ); } - - /* save user status */ UM()->user()->set_status( $status ); - /* create user uploads directory */ + // Create user uploads directory. UM()->uploader()->get_upload_user_base_dir( $user_id, true ); /** - * UM hook + * Fires after insert user to DB and there you can set any extra details. * - * @type action - * @title um_registration_set_extra_data - * @description Hook that runs after insert user to DB and there you can set any extra details - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}, - * {"var":"$args","type":"array","desc":"Form data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_registration_set_extra_data', 'function_name', 10, 2 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_registration_save_files()` Save registration files. + * 100 - `um_registration_set_profile_full_name()` Set user's full name. + * + * @since 2.0 + * @hook um_registration_set_extra_data + * + * @param {int} $user_id User ID. + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any custom action after insert user to DB. + * function my_registration_set_extra_data( $user_id, $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_registration_set_extra_data', 'my_registration_set_extra_data', 10, 3 ); */ - do_action( 'um_registration_set_extra_data', $user_id, $args ); - + do_action( 'um_registration_set_extra_data', $user_id, $args, $form_data ); /** - * UM hook + * Fires after complete UM user registration. + * Note: Native redirects handlers at 100 priority, you can add some info before redirects. * - * @type action - * @title um_registration_complete - * @description After complete UM user registration. Redirects handlers at 100 priority, you can add some info before redirects - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}, - * {"var":"$args","type":"array","desc":"Form data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_registration_complete', 'function_name', 10, 2 ); - * @example - * Callback name -> Excerpt): + * 10 - `um_send_registration_notification()` Send notifications. + * 100 - `um_check_user_status()` Redirect after registration based on user status. + * + * @since 2.0 + * @hook um_registration_complete + * + * @param {int} $user_id User ID. + * @param {array} $submitted_data $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any common action after complete UM user registration. + * function my_registration_complete( $user_id, $submitted_data, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_registration_complete', 'my_registration_complete', 10, 3 ); */ - do_action( 'um_registration_complete', $user_id, $args ); + do_action( 'um_registration_complete', $user_id, $args, $form_data ); } -add_action( 'um_user_register', 'um_after_insert_user', 1, 2 ); +add_action( 'um_user_register', 'um_after_insert_user', 1, 3 ); /** * Send notification about registration * * @param $user_id - * @param $args */ -function um_send_registration_notification( $user_id, $args ) { +function um_send_registration_notification( $user_id ) { um_fetch_user( $user_id ); $emails = um_multi_admin_email(); @@ -137,17 +134,17 @@ function um_send_registration_notification( $user_id, $args ) { } } } -add_action( 'um_registration_complete', 'um_send_registration_notification', 10, 2 ); +add_action( 'um_registration_complete', 'um_send_registration_notification' ); /** * Check user status and redirect it after registration * - * @param $user_id - * @param $args + * @param int $user_id + * @param array $args + * @param null|array $form_data */ -function um_check_user_status( $user_id, $args ) { +function um_check_user_status( $user_id, $args, $form_data = null ) { $status = um_user( 'account_status' ); - /** * UM hook * @@ -170,102 +167,102 @@ function um_check_user_status( $user_id, $args ) { */ do_action( "um_post_registration_{$status}_hook", $user_id, $args ); - if ( ! is_admin() ) { + if ( is_null( $form_data ) || is_admin() ) { + return; + } - do_action( "track_{$status}_user_registration" ); + do_action( "track_{$status}_user_registration" ); - if ( $status == 'approved' ) { - // Check if user is logged in because there can be the customized way when through 'um_registration_for_loggedin_users' hook the registration is enabled for the logged in users (e.g. Administrator). - if ( ! is_user_logged_in() ) { - // Custom way if 'um_registration_for_loggedin_users' hook after custom callbacks returns true. Then don't make auto-login because user is already logged-in. - UM()->user()->auto_login( $user_id ); - } - UM()->user()->generate_profile_slug( $user_id ); + if ( 'approved' === $status ) { + // Check if user is logged in because there can be the customized way when through 'um_registration_for_loggedin_users' hook the registration is enabled for the logged-in users (e.g. Administrator). + if ( ! is_user_logged_in() ) { + // Custom way if 'um_registration_for_loggedin_users' hook after custom callbacks returns true. Then don't make auto-login because user is already logged-in. + UM()->user()->auto_login( $user_id ); + } + UM()->user()->generate_profile_slug( $user_id ); + /** + * UM hook + * + * @type action + * @title um_registration_after_auto_login + * @description After complete UM user registration and autologin. + * @input_vars + * [{"var":"$user_id","type":"int","desc":"User ID"}] + * @change_log + * ["Since: 2.0"] + * @usage add_action( 'um_registration_after_auto_login', 'function_name', 10, 1 ); + * @example + * + */ + do_action( 'um_registration_after_auto_login', $user_id ); + + // Priority redirect + if ( isset( $args['redirect_to'] ) ) { + wp_safe_redirect( urldecode( $args['redirect_to'] ) ); + exit; + } + + um_fetch_user( $user_id ); + + if ( 'redirect_url' === um_user( 'auto_approve_act' ) && '' !== um_user( 'auto_approve_url' ) ) { + wp_safe_redirect( um_user( 'auto_approve_url' ) ); + exit; + } + + if ( 'redirect_profile' === um_user( 'auto_approve_act' ) ) { + wp_safe_redirect( um_user_profile_url() ); + exit; + } + } else { + if ( 'redirect_url' === um_user( $status . '_action' ) && '' !== um_user( $status . '_url' ) ) { /** * UM hook * - * @type action - * @title um_registration_after_auto_login - * @description After complete UM user registration and autologin. + * @type filter + * @title um_registration_pending_user_redirect + * @description Change redirect URL for pending user after registration * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}] + * [{"var":"$url","type":"string","desc":"Redirect URL"}, + * {"var":"$status","type":"string","desc":"User status"}, + * {"var":"$user_id","type":"int","desc":"User ID"}] * @change_log * ["Since: 2.0"] - * @usage add_action( 'um_registration_after_auto_login', 'function_name', 10, 1 ); + * @usage + * * @example * */ - do_action( 'um_registration_after_auto_login', $user_id ); - - // Priority redirect - if ( isset( $args['redirect_to'] ) ) { - exit( wp_safe_redirect( urldecode( $args['redirect_to'] ) ) ); - } - - um_fetch_user( $user_id ); - - if ( um_user( 'auto_approve_act' ) == 'redirect_url' && um_user( 'auto_approve_url' ) !== '' ) { - exit( wp_redirect( um_user( 'auto_approve_url' ) ) ); - } - - if ( um_user( 'auto_approve_act' ) == 'redirect_profile' ) { - exit( wp_redirect( um_user_profile_url() ) ); - } - - } else { - - if ( um_user( $status . '_action' ) == 'redirect_url' && um_user( $status . '_url' ) != '' ) { - /** - * UM hook - * - * @type filter - * @title um_registration_pending_user_redirect - * @description Change redirect URL for pending user after registration - * @input_vars - * [{"var":"$url","type":"string","desc":"Redirect URL"}, - * {"var":"$status","type":"string","desc":"User status"}, - * {"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * - */ - $redirect_url = apply_filters( 'um_registration_pending_user_redirect', um_user( $status . '_url' ), $status, um_user( 'ID' ) ); - - exit( wp_redirect( $redirect_url ) ); - } - - if ( um_user( $status . '_action' ) == 'show_message' && um_user( $status . '_message' ) != '' ) { - - $url = UM()->permalinks()->get_current_url(); - $url = add_query_arg( 'message', esc_attr( $status ), $url ); - //add only priority role to URL - $url = add_query_arg( 'um_role', esc_attr( um_user( 'role' ) ), $url ); - $url = add_query_arg( 'um_form_id', esc_attr( $args['form_id'] ), $url ); - - exit( wp_redirect( $url ) ); - } + $redirect_url = apply_filters( 'um_registration_pending_user_redirect', um_user( $status . '_url' ), $status, um_user( 'ID' ) ); + wp_safe_redirect( $redirect_url ); + exit; } - } + if ( 'show_message' === um_user( $status . '_action' ) && '' !== um_user( $status . '_message' ) ) { + $url = UM()->permalinks()->get_current_url(); + $url = add_query_arg( 'message', esc_attr( $status ), $url ); + // Add only priority role to URL. + $url = add_query_arg( 'um_role', esc_attr( um_user( 'role' ) ), $url ); + $url = add_query_arg( 'um_form_id', esc_attr( $form_data['form_id'] ), $url ); + wp_safe_redirect( $url ); + exit; + } + } } -add_action( 'um_registration_complete', 'um_check_user_status', 100, 2 ); +add_action( 'um_registration_complete', 'um_check_user_status', 100, 3 ); /** * Validate user password field on registration. @@ -284,8 +281,9 @@ add_action( 'um_submit_form_errors_hook__registration', 'um_submit_form_errors_h * Registration form submit handler. * * @param array $args + * @param array $form_data */ -function um_submit_form_register( $args ) { +function um_submit_form_register( $args, $form_data ) { if ( isset( UM()->form()->errors ) ) { return; } @@ -299,17 +297,18 @@ function um_submit_form_register( $args ) { * @hook um_add_user_frontend_submitted * * @param {array} $submitted Submitted registration data. + * @param {array} $form_data UM form data. Since 2.6.7 * * @return {array} Extended registration data. * * @example Extends registration data. - * function my_add_user_frontend_submitted( $submitted ) { + * function my_add_user_frontend_submitted( $submitted, $form_data ) { * // your code here * return $submitted; * } - * add_filter( 'um_add_user_frontend_submitted', 'my_add_user_frontend_submitted' ); + * add_filter( 'um_add_user_frontend_submitted', 'my_add_user_frontend_submitted', 10, 2 ); */ - $args = apply_filters( 'um_add_user_frontend_submitted', $args ); + $args = apply_filters( 'um_add_user_frontend_submitted', $args, $form_data ); if ( ! empty( $args['user_login'] ) ) { $user_login = $args['user_login']; @@ -411,6 +410,7 @@ function um_submit_form_register( $args ) { 'user_email' => trim( $user_email ), ); + // @todo test when ready maybe remove if ( ! empty( $args['submitted'] ) ) { $args['submitted'] = UM()->form()->clean_submitted_data( $args['submitted'] ); } @@ -446,17 +446,18 @@ function um_submit_form_register( $args ) { * * @param {string} $user_role User role. * @param {array} $args Registration data. + * @param {array} $form_data UM form data. Since 2.6.7 * * @return {string} User role. * * @example Change user role on registration process. - * function my_registration_user_role( $user_role, $args ) { + * function my_registration_user_role( $user_role, $args, $form_data ) { * // your code here * return $user_role; * } - * add_filter( 'um_registration_user_role', 'my_registration_user_role', 10, 2 ); + * add_filter( 'um_registration_user_role', 'my_registration_user_role', 10, 3 ); */ - $user_role = apply_filters( 'um_registration_user_role', $user_role, $args ); + $user_role = apply_filters( 'um_registration_user_role', $user_role, $args, $form_data ); $userdata = array( 'user_login' => $user_login, @@ -466,25 +467,32 @@ function um_submit_form_register( $args ) { ); $user_id = wp_insert_user( $userdata ); + if ( is_wp_error( $user_id ) ) { + return; + } /** * Fires after complete UM user registration. * + * Internal Ultimate Member callbacks (Priority -> Callback name -> Excerpt): + * 1 - `um_after_insert_user()` Make all Ultimate Member data set and actions after user registration|added via wp-admin. + * * @since 2.0 * @hook um_user_register * - * @param {int} $user_id User ID. - * @param {array} $args Form data. + * @param {int} $user_id User ID. + * @param {array} $args Form data. + * @param {array} $form_data UM form data. Since 2.6.7 * * @example Make any custom action after complete UM user registration. - * function my_um_user_register( $user_id, $args ) { + * function my_um_user_register( $user_id, $args, $form_data ) { * // your code here * } - * add_action( 'um_user_register', 'my_um_user_register', 10, 2 ); + * add_action( 'um_user_register', 'my_um_user_register', 10, 3 ); */ - do_action( 'um_user_register', $user_id, $args ); + do_action( 'um_user_register', $user_id, $args, $form_data ); } -add_action( 'um_submit_form_register', 'um_submit_form_register' ); +add_action( 'um_submit_form_register', 'um_submit_form_register', 10, 2 ); /** * Show the submit button @@ -615,36 +623,29 @@ function um_add_register_fields( $args ){ } add_action( 'um_main_register_fields', 'um_add_register_fields', 100 ); - /** - * Saving files to register a new user, if there are fields with files + * Saving files to register a new user, if there are fields with files. * * @param $user_id * @param $args + * @param $form_data */ -function um_registration_save_files( $user_id, $args ) { - - if ( empty( $args['custom_fields'] ) ) { +function um_registration_save_files( $user_id, $args, $form_data ) { + if ( empty( $args['submitted'] ) ) { + // It's only frontend case. return; } $files = array(); - $fields = unserialize( $args['custom_fields'] ); - - // loop through fields - if ( isset( $fields ) && is_array( $fields ) ) { - + $fields = maybe_unserialize( $form_data['custom_fields'] ); + if ( ! empty( $fields ) && is_array( $fields ) ) { foreach ( $fields as $key => $array ) { - if ( isset( $args['submitted'][ $key ] ) ) { - - if ( isset( $fields[ $key ]['type'] ) && in_array( $fields[ $key ]['type'], array( 'image', 'file' ) ) && - ( um_is_temp_file( $args['submitted'][ $key ] ) || $args['submitted'][ $key ] == 'empty_file' ) + if ( isset( $array['type'] ) && in_array( $array['type'], array( 'image', 'file' ), true ) && + ( um_is_temp_file( $args['submitted'][ $key ] ) || 'empty_file' === $args['submitted'][ $key ] ) ) { - $files[ $key ] = $args['submitted'][ $key ]; - } } } @@ -679,7 +680,7 @@ function um_registration_save_files( $user_id, $args ) { UM()->uploader()->replace_upload_dir = false; } } -add_action( 'um_registration_set_extra_data', 'um_registration_save_files', 10, 2 ); +add_action( 'um_registration_set_extra_data', 'um_registration_save_files', 10, 3 ); /** @@ -692,35 +693,29 @@ add_action( 'um_registration_set_extra_data', 'um_registration_save_files', 10, */ function um_registration_set_profile_full_name( $user_id, $args ) { /** - * UM hook + * Fires for updating user profile full name. * - * @type action - * @title um_update_profile_full_name - * @description On update user profile change full name - * @input_vars - * [{"var":"$user_id","type":"int","desc":"User ID"}, - * {"var":"$args","type":"array","desc":"Form data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_update_profile_full_name', 'function_name', 10, 2 ); - * @example - * Make any custom action when updating user profile full name. + * function my_registration_set_extra_data( $user_id, $submitted_data ) { * // your code here * } - * ?> + * add_action( 'um_update_profile_full_name', 'my_update_profile_full_name', 10, 2 ); */ do_action( 'um_update_profile_full_name', $user_id, $args ); } add_action( 'um_registration_set_extra_data', 'um_registration_set_profile_full_name', 10, 2 ); - /** * Redirect from default registration to UM registration page */ function um_form_register_redirect() { - $page_id = UM()->options()->get( UM()->options()->get_core_page_id( 'register' ) ); + $page_id = UM()->options()->get( UM()->options()->get_core_page_id( 'register' ) ); $register_post = get_post( $page_id ); if ( ! empty( $register_post ) ) { wp_safe_redirect( get_permalink( $page_id ) ); From 2ca243787edc3d5f8ca9a12dd11173ec56a44645 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Fri, 30 Jun 2023 22:10:16 +0300 Subject: [PATCH 05/11] - fix for registration form; --- includes/core/class-form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 41fe3550..6e56e432 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -450,7 +450,7 @@ if ( ! class_exists( 'um\core\Form' ) ) { unset( $custom_fields[ $cf_k ] ); } - if ( ! array_key_exists( 'type', $cf_data ) || 'password' === $cf_data['type'] ) { + if ( array_key_exists( 'type', $cf_data ) && 'password' === $cf_data['type'] ) { $ignore_keys[] = $cf_k; $ignore_keys[] = 'confirm_' . $cf_k; } From dad4c8017cb689ba1a676f060b96cac838d52f43 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Sat, 1 Jul 2023 01:52:43 +0300 Subject: [PATCH 06/11] - fix for profile form; --- includes/admin/class-admin.php | 4 +- includes/core/class-form.php | 29 +++-- includes/core/class-user.php | 12 +- includes/core/class-validation.php | 9 +- includes/core/um-actions-account.php | 2 +- includes/core/um-actions-profile.php | 179 +++++++++----------------- includes/core/um-actions-register.php | 34 +++-- 7 files changed, 114 insertions(+), 155 deletions(-) diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php index 7a848412..d9131416 100644 --- a/includes/admin/class-admin.php +++ b/includes/admin/class-admin.php @@ -760,10 +760,10 @@ if ( ! class_exists( 'um\admin\Admin' ) ) { 'sanitize' => 'bool', ), '_max_selections' => array( - 'sanitize' => 'absint', + 'sanitize' => 'empty_int', ), '_min_selections' => array( - 'sanitize' => 'absint', + 'sanitize' => 'empty_int', ), '_max_entries' => array( 'sanitize' => 'absint', diff --git a/includes/core/class-form.php b/includes/core/class-form.php index 6e56e432..a0463c2b 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -455,9 +455,26 @@ if ( ! class_exists( 'um\core\Form' ) ) { $ignore_keys[] = 'confirm_' . $cf_k; } + if ( 'profile' === $this->form_data['mode'] ) { + if ( ! empty( $cf_data['edit_forbidden'] ) ) { + $ignore_keys[] = $cf_k; + } + + if ( ! um_can_edit_field( $cf_data ) || ! um_can_view_field( $cf_data ) ) { + $ignore_keys[] = $cf_k; + } + } + if ( ! array_key_exists( 'metakey', $cf_data ) || empty( $cf_data['metakey'] ) ) { unset( $custom_fields[ $cf_k ] ); } + + if ( isset( $cf_data['required_opt'] ) ) { + $opt = $cf_data['required_opt']; + if ( UM()->options()->get( $opt[0] ) !== $opt[1] ) { + $ignore_keys[] = $cf_k; + } + } } $cf_metakeys = array_column( $custom_fields, 'metakey' ); $all_cf_metakeys = $cf_metakeys; @@ -473,6 +490,9 @@ if ( ! class_exists( 'um\core\Form' ) ) { $cf_metakeys = array_values( array_diff( $cf_metakeys, array( 'user_login' ) ) ); // Hidden for edit fields $cf_metakeys = array_values( array_diff( $cf_metakeys, UM()->fields()->get_restricted_fields_for_edit() ) ); + + $cf_metakeys[] = 'profile_photo'; + $cf_metakeys[] = 'cover_photo'; } // Add required usermeta for register. if ( 'register' === $this->form_data['mode'] ) { @@ -696,15 +716,6 @@ if ( ! class_exists( 'um\core\Form' ) ) { * add_action( 'um_submit_form_errors_hook', 'my_custom_submit_form_errors_hook', 10, 2 ); */ do_action( 'um_submit_form_errors_hook', $this->post_form, $this->form_data ); - if ( 'profile' === $this->form_data['mode'] ) { - var_dump( $this->post_form ); - var_dump( $this->form_data ); - var_dump( '------------------------------------------------------------' ); - var_dump( $all_cf_metakeys ); - var_dump( $cf_metakeys ); - var_dump( UM()->form()->errors ); - exit; - } /* Continue based on form mode - store data. */ /** * Fires for make main actions on UM login, registration or profile form submission. diff --git a/includes/core/class-user.php b/includes/core/class-user.php index 28ee975e..6bd73558 100644 --- a/includes/core/class-user.php +++ b/includes/core/class-user.php @@ -2119,11 +2119,15 @@ if ( ! class_exists( 'um\core\User' ) ) { /** * Update profile * - * @param $changes + * @param array $changes + * @param string $context */ - public function update_profile( $changes ) { - $this->updating_process = true; - $args['ID'] = $this->id; + public function update_profile( $changes, $context = '' ) { + if ( 'account' !== $context ) { + $this->updating_process = true; + } + + $args['ID'] = $this->id; /** * Filters the update profile changes data. diff --git a/includes/core/class-validation.php b/includes/core/class-validation.php index dcef592e..b835b009 100644 --- a/includes/core/class-validation.php +++ b/includes/core/class-validation.php @@ -1,8 +1,9 @@ user()->update_profile( $changes ); + UM()->user()->update_profile( $changes, 'account' ); if ( UM()->account()->is_secure_enabled() ) { update_user_meta( $user_id, 'um_account_secure_fields', array() ); diff --git a/includes/core/um-actions-profile.php b/includes/core/um-actions-profile.php index 2e5ba747..b7b63ecf 100644 --- a/includes/core/um-actions-profile.php +++ b/includes/core/um-actions-profile.php @@ -181,7 +181,7 @@ function um_profile_content_main( $args ) { add_action( 'um_profile_content_main', 'um_profile_content_main' ); /** - * Update user's profile + * Update user's profile (frontend). * * @param array $args * @param array $form_data @@ -200,29 +200,24 @@ function um_user_edit_profile( $args, $form_data ) { if ( UM()->roles()->um_current_user_can( 'edit', $user_id ) ) { UM()->user()->set( $user_id ); } else { - wp_die( __( 'You are not allowed to edit this user.', 'ultimate-member' ) ); + wp_die( esc_html__( 'You are not allowed to edit this user.', 'ultimate-member' ) ); } $userinfo = UM()->user()->profile; /** - * UM hook + * Fires before collecting data to update on profile form submit. * - * @type action - * @title um_user_before_updating_profile - * @description Some actions before profile submit - * @input_vars - * [{"var":"$userinfo","type":"array","desc":"User Data"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_user_before_updating_profile', 'function_name', 10, 1 ); - * @example - * Make any custom action before collecting data to update on profile form submit. + * function my_user_before_updating_profile( $role_key, $role_meta ) { * // your code here * } - * ?> + * add_action( 'um_user_before_updating_profile', 'my_user_before_updating_profile', 10, 2 ); */ do_action( 'um_user_before_updating_profile', $userinfo ); @@ -231,9 +226,7 @@ function um_user_edit_profile( $args, $form_data ) { // loop through fields if ( ! empty( $fields ) ) { - foreach ( $fields as $key => $array ) { - if ( ! isset( $array['type'] ) ) { continue; } @@ -243,16 +236,17 @@ function um_user_edit_profile( $args, $form_data ) { } // required option? 'required_opt' - it's field attribute predefined in the field data in code + // @todo can be unnecessary. it's used in 1 place (user account). if ( isset( $array['required_opt'] ) ) { $opt = $array['required_opt']; - if ( UM()->options()->get( $opt[0] ) != $opt[1] ) { + if ( UM()->options()->get( $opt[0] ) !== $opt[1] ) { continue; } } // fields that need to be disabled in edit mode (profile) (email, username, etc.) $arr_restricted_fields = UM()->fields()->get_restricted_fields_for_edit( $user_id ); - if ( in_array( $key, $arr_restricted_fields ) ) { + if ( in_array( $key, $arr_restricted_fields, true ) ) { continue; } @@ -261,13 +255,13 @@ function um_user_edit_profile( $args, $form_data ) { } // skip saving role here - if ( in_array( $key, array( 'role', 'role_select', 'role_radio' ) ) ) { + if ( in_array( $key, array( 'role', 'role_select', 'role_radio' ), true ) ) { continue; } //the same code in class-validation.php validate_fields_values for registration form //rating field validation - if ( $array['type'] == 'rating' && isset( $args['submitted'][ $key ] ) ) { + if ( 'rating' === $array['type'] && isset( $args['submitted'][ $key ] ) ) { if ( ! is_numeric( $args['submitted'][ $key ] ) ) { continue; } else { @@ -283,13 +277,12 @@ function um_user_edit_profile( $args, $form_data ) { } } - /** * Returns dropdown/multi-select options keys from a callback function * @since 2019-05-30 */ $has_custom_source = apply_filters( "um_has_dropdown_options_source__{$key}", false ); - if ( isset( $array['options'] ) && in_array( $array['type'], array( 'select', 'multiselect' ) ) ) { + if ( isset( $array['options'] ) && in_array( $array['type'], array( 'select', 'multiselect' ), true ) ) { $options = array(); if ( ! empty( $array['custom_dropdown_options_source'] ) && function_exists( $array['custom_dropdown_options_source'] ) && ! $has_custom_source ) { @@ -302,111 +295,89 @@ function um_user_edit_profile( $args, $form_data ) { } $array['options'] = apply_filters( "um_custom_dropdown_options__{$key}", $options ); - } - //validation of correct values from options in wp-admin $stripslashes = ''; if ( isset( $args['submitted'][ $key ] ) && is_string( $args['submitted'][ $key ] ) ) { $stripslashes = stripslashes( $args['submitted'][ $key ] ); } - if ( in_array( $array['type'], array( 'select' ) ) ) { + if ( 'select' === $array['type'] ) { if ( ! empty( $array['options'] ) && ! empty( $stripslashes ) && ! in_array( $stripslashes, array_map( 'trim', $array['options'] ) ) && ! $has_custom_source ) { continue; } //update empty user meta - if ( ! isset( $args['submitted'][ $key ] ) || $args['submitted'][ $key ] == '' ) { + if ( ! isset( $args['submitted'][ $key ] ) || '' === $args['submitted'][ $key ] ) { update_user_meta( $user_id, $key, '' ); } } //validation of correct values from options in wp-admin //the user cannot set invalid value in the hidden input at the page - if ( in_array( $array['type'], array( 'multiselect', 'checkbox', 'radio' ) ) ) { + if ( in_array( $array['type'], array( 'multiselect', 'checkbox', 'radio' ), true ) ) { if ( ! empty( $args['submitted'][ $key ] ) && ! empty( $array['options'] ) ) { $args['submitted'][ $key ] = array_map( 'stripslashes', array_map( 'trim', $args['submitted'][ $key ] ) ); $args['submitted'][ $key ] = array_intersect( $args['submitted'][ $key ], array_map( 'trim', $array['options'] ) ); } // update empty user meta - if ( ! isset( $args['submitted'][ $key ] ) || $args['submitted'][ $key ] == '' ) { + if ( ! isset( $args['submitted'][ $key ] ) || '' === $args['submitted'][ $key ] ) { update_user_meta( $user_id, $key, array() ); } } if ( isset( $args['submitted'][ $key ] ) ) { - - if ( isset( $array['type'] ) && in_array( $array['type'], array( 'image', 'file' ) ) ) { - - if ( um_is_temp_file( $args['submitted'][ $key ] ) || $args['submitted'][ $key ] == 'empty_file' ) { + if ( in_array( $array['type'], array( 'image', 'file' ), true ) ) { + if ( um_is_temp_file( $args['submitted'][ $key ] ) || 'empty_file' === $args['submitted'][ $key ] ) { $files[ $key ] = $args['submitted'][ $key ]; } elseif( um_is_file_owner( UM()->uploader()->get_upload_base_url() . $user_id . '/' . $args['submitted'][ $key ], $user_id ) ) { } else { $files[ $key ] = 'empty_file'; } - } else { - if ( $array['type'] == 'password' ) { - $to_update[ $key ] = wp_hash_password( $args['submitted'][ $key ] ); + if ( 'password' === $array['type'] ) { + $to_update[ $key ] = wp_hash_password( $args['submitted'][ $key ] ); $args['submitted'][ $key ] = sprintf( __( 'Your choosed %s', 'ultimate-member' ), $array['title'] ); } else { if ( isset( $userinfo[ $key ] ) && $args['submitted'][ $key ] != $userinfo[ $key ] ) { $to_update[ $key ] = $args['submitted'][ $key ]; - } elseif ( $args['submitted'][ $key ] != '' ) { + } elseif ( '' !== $args['submitted'][ $key ] ) { $to_update[ $key ] = $args['submitted'][ $key ]; } } - } - // use this filter after all validations has been completed and we can extends data based on key + // use this filter after all validations has been completed, and we can extend data based on key $to_update = apply_filters( 'um_change_usermeta_for_update', $to_update, $args, $fields, $key ); - } } } $description_key = UM()->profile()->get_show_bio_key( $args ); - if ( isset( $args['submitted'][ $description_key ] ) ) { - $to_update[ $description_key ] = $args['submitted'][ $description_key ]; + if ( ! isset( $to_update[ $description_key ] ) && ! empty( $form_data['show_bio'] ) ) { + if ( isset( $args['submitted'][ $description_key ] ) ) { + $to_update[ $description_key ] = $args['submitted'][ $description_key ]; + } } // Secure selected role - if ( is_admin() ) { + if ( ( isset( $fields['role'] ) && ! empty( $fields['role']['editable'] ) && um_can_view_field( $fields['role'] ) ) || + ( isset( $fields['role_select'] ) && ! empty( $fields['role_select']['editable'] ) && um_can_view_field( $fields['role_select'] ) ) || + ( isset( $fields['role_radio'] ) && ! empty( $fields['role_radio']['editable'] ) && um_can_view_field( $fields['role_radio'] ) ) ) { - if ( ! empty( $args['submitted']['role'] ) && current_user_can( 'promote_users' ) ) { + if ( ! empty( $args['submitted']['role'] ) ) { global $wp_roles; $exclude_roles = array_diff( array_keys( $wp_roles->roles ), UM()->roles()->get_editable_user_roles() ); - if ( ! in_array( $args['submitted']['role'], $exclude_roles ) ) { + if ( ! in_array( $args['submitted']['role'], $exclude_roles, true ) ) { $to_update['role'] = $args['submitted']['role']; } $args['roles_before_upgrade'] = UM()->roles()->get_all_user_roles( $user_id ); } - - } else { - - if ( ( isset( $fields['role'] ) && $fields['role']['editable'] != 0 && um_can_view_field( $fields['role'] ) ) || - ( isset( $fields['role_select'] ) && $fields['role_select']['editable'] != 0 && um_can_view_field( $fields['role_select'] ) ) || - ( isset( $fields['role_radio'] ) ) && $fields['role_radio']['editable'] != 0 && um_can_view_field( $fields['role_radio'] ) ) { - - if ( ! empty( $args['submitted']['role'] ) ) { - global $wp_roles; - $exclude_roles = array_diff( array_keys( $wp_roles->roles ), UM()->roles()->get_editable_user_roles() ); - - if ( ! in_array( $args['submitted']['role'], $exclude_roles ) ) { - $to_update['role'] = $args['submitted']['role']; - } - - $args['roles_before_upgrade'] = UM()->roles()->get_all_user_roles( $user_id ); - } - } - } /** @@ -429,7 +400,7 @@ function um_user_edit_profile( $args, $form_data ) { * } * ?> */ - do_action( 'um_user_pre_updating_profile', $to_update, $user_id ); + do_action( 'um_user_pre_updating_profile', $to_update, $user_id, $form_data ); /** * UM hook @@ -453,10 +424,9 @@ function um_user_edit_profile( $args, $form_data ) { * } * ?> */ - $to_update = apply_filters( 'um_user_pre_updating_profile_array', $to_update, $user_id ); + $to_update = apply_filters( 'um_user_pre_updating_profile_array', $to_update, $user_id, $form_data ); if ( is_array( $to_update ) ) { - if ( isset( $to_update['first_name'] ) || isset( $to_update['last_name'] ) || isset( $to_update['nickname'] ) ) { $user = get_userdata( $user_id ); if ( ! empty( $user ) && ! is_wp_error( $user ) ) { @@ -501,36 +471,17 @@ function um_user_edit_profile( $args, $form_data ) { do_action( 'um_after_user_updated', $user_id, $args, $to_update ); } - /** - * UM hook - * - * @type filter - * @title um_user_pre_updating_files_array - * @description Change submitted files before update profile - * @input_vars - * [{"var":"$files","type":"array","desc":"Profile data files"}, - * {"var":"$user_id","type":"int","desc":"User ID"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * - */ + /** This action is documented in ultimate-member/includes/core/um-actions-register.php */ $files = apply_filters( 'um_user_pre_updating_files_array', $files, $user_id ); - if ( ! empty( $files ) && is_array( $files ) ) { UM()->uploader()->replace_upload_dir = true; UM()->uploader()->move_temporary_files( $user_id, $files ); UM()->uploader()->replace_upload_dir = false; } + /** This action is documented in ultimate-member/includes/core/um-actions-register.php */ + do_action( 'um_update_profile_full_name', $user_id, $to_update ); + /** * UM hook * @@ -553,14 +504,11 @@ function um_user_edit_profile( $args, $form_data ) { */ do_action( 'um_user_after_updating_profile', $to_update, $user_id, $args ); - /** This action is documented in ultimate-member/includes/core/um-actions-register.php */ - do_action( 'um_update_profile_full_name', $user_id, $to_update ); - - if ( ! isset( $args['is_signup'] ) ) { - $url = um_user_profile_url( $user_id ); - $url = apply_filters( 'um_update_profile_redirect_after', $url, $user_id, $args ); - exit( wp_redirect( um_edit_my_profile_cancel_uri( $url ) ) ); - } + // Finally redirect to profile. + $url = um_user_profile_url( $user_id ); + $url = apply_filters( 'um_update_profile_redirect_after', $url, $user_id, $args ); + wp_safe_redirect( um_edit_my_profile_cancel_uri( $url ) ); + exit; } add_action( 'um_user_edit_profile', 'um_user_edit_profile', 10, 2 ); @@ -579,8 +527,9 @@ function um_profile_validate_nonce( $submitted_data ) { } add_action( 'um_submit_form_errors_hook__profile', 'um_profile_validate_nonce', 1 ); - -add_filter( 'um_user_pre_updating_files_array', array( UM()->validation(), 'validate_files' ), 10, 1 ); +// @todo maybe remove that because double validate +add_filter( 'um_user_pre_updating_files_array', array( UM()->validation(), 'validate_files' ) ); +// @todo maybe remove that because double validate add_filter( 'um_before_save_filter_submitted', array( UM()->validation(), 'validate_fields_values' ), 10, 3 ); /** @@ -1538,29 +1487,27 @@ function um_submit_form_profile( $args, $form_data ) { } /** - * UM hook + * Fires on successful submit profile form. * - * @type action - * @title um_user_edit_profile - * @description Run on successful submit profile form - * @input_vars - * [{"var":"$args","type":"array","desc":"Form Arguments"}] - * @change_log - * ["Since: 2.0"] - * @usage add_action( 'um_user_edit_profile', 'function_name', 10, 1 ); - * @example - * Callback name -> Excerpt): + * * 10 - `um_user_edit_profile()` Profile form main handler. + * + * @since 1.3.x + * @hook um_user_edit_profile + * + * @param {array} $post $_POST Submission array. + * @param {array} $form_data UM form data. Since 2.6.7 + * + * @example Make any custom action on successful submit profile form. + * function my_user_edit_profile( $post, $form_data ) { * // your code here * } - * ?> + * add_action( 'um_user_edit_profile', 'my_user_edit_profile', 10, 2 ); */ do_action( 'um_user_edit_profile', $args, $form_data ); } add_action( 'um_submit_form_profile', 'um_submit_form_profile', 10, 2 ); - /** * Show the submit button (highest priority) * diff --git a/includes/core/um-actions-register.php b/includes/core/um-actions-register.php index d70f0ada..b4d750c2 100644 --- a/includes/core/um-actions-register.php +++ b/includes/core/um-actions-register.php @@ -652,29 +652,25 @@ function um_registration_save_files( $user_id, $args, $form_data ) { } /** - * UM hook + * Filters files submitted by the UM registration or profile form. * - * @type filter - * @title um_user_pre_updating_files_array - * @description Change submitted files before register new user - * @input_vars - * [{"var":"$files","type":"array","desc":"Profile data files"}] - * @change_log - * ["Since: 2.0"] - * @usage - * - * @example - * Extends submitted files. + * function my_user_pre_updating_files( $files, $user_id ) { + * $files[] = 'some file'; * return $files; * } - * ?> + * add_filter( 'um_user_pre_updating_files_array', 'my_user_pre_updating_files', 10, 2 ); */ - $files = apply_filters( 'um_user_pre_updating_files_array', $files ); - - if ( ! empty( $files ) ) { + $files = apply_filters( 'um_user_pre_updating_files_array', $files, $user_id ); + if ( ! empty( $files ) && is_array( $files ) ) { UM()->uploader()->replace_upload_dir = true; UM()->uploader()->move_temporary_files( $user_id, $files ); UM()->uploader()->replace_upload_dir = false; From 13b8350e87dd8628dc3df30e62929d8bd5dde059 Mon Sep 17 00:00:00 2001 From: ashubawork Date: Sat, 1 Jul 2023 09:57:18 +0300 Subject: [PATCH 07/11] - fix file field allowed_types --- includes/core/class-fields.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/core/class-fields.php b/includes/core/class-fields.php index 511d8568..a11aed15 100644 --- a/includes/core/class-fields.php +++ b/includes/core/class-fields.php @@ -2990,9 +2990,9 @@ if ( ! class_exists( 'um\core\Fields' ) ) { $output .= ''; /* modal hidden */ if ( empty( $disabled ) ) { - if ( ! isset( $allowed_types ) ) { + if ( ! isset( $data['allowed_types'] ) ) { $allowed_types = 'pdf,txt'; - } elseif ( is_array( $allowed_types ) ) { + } elseif ( is_array( $data['allowed_types'] ) ) { $allowed_types = implode( ',', $data['allowed_types'] ); } else { $allowed_types = $data['allowed_types']; From 366da5d7f9be05dce8d01ad538fd915e4f49bff6 Mon Sep 17 00:00:00 2001 From: ashubawork Date: Sat, 1 Jul 2023 10:20:44 +0300 Subject: [PATCH 08/11] - fix semicolon --- includes/core/class-fields.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/class-fields.php b/includes/core/class-fields.php index a11aed15..c9db6c8b 100644 --- a/includes/core/class-fields.php +++ b/includes/core/class-fields.php @@ -2556,7 +2556,7 @@ if ( ! class_exists( 'um\core\Fields' ) ) { } if ( ! empty( $data['label_confirm_pass'] ) ) { - $placeholder = __( $data['label_confirm_pass'], 'ultimate-member' );; + $placeholder = __( $data['label_confirm_pass'], 'ultimate-member' ); } elseif ( ! empty( $placeholder ) && ! isset( $data['label'] ) ) { /* translators: 1: placeholder. */ $placeholder = sprintf( __( 'Confirm %s', 'ultimate-member' ), $placeholder ); From 755ff6a790619b45c74f62403998e0e64f52149e Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Sat, 1 Jul 2023 12:46:43 +0300 Subject: [PATCH 09/11] - fixed account form; --- includes/core/class-member-directory.php | 11 ++++++----- includes/core/class-user.php | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/includes/core/class-member-directory.php b/includes/core/class-member-directory.php index ec104cd9..3d8211cc 100644 --- a/includes/core/class-member-directory.php +++ b/includes/core/class-member-directory.php @@ -1458,11 +1458,12 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) { // phpcs:ignore WordPress.Security.NonceVerification -- already verified here $sorting = sanitize_text_field( $_POST['sorting'] ); $sorting_fields = maybe_serialize( $directory_data['sorting_fields'] ); - - foreach ( $sorting_fields as $field ) { - if ( isset( $field[ $sorting ] ) ) { - $custom_sort_type = ! empty( $field['type'] ) ? $meta_query->get_cast_for_type( $field['type'] ) : 'CHAR'; - $custom_sort_order = $field['order']; + if ( ! empty( $sorting_fields ) && is_array( $sorting_fields ) ) { + foreach ( $sorting_fields as $field ) { + if ( isset( $field[ $sorting ] ) ) { + $custom_sort_type = ! empty( $field['type'] ) ? $meta_query->get_cast_for_type( $field['type'] ) : 'CHAR'; + $custom_sort_order = $field['order']; + } } } } diff --git a/includes/core/class-user.php b/includes/core/class-user.php index 6bd73558..914f1814 100644 --- a/includes/core/class-user.php +++ b/includes/core/class-user.php @@ -2151,7 +2151,7 @@ if ( ! class_exists( 'um\core\User' ) ) { */ $changes = apply_filters( 'um_before_update_profile', $changes, $args['ID'] ); foreach ( $changes as $key => $value ) { - if ( $this->is_metakey_banned( $key, 'submission' ) ) { + if ( $this->is_metakey_banned( $key, ( 'account' !== $context ) ? 'submission' : '' ) ) { continue; } From d6d129d53b4c456e90cafc89d9052b6feddf59f8 Mon Sep 17 00:00:00 2001 From: Mykyta Synelnikov Date: Sat, 1 Jul 2023 13:54:57 +0300 Subject: [PATCH 10/11] - prepared for release; --- includes/core/class-form.php | 56 ------------------------------------ readme.txt | 6 ++-- ultimate-member.php | 2 +- 3 files changed, 4 insertions(+), 60 deletions(-) diff --git a/includes/core/class-form.php b/includes/core/class-form.php index a0463c2b..e5b07c09 100644 --- a/includes/core/class-form.php +++ b/includes/core/class-form.php @@ -613,62 +613,6 @@ if ( ! class_exists( 'um\core\Form' ) ) { $this->post_form['role'] = $role; } - // @todo REMOVE THAT !!! AND SEPARATE FORM DATA AND SUBMISSION DATA. MAY AFFECT TO EXTENSIONS - //$this->post_form = array_merge( $this->form_data, $this->post_form ); - - // Remove role from post_form at first if role ! empty and there aren't custom fields with role name -// if ( ! empty( $this->post_form['role'] ) ) { -// if ( ! strstr( $this->form_data['custom_fields'], 'role_' ) ) { -// unset( $this->post_form['role'] ); -// //unset( $this->post_form['submitted']['role'] ); -// } -// } - - // Secure sanitize of the submitted data -// if ( ! empty( $this->post_form ) ) { -// $this->post_form = $this->clean_submitted_data( $this->post_form ); -// } -// if ( ! empty( $this->post_form['submitted'] ) ) { -// $this->post_form['submitted'] = $this->clean_submitted_data( $this->post_form['submitted'] ); -// } - - - -// if ( isset( $this->form_data['custom_fields'] ) && strstr( $this->form_data['custom_fields'], 'role_' ) ) { // Secure selected role -// if ( ! empty( $_POST['role'] ) ) { -// $custom_field_roles = $this->custom_field_roles( $this->form_data['custom_fields'] ); -// -// if ( ! empty( $custom_field_roles ) ) { -// if ( is_array( $_POST['role'] ) ) { -// $role = current( $_POST['role'] ); -// $role = sanitize_key( $role ); -// } else { -// $role = sanitize_key( $_POST['role'] ); -// } -// -// global $wp_roles; -// $exclude_roles = array_diff( array_keys( $wp_roles->roles ), UM()->roles()->get_editable_user_roles() ); -// -// if ( ! empty( $role ) && -// ( ! in_array( $role, $custom_field_roles, true ) || in_array( $role, $exclude_roles, true ) ) ) { -// wp_die( esc_html__( 'This is not possible for security reasons.', 'ultimate-member' ) ); -// } -// -// $this->post_form['role'] = $role; -// $this->post_form['submitted']['role'] = $role; -// } else { -// unset( $this->post_form['role'] ); -// unset( $this->post_form['submitted']['role'] ); -// -// // set default role for registration form if custom field hasn't proper value -// if ( 'register' === $this->form_data['mode'] ) { -// $role = $this->assigned_role( $this->form_id ); -// $this->post_form['role'] = $role; -// } -// } -// } -// } - /** * Filters $_POST submitted data by the UM login, registration or profile form. * It's un-slashed by `wp_unslash()`, beautified and sanitized. `role` attribute is filtered by possible role. diff --git a/readme.txt b/readme.txt index c7031699..bccf43b9 100644 --- a/readme.txt +++ b/readme.txt @@ -160,15 +160,15 @@ No, you do not need to use our plugin’s login or registration pages and can us = Important: = -* To learn more about version 2.1 please see this [docs](https://docs.ultimatemember.com/article/1512-upgrade-2-1-0) -* UM2.1+ is a significant update to the Member Directories' code base from 2.0.x. Please make sure you take a full-site backup with restore point before updating the plugin +IMPORTANT: PLEASE UPDATE THE PLUGIN TO AT LEAST VERSION 2.6.7 IMMEDIATELY. VERSION 2.6.7 PATCHES SECURITY PRIVILEGE ESCALATION VULNERABILITY. -= 2.6.7: July xx, 2023 = += 2.6.7: July 1, 2023 = * Bugfixes: - Fixed: A privilege escalation vulnerability used through UM Forms. Known in the wild that vulnerability allowed strangers to create administrator-level WordPress users. Please update immediately and check all administrator-level users on your website. - Fixed: Displaying fields on Account page > Privacy > Member directory settings + - Fixed: Allowed types for the file field = 2.6.6: June 29, 2023 = diff --git a/ultimate-member.php b/ultimate-member.php index 7bf23571..032244b2 100644 --- a/ultimate-member.php +++ b/ultimate-member.php @@ -3,7 +3,7 @@ Plugin Name: Ultimate Member Plugin URI: http://ultimatemember.com/ Description: The easiest way to create powerful online communities and beautiful user profiles with WordPress -Version: 2.6.7-alpha +Version: 2.6.7 Author: Ultimate Member Author URI: http://ultimatemember.com/ Text Domain: ultimate-member From 8347dc901fec33d95488c158e4893835e47745fe Mon Sep 17 00:00:00 2001 From: ashubawork Date: Sat, 1 Jul 2023 14:09:32 +0300 Subject: [PATCH 11/11] - fix disabled_weekdays --- includes/core/class-fields.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/includes/core/class-fields.php b/includes/core/class-fields.php index c9db6c8b..687e940a 100644 --- a/includes/core/class-fields.php +++ b/includes/core/class-fields.php @@ -2637,7 +2637,12 @@ if ( ! class_exists( 'um\core\Fields' ) ) { $field_name = $key . $form_suffix; - $output .= ' + $disabled_weekdays = ''; + if ( isset( $data['disabled_weekdays'] ) ) { + $disabled_weekdays = '[' . implode( ',', $data['disabled_weekdays'] ) . ']'; + } + + $output .= ' ';