@@ -244,6 +249,5 @@ if ( ! class_exists( 'um\admin\core\Admin_DragDrop' ) ) {
UM()->member_directory()->sort_data_types,
)
);
@@ -566,7 +567,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Enqueue' ) ) {
* Load Gutenberg scripts
*/
public function load_gutenberg_js() {
- //disable Gutenberg scripts to avoid the conflicts
+ /** This filter is documented in includes/core/class-blocks.php */
$disable_script = apply_filters( 'um_disable_blocks_script', false );
if ( $disable_script ) {
return;
diff --git a/includes/admin/core/class-admin-forms.php b/includes/admin/core/class-admin-forms.php
index 260d29a9..92355732 100644
--- a/includes/admin/core/class-admin-forms.php
+++ b/includes/admin/core/class-admin-forms.php
@@ -125,6 +125,9 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
'target' => array(),
'class' => array(),
),
+ 'button' => array(
+ 'class' => array(),
+ ),
'i' => array(
'class' => array(),
),
@@ -576,33 +579,39 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
*
* @return bool|string
*/
- function render_users_dropdown( $field_data ) {
+ public function render_users_dropdown( $field_data ) {
if ( empty( $field_data['id'] ) ) {
return false;
}
$multiple = ! empty( $field_data['multi'] ) ? 'multiple' : '';
- $id = ( ! empty( $this->form_data['prefix_id'] ) ? $this->form_data['prefix_id'] : '' ) . '_' . $field_data['id'];
+ $id = ( ! empty( $this->form_data['prefix_id'] ) ? $this->form_data['prefix_id'] : '' ) . '_' . $field_data['id'];
$id_attr = ' id="' . esc_attr( $id ) . '" ';
- $class = ! empty( $field_data['class'] ) ? $field_data['class'] . ' ' : ' ';
- $class .= ! empty( $field_data['size'] ) ? 'um-' . $field_data['size'] . '-field' : 'um-long-field';
+ $class = ! empty( $field_data['class'] ) ? $field_data['class'] . ' ' : ' ';
+ $class .= ! empty( $field_data['size'] ) ? 'um-' . $field_data['size'] . '-field' : 'um-long-field';
$class_attr = ' class="um-forms-field um-user-select-field' . esc_attr( $class ) . '" ';
$data = array(
'field_id' => $field_data['id'],
+ 'avatar' => ! empty( $field_data['avatar'] ) ? 1 : 0,
);
+ if ( ! empty( $field_data['data'] ) && is_array( $field_data['data'] ) ) {
+ $data = array_merge( $data, $field_data['data'] );
+ }
+
$data_attr = '';
foreach ( $data as $key => $value ) {
$data_attr .= ' data-' . $key . '="' . esc_attr( $value ) . '" ';
}
- $name = $field_data['id'];
- $name = ! empty( $this->form_data['prefix_id'] ) ? $this->form_data['prefix_id'] . '[' . $name . ']' : $name;
+ $name = $field_data['id'];
+ $name = ! empty( $this->form_data['prefix_id'] ) ? $this->form_data['prefix_id'] . '[' . $name . ']' : $name;
$hidden_name_attr = ' name="' . $name . '" ';
- $name = $name . ( ! empty( $field_data['multi'] ) ? '[]' : '' );
+
+ $name = $name . ( ! empty( $field_data['multi'] ) ? '[]' : '' );
$name_attr = ' name="' . $name . '" ';
$value = $this->get_field_value( $field_data );
@@ -620,15 +629,22 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
$options = '';
if ( ! empty( $users ) ) {
foreach ( $users as $user ) {
- $options .= '
';
+ if ( ! empty( $field_data['avatar'] ) ) {
+ $url = get_avatar_url( $user->ID, 'size=20' );
+ $options .= '
';
+ }
}
}
+ $placeholder = ! empty( $field_data['placeholder'] ) ? $field_data['placeholder'] : __( 'Select Users', 'ultimate-member' );
+
$hidden = '';
if ( ! empty( $multiple ) ) {
$hidden = "
";
return $html;
}
@@ -869,8 +885,11 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
$value = $this->get_field_value( $field_data );
+ add_filter( 'wp_default_editor', array( &$this, 'set_default_editor_fix' ) );
+
ob_start();
- wp_editor( $value,
+ wp_editor(
+ $value,
$id,
array(
'textarea_name' => $name,
@@ -878,14 +897,25 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
'editor_height' => 425,
'wpautop' => false,
'media_buttons' => false,
- 'editor_class' => $class
+ 'editor_class' => $class,
)
);
$html = ob_get_clean();
+
+ remove_filter( 'wp_default_editor', array( &$this, 'set_default_editor_fix' ) );
+
return $html;
}
+ /**
+ * Fix the displaying wp_editor on macOS
+ *
+ * @return string
+ */
+ public function set_default_editor_fix() {
+ return 'html';
+ }
/**
* @param $field_data
@@ -1590,16 +1620,30 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
if ( ! empty( $values ) && is_array( $values ) ) {
foreach ( $values as $k => $value ) {
- $other_key = '';
+ $other_key = '';
$other_label = '';
+ $other_type = '';
+ $other_order = '';
+
if ( is_array( $value ) ) {
- $keys = array_keys( $value );
+ $keys = array_keys( $value );
$other_key = $keys[0];
- $labels = array_values( $value );
- $other_label = $labels[0];
+ if ( ! empty( $value['label'] ) ) {
+ $other_label = $value['label'];
+ } else {
+ $labels = array_values( $value );
+ $other_label = $labels[0];
+ }
+
+ if ( ! empty( $value['type'] ) ) {
+ $other_type = $value['type'];
+ }
+ if ( ! empty( $value['order'] ) ) {
+ $other_order = $value['order'];
+ }
} else {
- if ( ! in_array( $value, array_keys( $field_data['options'] ) ) ) {
+ if ( ! array_key_exists( $value, $field_data['options'] ) ) {
continue;
}
}
@@ -1609,7 +1653,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
$options = '';
foreach ( $field_data['options'] as $key => $option ) {
if ( is_array( $value ) ) {
- $selected = selected( $key == 'other', true, false );
+ $selected = selected( 'other' === $key, true, false );
} else {
$selected = selected( $key == $value, true, false );
}
@@ -1621,12 +1665,25 @@ if ( ! class_exists( 'um\admin\core\Admin_Forms' ) ) {
if ( $sorting ) {
$html .= '
- ";
+
+ $data_types_html = '';
+ foreach ( UM()->member_directory()->sort_data_types as $type_key => $type_label ) {
+ $data_types_html .= '
+ ';
}
} elseif ( ! empty( $field_data['show_default_number'] ) && is_numeric( $field_data['show_default_number'] ) && $field_data['show_default_number'] > 0 ) {
$i = 0;
diff --git a/includes/admin/core/class-admin-navmenu.php b/includes/admin/core/class-admin-navmenu.php
index bb0dcd4f..d2eba992 100644
--- a/includes/admin/core/class-admin-navmenu.php
+++ b/includes/admin/core/class-admin-navmenu.php
@@ -47,16 +47,13 @@ if ( ! class_exists( 'um\admin\core\Admin_Navmenu' ) ) {
* Fires just before the move buttons of a nav menu item in the menu editor.
* Adds block "Ultimate Member Menu Settings"
*
- * @since WP 5.4.0
- * @hook wp_nav_menu_item_custom_fields
- *
- * @param int $item_id Menu item ID.
+ * @param int $item_id Menu item ID.
* @param \WP_Post $item Menu item data object.
- * @param int $depth Depth of menu item. Used for padding.
+ * @param int $depth Depth of menu item. Used for padding.
* @param \stdClass $args An object of menu item arguments.
- * @param int $id Nav menu ID.
+ * @param int $id Nav menu ID.
*/
- function wp_nav_menu_item_custom_fields( $item_id, $item, $depth, $args, $id = null ) {
+ public function wp_nav_menu_item_custom_fields( $item_id, $item, $depth, $args, $id = null ) {
$um_nav_public = get_post_meta( $item->ID, 'menu-item-um_nav_public', true );
$_nav_roles_meta = get_post_meta( $item->ID, 'menu-item-um_nav_roles', true );
diff --git a/includes/admin/core/class-admin-users.php b/includes/admin/core/class-admin-users.php
index 09cef460..e8c7c296 100644
--- a/includes/admin/core/class-admin-users.php
+++ b/includes/admin/core/class-admin-users.php
@@ -1,13 +1,12 @@
admin()->check_ajax_nonce();
$search_request = ! empty( $_REQUEST['search'] ) ? sanitize_text_field( $_REQUEST['search'] ) : '';
@@ -53,17 +51,26 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
$args = array(
'fields' => array( 'ID', 'user_login' ),
'paged' => $page,
- 'number' => $per_page
+ 'number' => $per_page,
);
if ( ! empty( $search_request ) ) {
- $args['search'] = $search_request;
+ $args['search'] = '*' . $search_request . '*';
}
+ $args = apply_filters( 'um_get_users_list_ajax_args', $args );
+
$users_query = new \WP_User_Query( $args );
$users = $users_query->get_results();
$total_count = $users_query->get_total();
+ if ( ! empty( $_REQUEST['avatar'] ) ) {
+ foreach ( $users as $key => $user ) {
+ $url = get_avatar_url( $user->ID );
+ $users[ $key ]->img = $url;
+ }
+ }
+
wp_send_json_success(
array(
'users' => $users,
@@ -72,7 +79,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
);
}
-
/**
* Restrict the edit/delete users via wp-admin screen by the UM role capabilities
*
@@ -83,7 +89,7 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
*
* @return mixed
*/
- function map_caps_by_role( $allcaps, $cap, $args, $user ) {
+ public function map_caps_by_role( $allcaps, $cap, $args, $user ) {
if ( isset( $cap[0] ) && $cap[0] == 'edit_users' ) {
if ( isset( $args[0] ) && isset( $args[1] ) && ! user_can( $args[1], 'administrator' ) && $args[0] == 'edit_user' ) {
if ( isset( $args[2] ) && ! UM()->roles()->um_current_user_can( 'edit', $args[2] ) ) {
@@ -107,13 +113,12 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
return $allcaps;
}
-
/**
* Does an action to user asap
*
* @param string $action
*/
- function user_action_hook( $action ) {
+ public function user_action_hook( $action ) {
switch ( $action ) {
default:
/**
@@ -176,12 +181,12 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
}
}
-
/**
* Add UM Bulk actions to Users List Table
*
*/
- function restrict_manage_users() { ?>
+ public function restrict_manage_users() {
+ ?>
@@ -197,16 +202,16 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
- ID;
$actions['frontend_profile'] = '
' . __( 'View profile', 'ultimate-member' ) . ' ';
@@ -312,14 +316,13 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
return $actions;
}
-
/**
* Change default sorting at WP Users list table
*
* @param array $args
* @return array
*/
- function hide_by_caps( $args ) {
+ public function hide_by_caps( $args ) {
if ( ! current_user_can( 'administrator' ) ) {
$can_view_roles = um_user( 'can_view_roles' );
if ( um_user( 'can_view_all' ) && ! empty( $can_view_roles ) ) {
@@ -330,7 +333,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
return $args;
}
-
/**
* Change default sorting at WP Users list table
*
@@ -350,7 +352,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
return $query;
}
-
/**
* Filter WP users by UM Status
*
@@ -385,7 +386,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
return $query;
}
-
/**
* Add status links to WP Users List Table
*
@@ -474,7 +474,6 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
return $views;
}
-
/**
* Bulk user editing actions
*/
@@ -561,14 +560,13 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
}
}
-
/**
* Sets redirect URI after bulk action
*
* @param string $uri
* @return string
*/
- function set_redirect_uri( $uri ) {
+ public function set_redirect_uri( $uri ) {
if ( ! empty( $_REQUEST['s'] ) ) {
$uri = add_query_arg( 's', sanitize_text_field( $_REQUEST['s'] ), $uri );
@@ -581,6 +579,5 @@ if ( ! class_exists( 'um\admin\core\Admin_Users' ) ) {
return $uri;
}
-
}
}
diff --git a/includes/admin/core/list-tables/roles-list-table.php b/includes/admin/core/list-tables/roles-list-table.php
index 1ac73f4d..743171c2 100644
--- a/includes/admin/core/list-tables/roles-list-table.php
+++ b/includes/admin/core/list-tables/roles-list-table.php
@@ -42,6 +42,23 @@ if ( isset( $_GET['action'] ) ) {
}
delete_option( "um_role_{$role_key}_meta" );
+ /**
+ * Fires after delete UM role.
+ *
+ * @since 2.6.3
+ * @hook um_after_delete_role
+ *
+ * @param {string} $role_key Role key.
+ * @param {array} $role_meta Role meta.
+ *
+ * @example
Make any custom action after deleting UM role.
+ * function my_custom_um_after_delete_role( $role_key, $role_meta ) {
+ * // your code here
+ * }
+ * add_action( 'um_after_delete_role', 'my_custom_um_after_delete_role', 10, 2 );
+ */
+ do_action( 'um_after_delete_role', $role_key, $role_meta );
+
$um_roles = array_diff( $um_roles, array( $role_key ) );
$roleID = 'um_' . $role_key;
@@ -114,6 +131,23 @@ if ( isset( $_GET['action'] ) ) {
}
delete_option( "um_role_{$role_key}_meta" );
+
+ /**
+ * Fires after delete UM role meta.
+ *
+ * @since 2.6.3
+ * @hook um_after_delete_role_meta
+ *
+ * @param {string} $role_key Role key.
+ * @param {array} $role_meta Role meta.
+ *
+ * @example
Make any custom action after deleting UM role meta.
+ * function my_custom_um_after_delete_role_meta( $role_key, $role_meta ) {
+ * // your code here
+ * }
+ * add_action( 'um_after_delete_role_meta', 'my_custom_um_after_delete_role_meta', 10, 2 );
+ */
+ do_action( 'um_after_delete_role_meta', $role_key, $role_meta );
}
um_js_redirect( add_query_arg( 'msg', 'reset', $redirect ) );
@@ -362,7 +396,25 @@ class UM_Roles_List_Table extends WP_List_Table {
}
}
- return sprintf('%1$s %2$s', '
' . stripslashes( $item['name'] ) . ' ', $this->row_actions( $actions ) );
+ /**
+ * Filters the role actions in WP ListTable Ultimate Member > Roles screen.
+ *
+ * @since 2.6.3
+ * @hook um_role_row_actions
+ *
+ * @param {array} $actions Action links.
+ * @param {string} $id Role key.
+ *
+ * @example
Add custom action to role's row.
+ * function my_custom_um_role_row_actions( $actions, $id ) {
+ * $actions['{action_key}'] = "
Action Title ";
+ * return $actions;
+ * }
+ * add_action( 'um_role_row_actions', 'my_custom_um_role_row_actions', 10, 2 );
+ */
+ $actions = apply_filters( 'um_role_row_actions', $actions, $id );
+
+ return sprintf( '%1$s %2$s', '
' . stripslashes( $item['name'] ) . ' ', $this->row_actions( $actions ) );
}
diff --git a/includes/admin/templates/directory/sorting.php b/includes/admin/templates/directory/sorting.php
index b7f7832a..9a9566d0 100644
--- a/includes/admin/templates/directory/sorting.php
+++ b/includes/admin/templates/directory/sorting.php
@@ -24,6 +24,27 @@ $fields = array(
'value' => UM()->query()->get_meta_value( '_um_sortby_custom', null, 'na' ),
'conditional' => array( '_um_sortby', '=', 'other' ),
),
+ array(
+ 'id' => '_um_sortby_custom_type',
+ 'type' => 'select',
+ 'label' => __( 'Data type', 'ultimate-member' ),
+ 'tooltip' => __( 'To correct sort by a custom field, choose a data type', 'ultimate-member' ),
+ 'value' => UM()->query()->get_meta_value( '_um_sortby_custom_type', null, 'CHAR' ),
+ 'options' => UM()->member_directory()->sort_data_types,
+ 'conditional' => array( '_um_sortby', '=', 'other' ),
+ ),
+ array(
+ 'id' => '_um_sortby_custom_order',
+ 'type' => 'select',
+ 'label' => __( 'Order', 'ultimate-member' ),
+ 'tooltip' => __( 'To correct sort by a custom field, choose an order', 'ultimate-member' ),
+ 'value' => UM()->query()->get_meta_value( '_um_sortby_custom_order', null, 'ASC' ),
+ 'options' => array(
+ 'ASC' => __( 'ASC', 'ultimate-member' ),
+ 'DESC' => __( 'DESC', 'ultimate-member' ),
+ ),
+ 'conditional' => array( '_um_sortby', '=', 'other' ),
+ ),
array(
'id' => '_um_sortby_custom_label',
'type' => 'text',
diff --git a/includes/admin/templates/role/role-edit.php b/includes/admin/templates/role/role-edit.php
index 36845ca5..175ba84f 100644
--- a/includes/admin/templates/role/role-edit.php
+++ b/includes/admin/templates/role/role-edit.php
@@ -1,4 +1,5 @@
-options()->update( 'custom_roles_increment', $auto_increment );
}
+
+ $update = false;
}
- $role_meta = $data;
+ /**
+ * Filters the role meta before save it to DB.
+ *
+ * @param {array} $data Role meta.
+ * @param {string} $id Role key.
+ * @param {bool} $update Create or update role. "True" if update.
+ *
+ * @since 2.6.3
+ * @hook um_role_edit_data
+ *
+ * @example
Add custom metadata for role on saving.
+ * function my_custom_um_role_edit_data( $data, $id, $update ) {
+ * $data['{meta_key}'] = {meta_value}; // set your meta key and meta value
+ * return $data;
+ * }
+ * add_action( 'um_role_edit_data', 'my_custom_um_role_edit_data', 10, 3 );
+ * @example
Force remove role's metadata on saving when update.
+ * function my_custom_um_role_edit_data( $data, $id, $update ) {
+ * if ( true === $update ) {
+ * unset( $data['{meta_key}'] ); // set your meta key
+ * }
+ * return $data;
+ * }
+ * add_action( 'um_role_edit_data', 'my_custom_um_role_edit_data', 10, 3 );
+ */
+ $role_meta = apply_filters( 'um_role_edit_data', $data, $id, $update );
unset( $role_meta['id'] );
update_option( "um_role_{$id}_meta", $role_meta );
diff --git a/includes/class-config.php b/includes/class-config.php
index 1892d6fe..3273fa67 100644
--- a/includes/class-config.php
+++ b/includes/class-config.php
@@ -1,13 +1,12 @@
It adds iframe HTML tag and 'onclick' attribute for strong tag.
+ * function add_extra_kses_allowed_tags( $allowed_html, $context ) {
+ * if ( 'templates' === $context ) {
+ * $allowed_html['iframe'] = array(
+ * 'src' => true,
+ * );
+ * $allowed_html['strong']['onclick'] = true;
+ * }
+ * return $allowed_html;
+ * }
+ * add_filter( 'um_late_escaping_allowed_tags', 'add_extra_kses_allowed_tags', 10, 2 );
*/
$allowed_html = apply_filters( 'um_late_escaping_allowed_tags', $allowed_html, $context );
diff --git a/includes/core/class-account.php b/includes/core/class-account.php
index 446a5cb2..f8bea1b5 100644
--- a/includes/core/class-account.php
+++ b/includes/core/class-account.php
@@ -472,7 +472,7 @@ if ( ! class_exists( 'um\core\Account' ) ) {
*/
function tab_link( $id ) {
- if ( get_option( 'permalink_structure' ) ) {
+ if ( UM()->is_permalinks ) {
$url = trailingslashit( untrailingslashit( um_get_core_page( 'account' ) ) );
$url = $url . $id . '/';
diff --git a/includes/core/class-blocks.php b/includes/core/class-blocks.php
index 583743fb..1c8eb590 100644
--- a/includes/core/class-blocks.php
+++ b/includes/core/class-blocks.php
@@ -1,31 +1,40 @@
options()->get( 'restricted_blocks' );
+ if ( empty( $restricted_blocks ) ) {
+ return $settings;
+ }
+
if ( empty( $settings['attributes']['um_is_restrict'] ) ) {
$settings['attributes']['um_is_restrict'] = array(
'type' => 'boolean',
@@ -55,9 +64,31 @@ if ( ! class_exists( 'um\core\Blocks' ) ) {
return $settings;
}
-
+ /**
+ * Register UM Blocks.
+ *
+ * @uses register_block_type_from_metadata()
+ */
public function block_editor_render() {
- //disable Gutenberg scripts to avoid the conflicts
+ /**
+ * Filters the variable to disable adding UM Blocks to Gutenberg editor.
+ *
+ * Note: It's "false" by default. To disable Gutenberg scripts to avoid the conflicts set it to "true"
+ *
+ * @since 2.6.3
+ * @hook um_disable_blocks_script
+ *
+ * @param {bool} $disable_script Disabling block scripts variable.
+ *
+ * @return {bool} It's true for disabling block scripts.
+ *
+ * @example
Disable block scripts.
+ * function my_custom_um_disable_blocks_script( $disable_script ) {
+ * $disable_script = true;
+ * return $disable_script;
+ * }
+ * add_filter( 'um_disable_blocks_script', 'my_custom_um_disable_blocks_script', 10, 1 );
+ */
$disable_script = apply_filters( 'um_disable_blocks_script', false );
if ( $disable_script ) {
return;
@@ -70,7 +101,7 @@ if ( ! class_exists( 'um\core\Blocks' ) ) {
$blocks = array(
'um-block/um-member-directories' => array(
- 'render_callback' => array( $this, 'um_member_directories_render' ),
+ 'render_callback' => array( $this, 'member_directories_render' ),
'attributes' => array(
'member_id' => array(
'type' => 'string',
@@ -78,7 +109,7 @@ if ( ! class_exists( 'um\core\Blocks' ) ) {
),
),
'um-block/um-forms' => array(
- 'render_callback' => array( $this, 'um_forms_render' ),
+ 'render_callback' => array( $this, 'forms_render' ),
'attributes' => array(
'form_id' => array(
'type' => 'string',
@@ -86,10 +117,10 @@ if ( ! class_exists( 'um\core\Blocks' ) ) {
),
),
'um-block/um-password-reset' => array(
- 'render_callback' => array( $this, 'um_password_reset_render' ),
+ 'render_callback' => array( $this, 'password_reset_render' ),
),
'um-block/um-account' => array(
- 'render_callback' => array( $this, 'um_account_render' ),
+ 'render_callback' => array( $this, 'account_render' ),
'attributes' => array(
'tab' => array(
'type' => 'string',
@@ -104,8 +135,16 @@ if ( ! class_exists( 'um\core\Blocks' ) ) {
}
}
-
- public function um_member_directories_render( $atts ) {
+ /**
+ * Renders member directory block.
+ *
+ * @param array $atts Block attributes.
+ *
+ * @return string
+ *
+ * @uses apply_shortcodes()
+ */
+ public function member_directories_render( $atts ) {
$shortcode = '[ultimatemember';
if ( isset( $atts['member_id'] ) && '' !== $atts['member_id'] ) {
@@ -117,8 +156,16 @@ if ( ! class_exists( 'um\core\Blocks' ) ) {
return apply_shortcodes( $shortcode );
}
-
- public function um_forms_render( $atts ) {
+ /**
+ * Renders UM Form block.
+ *
+ * @param array $atts Block attributes.
+ *
+ * @return string
+ *
+ * @uses apply_shortcodes()
+ */
+ public function forms_render( $atts ) {
if ( isset( $atts['form_id'] ) && '' !== $atts['form_id'] ) {
$mode = get_post_meta( $atts['form_id'], '_um_mode', true );
if ( 'profile' === $mode && ( um_is_core_page( 'account' ) || um_is_core_page( 'user' ) ) ) {
@@ -136,15 +183,29 @@ if ( ! class_exists( 'um\core\Blocks' ) ) {
return apply_shortcodes( $shortcode );
}
-
- public function um_password_reset_render() {
+ /**
+ * Renders UM Reset Password form block.
+ *
+ * @return string
+ *
+ * @uses apply_shortcodes()
+ */
+ public function password_reset_render() {
$shortcode = '[ultimatemember_password]';
return apply_shortcodes( $shortcode );
}
-
- public function um_account_render( $atts ) {
+ /**
+ * Renders UM Account block.
+ *
+ * @param array $atts Block attributes.
+ *
+ * @return string
+ *
+ * @uses apply_shortcodes()
+ */
+ public function account_render( $atts ) {
if ( um_is_core_page( 'account' ) || um_is_core_page( 'user' ) ) {
return '';
}
diff --git a/includes/core/class-builtin.php b/includes/core/class-builtin.php
index ea0b80fd..805b258a 100644
--- a/includes/core/class-builtin.php
+++ b/includes/core/class-builtin.php
@@ -1,12 +1,12 @@
array(
'_title' => array(
'mode' => 'required',
- 'error' => __('You must provide a title','ultimate-member')
+ 'error' => __( 'You must provide a title', 'ultimate-member' ),
),
'_metakey' => array(
'mode' => 'unique',
),
- )
+ ),
+ ),
+ 'spotify' => array(
+ 'name' => __( 'Spotify URL', 'ultimate-member' ),
+ 'col1' => array('_title','_metakey','_help','_visibility'),
+ 'col2' => array('_label','_placeholder','_public','_roles','_validate','_custom_validate'),
+ 'col3' => array('_required','_editable','_icon'),
+ 'validate' => array(
+ '_title' => array(
+ 'mode' => 'required',
+ 'error' => __( 'You must provide a title', 'ultimate-member' ),
+ ),
+ '_metakey' => array(
+ 'mode' => 'unique',
+ ),
+ ),
),
/*'group' => array(
@@ -1497,6 +1512,7 @@ if ( ! class_exists( 'um\core\Builtin' ) ) {
$array['unique_username_or_email'] = __('Unique Username/E-mail','ultimate-member');
$array['url'] = __('Website URL','ultimate-member');
$array['youtube_url'] = __('YouTube Profile','ultimate-member');
+ $array['spotify_url'] = __('Spotify URL','ultimate-member');
$array['telegram_url'] = __('Telegram URL','ultimate-member');
$array['discord'] = __('Discord ID','ultimate-member');
$array['tiktok_url'] = __('TikTok URL','ultimate-member');
diff --git a/includes/core/class-external-integrations.php b/includes/core/class-external-integrations.php
index 2d33de79..aa100f34 100644
--- a/includes/core/class-external-integrations.php
+++ b/includes/core/class-external-integrations.php
@@ -31,7 +31,8 @@ if ( ! class_exists( 'um\core\External_Integrations' ) ) {
add_action( 'um_access_fix_external_post_content', array( &$this, 'forumwp_fix' ), 11 );
add_action( 'um_access_fix_external_post_content', array( &$this, 'woocommerce_fix' ), 12 );
- add_filter( 'um_localize_permalink_filter', array( &$this, 'um_localize_permalink_filter' ), 10, 2 );
+ add_filter( 'um_external_profile_url', array( &$this, 'um_localize_profile_url' ), 10, 2 );
+ add_filter( 'um_get_current_page_url', array( &$this, 'um_localize_profile_nav_url' ), 10, 2 );
add_filter( 'icl_ls_languages', array( &$this, 'um_core_page_wpml_permalink' ), 10, 1 );
// Integration for the "Transposh Translation Filter" plugin
@@ -50,7 +51,6 @@ if ( ! class_exists( 'um\core\External_Integrations' ) ) {
* UM filter - Restore original arguments on translated page
*
* @description Restore original arguments on load shortcode if they are missed in the WPML translation
- * @hook um_pre_args_setup
*
* @global \SitePress $sitepress
* @param array $args
@@ -81,7 +81,6 @@ if ( ! class_exists( 'um\core\External_Integrations' ) ) {
* Integration for the "Transposh Translation Filter" plugin
*
* @description Fix issue "404 Not Found" on profile page
- * @hook template_redirect
* @see http://transposh.org/
*
* @global transposh_plugin $my_transposh_plugin
@@ -175,76 +174,110 @@ if ( ! class_exists( 'um\core\External_Integrations' ) ) {
return $single_template;
}
-
/**
- * @param $profile_url
- * @param $page_id
+ * Change user profile URL for WPML compatibility.
*
- * @return bool|false|string
+ * @see \um\core\Permalinks::profile_permalink()
+ *
+ * @param bool|string $profile_url Profile URL.
+ * @param string $slug Profile slug.
+ *
+ * @return string
*/
- function um_localize_permalink_filter( $profile_url, $page_id ) {
-
- if ( ! $this->is_wpml_active() )
+ public function um_localize_profile_url( $profile_url, $slug ) {
+ if ( ! $this->is_wpml_active() ) {
return $profile_url;
+ }
- /*if ( function_exists( 'icl_get_current_language' ) && icl_get_current_language() != icl_get_default_language() ) {
- if ( get_the_ID() > 0 && get_post_meta( get_the_ID(), '_um_wpml_user', true ) == 1 ) {
- $profile_url = get_permalink( get_the_ID() );
- }
- }*/
+ $page_id = UM()->config()->permalinks['user'];
+ $lang_post_id = apply_filters( 'wpml_object_id', $page_id, 'page', true );
- // WPML compatibility
- if ( function_exists( 'icl_object_id' ) ) {
- $language_code = ICL_LANGUAGE_CODE;
- $lang_post_id = icl_object_id( $page_id , 'page', true, $language_code );
+ if ( $lang_post_id && $lang_post_id !== $page_id ) {
+ $user_page_url = get_permalink( $lang_post_id );
- if ( $lang_post_id != 0 ) {
- $profile_url = get_permalink( $lang_post_id );
+ if ( UM()->is_permalinks ) {
+ if ( false === strpos( $user_page_url, '?' ) ) {
+ $profile_url = trailingslashit( $user_page_url ) . trailingslashit( $slug );
+ } else {
+ $profile_url = str_replace( '?', trailingslashit( $slug ) . '?', $user_page_url );
+ }
} else {
- // No page found, it's most likely the homepage
- global $sitepress;
- $profile_url = $sitepress->language_url( $language_code );
+ $profile_url = add_query_arg( 'um_user', strtolower( $slug ), $user_page_url );
}
}
return $profile_url;
}
-
/**
- * @param $array
+ * Change current URL for WPML compatibility.
*
- * @return mixed
+ * Note: It's used for User Profile nav links fix
+ *
+ * @see \um\core\Permalinks::get_current_url()
+ *
+ * @param string $page_url Current URL.
+ * @param bool $no_query_params Ignore $_GET attributes in URL. "true" == ignore.
+ *
+ * @return string
*/
- function um_core_page_wpml_permalink( $array ) {
-
- if ( ! $this->is_wpml_active() )
- return $array;
-
- global $sitepress;
- if( ! um_is_core_page("user") ) return $array;
- if( ! defined("ICL_LANGUAGE_CODE") ) return $array;
- if( ! function_exists('icl_object_id') ) return $array;
-
- // Permalink base
- $permalink_base = UM()->options()->get( 'permalink_base' );
-
- // Get user slug
- $profile_slug = strtolower( get_user_meta( um_profile_id(), "um_user_profile_url_slug_{$permalink_base}", true ) );
- $current_language = ICL_LANGUAGE_CODE;
- foreach ( $array as $lang_code => $arr ) {
- $sitepress->switch_lang( $lang_code );
- $user_page = um_get_core_page( "user" );
-
- $array[ $lang_code ]['url'] = "{$user_page}{$profile_slug}/";
+ public function um_localize_profile_nav_url( $page_url, $no_query_params ) {
+ if ( ! $this->is_wpml_active() ) {
+ return $page_url;
}
- $sitepress->switch_lang( $current_language );
+ if ( false === $no_query_params ) {
+ return $page_url;
+ }
+
+ if ( ! empty( $_GET['lang'] ) ) {
+ $page_url = add_query_arg( 'lang', sanitize_key( $_GET['lang'] ), $page_url );
+ }
+
+ return $page_url;
+ }
+
+ /**
+ * Filters the displayed languages of the WPML language switcher.
+ *
+ * @see https://wpml.org/wpml-hook/icl_ls_languages/
+ *
+ * @param array $array Collection of active languages to display in the language switcher.
+ *
+ * @return array
+ */
+ public function um_core_page_wpml_permalink( $array ) {
+ if ( $this->is_wpml_active() && um_is_core_page( 'user' ) && is_array( $array ) ) {
+ global $sitepress;
+
+ $current_language = wpml_get_current_language();
+ $slug = strtolower( UM()->user()->get_profile_slug( um_profile_id() ) );
+
+ foreach ( $array as $lang_code => $arr ) {
+ $sitepress->switch_lang( $lang_code );
+
+ $lang_post_id = apply_filters( 'wpml_object_id', UM()->config()->permalinks['user'], 'page', true );
+ $user_page_url = get_permalink( $lang_post_id );
+
+ if ( UM()->is_permalinks ) {
+ if ( false === strpos( $user_page_url, '?' ) ) {
+ $profile_url = trailingslashit( $user_page_url ) . trailingslashit( $slug );
+ } else {
+ $profile_url = str_replace( '?', trailingslashit( $slug ) . '?', $user_page_url );
+ }
+ } else {
+ $profile_url = add_query_arg( 'um_user', strtolower( $slug ), $user_page_url );
+ }
+
+ $array[ $lang_code ]['url'] = $profile_url;
+ }
+
+ $sitepress->switch_lang( $current_language );
+ }
return $array;
}
-
/**
* Check if WPML is active
*
diff --git a/includes/core/class-fields.php b/includes/core/class-fields.php
index 3b197db9..34a3677a 100644
--- a/includes/core/class-fields.php
+++ b/includes/core/class-fields.php
@@ -1,13 +1,12 @@
get_atts( $key, $classes, $conditional, $data ) . '>';
@@ -2814,7 +2817,7 @@ if ( ! class_exists( 'um\core\Fields' ) ) {
$output .= '
';
- if ( isset( $data['html'] ) && $data['html'] != 0 && $key != "description" ) {
+ if ( isset( $data['html'] ) && $data['html'] != 0 && 'description' !== $key ) {
$textarea_settings = array(
'media_buttons' => false,
@@ -2863,7 +2866,10 @@ if ( ! class_exists( 'um\core\Fields' ) ) {
$output .= ob_get_clean();
$output .= '
' . $placeholder . ' ';
} else {
- $textarea_field_value = ! empty( $data['html'] ) ? $field_value : strip_tags( $field_value );
+ $textarea_field_value = '';
+ if ( ! empty( $field_value ) ) {
+ $textarea_field_value = ! empty( $data['html'] ) ? $field_value : wp_strip_all_tags( $field_value );
+ }
$output .= '
';
}
@@ -3881,9 +3887,10 @@ if ( ! class_exists( 'um\core\Fields' ) ) {
$um_field_checkbox_item_title = $v;
- $v = $this->filter_field_non_utf8_value( $v );
+ $v = $this->filter_field_non_utf8_value( $v );
+ $value_attr = ( ! empty( $v ) && is_string( $v ) ) ? wp_strip_all_tags( $v ) : $v;
- $output .= '
is_selected( $key, $v, $data ) ) {
$output .= 'checked';
@@ -3892,10 +3899,9 @@ if ( ! class_exists( 'um\core\Fields' ) ) {
$output .= ' />';
if ( ! empty( $disabled ) && $this->is_selected( $key, $v, $data ) ) {
- $output .= $this->disabled_hidden_field( $key . '[]', strip_tags( $v ) );
+ $output .= $this->disabled_hidden_field( $key . '[]', $value_attr );
}
-
$output .= '
';
/**
* UM hook
diff --git a/includes/core/class-fonticons.php b/includes/core/class-fonticons.php
index 6d964a23..9d7abd74 100644
--- a/includes/core/class-fonticons.php
+++ b/includes/core/class-fonticons.php
@@ -1,42 +1,47 @@
$file ) {
-
$css = file_get_contents( $file );
- if ( $c == 'fa' ) {
- preg_match_all('/\.(um-faicon-.*?):before/', $css, $matches);
+ if ( 'fa' === $c ) {
+ preg_match_all( '/\.(um-faicon-.*?):before/', $css, $matches );
} else {
- preg_match_all('/\.(um-icon-.*?):before/', $css, $matches);
+ preg_match_all( '/\.(um-icon-.*?):before/', $css, $matches );
}
foreach ( $matches[1] as $match ) {
- $icon = str_replace( ':before', '', $match );
+ $icon = str_replace( ':before', '', $match );
$array[] = $icon;
}
$array = array_unique( $array );
@@ -45,9 +50,7 @@ if ( ! class_exists( 'um\core\FontIcons' ) ) {
update_option( 'um_cache_fonticons', $array );
}
- $this->all = get_option( 'um_cache_fonticons' );
-
+ $this->all = $cached_option;
}
-
}
-}
\ No newline at end of file
+}
diff --git a/includes/core/class-form.php b/includes/core/class-form.php
index 1f958d90..bbe6d10f 100644
--- a/includes/core/class-form.php
+++ b/includes/core/class-form.php
@@ -1,12 +1,12 @@
get_blog_id();
diff --git a/includes/core/class-member-directory-meta.php b/includes/core/class-member-directory-meta.php
index 268934ed..75378531 100644
--- a/includes/core/class-member-directory-meta.php
+++ b/includes/core/class-member-directory-meta.php
@@ -1,27 +1,36 @@
get_var( $wpdb->prepare(
- "SELECT umeta_id
- FROM {$wpdb->prefix}um_metadata
- WHERE user_id = %d AND
- um_key = %s
+ "SELECT umeta_id
+ FROM {$wpdb->prefix}um_metadata
+ WHERE user_id = %d AND
+ um_key = %s
LIMIT 1",
$object_id,
$meta_key
@@ -501,7 +510,6 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
}
}
-
$profile_photo_where = '';
if ( $directory_data['has_profile_photo'] == 1 ) {
$profile_photo_where = " AND umm_general.um_value LIKE '%s:13:\"profile_photo\";b:1;%'";
@@ -517,7 +525,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_general ON umm_general.user_id = u.ID";
$this->general_meta_joined = true;
}
- $this->where_clauses[] = "( umm_general.um_key = 'um_member_directory_data' AND
+ $this->where_clauses[] = "( umm_general.um_key = 'um_member_directory_data' AND
umm_general.um_value LIKE '%s:14:\"account_status\";s:8:\"approved\";%' AND umm_general.um_value LIKE '%s:15:\"hide_in_members\";b:0;%'{$profile_photo_where}{$cover_photo_where} )";
} else {
if ( ! empty( $cover_photo_where ) || ! empty( $profile_photo_where ) ) {
@@ -578,7 +586,6 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
}
}
-
if ( ! empty( $_POST['search'] ) ) {
$search_line = trim( stripslashes( sanitize_text_field( $_POST['search'] ) ) );
@@ -600,7 +607,6 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
$this->is_search = true;
}
-
//filters
$filter_query = array();
if ( ! empty( $directory_data['search_fields'] ) ) {
@@ -638,7 +644,6 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
}
}
-
//unable default filter in case if we select other filters in frontend filters
//if ( empty( $this->custom_filters_in_query ) ) {
$default_filters = array();
@@ -676,7 +681,7 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
if ( ! empty( UM()->builtin()->saved_fields ) ) {
foreach ( UM()->builtin()->saved_fields as $key => $data ) {
- if ( $key == '_um_last_login' ) {
+ if ( '_um_last_login' === $key ) {
continue;
}
@@ -694,12 +699,29 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
// handle sorting options
// sort members by
if ( $sortby == $directory_data['sortby_custom'] || in_array( $sortby, $custom_sort ) ) {
+ $custom_sort_order = ! empty( $directory_data['sortby_custom_order'] ) ? $directory_data['sortby_custom_order'] : 'ASC';
$this->joins[] = "LEFT JOIN {$wpdb->prefix}um_metadata umm_sort ON ( umm_sort.user_id = u.ID AND umm_sort.um_key = '{$sortby}' )";
- $custom_sort_type = apply_filters( 'um_member_directory_custom_sorting_type', 'CHAR', $sortby, $directory_data );
+ $meta_query = new \WP_Meta_Query();
+ $custom_sort_type = ! empty( $directory_data['sortby_custom_type'] ) ? $meta_query->get_cast_for_type( $directory_data['sortby_custom_type'] ) : 'CHAR';
+ if ( ! empty( $directory_data['sorting_fields'] ) ) {
+ // phpcs:ignore WordPress.Security.NonceVerification -- already verified here
+ $sorting = sanitize_text_field( $_POST['sorting'] );
+ $sorting_fields = maybe_unserialize( $directory_data['sorting_fields'] );
- $this->sql_order = " ORDER BY CAST( umm_sort.um_value AS {$custom_sort_type} ) {$order} ";
+ foreach ( $sorting_fields as $field ) {
+ if ( isset( $field[ $sorting ] ) ) {
+ $custom_sort_type = ! empty( $field['type'] ) ? $meta_query->get_cast_for_type( $field['type'] ) : 'CHAR';
+ $custom_sort_order = $field['order'];
+ }
+ }
+ }
+
+ /** This filter is documented in includes/core/class-member-directory.php */
+ $custom_sort_type = apply_filters( 'um_member_directory_custom_sorting_type', $custom_sort_type, $sortby, $directory_data );
+
+ $this->sql_order = " ORDER BY CAST( umm_sort.um_value AS {$custom_sort_type} ) {$custom_sort_order} ";
} elseif ( count( $numeric_sorting_keys ) && in_array( $sortby, $numeric_sorting_keys ) ) {
@@ -802,7 +824,6 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
$this->sql_order = apply_filters( 'um_modify_sortby_parameter_meta', $this->sql_order, $sortby );
-
$profiles_per_page = $directory_data['profiles_per_page'];
if ( UM()->mobile()->isMobile() && isset( $directory_data['profiles_per_page_mobile'] ) ) {
$profiles_per_page = $directory_data['profiles_per_page_mobile'];
@@ -856,25 +877,22 @@ if ( ! class_exists( 'um\core\Member_Directory_Meta' ) ) {
$total_users = (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' );
/**
- * UM hook
+ * Filters the member directory query result when um_usermeta table is used.
*
- * @type filter
- * @title um_prepare_user_results_array_meta
- * @description Extend member directory query result
- * @input_vars
- * [{"var":"$result","type":"array","desc":"Members Query Result"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- * Remove some users where ID equals 10 and 12 from query.
+ * function my_custom_um_prepare_user_results_array_meta( $user_ids, $query_args ) {
+ * $user_ids = array_diff( $user_ids, array( 10, 12 ) );
* return $user_ids;
* }
- * ?>
+ * add_filter( 'um_prepare_user_results_array_meta', 'my_custom_um_prepare_user_results_array', 10, 2 );
*/
$user_ids = apply_filters( 'um_prepare_user_results_array_meta', $user_ids, $query );
diff --git a/includes/core/class-member-directory.php b/includes/core/class-member-directory.php
index b04cbca9..ec104cd9 100644
--- a/includes/core/class-member-directory.php
+++ b/includes/core/class-member-directory.php
@@ -1,20 +1,18 @@
! empty( $metalabel ) ? $metalabel : $metakey,
+ $metakey => $metakey,
+ 'label' => ! empty( $metalabel ) ? $metalabel : $metakey,
+ 'type' => ! empty( $data_type ) ? $data_type : '',
+ 'order' => ! empty( $order ) ? $order : '',
);
}
}
@@ -275,6 +285,10 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$value = sanitize_text_field( $value );
} elseif ( '_um_sortby_custom_label' === $key ) {
$value = wp_strip_all_tags( $value );
+ } elseif ( '_um_sortby_custom_type' === $key ) {
+ $value = sanitize_text_field( $value );
+ } elseif ( '_um_sortby_custom_order' === $key ) {
+ $value = sanitize_text_field( $value );
}
}
@@ -308,6 +322,20 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$this->sorting_supported_fields = apply_filters( 'um_members_directory_custom_field_types_supported_sorting', array( 'number' ) );
+ $this->sort_data_types = array(
+ 'CHAR' => __( 'CHAR', 'ultimate-member' ),
+ 'NUMERIC' => __( 'NUMERIC', 'ultimate-member' ),
+ 'BINARY' => __( 'BINARY', 'ultimate-member' ),
+ 'DATE' => __( 'DATE', 'ultimate-member' ),
+ 'DATETIME' => __( 'DATETIME', 'ultimate-member' ),
+ 'DECIMAL' => __( 'DECIMAL', 'ultimate-member' ),
+ 'SIGNED' => __( 'SIGNED', 'ultimate-member' ),
+ 'TIME' => __( 'TIME', 'ultimate-member' ),
+ 'UNSIGNED' => __( 'UNSIGNED', 'ultimate-member' ),
+ );
+
+ $this->sort_data_types = apply_filters( 'um_members_directory_sort_data_types', $this->sort_data_types );
+
if ( ! empty( UM()->builtin()->saved_fields ) ) {
foreach ( UM()->builtin()->saved_fields as $key => $data ) {
if ( $key == '_um_last_login' ) {
@@ -1422,23 +1450,64 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
unset( $this->query_args['order'] );
} elseif ( ( ! empty( $directory_data['sortby_custom'] ) && $sortby == $directory_data['sortby_custom'] ) || in_array( $sortby, $custom_sort ) ) {
+ $custom_sort_order = ! empty( $directory_data['sortby_custom_order'] ) ? $directory_data['sortby_custom_order'] : 'ASC';
- $custom_sort_type = apply_filters( 'um_member_directory_custom_sorting_type', 'CHAR', $sortby, $directory_data );
+ $meta_query = new \WP_Meta_Query();
+ $custom_sort_type = ! empty( $directory_data['sortby_custom_type'] ) ? $meta_query->get_cast_for_type( $directory_data['sortby_custom_type'] ) : 'CHAR';
+ if ( ! empty( $directory_data['sorting_fields'] ) ) {
+ // phpcs:ignore WordPress.Security.NonceVerification -- already verified here
+ $sorting = sanitize_text_field( $_POST['sorting'] );
+ $sorting_fields = maybe_serialize( $directory_data['sorting_fields'] );
+
+ foreach ( $sorting_fields as $field ) {
+ if ( isset( $field[ $sorting ] ) ) {
+ $custom_sort_type = ! empty( $field['type'] ) ? $meta_query->get_cast_for_type( $field['type'] ) : 'CHAR';
+ $custom_sort_order = $field['order'];
+ }
+ }
+ }
+ /**
+ * Filters the sorting MySQL type in member directory custom sorting query.
+ *
+ * Note: Possible MySQL types are BINARY|CHAR|DATE|DATETIME|SIGNED|UNSIGNED|TIME|DECIMAL
+ *
+ * @since 2.1.3
+ * @hook um_member_directory_custom_sorting_type
+ *
+ * @param {string} $custom_sort_type MySQL type to cast meta_value. 'CHAR' is default.
+ * @param {string} $sortby meta_key used for sorting.
+ * @param {array} $directory_data Member directory data.
+ *
+ * @return {string} MySQL type to cast meta_value.
+ * @example
Change type to DATE by the directory ID and mete_key.
+ * function my_um_member_directory_custom_sorting_type( $custom_sort_type, $sortby, $directory_data ) {
+ * if ( '{selected member directory ID}' == $directory_data['form_id'] && '{custom_date_key}' === $sortby ) {
+ * $custom_sort_type = 'DATE';
+ * }
+ *
+ * return $custom_sort_type;
+ * }
+ * add_filter( 'um_member_directory_custom_sorting_type', 'my_um_member_directory_custom_sorting_type', 10, 3 );
+ */
+ $custom_sort_type = apply_filters( 'um_member_directory_custom_sorting_type', $custom_sort_type, $sortby, $directory_data );
$this->query_args['meta_query'][] = array(
- 'relation' => 'OR',
+ 'relation' => 'OR',
$sortby . '_cs' => array(
- 'key' => $sortby,
- 'compare' => 'EXISTS',
- 'type' => $custom_sort_type,
+ 'key' => $sortby,
+ 'compare' => 'EXISTS',
+ 'type' => $custom_sort_type,
),
array(
- 'key' => $sortby,
- 'compare' => 'NOT EXISTS',
- )
+ 'key' => $sortby,
+ 'compare' => 'NOT EXISTS',
+ ),
);
- $this->query_args['orderby'] = array( $sortby . '_cs' => 'ASC', 'user_login' => 'ASC' );
+ $this->query_args['orderby'] = array(
+ $sortby . '_cs' => $custom_sort_order,
+ 'user_login' => 'ASC',
+ );
} else {
@@ -2648,29 +2717,25 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
$user_ids = ! empty( $user_query->results ) ? array_unique( $user_query->results ) : array();
/**
- * UM hook
+ * Filters the member directory query result.
*
- * @type filter
- * @title um_prepare_user_results_array
- * @description Extend member directory query result
- * @input_vars
- * [{"var":"$result","type":"array","desc":"Members Query Result"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- * Remove some users where ID equals 10 and 12 from query.
+ * function my_custom_um_prepare_user_results_array( $user_ids, $query_args ) {
+ * $user_ids = array_diff( $user_ids, array( 10, 12 ) );
* return $user_ids;
* }
- * ?>
+ * add_filter( 'um_prepare_user_results_array', 'my_custom_um_prepare_user_results_array', 10, 2 );
*/
$user_ids = apply_filters( 'um_prepare_user_results_array', $user_ids, $this->query_args );
-
$sizes = UM()->options()->get( 'cover_thumb_sizes' );
$this->cover_size = UM()->mobile()->isTablet() ? $sizes[1] : end( $sizes );
@@ -2762,5 +2827,27 @@ if ( ! class_exists( 'um\core\Member_Directory' ) ) {
wp_send_json_success( array( 'field_html' => $html ) );
}
+
+ /**
+ * Get member directory id by page id.
+ *
+ * @param int $page_id Page ID.
+ *
+ * @return array Member directories ID.
+ */
+ public function get_member_directory_id( $page_id ) {
+ $members_page = get_post( $page_id );
+ if ( ! empty( $members_page ) && ! is_wp_error( $members_page ) ) {
+ if ( ! empty( $members_page->post_content ) ) {
+ preg_match_all( '/\[ultimatemember[^\]]*?form_id\=[\'"]*?(\d+)[\'"]*?/i', $members_page->post_content, $matches );
+ if ( ! empty( $matches[1] ) && is_array( $matches[1] ) ) {
+ $member_directory_ids = array_map( 'absint', $matches[1] );
+ return $member_directory_ids;
+ }
+ }
+ }
+
+ return array();
+ }
}
}
diff --git a/includes/core/class-permalinks.php b/includes/core/class-permalinks.php
index 96a58880..59f9e6cd 100644
--- a/includes/core/class-permalinks.php
+++ b/includes/core/class-permalinks.php
@@ -1,35 +1,32 @@
current_url = $this->get_current_url();
}
-
- /**
- * SEO canonical href bugfix
- *
- * @deprecated since version 2.1.7
- *
- * @see function um_profile_remove_wpseo()
- */
- function um_rel_canonical_() {
- global $wp_the_query;
-
- if ( ! is_singular() )
- return;
-
- /**
- * UM hook
- *
- * @type filter
- * @title um_allow_canonical__filter
- * @description Allow canonical
- * @input_vars
- * [{"var":"$allow_canonical","type":"bool","desc":"Allow?"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- *
- */
- $enable_canonical = apply_filters( "um_allow_canonical__filter", true );
-
- if( ! $enable_canonical )
- return;
-
- if ( !$id = $wp_the_query->get_queried_object_id() )
- return;
-
- if ( UM()->config()->permalinks['user'] == $id ) {
- $link = esc_url( $this->get_current_url() );
- echo "
\n";
- return;
- }
-
- $link = get_permalink( $id );
- if ( $page = get_query_var( 'cpage' ) ){
- $link = get_comments_pagenum_link( $page );
- echo "
\n";
- }
-
- }
-
-
/**
* Get query as array
*
* @return array
*/
- function get_query_array() {
+ public function get_query_array() {
$parts = parse_url( $this->get_current_url() );
if ( isset( $parts['query'] ) ) {
parse_str( $parts['query'], $query );
@@ -118,66 +56,61 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
return array();
}
-
/**
* Get current URL anywhere
*
* @param bool $no_query_params
*
- * @return mixed|void
+ * @return string
*/
- function get_current_url( $no_query_params = false ) {
+ public function get_current_url( $no_query_params = false ) {
//use WP native function for fill $_SERVER variables by correct values
wp_fix_server_vars();
//check if WP-CLI there isn't set HTTP_HOST, use localhost instead
if ( defined( 'WP_CLI' ) && WP_CLI ) {
$host = isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : 'localhost';
- } else{
- if ( isset( $_SERVER['HTTP_HOST'] ) ) {
- $host = $_SERVER['HTTP_HOST'];
- }else{
- $host = 'localhost';
- }
- }
+ } else {
+ if ( isset( $_SERVER['HTTP_HOST'] ) ) {
+ $host = $_SERVER['HTTP_HOST'];
+ } else {
+ $host = 'localhost';
+ }
+ }
$page_url = ( is_ssl() ? 'https://' : 'http://' ) . $host . $_SERVER['REQUEST_URI'];
- if ( $no_query_params == true ) {
+ if ( false !== $no_query_params ) {
$page_url = strtok( $page_url, '?' );
}
/**
- * UM hook
+ * Filters current page URL.
*
- * @type filter
- * @title um_get_current_page_url
- * @description Change current page URL
- * @input_vars
- * [{"var":"$page_url","type":"string","desc":"Page URL"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- * Add your custom $_GET attribute to all links.
+ * function my_um_get_current_page_url( $page_url, $no_query_params ) {
+ * $page_url = add_query_arg( '{attr_value}', '{attr_key}', $page_url ); // replace to your custom value and key.
* return $page_url;
* }
- * ?>
+ * add_filter( 'um_get_current_page_url', 'my_um_get_current_page_url', 10, 2 );
*/
- return apply_filters( 'um_get_current_page_url', $page_url );
+ return apply_filters( 'um_get_current_page_url', $page_url, $no_query_params );
}
-
/**
* Activates an account via email
*/
public function activate_account_via_email_link() {
if ( isset( $_REQUEST['act'] ) && 'activate_via_email' === sanitize_key( $_REQUEST['act'] ) && isset( $_REQUEST['hash'] ) && is_string( $_REQUEST['hash'] ) && strlen( $_REQUEST['hash'] ) == 40 &&
- isset( $_REQUEST['user_id'] ) && is_numeric( $_REQUEST['user_id'] ) ) { // valid token
+ isset( $_REQUEST['user_id'] ) && is_numeric( $_REQUEST['user_id'] ) ) { // valid token
$user_id = absint( $_REQUEST['user_id'] );
delete_option( "um_cache_userdata_{$user_id}" );
@@ -238,18 +171,15 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
$redirect = apply_filters( 'um_after_email_confirmation_redirect', $redirect, $user_id, $login );
exit( wp_redirect( $redirect ) );
-
}
-
}
-
/**
* Makes an activate link for any user
*
* @return bool|string
*/
- function activate_url() {
+ public function activate_url() {
if ( ! um_user( 'account_secret_hash' ) ) {
return false;
}
@@ -283,17 +213,15 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
return $url;
}
-
/**
* Checks for UM query strings
*/
- function check_for_querystrings() {
+ public function check_for_querystrings() {
if ( isset( $_REQUEST['message'] ) ) {
UM()->shortcodes()->message_mode = true;
}
}
-
/**
* Add a query param to url
*
@@ -302,12 +230,11 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
*
* @return string
*/
- function add_query( $key, $value ) {
+ public function add_query( $key, $value ) {
$this->current_url = add_query_arg( $key, $value, $this->get_current_url() );
return $this->current_url;
}
-
/**
* Remove a query param from url
*
@@ -316,26 +243,25 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
*
* @return string
*/
- function remove_query( $key, $value ) {
+ public function remove_query( $key, $value ) {
$this->current_url = remove_query_arg( $key, $this->current_url );
return $this->current_url;
}
-
/**
* @param $slug
*
* @return int|null|string
*/
- function slug_exists_user_id( $slug ) {
+ public function slug_exists_user_id( $slug ) {
global $wpdb;
$permalink_base = UM()->options()->get( 'permalink_base' );
$user_id = $wpdb->get_var(
- "SELECT user_id
- FROM {$wpdb->usermeta}
- WHERE meta_key = 'um_user_profile_url_slug_{$permalink_base}' AND
+ "SELECT user_id
+ FROM {$wpdb->usermeta}
+ WHERE meta_key = 'um_user_profile_url_slug_{$permalink_base}' AND
meta_value = '{$slug}'
ORDER BY umeta_id ASC
LIMIT 1"
@@ -348,57 +274,93 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
return false;
}
-
/**
* Get Profile Permalink
*
* @param string $slug
- * @return string $profile_url
+ *
+ * @return string
*/
- function profile_permalink( $slug ) {
+ public function profile_permalink( $slug ) {
+ /**
+ * Filters user profile URL externally with own logic.
+ *
+ * @since 2.6.3
+ * @hook um_external_profile_url
+ *
+ * @param {bool|string} $profile_url Profile URL.
+ * @param {string} $slug User profile slug.
+ *
+ * @return {string} Profile URL.
+ *
+ * @example
Change profile URL to your custom link and ignore native profile permalink handlers.
+ * function my_um_external_profile_url( $profile_url, $slug ) {
+ * $profile_url = '{some your custom URL}'; // replace to your custom link.
+ * return $profile_url;
+ * }
+ * add_filter( 'um_external_profile_url', 'my_um_external_profile_url', 10, 2 );
+ */
+ $external_profile_url = apply_filters( 'um_external_profile_url', false, $slug );
+ if ( false !== $external_profile_url ) {
+ return ! empty( $external_profile_url ) ? $external_profile_url : '';
+ }
- $page_id = UM()->config()->permalinks['user'];
+ $page_id = UM()->config()->permalinks['user'];
$profile_url = get_permalink( $page_id );
/**
- * UM hook
+ * Filters the base URL of the UM profile page.
*
- * @type filter
- * @title um_localize_permalink_filter
- * @description Change user profile URL
- * @input_vars
- * [{"var":"$profile_url","type":"string","desc":"Profile URL"},
- * {"var":"$page_id","type":"int","desc":"Profile Page ID"}]
- * @change_log
- * ["Since: 2.0"]
- * @usage
- *
- * @example
- * 'post_link' instead.
+ * @hook um_localize_permalink_filter
+ * @todo fully remove since 2.7.0
+ *
+ * @param {string} $profile_url Profile URL.
+ * @param {int} $page_id Profile Page ID.
+ *
+ * @return {string} Profile URL.
+ *
+ * @example
Change profile base URL to your custom link.
* function my_localize_permalink( $profile_url, $page_id ) {
- * // your code here
+ * $profile_url = '{some your custom URL}'; // replace to your custom link.
* return $profile_url;
* }
- * ?>
+ * add_filter( 'um_localize_permalink_filter', 'my_localize_permalink', 10, 2 );
*/
$profile_url = apply_filters( 'um_localize_permalink_filter', $profile_url, $page_id );
- if ( get_option( 'permalink_structure' ) ) {
-
- $profile_url = trailingslashit( untrailingslashit( $profile_url ) );
- $profile_url = $profile_url . strtolower( $slug ). '/';
-
+ if ( UM()->is_permalinks ) {
+ $profile_url = trailingslashit( untrailingslashit( $profile_url ) );
+ $profile_url .= trailingslashit( strtolower( $slug ) );
} else {
-
- $profile_url = add_query_arg( 'um_user', strtolower( $slug ), $profile_url );
-
+ $profile_url = add_query_arg( 'um_user', strtolower( $slug ), $profile_url );
}
+ /**
+ * Filters user profile URL.
+ *
+ * @since 2.6.3
+ * @hook um_profile_permalink
+ *
+ * @param {string} $profile_url Profile URL.
+ * @param {int} $page_id Profile Page ID.
+ * @param {string} $slug User profile slug.
+ *
+ * @return {string} Profile URL.
+ *
+ * @example
Change profile URL to your custom link.
+ * function my_um_profile_permalink( $profile_url, $page_id, $slug ) {
+ * $profile_url = '{some your custom URL}'; // replace to your custom link.
+ * return $profile_url;
+ * }
+ * add_filter( 'um_profile_permalink', 'my_um_profile_permalink', 10, 3 );
+ */
+ $profile_url = apply_filters( 'um_profile_permalink', $profile_url, $page_id, $slug );
+
return ! empty( $profile_url ) ? $profile_url : '';
}
-
/**
* Generate profile slug
*
@@ -407,41 +369,38 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
* @param string $last_name
* @return string
*/
- function profile_slug( $full_name, $first_name, $last_name ){
-
+ public function profile_slug( $full_name, $first_name, $last_name ) {
$permalink_base = UM()->options()->get( 'permalink_base' );
$user_in_url = '';
- $full_name = str_replace("'", "", $full_name );
- $full_name = str_replace("&", "", $full_name );
- $full_name = str_replace("/", "", $full_name );
+ $full_name = str_replace( "'", "", $full_name );
+ $full_name = str_replace( "&", "", $full_name );
+ $full_name = str_replace( "/", "", $full_name );
- switch( $permalink_base ) {
+ switch ( $permalink_base ) {
case 'name': // dotted
-
$full_name_slug = $full_name;
$difficulties = 0;
-
- if( strpos( $full_name, '.' ) > -1 ){
- $full_name = str_replace(".", "_", $full_name );
+ if ( strpos( $full_name, '.' ) > -1 ) {
+ $full_name = str_replace( ".", "_", $full_name );
$difficulties++;
}
$full_name = strtolower( str_replace( " ", ".", $full_name ) );
- if( strpos( $full_name, '_.' ) > -1 ){
- $full_name = str_replace('_.', '_', $full_name );
+ if ( strpos( $full_name, '_.' ) > -1 ) {
+ $full_name = str_replace( '_.', '_', $full_name );
$difficulties++;
}
- $full_name_slug = str_replace( '-' , '.', $full_name_slug );
- $full_name_slug = str_replace( ' ' , '.', $full_name_slug );
- $full_name_slug = str_replace( '..' , '.', $full_name_slug );
+ $full_name_slug = str_replace( '-', '.', $full_name_slug );
+ $full_name_slug = str_replace( ' ', '.', $full_name_slug );
+ $full_name_slug = str_replace( '..', '.', $full_name_slug );
- if( strpos( $full_name, '.' ) > -1 ){
- $full_name = str_replace('.', ' ', $full_name );
+ if ( strpos( $full_name, '.' ) > -1 ) {
+ $full_name = str_replace( '.', ' ', $full_name );
$difficulties++;
}
@@ -450,76 +409,73 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
break;
case 'name_dash': // dashed
-
$difficulties = 0;
$full_name_slug = strtolower( $full_name );
// if last name has dashed replace with underscore
- if( strpos( $last_name, '-') > -1 && strpos( $full_name, '-' ) > -1 ){
+ if ( strpos( $last_name, '-' ) > -1 && strpos( $full_name, '-' ) > -1 ) {
$difficulties++;
- $full_name = str_replace('-', '_', $full_name );
+ $full_name = str_replace( '-', '_', $full_name );
}
// if first name has dashed replace with underscore
- if( strpos( $first_name, '-') > -1 && strpos( $full_name, '-' ) > -1 ){
+ if ( strpos( $first_name, '-' ) > -1 && strpos( $full_name, '-' ) > -1 ) {
$difficulties++;
- $full_name = str_replace('-', '_', $full_name );
+ $full_name = str_replace( '-', '_', $full_name );
}
// if name has space, replace with dash
- $full_name_slug = str_replace( ' ' , '-', $full_name_slug );
+ $full_name_slug = str_replace( ' ', '-', $full_name_slug );
// if name has period
- if( strpos( $last_name, '.') > -1 && strpos( $full_name, '.' ) > -1 ){
+ if ( strpos( $last_name, '.' ) > -1 && strpos( $full_name, '.' ) > -1 ) {
$difficulties++;
}
- $full_name_slug = str_replace( '.' , '-', $full_name_slug );
- $full_name_slug = str_replace( '--' , '-', $full_name_slug );
+ $full_name_slug = str_replace( '.', '-', $full_name_slug );
+ $full_name_slug = str_replace( '--', '-', $full_name_slug );
- $user_in_url = rawurlencode( $full_name_slug );
+ $user_in_url = rawurlencode( $full_name_slug );
break;
case 'name_plus': // plus
-
$difficulties = 0;
$full_name_slug = strtolower( $full_name );
// if last name has dashed replace with underscore
- if( strpos( $last_name, '+') > -1 && strpos( $full_name, '+' ) > -1 ){
+ if ( strpos( $last_name, '+' ) > -1 && strpos( $full_name, '+' ) > -1 ) {
$difficulties++;
- $full_name = str_replace('-', '_', $full_name );
+ $full_name = str_replace( '-', '_', $full_name );
}
// if first name has dashed replace with underscore
- if( strpos( $first_name, '+') > -1 && strpos( $full_name, '+' ) > -1 ){
+ if ( strpos( $first_name, '+' ) > -1 && strpos( $full_name, '+' ) > -1 ) {
$difficulties++;
- $full_name = str_replace('-', '_', $full_name );
+ $full_name = str_replace( '-', '_', $full_name );
}
- if( strpos( $last_name, '-') > -1 || strpos( $first_name, '-') > -1 || strpos( $full_name, '-') > -1 ){
+ if ( strpos( $last_name, '-' ) > -1 || strpos( $first_name, '-' ) > -1 || strpos( $full_name, '-' ) > -1 ) {
$difficulties++;
}
// if name has space, replace with dash
- $full_name_slug = str_replace( ' ' , '+', $full_name_slug );
- $full_name_slug = str_replace( '-' , '+', $full_name_slug );
+ $full_name_slug = str_replace( ' ', '+', $full_name_slug );
+ $full_name_slug = str_replace( '-', '+', $full_name_slug );
// if name has period
- if( strpos( $last_name, '.') > -1 && strpos( $full_name, '.' ) > -1 ){
+ if ( strpos( $last_name, '.' ) > -1 && strpos( $full_name, '.' ) > -1 ) {
$difficulties++;
}
- $full_name_slug = str_replace( '.' , '+', $full_name_slug );
- $full_name_slug = str_replace( '++' , '+', $full_name_slug );
+ $full_name_slug = str_replace( '.', '+', $full_name_slug );
+ $full_name_slug = str_replace( '++', '+', $full_name_slug );
$user_in_url = $full_name_slug;
break;
}
- return $user_in_url ;
+ return $user_in_url;
}
-
/**
* Get action url for admin use
*
@@ -528,12 +484,69 @@ if ( ! class_exists( 'um\core\Permalinks' ) ) {
*
* @return mixed|string|void
*/
- function admin_act_url( $action, $subaction ) {
+ public function admin_act_url( $action, $subaction ) {
$url = $this->get_current_url();
- $url = add_query_arg( 'um_adm_action', $action, $url );
- $url = add_query_arg( 'sub', $subaction, $url );
- $url = add_query_arg( 'user_id', um_user('ID'), $url );
+ $url = add_query_arg( 'um_adm_action', $action, $url );
+ $url = add_query_arg( 'sub', $subaction, $url );
+ $url = add_query_arg( 'user_id', um_user( 'ID' ), $url );
return $url;
}
+
+ /**
+ * SEO canonical href bugfix
+ *
+ * @deprecated since version 2.1.7
+ *
+ * @todo remove since 2.7.0
+ * @see function um_profile_remove_wpseo()
+ */
+ public function um_rel_canonical_() {
+ _deprecated_function( __METHOD__, '2.1.7', 'um_profile_remove_wpseo()' );
+ global $wp_the_query;
+
+ if ( ! is_singular() )
+ return;
+
+ /**
+ * UM hook
+ *
+ * @type filter
+ * @title um_allow_canonical__filter
+ * @description Allow canonical
+ * @input_vars
+ * [{"var":"$allow_canonical","type":"bool","desc":"Allow?"}]
+ * @change_log
+ * ["Since: 2.0"]
+ * @usage
+ *
+ * @example
+ *
+ */
+ $enable_canonical = apply_filters( "um_allow_canonical__filter", true );
+
+ if( ! $enable_canonical )
+ return;
+
+ if ( !$id = $wp_the_query->get_queried_object_id() )
+ return;
+
+ if ( UM()->config()->permalinks['user'] == $id ) {
+ $link = esc_url( $this->get_current_url() );
+ echo "
\n";
+ return;
+ }
+
+ $link = get_permalink( $id );
+ if ( $page = get_query_var( 'cpage' ) ) {
+ $link = get_comments_pagenum_link( $page );
+ echo "
\n";
+ }
+ }
}
}
diff --git a/includes/core/class-roles-capabilities.php b/includes/core/class-roles-capabilities.php
index 8155b576..9b60c143 100644
--- a/includes/core/class-roles-capabilities.php
+++ b/includes/core/class-roles-capabilities.php
@@ -91,40 +91,47 @@ if ( ! class_exists( 'um\core\Roles_Capabilities' ) ) {
}
}
-
/**
* Loop through dynamic roles and add them to the $wp_roles array
*
* @param null|object $wp_roles
* @return null
*/
- function um_roles_init( $wp_roles = null ) {
+ public function um_roles_init( $wp_roles = null ) {
+ $role_keys = get_option( 'um_roles', array() );
+ $um_roles = array_map( array( &$this, 'key_to_role_id_mapping' ), $role_keys );
- //Add UM role data to WP Roles
- foreach ( $wp_roles->roles as $roleID => $role_data ) {
- $role_meta = get_option( "um_role_{$roleID}_meta" );
+ // Add UM role data to WP Roles.
+ foreach ( $wp_roles->roles as $role_id => $role_data ) {
+ // Skip custom UM roles meta here, because it's added below. See: "Add custom UM roles".
+ if ( in_array( $role_id, $um_roles, true ) ) {
+ continue;
+ }
+ $role_meta = get_option( "um_role_{$role_id}_meta" );
if ( ! empty( $role_meta ) ) {
- $wp_roles->roles[ $roleID ] = array_merge( $role_data, $role_meta );
+ $wp_roles->roles[ $role_id ] = array_merge( $role_data, $role_meta );
}
}
-
- //Add custom UM roles
+ // Add custom UM roles.
$roles = array();
-
- $role_keys = get_option( 'um_roles', array() );
foreach ( $role_keys as $role_key ) {
$role_meta = get_option( "um_role_{$role_key}_meta" );
- if ( $role_meta ) {
+ if ( ! empty( $role_meta ) ) {
$roles[ 'um_' . $role_key ] = $role_meta;
}
}
+ if ( empty( $roles ) ) {
+ return $wp_roles;
+ }
+
foreach ( $roles as $role_id => $details ) {
- $capabilities = ! empty( $details['wp_capabilities'] ) ? array_keys( $details['wp_capabilities'] ) : array();
+ $capabilities = ! empty( $details['wp_capabilities'] ) ? array_keys( $details['wp_capabilities'] ) : array();
$details['capabilities'] = array_fill_keys( array_values( $capabilities ), true );
unset( $details['wp_capabilities'] );
+
$wp_roles->roles[ $role_id ] = $details;
$wp_roles->role_objects[ $role_id ] = new \WP_Role( $role_id, $details['capabilities'] );
$wp_roles->role_names[ $role_id ] = $details['name'];
@@ -134,6 +141,9 @@ if ( ! class_exists( 'um\core\Roles_Capabilities' ) ) {
return $wp_roles;
}
+ public function key_to_role_id_mapping( $role_key ) {
+ return 'um_' . $role_key;
+ }
/**
* Check if role is custom
@@ -141,22 +151,17 @@ if ( ! class_exists( 'um\core\Roles_Capabilities' ) ) {
* @param $role
* @return bool
*/
- function is_role_custom( $role ) {
+ public function is_role_custom( $role ) {
// User has roles so look for a UM Role one
$role_keys = get_option( 'um_roles', array() );
-
if ( empty( $role_keys ) ) {
return false;
}
- $role_keys = array_map( function( $item ) {
- return 'um_' . $item;
- }, $role_keys );
-
- return in_array( $role, $role_keys );
+ $um_roles = array_map( array( &$this, 'key_to_role_id_mapping' ), $role_keys );
+ return in_array( $role, $um_roles, true );
}
-
/**
* Return a user's main role
*
diff --git a/includes/core/class-shortcodes.php b/includes/core/class-shortcodes.php
index c87ac86d..e300d2e2 100644
--- a/includes/core/class-shortcodes.php
+++ b/includes/core/class-shortcodes.php
@@ -1260,7 +1260,7 @@ if ( ! class_exists( 'um\core\Shortcodes' ) ) {
*
* @return string
*/
- public function ultimatemember_searchform( $args = array(), $content = "" ) {
+ public function ultimatemember_searchform( $args = array(), $content = '' ) {
if ( ! UM()->options()->get( 'members_page' ) ) {
return '';
}
@@ -1269,15 +1269,7 @@ if ( ! class_exists( 'um\core\Shortcodes' ) ) {
$page_id = UM()->config()->permalinks['members'];
if ( ! empty( $page_id ) ) {
- $members_page = get_post( $page_id );
- if ( ! empty( $members_page ) && ! is_wp_error( $members_page ) ) {
- if ( ! empty( $members_page->post_content ) ) {
- preg_match_all( '/\[ultimatemember[^\]]*?form_id\=[\'"]*?(\d+)[\'"]*?/i', $members_page->post_content, $matches );
- if ( ! empty( $matches[1] ) && is_array( $matches[1] ) ) {
- $member_directory_ids = array_map( 'absint', $matches[1] );
- }
- }
- }
+ $member_directory_ids = UM()->member_directory()->get_member_directory_id( $page_id );
}
if ( empty( $member_directory_ids ) ) {
diff --git a/includes/core/um-actions-form.php b/includes/core/um-actions-form.php
index cbf67cec..3c4eae9f 100644
--- a/includes/core/um-actions-form.php
+++ b/includes/core/um-actions-form.php
@@ -715,6 +715,12 @@ function um_submit_form_errors_hook_( $args ) {
}
break;
+ case 'spotify_url':
+ if ( ! UM()->validation()->is_url( $args[ $key ], 'open.spotify.com' ) ) {
+ UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s URL', 'ultimate-member' ), $array['label'] ) );
+ }
+ break;
+
case 'telegram_url':
if ( ! UM()->validation()->is_url( $args[ $key ], 't.me' ) ) {
UM()->form()->add_error( $key, sprintf( __( 'Please enter a valid %s username or profile URL', 'ultimate-member' ), $array['label'] ) );
diff --git a/includes/core/um-actions-profile.php b/includes/core/um-actions-profile.php
index c180b3cb..f5cd85a0 100644
--- a/includes/core/um-actions-profile.php
+++ b/includes/core/um-actions-profile.php
@@ -1725,6 +1725,26 @@ function um_profile_menu( $args ) {
*/
$nav_link = apply_filters( "um_profile_menu_link_{$id}", $nav_link );
+ /**
+ * Filters a profile menu navigation links' tag attributes.
+ *
+ * @since 2.6.3
+ * @hook um_profile_menu_link_{$id}_attrs
+ *
+ * @param {string} $profile_nav_attrs Link's tag attributes.
+ * @param {array} $args Profile form arguments.
+ *
+ * @return {string} Link's tag attributes.
+ *
+ * @example
Add a link's tag attributes.
+ * function um_profile_menu_link_attrs( $profile_nav_attrs ) {
+ * // your code here
+ * return $profile_nav_attrs;
+ * }
+ * add_filter( 'um_profile_menu_link_{$id}_attrs', 'um_profile_menu_link_attrs', 10, 1 );
+ */
+ $profile_nav_attrs = apply_filters( "um_profile_menu_link_{$id}_attrs", '', $args );
+
$profile_nav_class = '';
if ( ! UM()->options()->get( 'profile_menu_icons' ) ) {
$profile_nav_class .= ' without-icon';
@@ -1737,7 +1757,7 @@ function um_profile_menu( $args ) {
options()->get( 'profile_menu_icons' ) ) { ?>
+ title="" original-title="" >
@@ -1748,7 +1768,7 @@ function um_profile_menu( $args ) {
+ title="" >
@@ -1760,7 +1780,7 @@ function um_profile_menu( $args ) {
+ title="" original-title="" >
@@ -1769,7 +1789,7 @@ function um_profile_menu( $args ) {
+ title="" >
0 ) { ?>
diff --git a/includes/core/um-filters-fields.php b/includes/core/um-filters-fields.php
index 22609c8d..a64ec2ad 100644
--- a/includes/core/um-filters-fields.php
+++ b/includes/core/um-filters-fields.php
@@ -77,6 +77,30 @@ function um_profile_field_filter_hook__youtube_video( $value, $data ) {
add_filter( 'um_profile_field_filter_hook__youtube_video', 'um_profile_field_filter_hook__youtube_video', 99, 2 );
+/**
+ * Outputs a spotify iframe
+ *
+ * @param $value
+ * @param $data
+ *
+ * @return bool|string
+ */
+function um_profile_field_filter_hook__spotify( $value, $data ) {
+ if ( preg_match( '/https:\/\/open.spotify.com\/.*/', $value ) ) {
+ $url = str_replace( 'open.spotify.com/', 'open.spotify.com/embed/', $value );
+
+ $value = '
+
+
';
+ } else {
+ return __( 'Invalid Spotify URL', 'ultimate-member' );
+ }
+
+ return $value;
+}
+add_filter( 'um_profile_field_filter_hook__spotify', 'um_profile_field_filter_hook__spotify', 99, 2 );
+
+
/**
* Outputs a vimeo video
*
diff --git a/includes/um-short-functions.php b/includes/um-short-functions.php
index 9c181605..c8951eac 100644
--- a/includes/um-short-functions.php
+++ b/includes/um-short-functions.php
@@ -1515,10 +1515,10 @@ function um_can_view_field( $data ) {
UM()->fields()->set_mode = '';
}
- if ( isset( $data['public'] ) && UM()->fields()->set_mode != 'register' ) {
+ if ( isset( $data['public'] ) && 'register' !== UM()->fields()->set_mode ) {
- $can_edit = false;
- $current_user_roles = [];
+ $can_edit = false;
+ $current_user_roles = array();
if ( is_user_logged_in() ) {
$can_edit = UM()->roles()->um_current_user_can( 'edit', um_user( 'ID' ) );
@@ -1563,7 +1563,6 @@ function um_can_view_field( $data ) {
$can_view = apply_filters( 'um_can_view_field_custom', $can_view, $data );
break;
}
-
}
return apply_filters( 'um_can_view_field', $can_view, $data );
diff --git a/package.json b/package.json
index ce1525b8..d08fe57d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,11 @@
{
- "name": "roots",
- "version": "7.0.3",
- "author": "Ben Word ",
+ "name": "ultimate-member",
+ "version": "2.6.3",
+ "author": {
+ "name": "Ultimate Member",
+ "email": "team@ultimatemember.com",
+ "url": "https://ultimatemember.com"
+ },
"homepage": "http://roots.io",
"repository": {
"type": "git",
@@ -17,7 +21,7 @@
}
],
"scripts": {
- "postinstall": "node node_modules/bower/bin/bower install && grunt dev",
+ "build:docs": "rm -rf docs/hooks/ && jsdoc -c hookdoc-conf.json",
"build": "npm-run-all build:*",
"build:all-blocks": "npm-run-all --parallel build-block-*",
"build-block-um-member-directories": "cd includes/blocks/um-member-directories && wp-scripts build src/index.js",
@@ -36,6 +40,8 @@
"gulp-sass": "^5.1.0",
"gulp-uglify": "^3.0.2",
"gulp-clean-css": "^4.3.0",
+ "jsdoc": "~4.0.2",
+ "wp-hookdoc": "^0.2.0",
"npm-run-all": "^4.1.5",
"@wordpress/block-editor": "^11.5.0",
"@wordpress/blocks": "^12.5.0",
@@ -45,6 +51,7 @@
"@wordpress/server-side-render": "^4.5.0"
},
"dependencies": {
- "react": "^18.2.0"
+ "react": "^18.2.0",
+ "taffydb": "^2.7.3"
}
}
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
new file mode 100644
index 00000000..2fb02cab
--- /dev/null
+++ b/phpdoc.dist.xml
@@ -0,0 +1,25 @@
+
+
+ Ultimate Member - PHPDoc
+
+ docs/phpdoc
+ docs/phpdoc/cache
+
+
+ latest
+
+
+ includes
+ templates
+
+
+ php
+
+
+
+
+
diff --git a/readme.txt b/readme.txt
index 312d97e6..74fb74d9 100644
--- a/readme.txt
+++ b/readme.txt
@@ -7,7 +7,7 @@ Tags: community, member, membership, user-profile, user-registration
Requires PHP: 5.6
Requires at least: 5.5
Tested up to: 6.2
-Stable tag: 2.6.2
+Stable tag: 2.6.3
License: GNU Version 2 or Any Later Version
License URI: http://www.gnu.org/licenses/gpl-3.0.txt
@@ -96,9 +96,9 @@ If you're a developer and would like to contribute to the source code of the plu
Want to add a new language to Ultimate Member? Great! You can contribute via [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/ultimate-member).
-If you are a developer and you need to know the list of UM Hooks, make this via our [Hooks Documentation](https://docs.ultimatemember.com/article/1324-hooks-list).
+If you are a developer and you need to know the list of UM Hooks, make this via our [Hooks Documentation](https://docs.ultimatemember.com/article/1324-hooks-list) or [Hooks Documentation v2](https://ultimatemember.github.io/ultimatemember/hooks/).
-If you are a developer and you need to know the structure of our code, make this via our [Documentation API](https://ultimatemember.com/php-docs/).
+If you are a developer and you need to know the structure of our code, make this via our [Documentation API](https://ultimatemember.github.io/ultimatemember/phpdoc/).
= Documentation & Support =
@@ -163,6 +163,36 @@ No, you do not need to use our plugin’s login or registration pages and can us
* To learn more about version 2.1 please see this [docs](https://docs.ultimatemember.com/article/1512-upgrade-2-1-0)
* UM2.1+ is a significant update to the Member Directories' code base from 2.0.x. Please make sure you take a full-site backup with restore point before updating the plugin
+= 2.6.3: June 14, 2023 =
+
+* Enhancements:
+
+ - Added: `um_profile_menu_link_{$id}_attrs` hook for changing link attributes
+ - Added: `get_member_directory_id()` function for getting member directory ID based on page ID
+ - Added: The "Order" and "Data type" settings for custom sorting fields based on metakey in Member Directory
+ - Added: New hooks `um_profile_permalink`,`um_external_profile_url`
+ - Added: Users dropdown field to Admin Forms class
+ - Added: Spotify URL field type
+ - Added: New developer docs [here](http://ultimatemember.github.io/ultimatemember/). It will be upgraded from version to version
+
+* Bugfixes:
+
+ - Fixed: PHP8.2 PHP errors (deprecated, warnings, etc.)
+ - Fixed: Filters visibility on member directory page based on public or private visibility for filter's field
+ - Fixed: Incorrect Member Directory numerical sorting order
+ - Fixed: wp_editor() doesn't work correctly in content restriction settings for Mac users
+ - Fixed: Profile links when WPML plugin is active
+ - Fixed: ACF and UM blocks conflict
+ - Fixed: `UM()->mail()->locate_template()` function's visibility
+
+* Deprecated:
+
+ - Deprecated: `um_localize_permalink_filter`. Use `post_link` instead
+
+* Templates required update:
+
+ - members.php
+
= 2.6.2: May 31, 2023 =
* Bugfixes:
diff --git a/templates/members.php b/templates/members.php
index ae295981..2ba8da56 100644
--- a/templates/members.php
+++ b/templates/members.php
@@ -6,7 +6,7 @@
*
* Page: "Members"
*
- * @version 2.6.1
+ * @version 2.6.3
*
* @var array $args
*/
@@ -139,6 +139,14 @@ if ( ! empty( $search_filters ) ) {
$search_filters = array_values( $search_filters );
}
+// Hide filter fields based on the field visibility.
+foreach ( $search_filters as $key => $filter ) {
+ $filter_data = UM()->fields()->get_field( $filter );
+ if ( ! um_can_view_field( $filter_data ) ) {
+ unset( $search_filters[ $key ] );
+ }
+}
+
// Classes
$classes = '';
if ( $search && $show_search ) {
diff --git a/ultimate-member.php b/ultimate-member.php
index ac36f83f..c194680b 100644
--- a/ultimate-member.php
+++ b/ultimate-member.php
@@ -3,7 +3,7 @@
Plugin Name: Ultimate Member
Plugin URI: http://ultimatemember.com/
Description: The easiest way to create powerful online communities and beautiful user profiles with WordPress
-Version: 2.6.2
+Version: 2.6.3
Author: Ultimate Member
Author URI: http://ultimatemember.com/
Text Domain: ultimate-member