Skip to content
wp-skills
Register
tools/wordpress-custom-user-profile-fields-generator

Custom User Profile Fields Generator

WordPress Custom User Profile Fields Generator is a tool that enables the creation of custom fields in the WordPress user profile.

Draws the fields. It is hooked to both show_user_profile and edit_user_profile, because your own profile and someone else's are different screens.

Saves them, on personal_options_update and edit_user_profile_update. It checks the capability first — the display hooks do not.

The heading printed above this group of fields.

Your theme or plugin's own domain, for the labels and descriptions below.

Fields1
  • #1

    Shown in the left column of the profile table.

    Decides the input drawn and the sanitising used when the value is saved — an email field is not sanitised the same way as a URL.

    Greyed-out text inside the empty input. Not a default value; nothing is saved from it.

    The user meta key, and the name the input posts under. get_the_author_meta() reads it back by this exact string.

    Printed under the input as help text.

snippet.php
/**
 * The one list both the form and the save routine read.
 *
 * Keeping the definitions in a single place is what lets the save routine know
 * each field's type, and so which sanitizer to apply to it.
 */
function wpskills_custom_user_profile_fields_definitions() {
	return array(
		array(
			'id'          => 'hobby',
			'type'        => 'text',
			'label'       => __( 'Hobby', 'text-domain' ),
			'placeholder' => __( 'Hobby', 'text-domain' ),
			'description' => __( 'What is your hobby?', 'text-domain' ),
		),
	);
}

function wpskills_custom_user_profile_fields( $user ) {
	$output = '<h2>' . esc_html__( 'Custom user profile fields', 'text-domain' ) . '</h2>';
	$output .= '<table class="form-table">';

	foreach ( wpskills_custom_user_profile_fields_definitions() as $field ) {
		$output .= sprintf(
			'<tr><th><label for="%1$s">%2$s</label></th><td>'
			. '<input type="%3$s" id="%1$s" name="%1$s" value="%4$s" placeholder="%5$s" class="regular-text" />'
			. '<p class="description">%6$s</p></td></tr>',
			esc_attr( $field['id'] ),
			esc_html( $field['label'] ),
			esc_attr( $field['type'] ),
			esc_attr( get_user_meta( $user->ID, $field['id'], true ) ),
			esc_attr( $field['placeholder'] ),
			esc_html( $field['description'] )
		);
	}

	$output .= '</table>';

	// Every interpolated value above went through an esc_* function, so the
	// assembled markup is safe to echo as-is.
	echo $output;
}
add_action( 'show_user_profile', 'wpskills_custom_user_profile_fields' );
add_action( 'edit_user_profile', 'wpskills_custom_user_profile_fields' );

function wpskills_custom_user_profile_fields_save( $user_id ) {
	if ( ! current_user_can( 'edit_user', $user_id ) ) {
		return false;
	}

	foreach ( wpskills_custom_user_profile_fields_definitions() as $field ) {
		// A field the browser did not post is not a field set to empty; writing
		// it anyway would store null for anything not on screen.
		if ( ! isset( $_POST[ $field['id'] ] ) ) {
			continue;
		}

		// wp_unslash first: WordPress adds slashes to everything in $_POST.
		$value = wp_unslash( $_POST[ $field['id'] ] );

		switch ( $field['type'] ) {
			case 'email':
				$value = sanitize_email( $value );
				break;

			case 'url':
				$value = sanitize_url( $value );
				break;

			case 'number':
				$value = is_numeric( $value ) ? $value + 0 : '';
				break;

			default:
				$value = sanitize_text_field( $value );
				break;
		}

		update_user_meta( $user_id, $field['id'], $value );
	}
}
add_action( 'personal_options_update', 'wpskills_custom_user_profile_fields_save' );
add_action( 'edit_user_profile_update', 'wpskills_custom_user_profile_fields_save' );