SilverStripe Membership Module Tutorial

by frank on October 12, 2010

in SilverStripe

This SilverStripe Membership Module by ajshort is one of the most useful and solid modules I’ve used on a SilverStripe install.

Strangely this module is not listed on SilverStripe.org’s collection of modules, I stumbled upon it after performing a search for “SilverStripe Membership Module” and coming across a forum post where the github repository for the module was linked to.

How to install the Membership module

  • Grab the code from the github repository, if you have git installed its a matter of cloning the repo with: git clone http://github.com/ajshort/silverstripe-memberprofiles.git
  • Rename the folder to ‘memberprofiles’ otherwise the little membership icon will not be found for the admin area. Make sure the memberprofiles folder is in the root of your SilverStripe install.
  • Run a /dev/build/
  • Create a new ‘Member Profile Page’ in the CMS.

The membership module should now be installed but to make life a bit easier go to the Security tab of the CMS and add a new group that will be used for new memberships – call it what you want, such as ‘members’.

Now go to the ‘Administrators’ security group and edit your admin account, add yourself to the new group you just created. Navigate back to the ‘Pages’ section of the CMS, edit the new membership profile page and on the Behaviour tab check the option to:
Allow members with member creation permissions to add members via this page

So you will now be able to log in as a member using your admin account and additionally add new memberships. I still found it handy to test signing up as a new member in another browser profile however.

What the Membership Module will do

Straight off the bat the module takes care of everything for basic memberships:

  • Registering new members
  • Editing member profiles
  • Forgotten passwords
  • Email confirmation as a requirement before signing up
  • Post registration and login redirection
  • Members can choose which groups they want to belong to

And all of the above is very customisable, you can…

  • choose not to send out any emails, just send a notification email confirming membership or send a validation email with confirmation link to ensure new members have a valid email address.
  • force new members to be assigned to certain groups and allow members to pick which groups they want to belong to.
  • customise registration and post registration page content and whether to redirect a new member to another page, with full control over which page to redirect to.
  • drag and drop to reorder the registration form fields, manage validation requirements, error messages, field titles and show only certain form fields on registration.
  • add more form fields by decorating / extending the member class (see below).

All memberships can be managed from the Security tab of the CMS, so the existing functionality for managing admin users etc. is used.

Extending the Member class

Its very easy to add some custom data to your memberships.

Create a new class to extend the existing member class in /mysite/code. If you are signing up members that are a certain type name the class after that type, in the example I’ll assume you are signing up pianists:

<?php
//mysite/code/Pianist.php
class Pianist extends DataObjectDecorator{
	function extraStatics(){
		return array(
			'db' => array(
			    'PostalAddress' => 'Varchar(255)',
        		    'HeardFrom' => "Enum('Word of mouth,Email,Website link,Facebook,Search Engine,Other','Word of mouth')",
		            'Status' => "Enum('Active,Disabled','Disabled')",
		            'AcceptTerms' => 'Boolean'
			),
			'defaults' => array(
			     'Status' => 'Disabled'
			)
		);
	}
}
?>

The pianist class adds some db data in order to record new members’ postal address, how the new member heard about the website and whether the new member has accepted the terms and conditions.

We are also setting the default status of this member to Disabled because we want to screen all new members before giving them access to parts of the site.

To instantiate this DataObjectDecorator you need to include a line to add the extension in the config file:

//Decorate/extend the member class
Object::add_extension('Member', 'Pianist');

After running a /dev/build you should be able to see the new fields in your members table in the database. You should also see the new fields populated on the Membership Profile page in the CMS, you can edit to make the AcceptTerms field required and only shown when a user registers, and similarly for the other fields – directly from the CMS.

One of the things I love about this module, and SilverStripe, is the ability to add functionality using the DataObjectDecorator without hacking about in the core of the module, its very erm modular.

Checking if active members are logged in

Above we added a field to the member table using the Pianist DataObjectDecorator which sets the status of a member to ‘Disabled’ by default. The nice thing about this is admin users can search through members in the Security area of the CMS and edit the member so that their status is either Active or Disabled, this way you can have control over what members can do and view on your site.

Some useful functions to help with this are:

<?php
//mysite/code/Page.php
class Page_Controller extends ContentController {
 
	public static $allowed_actions = array (
	);
 
	public function init() {
		parent::init();
		Requirements::block(SAPPHIRE_DIR . "/javascript/ConfirmedPasswordField.js"); 
	}
 
	public function getLoggedIn() {
 
	    //This should return false but is returning null when user is not logged in
	    if (!Member::currentUser()) {
	        return false;
	    }
	    return true;
	}
 
	public function getMemberActive() {
	    $member = Member::currentUser();
	    if (!$member) {
            return false;
        }
	    $status = $member->getField('Status');
	    if ($status == 'Active') {
	        return true;
	    }
	    return false;
	}
 
