I recently finished implementing a Drupal site that contained premium content, which a user can access only by purchasing a subscription. I am going to describe the general roadmap I followed to implement this, and while obviously somewhat specific to my situation, I think the guidelines provided can be easily adapted to many similar situations.
This is my first real use of the Drupal ecommerce module, and I am once again deeply impressed by the capabilities of Drupal and the many modules available. I was ultimately able to put my site together very quickly, with everything working smoothly.
Payment Gateways and Merchant Accounts
If by chance, this is your first ecommerce application, you will of course need to pick a payment gateway and set up a merchant account. Your bank can help you with the merchant account, which is just what it sounds like, a bank account to receive the millions of dollars of income from your Web site. The payment gateway takes care a actually handling the credit card transaction processing.
For the payment gateway, I have been happy with Authorize.net in the past, although on this particular project, the client had an existing PayPal account. I have mixed feelings about PayPal, but one intriguing possibility with PayPal is that they can act as both the payment gateway and provide a merchant account. Drupal can use either of these approaches as well as others.
Roles
One of the first things I did was settle on the roles I wanted in the system, through Administer -> User management -> Roles (at /admin/user/roles). In an effort to keep things simple, my first inclination was to author content with the admin role and allow anyone with the authenticated role to see restricted content. I quickly came to my senses, however, and saw that this was not really going to make things simpler.
Perhaps most obviously, I created a “content manager” role for the people authoring content on the site, so they would not be overpowered by the many options available to the administrator, and perhaps tempted to make changes to the site that they really shouldn’t. Even if you are going to be both the administrator and content manager, I would advise breaking these responsibilities into two roles in Drupal.
Then I created a “subscriber’ role. The idea behind the subscription purchasing process is that the customer is essentially buying a role in Drupal. As part of this purchasing process, the person has to register to create an account in Drupal so that when they return, we know they are a subscriber. So, its conceivable that someone could register in Drupal, obtaining the “authenticated” role when they login, but not purchase a subscription, which is why trying to make the authenticated role perform double-duty won’t work: potential subscribers still need to purchase a role that will enable them to view restricted content.
Remember to configure access control for each new role under Administer -> User management -> Access control (at /admin/user/access). More on this below.
Configuring Drupal for Ecommerce
Drupal has a mature ecommerce module and a number of other add-on modules if, for example, you don’t see support for your particular payment gateway. Once installed, go to your Administer -> Site building -> Modules screen (at /admin/build/modules) and activate the following sub-modules:
- All modules in the E-Commerce Core package.
- Your payment gateway choice.
- Generic Product.
- EC Recurring.
- EC Role.
You will now have two new menu items under Administer: E-Commerce, which is a reporting interface, and E-Commerce configuration (at /admin/ecsettings), which is just what it sounds like. Right off, you’ll want to check the values for your “Store” configuration, and for your particular payment gateway.
Now for the subscriptions themselves. Subscriptions are just “Non-Shippable Products” added like other content, through the “Create content” page. What makes it a subscription is that on the product creation screen you will associate it with a billing schedule and also indicate what roles are assigned at purchase, and what roles are removed at expiration.
So, the key thing to do before creating your subscription products is to create at least one billing schedule under the “Schedules” screen under Administer -> E-Commerce configuration. Schedules are where you specify how often to bill the subscriber (in my case, monthly), the number of allowed renewals, and when the subscription should expire. Additionally, you can configure each schedule to send reminder emails to subscribers.
From what I can tell, the ecommerce module adds cron tasks that are executed through cron.php to re-bill according to the schedule you created, so remember to execute the cron script on a regular basis.
Obviously, you can easily get fancier with this. Instead of just one “subscriber” role, you could have multiple roles–each with increasing access to content and capabilities within the Drupal instance–and charge more for subscriptions to the less restrictive roles. Its all just a matter of clicking through a few Drupal admin screens.
A Few Warnings.
As I mentioned, I happened to use PayPal for the site I created. A minor point is that PayPal actually has a recurring subscription capability as part of its service, and you might be expecting that the ecommerce module is using that, but it isn’t. As I said, the Drupal ecommerce module appears to handle recurring billing through cron tasks, and just creates regular ol’ transactions through PayPal.
Also, be sure to test your site by going through the checkout process yourself. For the site I developed, users could make donations anonymously, without the burden of registering, so I set my “Store” configuration to allow for flexible purchasing, then configured my subscription product to require registration, which should have overridden the overall Store setting. However, this just didn’t work, the product setting was ignored and people could “subscribe” without registering, which doesn’t make sense. (When they return to the site, they need to be logged in so I can check if they are a subscriber or not.) Since donations were a much less integral part of the site, and many of those donating would probably be subscribers anyway, I reset the Store to only allow purchases by registered users.
Its just a good idea to go through the checkout process anyway, to make sure you haven’t made a mistake along the way that will prevent sales. One thing to check for as you go through the process is whether the ecommerce module screens your users see are compatible with your theme. In my case, the shopping cart and several checkout screens were styled in such a way that the text and background color were the same! Don’t blame the poor theme author, he or she couldn’t test the theme with every module you might use. There may be a very clean, Drupalish way of adding custom CSS so it doesn’t inject code into someone else’s theme, but I didn’t have time to figure that out, so I just added the appropriate styles, commented, to the end of my theme’s style.css file.
Controlling Content Access
Hold on there, we’re not quite done yet. We still haven’t made it so that only subscribers can view content on the site! That’s because as we configured access control for the subscriber role, we only had the option of checking or unchecking the “access content” permission under the node module. The problem is, this isn’t very fine grained: we probably want anonymous users to see page content for example, so we can have a home page, but we don’t want them to see other types of nodes that hold our premium, restricted content. In the case of my site, the premium content is primarily blog entries, but it can be anything, like images, or a custom node type you created. So, we need to enable the “access content” permission for everyone, then figure out how to restrict access based on user roles and our particular site needs.
I’ve learned that whenever I need Drupal to do something it doesn’t already do out of the box, there is likely either a mature module I can install that provides the needed functionality, or there is a forum post describing what I need to do. If you are creating a subscription based site, I would encourage you to look at the premium module which allows node authors to restrict access on a node by node basis, under the “Publishing options” group. You can then limit access to premium content to subscribers through the user access control admin screens.
I tried the premium module, and it appeared to work exactly as advertised, and for most people, it will be exactly what you need to restrict access on a subscription based site. For my site, however, I have a few small edge cases that I felt I could handle a little better via the contemplate module, which I was already more familiar with anyway.
The contemplate module allows you to control how individual node types are displayed, which you can get a sense of by going to Administer -> Content management -> Content templates (at admin/content/templates). By default, Contemplates are configured to create teasers and RSS feed entries (with title and teaser) exactly the way I wanted, so I only had to focus on the full node (body) display: if a person has either the administrator, content manager, or subscriber role, they can see the full node body, if not, they can only see the title and teaser and for convenience, links to login or register:
function _isUserAllowedAccess($roles = NULL) { if ($roles == NULL || ! is_array($roles)) { $roles = array(‘administrator’, ‘content manager’, ‘subscriber’); } $isAllowed = FALSE; global $user; if (is_array($user->roles)) { foreach ($roles as $role) { if (in_array($role, array_values($user->roles))) { $isAllowed = TRUE; break; } } } return $isAllowed; } function displayPremiumBody($node) { // Check to see if $user has the administrator role. if (_isUserAllowedAccess()) { print $node->body; } else { // $node->teaser doesn’t work print node_teaser($node->body); print ‘<p> <a href=”/user/login?destination=node/’ . $node->nid . ‘”> Login </a> or <a href=”/user/register?destination=node/’ . $node->nid . ‘”> register </a> to view full content. </p>’; } } displayPremiumBody($node);
Again, this fits my particular needs, but it should give you a starting point for customizing your own node body access control via Contemplates. If you are new to Drupal, things to note include getting the user object with global $user and getting an array of role names for the user with $user->roles. You automatically have the node available in the $node variable. Also, note how I created the links for the login and registration forms. Finally, you might think, as I did, that you could access the teaser as you do the body, with $node->teaser, but you would be mistaken. Instead, you have to move up a level in Drupal and call the node_teaser formatting function on $node->body as shown.
Another word of advice, use file based contemplates instead of authoring PHP code directly in the admin interface. Even if you think you are only going to add a few lines of code, do it in a contemplate file. In my experience, what I expect to be the tiniest contemplate code block tends to grow, and I then quickly find myself trying to use an HTML textarea as a PHP IDE, which is not fun. Also, if you aren’t careful, even the slightest syntax error can make this admin screen, and other parts of your site, inaccessible, forcing you to directly access the appropriate record in MySQL to make a change to your template and gain access to the admin interface once again. Not that I ever did anything so foolish…
To create file based contemplates, you create a “contemplates” folder under your sites/all directory, or wherever your site specific files are. Each file follows a naming convention explained in the contemplates admin screen (at admin/help/contemplate#disk-based); in my case, I needed to control the body display for blog entries, so my file was “node-blog-body.tpl.php”.