wppaste
WordPress

do_action( 'xmlrpc_call', string $name, array|string $args, wp_xmlrpc_server $server )

Since
2.5.0, 5.7.0

Fires for every authenticated XML-RPC request, exposing the method name, its escaped arguments, and the server instance for inspection or blocking. The $server parameter was only added in 5.7.0, so callbacks written for older sites may register with just two accepted arguments. Because it's an action, returning a value from a callback does nothing; stopping a method requires calling die() or triggering an IXR error inside the callback. Pair it with xmlrpc_enabled if the goal is to turn XML-RPC off entirely rather than police individual methods.

Fires after the XML-RPC user has been authenticated but before the rest of the method logic begins.

Description

All built-in XML-RPC methods use the action xmlrpc_call, with a parameter equal to the method's name, e.g., wp.getUsersBlogs, wp.newPost, etc.

Compatibility

WordPress
since 5.7.0
  • 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).

Parameters

$namestring
The method name.
$argsarray|string
The escaped arguments passed to the method.
$serverwp_xmlrpc_server
The XML-RPC server instance.

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.

Log which XML-RPC method name triggered a request

Register a callback and then simulate an authenticated XML-RPC call so the hook fires and prints its arguments.

add_action( 'xmlrpc_call', 'wppaste_log_xmlrpc_method', 10, 3 );

function wppaste_log_xmlrpc_method( $name, $args, $server ) {
	printf(
		'Method called: %s using a %s server instance.',
		esc_html( $name ),
		esc_html( get_class( $server ) )
	);
}

require_once ABSPATH . WPINC . '/class-wp-xmlrpc-server.php';
$server = new wp_xmlrpc_server();

do_action( 'xmlrpc_call', 'wp.getUsersBlogs', array(), $server );

This calls do_action() directly to demonstrate the hook, since the browser sandbox never actually posts to xmlrpc.php; in production the same callback fires on real requests without this manual trigger.

Block a specific XML-RPC method such as pingback.ping

Check the method name inside the callback and short-circuit the ones you want to refuse, a common way to stop pingback abuse.

add_action( 'xmlrpc_call', 'wppaste_block_pingback', 10, 1 );

function wppaste_block_pingback( $name ) {
	if ( 'pingback.ping' === $name ) {
		echo esc_html( "Blocked XML-RPC method: {$name}" ) . '<br>';
		return;
	}

	echo esc_html( "Allowed XML-RPC method: {$name}" ) . '<br>';
}

require_once ABSPATH . WPINC . '/class-wp-xmlrpc-server.php';
$server = new wp_xmlrpc_server();

do_action( 'xmlrpc_call', 'pingback.ping', array(), $server );
do_action( 'xmlrpc_call', 'wp.getUsersBlogs', array(), $server );

In a live plugin you would normally call wp_die() or throw an IXR_Error after the echo so the offending method never actually runs.

Common problems and fixes · 4

Why doesn't my xmlrpc_call callback ever run on a live site?

The hook only fires from inside wp_xmlrpc_server after authentication succeeds, so it never runs if XML-RPC is disabled, the request never reaches xmlrpc.php, or the credentials fail before the action point. - Confirm XML-RPC isn't turned off by a security plugin or the xmlrpc_enabled filter. - Test with a real XML-RPC client hitting /xmlrpc.php, not a normal page load. - Make sure the request actually authenticates first; unauthenticated calls never reach this action.

Why does my callback only receive two arguments instead of three?

The $server parameter was added in 5.7.0. A callback registered with add_action() and an accepted_args value of 2 (or the default of 1) simply won't be passed $server, even though the action itself provides it.

Why is $args sometimes an array and sometimes a string?

The docs list $args as array|string because its shape depends on the XML-RPC method being called; some methods take a single scalar parameter, others take a list. It also arrives already escaped by the server before this action fires. - Use is_array( $args ) before looping over it. - Don't run wp_slash() or similar on $args again, it's already escaped.

Can I stop the XML-RPC method from running by returning false from this hook?

No. xmlrpc_call is an action, not a filter, so any return value from the callback is discarded and the requested method's logic still runs afterward. To actually block a call you have to terminate execution yourself inside the callback, for example with die() or by triggering an IXR_Error through the $server instance.

Alternatives and related functions

xmlrpc_enabled
When the goal is to disable XML-RPC entirely rather than inspect or block one method at a time.
xmlrpc_methods
When you need to add or remove entire method names from the XML-RPC method table before any request is handled.
wp_xmlrpc_server_class
When you need to swap in a custom server class instead of reacting to individual method calls.
xmlrpc_pingback_error
When the concern is specifically pingback error responses rather than general method auditing.

