diff --git a/includes/admin/templates/directory/search.php b/includes/admin/templates/directory/search.php
index 9cb32539..dce4221d 100644
--- a/includes/admin/templates/directory/search.php
+++ b/includes/admin/templates/directory/search.php
@@ -10,8 +10,10 @@ $_um_roles_search_value = empty( $_um_roles_search_value ) ? array() : $_um_role
$_um_roles_filter_value = get_post_meta( $post_id, '_um_roles_can_filter', true );
$_um_roles_filter_value = empty( $_um_roles_filter_value ) ? array() : $_um_roles_filter_value;
-$_um_search_fields = get_post_meta( $post_id, '_um_search_fields', true );
-$_um_search_filters = get_post_meta( $post_id, '_um_search_filters', true ); ?>
+$_um_search_exclude_fields = get_post_meta( $post_id, '_um_search_exclude_fields', true );
+$_um_search_include_fields = get_post_meta( $post_id, '_um_search_include_fields', true );
+$_um_search_fields = get_post_meta( $post_id, '_um_search_fields', true );
+$_um_search_filters = get_post_meta( $post_id, '_um_search_filters', true ); ?>
@@ -38,6 +40,30 @@ $_um_search_filters = get_post_meta( $post_id, '_um_search_filters', true ); ?>
'columns' => 3,
'conditional' => array( '_um_search', '=', 1 ),
),
+ array(
+ 'id' => '_um_search_exclude_fields',
+ 'type' => 'multi_selects',
+ 'label' => __( 'Exclude fields from search', 'ultimate-member' ),
+ 'value' => $_um_search_exclude_fields,
+ 'conditional' => array( '_um_search', '=', 1 ),
+ 'options' => UM()->member_directory()->searching_fields,
+ 'add_text' => __( 'Add New', 'ultimate-member' ),
+ 'show_default_number' => 0,
+ 'sorting' => true,
+ 'tooltip' => __( 'Choose fields to exclude them from search. This option will delete all included fields.', 'ultimate-member' ),
+ ),
+ array(
+ 'id' => '_um_search_include_fields',
+ 'type' => 'multi_selects',
+ 'label' => __( 'Fields to search by', 'ultimate-member' ),
+ 'value' => $_um_search_include_fields,
+ 'conditional' => array( '_um_search', '=', 1 ),
+ 'options' => UM()->member_directory()->searching_fields,
+ 'add_text' => __( 'Add New', 'ultimate-member' ),
+ 'show_default_number' => 0,
+ 'sorting' => true,
+ 'tooltip' => __( 'Choose fields to only include them in the search. This option will delete all excluded fields.', 'ultimate-member' ),
+ ),
array(
'id' => '_um_filters',
'type' => 'checkbox',
diff --git a/includes/ajax/class-secure.php b/includes/ajax/class-secure.php
index c57235eb..f69fc682 100644
--- a/includes/ajax/class-secure.php
+++ b/includes/ajax/class-secure.php
@@ -284,7 +284,7 @@ class Secure {
if ( $suspicious_accounts_count > 0 ) {
$lock_register_forms_url = admin_url( 'admin.php?page=um_options&tab=advanced§ion=secure&um_secure_lock_register_forms=1&_wpnonce=' . wp_create_nonce( 'um_secure_lock_register_forms' ) );
$content .= $br . esc_html__( '1. Please temporarily lock all your active Register forms.', 'ultimate-member' );
- $content .= '
' . esc_html__( 'Click here to lock them now.', 'ultimate-member' ) . ' ';
+ $content .= '
' . esc_html__( 'Click here to lock them now.', 'ultimate-member' ) . ' ';
$content .= ' ' . esc_html__( 'You can unblock the Register forms later. Just go to Ultimate Member > Settings > Advanced > Security and uncheck the option "Lock All Register Forms".', 'ultimate-member' );
$content .= $br . $br;
$suspicious_accounts_url = admin_url( 'users.php?um_status=inactive' );
@@ -300,24 +300,24 @@ class Secure {
}
$content .= esc_html__( '2. Review all suspicious accounts and delete them completely.', 'ultimate-member' );
- $content .= '
' . esc_html__( 'Click here to review accounts.', 'ultimate-member' ) . ' ';
+ $content .= '
' . esc_html__( 'Click here to review accounts.', 'ultimate-member' ) . ' ';
$content .= $br . $br;
$nonce = wp_create_nonce( 'um-secure-expire-session-nonce' );
$destroy_all_sessions_url = admin_url( '?um_secure_expire_all_sessions=1&_wpnonce=' . esc_attr( $nonce ) . '&except_me=1' );
$content .= esc_html__( '3. If accounts are suspicious to you, please destroy all user sessions to logout active users on your site.', 'ultimate-member' );
- $content .= '
' . esc_html__( 'Click here to Destroy Sessions now', 'ultimate-member' ) . ' ';
+ $content .= '
' . esc_html__( 'Click here to Destroy Sessions now', 'ultimate-member' ) . ' ';
$content .= $br . $br;
$content .= esc_html__( '4. Run a complete scan on your site using third-party Security plugins such as', 'ultimate-member' );
- $content .= '
' . esc_html__( 'WPScan/Jetpack Protect or WordFence Security', 'ultimate-member' ) . ' .';
+ $content .= '
' . esc_html__( 'WPScan/Jetpack Protect or WordFence Security', 'ultimate-member' ) . ' .';
$content .= $br . $br;
$nonce = wp_create_nonce( 'um-secure-enable-reset-pass-nonce' );
$reset_pass_sessions_url = admin_url( '?um_secure_enable_reset_password=1&_wpnonce=' . esc_attr( $nonce ) . '&except_me=1' );
$content .= esc_html__( '5. Force users to Reset their Passwords.', 'ultimate-member' );
- $content .= '
' . esc_html__( 'Click here to enable this option', 'ultimate-member' ) . ' .';
+ $content .= '
' . esc_html__( 'Click here to enable this option', 'ultimate-member' ) . ' .';
$content .= ' ' . esc_html__( 'When this option is enabled, users will be asked to reset their passwords(one-time) on the next login in the UM Login form.', 'ultimate-member' );
$content .= $br . $br;
diff --git a/includes/blocks/um-member-directories/build/index.asset.php b/includes/blocks/um-member-directories/build/index.asset.php
index 4c516119..83e8be83 100644
--- a/includes/blocks/um-member-directories/build/index.asset.php
+++ b/includes/blocks/um-member-directories/build/index.asset.php
@@ -1 +1 @@
- array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-server-side-render'), 'version' => 'a7aefdd7c81b99d7d5e3');
+ array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-server-side-render'), 'version' => '5b1a8ec016836a5c26cd');
diff --git a/includes/blocks/um-member-directories/build/index.js b/includes/blocks/um-member-directories/build/index.js
index 4a028c8b..7492c2d3 100644
--- a/includes/blocks/um-member-directories/build/index.js
+++ b/includes/blocks/um-member-directories/build/index.js
@@ -1 +1 @@
-!function(){"use strict";var e={n:function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,{a:r}),r},d:function(t,r){for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}},t=window.wp.element,r=window.wp.data,n=window.wp.components,i=window.wp.blockEditor,o=window.wp.serverSideRender,l=e.n(o);(0,window.wp.blocks.registerBlockType)("um-block/um-member-directories",{edit:function(e){let{member_id:o,setAttributes:u}=e.attributes;const c=(0,i.useBlockProps)(),a=(0,r.useSelect)((e=>e("core").getEntityRecords("postType","um_directory",{per_page:-1,_fields:["id","title"]})));if(!a)return(0,t.createElement)("p",null,(0,t.createElement)(n.Spinner,null),wp.i18n.__("Loading...","ultimate-member"));if(0===a.length)return"No posts found.";let d=[{id:"",title:""}].concat(a).map((e=>({label:e.title.rendered,value:e.id})));return(0,t.createElement)("div",{...c},(0,t.createElement)(l(),{block:"um-block/um-member-directories",attributes:e.attributes}),(0,t.createElement)(i.InspectorControls,null,(0,t.createElement)(n.PanelBody,{title:wp.i18n.__("Select Directories","ultimate-member")},(0,t.createElement)(n.SelectControl,{label:wp.i18n.__("Select Directories","ultimate-member"),className:"um_select_directory",value:o,options:d,style:{height:"35px",lineHeight:"20px",padding:"0 7px"},onChange:t=>{e.setAttributes({member_id:t})}}))))},save:function(e){return null}}),jQuery(window).on("load",(function(e){new MutationObserver((function(e){e.forEach((function(e){jQuery(e.addedNodes).find(".um.um-directory").each((function(){var e=jQuery(this);um_ajax_get_members(e),um_slider_filter_init(e),um_datepicker_filter_init(e),um_timepicker_filter_init(e)}))}))})).observe(document,{attributes:!1,childList:!0,characterData:!1,subtree:!0})}))}();
\ No newline at end of file
+(()=>{"use strict";var e={n:t=>{var r=t&&t.__esModule?()=>t.default:()=>t;return e.d(r,{a:r}),r},d:(t,r)=>{for(var i in r)e.o(r,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:r[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.React,r=window.wp.data,i=window.wp.components,n=window.wp.blockEditor,o=window.wp.serverSideRender;var l=e.n(o);(0,window.wp.blocks.registerBlockType)("um-block/um-member-directories",{edit:function(e){let{member_id:o,setAttributes:a}=e.attributes;const c=(0,n.useBlockProps)(),u=(0,r.useSelect)((e=>e("core").getEntityRecords("postType","um_directory",{per_page:-1,_fields:["id","title"]})));if(!u)return(0,t.createElement)("p",null,(0,t.createElement)(i.Spinner,null),wp.i18n.__("Loading...","ultimate-member"));if(0===u.length)return"No posts found.";let d=[{id:"",title:""}].concat(u).map((e=>({label:e.title.rendered,value:e.id})));return(0,t.createElement)("div",{...c},(0,t.createElement)(l(),{block:"um-block/um-member-directories",attributes:e.attributes}),(0,t.createElement)(n.InspectorControls,null,(0,t.createElement)(i.PanelBody,{title:wp.i18n.__("Select Directories","ultimate-member")},(0,t.createElement)(i.SelectControl,{label:wp.i18n.__("Select Directories","ultimate-member"),className:"um_select_directory",value:o,options:d,style:{height:"35px",lineHeight:"20px",padding:"0 7px"},onChange:t=>{e.setAttributes({member_id:t})}}))))},save:function(e){return null}}),jQuery(window).on("load",(function(e){new MutationObserver((function(e){e.forEach((function(e){jQuery(e.addedNodes).find(".um.um-directory").each((function(){var e=jQuery(this);um_ajax_get_members(e),um_slider_filter_init(e),um_datepicker_filter_init(e),um_timepicker_filter_init(e)})),jQuery(e.addedNodes).find(".um-member").each((function(){var e=jQuery(this).parent();UM_Member_Grid(e)}))}))})).observe(document,{attributes:!1,childList:!0,characterData:!1,subtree:!0})}))})();
\ No newline at end of file
diff --git a/includes/blocks/um-member-directories/src/index.js b/includes/blocks/um-member-directories/src/index.js
index 18bbcc63..41e606b3 100644
--- a/includes/blocks/um-member-directories/src/index.js
+++ b/includes/blocks/um-member-directories/src/index.js
@@ -101,6 +101,10 @@ jQuery(window).on( 'load', function($) {
um_datepicker_filter_init( directory );
um_timepicker_filter_init( directory );
});
+ jQuery(mutation.addedNodes).find('.um-member').each(function() {
+ var directory = jQuery(this).parent();
+ UM_Member_Grid(directory);
+ });
});
});
diff --git a/includes/class-config.php b/includes/class-config.php
index a7b64e2f..3d3039a5 100644
--- a/includes/class-config.php
+++ b/includes/class-config.php
@@ -204,29 +204,7 @@ if ( ! class_exists( 'um\Config' ) ) {
'_um_secondary_color',
);
- /**
- * UM hook
- *
- * @type filter
- * @title um_core_form_meta_all
- * @description Extend UM forms meta keys
- * @input_vars
- * [{"var":"$meta","type":"array","desc":"UM forms meta"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- *
- */
- $this->core_form_meta_all = apply_filters( 'um_core_form_meta_all', array(
+ $this->core_form_meta_all = array(
/*Profile Form*/
'_um_profile_show_name' => 1,
'_um_profile_show_social_links' => 0,
@@ -279,62 +257,49 @@ if ( ! class_exists( 'um\Config' ) ) {
'_um_directory_template' => 'members',
'_um_directory_header' => __( '{total_users} Members', 'ultimate-member' ),
'_um_directory_header_single' => __( '{total_users} Member', 'ultimate-member' ),
- ) );
+ );
+ /**
+ * Filters the list of Ultimate Member forms meta.
+ *
+ * @param {array} $form_meta UM Forms meta.
+ *
+ * @return {array} Forms meta.
+ *
+ * @since 1.3.x
+ * @hook um_core_form_meta_all
+ *
+ * @example
Add custom admin notice after {custom_update_key} action.
+ * function my_um_core_form_meta_all( $form_meta ) {
+ * // your code here
+ * $meta['my_meta_key'] = 'my_meta_value';
+ * return $meta;
+ * }
+ * add_filter( 'um_core_form_meta_all', 'my_um_core_form_meta_all' );
+ */
+ $this->core_form_meta_all = apply_filters( 'um_core_form_meta_all', $this->core_form_meta_all );
$this->core_form_meta['register'] = array(
- '_um_custom_fields' => 'a:6:{s:10:"user_login";a:15:{s:5:"title";s:8:"Username";s:7:"metakey";s:10:"user_login";s:4:"type";s:4:"text";s:5:"label";s:8:"Username";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:0;s:8:"validate";s:15:"unique_username";s:9:"min_chars";i:3;s:9:"max_chars";i:24;s:8:"position";s:1:"1";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:10:"user_email";a:13:{s:5:"title";s:14:"Email Address";s:7:"metakey";s:10:"user_email";s:4:"type";s:4:"text";s:5:"label";s:14:"E-mail Address";s:8:"required";i:0;s:6:"public";i:1;s:8:"editable";b:1;s:8:"validate";s:12:"unique_email";s:8:"position";s:1:"4";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:13:"user_password";a:16:{s:5:"title";s:8:"Password";s:7:"metakey";s:13:"user_password";s:4:"type";s:8:"password";s:5:"label";s:8:"Password";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:1;s:9:"min_chars";i:8;s:9:"max_chars";i:30;s:15:"force_good_pass";i:1;s:18:"force_confirm_pass";i:1;s:8:"position";s:1:"5";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:10:"first_name";a:12:{s:5:"title";s:10:"First Name";s:7:"metakey";s:10:"first_name";s:4:"type";s:4:"text";s:5:"label";s:10:"First Name";s:8:"required";i:0;s:6:"public";i:1;s:8:"editable";b:1;s:8:"position";s:1:"2";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:9:"last_name";a:12:{s:5:"title";s:9:"Last Name";s:7:"metakey";s:9:"last_name";s:4:"type";s:4:"text";s:5:"label";s:9:"Last Name";s:8:"required";i:0;s:6:"public";i:1;s:8:"editable";b:1;s:8:"position";s:1:"3";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:9:"_um_row_1";a:4:{s:4:"type";s:3:"row";s:2:"id";s:9:"_um_row_1";s:8:"sub_rows";s:1:"1";s:4:"cols";s:1:"1";}}',
- '_um_mode' => 'register',
- '_um_core' => 'register',
+ '_um_custom_fields' => 'a:6:{s:10:"user_login";a:15:{s:5:"title";s:8:"Username";s:7:"metakey";s:10:"user_login";s:4:"type";s:4:"text";s:5:"label";s:8:"Username";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:0;s:8:"validate";s:15:"unique_username";s:9:"min_chars";i:3;s:9:"max_chars";i:24;s:8:"position";s:1:"1";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:10:"user_email";a:13:{s:5:"title";s:14:"Email Address";s:7:"metakey";s:10:"user_email";s:4:"type";s:4:"text";s:5:"label";s:14:"E-mail Address";s:8:"required";i:0;s:6:"public";i:1;s:8:"editable";b:1;s:8:"validate";s:12:"unique_email";s:8:"position";s:1:"4";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:13:"user_password";a:16:{s:5:"title";s:8:"Password";s:7:"metakey";s:13:"user_password";s:4:"type";s:8:"password";s:5:"label";s:8:"Password";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:1;s:9:"min_chars";i:8;s:9:"max_chars";i:30;s:15:"force_good_pass";i:1;s:18:"force_confirm_pass";i:1;s:8:"position";s:1:"5";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:10:"first_name";a:12:{s:5:"title";s:10:"First Name";s:7:"metakey";s:10:"first_name";s:4:"type";s:4:"text";s:5:"label";s:10:"First Name";s:8:"required";i:0;s:6:"public";i:1;s:8:"editable";b:1;s:8:"position";s:1:"2";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:9:"last_name";a:12:{s:5:"title";s:9:"Last Name";s:7:"metakey";s:9:"last_name";s:4:"type";s:4:"text";s:5:"label";s:9:"Last Name";s:8:"required";i:0;s:6:"public";i:1;s:8:"editable";b:1;s:8:"position";s:1:"3";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:9:"_um_row_1";a:4:{s:4:"type";s:3:"row";s:2:"id";s:9:"_um_row_1";s:8:"sub_rows";s:1:"1";s:4:"cols";s:1:"1";}}',
+ '_um_mode' => 'register',
+ '_um_core' => 'register',
'_um_register_use_custom_settings' => 0,
);
$this->core_form_meta['login'] = array(
- '_um_custom_fields' => 'a:3:{s:8:"username";a:13:{s:5:"title";s:18:"Username or Email";s:7:"metakey";s:8:"username";s:4:"type";s:4:"text";s:5:"label";s:18:"Username or E-mail";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:0;s:8:"validate";s:24:"unique_username_or_email";s:8:"position";s:1:"1";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:13:"user_password";a:16:{s:5:"title";s:8:"Password";s:7:"metakey";s:13:"user_password";s:4:"type";s:8:"password";s:5:"label";s:8:"Password";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:1;s:9:"min_chars";i:8;s:9:"max_chars";i:30;s:15:"force_good_pass";i:1;s:18:"force_confirm_pass";i:1;s:8:"position";s:1:"2";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:9:"_um_row_1";a:4:{s:4:"type";s:3:"row";s:2:"id";s:9:"_um_row_1";s:8:"sub_rows";s:1:"1";s:4:"cols";s:1:"1";}}',
- '_um_mode' => 'login',
- '_um_core' => 'login',
+ '_um_custom_fields' => 'a:3:{s:8:"username";a:13:{s:5:"title";s:18:"Username or Email";s:7:"metakey";s:8:"username";s:4:"type";s:4:"text";s:5:"label";s:18:"Username or E-mail";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:0;s:8:"validate";s:24:"unique_username_or_email";s:8:"position";s:1:"1";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:13:"user_password";a:16:{s:5:"title";s:8:"Password";s:7:"metakey";s:13:"user_password";s:4:"type";s:8:"password";s:5:"label";s:8:"Password";s:8:"required";i:1;s:6:"public";i:1;s:8:"editable";b:1;s:9:"min_chars";i:8;s:9:"max_chars";i:30;s:15:"force_good_pass";i:1;s:18:"force_confirm_pass";i:1;s:8:"position";s:1:"2";s:6:"in_row";s:9:"_um_row_1";s:10:"in_sub_row";s:1:"0";s:9:"in_column";s:1:"1";s:8:"in_group";s:0:"";}s:9:"_um_row_1";a:4:{s:4:"type";s:3:"row";s:2:"id";s:9:"_um_row_1";s:8:"sub_rows";s:1:"1";s:4:"cols";s:1:"1";}}',
+ '_um_mode' => 'login',
+ '_um_core' => 'login',
'_um_login_use_custom_settings' => 0,
);
$this->core_form_meta['profile'] = array(
- '_um_custom_fields' => 'a:1:{s:9:"_um_row_1";a:4:{s:4:"type";s:3:"row";s:2:"id";s:9:"_um_row_1";s:8:"sub_rows";s:1:"1";s:4:"cols";s:1:"1";}}',
- '_um_mode' => 'profile',
- '_um_core' => 'profile',
+ '_um_custom_fields' => 'a:1:{s:9:"_um_row_1";a:4:{s:4:"type";s:3:"row";s:2:"id";s:9:"_um_row_1";s:8:"sub_rows";s:1:"1";s:4:"cols";s:1:"1";}}',
+ '_um_mode' => 'profile',
+ '_um_core' => 'profile',
'_um_profile_use_custom_settings' => 0,
);
-
- /**
- * UM hook
- *
- * @type filter
- * @title um_email_notifications
- * @description Extend UM email notifications
- * @input_vars
- * [{"var":"$emails","type":"array","desc":"UM email notifications"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- * 'my_email',
- * 'title' => __( 'my_email_title','ultimate-member' ),
- * 'subject' => 'my_email_subject',
- * 'body' => 'my_email_body',
- * 'description' => 'my_email_description',
- * 'recipient' => 'user', // set 'admin' for make administrator as recipient
- * 'default_active' => true // can be false for make disabled by default
- * );
- *
- * return $emails;
- * }
- * ?>
- */
- $this->email_notifications = apply_filters( 'um_email_notifications', array(
+ $this->email_notifications = array(
'welcome_email' => array(
'key' => 'welcome_email',
'title' => __( 'Account Welcome Email','ultimate-member' ),
@@ -514,85 +479,116 @@ if ( ! class_exists( 'um\Config' ) ) {
'recipient' => 'admin',
'default_active' => true,
),
- ) );
+ );
+ /**
+ * Filters the list of Ultimate Member email notifications.
+ *
+ * @param {array} $email_notifications Email notifications.
+ *
+ * @return {array} Email notifications.
+ *
+ * @since 2.0.0
+ * @hook um_email_notifications
+ *
+ * @example
Add custom admin notice after {custom_update_key} action.
+ * function my_um_email_notifications( $notifications ) {
+ * // your code here
+ * $emails['my_email'] = array(
+ * 'key' => 'my_email',
+ * 'title' => __( 'my_email_title','ultimate-member' ),
+ * 'subject' => 'my_email_subject',
+ * 'body' => 'my_email_body',
+ * 'description' => 'my_email_description',
+ * 'recipient' => 'user', // set 'admin' for make administrator as recipient
+ * 'default_active' => true // can be false for make disabled by default
+ * );
+ *
+ * return $emails;
+ * }
+ * add_filter( 'um_email_notifications', 'my_um_email_notifications' );
+ */
+ $this->email_notifications = apply_filters( 'um_email_notifications', $this->email_notifications );
- //settings defaults
+ // Settings defaults.
$this->settings_defaults = array(
- 'restricted_access_post_metabox' => array( 'post' => 1, 'page' => 1 ),
- 'disable_restriction_pre_queries' => 0,
- 'uninstall_on_delete' => 0,
+ 'restricted_access_post_metabox' => array(
+ 'post' => 1,
+ 'page' => 1,
+ ),
+ 'disable_restriction_pre_queries' => false,
+ 'uninstall_on_delete' => false,
'permalink_base' => 'user_login',
'permalink_base_custom_meta' => '',
'display_name' => 'full_name',
'display_name_field' => '',
- 'author_redirect' => 1,
+ 'author_redirect' => true,
'members_page' => true,
- 'use_gravatars' => 0,
+ 'use_gravatars' => false,
'use_um_gravatar_default_builtin_image' => 'default',
- 'use_um_gravatar_default_image' => 0,
+ 'use_um_gravatar_default_image' => false,
'toggle_password' => false,
- 'require_strongpass' => 0,
+ 'require_strongpass' => false,
'password_min_chars' => 8,
'password_max_chars' => 30,
- 'account_tab_password' => 1,
- 'account_tab_privacy' => 1,
- 'account_tab_notifications' => 1,
- 'account_tab_delete' => 1,
+ 'account_tab_password' => true,
+ 'account_tab_privacy' => true,
+ 'account_tab_notifications' => true,
+ 'account_tab_delete' => true,
'delete_account_text' => __( 'Are you sure you want to delete your account? This will erase all of your account data from the site. To delete your account enter your password below.', 'ultimate-member' ),
'delete_account_no_pass_required_text' => __( 'Are you sure you want to delete your account? This will erase all of your account data from the site. To delete your account, click on the button below.', 'ultimate-member' ),
- 'account_name' => 1,
- 'account_name_disable' => 0,
- 'account_name_require' => 1,
- 'account_email' => 1,
- 'account_general_password' => 0,
- 'account_hide_in_directory' => 1,
+ 'account_name' => true,
+ 'account_name_disable' => false,
+ 'account_name_require' => true,
+ 'account_email' => true,
+ 'account_general_password' => false,
+ 'account_hide_in_directory' => true,
'account_hide_in_directory_default' => 'No',
'photo_thumb_sizes' => array( 40, 80, 190 ),
'cover_thumb_sizes' => array( 300, 600 ),
'accessible' => 0,
'access_redirect' => '',
'access_exclude_uris' => array(),
- 'home_page_accessible' => 1,
- 'category_page_accessible' => 1,
- 'restricted_post_title_replace' => 1,
+ 'home_page_accessible' => true,
+ 'category_page_accessible' => true,
+ 'restricted_post_title_replace' => true,
'restricted_access_post_title' => __( 'Restricted content', 'ultimate-member' ),
'restricted_access_message' => '',
- 'restricted_blocks' => 0,
- 'enable_blocks' => 0,
+ 'restricted_blocks' => false,
+ 'enable_blocks' => false,
'restricted_block_message' => '',
- 'enable_reset_password_limit' => 1,
+ 'enable_reset_password_limit' => true,
'reset_password_limit_number' => 3,
'change_password_request_limit' => false,
'blocked_emails' => '',
'blocked_words' => 'admin' . "\r\n" . 'administrator' . "\r\n" . 'webmaster' . "\r\n" . 'support' . "\r\n" . 'staff',
'allowed_choice_callbacks' => '',
- 'allow_url_redirect_confirm' => 1,
+ 'allow_url_redirect_confirm' => true,
'default_avatar' => '',
'default_cover' => '',
- 'disable_profile_photo_upload' => 0,
- 'profile_show_metaicon' => 0,
- 'profile_menu' => 1,
+ 'disable_profile_photo_upload' => false,
+ 'profile_show_metaicon' => false,
+ 'profile_menu' => true,
'profile_menu_default_tab' => 'main',
- 'profile_menu_icons' => 1,
- 'form_asterisk' => 0,
+ 'profile_menu_icons' => true,
+ 'form_asterisk' => false,
'profile_title' => '{display_name} | {site_name}',
'profile_desc' => '{display_name} is on {site_name}. Join {site_name} to view {display_name}\'s profile',
'admin_email' => get_bloginfo( 'admin_email' ),
'mail_from' => get_bloginfo( 'name' ),
'mail_from_addr' => get_bloginfo( 'admin_email' ),
- 'email_html' => 1,
- 'image_orientation_by_exif' => 0,
+ 'email_html' => true,
+ 'image_orientation_by_exif' => false,
'image_compression' => 60,
'image_max_width' => 1000,
'cover_min_width' => 1000,
'profile_photo_max_size' => 999999999,
'cover_photo_max_size' => 999999999,
'custom_roles_increment' => 1,
- 'um_profile_object_cache_stop' => 0,
+ 'um_profile_object_cache_stop' => false,
'rest_api_version' => '2.0',
- 'member_directory_own_table' => 0,
+ 'member_directory_own_table' => false,
'profile_show_bio' => false,
- 'profile_show_html_bio' => 0,
+ 'profile_show_html_bio' => false,
'profile_bio_maxchars' => 180,
'profile_noindex' => 0,
'activation_link_expiry_time' => '',
@@ -603,7 +599,7 @@ if ( ! class_exists( 'um\Config' ) ) {
'secure_notify_admins_banned_accounts' => false,
'secure_notify_admins_banned_accounts__interval' => 'instant',
'secure_allowed_redirect_hosts' => '',
- 'delete_comments' => 0,
+ 'delete_comments' => false,
);
add_filter( 'um_get_tabs_from_config', '__return_true' );
@@ -620,26 +616,26 @@ if ( ! class_exists( 'um\Config' ) ) {
if ( ! isset( $tab['default_privacy'] ) ) {
$this->settings_defaults[ 'profile_tab_' . $id . '_privacy' ] = 0;
- $this->settings_defaults[ 'profile_tab_' . $id . '_roles' ] = '';
+ $this->settings_defaults[ 'profile_tab_' . $id . '_roles' ] = '';
}
}
foreach ( $this->email_notifications as $key => $notification ) {
- $this->settings_defaults[ $key . '_on' ] = ! empty( $notification['default_active'] );
+ $this->settings_defaults[ $key . '_on' ] = ! empty( $notification['default_active'] );
$this->settings_defaults[ $key . '_sub' ] = $notification['subject'];
- $this->settings_defaults[ $key ] = $notification['body'];
+ $this->settings_defaults[ $key ] = $notification['body'];
}
foreach ( $this->core_pages as $page_s => $page ) {
- $page_id = UM()->options()->get_core_page_id( $page_s );
+ $page_id = UM()->options()->get_predefined_page_option_key( $page_s );
+
$this->settings_defaults[ $page_id ] = '';
}
- foreach( $this->core_form_meta_all as $key => $value ) {
+ foreach ( $this->core_form_meta_all as $key => $value ) {
$this->settings_defaults[ str_replace( '_um_', '', $key ) ] = $value;
}
-
/**
* UM hook
*
@@ -665,126 +661,86 @@ if ( ! class_exists( 'um\Config' ) ) {
$this->permalinks = $this->get_core_pages();
-
-
$this->default_roles_metadata = array(
- /*
- * All caps map
- *
- * '_um_can_access_wpadmin' => 1,
- '_um_can_not_see_adminbar' => 0,
- '_um_can_edit_everyone' => 1,
- '_um_can_edit_roles' => '',
- '_um_can_delete_everyone' => 1,
- '_um_can_delete_roles' => '',
- '_um_after_delete' => '',
- '_um_delete_redirect_url' => '',
- '_um_can_edit_profile' => 1,
- '_um_can_delete_profile' => 1,
- '_um_default_homepage' => 1,
- '_um_redirect_homepage' => '',
- '_um_after_login' => 'redirect_admin',
- '_um_login_redirect_url' => '',
- '_um_after_logout' => 'redirect_home',
- '_um_logout_redirect_url' => '',
- '_um_can_view_all' => 1,
- '_um_can_view_roles' => '',
- '_um_can_make_private_profile' => 1,
- '_um_can_access_private_profile' => 1,
- '_um_status' => 'approved',
- '_um_auto_approve_act' => 'redirect_profile',
- '_um_auto_approve_url' => '',
- '_um_login_email_activate' => '',
- '_um_checkmail_action' => '',
- '_um_checkmail_message' => '',
- '_um_checkmail_url' => '',
- '_um_url_email_activate' => '',
- '_um_pending_action' => '',
- '_um_pending_message' => '',
- '_um_pending_url' => '',
- *
- * */
-
-
- 'subscriber' => array(
- '_um_can_access_wpadmin' => 0,
- '_um_can_not_see_adminbar' => 1,
- '_um_can_edit_everyone' => 0,
- '_um_can_delete_everyone' => 0,
- '_um_can_edit_profile' => 1,
- '_um_can_delete_profile' => 1,
- '_um_after_login' => 'redirect_profile',
- '_um_after_logout' => 'redirect_home',
- '_um_default_homepage' => 1,
- '_um_can_view_all' => 1,
- '_um_can_make_private_profile' => 0,
- '_um_can_access_private_profile' => 0,
- '_um_status' => 'approved',
- '_um_auto_approve_act' => 'redirect_profile',
+ 'subscriber' => array(
+ '_um_can_access_wpadmin' => 0,
+ '_um_can_not_see_adminbar' => 1,
+ '_um_can_edit_everyone' => 0,
+ '_um_can_delete_everyone' => 0,
+ '_um_can_edit_profile' => 1,
+ '_um_can_delete_profile' => 1,
+ '_um_after_login' => 'redirect_profile',
+ '_um_after_logout' => 'redirect_home',
+ '_um_default_homepage' => 1,
+ '_um_can_view_all' => 1,
+ '_um_can_make_private_profile' => 0,
+ '_um_can_access_private_profile' => 0,
+ '_um_status' => 'approved',
+ '_um_auto_approve_act' => 'redirect_profile',
),
- 'author' => array(
- '_um_can_access_wpadmin' => 0,
- '_um_can_not_see_adminbar' => 1,
- '_um_can_edit_everyone' => 0,
- '_um_can_delete_everyone' => 0,
- '_um_can_edit_profile' => 1,
- '_um_can_delete_profile' => 1,
- '_um_after_login' => 'redirect_profile',
- '_um_after_logout' => 'redirect_home',
- '_um_default_homepage' => 1,
- '_um_can_view_all' => 1,
- '_um_can_make_private_profile' => 0,
- '_um_can_access_private_profile' => 0,
- '_um_status' => 'approved',
- '_um_auto_approve_act' => 'redirect_profile',
+ 'author' => array(
+ '_um_can_access_wpadmin' => 0,
+ '_um_can_not_see_adminbar' => 1,
+ '_um_can_edit_everyone' => 0,
+ '_um_can_delete_everyone' => 0,
+ '_um_can_edit_profile' => 1,
+ '_um_can_delete_profile' => 1,
+ '_um_after_login' => 'redirect_profile',
+ '_um_after_logout' => 'redirect_home',
+ '_um_default_homepage' => 1,
+ '_um_can_view_all' => 1,
+ '_um_can_make_private_profile' => 0,
+ '_um_can_access_private_profile' => 0,
+ '_um_status' => 'approved',
+ '_um_auto_approve_act' => 'redirect_profile',
),
- 'contributor' => array(
- '_um_can_access_wpadmin' => 0,
- '_um_can_not_see_adminbar' => 1,
- '_um_can_edit_everyone' => 0,
- '_um_can_delete_everyone' => 0,
- '_um_can_edit_profile' => 1,
- '_um_can_delete_profile' => 1,
- '_um_after_login' => 'redirect_profile',
- '_um_after_logout' => 'redirect_home',
- '_um_default_homepage' => 1,
- '_um_can_view_all' => 1,
- '_um_can_make_private_profile' => 0,
- '_um_can_access_private_profile' => 0,
- '_um_status' => 'approved',
- '_um_auto_approve_act' => 'redirect_profile',
+ 'contributor' => array(
+ '_um_can_access_wpadmin' => 0,
+ '_um_can_not_see_adminbar' => 1,
+ '_um_can_edit_everyone' => 0,
+ '_um_can_delete_everyone' => 0,
+ '_um_can_edit_profile' => 1,
+ '_um_can_delete_profile' => 1,
+ '_um_after_login' => 'redirect_profile',
+ '_um_after_logout' => 'redirect_home',
+ '_um_default_homepage' => 1,
+ '_um_can_view_all' => 1,
+ '_um_can_make_private_profile' => 0,
+ '_um_can_access_private_profile' => 0,
+ '_um_status' => 'approved',
+ '_um_auto_approve_act' => 'redirect_profile',
),
- 'editor' => array(
- '_um_can_access_wpadmin' => 0,
- '_um_can_not_see_adminbar' => 1,
- '_um_can_edit_everyone' => 0,
- '_um_can_delete_everyone' => 0,
- '_um_can_edit_profile' => 1,
- '_um_can_delete_profile' => 1,
- '_um_after_login' => 'redirect_profile',
- '_um_after_logout' => 'redirect_home',
- '_um_default_homepage' => 1,
- '_um_can_view_all' => 1,
- '_um_can_make_private_profile' => 0,
- '_um_can_access_private_profile' => 0,
- '_um_status' => 'approved',
- '_um_auto_approve_act' => 'redirect_profile',
+ 'editor' => array(
+ '_um_can_access_wpadmin' => 0,
+ '_um_can_not_see_adminbar' => 1,
+ '_um_can_edit_everyone' => 0,
+ '_um_can_delete_everyone' => 0,
+ '_um_can_edit_profile' => 1,
+ '_um_can_delete_profile' => 1,
+ '_um_after_login' => 'redirect_profile',
+ '_um_after_logout' => 'redirect_home',
+ '_um_default_homepage' => 1,
+ '_um_can_view_all' => 1,
+ '_um_can_make_private_profile' => 0,
+ '_um_can_access_private_profile' => 0,
+ '_um_status' => 'approved',
+ '_um_auto_approve_act' => 'redirect_profile',
),
'administrator' => array(
- '_um_can_access_wpadmin' => 1,
- '_um_can_not_see_adminbar' => 0,
- '_um_can_edit_everyone' => 1,
- '_um_can_delete_everyone' => 1,
- '_um_can_edit_profile' => 1,
- '_um_can_delete_profile' => 1,
- '_um_default_homepage' => 1,
- '_um_after_login' => 'redirect_admin',
- '_um_after_logout' => 'redirect_home',
- '_um_can_view_all' => 1,
- '_um_can_make_private_profile' => 1,
- '_um_can_access_private_profile' => 1,
- '_um_status' => 'approved',
- '_um_auto_approve_act' => 'redirect_profile',
+ '_um_can_access_wpadmin' => 1,
+ '_um_can_not_see_adminbar' => 0,
+ '_um_can_edit_everyone' => 1,
+ '_um_can_delete_everyone' => 1,
+ '_um_can_edit_profile' => 1,
+ '_um_can_delete_profile' => 1,
+ '_um_default_homepage' => 1,
+ '_um_after_login' => 'redirect_admin',
+ '_um_after_logout' => 'redirect_home',
+ '_um_can_view_all' => 1,
+ '_um_can_make_private_profile' => 1,
+ '_um_can_access_private_profile' => 1,
+ '_um_status' => 'approved',
+ '_um_auto_approve_act' => 'redirect_profile',
),
);
@@ -812,7 +768,6 @@ if ( ! class_exists( 'um\Config' ) ) {
);
}
-
/**
* Get UM Pages
*
@@ -826,27 +781,41 @@ if ( ! class_exists( 'um\Config' ) ) {
}
foreach ( $core_pages as $page_key ) {
- $page_option_key = UM()->options()->get_core_page_id( $page_key );
+ $page_option_key = UM()->options()->get_predefined_page_option_key( $page_key );
$permalink[ $page_key ] = UM()->options()->get( $page_option_key );
}
return $permalink;
}
-
/**
* @todo make config class not cycled
*/
- function set_core_page() {
- $this->core_pages = apply_filters( 'um_core_pages', array(
- 'user' => array( 'title' => __( 'User', 'ultimate-member' ) ),
- 'login' => array( 'title' => __( 'Login', 'ultimate-member' ) ),
- 'register' => array( 'title' => __( 'Register', 'ultimate-member' ) ),
- 'members' => array( 'title' => __( 'Members', 'ultimate-member' ) ),
- 'logout' => array( 'title' => __( 'Logout', 'ultimate-member' ) ),
- 'account' => array( 'title' => __( 'Account', 'ultimate-member' ) ),
- 'password-reset' => array( 'title' => __( 'Password Reset', 'ultimate-member' ) ),
- ) );
+ public function set_core_page() {
+ $this->core_pages = array(
+ 'user' => array(
+ 'title' => __( 'User', 'ultimate-member' ),
+ ),
+ 'login' => array(
+ 'title' => __( 'Login', 'ultimate-member' ),
+ ),
+ 'register' => array(
+ 'title' => __( 'Register', 'ultimate-member' ),
+ ),
+ 'members' => array(
+ 'title' => __( 'Members', 'ultimate-member' ),
+ ),
+ 'logout' => array(
+ 'title' => __( 'Logout', 'ultimate-member' ),
+ ),
+ 'account' => array(
+ 'title' => __( 'Account', 'ultimate-member' ),
+ ),
+ 'password-reset' => array(
+ 'title' => __( 'Password Reset', 'ultimate-member' ),
+ ),
+ );
+ $this->core_pages = apply_filters( 'um_core_pages', $this->core_pages );
}
/**
diff --git a/includes/class-init.php b/includes/class-init.php
index 0a7d33b4..a8005d2a 100644
--- a/includes/class-init.php
+++ b/includes/class-init.php
@@ -235,93 +235,41 @@ if ( ! class_exists( 'UM' ) ) {
}
}
-
/**
- * Loading UM textdomain
+ * Loading UM textdomain.
*
- * 'ultimate-member' by default
+ * Note: 'ultimate-member' is a default textdomain.
+ *
+ * @since 2.8.5 WordPress native functions are used to make this function clear.
*/
public function localize() {
- // The function `get_user_locale()` will return `get_locale()` result by default if user or its locale is empty.
- $language_locale = get_user_locale();
-
+ $default_domain = dirname( plugin_basename( UM_PLUGIN ) );
/**
- * UM hook
+ * Filters the plugin's textdomain.
*
- * @type filter
- * @title um_language_locale
- * @description Change UM language locale
- * @input_vars
- * [{"var":"$locale","type":"string","desc":"UM language locale"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage add_filter( 'um_language_locale', 'function_name', 10, 1 );
- * @example
- *
- */
- $language_locale = apply_filters( 'um_language_locale', $language_locale );
-
-
- /**
- * UM hook
+ * @param {string} $domain Plugin's textdomain.
*
- * @type filter
- * @title um_language_textdomain
- * @description Change UM textdomain
- * @input_vars
- * [{"var":"$domain","type":"string","desc":"UM Textdomain"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage add_filter( 'um_language_textdomain', 'function_name', 10, 1 );
- * @example
- * Change UM language locale.
+ * function my_um_language_textdomain( $domain ) {
+ * $domain = 'ultimate-member-custom';
* return $domain;
* }
- * ?>
+ * add_filter( 'um_language_textdomain', 'my_um_language_textdomain' );
*/
- $language_domain = apply_filters( 'um_language_textdomain', 'ultimate-member' );
-
- $language_file = WP_LANG_DIR . '/plugins/' . $language_domain . '-' . $language_locale . '.mo';
-
- /**
- * UM hook
- *
- * @type filter
- * @title um_language_file
- * @description Change UM language file path
- * @input_vars
- * [{"var":"$language_file","type":"string","desc":"UM language file path"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage add_filter( 'um_language_file', 'function_name', 10, 1 );
- * @example
- *
- */
- $language_file = apply_filters( 'um_language_file', $language_file );
+ $domain = apply_filters( 'um_language_textdomain', $default_domain );
// Unload textdomain if it has already loaded.
- if ( is_textdomain_loaded( $language_domain ) ) {
- unload_textdomain( $language_domain, true );
+ if ( is_textdomain_loaded( $domain ) ) {
+ unload_textdomain( $domain, true );
}
- load_textdomain( $language_domain, $language_file );
+ load_plugin_textdomain( $domain, false, $default_domain . '/languages' );
}
-
/**
* 1.3.x active extensions deactivate for properly running 2.0.x AJAX upgrades
*/
diff --git a/includes/core/class-access.php b/includes/core/class-access.php
index 1cafc3b9..fa91fa31 100644
--- a/includes/core/class-access.php
+++ b/includes/core/class-access.php
@@ -1772,10 +1772,10 @@ if ( ! class_exists( 'um\core\Access' ) ) {
$access = UM()->options()->get( 'accessible' );
if ( $access == 2 ) {
- //global settings for accessible home page
+ // Global settings for accessible home page
$home_page_accessible = UM()->options()->get( 'home_page_accessible' );
- if ( $home_page_accessible == 0 ) {
+ if ( ! $home_page_accessible ) {
//get redirect URL if not set get login page by default
$redirect = UM()->options()->get( 'access_redirect' );
if ( ! $redirect ) {
@@ -1795,9 +1795,9 @@ if ( ! class_exists( 'um\core\Access' ) ) {
$access = UM()->options()->get( 'accessible' );
if ( $access == 2 ) {
- //global settings for accessible home page
+ // Global settings for accessible home page
$category_page_accessible = UM()->options()->get( 'category_page_accessible' );
- if ( $category_page_accessible == 0 ) {
+ if ( ! $category_page_accessible ) {
//get redirect URL if not set get login page by default
$redirect = UM()->options()->get( 'access_redirect' );
if ( ! $redirect ) {
diff --git a/includes/core/class-account.php b/includes/core/class-account.php
index 1128a08e..65df44e9 100644
--- a/includes/core/class-account.php
+++ b/includes/core/class-account.php
@@ -576,7 +576,7 @@ if ( ! class_exists( 'um\core\Account' ) ) {
case 'privacy':
- $args = 'profile_privacy,profile_noindex,hide_in_members';
+ $args = 'profile_privacy,profile_noindex,hide_in_members,um_show_last_login';
/**
* UM hook
*
diff --git a/includes/core/class-builtin.php b/includes/core/class-builtin.php
index 4939fbd2..cf3b7958 100644
--- a/includes/core/class-builtin.php
+++ b/includes/core/class-builtin.php
@@ -1336,6 +1336,23 @@ if ( ! class_exists( 'um\core\Builtin' ) ) {
'required_opt' => array( 'members_page', true ),
),
+ 'um_show_last_login' => array(
+ 'title' => __( 'Show my last login?', 'ultimate-member' ),
+ 'metakey' => 'um_show_last_login',
+ 'type' => 'radio',
+ 'label' => __( 'Show my last login?', 'ultimate-member' ),
+ 'help' => __( 'Here you can hide last login field on profile page and card in member directory', 'ultimate-member' ),
+ 'required' => 0,
+ 'public' => 1,
+ 'editable' => true,
+ 'default' => 'yes',
+ 'options' => array(
+ 'no' => __( 'No', 'ultimate-member' ),
+ 'yes' => __( 'Yes', 'ultimate-member' ),
+ ),
+ 'account_only' => true,
+ ),
+
'delete_account' => array(
'title' => __( 'Delete Account', 'ultimate-member' ),
'metakey' => 'delete_account',
diff --git a/includes/core/class-external-integrations.php b/includes/core/class-external-integrations.php
index 905ae007..8a846efe 100644
--- a/includes/core/class-external-integrations.php
+++ b/includes/core/class-external-integrations.php
@@ -604,7 +604,7 @@ if ( ! class_exists( 'um\core\External_Integrations' ) ) {
*/
function render_status_icon( $link, $text, $img ) {
- $icon_html = '
';
+ $icon_html = ' ';
$icon_html .= ' ';
-
- if ( ! empty( $data['icon'] ) && isset( $this->field_icons ) && 'off' !== $this->field_icons && ( 'label' === $this->field_icons || true === $this->viewing ) ) {
- $output .= '
';
- }
-
if ( true === $this->viewing ) {
/**
* Filters Ultimate Member field label on the Profile form: View mode.
@@ -730,13 +723,26 @@ if ( ! class_exists( 'um\core\Fields' ) ) {
$label = apply_filters( 'um_edit_label_all_fields', $label, $data );
}
+ $output = null;
+ $output .= '';
+
+ if ( ! empty( $data['icon'] ) && isset( $this->field_icons ) && 'off' !== $this->field_icons && ( 'label' === $this->field_icons || true === $this->viewing ) ) {
+ $output .= '
';
+ }
+
$fields_without_metakey = UM()->builtin()->get_fields_without_metakey();
$for_attr = '';
if ( ! in_array( $data['type'], $fields_without_metakey, true ) ) {
$for_attr = ' for="' . esc_attr( $key . UM()->form()->form_suffix ) . '"';
}
- $output .= '
' . __( $label, 'ultimate-member' ) . ' ';
+ $output .= '
' . esc_html__( $label, 'ultimate-member' );
+
+ if ( ! empty( $data['required'] ) && UM()->options()->get( 'form_asterisk' ) ) {
+ $output .= '* ';
+ }
+
+ $output .= ' ';
if ( ! empty( $data['help'] ) && false === $this->viewing && false === strpos( $key, 'confirm_user_pass' ) ) {
if ( ! UM()->mobile()->isMobile() ) {
@@ -3092,7 +3098,7 @@ if ( ! class_exists( 'um\core\Fields' ) ) {
$fonticon = UM()->files()->get_fonticon_by_ext( $file_type['ext'] );
$output .= '
';
@@ -4278,6 +4284,14 @@ if ( ! class_exists( 'um\core\Fields' ) ) {
* @throws \Exception
*/
public function view_field( $key, $data, $rule = false ) {
+ if ( '_um_last_login' === $key ) {
+ $profile_id = um_user( 'ID' );
+ $show_last_login = get_user_meta( $profile_id, 'um_show_last_login', true );
+ if ( ! empty( $show_last_login ) && 'no' === $show_last_login[0] ) {
+ return '';
+ }
+ }
+
$output = '';
// Get whole field data.
diff --git a/includes/core/class-member-directory-meta.php b/includes/core/class-member-directory-meta.php
index 41d8b18d..c3bc651f 100644
--- a/includes/core/class-member-directory-meta.php
+++ b/includes/core/class-member-directory-meta.php
@@ -224,6 +224,27 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
$blog_id = get_current_blog_id();
+ /**
+ * Filters member directory select-type filter relation in query.
+ *
+ * @param {string} $relation Relation `OR` or `AND`. `OR` by default.
+ * @param {string} $field Field key.
+ *
+ * @return {string} Relation.
+ *
+ * @since 2.8.5
+ * @hook um_members_directory_select_filter_relation
+ *
+ * @example Change relation to 'AND'.
+ * function my_um_members_directory_select_filter_relation( $relation, $field ) {
+ * // your code here
+ * $relation = 'AND';
+ * return $relation;
+ * }
+ * add_filter( 'um_members_directory_select_filter_relation', 'my_um_members_directory_select_filter_relation', 10, 2 );
+ */
+ $relation = apply_filters( 'um_members_directory_select_filter_relation', 'OR', $field );
+
switch ( $field ) {
default:
$filter_type = $this->filter_types[ $field ];
@@ -328,7 +349,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias is pre-escaped.
}
- $values = implode( ' OR ', $values_array );
+ $values = implode( ' ' . esc_sql( $relation ) . ' ', $values_array );
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias and $values variables are pre-escaped or $wpdb->prepare.
$this->where_clauses[] = $wpdb->prepare( "( {$join_alias}.um_key = %s AND ( {$values} ) )", $field );
@@ -421,7 +442,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
}
// $roles_clauses is pre-prepared.
- $this->where_clauses[] = '( ' . implode( ' OR ', $roles_clauses ) . ' )';
+ $this->where_clauses[] = '( ' . implode( ' ' . esc_sql( $relation ) . ' ', $roles_clauses ) . ' )';
if ( ! $is_default ) {
$this->custom_filters_in_query[ $field ] = $value;
@@ -483,19 +504,55 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
}
}
+ $value = array_map(
+ function( $date ) {
+ return is_numeric( $date ) ? $date : strtotime( $date );
+ },
+ $value
+ );
+
$from_date = gmdate( 'Y-m-d H:i:s', (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ) ); // client time zone offset
$to_date = gmdate( 'Y-m-d H:i:s', (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1 ); // time 23:59
// $join_alias is pre-escaped.
$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata {$join_alias} ON {$join_alias}.user_id = u.ID";
+ $join_alias_ll = $join_alias . '_show_las_login';
+ $this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata {$join_alias_ll} ON {$join_alias_ll}.user_id = u.ID AND {$join_alias_ll}.um_key = 'um_show_last_login'";
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias is pre-escaped.
- $this->where_clauses[] = $wpdb->prepare( "( {$join_alias}.um_key = '_um_last_login' AND {$join_alias}.um_value BETWEEN %s AND %s )", $from_date, $to_date );
+ $this->where_clauses[] = $wpdb->prepare( "( {$join_alias}.um_key = '_um_last_login' AND {$join_alias}.um_value BETWEEN %s AND %s AND ( {$join_alias_ll}.um_value IS NULL OR {$join_alias_ll}.um_value != %s ) )", $from_date, $to_date, 'a:1:{i:0;s:2:"no";}' );
if ( ! $is_default ) {
$this->custom_filters_in_query[ $field ] = $value;
}
break;
+ case 'gender':
+ if ( ! is_array( $value ) ) {
+ $value = array( $value );
+ }
+
+ // $join_alias is pre-escaped.
+ $this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata {$join_alias} ON {$join_alias}.user_id = u.ID";
+
+ $values_array = array();
+ foreach ( $value as $single_val ) {
+ $single_val = trim( stripslashes( $single_val ) );
+
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias and $compare variables are pre-escaped.
+ $values_array[] = $wpdb->prepare( "{$join_alias}.um_value LIKE %s", '%"' . $wpdb->esc_like( $single_val ) . '"%' );
+ $values_array[] = $wpdb->prepare( "{$join_alias}.um_value = %s", $single_val );
+ // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias is pre-escaped.
+ }
+
+ $values = implode( ' ' . esc_sql( $relation ) . ' ', $values_array );
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias and $values variables are pre-escaped or $wpdb->prepare.
+ $this->where_clauses[] = $wpdb->prepare( "( {$join_alias}.um_key = %s AND ( {$values} ) )", $field );
+
+ if ( ! $is_default ) {
+ $this->custom_filters_in_query[ $field ] = $value;
+ }
+ break;
}
}
@@ -649,13 +706,29 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
// phpcs:enable WordPress.Security.NonceVerification -- verified via `UM()->check_ajax_nonce();`.
if ( ! empty( $search_line ) ) {
$searches = array();
- foreach ( $this->core_search_fields as $field ) {
- $field = esc_sql( $field );
- // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $field is pre-escaped.
- $searches[] = $wpdb->prepare( "u.{$field} LIKE %s", '%' . $wpdb->esc_like( $search_line ) . '%' );
+
+ $exclude_fields = get_post_meta( $directory_id, '_um_search_exclude_fields', true );
+ $include_fields = get_post_meta( $directory_id, '_um_search_include_fields', true );
+
+ $core_search = $this->get_core_search_fields();
+ if ( ! empty( $include_fields ) ) {
+ $core_search = array_intersect( $core_search, $include_fields );
+ }
+ if ( ! empty( $exclude_fields ) ) {
+ $core_search = array_diff( $core_search, $exclude_fields );
+ }
+ if ( ! empty( $core_search ) ) {
+ foreach ( $core_search as $field ) {
+ $field = esc_sql( $field );
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $field is pre-escaped.
+ $searches[] = $wpdb->prepare( "u.{$field} LIKE %s", '%' . $wpdb->esc_like( $search_line ) . '%' );
+ }
}
$core_search = implode( ' OR ', $searches );
+ if ( ! empty( $core_search ) ) {
+ $core_search = ' OR ' . $core_search;
+ }
$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_search ON umm_search.user_id = u.ID";
@@ -663,8 +736,17 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
$search_like_string = apply_filters( 'um_member_directory_meta_search_like_type', '%' . $wpdb->esc_like( $search_line ) . '%', $search_line );
+ $custom_fields_sql = '';
+
+ if ( ! empty( $exclude_fields ) ) {
+ $custom_fields_sql = " AND umm_search.um_key NOT IN ('" . implode( "','", $exclude_fields ) . "') ";
+ }
+ if ( ! empty( $include_fields ) ) {
+ $custom_fields_sql = " AND umm_search.um_key IN ('" . implode( "','", $include_fields ) . "') ";
+ }
+
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $core_search and $additional_search are pre-prepared.
- $this->where_clauses[] = $wpdb->prepare( "( umm_search.um_value = %s OR umm_search.um_value LIKE %s OR umm_search.um_value LIKE %s OR {$core_search}{$additional_search})", $search_line, $search_like_string, '%' . $wpdb->esc_like( maybe_serialize( (string) $search_line ) ) . '%' );
+ $this->where_clauses[] = $wpdb->prepare( "( umm_search.um_value = %s OR umm_search.um_value LIKE %s OR umm_search.um_value LIKE %s{$core_search}{$additional_search}){$custom_fields_sql}", $search_line, $search_like_string, '%' . $wpdb->esc_like( maybe_serialize( (string) $search_line ) ) . '%' );
$this->is_search = true;
}
diff --git a/includes/core/class-member-directory.php b/includes/core/class-member-directory.php
index f2de4fb8..5be87b0d 100644
--- a/includes/core/class-member-directory.php
+++ b/includes/core/class-member-directory.php
@@ -42,6 +42,11 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
*/
var $filter_fields = array();
+ /**
+ * @var array
+ */
+ public $searching_fields = array();
+
/**
* @var array
@@ -122,7 +127,7 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
* Get the WordPress core searching fields in wp_users query.
* @return array
*/
- private function get_core_search_fields() {
+ protected function get_core_search_fields() {
/**
* Filters the WordPress core searching fields in wp_users query for UM Member directory query.
*
@@ -433,6 +438,25 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$this->filter_supported_fields = apply_filters( 'um_members_directory_custom_field_types_supported_filter', array( 'date', 'time', 'select', 'multiselect', 'radio', 'checkbox', 'rating', 'text', 'textarea', 'number' ) );
+ $core_search_keys = $this->get_core_search_fields();
+
+ $this->searching_fields = array();
+ if ( ! empty( UM()->builtin()->all_user_fields() ) ) {
+ foreach ( UM()->builtin()->all_user_fields() as $key => $data ) {
+ if ( in_array( $key, $core_search_keys, true ) ) {
+ if ( isset( $data['title'] ) && array_search( $data['title'], $this->searching_fields, true ) !== false ) {
+ $data['title'] = $data['title'] . ' (' . $key . ')';
+ }
+
+ $title = isset( $data['title'] ) ? $data['title'] : ( isset( $data['label'] ) ? $data['label'] : '' );
+ if ( empty( $title ) ) {
+ continue;
+ }
+
+ $this->searching_fields[ $key ] = $title;
+ }
+ }
+ }
if ( ! empty( UM()->builtin()->saved_fields ) ) {
foreach ( UM()->builtin()->saved_fields as $key => $data ) {
@@ -459,6 +483,9 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
ksort( $this->filter_fields );
+ $this->searching_fields = array_merge( $this->searching_fields, $this->filter_fields );
+ asort( $this->searching_fields );
+
$this->filter_types = apply_filters( 'um_members_directory_filter_types', array(
'country' => 'select',
'gender' => 'select',
@@ -1734,27 +1761,50 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$sql['where'] = str_replace( '#%&', '{' . $matches[0][0] . '}', $sql['where'] );
+ $directory_id = $this->get_directory_by_hash( sanitize_key( $_POST['directory_id'] ) );
+ $exclude_fields = get_post_meta( $directory_id, '_um_search_exclude_fields', true );
+ $include_fields = get_post_meta( $directory_id, '_um_search_include_fields', true );
+
if ( isset( $join_matches[1] ) ) {
$meta_join_for_search = trim( $join_matches[1] );
// skip private invisible fields
$custom_fields = array();
- foreach ( array_keys( UM()->builtin()->all_user_fields ) as $field_key ) {
- if ( empty( $field_key ) ) {
- continue;
- }
+ if ( empty( $include_fields ) ) {
+ foreach ( array_keys( UM()->builtin()->all_user_fields ) as $field_key ) {
+ if ( empty( $field_key ) ) {
+ continue;
+ }
- $data = UM()->fields()->get_field( $field_key );
- if ( ! um_can_view_field( $data ) ) {
- continue;
- }
+ $data = UM()->fields()->get_field( $field_key );
+ if ( ! um_can_view_field( $data ) ) {
+ continue;
+ }
- $custom_fields[] = $field_key;
+ $custom_fields[] = $field_key;
+ }
+ } else {
+ foreach ( $include_fields as $field_key ) {
+ if ( empty( $field_key ) ) {
+ continue;
+ }
+
+ $data = UM()->fields()->get_field( $field_key );
+ if ( ! um_can_view_field( $data ) ) {
+ continue;
+ }
+
+ $custom_fields[] = $field_key;
+ }
}
$custom_fields = apply_filters( 'um_general_search_custom_fields', $custom_fields );
if ( ! empty( $custom_fields ) ) {
+ if ( ! empty( $exclude_fields ) ) {
+ $custom_fields = array_diff( $custom_fields, $exclude_fields );
+ }
+
$sql['join'] = preg_replace(
'/(' . $meta_join_for_search . ' ON \( ' . $wpdb->users . '\.ID = ' . $meta_join_for_search . '\.user_id )(\))/im',
"$1 AND " . $meta_join_for_search . ".meta_key IN( '" . implode( "','", $custom_fields ) . "' ) $2",
@@ -1763,18 +1813,28 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
}
}
- // Add OR instead AND to search in WP core fields user_email, user_login, user_display_name
- $search_where = $context->get_search_sql( $search, $this->get_core_search_fields(), 'both' );
+ $core_search = $this->get_core_search_fields();
+ if ( ! empty( $include_fields ) ) {
+ $core_search = array_intersect( $core_search, $include_fields );
+ }
+ if ( ! empty( $exclude_fields ) ) {
+ $core_search = array_diff( $core_search, $exclude_fields );
+ }
- $search_where = preg_replace( '/ AND \((.*?)\)/im', "$1 OR", $search_where );
+ if ( ! empty( $core_search ) ) {
+ // Add OR instead AND to search in WP core fields user_email, user_login, user_display_name
+ $search_where = $context->get_search_sql( $search, $core_search, 'both' );
- // str_replace( '/', '\/', wp_slash( $search ) ) means that we add backslashes to special symbols + add backslash to slash(/) symbol for proper regular pattern.
- $sql['where'] = preg_replace(
- '/(' . $meta_join_for_search . '.meta_value = \'' . str_replace( '/', '\/', wp_slash( $search ) ) . '\')/im',
- trim( $search_where ) . " $1",
- $sql['where'],
- 1
- );
+ $search_where = preg_replace( '/ AND \((.*?)\)/im', "$1 OR", $search_where );
+
+ // str_replace( '/', '\/', wp_slash( $search ) ) means that we add backslashes to special symbols + add backslash to slash(/) symbol for proper regular pattern.
+ $sql['where'] = preg_replace(
+ '/(' . $meta_join_for_search . '.meta_value = \'' . str_replace( '/', '\/', wp_slash( $search ) ) . '\')/im',
+ trim( $search_where ) . " $1",
+ $sql['where'],
+ 1
+ );
+ }
}
}
@@ -1785,6 +1845,7 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
* Handle filters request
*/
function filters( $directory_data ) {
+ global $wpdb;
//filters
$filter_query = array();
if ( ! empty( $directory_data['search_fields'] ) ) {
@@ -1817,9 +1878,11 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
continue;
}
+ /** This filter is documented in includes/core/class-member-directory-meta.php */
+ $relation = apply_filters( 'um_members_directory_select_filter_relation', 'OR', $field );
+
switch ( $field ) {
default:
-
$filter_type = $this->filter_types[ $field ];
/**
@@ -1873,35 +1936,35 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
case 'select':
if ( is_array( $value ) ) {
- $field_query = array( 'relation' => 'OR' );
+ $field_query = array( 'relation' => esc_sql( $relation ) );
foreach ( $value as $single_val ) {
$single_val = trim( stripslashes( $single_val ) );
$arr_meta_query = array(
array(
- 'key' => $field,
- 'value' => $single_val,
- 'compare' => '=',
+ 'key' => $field,
+ 'value' => $single_val,
+ 'compare' => '=',
),
array(
- 'key' => $field,
- 'value' => serialize( (string) $single_val ),
- 'compare' => 'LIKE',
+ 'key' => $field,
+ 'value' => serialize( (string) $single_val ),
+ 'compare' => 'LIKE',
),
array(
- 'key' => $field,
- 'value' => '"' . $single_val . '"',
- 'compare' => 'LIKE',
- )
+ 'key' => $field,
+ 'value' => '"' . $single_val . '"',
+ 'compare' => 'LIKE',
+ ),
);
if ( is_numeric( $single_val ) ) {
$arr_meta_query[] = array(
- 'key' => $field,
- 'value' => serialize( (int) $single_val ),
- 'compare' => 'LIKE',
+ 'key' => $field,
+ 'value' => serialize( absint( $single_val ) ),
+ 'compare' => 'LIKE',
);
}
@@ -1975,26 +2038,39 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
if ( ! empty( $field_query ) && $field_query !== true ) {
$this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $field_query ) );
}
-
break;
case 'role':
$value = array_map( 'strtolower', $value );
- if ( ! empty( $this->query_args['role__in'] ) ) {
- $this->query_args['role__in'] = is_array( $this->query_args['role__in'] ) ? $this->query_args['role__in'] : array( $this->query_args['role__in'] );
- $default_role = array_intersect( $this->query_args['role__in'], $value );
- $um_role = array_diff( $value, $default_role );
-
- foreach ( $um_role as $key => &$val ) {
- $val = 'um_' . str_replace( ' ', '-', $val );
+ if ( 'OR' !== $relation ) {
+ $role__in_clauses = array( 'relation' => $relation );
+ foreach ( $value as $role ) {
+ $role__in_clauses[] = array(
+ 'key' => $wpdb->get_blog_prefix() . 'capabilities',
+ 'value' => '"' . $role . '"',
+ 'compare' => 'LIKE',
+ );
}
- $this->query_args['role__in'] = array_merge( $default_role, $um_role );
+
+ $this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $role__in_clauses ) );
+
+ $this->custom_filters_in_query[ $field ] = $value;
} else {
- $this->query_args['role__in'] = $value;
- };
+ if ( ! empty( $this->query_args['role__in'] ) ) {
+ $this->query_args['role__in'] = is_array( $this->query_args['role__in'] ) ? $this->query_args['role__in'] : array( $this->query_args['role__in'] );
+ $default_role = array_intersect( $this->query_args['role__in'], $value );
+ $um_role = array_diff( $value, $default_role );
- $this->custom_filters_in_query[ $field ] = $this->query_args['role__in'];
+ foreach ( $um_role as $key => &$val ) {
+ $val = 'um_' . str_replace( ' ', '-', $val );
+ }
+ $this->query_args['role__in'] = array_merge( $default_role, $um_role );
+ } else {
+ $this->query_args['role__in'] = $value;
+ }
+ $this->custom_filters_in_query[ $field ] = $this->query_args['role__in'];
+ }
break;
case 'birth_date':
$from_date = date( 'Y/m/d', mktime( 0,0,0, date( 'm', time() ), date( 'd', time() ), date( 'Y', time() - min( $value ) * YEAR_IN_SECONDS ) ) );
@@ -2016,7 +2092,6 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
break;
case 'user_registered':
-
$offset = 0;
if ( isset( $_POST['gmt_offset'] ) && is_numeric( $_POST['gmt_offset'] ) ) {
$offset = (int) $_POST['gmt_offset'];
@@ -2052,6 +2127,7 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
$to_date = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
$meta_query = array(
+ 'relation' => 'AND',
array(
'key' => '_um_last_login',
'value' => array( gmdate( 'Y-m-d H:i:s', $from_date ), gmdate( 'Y-m-d H:i:s', $to_date ) ),
@@ -2059,12 +2135,54 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
'inclusive' => true,
'type' => 'DATETIME',
),
+ array(
+ 'relation' => 'OR',
+ array(
+ 'key' => 'um_show_last_login',
+ 'compare' => 'NOT EXISTS',
+ ),
+ array(
+ 'key' => 'um_show_last_login',
+ 'value' => 'a:1:{i:0;s:2:"no";}',
+ 'compare' => '!=',
+ ),
+ ),
);
$this->custom_filters_in_query[ $field ] = $value;
$this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $meta_query ) );
break;
+ case 'gender':
+ if ( is_array( $value ) ) {
+ $field_query = array( 'relation' => $relation );
+
+ foreach ( $value as $single_val ) {
+ $single_val = trim( stripslashes( $single_val ) );
+
+ $arr_meta_query = array(
+ array(
+ 'key' => $field,
+ 'value' => $single_val,
+ 'compare' => '=',
+ ),
+ array(
+ 'key' => $field,
+ 'value' => '"' . $single_val . '"',
+ 'compare' => 'LIKE',
+ ),
+ );
+
+ $field_query = array_merge( $field_query, $arr_meta_query );
+ }
+ }
+
+ if ( ! empty( $field_query ) ) {
+ $this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $field_query ) );
+
+ $this->custom_filters_in_query[ $field ] = $value;
+ }
+ break;
}
}
}
@@ -2141,35 +2259,36 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$value = array( $value );
}
- $field_query = array( 'relation' => 'OR' );
+ /** This filter is documented in includes/core/class-member-directory.php */
+ $field_query = apply_filters( 'um_members_directory_filter_select', array( 'relation' => 'OR' ), $field );
foreach ( $value as $single_val ) {
$single_val = trim( $single_val );
$arr_meta_query = array(
array(
- 'key' => $field,
- 'value' => $single_val,
- 'compare' => '=',
+ 'key' => $field,
+ 'value' => $single_val,
+ 'compare' => '=',
),
array(
- 'key' => $field,
- 'value' => serialize( (string) $single_val ),
- 'compare' => 'LIKE',
+ 'key' => $field,
+ 'value' => serialize( (string) $single_val ),
+ 'compare' => 'LIKE',
),
array(
- 'key' => $field,
- 'value' => '"' . $single_val . '"',
- 'compare' => 'LIKE',
- )
+ 'key' => $field,
+ 'value' => '"' . $single_val . '"',
+ 'compare' => 'LIKE',
+ ),
);
if ( is_numeric( $single_val ) ) {
$arr_meta_query[] = array(
- 'key' => $field,
- 'value' => serialize( (int) $single_val ),
- 'compare' => 'LIKE',
+ 'key' => $field,
+ 'value' => serialize( absint( $single_val ) ),
+ 'compare' => 'LIKE',
);
}
@@ -2298,9 +2417,18 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$offset = $gmt_offset;
}
- $from_date = (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ); // client time zone offset
- $to_date = (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1; // time 23:59
+ $value = array_map(
+ function( $date ) {
+ return is_numeric( $date ) ? $date : strtotime( $date );
+ },
+ $value
+ );
+
+ $from_date = gmdate( 'Y-m-d H:i:s', (int) min( $value ) + ( $offset * HOUR_IN_SECONDS ) ); // client time zone offset
+ $to_date = gmdate( 'Y-m-d H:i:s', (int) max( $value ) + ( $offset * HOUR_IN_SECONDS ) + DAY_IN_SECONDS - 1 ); // time 23:59
+
$meta_query = array(
+ 'relation' => 'AND',
array(
'key' => '_um_last_login',
'value' => array( $from_date, $to_date ),
@@ -2308,6 +2436,18 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
'inclusive' => true,
'type' => 'DATETIME',
),
+ array(
+ 'relation' => 'OR',
+ array(
+ 'key' => 'um_show_last_login',
+ 'compare' => 'NOT EXISTS',
+ ),
+ array(
+ 'key' => 'um_show_last_login',
+ 'value' => 'a:1:{i:0;s:2:"no";}',
+ 'compare' => '!=',
+ ),
+ ),
);
$this->query_args['meta_query'] = array_merge( $this->query_args['meta_query'], array( $meta_query ) );
@@ -2513,6 +2653,13 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
continue;
}
+ if ( '_um_last_login' === $key ) {
+ $show_last_login = get_user_meta( $user_id, 'um_show_last_login', true );
+ if ( ! empty( $show_last_login ) && 'no' === $show_last_login[0] ) {
+ continue;
+ }
+ }
+
$value = um_filtered_value( $key );
if ( ! $value ) {
@@ -2537,6 +2684,13 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
continue;
}
+ if ( '_um_last_login' === $key ) {
+ $show_last_login = get_user_meta( $user_id, 'um_show_last_login', true );
+ if ( ! empty( $show_last_login ) && 'no' === $show_last_login[0] ) {
+ continue;
+ }
+ }
+
$value = um_filtered_value( $key );
if ( ! $value ) {
continue;
diff --git a/includes/core/class-options.php b/includes/core/class-options.php
index 66a0ca97..daf801e3 100644
--- a/includes/core/class-options.php
+++ b/includes/core/class-options.php
@@ -7,64 +7,56 @@ if ( ! defined( 'ABSPATH' ) ) {
if ( ! class_exists( 'um\core\Options' ) ) {
-
/**
* Class Options
* @package um\core
*/
class Options {
-
/**
* @var array
*/
- var $options = array();
-
+ private $options = array();
/**
* Options constructor.
*/
- function __construct() {
+ public function __construct() {
$this->init_variables();
}
-
/**
* Set variables
*/
- function init_variables() {
+ private function init_variables() {
$this->options = get_option( 'um_options', array() );
}
-
/**
- * Get UM option value
+ * Get UM option value.
*
- * @param $option_id
- * @return mixed|string|void
+ * @param string $option_id
+ *
+ * @return mixed
*/
- function get( $option_id ) {
+ public function get( $option_id ) {
if ( isset( $this->options[ $option_id ] ) ) {
/**
- * UM hook
+ * Filters the plugin option.
*
- * @type filter
- * @title um_get_option_filter__{$option_id}
- * @description Change UM option on get by $option_id
- * @input_vars
- * [{"var":"$option","type":"array","desc":"Option Value"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- * Change `option_1` value.
+ * function my_custom_option_1( $value ) {
+ * $value = 'option_1_custom_value';
+ * return $value;
* }
- * ?>
+ * add_filter( 'um_get_option_filter__option_1', 'my_custom_option_1' );
*/
return apply_filters( "um_get_option_filter__{$option_id}", $this->options[ $option_id ] );
}
@@ -72,35 +64,30 @@ if ( ! class_exists( 'um\core\Options' ) ) {
switch ( $option_id ) {
case 'site_name':
return get_bloginfo( 'name' );
- break;
case 'admin_email':
return get_bloginfo( 'admin_email' );
- break;
default:
return '';
- break;
}
}
-
/**
* Update UM option value
*
* @param $option_id
* @param $value
*/
- function update( $option_id, $value ) {
+ public function update( $option_id, $value ) {
$this->options[ $option_id ] = $value;
update_option( 'um_options', $this->options );
}
-
/**
* Delete UM option
*
* @param $option_id
*/
- function remove( $option_id ) {
+ public function remove( $option_id ) {
if ( ! empty( $this->options[ $option_id ] ) ) {
unset( $this->options[ $option_id ] );
}
@@ -108,16 +95,15 @@ if ( ! class_exists( 'um\core\Options' ) ) {
update_option( 'um_options', $this->options );
}
-
/**
* Get UM option default value
*
* @use UM()->config()
*
- * @param $option_id
+ * @param string $option_id
* @return mixed
*/
- function get_default( $option_id ) {
+ public function get_default( $option_id ) {
$settings_defaults = UM()->config()->settings_defaults;
if ( ! isset( $settings_defaults[ $option_id ] ) ) {
return false;
@@ -136,40 +122,58 @@ if ( ! class_exists( 'um\core\Options' ) ) {
* @return string
*/
public function get_predefined_page_option_key( $slug ) {
+ /**
+ * Filters the predefined page option key.
+ *
+ * @param {string} $option_key Predefined page option key.
+ *
+ * @return {string} Predefined page option key.
+ *
+ * @since 2.8.3
+ * @hook um_predefined_page_option_key
+ *
+ * @example Change option key for login predefined page.
+ * function my_um_predefined_page_option_key( $option_key ) {
+ * if ( 'core_login' === $option_key ) {
+ * $option_key = 'core_login_custom';
+ * }
+ * return $option_key;
+ * }
+ * add_filter( 'um_predefined_page_option_key', 'my_um_predefined_page_option_key' );
+ */
return apply_filters( 'um_predefined_page_option_key', "core_{$slug}" );
}
/**
* Get core page ID
*
+ * @todo Deprecate soon
+ *
* @param string $key
*
- * @return mixed|void
+ * @return string
*/
- function get_core_page_id( $key ) {
+ public function get_core_page_id( $key ) {
/**
- * UM hook
+ * Filters the predefined page option key.
*
- * @type filter
- * @title um_core_page_id_filter
- * @description Change UM page slug
- * @input_vars
- * [{"var":"$slug","type":"array","desc":"UM page slug"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- * Change option key for login predefined page.
+ * function my_um_core_page_id_filter( $page_key ) {
+ * if ( 'core_login' === $page_key ) {
+ * $page_key = 'core_login_custom';
+ * }
+ * return $page_key;
* }
- * ?>
+ * add_filter( 'um_core_page_id_filter', 'my_um_core_page_id_filter' );
*/
- return apply_filters( 'um_core_page_id_filter', 'core_' . $key );
+ return apply_filters( 'um_core_page_id_filter', $this->get_predefined_page_option_key( $key ) );
}
-
}
}
diff --git a/includes/core/class-password.php b/includes/core/class-password.php
index 3028456a..66a7bfcf 100644
--- a/includes/core/class-password.php
+++ b/includes/core/class-password.php
@@ -57,7 +57,7 @@ if ( ! class_exists( 'um\core\Password' ) ) {
array(
'act' => 'reset_password',
'hash' => $reset_key,
- 'login' => $user_data->user_login,
+ 'login' => rawurlencode( $user_data->user_login ),
),
um_get_core_page( 'password-reset' )
);
diff --git a/includes/core/class-profile.php b/includes/core/class-profile.php
index ca698a96..b469209e 100644
--- a/includes/core/class-profile.php
+++ b/includes/core/class-profile.php
@@ -418,6 +418,13 @@ if ( ! class_exists( 'um\core\Profile' ) ) {
if ( ! empty( $array ) ) {
foreach ( $array as $key ) {
if ( $key ) {
+ if ( '_um_last_login' === $key ) {
+ $show_last_login = get_user_meta( um_user( 'ID' ), 'um_show_last_login', true );
+ if ( ! empty( $show_last_login ) && 'no' === $show_last_login[0] ) {
+ continue;
+ }
+ }
+
$data = array();
if ( isset( UM()->builtin()->all_user_fields[ $key ] ) ) {
$data = UM()->builtin()->all_user_fields[ $key ];
diff --git a/includes/core/class-setup.php b/includes/core/class-setup.php
index 305397b1..ae67f0ac 100644
--- a/includes/core/class-setup.php
+++ b/includes/core/class-setup.php
@@ -213,7 +213,7 @@ KEY meta_value_indx (um_value(191))
$options = get_option( 'um_options', array() );
foreach ( $core_pages as $slug => $page_id ) {
- $key = UM()->options()->get_core_page_id( $slug );
+ $key = UM()->options()->get_predefined_page_option_key( $slug );
$options[ $key ] = $page_id;
}
diff --git a/includes/core/um-actions-account.php b/includes/core/um-actions-account.php
index 84544975..b761a49f 100644
--- a/includes/core/um-actions-account.php
+++ b/includes/core/um-actions-account.php
@@ -330,7 +330,7 @@ function um_submit_account_details( $args ) {
$v = sanitize_text_field( $v );
} elseif ( 'user_email' === $k ) {
$v = sanitize_email( $v );
- } elseif ( 'hide_in_members' === $k ) {
+ } elseif ( 'hide_in_members' === $k || 'um_show_last_login' === $k ) {
$v = array_map( 'sanitize_text_field', $v );
}
@@ -351,6 +351,13 @@ function um_submit_account_details( $args ) {
}
}
+ if ( isset( $changes['um_show_last_login'] ) ) {
+ if ( 'yes' === $changes['um_show_last_login'] || array_intersect( array( 'yes' ), $changes['um_show_last_login'] ) ) {
+ delete_user_meta( $user_id, 'um_show_last_login' );
+ unset( $changes['um_show_last_login'] );
+ }
+ }
+
/**
* UM hook
*
@@ -552,8 +559,13 @@ add_action( 'um_after_user_account_updated', 'um_after_user_account_updated_perm
* @param $changed
*/
function um_account_updated_notification( $user_id, $changed ) {
- um_fetch_user( $user_id );
- UM()->mail()->send( um_user( 'user_email' ), 'changedaccount_email' );
+ // phpcs:disable WordPress.Security.NonceVerification
+ if ( 'password' !== $_POST['_um_account_tab'] || ! UM()->options()->get( 'changedpw_email_on' ) ) {
+ // Avoid email duplicates (account changed and password changed) on the password change tab.
+ um_fetch_user( $user_id );
+ UM()->mail()->send( um_user( 'user_email' ), 'changedaccount_email' );
+ }
+ // phpcs:enable WordPress.Security.NonceVerification
}
add_action( 'um_after_user_account_updated', 'um_account_updated_notification', 20, 2 );
@@ -612,7 +624,7 @@ function um_after_account_privacy( $args ) {
$exports_url = wp_privacy_exports_url();
echo '' . esc_html__( 'You could download your previous data:', 'ultimate-member' ) . '
';
- echo ' ' . esc_html__( 'Download Personal Data', 'ultimate-member' ) . ' ';
+ echo '
' . esc_html__( 'Download Personal Data', 'ultimate-member' ) . ' ';
echo '
' . esc_html__( 'You could send a new request for an export of personal your data.', 'ultimate-member' ) . '
';
}
diff --git a/includes/core/um-actions-register.php b/includes/core/um-actions-register.php
index 5d4bf6ac..d79718c4 100644
--- a/includes/core/um-actions-register.php
+++ b/includes/core/um-actions-register.php
@@ -766,7 +766,7 @@ add_action( 'um_registration_set_extra_data', 'um_registration_set_profile_full_
* 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_predefined_page_option_key( 'register' ) );
// Do not redirect if the registration page is not published.
if ( ! empty( $page_id ) && 'publish' === get_post_status( $page_id ) ) {
// Not `um_safe_redirect()` because predefined register page is situated on the same host.
diff --git a/includes/core/um-filters-commenting.php b/includes/core/um-filters-commenting.php
index acadc17f..b6f6f570 100644
--- a/includes/core/um-filters-commenting.php
+++ b/includes/core/um-filters-commenting.php
@@ -1,37 +1,38 @@
-user_id ) && ! empty( $comment->user_id ) ){
+ if ( ! empty( $comment->user_id ) ) {
if ( isset( UM()->user()->cached_user[ $comment->user_id ] ) && UM()->user()->cached_user[ $comment->user_id ] ) {
-
- $return = '
' . UM()->user()->cached_user[$comment->user_id]['name'] . ' ';
-
+ $return = '
' . UM()->user()->cached_user[ $comment->user_id ]['name'] . ' ';
} else {
-
um_fetch_user( $comment->user_id );
- UM()->user()->cached_user[ $comment->user_id ] = array('url' => um_user_profile_url(), 'name' => um_user('display_name') );
- $return = '
' . UM()->user()->cached_user[$comment->user_id]['name'] . ' ';
+ UM()->user()->cached_user[ $comment->user_id ] = array(
+ 'url' => um_user_profile_url(),
+ 'name' => um_user( 'display_name' ),
+ );
+
+ $return = '
' . UM()->user()->cached_user[ $comment->user_id ]['name'] . ' ';
um_reset_user();
-
}
}
return $return;
}
-add_filter('get_comment_author_link', 'um_comment_link_to_profile', 10000, 3 );
\ No newline at end of file
+add_filter( 'get_comment_author_link', 'um_comment_link_to_profile', 10000, 3 );
diff --git a/includes/core/um-filters-fields.php b/includes/core/um-filters-fields.php
index 94423d43..251d4e63 100644
--- a/includes/core/um-filters-fields.php
+++ b/includes/core/um-filters-fields.php
@@ -3,24 +3,6 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
-/**
- * Field is required?
- *
- * @param $label
- * @param $data
- *
- * @return string
- */
-function um_edit_label_all_fields( $label, $data ) {
- $asterisk = UM()->options()->get( 'form_asterisk' );
- if ( $asterisk && ! empty( $data['required'] ) ) {
- $label .= '
* ';
- }
-
- return $label;
-}
-add_filter( 'um_edit_label_all_fields', 'um_edit_label_all_fields', 10, 2 );
-
/**
* Outputs a oEmbed field
*
@@ -114,7 +96,7 @@ add_filter( 'um_profile_field_filter_hook__youtube_video', 'um_profile_field_fil
function um_profile_field_filter_hook__spotify( $value, $data ) {
if ( preg_match( '/https:\/\/open.spotify.com\/.*/', $value ) ) {
if ( false !== strpos( $value, '/user/' ) ) {
- $value = '
' . esc_html( $value ) . ' ';
+ $value = '
' . esc_html( $value ) . ' ';
} else {
$url = str_replace( 'open.spotify.com/', 'open.spotify.com/embed/', $value );
@@ -162,12 +144,10 @@ add_filter( 'um_profile_field_filter_hook__vimeo_video', 'um_profile_field_filte
* @return int|string
*/
function um_profile_field_filter_hook__phone( $value, $data ) {
- $value = '
' . esc_html( $value ) . ' ';
+ $value = '
' . esc_html( $value ) . ' ';
return $value;
}
-add_filter( 'um_profile_field_filter_hook__phone_number', 'um_profile_field_filter_hook__phone', 99, 2 );
-add_filter( 'um_profile_field_filter_hook__mobile_number', 'um_profile_field_filter_hook__phone', 99, 2 );
-
+add_filter( 'um_profile_field_filter_hook__tel', 'um_profile_field_filter_hook__phone', 99, 2 );
/**
* Outputs a viber link
@@ -178,8 +158,9 @@ add_filter( 'um_profile_field_filter_hook__mobile_number', 'um_profile_field_fil
* @return int|string
*/
function um_profile_field_filter_hook__viber( $value, $data ) {
- $value = str_replace('+', '', $value);
- $value = '
' . esc_html( $value ) . ' ';
+ $value = str_replace( '+', '', $value );
+ $url = 'viber://chat?number=%2B' . $value;
+ $value = '
' . esc_html( $value ) . ' ';
return $value;
}
add_filter( 'um_profile_field_filter_hook__viber', 'um_profile_field_filter_hook__viber', 99, 2 );
@@ -194,8 +175,9 @@ add_filter( 'um_profile_field_filter_hook__viber', 'um_profile_field_filter_hook
* @return int|string
*/
function um_profile_field_filter_hook__whatsapp( $value, $data ) {
- $value = str_replace('+', '', $value);
- $value = '
' . esc_html( $value ) . ' ';
+ $value = str_replace( '+', '', $value );
+ $url = add_query_arg( array( 'phone' => $value ), 'https://api.whatsapp.com/send' );
+ $value = '
' . esc_html( $value ) . ' ';
return $value;
}
add_filter( 'um_profile_field_filter_hook__whatsapp', 'um_profile_field_filter_hook__whatsapp', 99, 2 );
@@ -391,7 +373,7 @@ function um_profile_field_filter_hook__file( $value, $data ) {
}
$value = '
-
+
' . esc_attr( $value ) . '
@@ -465,11 +447,13 @@ function um_profile_field_filter_hook__( $value, $data, $type = '' ) {
$url_rel = ( isset( $data['url_rel'] ) && 'nofollow' === $data['url_rel'] ) ? 'rel="nofollow"' : '';
$data['url_target'] = ( isset( $data['url_target'] ) ) ? $data['url_target'] : '_blank';
+ $protocols = wp_allowed_protocols();
if ( false === strstr( $value, 'join.skype.com' ) ) {
$value = 'skype:' . $value . '?chat';
+ $protocols[] = 'skype';
}
- $value = '
' . esc_html( $alt ) . ' ';
+ $value = '
' . esc_html( $alt ) . ' ';
} else {
// check $value is oEmbed
if ( 'oembed' === $data['type'] ) {
@@ -545,7 +529,7 @@ function um_profile_field_filter_hook__( $value, $data, $type = '' ) {
if ( ! is_array( $value ) ) {
if ( is_email( $value ) ) {
- $value = '
' . $value . ' ';
+ $value = '
' . $value . ' ';
}
} else {
$value = implode( ', ', $value );
diff --git a/includes/um-deprecated-hooks.php b/includes/um-deprecated-hooks.php
new file mode 100644
index 00000000..86a01327
--- /dev/null
+++ b/includes/um-deprecated-hooks.php
@@ -0,0 +1,47 @@
+Change UM language locale.
+ * function my_um_language_locale( $language_locale ) {
+ * $language_locale = 'es_ES';
+ * return $language_locale;
+ * }
+ * add_filter( 'um_language_locale', 'my_um_language_locale' );
+ */
+
+/**
+ * Filters the path to the language file (*.mo).
+ *
+ * @param {string} $language_file Default path to the language file.
+ *
+ * @return {string} Language file path.
+ *
+ * @since 1.3.x
+ * @depecated 2.8.5 Used WordPress native `load_plugin_textdomain()`. And can be replaced via WordPress native hook 'load_textdomain_mofile'.
+ * @hook um_language_file
+ *
+ * @example
Change UM language file path.
+ * function my_um_language_file( $language_file ) {
+ * $language_file = '{path-to-language-file}';
+ * return $language_file;
+ * }
+ * add_filter( 'um_language_file', 'my_um_language_file' );
+ */
diff --git a/includes/um-short-functions.php b/includes/um-short-functions.php
index 0b8e7d98..a26f0d5a 100644
--- a/includes/um-short-functions.php
+++ b/includes/um-short-functions.php
@@ -870,7 +870,7 @@ function um_user_submited_display( $k, $title, $data = array(), $style = true )
}
if ( ! empty( $filedata['original_name'] ) ) {
- $v = '
' . esc_html( $filedata['original_name'] ) . ' ';
+ $v = '
' . esc_html( $filedata['original_name'] ) . ' ';
} else {
$v = $baseurl . um_user( 'ID' ) . '/' . $file;
}
diff --git a/readme.txt b/readme.txt
index 4dfcefec..f628c62e 100644
--- a/readme.txt
+++ b/readme.txt
@@ -2,12 +2,11 @@
Author URI: https://ultimatemember.com/
Plugin URI: https://ultimatemember.com/
Contributors: ultimatemember, champsupertramp, nsinelnikov
-Donate link:
Tags: community, member, membership, user-profile, user-registration
Requires PHP: 5.6
Requires at least: 5.5
-Tested up to: 6.4
-Stable tag: 2.8.4
+Tested up to: 6.5
+Stable tag: 2.8.5
License: GNU Version 2 or Any Later Version
License URI: http://www.gnu.org/licenses/gpl-3.0.txt
@@ -167,6 +166,25 @@ No specific extensions are needed. But we highly recommended keep active these P
IMPORTANT: PLEASE UPDATE THE PLUGIN TO AT LEAST VERSION 2.6.7 IMMEDIATELY. VERSION 2.6.7 PATCHES SECURITY PRIVILEGE ESCALATION VULNERABILITY. PLEASE SEE [THIS ARTICLE](https://docs.ultimatemember.com/article/1866-security-incident-update-and-recommended-actions) FOR MORE INFORMATION
+= 2.8.5 2024-04-09 =
+
+**Enhancements**
+
+* Added: "Hide my last login" via the Account > Privacy setting
+* Added: Exclude and Include fields for member directory searching
+* Tweak: Compatibility with WordPress 6.5
+
+**Bugfixes**
+
+* Fixed: URL attributes escaping (CVE-2024-2765)
+* Fixed: wp-admin Ultimate Member > Dashboard layouts
+* Fixed: Required fields labels
+* Fixed: Change password and update account email notifications duplicates
+* Fixed: Reset Password urlencoded username
+* Fixed: Clear media JS in wp-admin settings
+
+**Cached and optimized/minified assets(JS/CSS) must be flushed/re-generated after upgrade**
+
= 2.8.4 2024-03-06 =
**Enhancements**
@@ -181,6 +199,8 @@ IMPORTANT: PLEASE UPDATE THE PLUGIN TO AT LEAST VERSION 2.6.7 IMMEDIATELY. VERSI
* Fixed: Password reset url for the approved user who didn't set their password after registration without password
* Fixed: Conflict with WebP Uploads
+**Cached and optimized/minified assets(JS/CSS) must be flushed/re-generated after upgrade**
+
= 2.8.3 2024-02-19 =
**Enhancements**
@@ -313,6 +333,9 @@ IMPORTANT: PLEASE UPDATE THE PLUGIN TO AT LEAST VERSION 2.6.7 IMMEDIATELY. VERSI
== Upgrade Notice ==
+= 2.8.5 =
+This version fixes a security related bug. Upgrade immediately.
+
= 2.8.4 =
This version fixes a security related bug. Upgrade immediately.
diff --git a/ultimate-member.php b/ultimate-member.php
index 1498f852..d7e522b3 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.8.4
+ * Version: 2.8.5
* Author: Ultimate Member
* Author URI: http://ultimatemember.com/
* Text Domain: ultimate-member