XML-RPC & WP-API

If you’ve ever looked at the logs from a WordPress site, then you know that one of the most target requests is the xmlrpc.php file. XML-RPC is kind a relic before the JSON WP-API days. WordPress used to use it for pingbacks, trackbacks, RSD, JetPack and the mobile application. Pingbacks and trackbacks are something I support in theory, but they’ve been generally abused. Perhaps the API will come up with a mechanism in which to prevent this type of abuse. I prefer to block it server side but I didn’t want to lock users into having it disabled so I created a couple settings to handle it.

I’ve set options in the theme settings which call the following functions to disable xml-rpc, remove the wp-api headers and require authentication to access the api. The four settings in the options table are: [ dwp23_theme_comments, dwp23_theme_xmlrpc, dwp23_theme_api, dwp23_theme_api_auth ].

/inc/theme-settings.php
add_action( 'after_setup_theme', 'dwp23_disable_comments' );
function dwp23_disable_comments() {
  $comments = get_option('dwp23_theme_comments');
  if( $comments == '1' ) {
    add_action('admin_menu', function () {
      remove_menu_page('edit-comments.php');
      remove_submenu_page( 'options-general.php', 'options-discussion.php' );
      remove_meta_box('dashboard_recent_comments', 'dashboard', 'normal');
    });
    add_filter('comments_array', '__return_empty_array', 10, 2);
    add_filter('comments_open', '__return_false', 20, 2);
    add_filter('pings_open', '__return_false', 20, 2);
    remove_post_type_support( 'post', 'comments' );
    remove_post_type_support( 'page', 'comments' );
    unregister_widget( 'WP_Widget_Recent_Comments' );
    add_action( 'wp_dashboard_setup', function() {
      remove_meta_box('dashboard_recent_comments', 'dashboard', 'normal');
    });
    add_action( 'admin_head-index.php', function() {
      print '<style>#latest-comments{ display:none; }</style>';
    });
    add_action( 'enqueue_block_editor_assets', function() {
    	wp_enqueue_script( 'dwp-editor-options',
      get_stylesheet_directory_uri() . '/js/editor-comment-option.js',
      array( 'wp-blocks', 'wp-dom' ),
      filemtime( get_stylesheet_directory() . '/js/editor-comment-option.js' ), true );
    });
    global $pagenow;
    if ($pagenow === 'edit-comments.php') {
      wp_redirect(admin_url());
      exit;
    }
  }
}

add_action( 'after_setup_theme', 'dwp23_disable_xmlrpc' );
function dwp23_disable_xmlrpc() {
  $xmlrpc = get_option('dwp23_theme_xmlrpc');
  if( $xmlrpc == '1' ) {
    remove_action('wp_head', 'rsd_link');
    add_filter( 'xmlrpc_enabled', '__return_false' );
    add_filter( 'wp_headers', function($headers) {
      unset( $headers['X-Pingback'] );
      return $headers;
    });
  }
}

add_action( 'after_setup_theme', 'dwp23_disable_api' );
function dwp23_disable_api() {
  $wp_api = get_option('dwp23_theme_api');
  if( $wp_api == '1' ) {
    remove_action('wp_head', 'rest_output_link_wp_head', 10);
    remove_action('template_redirect', 'rest_output_link_header', 11, 0);
    remove_action('wp_head', 'wp_oembed_add_discovery_links', 10);
    remove_action('wp_head', 'wp_oembed_add_host_js', 10);
  }
}

add_action( 'after_setup_theme', 'dwp23_enable_api_auth' );
function dwp23_enable_api_auth() {
  $api_auth = get_option('dwp23_theme_api_auth');
  if( $api_auth == '1' ) {
    add_filter( 'rest_authentication_errors', function( $result ) {
      if ( ! empty( $result ) ) { return $result; }
      if ( ! is_user_logged_in() ) {
        return new WP_Error( 'rest_not_logged_in', 'You are not currently logged in.', array( 'status' => 401 ) );
      }
      return $result;
    });
  }
}

Removing the meta boxes from the Gutenberg editor requires an additional piece of JavaScript instead of old function to remove_meta_box. LIne 22 above calls add_action( enqueue_block_editor_assets... which requires:

/js/editor-comment-option.js
wp.domReady( () => {

  wp.data.dispatch( 'core/edit-post').removeEditorPanel( 'discussion-panel' );

});

References: