2

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 1

5

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.

6
  • @Iurie there was 2 bugs: 1) the post created was not a member cpt, but a regular post 2) code didn't check if the post already exists causing duplicate. Both fixed, even if still untsed.
    – gmazzap
    Commented Sep 12, 2013 at 21:31
  • @g-m Can you comment a little this line: // if ( ! in_array('member', $user->roles) ) return ''; ? What will happens if I will uncomment it?
    – Yuri
    Commented Jan 30, 2014 at 10:54
  • @lurie with that line commented, the function does not differe from author roles: search only if there is a post in "member" post type for a user (whatever is the role). In comments I suggest you to create a specific user role for users that should be "members". If you add that specific user role (see here), then you can uncomment that line and the function will work only if the post author of the "member" post type has that role.
    – gmazzap
    Commented Jan 30, 2014 at 11:29
  • @g-m Thank you, Giuseppe! I will analyse your suggestion. But right now I have another problem. Your code worked very well last year in an older version of WP. I'm trying to use it in the last version of WP (3.8.1), but it not working any more. I mean, the CPT is registered, its contents is saved (I checked with phpMyAdmin in the database), but the post can not be accessed. When I try to open it for viewing with the link from dashboard (I made the CPT 'Members' visible) I get just an error message: "Oops! That page can’t be found". Why this happens? P.S. Must I create another question?
    – Yuri
    Commented Jan 30, 2014 at 12:49
  • @lurie very odd, indeed. Post another question, and there publish the code you used to register the post type.
    – gmazzap
    Commented Jan 30, 2014 at 13:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.