Custom WordPress user permalink

the problem with this question, and of a lot of questions like this, is the one pinted out by @Milo in comments: if you write a rewrite rule to handle you custom url, this goes in conflict with WordPress rules, e.g. if your urls are

htt://example.com/username/city/occupation

how WordPress can know if you are actually lookin for the page occupation child of page city granchild of page username?

Answer is can’t, unless you do a query on database to see if the username part is a real username or not.

To simplify things like that I wrote a plugin called Clever Rules and in this answer I will use a technique I used for that plugin. This technique can’t be used inside themes, but need to be used in plugins, so for this anwser I write a little plugin that uses 2 function taken from your code (just little bit optimized) and a small class that will do the magic.

How it Works

  1. I create a class that extends WP class.
  2. Then I replace the global $wp variable (that normally contain an
    instance of WP) with an instance of my class. This one contain
    only a method: parse_request that override WP method, so when
    WordPress call parse_request the one my class is called instead
    of the core one.
  3. In this method I check the current url, if it seems one we want to target
    I check the first part of the url and if it’s a valid username set
    up the query vars otherwise let core parse_request run.

Code

<?php
/**
 * Plugin Name: GM Custom Author Url WPSE Q#122829
 * Plugin URI: http://wordpress.stackexchange.com/questions/122829/custom-wordpress-user-permalink
 * Author: G.M.
 * Author URI: http://wordpress.stackexchange.com/users/35541/g-m
 *
 */
class GMWPE extends WP {    
  function parse_request( $extra_query_vars="" )
  {
    $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), "https://wordpress.stackexchange.com/" );
    $full = str_replace( $home_path, '', add_query_arg( array() ) );
    $sane_array = explode( '?', $full );
    $sane = trim( $sane_array[0], '/\\' );
    $parts = array_filter( explode( "https://wordpress.stackexchange.com/", $sane ) );
    if ( count($parts) === 3 ) {
      $maybe_author = $parts[0];
      $user = get_user_by('slug', $maybe_author);
      if ( $user !== false ) {
        remove_filter( 'template_redirect', 'redirect_canonical' );
        $this->query_vars = array( 'author' => $user->ID );
        return;
      }
    }
    parent::parse_request( $extra_query_vars="" );
  } 
}

add_action( 'setup_theme', 'GMWPE_init', 9999 );
function GMWPE_init() {
  global $wp;
  if ( get_class( $wp ) === 'WP' ) $wp = new GMWPE();
}

add_filter( 'author_link', 'gmcau_author_link', 10, 3 );
function gmcau_author_link( $link, $author_id, $author_nicename )
{
  $part2 = get_user_meta( $author_id, '_themex_city', true );
  $part3 = get_user_meta( $author_id, '_themex_thesubject', true );
  if ( $part2 && $part3 ) {
    $newlink  = $author_nicename . "https://wordpress.stackexchange.com/" . $part2 . "https://wordpress.stackexchange.com/" . $part3;
    $link = home_url( $newlink );
  }
  return $link; 
}

add_action( 'user_profile_update_errors', 'gmcau_set_user_nicename_to_nickname', 10, 3 );
function gmcau_set_user_nicename_to_nickname( &$errors, $update, &$user )
{
  if ( ! empty( $user->nickname ) ) {
   $user->user_nicename = sanitize_title( $user->nickname, $user->display_name );
  }
}

This is the only thing you need (you can remove the functions you posted). Save this code in a file, put it in your plugins folder and activate it form your dashboard.


PS: if you are interested in have a look on my plugin that use this technique to give a flexible urls handling you can find it here.