Figured it out!
/**
* Replace %author_id% by author_id.
*
* @since 1.0.0
* @param string $link
* @param int $author_id
*/
add_filter( 'author_link', 'wpse_298572_change_author_link', 10, 2 );
function wpse_298572_change_author_link( $link, $author_id ) {
$link = str_replace( '%author_id%', $author_id, $link );
return $link;
}
/**
* Rewrite the user link.
*
* @since 1.0.0
*/
add_action('init', 'wpse_298572_rewrite_user_link');
function wpse_298572_rewrite_user_link() {
global $wp_rewrite;
$wp_rewrite->author_base="u";
$wp_rewrite->author_structure="https://wordpress.stackexchange.com/" . $wp_rewrite->author_base .'/%author_id%/%author%/';
add_rewrite_rule('^u/([\d]+)/?([A-Za-z0-9\-\_]+)\/?$', 'index.php?author=$matches[1]', 'top');
}
/**
* Redirect to full user link.
*
* @since 1.0.0
*/
add_action('template_redirect', 'wpse_298572_user_permalink_redirect');
function wpse_298572_user_permalink_redirect() {
global $wp;
// Check if on author page
$author = get_query_var('author');
if ( !isset($author) ) {
return;
}
preg_match("/\/?u\/([\d]+)\/?([A-Za-z0-9\-\_]+)?\/?(.*)$/", $wp->request, $matches);
if ( isset($matches[1]) && $user = get_user_by('ID', $matches[1]) ) {
// Don't redirect if url already matches the correct name
if ( $matches[2] == $user->user_nicename ) {
return;
}
$author_permalink = get_author_posts_url($user->ID) . $matches[3];
wp_safe_redirect($author_permalink, 301);
exit();
}
}