Manage your avatar in WordPress

An update of this tutorial showing a code snippet to choose between using a Gravatar or a custom avatar.

/**
 * Two-Image Avatar Selection (Gravatar + Custom Avatar)
 * Fully featured: highlight, hover, recommended size, cropping preview, accessibility
 */

// Enqueue WordPress media scripts
add_action('admin_enqueue_scripts', function() {
    wp_enqueue_media();
});

// Custom CSS for avatar selection, highlight, hover, and accessibility
add_action('admin_head-user-edit.php', 'avatar_selection_styles');
add_action('admin_head-profile.php', 'avatar_selection_styles');
function avatar_selection_styles() {
    echo '<style>
        /* Hide default profile image and description */
        tr.user-profile-picture td img.avatar,
        tr.user-profile-picture td p.description { display: none !important; }

        /* Avatar images styling */
        .avatar-choice-container img { 
            width: 96px; 
            height: 96px; 
            object-fit: cover; 
            display: block; 
            margin: 0 auto 8px auto; 
            border: 1px solid #ccc; 
            transition: border 0.2s, box-shadow 0.2s;
            cursor: pointer;
        }

        /* Highlight selected avatar */
        .avatar-choice-container.selected img {
            border: 2px solid #0073aa;
            box-shadow: 0 0 4px rgba(0,115,170,0.6);
        }

        /* Hover effect on selectable avatars */
        .avatar-choice-container img:hover {
            border-color: #0073aa;
            box-shadow: 0 0 4px rgba(0,115,170,0.4);
        }

        /* Center radio labels */
        .avatar-choice-container label { 
            text-align: center; 
            display: block; 
        }

        /* Recommended size note */
        .avatar-size-note {
            font-size: 12px;
            color: #555;
            margin-top: 4px;
            text-align: center;
        }

        /* Optional overlay for non-square images */
        .avatar-choice-container img.unsquare::after {
            content: "Cropped to fit";
            font-size: 10px;
            color: #555;
            position: absolute;
            bottom: 2px;
            right: 2px;
            background: rgba(255,255,255,0.7);
            padding: 1px 3px;
            border-radius: 2px;
        }
    </style>';
}

// Add the avatar selection UI
add_action('show_user_profile', 'two_avatar_selection');
add_action('edit_user_profile', 'two_avatar_selection');
function two_avatar_selection($user) {
    $custom_id  = get_user_meta($user->ID, 'custom_avatar', true);
    $custom_url = $custom_id ? wp_get_attachment_url($custom_id) : '';
    $gravatar   = get_avatar_url($user->user_email, ['size' => 96]);
    $use_custom = get_user_meta($user->ID, 'use_custom_avatar', true) === 'custom' ? 'custom' : 'gravatar';
    ?>
    <script>
    jQuery(document).ready(function($){
        const gravatarUrl = '<?php echo esc_js($gravatar); ?>';
        const customUrl   = '<?php echo esc_js($custom_url); ?>';
        const useCustom   = '<?php echo esc_js($use_custom); ?>';
        const customId    = '<?php echo esc_js($custom_id); ?>';

        const $row = $('tr.user-profile-picture');
        if (!$row.length) return;

        $row.find('td').empty();

        const avatarUI = `
            <div style="display:flex;gap:60px;align-items:flex-start;flex-wrap:wrap;margin-top:10px;">
                <!-- Gravatar choice -->
                <div class="avatar-choice-container">
                    <img src="${gravatarUrl}" alt="Gravatar">
                    <label>
                        <input type="radio" name="avatar_choice" value="gravatar" ${useCustom === 'gravatar' ? 'checked' : ''} aria-checked="${useCustom === 'gravatar' ? 'true' : 'false'}">
                        Use Gravatar
                    </label>
                    <div class="avatar-size-note">Recommended: 96×96px</div>
                </div>
                <!-- Custom avatar choice -->
                <div class="avatar-choice-container">
                    <img src="${customUrl || gravatarUrl}" alt="Custom Avatar" style="${customUrl ? '' : 'opacity:0.4;'}">
                    <label>
                        <input type="radio" name="avatar_choice" value="custom" ${useCustom === 'custom' ? 'checked' : ''} aria-checked="${useCustom === 'custom' ? 'true' : 'false'}">
                        Use Custom Avatar
                    </label>
                    <input type="hidden" name="custom_avatar" id="custom_avatar" value="${customId}">
                    <button type="button" class="button upload-avatar-button" style="margin-top:8px;">Select / Upload Avatar</button>
                    <div class="avatar-size-note">Recommended: 96×96px</div>
                </div>
            </div>
            <p class="description" style="margin-top:10px;">Choose your preferred avatar or upload your own image.</p>
        `;
        $row.find('td').append(avatarUI);

        // Media uploader
        let mediaUploader;
        $(document).on('click', '.upload-avatar-button', function(e){
            e.preventDefault();
            if (mediaUploader) { mediaUploader.open(); return; }

            mediaUploader = wp.media({
                title: 'Select Custom Avatar',
                button: { text: 'Use this image' },
                multiple: false
            });

            mediaUploader.on('select', function(){
                const attachment = mediaUploader.state().get('selection').first().toJSON();
                $('#custom_avatar').val(attachment.id);

                const imgTag = `<img src="${attachment.url}" alt="Custom Avatar" style="width:96px;height:96px;object-fit:cover;display:block;margin:0 auto 8px auto;border:1px solid #ccc;">`;
                $('input[value="custom"]').closest('.avatar-choice-container').find('img').replaceWith(imgTag);
            });

            mediaUploader.open();
        });

        // Highlight selected avatar and update aria-checked
        $('input[name="avatar_choice"]').on('change', function(){
            $('.avatar-choice-container').removeClass('selected');
            $(this).closest('.avatar-choice-container').addClass('selected');
            $('input[name="avatar_choice"]').attr('aria-checked', 'false');
            $(this).attr('aria-checked', 'true');
        });

        // Initialize highlight on page load
        $('input[name="avatar_choice"]:checked').closest('.avatar-choice-container').addClass('selected');
    });
    </script>
<?php
}