Where this hook fires · 67

  • wp-includes/class-wp-xmlrpc-server.php:744wp_xmlrpc_server::wp_getUsersBlogs()
  • wp-includes/class-wp-xmlrpc-server.php:1358wp_xmlrpc_server::wp_newPost()
  • wp-includes/class-wp-xmlrpc-server.php:1759wp_xmlrpc_server::wp_editPost()
  • wp-includes/class-wp-xmlrpc-server.php:1842wp_xmlrpc_server::wp_deletePost()
  • wp-includes/class-wp-xmlrpc-server.php:1943wp_xmlrpc_server::wp_getPost()
  • wp-includes/class-wp-xmlrpc-server.php:2004wp_xmlrpc_server::wp_getPosts()
  • wp-includes/class-wp-xmlrpc-server.php:2103wp_xmlrpc_server::wp_newTerm()
  • wp-includes/class-wp-xmlrpc-server.php:2208wp_xmlrpc_server::wp_editTerm()
  • wp-includes/class-wp-xmlrpc-server.php:2324wp_xmlrpc_server::wp_deleteTerm()
  • wp-includes/class-wp-xmlrpc-server.php:2403wp_xmlrpc_server::wp_getTerm()
  • wp-includes/class-wp-xmlrpc-server.php:2468wp_xmlrpc_server::wp_getTerms()
  • wp-includes/class-wp-xmlrpc-server.php:2575wp_xmlrpc_server::wp_getTaxonomy()
  • wp-includes/class-wp-xmlrpc-server.php:2633wp_xmlrpc_server::wp_getTaxonomies()
  • wp-includes/class-wp-xmlrpc-server.php:2719wp_xmlrpc_server::wp_getUser()
  • wp-includes/class-wp-xmlrpc-server.php:2782wp_xmlrpc_server::wp_getUsers()
  • wp-includes/class-wp-xmlrpc-server.php:2862wp_xmlrpc_server::wp_getProfile()
  • wp-includes/class-wp-xmlrpc-server.php:2912wp_xmlrpc_server::wp_editProfile()
  • wp-includes/class-wp-xmlrpc-server.php:3001wp_xmlrpc_server::wp_getPage()
  • wp-includes/class-wp-xmlrpc-server.php:3044wp_xmlrpc_server::wp_getPages()
  • wp-includes/class-wp-xmlrpc-server.php:3099wp_xmlrpc_server::wp_newPage()
  • wp-includes/class-wp-xmlrpc-server.php:3136wp_xmlrpc_server::wp_deletePage()
  • wp-includes/class-wp-xmlrpc-server.php:3205wp_xmlrpc_server::wp_editPage()
  • wp-includes/class-wp-xmlrpc-server.php:3268wp_xmlrpc_server::wp_getPageList()
  • wp-includes/class-wp-xmlrpc-server.php:3329wp_xmlrpc_server::wp_getAuthors()
  • wp-includes/class-wp-xmlrpc-server.php:3373wp_xmlrpc_server::wp_getTags()
  • wp-includes/class-wp-xmlrpc-server.php:3423wp_xmlrpc_server::wp_newCategory()
  • wp-includes/class-wp-xmlrpc-server.php:3510wp_xmlrpc_server::wp_deleteCategory()
  • wp-includes/class-wp-xmlrpc-server.php:3567wp_xmlrpc_server::wp_suggestCategories()
  • wp-includes/class-wp-xmlrpc-server.php:3613wp_xmlrpc_server::wp_getComment()
  • wp-includes/class-wp-xmlrpc-server.php:3669wp_xmlrpc_server::wp_getComments()

… and 37 more locations

Source code

		 * @since 5.7.0 Added the `$args` and `$server` parameters.		 *		 * @param string           $name   The method name.		 * @param array|string     $args   The escaped arguments passed to the method.		 * @param wp_xmlrpc_server $server The XML-RPC server instance.		 */		do_action( 'xmlrpc_call', 'wp.getUsersBlogs', $args, $this ); 		$blogs  = (array) get_blogs_of_user( $user->ID );		$struct = array(); 		$primary_blog_id = 0;		$active_blog     = get_active_blog_for_user( $user->ID );

Changelog

Introduced in 2.5.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.

5.7.0
Added the $args and $server parameters.from the docblock
2.5.0
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 6.9.7 tag, 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.