wppaste
WordPress

wp_xmlrpc_server::login( string $username, string $password ): WP_User|false

Since
2.8.0
Source
wp-includes/class-wp-xmlrpc-server.php:295

Authenticates a username and password pair the way the XML-RPC endpoint does, then sets the current user on success. Returns a WP_User object on success or false on failure, and caches a failed attempt on the wp_xmlrpc_server instance so later calls in the same request skip re-checking credentials. It underlies nearly every other wp_xmlrpc_server method (blogger_*, mt_*, mw_*) rather than being called directly by typical plugin code.

Logs user in.

Compatibility

WordPress
since 2.8.0
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$usernamestring
User's username.
$passwordstring
User's password.

Return value

WP_User|false
WP_User object if authentication passed, false otherwise.

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Authenticate a username and password pair the way XML-RPC does

Create a wp_xmlrpc_server instance and reuse the same credential check the XML-RPC endpoint runs internally.

require_once ABSPATH . WPINC . '/class-wp-xmlrpc-server.php';

$server = new wp_xmlrpc_server();
$user   = $server->login( 'xmlrpc_tester', 'CorrectHorse123!' );

if ( $user instanceof WP_User ) {
	printf( 'Authenticated as %s (user ID %d).', esc_html( $user->display_name ), $user->ID );
} else {
	echo esc_html( 'Login failed.' );
}

wp_set_current_user() runs inside login() on success, so the current user is switched for the rest of the request.

Customize the XML-RPC login error message with the xmlrpc_login_error filter

Rewrite the error object login() produces on a failed attempt before it reaches the XML-RPC client.

require_once ABSPATH . WPINC . '/class-wp-xmlrpc-server.php';

add_filter( 'xmlrpc_login_error', function( $error, $user_error ) {
	return new IXR_Error( 403, 'Access denied: check your XML-RPC credentials.' );
}, 10, 2 );

$server = new wp_xmlrpc_server();
$result = $server->login( 'nobody', 'not-a-real-password' );

if ( false === $result ) {
	printf( 'Login rejected: %s', esc_html( $server->error->message ) );
}

Common problems and fixes · 4

Why does login() keep failing even though the second password I try is correct?

The first failed call sets $this->auth_failed to true on that wp_xmlrpc_server instance. Every later call to login() checks that flag before wp_authenticate() ever runs, so it returns a WP_Error('login_prevented') and false no matter what credentials come next.

How do I read the actual error message when login() returns false?

login() only returns false or a WP_User object; the human-readable message is stored on $this->error as an IXR_Error, not in the return value.

Why does login() fail immediately even with valid credentials?

If $this->is_enabled is false, login() short-circuits with a 405 IXR_Error before it ever calls wp_authenticate(). That flag reflects whether XML-RPC is enabled for the site.

Does login() log a visitor in the same way a front-end login form does?

No. Source only calls wp_set_current_user( $user->ID ), it never sets an auth cookie, so the effect lasts only for the current PHP execution, not across page loads in a browser.

Alternatives and related functions

wp_authenticate
When you need to check a username and password without any of the XML-RPC-specific IXR_Error wrapping or the auth_failed caching.
wp_signon
When a successful login should also set an auth cookie so the user stays signed in across page loads in a browser.
wp_set_current_user
When you already have a trusted WP_User object or ID and just need to switch the current user without re-checking credentials.
wp_xmlrpc_server::login_pass_ok
When another XML-RPC server method just needs a simple pass or fail check rather than the full WP_User object login() returns.

Performance profile

How much work a call to wp_xmlrpc_server::login() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Trivial

Touches nothing outside its own arguments.

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
14–36

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 57.

Plugin surface
1 hook

Third-party callbacks on 'xmlrpc_login_error' run inside this call, and their cost is not bounded by anything here.

Called by
50

50 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • hookthird-party callbacksapply_filters()called directly

Further down the call graph this can also reach query, option, cache, serialize and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 5 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost wp_xmlrpc_server::login() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
always14__()
!is_wp_error()21is_wp_error(), wp_set_current_user()
!is_wp_error()21wp_authenticate(), is_wp_error(), wp_set_current_user()
is_wp_error()36is_wp_error(), __(), apply_filters()
is_wp_error()36wp_authenticate(), is_wp_error(), __(), apply_filters()

Across PHP versions

Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 57 instructions, 14–36 executed per call, 3 branches. The work does not change between versions.

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Hooks and filters fired · 1

One hook fires while wp_xmlrpc_server::login() runs, in this order:

  1. apply_filters( xmlrpc_login_error )filterline 325 (+30 into the body)

    Filters the XML-RPC user login error message.

Uses · 7

Used by · 50

Show all 50

Source code

	public function login(		$username,		#[\SensitiveParameter]		$password	) {		if ( ! $this->is_enabled ) {			$this->error = new IXR_Error( 405, __( 'XML-RPC services are disabled on this site.' ) );			return false;		} 		if ( $this->auth_failed ) {			$user = new WP_Error( 'login_prevented' );		} else {			$user = wp_authenticate( $username, $password );		} 		if ( is_wp_error( $user ) ) {			$this->error = new IXR_Error( 403, __( 'Incorrect username or password.' ) ); 			// Flag that authentication has failed once on this wp_xmlrpc_server instance.			$this->auth_failed = true; 			/**			 * Filters the XML-RPC user login error message.			 *			 * @since 3.5.0			 *			 * @param IXR_Error $error The XML-RPC error message.			 * @param WP_Error  $user  WP_Error object.			 */			$this->error = apply_filters( 'xmlrpc_login_error', $this->error, $user );			return false;		} 		wp_set_current_user( $user->ID );		return $user;	}

Changelog

Introduced in 2.8.0. Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

About this page

Parsed data
Generated from the wordpress-develop 7.1.0 tag, from src/wp-includes/class-wp-xmlrpc-server.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.