I think Douglas has kind of answered this here, but just to ask as a separate question:

Given I have made use of Craft's User section to hold data about a company's team members, how do I now make an entry page for each member, which can link through from the list page? ('About us' single containing a loop over Users).

I originally had a channel for the team members, but switched to using Users because they will be authoring blog posts, and I figured the relation would be cleaner.



Not to diminish from Damon's excellent answer — I have certainly used this technique in the past when needed. However, just to provide another option, keep in mind that you don't need to create a separate section/channel for profile information (and thus a plugin to keep them in sync, etc). You can also simply link to a user profile template by creating a route, using username or id (or any other unique identifiable user field or field combination) to identify the user, and then pull data from the custom fields you added to 'users'.

You will first want to create a route in settings to your user profile template. Notice the use of the 'slug' token, which will be available to the template as simply {{ slug }}:

If the URL looks like this:
about/profiles/<slug>   <-- where '<slug>' is the slug token

Load this template:

In your 'about' page template (i.e. the user's index page):

{% set users = craft.users.group('myGroup').limit(null) %}
    {% for user in users %}
        <li><a href="{{ siteUrl }}about/profiles/{{ user.username|lower }}>{{ user.firstName }} {{ user.lastName }}</a></li>
    {% endfor %}

Then, in your 'about/user-profile' template:

{% set user = craft.users.username(slug).first %}
{% if user %}
    <h1>{{ user.firstName }} {{ user.LastName }}<h1>
    <p>{{ user.biography }}<p>
{% else %}
    {% redirect '404' %}
{% endif %}

I would create a new section called "Profiles" or something along those lines. This is where all of your...extended profile information will go. You can then add a users filed type on those entries that will link back to the user account.

Depending on how you are creating users (manually or through some other form) you will want to create a plugin that listens to the users.onSaveUser event.

So in your plugin that would look something like this:


public function init()
    craft()->on('users.onSaveUser', function (Event $event)
        // Get the userId       
        // Check if the user already has a profile
        // Create a new entry in the 'profiles' section
        // Set the author id to the userid
        // Set other params

        $user = $event->params['user'];

        $entry = new EntryModel()
        $entry->section = 'profiles' // or whatever the handle is


        // Set the page title so its easily found/searched
        $entry->getContent()->title = $user->firstName.' '.$user->lastName;

        // userAccount is the field handle to the users field that will link back to the actual user account
        $entry->setContentFromPost(['userAccount' => array($user->id]);


        // save the entry


Another thing to pay attention to I've found is to make sure you listen for the suspend, unsuspend and delete methods as you'll need to update the corresponding profile entry accordingly.

Hope this helps!

  • cool, thanks. So the plugin to hook in is just to avoid having to make the Profile channel entries manually? Mar 31 '16 at 16:03
  • Yep! That way the plugin does the work of managing the entries. It's up to the user to then manage the actual content of their own profile.
    – Damon
    Mar 31 '16 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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