Merge pull request #1753 from ultimatemember/development/2.9.x

Version 2.10.7
This commit is contained in:
Mykyta Synelnikov
2025-11-18 14:40:03 +02:00
committed by GitHub
15 changed files with 217 additions and 66 deletions
+1 -1
View File
@@ -15,7 +15,7 @@
"step": "installPlugin", "step": "installPlugin",
"pluginZipFile": { "pluginZipFile": {
"resource": "url", "resource": "url",
"url": "https:\/\/downloads.wordpress.org\/plugin\/ultimate-member.2.10.6.zip" "url": "https:\/\/downloads.wordpress.org\/plugin\/ultimate-member.2.10.7.zip"
}, },
"options": { "options": {
"activate": true "activate": true
+1 -1
View File
@@ -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 ### 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.6](https://github.com/ultimatemember/ultimatemember/releases/tag/2.10.6). [Official Release Version: 2.10.7](https://github.com/ultimatemember/ultimatemember/releases/tag/2.10.7).
## Changelog ## Changelog
+1
View File
@@ -348,6 +348,7 @@ function initImageUpload_UM( trigger ) {
var cache_ts = new Date(); var cache_ts = new Date();
img_id.removeAttr("loading");
img_id.attr("src", d.url + "?"+cache_ts.getTime() ); img_id.attr("src", d.url + "?"+cache_ts.getTime() );
img_id.data("file", d.file ); img_id.data("file", d.file );
+1 -1
View File
File diff suppressed because one or more lines are too long
+16
View File
@@ -1,5 +1,21 @@
== Changelog == == Changelog ==
= 2.10.7 November 20, 2025 =
* Enhancements:
- Added: Extra condition for checking the license activation requests.
- Added: 2nd `$args` attribute to the action hook 'um_cover_area_content'.
- Tweak: Updated `Extensions_Updater` class to use Action Scheduler in the upgrade process of the UM extensions.
* Bugfixes:
- Fixed: User profile links in the comments section on the frontend when the `$comment->user_id` is empty.
- Fixed: The `emotize` function regexp for better emoji converting.
- Fixed: The conflict between the image uploader and lazy-loading attribute added by 3rd-party plugins.
- Fixed: PHP warnings for roles without meta data.
- Fixed: Typo in labels.
= 2.10.6 October 02, 2025 = = 2.10.6 October 02, 2025 =
* Enhancements: * Enhancements:
+120 -23
View File
@@ -10,6 +10,10 @@ if ( ! defined( 'ABSPATH' ) ) {
*/ */
class Extensions_Updater { class Extensions_Updater {
const EXTRA_TIME = 30;
const PAGINATION = 50;
/** /**
* @var array * @var array
*/ */
@@ -33,41 +37,109 @@ class Extensions_Updater {
); );
add_action( 'admin_init', array( $this, 'maybe_run_updater' ) ); add_action( 'admin_init', array( $this, 'maybe_run_updater' ) );
add_action( 'um_' . $this->updater_data['slug'] . '_package_start', array( $this, 'package_start' ), 10, 4 );
add_action( 'um_' . $this->updater_data['slug'] . '_package_complete', array( $this, 'package_complete' ) );
}
public function package_start( $version, $file_path, $delay, $per_page ) {
$hooks = array(
'start' => 'um_' . $this->updater_data['slug'] . '_package_start',
'complete' => 'um_' . $this->updater_data['slug'] . '_package_complete',
);
$debug = defined( 'UM_UPDATER_DEBUG' ) && UM_UPDATER_DEBUG;
include_once $file_path;
/**
* IMPORTANT!!!: Last action that we need to do after package is complete.
* `UM()->maybe_action_scheduler()->schedule_single_action(
* time() + 1,
* $hook,
* array(
* 'version' => $version,
* )
* );`
*/
}
public function package_complete( $version ) {
$this->set_last_version_upgrade( $version );
$this->reset_in_process_package_version();
} }
/** /**
* Maybe run upgrade if needed. * Maybe run upgrade if needed.
*/ */
public function maybe_run_updater() { public function maybe_run_updater() {
$last_version_upgrade = $this->get_last_version_upgrade(); // Cold start to avoid scheduled actions duplicates. Don't remove it.
if ( ! empty( $last_version_upgrade ) && version_compare( $last_version_upgrade, $this->updater_data['version'], '>=' ) ) { $init = get_transient( 'um_' . $this->updater_data['slug'] . '_updater_init' );
// Don't need update. if ( ! empty( $init ) ) {
return;
}
set_transient( 'um_' . $this->updater_data['slug'] . '_updater_init', true, 10 );
$next_package = $this->get_next_package();
if ( empty( $next_package ) ) {
$this->set_last_version_upgrade( $this->updater_data['version'] );
$this->reset_in_process_package_version();
return; return;
} }
$packages = $this->get_packages(); list( $package_version, $file_path ) = $next_package;
if ( ! empty( $packages ) ) {
$packages_dir = $this->get_packages_dir();
foreach ( $packages as $package_version ) {
if ( version_compare( $package_version, $last_version_upgrade, '<=' ) ) {
continue;
}
if ( version_compare( $package_version, $this->updater_data['version'], '>' ) ) { $in_process_package = $this->get_in_process_package_version();
continue; if ( ! empty( $in_process_package ) && version_compare( $in_process_package, $package_version, '=' ) ) {
} return;
$file_path = $packages_dir . $package_version . '.php';
if ( ! file_exists( $file_path ) ) {
continue;
}
include_once $file_path;
$this->set_last_version_upgrade( $package_version );
}
} }
$this->set_last_version_upgrade( $this->updater_data['version'] ); // Initialize start package action.
$action_id = UM()->maybe_action_scheduler()->schedule_single_action(
time() + self::EXTRA_TIME,
'um_' . $this->updater_data['slug'] . '_package_start',
array(
'version' => $package_version,
'path' => $file_path,
'delay' => self::EXTRA_TIME,
'per_page' => self::PAGINATION,
)
);
// As soon as scheduler single action is created - then set in progress package version to avoid duplicates of the package start action.
if ( ! empty( $action_id ) ) {
$this->set_in_process_package_version( $package_version );
}
}
private function get_next_package() {
$last_version_upgrade = $this->get_last_version_upgrade();
if ( ! empty( $last_version_upgrade ) && version_compare( $last_version_upgrade, $this->updater_data['version'], '>=' ) ) {
return null;
}
$packages = $this->get_packages();
if ( empty( $packages ) ) {
return null;
}
$packages_dir = $this->get_packages_dir();
foreach ( $packages as $package_version ) {
if ( version_compare( $package_version, $last_version_upgrade, '<=' ) ) {
continue;
}
if ( version_compare( $package_version, $this->updater_data['version'], '>' ) ) {
continue;
}
$file_path = $packages_dir . $package_version . '.php';
if ( ! file_exists( $file_path ) ) {
continue;
}
return array( $package_version, $file_path );
}
return null;
} }
/** /**
@@ -121,4 +193,29 @@ class Extensions_Updater {
private function set_last_version_upgrade( $version ) { private function set_last_version_upgrade( $version ) {
update_option( 'um_' . $this->updater_data['slug'] . '_last_version_upgrade', $version ); update_option( 'um_' . $this->updater_data['slug'] . '_last_version_upgrade', $version );
} }
/**
* Gets the last version upgrade from options.
*
* @return string The last version upgrade.
*/
private function get_in_process_package_version() {
return get_option( 'um_' . $this->updater_data['slug'] . '_in_process_package_upgrade', '' );
}
/**
* Set the last version upgrade for the updater.
*
* @param string $version The version to set as the last upgrade version.
*/
private function set_in_process_package_version( $version ) {
update_option( 'um_' . $this->updater_data['slug'] . '_in_process_package_upgrade', $version );
}
/**
* Set the last version upgrade for the updater.
*/
private function reset_in_process_package_version() {
update_option( 'um_' . $this->updater_data['slug'] . '_in_process_package_upgrade', '' );
}
} }
+19 -5
View File
@@ -325,7 +325,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
break; break;
case 'members': case 'members':
if ( ! has_shortcode( $content, 'ultimatemember' ) ) { if ( ! has_shortcode( $content, 'ultimatemember' ) ) {
$page_setting_description = __( '<strong>Warning:</strong> Members page must contain a profile form shortcode. You can get existing shortcode or create a new one <a href="edit.php?post_type=um_directory" target="_blank">here</a>.', 'ultimate-member' ); $page_setting_description = __( '<strong>Warning:</strong> Members page must contain a member directory shortcode. You can get existing shortcode or create a new one <a href="edit.php?post_type=um_directory" target="_blank">here</a>.', 'ultimate-member' );
} }
break; break;
default: default:
@@ -2969,11 +2969,9 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
} }
$request = wp_remote_post( UM()::$store_url, $post_attr ); $request = wp_remote_post( UM()::$store_url, $post_attr );
if ( ! is_wp_error( $request ) ) { if ( empty( $request ) || is_wp_error( $request ) ) {
$request = json_decode( wp_remote_retrieve_body( $request ) );
} else {
if ( self::is_license_debug_enabled() ) { if ( self::is_license_debug_enabled() ) {
error_log( '> Got `wp_error`, try again with `sslverify=true`' ); error_log( '> Got `wp_error` or empty request body, try again with `sslverify=true`' );
} }
$post_attr['sslverify'] = true; $post_attr['sslverify'] = true;
@@ -2982,6 +2980,20 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
if ( ! is_wp_error( $request ) ) { if ( ! is_wp_error( $request ) ) {
$request = json_decode( wp_remote_retrieve_body( $request ) ); $request = json_decode( wp_remote_retrieve_body( $request ) );
} }
} else {
$request = json_decode( wp_remote_retrieve_body( $request ) );
if ( empty( $request ) ) {
if ( self::is_license_debug_enabled() ) {
error_log( '> Got empty request body, try again with `sslverify=true`' );
}
$post_attr['sslverify'] = true;
$request = wp_remote_post( UM()::$store_url, $post_attr );
if ( ! is_wp_error( $request ) ) {
$request = json_decode( wp_remote_retrieve_body( $request ) );
}
}
} }
if ( self::is_license_debug_enabled() ) { if ( self::is_license_debug_enabled() ) {
@@ -2989,6 +3001,8 @@ if ( ! class_exists( 'um\admin\core\Admin_Settings' ) ) {
error_log( '> Finally got `wp_error`. Details below.' ); error_log( '> Finally got `wp_error`. Details below.' );
error_log( '>> Error code: ' . $request->get_error_code() ); error_log( '>> Error code: ' . $request->get_error_code() );
error_log( '>> Error message: ' . $request->get_error_message() ); error_log( '>> Error message: ' . $request->get_error_message() );
} elseif ( empty( $request ) ) {
error_log( '> Finally got empty UM website response.' );
} else { } else {
error_log( '### Response from UM website:' ); error_log( '### Response from UM website:' );
error_log( '>' . maybe_serialize( $request ) ); error_log( '>' . maybe_serialize( $request ) );
+1 -1
View File
@@ -55,7 +55,7 @@ if ( ! empty( $_GET['id'] ) ) {
// roles e.g. "潜水艦subs" with both latin + not-UTB-8 symbols had invalid role ID // roles e.g. "潜水艦subs" with both latin + not-UTB-8 symbols had invalid role ID
$role_id = sanitize_title( $_GET['id'] ); $role_id = sanitize_title( $_GET['id'] );
$data = get_option( "um_role_{$role_id}_meta" ); $data = get_option( "um_role_{$role_id}_meta", array() );
if ( empty( $data['_um_is_custom'] ) ) { if ( empty( $data['_um_is_custom'] ) ) {
$data['name'] = $wp_roles->roles[ $role_id ]['name']; $data['name'] = $wp_roles->roles[ $role_id ]['name'];
+5 -5
View File
@@ -31,23 +31,23 @@ if ( ! class_exists( 'um\Dependencies' ) ) {
*/ */
public $ext_required_version = array( public $ext_required_version = array(
'bbpress' => '2.0.7', 'bbpress' => '2.0.7',
'followers' => '2.1.6', 'followers' => '2.3.5',
'forumwp' => '2.1.5', 'forumwp' => '2.1.5',
'friends' => '2.1.4', 'friends' => '2.3.4',
'groups' => '2.4.2', 'groups' => '2.4.2',
'jobboardwp' => '1.0.7', 'jobboardwp' => '1.0.7',
'mailchimp' => '2.2.0', 'mailchimp' => '2.6.2',
'messaging' => '2.2.5', 'messaging' => '2.2.5',
'mycred' => '2.2.4', 'mycred' => '2.2.4',
'notices' => '2.0.5', 'notices' => '2.0.5',
'notifications' => '2.1.3', 'notifications' => '2.3.8',
'online' => '2.1.1', 'online' => '2.1.1',
'private-content' => '2.0.5', 'private-content' => '2.0.5',
'profile-completeness' => '2.2.7', 'profile-completeness' => '2.2.7',
'profile-tabs' => '1.0.0', 'profile-tabs' => '1.0.0',
'recaptcha' => '2.3.4', 'recaptcha' => '2.3.4',
'reviews' => '2.1.5', 'reviews' => '2.1.5',
'social-activity' => '2.2.0', 'social-activity' => '2.4.0',
'social-login' => '2.2.0', 'social-login' => '2.2.0',
'stripe' => '1.0.0', 'stripe' => '1.0.0',
'zapier' => '1.0.0', 'zapier' => '1.0.0',
+12 -7
View File
@@ -217,24 +217,29 @@ if ( ! class_exists( 'um\core\Shortcodes' ) ) {
return $args; return $args;
} }
/** /**
* Emoji support * Emoji support
* *
* @param $content * @param string $content
* @param bool $stripslashes
* *
* @return mixed|string * @return mixed|string
*/ */
function emotize( $content ) { public function emotize( $content, $stripslashes = true ) {
$content = stripslashes( $content ); if ( $stripslashes ) {
$content = stripslashes( $content );
}
foreach ( $this->emoji as $code => $val ) { foreach ( $this->emoji as $code => $val ) {
$regex = str_replace(array('(', ')'), array("\\" . '(', "\\" . ')'), $code); $regex = str_replace( array( '(', ')' ), array( '\\' . '(', '\\' . ')' ), $code );
$content = preg_replace('/(' . $regex . ')(\s|$)/', '<img src="' . $val . '" alt="' . $code . '" title="' . $code . '" class="emoji" />$2', $content); $content = preg_replace(
'/(' . $regex . ')(?=\s|$|<)/',
'<img src="' . $val . '" alt="' . $code . '" title="' . $code . '" class="emoji" />',
$content
);
} }
return $content; return $content;
} }
/** /**
* Remove wpautop filter for post content if it's UM core page * Remove wpautop filter for post content if it's UM core page
*/ */
+12 -15
View File
@@ -863,25 +863,22 @@ function um_profile_header_cover_area( $args ) {
data-user_id="<?php echo esc_attr( um_profile_id() ); ?>" data-ratio="<?php echo esc_attr( $args['cover_ratio'] ); ?>"> data-user_id="<?php echo esc_attr( um_profile_id() ); ?>" data-ratio="<?php echo esc_attr( $args['cover_ratio'] ); ?>">
<?php <?php
/** /**
* UM hook * Fires in the User Profile cover wrapper.
* *
* @type action * @since 1.3.x
* @title um_cover_area_content * @since 2.10.7 Added $args attribute.
* @description Cover area content change * @hook um_cover_area_content
* @input_vars *
* [{"var":"$user_id","type":"int","desc":"User ID"}] * @param {int} $user_id User Profile ID.
* @change_log * @param {array} $args User Profile data.
* ["Since: 2.0"] *
* @usage add_action( 'um_cover_area_content', 'function_name', 10, 1 ); * @example <caption>Make any custom action in the User Profile cover wrapper.</caption>
* @example * function my_cover_area_content( $user_id, $args ) {
* <?php
* add_action( 'um_cover_area_content', 'my_cover_area_content', 10, 1 );
* function my_cover_area_content( $user_id ) {
* // your code here * // your code here
* } * }
* ?> * add_action( 'um_cover_area_content', 'my_cover_area_content', 10, 2 );
*/ */
do_action( 'um_cover_area_content', um_profile_id() ); do_action( 'um_cover_area_content', um_profile_id(), $args );
if ( true === UM()->fields()->editing ) { if ( true === UM()->fields()->editing ) {
$hide_remove = ' style="display:none;"'; $hide_remove = ' style="display:none;"';
+8 -4
View File
@@ -87,14 +87,18 @@ if ( ! class_exists( 'um\frontend\User_Profile' ) ) {
/** /**
* Retrieves the user profile URL for the given comment author. * Retrieves the user profile URL for the given comment author.
* *
* @param string $comment_author_url The URL of the comment author. * @param string $comment_author_url The URL of the comment author.
* @param int $comment_id The ID of the comment. * @param int $comment_id The ID of the comment.
* @param WP_Comment $comment The comment object. * @param WP_Comment|null $comment The comment object.
* *
* @return string The user profile URL for the comment author. * @return string The user profile URL for the comment author.
*/ */
public function change_comment_author_url( $comment_author_url, $comment_id, $comment ) { public function change_comment_author_url( $comment_author_url, $comment_id, $comment ) {
return um_user_profile_url( $comment->user_id ); if ( ! is_null( $comment ) && ! empty( $comment->user_id ) ) {
return um_user_profile_url( $comment->user_id );
}
return $comment_author_url;
} }
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ultimate-member", "name": "ultimate-member",
"version": "2.10.6", "version": "2.10.7",
"author": { "author": {
"name": "Ultimate Member", "name": "Ultimate Member",
"email": "team@ultimatemember.com", "email": "team@ultimatemember.com",
+17 -1
View File
@@ -6,7 +6,7 @@ Tags: community, member, membership, user-profile, user-registration
Requires PHP: 7.0 Requires PHP: 7.0
Requires at least: 6.2 Requires at least: 6.2
Tested up to: 6.8 Tested up to: 6.8
Stable tag: 2.10.6 Stable tag: 2.10.7
License: GPLv3 License: GPLv3
License URI: http://www.gnu.org/licenses/gpl-3.0.txt License URI: http://www.gnu.org/licenses/gpl-3.0.txt
@@ -167,6 +167,22 @@ 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 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.7 2025-11-20 =
**Enhancements**
* Added: Extra condition for checking the license activation requests.
* Added: 2nd `$args` attribute to the action hook 'um_cover_area_content'.
* Tweak: Updated `Extensions_Updater` class to use Action Scheduler in the upgrade process of the UM extensions.
**Bugfixes**
* Fixed: User profile links in the comments section on the frontend when the `$comment->user_id` is empty.
* Fixed: The `emotize` function regexp for better emoji converting.
* Fixed: The conflict between the image uploader and lazy-loading attribute added by 3rd-party plugins.
* Fixed: PHP warnings for roles without meta data.
* Fixed: Typo in labels.
= 2.10.6 2025-10-02 = = 2.10.6 2025-10-02 =
**Enhancements** **Enhancements**
+2 -1
View File
@@ -3,7 +3,7 @@
* Plugin Name: Ultimate Member * Plugin Name: Ultimate Member
* Plugin URI: http://ultimatemember.com/ * Plugin URI: http://ultimatemember.com/
* Description: The easiest way to create powerful online communities and beautiful user profiles with WordPress * Description: The easiest way to create powerful online communities and beautiful user profiles with WordPress
* Version: 2.10.6 * Version: 2.10.7
* Author: Ultimate Member * Author: Ultimate Member
* Author URI: http://ultimatemember.com/ * Author URI: http://ultimatemember.com/
* License: GPLv3 * License: GPLv3
@@ -36,6 +36,7 @@ define( 'UM_VERSION', $plugin_data['Version'] );
define( 'UM_PLUGIN_NAME', $plugin_data['Name'] ); define( 'UM_PLUGIN_NAME', $plugin_data['Name'] );
define( 'UM_WP_FUNCTIONS_VERSION', '6.8.0' ); // Updates every major WordPress release. define( 'UM_WP_FUNCTIONS_VERSION', '6.8.0' ); // Updates every major WordPress release.
define( 'UM_LICENSE_REQUEST_DEBUG', false ); // Set true then need to debug the license request. define( 'UM_LICENSE_REQUEST_DEBUG', false ); // Set true then need to debug the license request.
define( 'UM_UPDATER_DEBUG', false ); // Set true then need to debug the upgrade packages.
// define( 'UM_DEV_MODE', true ); // define( 'UM_DEV_MODE', true );
require_once 'includes/class-functions.php'; require_once 'includes/class-functions.php';