Disabling XML-RPC in WordPress is a common hardening step. xmlrpc.php is a favourite target for password guessing and for pingback abuse, where bots make your site send requests to other servers.
The usual one-liner, add_filter( 'xmlrpc_enabled', '__return_false' ), does less than its name suggests. It only refuses methods that need a login; pingback.ping, system.multicall and the other public methods keep answering. This snippet turns all of them off and stops advertising the endpoint.
The snippet
<?php
// Refuse every XML-RPC method that needs a login.
add_filter( 'xmlrpc_enabled', '__return_false' );
// Remove all remaining methods, including pingback.ping and system.multicall.
add_filter( 'xmlrpc_methods', 'dpc_disable_xmlrpc_methods', PHP_INT_MAX );
function dpc_disable_xmlrpc_methods( $methods ) {
return array();
}
// Stop advertising the endpoint in the X-Pingback response header.
add_filter( 'wp_headers', 'dpc_remove_x_pingback_header' );
function dpc_remove_x_pingback_header( $headers ) {
unset( $headers['X-Pingback'] );
return $headers;
}
Add it with Scripts Organizer
Scripts Organizer ships this snippet in its One-Click Import library. To add it by hand:
- In wp-admin go to Scripts Organizer → Code Blocks → Add New and give the block a title.
- Script location: PHP.
- Trigger location: Everywhere.
xmlrpc.phploads WordPress and its plugins like any other request, so Everywhere code is in place before the XML-RPC server reads its method list. Admin only would never run there. - Action hook: leave it empty. The code only registers filters and actions, so it can run while plugins load.
- Paste the snippet into the PHP editor, enable the block and publish it.
The same code also works unchanged in a small plugin or an mu-plugin file in wp-content/mu-plugins/.
How it works
xmlrpc_enabledreturningfalsemakes every authenticated method, such as publishing posts orwp.getUsersBlogs, return an error before the username and password are checked.xmlrpc_methodsruns when WordPress builds the XML-RPC server. Returning an empty array removes every method, so any call gets a “method not found” fault. The priorityPHP_INT_MAXmakes it run after plugins that add methods of their own.wp_headersfilters the HTTP headers WordPress sends with front-end pages. RemovingX-Pingbackstops telling scanners where the endpoint lives.
Customise it
Jetpack and some remote publishing tools still use XML-RPC. To keep the endpoint for them and only close the parts bots abuse, drop the xmlrpc_enabled and dpc_disable_xmlrpc_methods lines and remove just these methods:
add_filter( 'xmlrpc_methods', 'dpc_remove_pingback_methods' );
function dpc_remove_pingback_methods( $methods ) {
unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'], $methods['system.multicall'] );
return $methods;
}
Gotchas
xmlrpc.phpstill loads WordPress and answers, it just has nothing to offer. To stop those requests before PHP runs at all, block the file at the web server or CDN.- Classic themes may print
<link rel="pingback">themselves withbloginfo( 'pingback_url' )in header.php. Remove that line in a child theme if you want no trace left. - Also untick Allow link notifications from other blogs (pingbacks and trackbacks) on new posts in Settings → Discussion.
- For more hardening, see Lockdown Admin Backend to your IP and WordPress Security Updates Email Alert Without a Plugin.
In the Scripts Organizer library Import it with one click from Scripts Organizer.