Home About Me

Silencing WordPress.org Requests During Local Debugging

When developing plugins or themes locally, turning on WP_DEBUG in wp-config.php is often the quickest way to catch what your code is doing wrong. If you are not already using this switch, the rest of this probably is not for you.

define('WP_DEBUG', true);

With debug mode enabled, PHP warnings and errors are printed directly on the page in a way that is hard to miss.

WordPress local debug warning

That is useful until WordPress starts shouting about problems that are not yours.

A mature product like WordPress normally does a good job of keeping warnings away from end users. But local development is a different story. Because access to wordpress.org can be unreliable, any failed request tied to updates or translations may flood the admin area with warnings. Once that happens, debugging becomes noisy and misleading.

After installation, there are roughly four places in the admin that may trigger calls to wordpress.org: core updates, theme updates, plugin updates, and the translation API. These requests show up across the Dashboard, Plugins, Themes, and Settings screens. The Dashboard typically involves the first three update checks, while Settings may touch all four.

The problem is not just visual clutter. Those warnings can interfere with reading the real error output. For example, a message like Cannot modify header information may look like a local header issue when it is actually just fallout from a failed remote request. In some cases, the warnings also affect how page elements render and behave.

So the cleanest approach during local debugging is to stop those requests altogether.

One possible idea is this:

define('WP_HTTP_BLOCK_EXTERNAL', true);

In practice, that does not solve the issue here. A more direct approach works better.

Use the following code:


//下面的action钩子调用的早,所以在加载主题或插件的时候就要直接remove掉,否则没机会了。
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
    remove_action('admin_init', '_maybe_update_core');
    remove_action('admin_init', '_maybe_update_plugins');
    remove_action('admin_init', '_maybe_update_themes');
    remove_action('init', 'wp_schedule_update_checks');

    //translations_api默认会返回false,之后会访问wordpress.org,返回空数组之后就不访问了。
    //Since 4.0.0
    add_filter('translations_api', '__return_empty_array');
}

//调试者作为admin,默认是有各种update权限的。这里令各种内部调用user_has_cap询问4种权限的结果强行置为false。
function _debug_ignore_wp_request ($allcaps, $caps, $args){
    $server_caps = array('install_languages', 'update_themes', 'update_plugins', 'update_core', 'install_themes', 'install_plugins');
    foreach ($caps as $cap) {
        if ( in_array($cap, $server_caps)) {
            $allcaps
[$cap]
 = false;
        }
    }
    return $allcaps;
}

function my_admin_init {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        //下面的钩子很多不能移除得太早。
        //宁杀错不放过。
        remove_action('upgrader_process_complete', 'wp_update_plugins');
        remove_action('upgrader_process_complete', 'wp_update_themes');
        remove_action('load-plugins.php', 'wp_plugin_update_rows', 20);
        remove_action('load-themes.php', 'wp_theme_update_rows', 20);
        remove_action('load-plugins.php', 'wp_update_plugins');
        remove_action('load-themes.php', 'wp_update_themes');
        wp_unschedule_hook('wp_version_check');
        wp_unschedule_hook('wp_update_plugins');
        wp_unschedule_hook('wp_update_themes');

        remove_action('wp_version_check', 'wp_version_check');
        remove_action('load-plugins.php', 'wp_update_plugins');
        remove_action('load-update.php', 'wp_update_plugins');
        remove_action('load-update-core.php', 'wp_update_plugins');
        remove_action('wp_update_plugins', 'wp_update_plugins');
        remove_action('load-themes.php', 'wp_update_themes');
        remove_action('load-update.php', 'wp_update_themes');
        remove_action('load-update-core.php', 'wp_update_themes');
        remove_action('wp_update_themes', 'wp_update_themes');
        remove_action('update_option_WPLANG', 'wp_clean_update_cache', 10, 0);
        remove_action('wp_maybe_auto_update', 'wp_maybe_auto_update');
        add_filter('user_has_cap', '_debug_ignore_wp_request', 10, 3);
    }
}

add_action('admin_init','my_admin_init');

The idea is straightforward:

  • Some update-related hooks run very early, so they need to be removed before themes or plugins finish loading, otherwise you miss the chance.
  • translations_api normally returns false, which then leads to a request to wordpress.org. Returning an empty array prevents that follow-up request.
  • During debugging, the current user is usually an admin and therefore has permission to check for updates. The user_has_cap filter is used here to forcibly turn several relevant capabilities into false, including language, theme, plugin, and core update-related permissions.
  • Additional actions and scheduled hooks are then removed or unscheduled inside admin_init so WordPress does not keep trying again through other entry points.

Once those requests are neutralized, the admin area becomes quiet again and the debug output is much easier to trust.