WordPress privacy & user profiles

Stop sending every user's email to a third party just to show an avatar

Local Avatar lets every logged-in user, including roles with no media library access, upload their own profile picture stored directly on the site — replacing Gravatar everywhere an avatar appears, with an option to eliminate outbound requests to gravatar.com entirely.

  • Available to every role, even those without upload_files.
  • Replaces Gravatar site-wide, automatically, everywhere get_avatar() is used.
  • Optional fully local initials placeholder, zero external requests.
  • Keeps up to 8 previous uploads, selectable again without re-uploading.
Profile ScreenLocal Avatar

Profile Picture

A
Choose fileNo file chosen

JPG, PNG, GIF or WebP.

Disable Gravatar fallbackUsers without a local avatar get a locally-generated initials placeholder instead of a request to gravatar.com — no external calls at all.
No email hash sent to GravatarWorks for every role, even without media library access.
Active
Quick answer

What does Local Avatar do?

When the local_avatar module is active, TOWP_Local_Avatar adds a picture upload field to every user's own profile screen, available even to roles like Subscriber or Contributor that normally can't use the media library at all. The uploaded image gets stored as a regular attachment and picked up automatically everywhere WordPress or another module calls get_avatar(), via the pre_get_avatar_data filter, so nothing elsewhere in the site needs to change. With Gravatar's fallback disabled, anyone without a local avatar gets a deterministic, locally generated initials placeholder instead, an inline SVG with no file and no external request at all.

The "your email just left the building" problem

Every avatar on the site quietly phones Gravatar

Since Gravatar is WordPress's default avatar source, most sites send this request without anyone deciding that was the right tradeoff.

An email hash goes out on every page that shows a face

By default, WordPress sends a hash of a user's email address to Gravatar's servers on every single page that displays an avatar, whether that user ever signed up there or not.

Most people never signed up, so they just get a generic icon anyway

The request still goes out even for someone who never created a Gravatar account, and all that's shown in return is a default placeholder, not an actual picture.

A dedicated WordPress solution

A real face, stored where the site already is

The module replaces the external lookup with a picture stored locally, available to every role and picked up automatically wherever an avatar already appears.

Available to every role

Even a Subscriber or Contributor, roles with no access to the media library otherwise, can upload their own picture from their profile screen.

Replaces Gravatar everywhere automatically

Every existing call to get_avatar() across WordPress core and other modules picks up the local picture without any code changes elsewhere.

An option to stop the external request entirely

With Gravatar's fallback disabled, anyone without a local picture gets a locally generated placeholder instead, no request to gravatar.com at all.

Verified feature set

Local by default, verified at every step

Every capability below is present in the supplied PHP class and its settings registration.

Works without upload_files

A deliberate carve-out for every role

The profile upload field works for any logged-in user, including roles that can't otherwise upload anything to the media library at all.

Any logged-in roleBypasses upload_files requirement
A history of up to 8 previous pictures

Switch back without re-uploading

Past uploads stay selectable from a gallery on the profile screen, with the oldest surplus automatically pruned once the limit is reached.

MAX_HISTORYAuto-pruned gallery
A fully local initials placeholder

An inline SVG, no file, no request

When Gravatar's fallback is disabled, a deterministic colored-initial SVG gets generated as a data URI, the same person always getting the same color.

Inline SVG data URIDeterministic per person
Ownership verified before every action

Selecting or deleting checks who actually uploaded it

A dedicated ownership meta field gets checked before any history item can be selected or deleted, protecting against a tampered request.

Ownership meta checkPer-action verification
Defense-in-depth file validation

Extension, MIME and actual image content, all checked

An uploaded file is restricted by extension and MIME type, then independently confirmed to be a genuinely readable image before it's ever registered.

MIME allowlistgetimagesize() verification
Practical use cases

Where local avatars help most

The module supports any site that would rather not depend on an external avatar service.

Privacy-conscious sites that don't want emails leaving the server

Stop sending a hash of every user's email address to a third party just to render an avatar.

Membership or community sites where every role should look real

Let subscribers, members and contributors add a real picture, not just staff-level roles with media access.

Comment sections and chat features that already call get_avatar()

Get consistent, local avatars in every existing avatar-driven feature without touching that feature's own code.

Operational benefits

Less exposure, more presence

The module combines a genuine privacy improvement with a more personal-feeling profile for every role.

No email address handed to a third partyA locally stored picture means nothing about a user's email gets sent anywhere just to display their avatar.
One less external request per avatar shownWith Gravatar's fallback disabled, rendering an avatar never triggers an outbound request at all.
Every role gets a real profile pictureThe upload field works regardless of whether a role can normally touch the media library.
Zero integration work for existing avatar featuresAnything already calling get_avatar() picks up the change automatically, with nothing to update in that feature itself.
Performance behaviour

One lookup, or nothing at all

The verified implementation stays lightweight whether a picture exists or not.

One filter check per avatar request

Resolving the picture is a single user-meta lookup and an attachment check, no heavier than any other avatar-rendering logic.

No file, no request for the placeholder option

The initials placeholder is generated inline as a data URI; there's no image file to store and no network request to make.

History capped, so it never grows unbounded

The 8-item history limit keeps the number of stored avatar attachments per user under control automatically.

Security implementation

Verified, owned, and logged

The code validates every upload thoroughly and checks ownership before every action.

01

File type restricted, then independently verified

