First of all register the cpt. Probably if you don’t want add the UI for that post type you can set the show_ui
to false.
$args = array(
'label' => 'Members',
'public' => true,
'exclude_from_search' => true,
'show_ui' => false,
'show_in_nav_menus' => false,
'show_in_menu' => false,
'show_in_admin_bar' => false,
'hierarchical' => false,
'has_archive' => true,
'publicly_queryable' => true,
'rewrite' => true,
'query_var' => 'member'
);
register_post_type( 'member', $args );
After that create a function that accept an user id and create the post content
function create_member_page( $user_id = '' ) {
$user = new WP_User($user_id);
if ( ! $user->ID ) return '';
// check if the user whose profile is updating has already a post
global $wpdb;
$member_post_exists = $wpdb->get_var( $wpdb->prepare(
"SELECT ID FROM $wpdb->posts WHERE post_name = %s AND post_type="member" and post_status="publish"", $user->user_nicename
) );
// you have a custom role for members?
// you should, because if not all user will have a page, also admin, subscribers...
// if ( ! in_array('member', $user->roles) ) return '';
$user_info = array_map( function( $a ){ return $a[0]; }, get_user_meta( $user->ID ) );
$title = $user_info['first_name'] . ' ' . $user_info['last_name'];
// of course create the content as you want
$content="This is the page for: ";
$content .= $user_info['first_name'] . ' ' .$user_info['last_name'];
$post = array(
'post_title' => $title,
'post_name' => $user->user_nicename,
'post_content' => $content,
'post_status' => 'publish',
'post_type' => 'member'
);
if ( $member_post_exists ) {
$post['ID'] = $member_post_exists;
wp_update_post( $post );
} else {
wp_insert_post( $post );
}
}
Now you have to run this function on every user creation / updating
add_action( 'personal_options_update', 'create_member_page' );
add_action( 'edit_user_profile_update', 'create_member_page' );
That’s all.
Now you can create your archive-member.php
template to show all members, you can get them using WP_Query
or get_posts
.
And, you can create the template single-member.php
to show the member profile, that’s a real page, not a virtual one, for this reason you can use all the WP function with it.
If you want a link to the member page, of course you can use get_permalink($postid);
but this is not an intuitive way, you probably prefer to get link from an user id or name, so let’s create anothe function:
function member_permalink ( $user="" ) {
if ( ! empty($user) ) {
if ( is_numeric($user) ) { // user id
$userObj = get_user($user);
} else { // user nicename
$userObj = -1;
}
} else {
$userObj = wp_get_current_user();
$name = isset($userObj->user_nicename) ? $userObj->user_nicename : '';
}
if ( ! isset($name) ) $name = $userObj == -1 ? $user : $userObj->user_nicename;
global $wpdb;
$id = $wpdb->get_var( $wpdb->prepare(
"SELECT ID FROM $wpdb->posts WHERE post_name = %s AND post_type="member" AND post_status="publish"",
$name
) );
return $id ? get_permalink($id) : '';
}
This function is flexible, you can use it like: member_permalink($user_id)
also you can use it like member_permalink($user_nicename)
.
If the current logged user is a member, you can use the function like member_permalink()
to retrive the url of the current logged-in member.
Note the code is untested, and written here, without syntax highlight, so there are chances for typos…
A side note
Some time ago an user asked if was better generate ‘staff’ content from pages (like present solution) or from user meta fields. In that occasion I opted for second option. That’s because your question is different (virtual pages vs real pages), however read that question / answer can be useful for you.. Find it here.