Wordpress - How to create a front end user profile with a friendly permalink

There are two ways I've discovered doing this:

  1. Author Page with a custom rewrite rule
  2. A custom template files paired with a rewrite rule

The first is more simple to implement, but may not work in all circumstances (one of which I'll describe soon).

Custom Rewrite Rule

I found this solution a few days ago here: URL Rewriting

And here's the code, with comments:

// Define the author levels you want to use
$custom_author_levels = array( 'user', 'leader' );

// On init, add a new author_level rewrite tag and add it to the author_base property of wp_rewrite
add_action( 'init', 'wpleet_init' );
function wpleet_init()
    global $wp_rewrite;
    $author_levels = $GLOBALS['custom_author_levels'];

    // Define the tag and use it in the rewrite rule
    add_rewrite_tag( '%author_level%', '(' . implode( '|', $author_levels ) . ')' );
    $wp_rewrite->author_base = '%author_level%';


// The previous function creates extra author_name rewrite rules that are unnecessary.  
//This function tests for and removes them

add_filter( 'author_rewrite_rules', 'wpleet_author_rewrite_rules' );
function wpleet_author_rewrite_rules( $author_rewrite_rules )
    foreach ( $author_rewrite_rules as $pattern => $substitution ) {
        if ( FALSE === strpos( $substitution, 'author_name' ) ) {
            unset( $author_rewrite_rules[$pattern] );
    return $author_rewrite_rules;

You can then use the built in author.php template, modifying to your hearts content.

Sincerely, check the link listed above, as Jan Fabry does an excellent job explaining everything.

Query Vars and Page Templates

For the theme I was working on while discovering these solutions, I needed to serve a custom page based on a user meta value (a separate ID). My client did not want the username or user ID visible publicly, so we created a separate layer.

The only problem? At the moment, there isn't a clear way how to use the Rewrite API to query by meta keys/values. Luckily, there was a solution.

In your functions.php file...

// Create the query var so that WP catches your custom /user/username url
add_filter( 'query_vars', 'wpleet_rewrite_add_var' );
function wpleet_rewrite_add_var( $vars )
    $vars[] = 'user';
    return $vars;

And then, you need to create a new rewrite tag and rule so that it knows when and how to handle the new query var.

add_rewrite_tag( '%user%', '([^&]+)' );

Once you've done this, you merely need to "catch" when the query var is being served, and then redirect to the template of your choice:

add_action( 'template_redirect', 'wpleet_rewrite_catch' );
function wpleet_rewrite_catch()
    global $wp_query;

    if ( array_key_exists( 'user', $wp_query->query_vars ) ) {
        include (TEMPLATEPATH . '/user-profile.php');

Just make sure you have created user-profile.php.

In my own example, I created a third function that matched the "public User ID" to the actual user_id via the $wpdb->usermeta table, and passed the information to the template.

If you need to create a template different from the rest of your theme, remember that with get_header, you can specify a name:

get_header( 'user' );

Which will call the header-user.php file.


Both of these are valid, working solutions. The second offers a separate layer of "security" as it does not reveal user IDs or usernames, if other people will be able to browse the profiles.

Hope that helps, let me know if you have any questions.

I found this earlier today and made some modificatios to @bybloggers code with the diference that instead of using template_redirect I change the request to show a static page, that means that you can now add anything you like to a page template and use it on that page.

class ProfilePage {
function __construct() {
    add_filter( 'init',array($this,'rw_init'));
    add_filter( 'query_vars', array($this,'wpleet_rewrite_add_var') );
    add_filter( 'request', array($this,'change_requests'));
function wpleet_rewrite_add_var( $vars ) {
    $vars[] = 'usuario';
    return $vars;
function rw_init(){
    add_rewrite_tag( '%usuario%', '([^&]+)' );
function change_requests($query_vars) {
    //go to a specific page when the usuario key is set
    $query_vars['page_id'] = isset($query_vars['usuario']) ? 7581 : $query_vars['page_id'];
    return $query_vars;
new ProfilePage();

Spanish -> usuario = user <- English