mirror of
https://github.com/10h30/ultimatemember.git
synced 2026-07-11 18:56:10 +09:00
Merge pull request #1667 from ultimatemember/development/2.9.x
Version 2.10.3
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
"step": "installPlugin",
|
||||
"pluginZipFile": {
|
||||
"resource": "url",
|
||||
"url": "https:\/\/downloads.wordpress.org\/plugin\/ultimate-member.2.10.2.zip"
|
||||
"url": "https:\/\/downloads.wordpress.org\/plugin\/ultimate-member.2.10.3.zip"
|
||||
},
|
||||
"options": {
|
||||
"activate": true
|
||||
|
||||
@@ -44,7 +44,7 @@ GNU Version 2 or Any Later Version
|
||||
|
||||
### 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
|
||||
|
||||
[Official Release Version: 2.10.2](https://github.com/ultimatemember/ultimatemember/releases/tag/2.10.2).
|
||||
[Official Release Version: 2.10.3](https://github.com/ultimatemember/ultimatemember/releases/tag/2.10.3).
|
||||
|
||||
## Changelog
|
||||
|
||||
|
||||
@@ -495,6 +495,11 @@
|
||||
line-height: 18px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
.um-admin-drag-col.cols-3 .um-admin-drag-fld-banned {
|
||||
height: auto;
|
||||
line-height: 18px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
.um-admin-drag-col.cols-3 .um-admin-drag-fld-icons {
|
||||
float: none;
|
||||
position: absolute;
|
||||
@@ -600,6 +605,16 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.um-admin-drag-fld-banned {
|
||||
float: left;
|
||||
font-size: 13px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin: 0 0 0 20px;
|
||||
font-weight: 400;
|
||||
color: var(--um-blocks-error-color, #d92d20);
|
||||
}
|
||||
|
||||
.um-admin-drag-fld-icons {
|
||||
float: right;
|
||||
}
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -400,6 +400,10 @@
|
||||
height: auto
|
||||
line-height: 18px
|
||||
margin: 0 0 10px 0
|
||||
.#{$prefix}admin-drag-fld-banned
|
||||
height: auto
|
||||
line-height: 18px
|
||||
margin: 0 0 10px 0
|
||||
.#{$prefix}admin-drag-fld-icons
|
||||
float: none
|
||||
position: absolute
|
||||
@@ -492,6 +496,14 @@
|
||||
&.um-field-type-group
|
||||
color: #fff
|
||||
|
||||
.#{$prefix}admin-drag-fld-banned
|
||||
float: left
|
||||
font-size: 13px
|
||||
height: 30px
|
||||
line-height: 30px
|
||||
margin: 0 0 0 20px
|
||||
font-weight: 400
|
||||
color: $error-text
|
||||
|
||||
.#{$prefix}admin-drag-fld-icons
|
||||
float: right
|
||||
|
||||
@@ -582,6 +582,7 @@ body #content .um-directory a:hover, body #content .um-directory a:focus {
|
||||
background-color: #eee;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
min-height: 50px;
|
||||
}
|
||||
.um-directory .um-members-wrapper .um-members.um-members-grid .um-member .um-member-cover[data-ratio] {
|
||||
overflow-y: hidden;
|
||||
@@ -1248,4 +1249,4 @@ body #content .um-directory a:hover, body #content .um-directory a:focus {
|
||||
|
||||
.select2-container .select2-results li.select2-results__option[aria-disabled=true] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,6 +435,7 @@ body
|
||||
background-color: #eee
|
||||
box-sizing: border-box
|
||||
position: relative
|
||||
min-height: 50px
|
||||
&[data-ratio]
|
||||
overflow-y: hidden
|
||||
.um-member-cover-e
|
||||
@@ -1005,4 +1006,4 @@ body
|
||||
|
||||
|
||||
.select2-container .select2-results li.select2-results__option[aria-disabled=true]
|
||||
display: none
|
||||
display: none
|
||||
|
||||
@@ -89,7 +89,9 @@ jQuery(window).on( 'load', function($) {
|
||||
jQuery(mutation.addedNodes).find('.um-member').each(function() {
|
||||
let wrapper = document.querySelector('.um-member');
|
||||
let directory = jQuery(this).parent();
|
||||
UM_Member_Grid(directory);
|
||||
if (directory.hasClass('um-members-grid')) {
|
||||
UM_Member_Grid(directory);
|
||||
}
|
||||
|
||||
if (wrapper) {
|
||||
wrapper.addEventListener('click', (event) => {
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
== Changelog ==
|
||||
|
||||
= 2.10.3 April 24, 2025 =
|
||||
|
||||
* Enhancements:
|
||||
|
||||
- Added: The `Ignore the "User Role > Registration Options"` setting. It provides an ability to auto-approve users if they were created via wp-admin > Users screen.
|
||||
- Tweak: Avoid email notifications to Administrator about user registration via wp-admin > Users screen.
|
||||
- Tweak: Updated the Action Scheduler implementation to improve flexibility and clarity. Refactor Action Scheduler for not only email handling.
|
||||
|
||||
* Bugfixes:
|
||||
|
||||
- Fixed: Member Directory styles when it's rendered on the Gutenberg builder page.
|
||||
- Fixed: Member Directory filtering query when the custom users metatable is used.
|
||||
- Fixed: PHP Warning that occurs when using the `getimagesize` function with an image from an external source.
|
||||
- Fixed: Reset Password email notification's the {password_reset_link}` placeholder.
|
||||
- Fixed: Changed "Turkey" to the current official term "Türkiye".
|
||||
|
||||
* Cached and optimized/minified assets(JS/CSS) must be flushed/re-generated after upgrade *
|
||||
|
||||
= 2.10.2 April 02, 2025 =
|
||||
|
||||
* Enhancements:
|
||||
|
||||
@@ -43,13 +43,13 @@ if ( ! class_exists( 'um\action_scheduler\Init' ) ) {
|
||||
public function __construct() {
|
||||
if ( ! $this->can_be_active() ) {
|
||||
add_action( 'init', array( $this, 'add_notice' ) );
|
||||
add_filter( 'um_site_health_extend', array( $this, 'change_site_health' ) );
|
||||
} else {
|
||||
add_filter( 'um_settings_structure', array( $this, 'add_setting' ) );
|
||||
|
||||
if ( UM()->options()->get( 'enable_action_scheduler' ) ) {
|
||||
$this->enabled = true;
|
||||
$this->load_library( true );
|
||||
}
|
||||
// Since 2.10.3 we load library as soon as there are required library files.
|
||||
// Options above are used for enable/disable some Action Scheduler hooks e.g. um_dispatch_email.
|
||||
$this->enabled = true;
|
||||
$this->load_library( true );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,18 @@ if ( ! class_exists( 'um\action_scheduler\Init' ) ) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Action Scheduler setting to Ultimate Member feature settings
|
||||
*
|
||||
* @param array $settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function change_site_health( $site_health ) {
|
||||
$site_health['ultimate-member']['fields']['enable_as_email_sending']['value'] = __( 'No', 'ultimate-member' );
|
||||
return $site_health;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Action Scheduler setting to Ultimate Member feature settings
|
||||
*
|
||||
@@ -77,11 +89,11 @@ if ( ! class_exists( 'um\action_scheduler\Init' ) ) {
|
||||
*/
|
||||
public function add_setting( $settings ) {
|
||||
$settings['advanced']['sections']['features']['form_sections']['features']['fields'][] = array(
|
||||
'id' => 'enable_action_scheduler',
|
||||
'id' => 'enable_as_email_sending',
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Action Scheduler', 'ultimate-member' ),
|
||||
'checkbox_label' => __( 'Enable Action Scheduler', 'ultimate-member' ),
|
||||
'description' => __( 'Check this box if you want to use the Ultimate Member action scheduler. By enabling it, certain tasks like sending system emails will be scheduled to run at optimal times, which can help reduce the load on your server', 'ultimate-member' ),
|
||||
'label' => __( 'Email sending by Action Scheduler', 'ultimate-member' ),
|
||||
'checkbox_label' => __( 'Enable Action Scheduler for Ultimate Member emails sending', 'ultimate-member' ),
|
||||
'description' => __( 'Check this box if you want to use the Action Scheduler for Ultimate Member emails sending. By enabling it, sending system emails will be scheduled to run at optimal times, which can help reduce the load on your server', 'ultimate-member' ),
|
||||
);
|
||||
|
||||
return $settings;
|
||||
@@ -131,6 +143,10 @@ if ( ! class_exists( 'um\action_scheduler\Init' ) ) {
|
||||
return $this->verify_wc_action_scheduler() || $this->load_library();
|
||||
}
|
||||
|
||||
public function is_hook_enabled( $hook ) {
|
||||
return apply_filters( 'um_action_scheduler_is_hook_enabled', $this->is_enabled(), $hook );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue an action to run one time, as soon as possible.
|
||||
* If Action Scheduler is disabled then do_action_ref_array is called to run action right away.
|
||||
@@ -144,11 +160,12 @@ if ( ! class_exists( 'um\action_scheduler\Init' ) ) {
|
||||
* @return int Еhe action’s ID. Zero if there was an error scheduling the action. The error will be sent to error_log
|
||||
*/
|
||||
public function enqueue_async_action( $hook, $args = array(), $group = '', $unique = false, $priority = 10 ) {
|
||||
if ( $this->enabled ) {
|
||||
if ( $this->is_hook_enabled( $hook ) ) {
|
||||
$group = $this->set_group( $group );
|
||||
return as_enqueue_async_action( $hook, $args, $group, $unique, $priority );
|
||||
}
|
||||
|
||||
// Make then standard action without Action Scheduler.
|
||||
do_action_ref_array( $hook, $args );
|
||||
return 0;
|
||||
}
|
||||
@@ -166,11 +183,12 @@ if ( ! class_exists( 'um\action_scheduler\Init' ) ) {
|
||||
* @return int The action’s ID. Zero if there was an error scheduling the action. The error will be sent to error_log.
|
||||
*/
|
||||
public function schedule_single_action( $timestamp, $hook, $args = array(), $group = '', $unique = false, $priority = 10 ) {
|
||||
if ( $this->enabled ) {
|
||||
if ( $this->is_hook_enabled( $hook ) ) {
|
||||
$group = $this->set_group( $group );
|
||||
return as_schedule_single_action( $timestamp, $hook, $args, $group, $unique, $priority );
|
||||
}
|
||||
|
||||
// Make then standard action without Action Scheduler.
|
||||
do_action_ref_array( $hook, $args );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ final class Enqueue extends \um\common\Enqueue {
|
||||
wp_register_style( 'um_responsive', $css_url . 'um-responsive' . $suffix . '.css', array( 'um_profile' ), UM_VERSION );
|
||||
wp_register_style( 'um_account', $css_url . 'um-account' . $suffix . '.css', array(), UM_VERSION );
|
||||
wp_register_style( 'um_default_css', $css_url . 'um-old-default' . $suffix . '.css', array(), UM_VERSION );
|
||||
wp_register_style( 'um_misc', $css_url . 'um-misc' . $suffix . '.css', array( 'um_styles' ), UM_VERSION );
|
||||
|
||||
wp_register_style( 'um_datetime', $libs_url . 'pickadate/default' . $suffix . '.css', array(), '3.6.2' );
|
||||
wp_register_style( 'um_datetime_date', $libs_url . 'pickadate/default.date' . $suffix . '.css', array( 'um_datetime' ), '3.6.2' );
|
||||
@@ -209,6 +210,7 @@ final class Enqueue extends \um\common\Enqueue {
|
||||
wp_enqueue_style( 'um_profile' );
|
||||
wp_enqueue_style( 'um_responsive' );
|
||||
wp_enqueue_style( 'um_account' );
|
||||
wp_enqueue_style( 'um_misc' );
|
||||
|
||||
wp_enqueue_style( 'um_datetime_date' );
|
||||
wp_enqueue_style( 'um_datetime_time' );
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace um\admin;
|
||||
|
||||
use WP_Query;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
@@ -48,6 +50,20 @@ class Site_Health {
|
||||
);
|
||||
}
|
||||
|
||||
// Searching in the global registered custom fields banned or blacklisted fields.
|
||||
$custom_fields = get_option( 'um_fields', array() );
|
||||
if ( ! empty( $custom_fields ) ) {
|
||||
foreach ( array_keys( $custom_fields ) as $key ) {
|
||||
if ( self::field_is_banned( $key ) ) {
|
||||
$tests['direct']['um_banned_fields'] = array(
|
||||
'label' => esc_html__( 'Are the banned custom fields?', 'ultimate-member' ),
|
||||
'test' => array( $this, 'banned_fields_test' ),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
@@ -210,6 +226,132 @@ class Site_Health {
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function field_is_banned( $metakey ) {
|
||||
return UM()->user()->is_metakey_banned( $metakey ) || in_array( strtolower( $metakey ), UM()->builtin()->blacklist_fields, true );
|
||||
}
|
||||
|
||||
public function get_banned_fields() {
|
||||
$result = array(
|
||||
'description' => '',
|
||||
'actions' => '',
|
||||
);
|
||||
|
||||
$forms = get_posts(
|
||||
array(
|
||||
'post_type' => 'um_form',
|
||||
'posts_per_page' => -1,
|
||||
'fields' => 'ids',
|
||||
)
|
||||
);
|
||||
|
||||
$forms_count = 0;
|
||||
$break_forms = array();
|
||||
if ( ! empty( $forms ) ) {
|
||||
foreach ( $forms as $form_id ) {
|
||||
$fields = UM()->query()->get_attr( 'custom_fields', $form_id );
|
||||
if ( empty( $fields ) ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $fields as $field ) {
|
||||
if ( empty( $field['metakey'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( self::field_is_banned( $field['metakey'] ) ) {
|
||||
if ( ! array_key_exists( $form_id, $break_forms ) ) {
|
||||
$break_forms[ $form_id ] = array(
|
||||
'title' => get_the_title( $form_id ),
|
||||
'link' => get_edit_post_link( $form_id ),
|
||||
'fields' => array(
|
||||
$field['metakey'] => isset( $field['title'] ) ? $field['title'] : __( 'Unknown title', 'ultimate-member' ),
|
||||
),
|
||||
);
|
||||
|
||||
++$forms_count;
|
||||
} else {
|
||||
$break_forms[ $form_id ]['fields'][ $field['metakey'] ] = isset( $field['title'] ) ? $field['title'] : __( 'Unknown title', 'ultimate-member' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 < $forms_count ) {
|
||||
$result['description'] .= sprintf(
|
||||
'<p>%s</p>',
|
||||
__( 'Please note that some fields in your Ultimate Member Forms are currently on a restricted list that disallows their use. This is particularly related to the Ultimate Member Forms and their fields below.', 'ultimate-member' )
|
||||
);
|
||||
|
||||
if ( ! empty( $break_forms ) ) {
|
||||
$forms_description = array();
|
||||
foreach ( $break_forms as $form_id => $form_data ) {
|
||||
$fields = array();
|
||||
foreach ( $form_data['fields'] as $metakey => $field_title ) {
|
||||
$fields[] = sprintf( __( '%s (<code>%s</code>)', 'ultimate-member' ), $field_title, $metakey );
|
||||
}
|
||||
|
||||
$forms_description[] = '<h4>' . sprintf(
|
||||
__( 'Fields in <a href="%s" target="_blank">%s (#ID: %s)</a>:', 'ultimate-member' ),
|
||||
esc_url( $form_data['link'] ),
|
||||
esc_html( $form_data['title'] ),
|
||||
esc_html( $form_id )
|
||||
) . '</h4><ul><li>' . implode( '</li><li>', $fields ) . '</li></ul>';
|
||||
}
|
||||
|
||||
$result['description'] .= implode( ' ', $forms_description );
|
||||
}
|
||||
|
||||
$result['actions'] .= sprintf(
|
||||
'<p><a href="%s">%s</a></p>',
|
||||
admin_url( 'edit.php?post_type=um_form' ),
|
||||
esc_html__( 'Edit form fields and update', 'ultimate-member' )
|
||||
);
|
||||
}
|
||||
|
||||
$result = apply_filters( 'um_get_banned_fields_result', $result );
|
||||
|
||||
if ( ! empty( $result['description'] ) ) {
|
||||
$result['description'] .= sprintf(
|
||||
'<p>%s</p>',
|
||||
__( 'The using meta keys from restricted list in Ultimate Member Forms may break the website\'s functionality and is unsecure.', 'ultimate-member' )
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $result['description'] ) && ! empty( $result['actions'] ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function banned_fields_test() {
|
||||
$result = array(
|
||||
'label' => __( 'You have correct Ultimate Member fields', 'ultimate-member' ),
|
||||
'status' => 'good',
|
||||
'badge' => array(
|
||||
'label' => UM_PLUGIN_NAME,
|
||||
'color' => self::BADGE_COLOR,
|
||||
),
|
||||
'description' => sprintf(
|
||||
'<p>%s</p>',
|
||||
__( 'Your all custom Ultimate Member fields are correct.', 'ultimate-member' )
|
||||
),
|
||||
'actions' => '',
|
||||
'test' => 'um_banned_fields',
|
||||
);
|
||||
|
||||
$banned_fields = $this->get_banned_fields();
|
||||
if ( false !== $banned_fields ) {
|
||||
$result['label'] = __( 'Some field from Ultimate Member forms has banned meta key', 'ultimate-member' );
|
||||
$result['status'] = 'critical';
|
||||
$result['badge']['color'] = 'red';
|
||||
$result['description'] = $banned_fields['description'];
|
||||
$result['actions'] = $banned_fields['actions'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function get_roles() {
|
||||
return UM()->roles()->get_roles();
|
||||
}
|
||||
@@ -240,7 +382,7 @@ class Site_Health {
|
||||
}
|
||||
|
||||
private function get_field_data( $info, $key, $field_key, $field ) {
|
||||
$row = isset( $field['metakey'] ) ? false : true;
|
||||
$row = array_key_exists( 'type', $field ) && 'row' === $field['type'];
|
||||
$title = $row ? __( 'Row: ', 'ultimate-member' ) . $field['id'] : __( 'Field: ', 'ultimate-member' ) . $field['metakey'];
|
||||
$field = array_map( array( &$this, 'array_map' ), $field );
|
||||
$field_info = array(
|
||||
@@ -254,7 +396,7 @@ class Site_Health {
|
||||
}
|
||||
|
||||
private function get_member_directories() {
|
||||
$query = new \WP_Query();
|
||||
$query = new WP_Query();
|
||||
$member_directories = $query->query(
|
||||
array(
|
||||
'post_type' => 'um_directory',
|
||||
@@ -372,6 +514,10 @@ class Site_Health {
|
||||
'label' => __( 'Use Gravatars?', 'ultimate-member' ),
|
||||
'value' => UM()->options()->get( 'use_gravatars' ) ? $labels['yes'] : $labels['no'],
|
||||
),
|
||||
'um-admin_ignore_user_status' => array(
|
||||
'label' => __( 'Ignore the "User Role > Registration Options" if this user is added from the wp-admin dashboard', 'ultimate-member' ),
|
||||
'value' => UM()->options()->get( 'admin_ignore_user_status' ) ? $labels['yes'] : $labels['no'],
|
||||
),
|
||||
'um-delete_comments' => array(
|
||||
'label' => __( 'Deleting user comments after deleting a user', 'ultimate-member' ),
|
||||
'value' => UM()->options()->get( 'delete_comments' ) ? $labels['yes'] : $labels['no'],
|
||||
@@ -1080,6 +1226,10 @@ class Site_Health {
|
||||
'label' => __( 'Enable Gutenberg Blocks', 'ultimate-member' ),
|
||||
'value' => UM()->options()->get( 'enable_blocks' ) ? $labels['yes'] : $labels['no'],
|
||||
),
|
||||
'um-enable_as_email_sending' => array(
|
||||
'label' => __( 'Email sending by Action Scheduler', 'ultimate-member' ),
|
||||
'value' => UM()->options()->get( 'enable_as_email_sending' ) ? $labels['yes'] : $labels['no'],
|
||||
),
|
||||
'um-rest_api_version' => array(
|
||||
'label' => __( 'REST API version', 'ultimate-member' ),
|
||||
'value' => UM()->options()->get( 'rest_api_version' ),
|
||||
@@ -1627,10 +1777,8 @@ class Site_Health {
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( array_key_exists( '_um_login_redirect_url', $rolemeta ) && 'redirect_url' === $rolemeta['_um_login_redirect_url'] ) {
|
||||
if ( array_key_exists( '_um_pending_url', $rolemeta ) ) {
|
||||
if ( 'redirect_url' === $rolemeta['_um_after_login'] && array_key_exists( '_um_login_redirect_url', $rolemeta ) ) {
|
||||
$info[ 'ultimate-member-' . $key ]['fields'] = array_merge(
|
||||
$info[ 'ultimate-member-' . $key ]['fields'],
|
||||
array(
|
||||
@@ -1660,10 +1808,8 @@ class Site_Health {
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'redirect_url' === $rolemeta['_um_after_logout'] ) {
|
||||
if ( array_key_exists( '_um_logout_redirect_url', $rolemeta ) ) {
|
||||
if ( 'redirect_url' === $rolemeta['_um_after_logout'] && array_key_exists( '_um_logout_redirect_url', $rolemeta ) ) {
|
||||
$info[ 'ultimate-member-' . $key ]['fields'] = array_merge(
|
||||
$info[ 'ultimate-member-' . $key ]['fields'],
|
||||
array(
|
||||
@@ -1689,10 +1835,8 @@ class Site_Health {
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'redirect_url' === $rolemeta['_um_after_delete'] ) {
|
||||
if ( array_key_exists( '_um_delete_redirect_url', $rolemeta ) ) {
|
||||
if ( 'redirect_url' === $rolemeta['_um_after_delete'] && array_key_exists( '_um_delete_redirect_url', $rolemeta ) ) {
|
||||
$info[ 'ultimate-member-' . $key ]['fields'] = array_merge(
|
||||
$info[ 'ultimate-member-' . $key ]['fields'],
|
||||
array(
|
||||
@@ -1706,17 +1850,15 @@ class Site_Health {
|
||||
}
|
||||
|
||||
if ( ! empty( $rolemeta['wp_capabilities'] ) ) {
|
||||
if ( array_key_exists( 'wp_capabilities', $rolemeta ) ) {
|
||||
$info[ 'ultimate-member-' . $key ]['fields'] = array_merge(
|
||||
$info[ 'ultimate-member-' . $key ]['fields'],
|
||||
array(
|
||||
'um-wp_capabilities' => array(
|
||||
'label' => __( 'WP Capabilities', 'ultimate-member' ),
|
||||
'value' => $rolemeta['wp_capabilities'],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
$info[ 'ultimate-member-' . $key ]['fields'] = array_merge(
|
||||
$info[ 'ultimate-member-' . $key ]['fields'],
|
||||
array(
|
||||
'um-wp_capabilities' => array(
|
||||
'label' => __( 'WP Capabilities', 'ultimate-member' ),
|
||||
'value' => $rolemeta['wp_capabilities'],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$info = apply_filters( 'um_debug_information_user_role', $info, $key );
|
||||
@@ -2160,11 +2302,7 @@ class Site_Health {
|
||||
)
|
||||
);
|
||||
} else {
|
||||
if ( isset( $options[ $field ] ) ) {
|
||||
$sortby_label = $options[ $field ];
|
||||
} else {
|
||||
$sortby_label = $field;
|
||||
}
|
||||
$sortby_label = isset( $options[ $field ] ) ? $options[ $field ] : $field;
|
||||
$info[ 'ultimate-member-directory-' . $key ]['fields'] = array_merge(
|
||||
$info[ 'ultimate-member-directory-' . $key ]['fields'],
|
||||
array(
|
||||
@@ -2419,6 +2557,17 @@ class Site_Health {
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
/**
|
||||
* Filters the site health information.
|
||||
*
|
||||
* @hook um_site_health_extend
|
||||
*
|
||||
* @since 2.10.3
|
||||
*
|
||||
* @param {array} $info The site health info to be filtered.
|
||||
*
|
||||
* @return {array} The filtered site health info.
|
||||
*/
|
||||
return apply_filters( 'um_site_health_extend', $info );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,9 +350,6 @@ if ( ! class_exists( 'um\admin\Users_Columns' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default statuses if not already done.
|
||||
UM()->setup()->set_default_user_status();
|
||||
|
||||
$id = 'um_user_status';
|
||||
|
||||
// need to add there additional nonce field because WordPress native _wpnonce field isn't visible on the users.php screen then custom actions
|
||||
|
||||
@@ -546,6 +546,9 @@ if ( ! class_exists( 'um\admin\core\Admin_Builder' ) ) {
|
||||
<?php echo ! empty( $field_title ) ? esc_html( $field_title ) : esc_html__( '(no title)', 'ultimate-member' ); ?>
|
||||
</div>
|
||||
<div class="um-admin-drag-fld-type um-field-type-<?php echo esc_attr( $field_type ); ?>"><?php echo esc_html( $field_name ); ?></div>
|
||||
<?php if ( UM()->user()->is_metakey_banned( $key ) || in_array( strtolower( $key ), UM()->builtin()->blacklist_fields, true ) ) { ?>
|
||||
<div class="um-admin-drag-fld-banned um-field-type-<?php echo esc_attr( $field_type ); ?>"><?php esc_html_e( 'This is not permitted for security reasons. For your safety, please remove it.', 'ultimate-member' ); ?></div>
|
||||
<?php } ?>
|
||||
<div class="um-admin-drag-fld-icons um-field-type-<?php echo esc_attr( $field_type ); ?>">
|
||||
<a href="javascript:void(0);" class="um-tip-n" title="<?php esc_attr_e( 'Edit', 'ultimate-member' ); ?>" data-modal="UM_edit_field" data-modal-size="normal" data-dynamic-content="um_admin_edit_field_popup" data-arg1="<?php echo esc_attr( $field_type ); ?>" data-arg2="<?php echo esc_attr( $this->form_id ); ?>" data-arg3="<?php echo esc_attr( $key ); ?>"><i class="um-faicon-pencil"></i></a>
|
||||
<a href="javascript:void(0);" class="um-tip-n um_admin_duplicate_field" title="<?php esc_attr_e( 'Duplicate', 'ultimate-member' ); ?>" data-silent_action="um_admin_duplicate_field" data-arg1="<?php echo esc_attr( $key ); ?>" data-arg2="<?php echo esc_attr( $this->form_id ); ?>"><i class="um-faicon-files-o"></i></a>
|
||||
|
||||
@@ -47,6 +47,8 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
|
||||
$this->lock_registration();
|
||||
|
||||
$this->empty_status_users();
|
||||
|
||||
$this->extensions_page();
|
||||
|
||||
$this->child_theme_required();
|
||||
@@ -204,17 +206,17 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
|
||||
ob_start(); ?>
|
||||
|
||||
<div class="<?php echo esc_attr( $class ) ?> um-admin-notice notice <?php echo $dismissible ? 'is-dismissible' : '' ?>" data-key="<?php echo esc_attr( $key ) ?>">
|
||||
<?php echo ! empty( $notice_data['message'] ) ? $notice_data['message'] : '' ?>
|
||||
<div class="<?php echo esc_attr( $class ); ?> um-admin-notice notice <?php echo $dismissible ? 'is-dismissible' : ''; ?>" data-key="<?php echo esc_attr( $key ); ?>">
|
||||
<?php echo ! empty( $notice_data['message'] ) ? $notice_data['message'] : ''; ?>
|
||||
</div>
|
||||
|
||||
<?php $notice = ob_get_clean();
|
||||
<?php
|
||||
$notice = ob_get_clean();
|
||||
if ( $echo ) {
|
||||
echo $notice;
|
||||
return;
|
||||
} else {
|
||||
return $notice;
|
||||
}
|
||||
return $notice;
|
||||
}
|
||||
|
||||
|
||||
@@ -246,6 +248,37 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking if the "Membership - Anyone can register" WordPress general setting is active
|
||||
*/
|
||||
public function empty_status_users() {
|
||||
$empty_status_users = get_option( '_um_log_empty_status_users', array( 0, 0 ) );
|
||||
if ( ! is_array( $empty_status_users ) ) {
|
||||
$empty_status_users = array( 0, 0 );
|
||||
}
|
||||
|
||||
if ( array( 0, 0 ) === $empty_status_users ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$allowed_html = array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
),
|
||||
'strong' => array(),
|
||||
);
|
||||
|
||||
$this->add_notice(
|
||||
'empty_status_users',
|
||||
array(
|
||||
'class' => 'info',
|
||||
// translators: %1$d: Background update for users is complete; %2$d: Total users for background update.
|
||||
'message' => '<p>' . wp_kses( sprintf( __( 'Background process is running: Setting user statuses %1$d/%2$d.', 'ultimate-member' ), $empty_status_users[0], $empty_status_users[1] ), $allowed_html ) . '</p>',
|
||||
'dismissible' => false,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking if the "Membership - Anyone can register" WordPress general setting is active
|
||||
*/
|
||||
@@ -256,11 +289,11 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?php _e( '<strong>All Access Pass</strong> – Get access to all Ultimate Member extensions at a significant discount with our All Access Pass.', 'ultimate-member' ) ?>
|
||||
<?php _e( '<strong>All Access Pass</strong> – Get access to all Ultimate Member extensions at a significant discount with our All Access Pass.', 'ultimate-member' ); ?>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://ultimatemember.com/pricing/" class="button button-primary" target="_blank">
|
||||
<?php _e( 'View Pricing', 'ultimate-member' ) ?>
|
||||
<?php esc_html_e( 'View Pricing', 'ultimate-member' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -290,7 +323,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
$path = str_replace( '//', '/', $path );
|
||||
|
||||
if ( ! file_exists( $path ) ) {
|
||||
$old = umask(0);
|
||||
$old = umask( 0 );
|
||||
@mkdir( $path, 0777, true );
|
||||
umask( $old );
|
||||
}
|
||||
@@ -326,9 +359,12 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
'woocommerce',
|
||||
);
|
||||
|
||||
$slugs = array_map( function( $item ) {
|
||||
return 'um-' . $item . '/um-' . $item . '.php';
|
||||
}, $old_extensions );
|
||||
$slugs = array_map(
|
||||
function ( $item ) {
|
||||
return 'um-' . $item . '/um-' . $item . '.php';
|
||||
},
|
||||
$old_extensions
|
||||
);
|
||||
|
||||
$active_plugins = UM()->dependencies()->get_active_plugins();
|
||||
foreach ( $slugs as $slug ) {
|
||||
@@ -622,7 +658,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
$arr_inactive_license_keys[] = $license->item_name;
|
||||
}
|
||||
|
||||
$invalid_license++;
|
||||
++$invalid_license;
|
||||
}
|
||||
|
||||
if ( ! empty( $arr_inactive_license_keys ) ) {
|
||||
@@ -676,34 +712,41 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="<?php echo esc_url( $url ) ?>" class="button button-primary"><?php esc_html_e( 'Visit Upgrade Page', 'ultimate-member' ); ?></a>
|
||||
<a href="<?php echo esc_url( $url ); ?>" class="button button-primary"><?php esc_html_e( 'Visit Upgrade Page', 'ultimate-member' ); ?></a>
|
||||
|
||||
</p>
|
||||
|
||||
<?php $message = ob_get_clean();
|
||||
<?php
|
||||
$message = ob_get_clean();
|
||||
|
||||
$this->add_notice( 'upgrade', array(
|
||||
'class' => 'error',
|
||||
'message' => $message,
|
||||
), 4 );
|
||||
} else {
|
||||
if ( isset( $_GET['msg'] ) && 'updated' === sanitize_key( $_GET['msg'] ) ) {
|
||||
if ( isset( $_GET['page'] ) && 'um_options' === sanitize_key( $_GET['page'] ) ) {
|
||||
$this->add_notice( 'settings_upgrade', array(
|
||||
'class' => 'updated',
|
||||
'message' => '<p>' . __( 'Settings successfully upgraded', 'ultimate-member' ) . '</p>',
|
||||
), 4 );
|
||||
} else {
|
||||
$this->add_notice(
|
||||
'upgrade',
|
||||
array(
|
||||
'class' => 'updated',
|
||||
// translators: %1$s is a plugin name title; %2$s is a plugin version.
|
||||
'message' => '<p>' . sprintf( __( '<strong>%1$s %2$s</strong> Successfully Upgraded', 'ultimate-member' ), UM_PLUGIN_NAME, UM_VERSION ) . '</p>',
|
||||
),
|
||||
4
|
||||
);
|
||||
}
|
||||
$this->add_notice(
|
||||
'upgrade',
|
||||
array(
|
||||
'class' => 'error',
|
||||
'message' => $message,
|
||||
),
|
||||
4
|
||||
);
|
||||
} elseif ( isset( $_GET['msg'] ) && 'updated' === sanitize_key( $_GET['msg'] ) ) {
|
||||
if ( isset( $_GET['page'] ) && 'um_options' === sanitize_key( $_GET['page'] ) ) {
|
||||
$this->add_notice(
|
||||
'settings_upgrade',
|
||||
array(
|
||||
'class' => 'updated',
|
||||
'message' => '<p>' . __( 'Settings successfully upgraded', 'ultimate-member' ) . '</p>',
|
||||
),
|
||||
4
|
||||
);
|
||||
} else {
|
||||
$this->add_notice(
|
||||
'upgrade',
|
||||
array(
|
||||
'class' => 'updated',
|
||||
// translators: %1$s is a plugin name title; %2$s is a plugin version.
|
||||
'message' => '<p>' . sprintf( __( '<strong>%1$s %2$s</strong> Successfully Upgraded', 'ultimate-member' ), UM_PLUGIN_NAME, UM_VERSION ) . '</p>',
|
||||
),
|
||||
4
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -734,18 +777,18 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<a href="javascript:void(0);" id="um_add_review_love"><?php _e( 'I love it!', 'ultimate-member' ) ?></a> |
|
||||
<a href="javascript:void(0);" id="um_add_review_good"><?php _e('It\'s good but could be better', 'ultimate-member' ) ?></a> |
|
||||
<a href="javascript:void(0);" id="um_add_review_bad"><?php _e('I don\'t like the plugin', 'ultimate-member' ) ?></a>
|
||||
<a href="javascript:void(0);" id="um_add_review_love"><?php _e( 'I love it!', 'ultimate-member' ); ?></a> |
|
||||
<a href="javascript:void(0);" id="um_add_review_good"><?php _e( 'It\'s good but could be better', 'ultimate-member' ); ?></a> |
|
||||
<a href="javascript:void(0);" id="um_add_review_bad"><?php _e( 'I don\'t like the plugin', 'ultimate-member' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="um-hidden-notice" data-key="love">
|
||||
<p>
|
||||
<?php printf( __( 'Great! We\'re happy to hear that you love the plugin. It would be amazing if you could let others know why you like %s by leaving a review of the plugin. This will help %s to grow and become more popular and would be massively appreciated by us!' ), UM_PLUGIN_NAME, UM_PLUGIN_NAME ); ?>
|
||||
<?php printf( __( 'Great! We\'re happy to hear that you love the plugin. It would be amazing if you could let others know why you like %1$s by leaving a review of the plugin. This will help %2$s to grow and become more popular and would be massively appreciated by us!' ), UM_PLUGIN_NAME, UM_PLUGIN_NAME ); ?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://wordpress.org/support/plugin/ultimate-member/reviews/?rate=5#new-post" target="_blank" class="button button-primary um_review_link"><?php _e( 'Leave Review', 'ultimate-member' ) ?></a>
|
||||
<a href="https://wordpress.org/support/plugin/ultimate-member/reviews/?rate=5#new-post" target="_blank" class="button button-primary um_review_link"><?php _e( 'Leave Review', 'ultimate-member' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="um-hidden-notice" data-key="good">
|
||||
@@ -754,7 +797,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://ultimatemember.com/feedback/" target="_blank" class="button button-primary um_review_link"><?php _e( 'Provide Feedback', 'ultimate-member' ) ?></a>
|
||||
<a href="https://ultimatemember.com/feedback/" target="_blank" class="button button-primary um_review_link"><?php _e( 'Provide Feedback', 'ultimate-member' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="um-hidden-notice" data-key="bad">
|
||||
@@ -763,17 +806,22 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://ultimatemember.com/feedback/" target="_blank" class="button button-primary um_review_link"><?php _e( 'Provide Feedback', 'ultimate-member' ) ?></a>
|
||||
<a href="https://ultimatemember.com/feedback/" target="_blank" class="button button-primary um_review_link"><?php _e( 'Provide Feedback', 'ultimate-member' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php $message = ob_get_clean();
|
||||
<?php
|
||||
$message = ob_get_clean();
|
||||
|
||||
$this->add_notice( 'reviews_notice', array(
|
||||
'class' => 'updated',
|
||||
'message' => $message,
|
||||
'dismissible' => true
|
||||
), 1 );
|
||||
$this->add_notice(
|
||||
'reviews_notice',
|
||||
array(
|
||||
'class' => 'updated',
|
||||
'message' => $message,
|
||||
'dismissible' => true,
|
||||
),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -782,7 +830,8 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
*/
|
||||
function future_changed() {
|
||||
|
||||
ob_start(); ?>
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
@@ -791,12 +840,17 @@ if ( ! class_exists( 'um\admin\core\Admin_Notices' ) ) {
|
||||
?>
|
||||
</p>
|
||||
|
||||
<?php $message = ob_get_clean();
|
||||
<?php
|
||||
$message = ob_get_clean();
|
||||
|
||||
$this->add_notice( 'future_changes', array(
|
||||
'class' => 'updated',
|
||||
'message' => $message,
|
||||
), 2 );
|
||||
$this->add_notice(
|
||||
'future_changes',
|
||||
array(
|
||||
'class' => 'updated',
|
||||
'message' => $message,
|
||||
),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,19 +100,20 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
|
||||
$sites = get_sites( array( 'fields' => 'ids' ) );
|
||||
foreach ( $sites as $blog_id ) {
|
||||
$metakeys[] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
|
||||
$metakeys[] = 'wc_money_spent_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' );
|
||||
$metakeys[] = 'wc_order_count_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' );
|
||||
$metakeys[] = 'wc_money_spent_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' ); // Is used since Woocommerce 9.1.0
|
||||
$metakeys[] = 'wc_order_count_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' ); // Is used since Woocommerce 9.1.0 TODO remove as soon as used 'um_wc_order_count_'
|
||||
}
|
||||
} else {
|
||||
$blog_id = get_current_blog_id();
|
||||
$metakeys[] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
|
||||
$metakeys[] = 'wc_money_spent_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' );
|
||||
$metakeys[] = 'wc_order_count_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' );
|
||||
$metakeys[] = 'wc_money_spent_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' ); // Is used since Woocommerce 9.1.0
|
||||
$metakeys[] = 'wc_order_count_' . rtrim( $wpdb->get_blog_prefix( $blog_id ), '_' ); // Is used since Woocommerce 9.1.0 TODO remove as soon as used 'um_wc_order_count_'
|
||||
}
|
||||
|
||||
//member directory data
|
||||
// Member directory data
|
||||
$metakeys[] = 'um_member_directory_data';
|
||||
$metakeys[] = '_um_verified';
|
||||
$metakeys[] = '_money_spent'; // Legacy since Woocommerce 9.1.0. TODO remove as soon as stop support Woo below 9.1.0 version
|
||||
$metakeys[] = '_completed';
|
||||
$metakeys[] = '_reviews_avg';
|
||||
|
||||
@@ -752,6 +753,9 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
|
||||
'use_um_gravatar_default_image' => array(
|
||||
'sanitize' => 'bool',
|
||||
),
|
||||
'admin_ignore_user_status' => array(
|
||||
'sanitize' => 'bool',
|
||||
),
|
||||
'delete_comments' => array(
|
||||
'sanitize' => 'bool',
|
||||
),
|
||||
@@ -1010,7 +1014,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
|
||||
'enable_blocks' => array(
|
||||
'sanitize' => 'bool',
|
||||
),
|
||||
'enable_action_scheduler' => array(
|
||||
'enable_as_email_sending' => array(
|
||||
'sanitize' => 'bool',
|
||||
),
|
||||
'rest_api_version' => array(
|
||||
@@ -1181,6 +1185,13 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
|
||||
'description' => __( 'Do you want to use the plugin default avatar instead of the gravatar default photo (If the user did not upload a custom profile photo/avatar).', 'ultimate-member' ),
|
||||
'conditional' => array( 'use_um_gravatar_default_builtin_image', '=', 'default' ),
|
||||
),
|
||||
array(
|
||||
'id' => 'admin_ignore_user_status',
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Ignore the "User Role > Registration Options"', 'ultimate-member' ),
|
||||
'checkbox_label' => __( 'Automatically approve users from the wp-admin dashboard', 'ultimate-member' ),
|
||||
'description' => __( 'Ignore registration settings and automatically approve the user if this user is added from the wp-admin dashboard.', 'ultimate-member' ),
|
||||
),
|
||||
array(
|
||||
'id' => 'delete_comments',
|
||||
'type' => 'checkbox',
|
||||
|
||||
@@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-server-side-render'), 'version' => 'cced871823424b7be338');
|
||||
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-server-side-render'), 'version' => 'b29cf253331968aa1d87');
|
||||
|
||||
@@ -1 +1 @@
|
||||
(()=>{"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.wp.data,r=window.wp.components,i=window.wp.blockEditor,n=window.wp.serverSideRender;var o=e.n(n);const l=window.wp.blocks,a=window.wp.element,c=window.ReactJSXRuntime;(0,l.registerBlockType)("um-block/um-member-directories",{edit:function(e){const n=(0,i.useBlockProps)(),{attributes:l,setAttributes:d}=e,{member_id:u}=l,m=(0,t.useSelect)((e=>e("core").getEntityRecords("postType","um_directory",{per_page:-1,_fields:["id","title"]})),[]),s=(0,a.useMemo)((()=>m?0===m.length?[{label:wp.i18n.__("No posts found.","ultimate-member"),value:""}]:[{label:wp.i18n.__("Select Directory","ultimate-member"),value:""}].concat(m.map((e=>({label:e.title.rendered,value:e.id})))):[{label:wp.i18n.__("Loading...","ultimate-member"),value:""}]),[m]);return m?(0,c.jsxs)("div",{...n,children:[(0,c.jsx)(o(),{block:"um-block/um-member-directories",attributes:l}),(0,c.jsx)(i.InspectorControls,{children:(0,c.jsx)(r.PanelBody,{title:wp.i18n.__("Select Directories","ultimate-member"),children:(0,c.jsx)(r.SelectControl,{label:wp.i18n.__("Select Directories","ultimate-member"),className:"um_select_directory",value:u,options:s,onChange:e=>d({member_id:e})})})})]}):(0,c.jsxs)("p",{children:[(0,c.jsx)(r.Spinner,{}),wp.i18n.__("Loading...","ultimate-member")]})},save:()=>null}),jQuery(window).on("load",(function(e){new MutationObserver((function(e){e.forEach((function(e){jQuery(e.addedNodes).find(".um.um-directory").each((function(){let e=document.querySelector(".um-directory"),t=jQuery(this);um_ajax_get_members(t),um_slider_filter_init(t),um_datepicker_filter_init(t),um_timepicker_filter_init(t),e&&e.addEventListener("click",(t=>{t.target!==e&&(t.preventDefault(),t.stopPropagation())}))})),jQuery(e.addedNodes).find(".um-member").each((function(){let e=document.querySelector(".um-member"),t=jQuery(this).parent();UM_Member_Grid(t),e&&e.addEventListener("click",(t=>{t.target!==e&&(t.preventDefault(),t.stopPropagation())}))}))}))})).observe(document,{attributes:!1,childList:!0,characterData:!1,subtree:!0})}))})();
|
||||
(()=>{"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.wp.data,r=window.wp.components,i=window.wp.blockEditor,n=window.wp.serverSideRender;var o=e.n(n);const l=window.wp.blocks,a=window.wp.element,c=window.ReactJSXRuntime;(0,l.registerBlockType)("um-block/um-member-directories",{edit:function(e){const n=(0,i.useBlockProps)(),{attributes:l,setAttributes:d}=e,{member_id:s}=l,u=(0,t.useSelect)((e=>e("core").getEntityRecords("postType","um_directory",{per_page:-1,_fields:["id","title"]})),[]),m=(0,a.useMemo)((()=>u?0===u.length?[{label:wp.i18n.__("No posts found.","ultimate-member"),value:""}]:[{label:wp.i18n.__("Select Directory","ultimate-member"),value:""}].concat(u.map((e=>({label:e.title.rendered,value:e.id})))):[{label:wp.i18n.__("Loading...","ultimate-member"),value:""}]),[u]);return u?(0,c.jsxs)("div",{...n,children:[(0,c.jsx)(o(),{block:"um-block/um-member-directories",attributes:l}),(0,c.jsx)(i.InspectorControls,{children:(0,c.jsx)(r.PanelBody,{title:wp.i18n.__("Select Directories","ultimate-member"),children:(0,c.jsx)(r.SelectControl,{label:wp.i18n.__("Select Directories","ultimate-member"),className:"um_select_directory",value:s,options:m,onChange:e=>d({member_id:e})})})})]}):(0,c.jsxs)("p",{children:[(0,c.jsx)(r.Spinner,{}),wp.i18n.__("Loading...","ultimate-member")]})},save:()=>null}),jQuery(window).on("load",(function(e){new MutationObserver((function(e){e.forEach((function(e){jQuery(e.addedNodes).find(".um.um-directory").each((function(){let e=document.querySelector(".um-directory"),t=jQuery(this);um_ajax_get_members(t),um_slider_filter_init(t),um_datepicker_filter_init(t),um_timepicker_filter_init(t),e&&e.addEventListener("click",(t=>{t.target!==e&&(t.preventDefault(),t.stopPropagation())}))})),jQuery(e.addedNodes).find(".um-member").each((function(){let e=document.querySelector(".um-member"),t=jQuery(this).parent();t.hasClass("um-members-grid")&&UM_Member_Grid(t),e&&e.addEventListener("click",(t=>{t.target!==e&&(t.preventDefault(),t.stopPropagation())}))}))}))})).observe(document,{attributes:!1,childList:!0,characterData:!1,subtree:!0})}))})();
|
||||
@@ -658,6 +658,7 @@ if ( ! class_exists( 'um\Config' ) ) {
|
||||
'use_gravatars' => false,
|
||||
'use_um_gravatar_default_builtin_image' => 'default',
|
||||
'use_um_gravatar_default_image' => false,
|
||||
'admin_ignore_user_status' => false,
|
||||
'toggle_password' => false,
|
||||
'require_strongpass' => false,
|
||||
'password_min_chars' => 8,
|
||||
@@ -733,7 +734,7 @@ if ( ! class_exists( 'um\Config' ) ) {
|
||||
'secure_notify_admins_banned_accounts__interval' => 'instant',
|
||||
'secure_allowed_redirect_hosts' => '',
|
||||
'delete_comments' => false,
|
||||
'enable_action_scheduler' => false,
|
||||
'enable_as_email_sending' => UM()->options()->get( 'enable_action_scheduler' ), // Use legacy option value by default. It helps during update to set the same value. The last version when we used 'enable_action_scheduler' is 2.10.2
|
||||
);
|
||||
|
||||
add_filter( 'um_get_tabs_from_config', '__return_true' );
|
||||
|
||||
@@ -180,27 +180,41 @@ if ( ! class_exists( 'um\Dependencies' ) ) {
|
||||
/**
|
||||
* Compare UM core and extension versions
|
||||
*
|
||||
* @param string $um_required_ver
|
||||
* @param string $um_required_ver UM core required version.
|
||||
* @param string $ext_ver
|
||||
* @param string $ext_key
|
||||
* @param string $ext_title
|
||||
* @param bool $raw False by default. Then return message. Use `true` in conditions inside `plugins_loaded` hook
|
||||
* @return bool
|
||||
*/
|
||||
public function compare_versions( $um_required_ver, $ext_ver, $ext_key, $ext_title ) {
|
||||
|
||||
if ( version_compare( UM_VERSION, $um_required_ver, '<' )
|
||||
|| empty( $this->ext_required_version[$ext_key] )
|
||||
|| version_compare( $this->ext_required_version[$ext_key], $ext_ver, '>' ) ) {
|
||||
public function compare_versions( $um_required_ver, $ext_ver, $ext_key, $ext_title, $raw = false ) {
|
||||
if ( empty( $this->ext_required_version[ $ext_key ] ) ||
|
||||
version_compare( UM_VERSION, $um_required_ver, '<' ) ||
|
||||
version_compare( $this->ext_required_version[ $ext_key ], $ext_ver, '>' ) ) {
|
||||
|
||||
$message = '';
|
||||
if ( version_compare( UM_VERSION, $um_required_ver, '<' ) ) {
|
||||
// translators: %1$s is a extension name; %2$s is a plugin name; %3$s is a required version.
|
||||
$message = sprintf( __( 'This version of <strong>"%1$s"</strong> requires the core <strong>%2$s</strong> plugin to be <strong>%3$s</strong> or higher.', 'ultimate-member' ), $ext_title, UM_PLUGIN_NAME, $um_required_ver ) .
|
||||
'<br />' .
|
||||
// translators: %s: plugin name.
|
||||
sprintf( __( 'Please update <strong>%s</strong> to the latest version.', 'ultimate-member' ), UM_PLUGIN_NAME );
|
||||
if ( $raw ) {
|
||||
return false;
|
||||
}
|
||||
if ( UM()->is_new_ui() ) {
|
||||
// translators: %1$s is an extension name; %2$s is a plugin name; %3$s is a required version.
|
||||
$message = sprintf( __( 'When new UI is enabled this version of <strong>"%1$s"</strong> requires the core <strong>%2$s</strong> plugin to be <strong>%3$s</strong> or higher.', 'ultimate-member' ), $ext_title, UM_PLUGIN_NAME, $um_required_ver ) .
|
||||
'<br />' .
|
||||
// translators: %s: plugin name.
|
||||
sprintf( __( 'Please update <strong>%s</strong> to the latest version or disable new UI.', 'ultimate-member' ), UM_PLUGIN_NAME );
|
||||
} else {
|
||||
// translators: %1$s is an extension name; %2$s is a plugin name; %3$s is a required version.
|
||||
$message = sprintf( __( 'This version of <strong>"%1$s"</strong> requires the core <strong>%2$s</strong> plugin to be <strong>%3$s</strong> or higher.', 'ultimate-member' ), $ext_title, UM_PLUGIN_NAME, $um_required_ver ) .
|
||||
'<br />' .
|
||||
// translators: %s: plugin name.
|
||||
sprintf( __( 'Please update <strong>%s</strong> to the latest version.', 'ultimate-member' ), UM_PLUGIN_NAME );
|
||||
}
|
||||
} elseif ( empty( $this->ext_required_version[ $ext_key ] ) || version_compare( $this->ext_required_version[ $ext_key ], $ext_ver, '>' ) ) {
|
||||
// translators: %1$s is a plugin name; %2$s is a extension name; %3$s is a extension version.
|
||||
if ( $raw ) {
|
||||
return false;
|
||||
}
|
||||
// translators: %1$s is a plugin name; %2$s is an extension name; %3$s is an extension version.
|
||||
$message = sprintf( __( 'Sorry, but this version of <strong>%1$s</strong> does not work with extension <strong>"%2$s" %3$s</strong> version.', 'ultimate-member' ), UM_PLUGIN_NAME, $ext_title, $ext_ver ) .
|
||||
'<br /> ' .
|
||||
// translators: %s: extension name.
|
||||
@@ -208,19 +222,24 @@ if ( ! class_exists( 'um\Dependencies' ) ) {
|
||||
}
|
||||
|
||||
return $message;
|
||||
} else {
|
||||
//check correct folder name for extensions
|
||||
if ( ! self::$active_plugins ) self::init();
|
||||
}
|
||||
|
||||
if ( ! in_array( "um-{$ext_key}/um-{$ext_key}.php", self::$active_plugins ) && ! array_key_exists( "um-{$ext_key}/um-{$ext_key}.php", self::$active_plugins ) ) {
|
||||
// translators: %1$s is a extension name; %2$s is a extension version.
|
||||
$message = sprintf( __( 'Please check <strong>"%1$s" %2$s</strong> extension\'s folder name.', 'ultimate-member' ), $ext_title, $ext_ver ) .
|
||||
'<br />' .
|
||||
// translators: %s: extension name.
|
||||
sprintf( __( 'Correct folder name is <strong>"%s"</strong>', 'ultimate-member' ), "um-{$ext_key}" );
|
||||
// Check correct folder name for extensions.
|
||||
if ( ! self::$active_plugins ) {
|
||||
self::init();
|
||||
}
|
||||
|
||||
return $message;
|
||||
if ( ! array_key_exists( "um-{$ext_key}/um-{$ext_key}.php", self::$active_plugins ) &&
|
||||
! in_array( "um-{$ext_key}/um-{$ext_key}.php", self::$active_plugins, true ) ) {
|
||||
if ( $raw ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// translators: %1$s is an extension name; %2$s is an extension version.
|
||||
return sprintf( __( 'Please check <strong>"%1$s" %2$s</strong> extension\'s folder name.', 'ultimate-member' ), $ext_title, $ext_ver ) .
|
||||
'<br />' .
|
||||
// translators: %s: extension name.
|
||||
sprintf( __( 'Correct folder name is <strong>"%s"</strong>', 'ultimate-member' ), "um-{$ext_key}" );
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -17,10 +17,18 @@ if ( ! class_exists( 'um\common\actions\Emails' ) ) {
|
||||
class Emails {
|
||||
|
||||
public function __construct() {
|
||||
add_filter( 'um_action_scheduler_is_hook_enabled', array( $this, 'is_enabled' ), 10, 2 );
|
||||
add_action( 'um_dispatch_email', array( $this, 'send' ), 10, 3 );
|
||||
add_action( 'um_before_email_notification_sending', array( $this, 'before_email_send' ), 10, 2 );
|
||||
}
|
||||
|
||||
public function is_enabled( $is_enabled, $hook ) {
|
||||
if ( 'um_dispatch_email' === $hook ) {
|
||||
$is_enabled = UM()->options()->get( 'enable_as_email_sending' );
|
||||
}
|
||||
return $is_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email
|
||||
*
|
||||
@@ -36,7 +44,7 @@ if ( ! class_exists( 'um\common\actions\Emails' ) ) {
|
||||
// @todo Workaround for now. Maybe we need to put base $user_id everytime
|
||||
if ( array_key_exists( 'fetch_user_id', $args ) ) {
|
||||
// When Action Scheduler is enabled, email sending script is located out of basic functionality, so we need to fetch the user for replace placeholders.
|
||||
if ( UM()->maybe_action_scheduler()->is_enabled() ) {
|
||||
if ( UM()->maybe_action_scheduler()->is_hook_enabled( 'um_dispatch_email' ) ) {
|
||||
um_fetch_user( $args['fetch_user_id'] );
|
||||
}
|
||||
unset( $args['fetch_user_id'] );
|
||||
@@ -56,7 +64,7 @@ if ( ! class_exists( 'um\common\actions\Emails' ) ) {
|
||||
* @return void
|
||||
*/
|
||||
public function before_email_send( $email, $template ) {
|
||||
if ( ! UM()->maybe_action_scheduler()->is_enabled() ) {
|
||||
if ( ! UM()->maybe_action_scheduler()->is_hook_enabled( 'um_dispatch_email' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
namespace um\common\actions;
|
||||
|
||||
use WP_User_Query;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'um\common\actions\Users' ) ) {
|
||||
|
||||
/**
|
||||
* Class Users
|
||||
*
|
||||
* @since 2.10.3
|
||||
*
|
||||
* @package um\common\actions
|
||||
*/
|
||||
class Users {
|
||||
|
||||
const INTERVAL = 3600;
|
||||
|
||||
const SCHEDULE_ACTION = 'um_schedule_empty_account_status_check';
|
||||
|
||||
const BATCH_SIZE = 50;
|
||||
|
||||
const BATCH_ACTION = 'um_set_default_account_status';
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'init', array( &$this, 'add_recurring_action' ) );
|
||||
add_action( self::SCHEDULE_ACTION, array( &$this, 'status_check' ) );
|
||||
add_action( self::BATCH_ACTION, array( &$this, 'batch_check' ), 10, 3 );
|
||||
}
|
||||
|
||||
public function add_recurring_action() {
|
||||
if ( UM()->maybe_action_scheduler()->next_scheduled_action( self::SCHEDULE_ACTION ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
UM()->maybe_action_scheduler()->schedule_recurring_action(
|
||||
time() + 60,
|
||||
self::INTERVAL,
|
||||
self::SCHEDULE_ACTION
|
||||
);
|
||||
}
|
||||
|
||||
public function status_check() {
|
||||
$total_users = UM()->common()->users()::get_empty_status_users();
|
||||
if ( empty( $total_users ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
UM()->maybe_action_scheduler()->enqueue_async_action(
|
||||
self::BATCH_ACTION,
|
||||
array(
|
||||
'page' => 1,
|
||||
'total' => $total_users,
|
||||
'pages' => ceil( $total_users / self::BATCH_SIZE ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform batch checking for users based on specific conditions.
|
||||
* Ignore users with `_um_registration_in_progress` that can be in the process of the registration.
|
||||
* Get users with empty `account_status` meta.
|
||||
*
|
||||
* @param int $page The current page number.
|
||||
* @param int $total The total number of users to process.
|
||||
* @param int $pages The total number of pages to process.
|
||||
*/
|
||||
public function batch_check( $page, $total, $pages ) {
|
||||
$users = new WP_User_Query(
|
||||
array(
|
||||
'number' => self::BATCH_SIZE,
|
||||
'fields' => 'ids',
|
||||
'meta_query' => array(
|
||||
'relation' => 'AND',
|
||||
array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => '_um_registration_in_progress',
|
||||
'compare' => 'NOT EXISTS',
|
||||
),
|
||||
array(
|
||||
'key' => '_um_registration_in_progress',
|
||||
'value' => '1',
|
||||
'compare' => '!=',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => 'account_status',
|
||||
'compare' => 'NOT EXISTS',
|
||||
),
|
||||
array(
|
||||
'key' => 'account_status',
|
||||
'value' => '',
|
||||
'compare' => '=',
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$results = $users->get_results();
|
||||
|
||||
if ( ! empty( $results ) ) {
|
||||
$um_empty_status_users = get_option( '_um_log_empty_status_users', array( 0, 0 ) );
|
||||
if ( ! is_array( $um_empty_status_users ) ) {
|
||||
$um_empty_status_users = array( 0, count( $results ) );
|
||||
}
|
||||
|
||||
foreach ( $results as $user_id ) {
|
||||
$res = UM()->common()->users()->approve( $user_id, true, true );
|
||||
if ( $res ) {
|
||||
++$um_empty_status_users[0];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $um_empty_status_users[0] < $um_empty_status_users[1] ) {
|
||||
update_option( '_um_log_empty_status_users', $um_empty_status_users );
|
||||
} else {
|
||||
delete_option( '_um_log_empty_status_users' );
|
||||
}
|
||||
|
||||
$next_page = $page + 1;
|
||||
if ( $next_page <= $pages ) {
|
||||
UM()->maybe_action_scheduler()->enqueue_async_action(
|
||||
self::BATCH_ACTION,
|
||||
array(
|
||||
'page' => $next_page,
|
||||
'total' => $total,
|
||||
'pages' => $pages,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,10 @@ if ( ! class_exists( 'um\common\Init' ) ) {
|
||||
if ( empty( UM()->classes['um\common\actions\emails'] ) ) {
|
||||
UM()->classes['um\common\actions\emails'] = new actions\Emails();
|
||||
}
|
||||
|
||||
if ( empty( UM()->classes['um\common\actions\users'] ) ) {
|
||||
UM()->classes['um\common\actions\users'] = new actions\Users();
|
||||
}
|
||||
// Other classes init here as soon as possible.
|
||||
}
|
||||
|
||||
|
||||
@@ -658,11 +658,12 @@ class Users {
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
* @param bool $force If true - ignore current user condition.
|
||||
* @param bool $silent If true - don't send email notification. E.g. case when user already exists, but doesn't have a status.
|
||||
*
|
||||
* @return bool `true` if the user has been approved
|
||||
* `false` on failure or if the user already has approved status.
|
||||
*/
|
||||
public function approve( $user_id, $force = false ) {
|
||||
public function approve( $user_id, $force = false, $silent = false ) {
|
||||
if ( ! $this->can_be_approved( $user_id, $force ) ) {
|
||||
return false;
|
||||
}
|
||||
@@ -683,25 +684,27 @@ class Users {
|
||||
|
||||
// It's `false` on failure or if the user already has approved status.
|
||||
if ( false !== $result ) {
|
||||
$userdata = get_userdata( $user_id );
|
||||
if ( false === $silent ) {
|
||||
$userdata = get_userdata( $user_id );
|
||||
|
||||
$this->reset_activation_link( $user_id );
|
||||
$this->reset_activation_link( $user_id );
|
||||
|
||||
$email_slug = 'welcome_email';
|
||||
if ( 'awaiting_admin_review' === $old_status ) {
|
||||
$email_slug = 'approved_email';
|
||||
$this->maybe_generate_password_reset_key( $userdata );
|
||||
$email_slug = 'welcome_email';
|
||||
if ( 'awaiting_admin_review' === $old_status ) {
|
||||
$email_slug = 'approved_email';
|
||||
$this->maybe_generate_password_reset_key( $userdata );
|
||||
}
|
||||
|
||||
$current_user_id = get_current_user_id();
|
||||
um_fetch_user( $user_id );
|
||||
|
||||
add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ) );
|
||||
add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ) );
|
||||
|
||||
UM()->maybe_action_scheduler()->enqueue_async_action( 'um_dispatch_email', array( $userdata->user_email, $email_slug, array( 'fetch_user_id' => $user_id ) ) );
|
||||
|
||||
um_fetch_user( $current_user_id );
|
||||
}
|
||||
|
||||
$current_user_id = get_current_user_id();
|
||||
um_fetch_user( $user_id );
|
||||
|
||||
add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ) );
|
||||
add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ) );
|
||||
|
||||
UM()->maybe_action_scheduler()->enqueue_async_action( 'um_dispatch_email', array( $userdata->user_email, $email_slug, array( 'fetch_user_id' => $user_id ) ) );
|
||||
|
||||
um_fetch_user( $current_user_id );
|
||||
/**
|
||||
* Fires after User has been approved.
|
||||
*
|
||||
@@ -827,4 +830,29 @@ class Users {
|
||||
$user = WP_Session_Tokens::get_instance( $user_id );
|
||||
$user->destroy_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the number of users with empty `account_status` usermeta.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_empty_status_users() {
|
||||
global $wpdb;
|
||||
|
||||
$total_users = $wpdb->get_var(
|
||||
"SELECT COUNT(u.ID)
|
||||
FROM {$wpdb->users} u
|
||||
LEFT JOIN {$wpdb->usermeta} um ON u.ID = um.user_id AND um.meta_key = 'account_status'
|
||||
LEFT JOIN {$wpdb->usermeta} um2 ON u.ID = um2.user_id AND um2.meta_key = '_um_registration_in_progress'
|
||||
WHERE ( um.meta_value IS NULL OR um.meta_value = '' ) AND
|
||||
um2.meta_value IS NULL OR um2.meta_value != '1'"
|
||||
);
|
||||
|
||||
$total_users = absint( $total_users );
|
||||
// In WordPress, an underscore prefix before the option name (e.g., _my_option_name) is commonly used to indicate that the option is private.
|
||||
// This option has a format: {updated_users}/{total_users_for_update}.
|
||||
update_option( '_um_log_empty_status_users', array( 0, $total_users ) );
|
||||
|
||||
return $total_users;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ if ( ! class_exists( 'um\core\Builtin' ) ) {
|
||||
public $saved_fields = array();
|
||||
|
||||
/**
|
||||
* Field keys that cannot be used as metakey when add new custom field to UM Form.
|
||||
* Note: They are used both with function `UM()->user()->is_metakey_banned()` to avoid using unsecure metakeys.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $blacklist_fields = array();
|
||||
@@ -183,7 +186,7 @@ if ( ! class_exists( 'um\core\Builtin' ) ) {
|
||||
* @return int|string Empty or error string.
|
||||
*/
|
||||
public function blacklist_field_err( $key ) {
|
||||
if ( in_array( strtolower( $key ), $this->blacklist_fields, true ) ) {
|
||||
if ( in_array( strtolower( $key ), $this->blacklist_fields, true ) || UM()->user()->is_metakey_banned( $key ) ) {
|
||||
return __( 'Your meta key can not be used', 'ultimate-member' );
|
||||
}
|
||||
|
||||
@@ -1426,6 +1429,9 @@ if ( ! class_exists( 'um\core\Builtin' ) ) {
|
||||
public function set_blacklist_fields() {
|
||||
$this->blacklist_fields = array(
|
||||
'id',
|
||||
'role',
|
||||
'user_id',
|
||||
'user_pass',
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -2056,7 +2062,7 @@ if ( ! class_exists( 'um\core\Builtin' ) ) {
|
||||
'TO' => __('Tonga','ultimate-member'),
|
||||
'TT' => __('Trinidad and Tobago','ultimate-member'),
|
||||
'TN' => __('Tunisia','ultimate-member'),
|
||||
'TR' => __('Turkey','ultimate-member'),
|
||||
'TR' => __('Türkiye','ultimate-member'),
|
||||
'TM' => __('Turkmenistan','ultimate-member'),
|
||||
'TC' => __('Turks and Caicos Islands','ultimate-member'),
|
||||
'TV' => __('Tuvalu','ultimate-member'),
|
||||
|
||||
@@ -340,11 +340,11 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
|
||||
|
||||
// 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 LIKE %s", '%' . $wpdb->esc_like( maybe_serialize( (string) $single_val ) ) . '%' );
|
||||
$values_array[] = $wpdb->prepare( "{$join_alias}.um_value LIKE %s", '%' . $wpdb->esc_like( serialize( (string) $single_val ) ) . '%' );
|
||||
$values_array[] = $wpdb->prepare( "{$join_alias}.um_value = %s", $single_val );
|
||||
|
||||
if ( is_numeric( $single_val ) ) {
|
||||
$values_array[] = $wpdb->prepare( "{$join_alias}.um_value LIKE %s", '%' . $wpdb->esc_like( maybe_serialize( (int) $single_val ) ) . '%' );
|
||||
$values_array[] = $wpdb->prepare( "{$join_alias}.um_value LIKE %s", '%' . $wpdb->esc_like( serialize( (int) $single_val ) ) . '%' );
|
||||
}
|
||||
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $join_alias is pre-escaped.
|
||||
}
|
||||
|
||||
@@ -36,18 +36,26 @@ if ( ! class_exists( 'um\core\Password' ) ) {
|
||||
/**
|
||||
* Get Reset URL
|
||||
*
|
||||
* @return bool|string
|
||||
* @param int|null $user_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function reset_url() {
|
||||
public function reset_url( $user_id = null ) {
|
||||
static $reset_key = null;
|
||||
|
||||
$user_id = um_user( 'ID' );
|
||||
if ( is_null( $user_id ) ) {
|
||||
$user_id = um_user( 'ID' );
|
||||
}
|
||||
|
||||
delete_option( "um_cache_userdata_{$user_id}" );
|
||||
|
||||
// New reset password key via WordPress native field. It maybe already exists here but generated twice to make sure that emailed with a proper and fresh hash.
|
||||
// But doing that only once in 1 request using static variable. Different email placeholders can use reset_url() and we have to use 1 time generated to avoid invalid keys.
|
||||
$user_data = get_userdata( $user_id );
|
||||
if ( empty( $user_data ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( empty( $reset_key ) ) {
|
||||
$reset_key = UM()->user()->maybe_generate_password_reset_key( $user_data );
|
||||
}
|
||||
@@ -466,7 +474,7 @@ if ( ! class_exists( 'um\core\Password' ) ) {
|
||||
um_fetch_user( $data->ID );
|
||||
|
||||
if ( false === UM()->options()->get( 'only_approved_user_reset_password' ) || UM()->common()->users()->has_status( $data->ID, 'approved' ) ) {
|
||||
UM()->user()->password_reset();
|
||||
UM()->user()->password_reset( $data->ID );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -310,37 +310,21 @@ KEY meta_value_indx (um_value(191))
|
||||
* @since 2.4.2
|
||||
*/
|
||||
public function set_default_user_status() {
|
||||
$result = get_transient( 'um_count_users_unassigned' );
|
||||
if ( false === $result ) {
|
||||
$args = array(
|
||||
'fields' => 'ids',
|
||||
'number' => 0,
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => 'account_status',
|
||||
'compare' => 'NOT EXISTS',
|
||||
),
|
||||
),
|
||||
'um_custom_user_query' => true,
|
||||
);
|
||||
|
||||
$users = new WP_User_Query( $args );
|
||||
if ( empty( $users ) || is_wp_error( $users ) ) {
|
||||
$result = array();
|
||||
} else {
|
||||
$result = $users->get_results();
|
||||
}
|
||||
|
||||
set_transient( 'um_count_users_unassigned', $result, DAY_IN_SECONDS );
|
||||
}
|
||||
|
||||
if ( empty( $result ) ) {
|
||||
$total_users = UM()->common()->users()::get_empty_status_users();
|
||||
if ( empty( $total_users ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $result as $user_id ) {
|
||||
update_user_meta( $user_id, 'account_status', 'approved' );
|
||||
}
|
||||
// If there are some users without `account_status` then run the first async batch for update.
|
||||
$batch_size = 50; // See the class constant value `\um\common\actions\Users::BATCH_ACTION`.
|
||||
UM()->maybe_action_scheduler()->enqueue_async_action(
|
||||
$batch_size,
|
||||
array(
|
||||
'page' => 1,
|
||||
'total' => $total_users,
|
||||
'pages' => ceil( $total_users / $batch_size ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -640,7 +640,6 @@ if ( ! class_exists( 'um\core\User' ) ) {
|
||||
UM()->files()->remove_dir( UM()->files()->upload_temp );
|
||||
UM()->files()->remove_dir( UM()->uploader()->get_upload_base_dir() . um_user( 'ID' ) . DIRECTORY_SEPARATOR );
|
||||
|
||||
delete_transient( 'um_count_users_unassigned' );
|
||||
delete_transient( 'um_count_users_pending_dot' );
|
||||
}
|
||||
|
||||
@@ -959,8 +958,6 @@ if ( ! class_exists( 'um\core\User' ) ) {
|
||||
/** 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' );
|
||||
}
|
||||
|
||||
|
||||
@@ -1487,22 +1484,34 @@ if ( ! class_exists( 'um\core\User' ) ) {
|
||||
return get_password_reset_key( $userdata );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Password reset email
|
||||
*
|
||||
* @param int|null $user_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function password_reset() {
|
||||
$userdata = get_userdata( um_user( 'ID' ) );
|
||||
public function password_reset( $user_id = null ) {
|
||||
if ( is_null( $user_id ) ) {
|
||||
$user_id = um_user( 'ID' );
|
||||
}
|
||||
$userdata = get_userdata( $user_id );
|
||||
|
||||
$this->maybe_generate_password_reset_key( $userdata );
|
||||
|
||||
add_filter( 'um_template_tags_patterns_hook', array( UM()->password(), 'add_placeholder' ) );
|
||||
add_filter( 'um_template_tags_replaces_hook', array( UM()->password(), 'add_replace_placeholder' ) );
|
||||
$mail_args = array(
|
||||
'fetch_user_id' => $user_id,
|
||||
'tags' => array(
|
||||
'{password_reset_link}',
|
||||
),
|
||||
'tags_replace' => array(
|
||||
UM()->password()->reset_url( $user_id ),
|
||||
),
|
||||
);
|
||||
|
||||
UM()->maybe_action_scheduler()->enqueue_async_action( 'um_dispatch_email', array( $userdata->user_email, 'resetpw_email', array( 'fetch_user_id' => um_user( 'ID' ) ) ) );
|
||||
UM()->maybe_action_scheduler()->enqueue_async_action( 'um_dispatch_email', array( $userdata->user_email, 'resetpw_email', $mail_args ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Password changed email
|
||||
*
|
||||
|
||||
@@ -737,18 +737,18 @@ function um_profile_dynamic_meta_desc() {
|
||||
$image_info = array();
|
||||
$image_width = $image_size;
|
||||
$image_height = $image_size;
|
||||
if ( false === strpos( $image, 'gravatar.com' ) ) {
|
||||
// Ignore Gravatar image here and handler a real image.
|
||||
$upload_dir = wp_get_upload_dir();
|
||||
if ( false !== strpos( $image, $upload_dir['url'] ) ) {
|
||||
// Get the image size of the real image.
|
||||
$image = current( explode( '?', $image ) ); // strip $_GET attributes from photo URL.
|
||||
$image_path = wp_normalize_path( ABSPATH . wp_parse_url( $image, PHP_URL_PATH ) );
|
||||
$image_info = wp_check_filetype( $image_path );
|
||||
$imagesizes = getimagesize( $image_path );
|
||||
if ( is_array( $imagesizes ) ) {
|
||||
list( $image_width, $image_height ) = $imagesizes;
|
||||
if ( file_exists( $image_path ) ) {
|
||||
$image_info = wp_check_filetype( $image_path );
|
||||
$imagesizes = @getimagesize( $image_path );
|
||||
if ( is_array( $imagesizes ) ) {
|
||||
list( $image_width, $image_height ) = $imagesizes;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Gravatar image.
|
||||
$image_path = esc_url_raw( $image );
|
||||
}
|
||||
|
||||
$person = array(
|
||||
|
||||
@@ -113,6 +113,11 @@ add_action( 'um_user_register', 'um_after_insert_user', 1, 3 );
|
||||
* @param $user_id
|
||||
*/
|
||||
function um_send_registration_notification( $user_id ) {
|
||||
if ( is_admin() ) {
|
||||
// Don't send email notifications to administrators about new user registration, because the user was created from wp-admin.
|
||||
return;
|
||||
}
|
||||
|
||||
um_fetch_user( $user_id );
|
||||
$registration_status = um_user( 'status' );
|
||||
|
||||
@@ -137,7 +142,12 @@ add_action( 'um_registration_complete', 'um_send_registration_notification' );
|
||||
* @param null|array $form_data
|
||||
*/
|
||||
function um_check_user_status( $user_id, $args, $form_data = null ) {
|
||||
$registration_status = um_user( 'status' );
|
||||
if ( ( is_null( $form_data ) || is_admin() ) && UM()->options()->get( 'admin_ignore_user_status' ) ) {
|
||||
$registration_status = 'approved';
|
||||
} else {
|
||||
$registration_status = um_user( 'status' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after complete UM user registration.
|
||||
* Where $status can be equal to 'approved', 'checkmail' or 'pending'.
|
||||
@@ -169,9 +179,12 @@ function um_check_user_status( $user_id, $args, $form_data = null ) {
|
||||
*/
|
||||
do_action( "um_post_registration_{$registration_status}_hook", $user_id, $args, $form_data );
|
||||
|
||||
delete_user_meta( $user_id, '_um_registration_in_progress' ); // Status is set. We can delete this marker.
|
||||
|
||||
if ( is_null( $form_data ) || is_admin() ) {
|
||||
return;
|
||||
}
|
||||
// Code below is running only for registration from the frontend forms.
|
||||
|
||||
/**
|
||||
* Fires after complete UM user registration. Only for the frontend action which is run before autologin and redirects.
|
||||
@@ -502,6 +515,11 @@ function um_submit_form_register( $args, $form_data ) {
|
||||
'user_pass' => $user_password,
|
||||
'user_email' => $user_email,
|
||||
'role' => $user_role,
|
||||
'meta_input' => array(
|
||||
// It's used to ignore users who cannot finish the registration process in the scheduled tasks
|
||||
// to set 'approved' status to the users without `account_status` meta.
|
||||
'_um_registration_in_progress' => true,
|
||||
),
|
||||
);
|
||||
|
||||
$user_id = wp_insert_user( $userdata );
|
||||
|
||||
+19
-1
@@ -5,7 +5,7 @@ Contributors: ultimatemember, champsupertramp, nsinelnikov
|
||||
Tags: community, member, membership, user-profile, user-registration
|
||||
Requires PHP: 7.0
|
||||
Requires at least: 6.2
|
||||
Tested up to: 6.7
|
||||
Tested up to: 6.8
|
||||
Stable tag: 2.10.2
|
||||
License: GPLv3
|
||||
License URI: http://www.gnu.org/licenses/gpl-3.0.txt
|
||||
@@ -167,6 +167,24 @@ 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.10.3 2025-04-24 =
|
||||
|
||||
**Enhancements**
|
||||
|
||||
* Added: The `Ignore the "User Role > Registration Options"` setting. It provides an ability to auto-approve users if they were created via wp-admin > Users screen.
|
||||
* Tweak: Avoid email notifications to Administrator about user registration via wp-admin > Users screen.
|
||||
* Tweak: Updated the Action Scheduler implementation to improve flexibility and clarity. Refactor Action Scheduler for not only email handling.
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed: Member Directory styles when it's rendered on the Gutenberg builder page.
|
||||
* Fixed: Member Directory filtering query when the custom users metatable is used.
|
||||
* Fixed: PHP Warning that occurs when using the `getimagesize` function with an image from an external source.
|
||||
* Fixed: Reset Password email notification's the {password_reset_link}` placeholder.
|
||||
* Fixed: Changed "Turkey" to the current official term "Türkiye".
|
||||
|
||||
**Cached and optimized/minified assets(JS/CSS) must be flushed/re-generated after upgrade**
|
||||
|
||||
= 2.10.2 2025-04-02 =
|
||||
|
||||
**Enhancements**
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
require_once '../../../../wp-load.php';
|
||||
|
||||
function um_test_generate_random_string( $length = 10 ) {
|
||||
return substr( str_shuffle( str_repeat( $x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil( $length / strlen( $x ) ) ) ), 1, $length );
|
||||
}
|
||||
|
||||
for ( $i = 0; $i < 1000; $i++ ) {
|
||||
$random_user_name = um_test_generate_random_string( 8 ); // Generate a random user name
|
||||
$random_user_email = $random_user_name . '@example.com'; // Append the user name to a dummy email domain
|
||||
$random_user_pass = um_test_generate_random_string( 12 ); // Generate a random user password
|
||||
$random_first_name = um_test_generate_random_string( 5 ); // Generate a random first name
|
||||
$random_last_name = um_test_generate_random_string( 8 ); // Generate a random last name
|
||||
|
||||
$userdata = array(
|
||||
'user_login' => $random_user_name,
|
||||
'user_pass' => 'q1q2q1q2',
|
||||
'user_email' => $random_user_email,
|
||||
'first_name' => $random_first_name,
|
||||
'last_name' => $random_last_name,
|
||||
'role' => 'subscriber',
|
||||
);
|
||||
|
||||
$user_id = wp_insert_user( $userdata );
|
||||
|
||||
if ( is_wp_error( $user_id ) ) {
|
||||
// Something went wrong, handle the error
|
||||
var_dump( 'User creation failed: ' . $user_id->get_error_message() );
|
||||
} else {
|
||||
var_dump( 'User creation complete: ID:' . $user_id . ' Username:' . $userdata['user_login'] );
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
+1
-1
@@ -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.10.2
|
||||
* Version: 2.10.3
|
||||
* Author: Ultimate Member
|
||||
* Author URI: http://ultimatemember.com/
|
||||
* Text Domain: ultimate-member
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ if ( ! empty( $delete_options ) ) {
|
||||
delete_transient( "um_count_users_{$status}" );
|
||||
}
|
||||
delete_transient( 'um_count_users_pending_dot' );
|
||||
delete_transient( 'um_count_users_unassigned' );
|
||||
delete_transient( 'um_count_users_unassigned' ); // legacy but still need to delete while uninstall.
|
||||
|
||||
//remove all users cache
|
||||
UM()->user()->remove_cache_all_users();
|
||||
|
||||
Reference in New Issue
Block a user