An upload gets checked against an explicit MIME allowlist, then confirmed with getimagesize() to catch a disguised file that slipped past the extension check.

02

Every action requires editing that specific user

Both uploading and managing history require current_user_can('edit_user', $user_id), the same check whether it's a user editing their own profile or an admin editing someone else's.

03

Ownership checked before every select or delete

A hidden field tampered with client-side can't be used to select or delete another user's avatar history, since ownership gets verified server-side first.

04

Every action logged

Uploads, selections, removals, deletions and even failures get recorded through the audit log.

Verified compatibility

Built directly around WordPress's own avatar and upload APIs

The supplied code integrates through APIs present in WordPress core; this page makes no compatibility claim beyond the verified implementation.

Site-wide avatar filter

pre_get_avatar_data

The native WordPress filter used to intercept and override avatar resolution before WordPress falls back to Gravatar.

pre_get_avatar_dataNative avatar filter
Standard upload handling

wp_handle_upload() and wp_insert_attachment()

The same core functions WordPress itself uses for any file upload, applied here to a user's own profile picture.

wp_handle_uploadwp_insert_attachment
Form encoding fix

user_edit_form_tag

The native hook used to add multipart form encoding to the profile screen, which doesn't have it by default since WordPress never expected a file upload there.

user_edit_form_tagmultipart/form-data
Solution comparison

TheOneWP versus common alternatives

Compare the verified Local Avatar implementation with a typical media-library-only upload approach.

CapabilityTheOneWP Local AvatarOther common solutions
Who can upload a picture Every logged-in role, media library access or notOften limited to roles that already have upload_files
Replacing Gravatar everywhere One filter, automatic for every existing avatar callSome approaches require updating each avatar-displaying feature individually
Eliminating external requests entirely A fully local, deterministic placeholder optionFrequently still falls back to Gravatar for anyone without a picture
File validation MIME allowlist plus independent image-content verificationSome approaches trust the file extension alone
Avatar history Up to 8 previous pictures, selectable againUsually only the single current picture is kept
Recommended workflow

Add local avatars in four steps

Decide on the Gravatar fallback setting first, since it shapes what everyone without a picture sees.

01

Enable Local Avatar

Activate the module from the TheOneWP Backend settings tab.

02

Decide whether to disable the Gravatar fallback

Turn it off if the goal is eliminating outbound requests entirely, or leave it on to keep Gravatar as a fallback for users without a local picture.

03

Upload a picture from the profile screen

Visit any user's profile screen and use the Profile Picture field to choose an image.

04

Confirm it appears wherever avatars are shown

Check comments, chat, or any other avatar-driven feature to confirm the picture appears automatically.

Best practices

Decide the privacy stance deliberately

The Gravatar fallback setting is the single decision that shapes the module's overall privacy impact.

01

Disable the Gravatar fallback for the strongest privacy stance

Turning it off removes every remaining outbound request, not just the ones for users who already uploaded a picture.

02

Encourage uploads for roles that interact with visitors

A real picture next to a name adds recognition value for any role customers or members regularly see, like support staff or moderators.

03

Let the history gallery handle picture changes

Switching back to a previous picture through the gallery avoids uploading the same file again.

04

Review the audit log after a bulk profile update

Since every avatar action gets logged, the audit log is the fastest way to confirm what changed across many accounts.

Common mistakes

Avoid a couple of details that are easy to misread

A few behaviors are easy to assume incorrectly the first time through.

Assuming Remove deletes the picture entirely

Removing the current avatar only clears which picture is active; the file itself stays in the history gallery for later reuse.

Expecting the placeholder without disabling the Gravatar fallback

The locally generated initials placeholder only replaces Gravatar when the fallback is explicitly turned off; otherwise Gravatar remains the fallback.

Forgetting this also affects guest commenters

Since avatar resolution covers WP_Comment data too, a placeholder for an unregistered commenter is based on their email or name, not just registered users.

Frequently asked questions

Local Avatar FAQ

These answers come directly from the verified class and its settings registration.

What does Local Avatar do?

It lets every logged-in user upload their own profile picture, stored on the site and shown automatically everywhere an avatar normally appears.

Can a role without media library access use this?

Yes. The upload field works for any logged-in user, including roles that can't otherwise upload to the media library.

Does this replace Gravatar automatically everywhere?

Yes. A single filter intercepts every existing avatar call, so nothing elsewhere needs to change.

What happens to users who haven't uploaded a picture?

They fall back to Gravatar by default, or to a locally generated initials placeholder if the Gravatar fallback has been disabled.

Does the initials placeholder make any external request?

No. It's generated inline as an SVG data URI, with no file and no network request involved.

Can I switch back to a previously uploaded picture?

Yes. Up to 8 previous uploads stay selectable from a history gallery on the profile screen.

What happens when I remove my current avatar?

Only the active pointer gets cleared; the picture itself stays in the history gallery in case it's wanted again later.

Is an uploaded file actually verified as a real image?

Yes. Beyond the file type check, the upload is independently confirmed to be a genuinely readable image before it's stored.

Can I delete a picture that belongs to another user?

No. Ownership gets verified before any selection or deletion, so only a user's own uploads can be managed this way.

Who can enable this module and its Gravatar setting?

Only an administrator with access to the TheOneWP settings screen.

Stop sending user emails to a third party for a picture.Store avatars locally, for every role.

Use Local Avatar to let every user upload a real profile picture, replacing Gravatar automatically everywhere, with the option to eliminate outbound requests entirely.