Cchost/developer/Hooking the User Profile
Docs Home | Install | Upgrade | Troubleshoot | Customize | Admins | Devs | Content | Query | Templates | Commands | Skins |
If you like the data shown on the user profile page but want to change the layout you can skip down the layout section. If you like layout of the data shown on the user profile page but want to change the data, you'll need to able to do some PHP hacking. If you want to change both the data shown and the layout you'll have to do both.
The exceptions are the 'Contact' and 'Member since' fields which are handled directly in the layout template (wups). In order to edit or remove those you'll need to hook the layout template.
Contents
Changing the Data
The data on the user profile page is very dynamic based on a myriad of user stats. In order to manipulate them you hook the user profile filter event which is called whenever the user profile template is about to be displayed.
CCEvents::AddHandler( CC_EVENT_FILTER_USER_PROFILE, 'user_profile_filter' ); function user_profile_filter(&$rows) { $user_row =& $rows[0]; }
Your handler will be called with an array, the first element of which will be a user record that has already been massaged by the other modules interested in displaying something. In the code above we make a reference to that record for better readability throughout the code.
There are three areas in the user record with potential interest:
- $user_row['user_fields'] is an array of labeled data fields for display
- $user_row['user_tag_fields'] is an array list links that are supposed to treated and displayed as folksonomy tags
- (everything else) in the record is raw data taken out of the database for that user.
The 'user_fields' and 'user_tag_field' arrays are not indexed, which means if you want to remove an element, the safest thing to do is to make a copy of the array:
$ok_array = array(); foreach( $user_row['user_fields'] as $uf ) { if( $uf['label'] == 'str_stats' ) continue; $ok_array[] = $uf; }
Then set the new array it back into the user record:
$user_row['user_fields'] = $ok_array;
The actual contents of any of those areas is very sensitive to context and might change from session to session so you should never assume the presence of any, always be ready for any these and don't assume that a comprehensive list is feasible.
Having said all that, possible values to watch for in 'user_fields'
label | Typical value | |
---|---|---|
str_user_about_me | HTML formatted user description | |
str_user_home_page | HTML formatted link to user's home page | |
str_user_feeds | Link to user_feeds template | |
str_user_forum_posts | Number of posts user has made to the forums | |
str_playlists | Link to number of playlists (or galleries) user is featured in | |
str_publicize | Link to 'publicize' feature | |
str_review_stats | Stats about reviews | |
str_stats | Remix stats |
Possible values to search for in 'user_tag_fields'
label | Typical value | |
---|---|---|
Favorite people | Links to other users | |
str_prof_what_i_like | Links to search/people/whatilike tags | |
str_prof_what_i_pound_on | Links to search/people/whatido tags | |
str_prof_what_im_looking_for | Links to search/people/lookinfor |
Other fields that may be available directly off the record:
- user_avatar_url
- user_date_format
- user_emailurl
- user_homepage
- user_id
- user_name
- user_num_posts
- user_num_remixed
- user_num_remixes
- user_num_reviewed
- user_num_reviews
- user_num_uploads
- user_real_name
You can use these to build up new versions of user fields:
$user_row['user_fields'][] = array( 'label' => 'Posting stats for ' . $user_row['user_real_name'], 'value' => $user_row['user_num_reviews'] . ' reviews, ' . $user_row['user_num_posts'] . ' forum posts' )
Full Example Code
Put the following into a module at <local_files>/lib/my_user_profile_hook.php
<? CCEvents::AddHandler( CC_EVENT_FILTER_USER_PROFILE, 'user_profile_filter' ); function user_profile_filter(&$rows) { // Setup some useful variables $user_row =& $rows[0]; $is_user_logged_in = CCUser::IsLoggedIn(); $is_current_user = $is_user_logged_in && (CCUser::CurrentUser() == $user_row['user_id']); // If we want to remove a field (like the // 'review' stats) then we have make a copy // of the user_fields $ok_fields = array(); foreach( $user_row['user_fields'] as $uf ) { if( $uf['label'] == 'str_review_stats' ) continue; $ok_fields[] = $uf; } // We want to add a special message to everybody but 'joe' if( !$is_current_user || ($user_row['user_name'] != 'joe') ) { $ok_fields[] = array( 'label' => "Special Message", 'value' => "<h3>It's joe's birthday on Friday!</h3>" ); } $user_row['user_fields'] = $ok_fields; } ?>
Changing the Layout
Setting things up
In order to change the look and layout of the user profile copy ccskins/shared/user_profile.tpl to <local_files>/skins/user_profile.tpl (make sure to keep the same file name!)
If you plan on changing the CSS (likely) copy ccskins/shared/css/user_profile.css to <local_files>/skins/css/user_profile.css (make sure to keep the same file name!)
Before you get too far and in order to fully understand this template it helps to temporarily insert an %inspect% macro after the call to %map% while developing:
%map(#U,records/0)% %inspect(#U)% <link rel="stylesheet" title="Default Style" href="%url(css/user_profile.css)%" />
Now browse to a profile (e.g. people/admin/profile) to see if you've properly hooked the system and view a dump of the user record.
And don't forget about variable dumps.
Walking through the template
The template has a couple of 'tricks' to get things laid out in a certain way.
A Quick Hack
This template assumes that the user description is at the top of the array and has an ID of user_description_html
Because of convention in social sites, we want the 'Contact' and 'Member Since' fields to follow directly below that. In order to make sure that happens, the template hacks in two user fields into the second and third slot of the array the line that looks like:
array_splice( $U['user_fields'], 1, 0, array( ...<snip>
Printing the user_fields
Once those elements are in, we loop over the 'user_fields' displaying them "as is"
<div id="user_fields"> %loop(#U/user_fields,uf)% <div class="ufc" %if_attr(#uf/id,id)%><span class="ufc_label">%text(#uf/label)%</span> <div class="ufc_value">%text(#uf/value)%</div></div> %end_loop% </div>
Printing the user_tag_links
Then we output the 'user_tag_fields' which are tag links for this user. The links URLs (HREF value) and text are already formatted, we just have to lay out the links in an orderly fashion. The links are 'grouped' so there's an outer loop for the groups:
<div class="user_tag_links"> %loop(#U/user_tag_links,groups)% <span class="ufc_label">%text(#groups/label)%</span>
And within each group is array of links:
<div class="ufc_value taglinks"> %loop(#groups/value,link)% <a href="%(#link/tagurl)%">%(#link/tag)%</a>%if_not_last(#link)%, %end_if% %end_loop% </div>
Then we close off the outer group loop and DIV:
%end_loop% </div>
Hacking the avatar into the user description
The template then outputs some javascript that will reformat things and 'make things nice.'
If the user has written something about themselves, then we want to put their avatar into the description box and make it round and pretty.
If the user did not fill out a description then we inject the avatar in the top of the profile page.
All of this, of course, is default policy driven lay out code, hopefully your mileage will vary.