admin->trace_current_screen();
}
/**
* Handles all actions for the admin area for creating, editing and deleting
* profile groups and fields.
*
* @since 1.0.0
*
* @param string $message Message to display.
* @param string $type Type of action to be displayed.
*/
function xprofile_admin( $message = '', $type = 'error' ) {
// What mode?
$mode = ! empty( $_GET['mode'] )
? sanitize_key( $_GET['mode'] )
: false;
// Group ID.
$group_id = ! empty( $_GET['group_id'] )
? intval( $_GET['group_id'] )
: false;
// Field ID.
$field_id = ! empty( $_GET['field_id'] )
? intval( $_GET['field_id'] )
: false;
// Option ID.
$option_id = ! empty( $_GET['option_id'] )
? intval( $_GET['option_id'] )
: false;
// Allowed modes.
$allowed_modes = array(
'add_group',
'edit_group',
'delete_group',
'do_delete_group',
'add_field',
'edit_field',
'delete_field',
'do_delete_field',
'delete_option',
'do_delete_option',
);
// Is an allowed mode.
if ( in_array( $mode, $allowed_modes, true ) ) {
// All group actions.
if ( false !== $group_id ) {
// Add field to group.
if ( 'add_field' === $mode ) {
xprofile_admin_manage_field( $group_id );
// Edit field of group.
} elseif ( ! empty( $field_id ) && 'edit_field' === $mode ) {
xprofile_admin_manage_field( $group_id, $field_id );
// Delete group.
} elseif ( in_array( $mode, array( 'delete_group', 'do_delete_group' ), true ) ) {
xprofile_admin_delete_group( $group_id );
// Edit group.
} elseif ( 'edit_group' === $mode ) {
xprofile_admin_manage_group( $group_id );
}
// Delete field.
} elseif ( ( false !== $field_id ) && ( in_array( $mode, array( 'delete_field', 'do_delete_field' ), true ) ) ) {
$delete_data = false;
if ( isset( $_GET['delete_data'] ) && $_GET['delete_data'] ) {
$delete_data = true;
}
xprofile_admin_delete_field( $field_id, 'field', $delete_data );
// Delete option.
} elseif ( ! empty( $option_id ) && in_array( $mode, array( 'delete_option', 'do_delete_option' ), true ) ) {
xprofile_admin_delete_field( $option_id, 'option' );
// Add group.
} elseif ( 'add_group' === $mode ) {
xprofile_admin_manage_group();
}
} else {
xprofile_admin_screen( $message, $type );
}
}
/**
* Output the main XProfile management screen.
*
* @since 2.3.0
*
* @param string $message Feedback message.
* @param string $type Feedback type.
*
* @todo Improve error message output
*/
function xprofile_admin_screen( $message = '', $type = 'error' ) {
// Users admin URL.
$url = bp_get_admin_url( 'users.php' );
// Add Group.
$add_group_url = add_query_arg(
array(
'page' => 'bp-profile-setup',
'mode' => 'add_group',
),
$url
);
// Validate type.
$type = preg_replace( '|[^a-z]|i', '', $type );
// Get all of the profile groups & fields.
$groups = bp_xprofile_get_groups(
array(
'fetch_fields' => true,
)
); ?>
name = $_POST['group_name'];
// Set the group description.
if ( ! empty( $_POST['group_description'] ) ) {
$group->description = $_POST['group_description'];
} else {
$group->description = '';
}
// Attempt to save the field group.
if ( false === $group->save() ) {
$message = __( 'There was an error saving the group. Please try again.', 'buddypress' );
$type = 'error';
// Save successful.
} else {
$message = __( 'The group was saved successfully.', 'buddypress' );
$type = 'success';
// @todo remove these old options.
if ( 1 === $group_id ) {
bp_update_option( 'bp-xprofile-base-group-name', $group->name );
}
/**
* Fires at the end of the group adding/saving process, if successful.
*
* @since 1.0.0
*
* @param BP_XProfile_Group $group Current BP_XProfile_Group object.
*/
do_action( 'xprofile_groups_saved_group', $group );
}
xprofile_admin_screen( $message, $type );
} else {
$group->render_admin_form( $message );
}
} else {
$group->render_admin_form();
}
}
/**
* Handles the deletion of profile data groups.
*
* @since 1.0.0
*
* @global string $message The feedback message to show.
* @global string $type The type of feedback message to show.
*
* @param int $group_id ID of the group to delete.
*/
function xprofile_admin_delete_group( $group_id ) {
global $message, $type;
check_admin_referer( 'bp_xprofile_delete_group' );
$mode = ! empty( $_GET['mode'] )
? sanitize_key( $_GET['mode'] )
: false;
// Display the group delete confirmation screen.
if ( 'delete_group' === $mode ) {
xprofile_admin_delete_group_screen( $group_id );
// Handle the deletion of group.
} else {
$group = new BP_XProfile_Group( $group_id );
if ( ! $group->delete() ) {
$message = _x( 'There was an error deleting the group. Please try again.', 'Error when deleting profile fields group', 'buddypress' );
$type = 'error';
} else {
$message = _x( 'The group was deleted successfully.', 'Profile fields group was deleted successfully', 'buddypress' );
$type = 'success';
/**
* Fires at the end of group deletion process, if successful.
*
* @since 1.0.0
*
* @param BP_XProfile_Group $group Current BP_XProfile_Group object.
*/
do_action( 'xprofile_groups_deleted_group', $group );
}
xprofile_admin_screen( $message, $type );
}
}
/**
* Display the delete confirmation screen of profile data groups.
*
* @since 7.0.0
* @param int $group_id ID of the profile field group to delete.
*/
function xprofile_admin_delete_group_screen( $group_id ) {
if ( ! bp_current_user_can( 'bp_moderate' ) ) {
die( '-1' );
}
$group = new BP_XProfile_Group( $group_id );
$base_url = remove_query_arg( array( 'mode', 'group_id', '_wpnonce' ), $_SERVER['REQUEST_URI'] );
?>
'do_delete_group',
'group_id' => $group_id,
),
$base_url
),
'bp_xprofile_delete_group'
);
?>
group_id = $group_id;
if ( isset( $_POST['saveField'] ) ) {
// Check nonce.
check_admin_referer( 'bp_xprofile_admin_field', 'bp_xprofile_admin_field' );
if ( BP_XProfile_Field::admin_validate() ) {
$field->is_required = $_POST['required'];
$field->type = $_POST['fieldtype'];
$field->name = $_POST['title'];
/*
* By default a Textbox field is created. To run field type's feature
* checks we need to set it to what it really is early.
*/
if ( is_null( $field_id ) ) {
$field_type = bp_xprofile_create_field_type( $field->type );
// If it's a placeholder, then the field type is not registered.
if ( ! $field_type instanceof BP_XProfile_Field_Type_Placeholder ) {
$field->type_obj = $field_type;
}
}
if ( ! $field->field_type_supports( 'required' ) ) {
$field->is_required = '0';
}
if ( ! empty( $_POST['description'] ) ) {
$field->description = $_POST['description'];
} else {
$field->description = '';
}
if ( ! empty( $_POST[ "sort_order_{$field->type}" ] ) ) {
$field->order_by = $_POST[ "sort_order_{$field->type}" ];
}
$field->field_order = $wpdb->get_var( $wpdb->prepare( "SELECT field_order FROM {$bp->profile->table_name_fields} WHERE id = %d", $field_id ) );
if ( ! is_numeric( $field->field_order ) || is_wp_error( $field->field_order ) ) {
$field->field_order = (int) $wpdb->get_var( $wpdb->prepare( "SELECT max(field_order) FROM {$bp->profile->table_name_fields} WHERE group_id = %d", $group_id ) );
$field->field_order++;
}
// For new profile fields, set the $field_id. For existing profile
// fields, this will overwrite $field_id with the same value.
$field_id = $field->save();
if ( empty( $field_id ) ) {
$message = __( 'There was an error saving the field. Please try again.', 'buddypress' );
$type = 'error';
} else {
$message = __( 'The field was saved successfully.', 'buddypress' );
$type = 'success';
// @todo remove these old options.
if ( 1 === $field_id ) {
bp_update_option( 'bp-xprofile-fullname-field-name', $field->name );
}
// Set member types.
if ( isset( $_POST['has-member-types'] ) ) {
$member_types = array();
if ( isset( $_POST['member-types'] ) ) {
$member_types = stripslashes_deep( $_POST['member-types'] );
}
$field->set_member_types( $member_types );
}
// Validate default visibility.
if ( ! empty( $_POST['default-visibility'] ) && in_array( $_POST['default-visibility'], wp_list_pluck( bp_xprofile_get_visibility_levels(), 'id' ), true ) ) {
$default_visibility = $_POST['default-visibility'];
if ( ! $field->field_type_supports( 'allow_custom_visibility' ) ) {
$default_visibility = 'public';
$available_visibility_levels = bp_xprofile_get_visibility_levels();
if ( isset( $field->type_obj->visibility ) && in_array( $field->type_obj->visibility, array_keys( $available_visibility_levels ), true ) ) {
$default_visibility = $field->type_obj->visibility;
}
}
bp_xprofile_update_field_meta( $field_id, 'default_visibility', $default_visibility );
}
// Validate custom visibility.
if ( ! empty( $_POST['allow-custom-visibility'] ) && in_array( $_POST['allow-custom-visibility'], array( 'allowed', 'disabled' ), true ) ) {
$allow_custom_visibility = $_POST['allow-custom-visibility'];
if ( ! $field->field_type_supports( 'allow_custom_visibility' ) ) {
$allow_custom_visibility = 'disabled';
}
bp_xprofile_update_field_meta( $field_id, 'allow_custom_visibility', $allow_custom_visibility );
}
// Validate signup.
if ( $field->field_type_supports( 'signup_position' ) ) {
if ( ! empty( $_POST['signup-position'] ) ) {
bp_xprofile_update_field_meta( $field_id, 'signup_position', (int) $_POST['signup-position'] );
} else {
bp_xprofile_delete_meta( $field_id, 'field', 'signup_position' );
}
}
$do_autolink = '';
if ( $field->field_type_supports( 'do_autolink' ) && isset( $_POST['do_autolink'] ) && $_POST['do_autolink'] ) {
$do_autolink = wp_unslash( $_POST['do_autolink'] );
}
// Save autolink settings.
if ( 'on' === $do_autolink ) {
bp_xprofile_update_field_meta( $field_id, 'do_autolink', 'on' );
} else {
bp_xprofile_update_field_meta( $field_id, 'do_autolink', 'off' );
}
if ( $field->type_obj->do_settings_section() ) {
$settings = isset( $_POST['field-settings'] ) ? wp_unslash( $_POST['field-settings'] ) : array();
$field->admin_save_settings( $settings );
}
/**
* Fires at the end of the process to save a field for a user, if successful.
*
* @since 1.0.0
*
* @param BP_XProfile_Field $field Current BP_XProfile_Field object.
*/
do_action( 'xprofile_fields_saved_field', $field );
$groups = bp_xprofile_get_groups();
}
xprofile_admin_screen( $message, $type );
} else {
$field->render_admin_form( $message );
}
} else {
$field->render_admin_form();
}
}
/**
* Handles the deletion of a profile field (or field option).
*
* @since 1.0.0
*
* @global string $message The feedback message to show.
* @global string $type The type of feedback message to show.
*
* @param int $field_id The field to delete.
* @param string $field_type The type of field being deleted.
* @param bool $delete_data Should the field data be deleted too.
*/
function xprofile_admin_delete_field( $field_id, $field_type = 'field', $delete_data = false ) {
global $message, $type;
check_admin_referer( 'bp_xprofile_delete_field-' . $field_id, 'bp_xprofile_delete_field' );
$mode = ! empty( $_GET['mode'] ) ? sanitize_key( $_GET['mode'] ) : false;
// Switch type to 'option' if type is not 'field'.
// @todo trust this param.
$field_type = ( 'field' === $field_type ) ? __( 'field', 'buddypress' ) : __( 'option', 'buddypress' );
// Display the field/option delete confirmation screen.
if ( in_array( $mode, array( 'delete_field', 'delete_option' ), true ) ) {
xprofile_admin_delete_field_screen( $field_id, $field_type );
// Handle the deletion of field
} else {
$field = xprofile_get_field( $field_id, null, false );
if ( ! $field->delete( (bool) $delete_data ) ) {
/* translators: %s: the field type */
$message = sprintf( __( 'There was an error deleting the %s. Please try again.', 'buddypress' ), $field_type );
$type = 'error';
} else {
/* translators: %s: the field type */
$message = sprintf( __( 'The %s was deleted successfully!', 'buddypress' ), $field_type );
$type = 'success';
/**
* Fires at the end of the field deletion process, if successful.
*
* @since 1.0.0
*
* @param BP_XProfile_Field $field Current BP_XProfile_Field object.
*/
do_action( 'xprofile_fields_deleted_field', $field );
}
xprofile_admin_screen( $message, $type );
}
}
/**
* Display the delete confirmation screen of xprofile field/option.
*
* @since 7.0.0
* @param int $field_id ID of the profile field to delete.
* @param string $field_type Type of the profile field to delete.
*/
function xprofile_admin_delete_field_screen( $field_id, $field_type ) {
if ( ! bp_current_user_can( 'bp_moderate' ) ) {
die( '-1' );
}
$field = xprofile_get_field( $field_id, null, false );
$base_url = remove_query_arg( array( 'page', 'mode', 'field_id', 'bp_xprofile_delete_field' ), $_SERVER['REQUEST_URI'] );
?>
' . esc_html( $field->name ) . ''
);
?>
field_type_supports( 'signup_position' ) ) {
wp_send_json_error(
array(
'message' => __( 'This field cannot be inserted into the registration form.', 'buddypress' ),
)
);
}
$signup_position = bp_xprofile_get_meta( $field->id, 'field', 'signup_position' );
if ( ! $signup_position ) {
$position = array_search( $field->id, $fields, true );
if ( false !== $position ) {
$position += 1;
} else {
$position = 1;
}
// Set the signup position.
bp_xprofile_update_field_meta( $field->id, 'signup_position', $position );
// Get the real Group object.
$group = xprofile_get_field_group( $field->id );
// Gets the HTML Output of the signup field.
$signup_field = bp_xprofile_admin_get_signup_field( $field, $group );
/**
* Fires once a signup field has been inserted.
*
* @since 8.0.0
*/
do_action( 'bp_xprofile_inserted_signup_field' );
// Send the signup field to output.
wp_send_json_success(
array(
'signup_field' => $signup_field,
'field_id' => $field->id,
)
);
} else {
wp_send_json_error(
array(
'message' => __( 'This field has been already added to the registration form.', 'buddypress' ),
)
);
}
} else {
wp_send_json_error();
}
} else {
// it's a sort operation.
foreach ( $fields as $position => $field_id ) {
bp_xprofile_update_field_meta( (int) $field_id, 'signup_position', (int) $position + 1 );
}
/**
* Fires once the signup fields have been reordered.
*
* @since 8.0.0
*/
do_action( 'bp_xprofile_reordered_signup_fields' );
wp_send_json_success();
}
} else {
/**
* Reorders profile fields.
*
* @todo there's something going wrong here.
* moving a field to another tab when there's only the fullname field fails.
*/
parse_str( $_POST['field_order'], $order );
$fields = (array) $order['draggable_field'];
foreach ( $fields as $position => $field_id ) {
xprofile_update_field_position( (int) $field_id, (int) $position, (int) $field_group_id );
}
wp_send_json_success();
}
}
add_action( 'wp_ajax_xprofile_reorder_fields', 'xprofile_ajax_reorder_fields' );
/**
* Removes a field from signup fields.
*
* @since 8.0.0
*/
function bp_xprofile_ajax_remove_signup_field() {
// Check the nonce.
check_admin_referer( 'bp_reorder_fields', '_wpnonce_reorder_fields' );
if ( ! isset( $_POST['signup_field_id'] ) || ! $_POST['signup_field_id'] ) {
return wp_send_json_error();
}
$signup_field_id = (int) wp_unslash( $_POST['signup_field_id'] );
// Validate the field ID.
$signup_position = bp_xprofile_get_meta( $signup_field_id, 'field', 'signup_position' );
if ( ! $signup_position ) {
wp_send_json_error();
}
bp_xprofile_delete_meta( $signup_field_id, 'field', 'signup_position' );
/**
* Fires when a signup field is removed from the signup form.
*
* @since 8.0.0
*/
do_action( 'bp_xprofile_removed_signup_field' );
wp_send_json_success();
}
add_action( 'wp_ajax_xprofile_remove_signup_field', 'bp_xprofile_ajax_remove_signup_field' );
/**
* Handles the reordering of field groups.
*
* @since 1.5.0
*/
function xprofile_ajax_reorder_field_groups() {
// Check the nonce.
check_admin_referer( 'bp_reorder_groups', '_wpnonce_reorder_groups' );
if ( empty( $_POST['group_order'] ) ) {
return false;
}
parse_str( $_POST['group_order'], $order );
foreach ( (array) $order['group'] as $position => $field_group_id ) {
xprofile_update_field_group_position( (int) $field_group_id, (int) $position );
}
}
add_action( 'wp_ajax_xprofile_reorder_groups', 'xprofile_ajax_reorder_field_groups' );
/**
* Handles the WYSIWYG display of each profile field on the edit screen.
*
* @since 1.5.0
* @since 8.0.0 Adds the `$is_signup` parameter.
*
* @global BP_XProfile_Field $field The Admin field.
*
* @param BP_XProfile_Field $admin_field Admin field.
* @param object $admin_group Admin group object.
* @param string $class Classes to append to output.
* @param bool $is_signup Whether the admin field output is made inside the signup group.
*/
function xprofile_admin_field( $admin_field, $admin_group, $class = '', $is_signup = false ) {
global $field;
$field = $admin_field;
$fieldset_id = sprintf( 'draggable_field_%d', $field->id );
// Users admin URL.
$url = bp_get_admin_url( 'users.php' );
// Edit.
$field_edit_url = add_query_arg(
array(
'page' => 'bp-profile-setup',
'mode' => 'edit_field',
'group_id' => (int) $field->group_id,
'field_id' => (int) $field->id,
),
$url
);
// Delete.
if ( $field->can_delete ) {
$field_delete_url = add_query_arg(
array(
'page' => 'bp-profile-setup',
'mode' => 'delete_field',
'field_id' => (int) $field->id,
),
$url . '#tabs-' . (int) $field->group_id
);
}
// Avoid duplicate IDs into the signup group.
if ( $is_signup ) {
$fieldset_id = sprintf( 'draggable_signup_field_%d', $field->id );
}
?>
can_delete ) ) : ?>
get_signup_position() ) : ?>
get_member_type_label(), array( 'span' => array( 'class' => true ) ) ); ?>
type, array_keys( bp_xprofile_get_field_types() ), true ) ) {
$field_type = bp_xprofile_create_field_type( $field->type );
$field_type->admin_field_html();
} else {
/**
* Fires after the input if the current field is not in default field types.
*
* @since 1.5.0
*
* @param BP_XProfile_Field $field Current BP_XProfile_Field
* object being rendered.
* @param int $value Integer 1.
*/
do_action( 'xprofile_admin_field', $field, 1 );
}
?>
description ) : ?>
description ); ?>
can_delete && ! $is_signup ) : ?>
can_delete && $is_signup ) : ?>
elements containing the xprofile field types.
*
* @since 2.0.0
*
* @param string $select_field_type The name of the field type that should be selected.
* Will defaults to "textbox" if NULL is passed.
*/
function bp_xprofile_admin_form_field_types( $select_field_type ) {
$categories = array();
if ( empty( $select_field_type ) ) {
$select_field_type = 'textbox';
}
// Sort each field type into its category.
foreach ( bp_xprofile_get_field_types() as $field_name => $field_class ) {
$field_type_obj = new $field_class();
$the_category = $field_type_obj->category;
// Fallback to a catch-all if category not set.
if ( ! $the_category ) {
$the_category = _x( 'Other', 'xprofile field type category', 'buddypress' );
}
if ( isset( $categories[ $the_category ] ) ) {
$categories[ $the_category ][] = array( $field_name, $field_type_obj );
} else {
$categories[ $the_category ] = array( array( $field_name, $field_type_obj ) );
}
}
// Sort the categories alphabetically. ksort()'s SORT_NATURAL is only in PHP >= 5.4 :((.
uksort( $categories, 'strnatcmp' );
// Loop through each category and output form .
foreach ( $categories as $category => $fields ) {
printf( '', esc_attr( $category ) ); // Already i18n'd in each profile type class.
// Sort these fields types alphabetically.
uasort( $fields, function ( $a, $b ) { return strnatcmp( $a[1]->name, $b[1]->name ); } );
foreach ( $fields as $field_type_obj ) {
$field_name = $field_type_obj[0];
$field_type_obj = $field_type_obj[1];
printf( '%3$s ', esc_attr( $field_name ), selected( $select_field_type, $field_name, false ), esc_html( $field_type_obj->name ) );
}
printf( ' ' );
}
}
// Load the xprofile user admin.
add_action( 'bp_init', array( 'BP_XProfile_User_Admin', 'register_xprofile_user_admin' ), 11 );