I asked here how to create virtual pages with information from the user meta profile fields using an external class. I got a good answer and also I have implemented it successfully (thanks to @g-m!). At the same time, the author of answer suggested me that what I want can be done “in a lot simpler and more performant way“, using the core WP functions, just creating a real post type: registering a CPT, maybe not public (so no UI is showed on dashboard), and on user profile saving/updating just created/updated CPT entry.
This is how I created and saved initially some extra user profile fields:
/* Add Extra Fields to the User Profile */
add_action( 'show_user_profile', 'extra_user_profile_fields' );
add_action( 'edit_user_profile', 'extra_user_profile_fields' );
function extra_user_profile_fields( $user ) { ?>
<h3><?php _e("Academic", "blank"); ?></h3>
<table class="form-table">
<!-- Teaching position -->
<tr>
<th><label for="teaching_position"><?php _e("Teaching position"); ?></label></th>
<td>
<input type="text" name="teaching_position" id="teaching_position" value="<?php echo esc_attr( get_the_author_meta( 'teaching_position', $user->ID ) ); ?>" class="regular-text" /><br />
<span class="description"><?php _e("Put here your teaching position"); ?></span>
</td>
</tr>
</table>
}
/* Save Extra User Profile Fields */
add_action( 'personal_options_update', 'save_extra_user_profile_fields' );
add_action( 'edit_user_profile_update', 'save_extra_user_profile_fields' );
function save_extra_user_profile_fields( $user_id ) {
if ( !current_user_can( 'edit_user', $user_id ) ) { return false; }
update_user_meta( $user_id, 'teaching_position', $_POST['teaching_position'] );
}
What I want, is to put on my site a list of department members with links to their personal pages (e.g. example.com/users/user_nicename) with some content from their profiles. Pages must be created automatically, so I do not have to create manually a personal page for each new member. How can this be achieved (except the cited solution)?
1 Answer
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.