Index: trunk/src/bp-xprofile/classes/class-bp-xprofile-field.php
===================================================================
--- trunk/src/bp-xprofile/classes/class-bp-xprofile-field.php	(revision 12725)
+++ trunk/src/bp-xprofile/classes/class-bp-xprofile-field.php	(revision 12868)
@@ -183,4 +183,13 @@
 			$this->type_obj->field_obj = $this;
 		}
+
+		/**
+		 * Fires when the xProfile field object has been constructed.
+		 *
+		 * @since 8.0.0
+		 *
+		 * @param BP_XProfile_Field $this The xProfile field object.
+		 */
+		do_action( 'bp_xprofile_field', $this );
 	}
 
@@ -807,8 +816,17 @@
 	public function get_default_visibility() {
 		if ( ! isset( $this->default_visibility ) ) {
-			$this->default_visibility = bp_xprofile_get_meta( $this->id, 'field', 'default_visibility' );
-
-			if ( ! $this->default_visibility ) {
-				$this->default_visibility = 'public';
+			$this->default_visibility = 'public';
+			$this->visibility         = '';
+
+			if ( isset( $this->type_obj->visibility ) && $this->type_obj->visibility ) {
+				$this->visibility = $this->type_obj->visibility;
+			}
+
+			if ( $this->field_type_supports( 'allow_custom_visibility' ) ) {
+				$this->visibility = bp_xprofile_get_meta( $this->id, 'field', 'default_visibility' );
+			}
+
+			if ( $this->visibility ) {
+				$this->default_visibility = $this->visibility;
 			}
 		}
@@ -1319,4 +1337,50 @@
 
 	/**
+	 * Gets field type supports.
+	 *
+	 * @since 8.0.0
+	 *
+	 * @return bool[] Supported features.
+	 */
+	public function get_field_type_supports() {
+		$supports = array(
+			'switch_fieldtype'        => true,
+			'allow_required'          => true,
+			'allow_autolink'          => true,
+			'allow_custom_visibility' => true,
+			'member_types'            => true,
+		);
+
+		if ( isset( $this->type_obj ) && $this->type_obj ) {
+			$field_type = $this->type_obj;
+
+			if ( isset( $field_type::$supported_features ) ) {
+				$supports = array_merge( $supports, $field_type::$supported_features );
+			}
+		}
+
+		return $supports;
+	}
+
+	/**
+	 * Checks whether the field type supports the requested feature.
+	 *
+	 * @since 8.0.0
+	 *
+	 * @param string $support The name of the feature.
+	 * @return boolean True if the field type supports the feature. False otherwise.
+	 */
+	public function field_type_supports( $support = '' ) {
+		$retval   = true;
+		$features = $this->get_field_type_supports();
+
+		if ( isset( $features[ $support ] ) ) {
+			$retval = $features[ $support ];
+		}
+
+		return $retval;
+	}
+
+	/**
 	 * Private method used to display the submit metabox.
 	 *
@@ -1443,5 +1507,5 @@
 
 		// The primary field is for all, so bail.
-		if ( 1 === (int) $this->id ) {
+		if ( 1 === (int) $this->id || ! $this->field_type_supports( 'member_types' ) ) {
 			return;
 		}
@@ -1456,5 +1520,5 @@
 		?>
 
-		<div id="member-types-div" class="postbox">
+		<div id="field-type-member-types" class="postbox">
 			<h2><?php _e( 'Member Types', 'buddypress' ); ?></h2>
 			<div class="inside">
@@ -1497,10 +1561,10 @@
 	private function visibility_metabox() {
 
-		// Default field cannot have custom visibility.
-		if ( true === $this->is_default_field() ) {
+		// Default field and field types not supporting the feature cannot have custom visibility.
+		if ( true === $this->is_default_field() || ! $this->field_type_supports( 'allow_custom_visibility' ) ) {
 			return;
 		} ?>
 
-		<div class="postbox">
+		<div class="postbox" id="field-type-visibiliy-metabox">
 			<h2><label for="default-visibility"><?php esc_html_e( 'Visibility', 'buddypress' ); ?></label></h2>
 			<div class="inside">
@@ -1546,10 +1610,10 @@
 	private function required_metabox() {
 
-		// Default field is always required.
-		if ( true === $this->is_default_field() ) {
+		// Default field and field types not supporting the feature cannot be required.
+		if ( true === $this->is_default_field() || ! $this->field_type_supports( 'required' ) ) {
 			return;
 		} ?>
 
-		<div class="postbox">
+		<div class="postbox" id="field-type-required-metabox">
 			<h2><label for="required"><?php esc_html_e( 'Requirement', 'buddypress' ); ?></label></h2>
 			<div class="inside">
@@ -1572,7 +1636,11 @@
 	 */
 	private function autolink_metabox() {
-		?>
-
-		<div class="postbox">
+
+		// Field types not supporting the feature cannot use autolink.
+		if ( ! $this->field_type_supports( 'do_autolink' ) ) {
+			return;
+		} ?>
+
+		<div class="postbox" id="field-type-autolink-metabox">
 			<h2><?php esc_html_e( 'Autolink', 'buddypress' ); ?></h2>
 			<div class="inside">
@@ -1607,14 +1675,21 @@
 		if ( true === $this->is_default_field() ) {
 			return;
-		} ?>
+		}
+		?>
 
 		<div class="postbox">
 			<h2><label for="fieldtype"><?php esc_html_e( 'Type', 'buddypress'); ?></label></h2>
 			<div class="inside" aria-live="polite" aria-atomic="true" aria-relevant="all">
-				<select name="fieldtype" id="fieldtype" onchange="show_options(this.value)">
-
-					<?php bp_xprofile_admin_form_field_types( $this->type ); ?>
-
-				</select>
+				<?php if ( ! $this->field_type_supports( 'switch_fieldtype' ) ) : ?>
+					<input type="text" disabled="true" value="<?php echo esc_attr( $this->type_obj->name ); ?>">
+					<input type="hidden" name="fieldtype" id="fieldtype" value="<?php echo esc_attr( $this->type ); ?>">
+
+				<?php else : ?>
+					<select name="fieldtype" id="fieldtype" onchange="show_options(this.value)">
+
+						<?php bp_xprofile_admin_form_field_types( $this->type ); ?>
+
+					</select>
+				<?php endif; ?>
 
 				<?php
@@ -1643,13 +1718,71 @@
 		wp_nonce_field( 'bp_xprofile_admin_field', 'bp_xprofile_admin_field' );
 
-		// Field 1 is the fullname field, which cannot have custom visibility.
-		if ( false === $this->is_default_field() ) {
+		// Init default field hidden inputs.
+		$default_field_hidden_inputs = array();
+		$hidden_fields = array(
+			'required' => array(
+				'name'  => 'required',
+				'id'    => 'required',
+				'value' => '0',
+			),
+			'default_visibility' => array(
+				'name'  => 'default-visibility',
+				'id'    => 'default-visibility',
+				'value' => $this->get_default_visibility(),
+			),
+			'allow_custom_visibility' => array(
+				'name'  => 'allow-custom-visibility',
+				'id'    => 'allow-custom-visibility',
+				'value' => 'disabled',
+			),
+			'do_autolink' => array(
+				'name'  => 'do_autolink',
+				'id'    => 'do-autolink',
+				'value' => '',
+			),
+		);
+
+		// Field 1 is the fullname field, which is required.
+		if ( true === $this->is_default_field() ) {
+			$default_field_required          = $hidden_fields['required'];
+			$default_field_required['value'] = '1';
+
+			$default_field_hidden_inputs = array(
+				$default_field_required,
+				array(
+					'name'  => 'fieldtype',
+					'id'    => 'fieldtype',
+					'value' => 'textbox',
+				),
+			);
+		}
+
+		$supports = $this->get_field_type_supports();
+		if ( $supports ) {
+			foreach ( $supports as $feature => $support ) {
+				if ( true === $support || in_array( $feature, array( 'switch_fieldtype', 'member_types' ), true ) ) {
+					continue;
+				}
+
+				$default_field_hidden_inputs[] = $hidden_fields[ $feature ];
+
+				if ( 'allow_custom_visibility' === $feature ) {
+					$default_field_hidden_inputs[] = $hidden_fields['default_visibility'];
+				}
+			}
+		}
+
+		if ( ! $default_field_hidden_inputs ) {
 			return;
-		} ?>
-
-		<input type="hidden" name="required"  id="required"  value="1"       />
-		<input type="hidden" name="fieldtype" id="fieldtype" value="textbox" />
-
-		<?php
+		}
+
+		foreach ( $default_field_hidden_inputs as $default_field_hidden_input ) {
+			printf(
+				'<input type="hidden" name="%1$s" id="%2$s" value="%3$s"/>',
+				esc_attr( $default_field_hidden_input['name'] ),
+				esc_attr( $default_field_hidden_input['id'] ),
+				esc_attr( $default_field_hidden_input['value'] )
+			);
+		}
 	}
 
