Excluding a category from wp_query breaks recent post widget

The $wp_query object is used to store the main page query, so when you’re using

$wp_query = new WP_Query( $args );

you’re wiping out the defaults. Hence, the wp_reset_query() has nothing to reset.

To fix the problem, save your custom query object with a different name, maybe $mr_custom_query, and then when looping through it, use the format:

if( $mr_custom_query->have_posts() ) : while( $mr_custom_query->have_posts() ) : $mr_custom_query-> the_post();

The WP_Query page on the codex has a ton of great code snippets if you’re still stuck.

I should also add that if you were intentionally using $wp_query to override the main page query, you should instead use query_posts(), or better yet, the pre_get_posts hook.