// Save avatar selection
add_action('personal_options_update', 'save_two_avatar_choice');
add_action('edit_user_profile_update', 'save_two_avatar_choice');
function save_two_avatar_choice($user_id) {
    if (!current_user_can('edit_user', $user_id)) return false;

    if (isset($_POST['custom_avatar'])) {
        update_user_meta($user_id, 'custom_avatar', intval($_POST['custom_avatar']));
    }

    if (isset($_POST['avatar_choice'])) {
        $choice = ($_POST['avatar_choice'] === 'custom') ? 'custom' : 'gravatar';
        update_user_meta($user_id, 'use_custom_avatar', $choice);
    }
}

// Override avatars on frontend and Users screen
add_filter('get_avatar', function($avatar, $id_or_email, $size, $default, $alt){
    $user = false;

    if (is_numeric($id_or_email)) {
        $user = get_user_by('id', $id_or_email);
    } elseif (is_object($id_or_email) && !empty($id_or_email->user_id)) {
        $user = get_user_by('id', $id_or_email->user_id);
    } else {
        $user = get_user_by('email', $id_or_email);
    }

    if ($user) {
        $choice = get_user_meta($user->ID, 'use_custom_avatar', true);
        if ($choice === 'custom') {
            $avatar_id = get_user_meta($user->ID, 'custom_avatar', true);
            $avatar_url = $avatar_id ? wp_get_attachment_image_url($avatar_id, [$size, $size]) : '';
            if ($avatar_url) {
                return sprintf(
                    '<img alt="%s" src="%s" class="avatar avatar-%d photo" height="%d" width="%d" />',
                    esc_attr($alt),
                    esc_url($avatar_url),
                    intval($size),
                    intval($size),
                    intval($size)
                );
            }
        }
    }

    return $avatar;
}, 10, 5);

Managing your avatar profile image in WordPress.

The default for managing your avatar in WordPress is using a gravatar. This means you need to sign up at gravatar.com and add some avatar images to your new account. The e-mail address you at gravatar.com and for your WordPress sites will link the avatar image from gravatar.com to your sites.

The process is a bit cumbersome for users that just need to make some posts on occasion or need to be a part of a site. So various plugins are created to fix this cap.

An example from WP user Avatars.

WP User Avatars WordPress plugin
WP User Avatars WordPress plugin.

https://wordpress.org/plugins/wp-user-avatars/

https://wordpress.org/plugins/wp-user-avatar/

https://wordpress.org/plugins/metronet-profile-picture/

https://wordpress.org/plugins/bp-local-avatars/

https://wordpress.org/plugins/simple-local-avatars/

It is being worked on adding an avatar feature into WordPress so the user can upload and use their own image without having to sign up at gravatar.com.
https://core.trac.wordpress.org/ticket/16020

Resources:

https://www.billerickson.net/wordpress-custom-avatar/

Share the article:

Leave a Reply

Your email address will not be published. Required fields are marked *