@@ -467,6 +410,57 @@
elements containing the xprofile field types.
+ *
+ * @param string $select_field_type The name of the field type that should be selected. Will defaults to "textbox" if NULL is passed.
+ * @since BuddyPress (2.0.0)
+ */
+function bp_xprofile_admin_form_field_types( $select_field_type ) {
+ $categories = array();
+
+ if ( is_null( $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( '' );
+ }
+}
+
if ( ! class_exists( 'BP_XProfile_User_Admin' ) ) :
/**
* Load xProfile Profile admin area.
@@ -642,7 +636,7 @@
// Set the errors var
$errors = false;
- // Now we've checked for required fields, lets save the values.
+ // Now we've checked for required fields, let's save the values.
foreach ( (array) $posted_field_ids as $field_id ) {
// Certain types of fields (checkboxes, multiselects) may come through empty. Save them as an empty array so that they don't get overwritten by the default on the next edit.
@@ -702,169 +696,55 @@
}
if ( bp_has_profile( $r ) ) :
-
while ( bp_profile_groups() ) : bp_the_profile_group(); ?>
+
-
+
+
+
-
+ while ( bp_profile_fields() ) : bp_the_profile_field(); ?>
-
+
', esc_attr( 'field_' . $this->field_obj->id ) );
+
+ for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
+
+ // Check for updated posted values, but errors preventing them from being saved first time
+ if ( isset( $_POST['field_' . $this->field_obj->id] ) && $option_value != $_POST['field_' . $this->field_obj->id] ) {
+ if ( ! empty( $_POST['field_' . $this->field_obj->id] ) ) {
+ $option_value = sanitize_text_field( $_POST['field_' . $this->field_obj->id] );
+ }
+ }
+
+ // Run the allowed option name through the before_save filter, so we'll be sure to get a match
+ $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
+ $selected = '';
+
+ if ( $option_value === $allowed_options || ( empty( $option_value ) && ! empty( $options[$k]->is_default_option ) ) ) {
+ $selected = ' checked="checked"';
+ }
+
+ $new_html = sprintf( '',
+ $selected,
+ esc_attr( "field_{$this->field_obj->id}" ),
+ esc_attr( "option_{$options[$k]->id}" ),
+ esc_attr( stripslashes( $options[$k]->name ) ),
+ esc_html( stripslashes( $options[$k]->name ) )
+ );
+ $html .= apply_filters( 'bp_get_the_profile_field_options_radio', $new_html, $options[$k], $this->field_obj->id, $selected, $k );
+ }
+
+ echo $html . '
';
+ }
+
+ /**
+ * Output HTML for this field type on the wp-admin Profile Fields screen.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function admin_field_html( array $raw_properties = array() ) {
+ bp_the_profile_field_options();
+
+ if ( ! bp_get_the_profile_field_is_required() ) : ?>
+
+
+ category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
+ $this->name = _x( 'Multi Select Box', 'xprofile field type', 'buddypress' );
+
+ $this->supports_multiple_defaults = true;
+ $this->accepts_null_value = true;
+ $this->supports_options = true;
+
+ $this->set_format( '/^.+$/', 'replace' );
+ do_action( 'bp_xprofile_field_type_multiselectbox', $this );
+ }
+
+ /**
+ * Output the edit field HTML for this field type.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/select.html permitted attributes} that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function edit_field_html( array $raw_properties = array() ) {
+ $user_id = bp_displayed_user_id();
+
+ // user_id is a special optional parameter that we pass to {@link bp_the_profile_field_options()}.
+ if ( isset( $raw_properties['user_id'] ) ) {
+ $user_id = (int) $raw_properties['user_id'];
+ unset( $raw_properties['user_id'] );
+ }
+
+ $html = $this->get_edit_field_html_elements( array_merge(
+ array( 'multiple' => 'multiple' ),
+ $raw_properties
+ ) );
+ ?>
+
+
+
+
+
+
+ field_obj->id, $args['user_id'] ) );
+
+ $options = $this->field_obj->get_children();
+ $html = '';
+
+ if ( empty( $original_option_values ) && ! empty( $_POST['field_' . $this->field_obj->id] ) ) {
+ $original_option_values = sanitize_text_field( $_POST['field_' . $this->field_obj->id] );
+ }
+
+ $option_values = (array) $original_option_values;
+ for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
+ $selected = '';
+
+ // Check for updated posted values, but errors preventing them from being saved first time
+ foreach( $option_values as $i => $option_value ) {
+ if ( isset( $_POST['field_' . $this->field_obj->id] ) && $_POST['field_' . $this->field_obj->id][$i] != $option_value ) {
+ if ( ! empty( $_POST['field_' . $this->field_obj->id][$i] ) ) {
+ $option_values[] = sanitize_text_field( $_POST['field_' . $this->field_obj->id][$i] );
+ }
+ }
+ }
+
+ // Run the allowed option name through the before_save filter, so we'll be sure to get a match
+ $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
+
+ // First, check to see whether the user-entered value matches
+ if ( in_array( $allowed_options, $option_values ) ) {
+ $selected = ' selected="selected"';
+ }
+
+ // Then, if the user has not provided a value, check for defaults
+ if ( ! is_array( $original_option_values ) && empty( $option_values ) && ! empty( $options[$k]->is_default_option ) ) {
+ $selected = ' selected="selected"';
+ }
+
+ $html .= apply_filters( 'bp_get_the_profile_field_options_multiselect', '', $options[$k], $this->field_obj->id, $selected, $k );
+ }
+
+ echo $html;
+ }
+
+ /**
+ * Output HTML for this field type on the wp-admin Profile Fields screen.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function admin_field_html( array $raw_properties = array() ) {
+ $html = $this->get_edit_field_html_elements( array_merge(
+ array( 'multiple' => 'multiple' ),
+ $raw_properties
+ ) );
+ ?>
+
+ category = _x( 'Multi Fields', 'xprofile field type category', 'buddypress' );
+ $this->name = _x( 'Drop Down Select Box', 'xprofile field type', 'buddypress' );
+
+ $this->supports_options = true;
+
+ $this->set_format( '/^.+$/', 'replace' );
+ do_action( 'bp_xprofile_field_type_selectbox', $this );
+ }
+
+ /**
+ * Output the edit field HTML for this field type.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/select.html permitted attributes} that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function edit_field_html( array $raw_properties = array() ) {
+ $user_id = bp_displayed_user_id();
+
+ // user_id is a special optional parameter that we pass to {@link bp_the_profile_field_options()}.
+ if ( isset( $raw_properties['user_id'] ) ) {
+ $user_id = (int) $raw_properties['user_id'];
+ unset( $raw_properties['user_id'] );
+ }
+
+ $html = $this->get_edit_field_html_elements( $raw_properties );
+ ?>
+
+
+ field_obj->id, $args['user_id'] ) );
+
+ $options = $this->field_obj->get_children();
+ $html = '';
+
+ if ( empty( $original_option_values ) && !empty( $_POST['field_' . $this->field_obj->id] ) ) {
+ $original_option_values = sanitize_text_field( $_POST['field_' . $this->field_obj->id] );
+ }
+
+ $option_values = (array) $original_option_values;
+ for ( $k = 0, $count = count( $options ); $k < $count; ++$k ) {
+ $selected = '';
+
+ // Check for updated posted values, but errors preventing them from being saved first time
+ foreach( $option_values as $i => $option_value ) {
+ if ( isset( $_POST['field_' . $this->field_obj->id] ) && $_POST['field_' . $this->field_obj->id] != $option_value ) {
+ if ( ! empty( $_POST['field_' . $this->field_obj->id] ) ) {
+ $option_values[$i] = sanitize_text_field( $_POST['field_' . $this->field_obj->id] );
+ }
+ }
+ }
+
+ // Run the allowed option name through the before_save filter, so we'll be sure to get a match
+ $allowed_options = xprofile_sanitize_data_value_before_save( $options[$k]->name, false, false );
+
+ // First, check to see whether the user-entered value matches
+ if ( in_array( $allowed_options, $option_values ) ) {
+ $selected = ' selected="selected"';
+ }
+
+ // Then, if the user has not provided a value, check for defaults
+ if ( ! is_array( $original_option_values ) && empty( $option_values ) && $options[$k]->is_default_option ) {
+ $selected = ' selected="selected"';
+ }
+
+ $html .= apply_filters( 'bp_get_the_profile_field_options_select', '', $options[$k], $this->field_obj->id, $selected, $k );
+ }
+
+ echo $html;
+ }
+
+ /**
+ * Output HTML for this field type on the wp-admin Profile Fields screen.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function admin_field_html( array $raw_properties = array() ) {
+ $html = $this->get_edit_field_html_elements( $raw_properties );
+ ?>
+
+ category = _x( 'Single Fields', 'xprofile field type category', 'buddypress' );
+ $this->name = _x( 'Multi-line Text Area', 'xprofile field type', 'buddypress' );
+
+ $this->set_format( '/^.*$/m', 'replace' );
+ do_action( 'bp_xprofile_field_type_textarea', $this );
+ }
+
+ /**
+ * Output the edit field HTML for this field type.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/textarea.html permitted attributes} that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function edit_field_html( array $raw_properties = array() ) {
+
+ // user_id is a special optional parameter that certain other fields types pass to {@link bp_the_profile_field_options()}.
+ if ( isset( $raw_properties['user_id'] ) ) {
+ unset( $raw_properties['user_id'] );
+ }
+
+ $html = $this->get_edit_field_html_elements( array_merge(
+ array(
+ 'cols' => 40,
+ 'rows' => 5,
+ ),
+ $raw_properties
+ ) );
+ ?>
+
+
+ get_edit_field_html_elements( array_merge(
+ array(
+ 'cols' => 40,
+ 'rows' => 5,
+ ),
+ $raw_properties
+ ) );
+ ?>
+
+ category = _x( 'Single Fields', 'xprofile field type category', 'buddypress' );
+ $this->name = _x( 'Text Box', 'xprofile field type', 'buddypress' );
+
+ $this->set_format( '/^.*$/', 'replace' );
+ do_action( 'bp_xprofile_field_type_textbox', $this );
+ }
+
+ /**
+ * Output the edit field HTML for this field type.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/input.text.html permitted attributes} that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function edit_field_html( array $raw_properties = array() ) {
+
+ // user_id is a special optional parameter that certain other fields types pass to {@link bp_the_profile_field_options()}.
+ if ( isset( $raw_properties['user_id'] ) ) {
+ unset( $raw_properties['user_id'] );
+ }
+
+ $html = $this->get_edit_field_html_elements( array_merge(
+ array(
+ 'type' => 'text',
+ 'value' => bp_get_the_profile_field_edit_value(),
+ ),
+ $raw_properties
+ ) );
+ ?>
+
+ >
+ get_edit_field_html_elements( array_merge(
+ array( 'type' => 'text' ),
+ $raw_properties
+ ) );
+ ?>
+ >
+ category = _x( 'Single Fields', 'xprofile field type category', 'buddypress' );
+ $this->name = _x( 'Number', 'xprofile field type', 'buddypress' );
+
+ $this->set_format( '/^\d+$/', 'replace' );
+ do_action( 'bp_xprofile_field_type_number', $this );
+ }
+
+ /**
+ * Output the edit field HTML for this field type.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of {@link http://dev.w3.org/html5/markup/input.number.html permitted attributes} that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ public function edit_field_html( array $raw_properties = array() ) {
+
+ // user_id is a special optional parameter that certain other fields types pass to {@link bp_the_profile_field_options()}.
+ if ( isset( $raw_properties['user_id'] ) ) {
+ unset( $raw_properties['user_id'] );
+ }
+
+ $html = $this->get_edit_field_html_elements( array_merge(
+ array(
+ 'type' => 'number',
+ 'value' => bp_get_the_profile_field_edit_value(),
+ ),
+ $raw_properties
+ ) );
+ ?>
+
+ >
+ get_edit_field_html_elements( array_merge(
+ array( 'type' => 'number' ),
+ $raw_properties
+ ) );
+ ?>
+ >
+ Profile Fields] screen in wp-admin.
+ *
+ * @since BuddyPress (2.0.0)
+ * @var string
+ */
+ public $category = '';
+
+ /**
+ * @since BuddyPress (2.0.0)
+ * @var bool If this is set, allow BP to store null/empty values for this field type.
+ */
+ public $accepts_null_value = false;
+
+ /**
+ * If this is set, BP will set this field type's validation whitelist from the field's options (e.g checkbox, selectbox).
+ *
+ * @since BuddyPress (2.0.0)
+ * @var bool Does this field support options? e.g. selectbox, radio buttons, etc.
+ */
+ public $supports_options = false;
+
+ /**
+ * @since BuddyPress (2.0.0)
+ * @var bool Does this field type support multiple options being set as default values? e.g. multiselectbox, checkbox.
+ */
+ public $supports_multiple_defaults = false;
+
+ /**
+ * @since BuddyPress (2.0.0)
+ * @var BP_XProfile_Field If this object is created by instantiating a {@link BP_XProfile_Field}, this is a reference back to that object.
+ */
+ public $field_obj = null;
+
+ /**
+ * Constructor
+ *
+ * @since BuddyPress (2.0.0)
+ */
+ public function __construct() {
+ do_action( 'bp_xprofile_field_type', $this );
+ }
+
+ /**
+ * Set a regex that profile data will be asserted against.
+ *
+ * You can call this method multiple times to set multiple formats. When validation is performed,
+ * it's successful as long as the new value matches any one of the registered formats.
+ *
+ * @param string $format Regex string
+ * @param string $replace_format Optional; if 'replace', replaces the format instead of adding to it. Defaults to 'add'.
+ * @return BP_XProfile_Field_Type
+ * @since BuddyPress (2.0.0)
+ */
+ public function set_format( $format, $replace_format = 'add' ) {
+
+ $format = apply_filters( 'bp_xprofile_field_type_set_format', $format, $replace_format, $this );
+
+ if ( 'add' === $replace_format ) {
+ $this->validation_regex[] = $format;
+ } elseif ( 'replace' === $replace_format ) {
+ $this->validation_regex = array( $format );
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a value to this type's whitelist that that profile data will be asserted against.
+ *
+ * You can call this method multiple times to set multiple formats. When validation is performed,
+ * it's successful as long as the new value matches any one of the registered formats.
+ *
+ * @param string|array $values
+ * @return BP_XProfile_Field_Type
+ * @since BuddyPress (2.0.0)
+ */
+ public function set_whitelist_values( $values ) {
+ foreach ( (array) $values as $value ) {
+ $this->validation_whitelist[] = apply_filters( 'bp_xprofile_field_type_set_whitelist_values', $value, $values, $this );
+ }
+
+ return $this;
+ }
+
+ /**
+ * Check the given string against the registered formats for this field type.
+ *
+ * This method doesn't support chaining.
+ *
+ * @param string|array $values Value to check against the registered formats
+ * @return bool True if the value validates
+ * @since BuddyPress (2.0.0)
+ */
+ public function is_valid( $values ) {
+ $validated = false;
+
+ // Some types of field (e.g. multi-selectbox) may have multiple values to check
+ foreach ( (array) $values as $value ) {
+
+ // Validate the $value against the type's accepted format(s).
+ foreach ( $this->validation_regex as $format ) {
+ if ( 1 === preg_match( $format, $value ) ) {
+ $validated = true;
+ continue;
+
+ } else {
+ $validated = false;
+ }
+ }
+ }
+
+ // Handle field types with accepts_null_value set if $values is an empty array
+ if ( ! $validated && is_array( $values ) && empty( $values ) && $this->accepts_null_value ) {
+ $validated = true;
+ }
+
+ // If there's a whitelist set, also check the $value.
+ if ( $validated && ! empty( $values ) && ! empty( $this->validation_whitelist ) ) {
+
+ foreach ( (array) $values as $value ) {
+ $validated = in_array( $value, $this->validation_whitelist, true );
+ }
+ }
+
+ return (bool) apply_filters( 'bp_xprofile_field_type_is_valid', $validated, $values, $this );
+ }
+
+ /**
+ * Output the edit field HTML for this field type.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ abstract public function edit_field_html( array $raw_properties = array() );
+
+ /**
+ * Output the edit field options HTML for this field type.
+ *
+ * BuddyPress considers a field's "options" to be, for example, the items in a selectbox.
+ * These are stored separately in the database, and their templating is handled separately.
+ * Populate this method in a child class if it's required. Otherwise, you can leave it out.
+ *
+ * This templating is separate from {@link BP_XProfile_Field_Type::edit_field_html()} because
+ * it's also used in the wp-admin screens when creating new fields, and for backwards compatibility.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $args Optional. The arguments passed to {@link bp_the_profile_field_options()}.
+ * @since BuddyPress (2.0.0)
+ */
+ public function edit_field_options_html( array $args = array() ) {}
+
+ /**
+ * Output HTML for this field type on the wp-admin Profile Fields screen.
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param array $raw_properties Optional key/value array of permitted attributes that you want to add.
+ * @since BuddyPress (2.0.0)
+ */
+ abstract public function admin_field_html( array $raw_properties = array() );
+
+ /**
+ * Output HTML for this field type's children options on the wp-admin Profile Fields "Add Field" and "Edit Field" screens.
+ *
+ * You don't need to implement this method for all field types. It's used in core by the
+ * selectbox, multi selectbox, checkbox, and radio button fields, to allow the admin to
+ * enter the child option values (e.g. the choices in a select box).
+ *
+ * Must be used inside the {@link bp_profile_fields()} template loop.
+ *
+ * @param BP_XProfile_Field $current_field The current profile field on the add/edit screen.
+ * @param string $control_type Optional. HTML input type used to render the current field's child options.
+ * @since BuddyPress (2.0.0)
+ */
+ public function admin_new_field_html( BP_XProfile_Field $current_field, $control_type = '' ) {
+ $type = array_search( get_class( $this ), bp_xprofile_get_field_types() );
+ if ( false === $type ) {
+ return;
+ }
+
+ $class = $current_field->type != $type ? 'display: none;' : '';
+ $current_type_obj = bp_xprofile_create_field_type( $type );
+ ?>
+
+
+
+
+
+
+
+
+
+ get_children( true );
+
+ // If no children options exists for this field, check in $_POST for a submitted form (e.g. on the "new field" screen).
+ if ( ! $options ) {
+
+ $options = array();
+ $i = 1;
+
+ while ( isset( $_POST[$type . '_option'][$i] ) ) {
+
+ // Multiselectbox and checkboxes support MULTIPLE default options; all other core types support only ONE.
+ if ( $current_type_obj->supports_options && ! $current_type_obj->supports_multiple_defaults && isset( $_POST["isDefault_{$type}_option"][$i] ) && (int) $_POST["isDefault_{$type}_option"] === $i ) {
+ $is_default_option = true;
+ } elseif ( isset( $_POST["isDefault_{$type}_option"][$i] ) ) {
+ $is_default_option = (bool) $_POST["isDefault_{$type}_option"][$i];
+ } else {
+ $is_default_option = false;
+ }
+
+ // Grab the values from $_POST to use as the form's options
+ $options[] = (object) array(
+ 'id' => -1,
+ 'is_default_option' => $is_default_option,
+ 'name' => sanitize_text_field( stripslashes( $_POST[$type . '_option'][$i] ) ),
+ );
+
+ ++$i;
+ }
+
+ // If there are still no children options set, this must be the "new field" screen, so add one new/empty option.
+ if ( ! $options ) {
+ $options[] = (object) array(
+ 'id' => -1,
+ 'is_default_option' => false,
+ 'name' => '',
+ );
+ }
+ }
+
+ // Render the markup for the children options
+ if ( ! empty( $options ) ) {
+ $default_name = '';
+
+ for ( $i = 0, $count = count( $options ); $i < $count; ++$i ) :
+ $j = $i + 1;
+
+ // Multiselectbox and checkboxes support MULTIPLE default options; all other core types support only ONE.
+ if ( $current_type_obj->supports_options && $current_type_obj->supports_multiple_defaults ) {
+ $default_name = '[' . $j . ']';
+ }
+ ?>
+
+