    public function logout() {
        Security::logout(false);
        Director::redirect("home/");
    }
}

Emailing the site owner when new members join

Another nice addition is emailing the site owner when a new member signs up. Its quite easy to do so using the DataObjectDecorator again:

<?php
//mysite/code/Pianist.php
class Pianist extends DataObjectDecorator{
 
    //Other code from above here
 
    function onBeforeWrite() { 
 
        if (!$this->owner->exists()) {
            $email = new Email(); 
            $data = $this->owner->getAllFields();
 
            $toAddress = Email::getAdminEmail();
            $email->setTo($toAddress); 
 
            $email->setSubject('New Pianist has just registered'); 
            $email->setFrom($data['Email']);
 
            $email->setTemplate('NewPianistEmail');
            $email->populateTemplate($data);
 
            $email->send();
        }
    }
 
}
?>

The above code checks if a new Pianist is registering then sends an email to the site admin if so. You will need to add an admin email address in config in order for Email::getAdminEmail() to retrieve something useful:

//mysite/_config.php
Email::setAdminEmail('admin@example.com');

Issues

One issue I had with the module was the double up of the password confirm field labels for some reason. Someone else had this issue as well, this hack works:

//memberprofiles/code/MemberProfilePage.php line ~750 in MemberProfilePage_Controller::getProfileFields()
 
//Changed to remove duplicate password labels on register form
if (!$field instanceof ConfirmedPasswordField) {
    $field->setTitle($profileField->Title);
}

I also had an issue with the ConfirmedPasswordField not hiding by default, this is not an issue related to the module I don’t believe. Applying this hack fixed it for me.

Notes

The membership module scores very highly for me and should be included in SilverStripe’s module directory. Many thanks to Andrew Short for this awesome piece of work! The membership profiles github repository is a great place to start for documentation etc.

Was this article useful?

rss feed icon

Email this article to yourself or...

rss feed icon

Subscribe to the RSS feed for more useful articles and tips.

