# Front-End Profile Editing Form

> Adds a [wpide_edit_profile] shortcode where logged-in members can update their name, display name, email, website and bio without visiting wp-admin.

- Type: PHP
- Runs: Run everywhere
- Category: [Users](https://wpide.com/library/category/users/)
- Tags: profile, shortcode, account
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/frontend-edit-profile-form/

## Code

```php
$wpide_profile_errors = null;

add_action( 'template_redirect', function () use ( &$wpide_profile_errors ) {
    if ( empty( $_POST['wpide_profile_nonce'] ) || ! is_user_logged_in() ) {
        return;
    }

    if ( ! wp_verify_nonce( sanitize_key( $_POST['wpide_profile_nonce'] ), 'wpide_edit_profile' ) ) {
        $wpide_profile_errors = new WP_Error( 'nonce', 'The form expired. Please try again.' );
        return;
    }

    $user  = wp_get_current_user();
    $email = isset( $_POST['wpide_email'] ) ? sanitize_email( wp_unslash( $_POST['wpide_email'] ) ) : '';
    $errors = new WP_Error();

    if ( ! is_email( $email ) ) {
        $errors->add( 'email', 'Please enter a valid email address.' );
    } elseif ( strtolower( $email ) !== strtolower( $user->user_email ) && email_exists( $email ) ) {
        $errors->add( 'email', 'That email address is already used by another account.' );
    }

    if ( $errors->has_errors() ) {
        $wpide_profile_errors = $errors;
        return;
    }

    $first   = isset( $_POST['wpide_first_name'] ) ? sanitize_text_field( wp_unslash( $_POST['wpide_first_name'] ) ) : '';
    $last    = isset( $_POST['wpide_last_name'] ) ? sanitize_text_field( wp_unslash( $_POST['wpide_last_name'] ) ) : '';
    $display = isset( $_POST['wpide_display_name'] ) ? sanitize_text_field( wp_unslash( $_POST['wpide_display_name'] ) ) : '';
    $allowed = array_filter( array_unique( array( $user->user_login, $user->nickname, $first, $last, trim( "$first $last" ), trim( "$last $first" ) ) ) );

    $result = wp_update_user( array(
        'ID'           => $user->ID,
        'first_name'   => $first,
        'last_name'    => $last,
        'display_name' => in_array( $display, $allowed, true ) ? $display : $user->display_name,
        'user_email'   => $email,
        'user_url'     => isset( $_POST['wpide_url'] ) ? esc_url_raw( wp_unslash( $_POST['wpide_url'] ) ) : '',
        'description'  => isset( $_POST['wpide_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['wpide_description'] ) ) : '',
    ) );

    if ( is_wp_error( $result ) ) {
        $wpide_profile_errors = $result;
        return;
    }

    wp_safe_redirect( add_query_arg( 'profile-updated', 1 ) );
    exit;
} );

add_shortcode( 'wpide_edit_profile', function () use ( &$wpide_profile_errors ) {
    if ( ! is_user_logged_in() ) {
        return '<p>Please <a href="' . esc_url( wp_login_url( get_permalink() ) ) . '">log in</a> to edit your profile.</p>';
    }

    $user    = wp_get_current_user();
    $options = array_filter( array_unique( array( $user->user_login, $user->nickname, $user->first_name, $user->last_name, trim( $user->first_name . ' ' . $user->last_name ) ) ) );

    ob_start();

    if ( isset( $_GET['profile-updated'] ) ) {
        echo '<p class="wpide-profile-notice" role="status">Your profile has been updated.</p>';
    }

    if ( is_wp_error( $wpide_profile_errors ) ) {
        echo '<div class="wpide-profile-errors" role="alert"><p>' . implode( '</p><p>', array_map( 'esc_html', $wpide_profile_errors->get_error_messages() ) ) . '</p></div>';
    }
    ?>
    <form class="wpide-profile-form" method="post">
        <p><label for="wpide-first-name">First name</label><br><input type="text" id="wpide-first-name" name="wpide_first_name" value="<?php echo esc_attr( $user->first_name ); ?>" autocomplete="given-name"></p>
        <p><label for="wpide-last-name">Last name</label><br><input type="text" id="wpide-last-name" name="wpide_last_name" value="<?php echo esc_attr( $user->last_name ); ?>" autocomplete="family-name"></p>
        <p><label for="wpide-display-name">Show my name as</label><br><select id="wpide-display-name" name="wpide_display_name">
            <?php foreach ( $options as $option ) : ?>
                <option value="<?php echo esc_attr( $option ); ?>" <?php selected( $user->display_name, $option ); ?>><?php echo esc_html( $option ); ?></option>
            <?php endforeach; ?>
        </select></p>
        <p><label for="wpide-email">Email</label><br><input type="email" id="wpide-email" name="wpide_email" value="<?php echo esc_attr( $user->user_email ); ?>" autocomplete="email" required></p>
        <p><label for="wpide-url">Website</label><br><input type="url" id="wpide-url" name="wpide_url" value="<?php echo esc_attr( $user->user_url ); ?>" autocomplete="url"></p>
        <p><label for="wpide-description">About you</label><br><textarea id="wpide-description" name="wpide_description" rows="4"><?php echo esc_textarea( $user->description ); ?></textarea></p>
        <?php wp_nonce_field( 'wpide_edit_profile', 'wpide_profile_nonce' ); ?>
        <p><button type="submit">Save profile</button></p>
    </form>
    <?php
    return ob_get_clean();
} );
```

## Notes

Saving is protected by a nonce and only ever changes the logged-in user's own account. WordPress emails the old address when the email changes.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Front-End Profile Editing Form" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
