WordPress category widget only show categories with children

I would suggest something like this:

function exclude_widget_subcategories($args){
  $all_categories = get_terms('category', array('parent' => 0, 'fields' => 'ids'));

  $exclude_categories = array();

  foreach($all_categories as $category_id){
    $children = get_term_children($category_id, 'category');

    if(count($children)!=0){
        $exclude_categories[] = $category_id;
    }
  }
  $exclude = implode(",",$exclude_categories); // The IDs of the excluding categories
  $args["exclude"] = $exclude;
  return $args;
}
add_filter("widget_categories_args","exclude_widget_subcategories");

get_terms('category', array('parent' => 0, 'fields' => 'ids')); gets all category wordpress terms that are children of ‘0’, ie they are top level items. It also specifies that only the ids are returned, rather than term objects. More documentation here

get_term_children should be fairly self-explanatory, though note that you need to pass the name of the taxonomy to the function call. More documentation here

Please note I haven’t tested this out so there may be syntax errors – let me know if there are and I may be able to help further 🙂