Share this article with others

  • del.icio.us
  • Twitter
  • Reddit
  • StumbleUpon
  • Facebook
  • Digg
  • http://andrewshort.name/ Andrew Short

    Hey there! Thanks for the great feedback. Regarding the duplicate password label issue, you can also temporarily fix this by setting the custom title field on the Password field to ” ” – that is, a blank space. This is probably the best way to temporarily fix it without changing the code until I push a proper fix.

  • http://www.silverstripe.com.au Shane Weddell

    Frank, great article and much kudos to Andrew for the work on this module.

    This module and a bunch of others are the quality contributions of the SilverStripe Australia development team. We have Australian State and Federal Government clients driving the development that is now feeding back into the community. Currently the complete set are found on the git repositories of Andrew and Marcus, github.com/ajshort and github.com/nyeholt

    The modules are finding their way to the silverstripe.org modules list as we find the time to get them polished and across. We are keen to get larger community involvement in the work we are doing and welcome all the feedback we can get from the community.

  • frank

    Yeah, there is quite the cache of silverstripe modules in those two github accounts! I was quite pleased when I stumbled across them!

    Yell out Andrew (or Marcus) if there’s anything that needs to be done for this module to get it listed on SilverStripe.org, I wouldn’t mind contributing now that I am somewhat familiar with it and intend on using it for other projects.

  • Austin

    I’m quite impressed with the module. I wondered if there’s a way to get the people to logout once they have been logged in?

    Cheers

  • frank

    Hey Austin, you can create a very simple logout function like the one in Page_Controller above and then provide a link for logged in visitors to {$BaseHref}home/logout, after visiting that link they should be logged out.

  • Rick

    Nice! Any ideas how I add an image to a member?

    Cheers

  • frank

    Hey Rick, you could probably play around with the has_one extraStatics of the DataObjectDecorator and maybe some methods in there that will help you add images to each member…

  • codivist

    nice tutorial. Is there a way to change the select boxes to radio buttons from the Enum fields?

  • frank

    Hey codivist, thats a really good question. I presume you mean the enum fields in the data object decorator – I did have a quick look into doing exactly that but it wasn’t required for the project I was working on so didn’t spend much time on it. There will be a solution I’m sure but you will have to look on the SilverStripe forums or IRC channel.

  • Luis

    It’s a real cool module, I don’t know why they haven’t published it yet

  • borriej

    Is the above code correct?
    I get a 404 after registering!

    Added the above code:
    array(
    ‘PostalAddress’ => ‘Varchar(255)’,
    ‘HeardFrom’ => “Enum(‘Word of mouth,Email,Website link,Facebook,Search Engine,Other’,'Word of mouth’)”,
    ‘Status’ => “Enum(‘Active,Disabled’,'Disabled’)”,
    ‘AcceptTerms’ => ‘Boolean’
    ),
    ‘defaults’ => array(
    ‘Status’ => ‘Disabled’
    )
    );
    }

    function onBeforeWrite() {

    if (!$this->owner->exists()) {
    $email = new Email();
    $data = $this->owner->getAllFields();

    $toAddress = Email::getAdminEmail();
    $email->setTo($toAddress);

    $email->setSubject(‘New Pianist has just registered’);
    $email->setFrom($data['Email']);

    $email->setTemplate(‘NewPianistEmail’);
    $email->populateTemplate($data);

    $email->send();
    }
    }

    }
    ?>

    I open the browser:
    go to register page -> hit register botton.
    page not found!

    When i rewrite the code like this:

    array(
    ‘PostalAddress’ => ‘Varchar(255)’,
    ‘HeardFrom’ => “Enum(‘Word of mouth,Email,Website link,Facebook,Search Engine,Other’,'Word of mouth’)”,
    ‘Status’ => “Enum(‘Active,Disabled’,'Disabled’)”,
    ‘AcceptTerms’ => ‘Boolean’
    ),
    ‘defaults’ => array(
    ‘Status’ => ‘Disabled’
    )
    );

    function onBeforeWrite() {

    if (!$this->owner->exists()) {
    $email = new Email();
    $data = $this->owner->getAllFields();

    $toAddress = Email::getAdminEmail();
    $email->setTo($toAddress);

    $email->setSubject(‘Member activation required’);
    $email->setFrom($data['Email']);

    $email->setTemplate(‘EmailTemplate’);
    $email->populateTemplate($data);

    $email->send();
    }

    }

    }

    }
    ?>

    Any ID?

  • borriej

    And another issue:

    i all my members can instantly walk into the member section withouth the admin setting the accounts to active! When looking in the CMS the account says: disabled, but they are able to login after registration, this is strange!

    Any ID?
    Im using groupDecorator/ CustomLoginForm

  • frank

    hi borriej, not sure about the 404, does your EmailTemplate file exist? Perhaps try commenting out the onBeforeWrite() function and see if the problem is in there. You can use the getMemberActive() function in your template to show a member parts of a page depending on whether their account is active or not. Something like:

    < % if MemberActive %>
    Here is some content, we have approved your account.
    < % else %>
    We are still in the process of approving your account. Thanks.
    < % end_if %>

    HTH

  • borriej

    @Frank how do you set the template?
    Just upload a template into templates folder?
    ThisEmailTemplate.ss -> $email->setTemplate(‘ThisEmailTemplate’);

    Like this?

  • borriej

    Or could you upload all the files as a package that does work?

    thx!

  • Gerard

    Hi frank,
    Before I spend unavailable days getting my head around the code (slowly learning), is there any quick way of changing the key membership id from email to a Membership number? Members would log in via a provided M# and password rather than register themselves. I’d still want them to be able to change their passwords and request a new password via email so can’t just change the email fieldname. Thoughts?
    Thanks,
    G.

  • frank

    Hi borriej: sorry, missed your comments. In this example you would just need to create the file: NewPianistEmail.ss in the templates folder.

    Gerard: I’m sure you could do that, add an id to the member I guess (make sure you make it unique as an index in mysql) then overload the login method of the membership module. Thats my guess anyway.

  • Borriej

    Frank, another question:
    how do you set an auto email when the admin activates your account?

  • frank

    I would probably put that in the onBeforeWrite() of the Pianist class, when the member gets saved you can get the old record of the data and compare it to the new one (there are shortcuts to this data in SilverStripe which I can’t remember off the top of my head). If the member has been activated when it was previously not then send an email there.

  • http://graphicagenda.com Greg Kerstin

    Hey Frank. Thank you for this great member profile information. I added a new member extension just like you described. I ran into a problem trying to save the Word of Mouth in the dropdown. I enabled it to be edited only in the profile screen. When I go to the member profile page, I changed the dropdown to another item, but it would not get saved.
    Asides, the other text fields (extraStatics) that I added get saved.

  • frank

    @Greg not sure about that problem, might be a good idea to log that issue on the github repository or let one of the Australian SilverStripe team know. You can add issues to the repository here: https://github.com/ajshort/silverstripe-memberprofiles/issues

  • custer

    Hi Frank,
    I have some minor issue regarding the editing of the profile. When there is a required field that was empty on form submission, when the page reloads, all other inputs are gone. It is very gruesome to users if they forget to fill up one field and hit the Save button just for them to find out that they have to redo the same process. Have you encountered this problem? Do you have some quick fix?

    Thanks mate!

  • frank

    Hey custer, I haven’t had that problem but I also haven’t used the latest version of the memberships module from github. Best man to ask would be ajshort, perhaps in the SilverStripe forum. Sorry couldn’t be more help mate.

  • Stephen Deere

    How can i disable registration.
    can’t see any option in admin

  • frank

    In the behaviour tab of the MemberProfilesPage you have created there is an option: “Allow registration via this page” hth.

  • http://webintegrations.co.uk Sam Jarvis

    Followed the first 2 steps, website is now completely fucked, ?isDev=1 gives me “Sorry, you can’t use ?isDev=1 until your Member and Group tables database are available. Perhaps your database connection is failing?”

    Thanks bro!

  • John

    Fantastic module and great write up.
    I have been trying to get this to work for multiple member types. RTFM me their is a doc page I missed for dealing with multiple member types (The SS topic page for members is vague).
    Having tried by creating a ‘member profile page’ for each,…. I am guessing (but not sure) this approach accomodates one user type only. I think because the decorator instantiators (mysite/_config) cannot distuingiush the Member types. Am I Wrong about that?
    Any wisdom to the best approach to this problem?

  • frank

    @Sam sorry about the difficulties, I have come across the same situation you describe a few times when installing modules. If trying /dev/build?isDev=1 does not work (it might give you a popup to log in) then perhaps remove the module folder and run it again. If its still not working try setting the admin password in _config. From memory its not a serious problem, your database should still be fine, I’ve gotten past this error before without too much trouble. Let me know how you go or hit up the IRC channel at #silverstripe on freenode.net.

    @John Cheers, not sure about the best approach to support multiple member types actually, I haven’t tried it myself. You could try using 2 member profile pages I can’t think why that would be a problem. Would be interested to hear what you go with.

  • Tee

    Great tutorial thank you. I’ve successfully extended the members class. Can you please tell me how I would add a radio button type field.

  • http://www.facebook.com/ryanseanbadger Ryan Badger

    has anybody else noticed that the email field when registering new users doesn’t have any “email” validation? with userfomrs we have this:

    public function getValidation() {
    return array(
    ‘email’ => true
    );
    }

    but with the member profile module, you can insert anything as an email and the form will still submit.
    I know you can enable the function to send email validation, but ideally I want users to be able to sign up without confirming their email address, but I also don’t want spambots gaining access by entering any old data into the email field.

    can anybody shed any light on this?
    sorry if my description is terrible, it’s 02:30am here and I’ve been coding for about 2 days straight.
    cheers!

  • will barker

    Hello, Thanks for this – good write up.

    Couple of questions – How do i link to my profile – as in view rather than edit – once i am logged in?

    Also, when on the edit page, there is a link to change password with the fields beneath it – looks like the link is supposed to show / hide the fields? is that right? any ideas why the password fields show up all the time?

    finally – the password fields are populated with their values – so big list of stars – looks a bit clunky. shouldn’t they be blank?

  • Will barker

    oh, yikes, im a moron.

    so i applied the JS addition to hide / show the password fields. So now the fields are hide & showing password is saving properly.

    still, the passwords are in the fields as a hash. would be neater if they didn’t.

  • Anonymous

    Hey Will, the module uses SilverStripes built in PasswordConfirmField btw. I agree it would be neater if the password fields weren’t populated with the password hashes from the DB, I’ve tried playing around and changing the behaviour of the PasswordWonfirmField but its a bit fiddly.

  • Pascal

    I had to find out ‘the hard way’ that this module needs the orderable module to work…

    might be worth the mention, thanks though, seems like a great module!

  • http://unraveledideamill.com Unraveled Idea Mill

    I’ve been searching for information on how to add a boolean “accept terms” field to the registration form for a while. The only problem is I had everything set up as you suggest and the form will submit and register a user whether the field has been checked or not.

    Has anyone else run into this? Thx.

  • Mauricio Padilla Gutierrez

    how can i customize it? i’ve tried several things and i think i’m not doing anything at all, i could add an dropBox with some of my data( hell yeah ), but i can’t get rid of the locale interface, the date format and that stuff that i don’t need…i’m also triying to login while i’m log in as admin, but it messed up my admin login form, i can’t understand :( pleaseee give me some guideeee :(

  • Anonymous

    You can customize Member using DataObjectDecorators. If you look in that class there is an updateCMSFields which you can use to remove fields like locale, date formats etc. from the admin interface for editing members.

    If you accidentally reset your admin password and that is preventing you from logging in you can use: Security::setDefaultAdmin(‘admin’,'password’); in the _config.php to set the admin password. Hope that helps.

  • Mauricio Padilla Gutierrez

    thanks for the response, but it’s no what i was looking for :/ … when i’m logged the page displays some lorem ipsum and stuff like that, and i want to remove that and instead place my own texts, and i don’ know where i have to modified it!

  • Anonymous

    thats a tricky one, sorry I can’t really help you there. search is your friend I guess – the filesystem and the DB.