Viewing output when the “The plugin generated x characters of unexpected output during activation” error is triggered

Interestingly the ability to display errors and output from a plugin on activation seems to be build in to WordPress. If you take a look at wp-admin/plugins.php there’s a case in the $action switch statement that says error_scrape — hinted at in Lars’ answer.

Looks like this:

<?php
// wp-admin/plugins.php
case 'error_scrape':
    if ( ! current_user_can('activate_plugins') )
        wp_die(__('You do not have sufficient permissions to activate plugins for this site.'));

    check_admin_referer('plugin-activation-error_' . $plugin);

    $valid = validate_plugin($plugin);
    if ( is_wp_error($valid) )
        wp_die($valid);

    if ( ! WP_DEBUG ) {
        error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
    }

    @ini_set('display_errors', true); //Ensure that Fatal errors are displayed.
    // Go back to "sandbox" scope so we get the same errors as before
    function plugin_sandbox_scrape( $plugin ) {
        include( WP_PLUGIN_DIR . "https://wordpress.stackexchange.com/" . $plugin );
    }
    plugin_sandbox_scrape( $plugin );
    do_action('activate_' . $plugin);
    exit;
    break;

As you can see, it mimics the plugin activation senario, but it doesn’t actually activate the plugin. It includes the plugin file, calls the activate hook, then exits. It does all this without output buffering so you can see what’s happening.

SO, if that’s already there, we just need to expose it. A bit of digging in wp-admin/plugins.php shows we need a nonce to verify. So we can copy that and study how the plugins list table builds its activation links. Then simply add an error scrape link on the inactive plugins. Click it, and see your errors.

Just hook into plugin_action_links and add the link:

<?php
add_filter('plugin_action_links', 'wpse24278_add_scrape', 10, 2);
/**
 * Add an "Error Scrape" action to inactive plugins.
 *
 * @uses    is_plugin_active
 * @return  array
 */
function wpse24278_add_scrape($actions, $plugin)
{
    global $status, $page, $s;

    // leave active plugins alone
    if (is_plugin_active($plugin)) {
        return $actions;
    }

    // build the url, identical to the activate URL, see the
    // plugings list table for more information.
    $url = add_query_arg(array(
        'action'            => 'error_scrape',
        'plugin'            => $plugin,
        'plugin_status'     => $status,
        'paged'             => $page,
        's'                 => $s,
    ), admin_url('plugins.php'));

    // add our action.
    $actions['error_scrape'] = sprintf(
        '<a href="https://wordpress.stackexchange.com/questions/24278/%s" title="https://wordpress.stackexchange.com/questions/24278/%s" class="edit">%s</a>',
        wp_nonce_url($url, 'plugin-activation-error_' . $plugin), // see `wp-admin/plugins.php` for the nonce name
        esc_attr__('Check for Errors', 'wpse'),
        esc_html__('Error Scrape', 'wpse')
    );

    return $actions;
}

Here is the above wrapped up in a plugin.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)