Ropeline Check my site

How to hide your WordPress username (and stop user enumeration)

A guide for site owners. Updated October 13, 2026.

A login is two halves: a username and a password. On most WordPress sites, anyone can read the first half. Bots collect it automatically (that's called user enumeration), then spend every guess on the password alone.

Hiding usernames isn't a fix on its own: a strong password and a login limit matter more. But it takes away half the work, and a bot that has to guess the username too wastes its tries on names like admin.

The five places WordPress shows usernames

  1. The REST API user list. /wp-json/wp/v2/users lists everyone who has published a post. Each entry has a slug, and unless someone changed it, the slug is the login name (lowercased, with spaces and dots turned into dashes).
  2. Author pages. /?author=1 redirects to /author/slug/. Bots count up from 1 to collect every author.
  3. The users sitemap. Since WordPress 5.5, /wp-sitemap-users-1.xml links to every author page, slug and all.
  4. Embeds. WordPress's oEmbed answer for a post (/wp-json/oembed/1.0/embed?url=…) includes the author's name and a link to their author page.
  5. Login and lost-password messages. The login form says "The username x is not registered" or "The password you entered for the username x is incorrect", and the lost-password form says when there's no such account. Either one confirms a guess.

Is yours public? Check in 10 seconds

Open https://yoursite.com/wp-json/wp/v2/users and https://yoursite.com/?author=1 in a browser. If you see a list with "slug" in it, or land on /author/something/, they're public. Or run the free store check: it counts the usernames anyone can read (it never shows or keeps them) and looks for the other doors bots use.

How to close each one

1. Change the slug, not just the display name

Setting Display name publicly as on your profile changes the name on posts, but not the slug in the REST API, author pages and the sitemap. WordPress has no screen for the slug. With WP-CLI:

wp user update 1 --user_nicename=store-team

That alone stops the slug from giving away your login name, even where it's still shown. Old links to /author/old-slug/ will stop working.

2. Close the REST API user list to logged-out visitors

In a small plugin or your theme's functions.php. Logged-in users keep it, so the block editor still works:

add_filter( 'rest_endpoints', function ( $endpoints ) {
	if ( ! is_user_logged_in() ) {
		unset( $endpoints['/wp/v2/users'], $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
	}
	return $endpoints;
} );

3. Stop ?author= scans and the users sitemap

add_action( 'template_redirect', function () {
	if ( isset( $_GET['author'] ) && ! is_user_logged_in() ) {
		wp_safe_redirect( home_url( '/' ), 301 );
		exit;
	}
}, 1 );

add_filter( 'wp_sitemaps_add_provider', function ( $provider, $name ) {
	return 'users' === $name ? false : $provider;
}, 10, 2 );

4. Take the author out of embeds

add_filter( 'oembed_response_data', function ( $data ) {
	unset( $data['author_name'], $data['author_url'] );
	return $data;
} );

5. Give every failed login the same message

The simplest version replaces the message on WordPress's own login page:

add_filter( 'login_errors', function () {
	return 'The username or password you entered is incorrect.';
} );

WooCommerce's My Account login passes its message through the same filter. The lost-password form doesn't: closing it takes more code, because a reset for an account that doesn't exist has to get the same "check your email" answer as a real one.

Or: one setting

Ropeline Pro's Hide usernames from bots setting closes all five for logged-out visitors, WooCommerce's login and lost-password forms included, and logs the author scans and user-list requests it turns away. Logged-in users and the block editor keep working.

Start with the free check. See what bots can read on your site, then fix it in a few minutes. Ropeline Pro is free for 14 days.

Check my site free See Ropeline Pro