Last updated February 13, 2013. Created by queryblitz on December 30, 2011.
Log in to edit this page.

This tutorial will show you how to set up a small online store using UserPoints as your currency. The best part is you won't have to use a big e-store module like Ubercart - just follow this tutorial and use the modules listed below:

Flag
UserPoints
Token
Rules
Better Message Action for Rules
Taxonomy
CCK
Views 2.x.

Note: This tutorial also allows for returns. If you don't want to allow returns on your site, ignore the parts in italics.

Step 1.
Install and enable the listed modules, and also enable number fields CCK field. Then go to /admin/settings/userpoints and set up a category for your UserPoints. For the rest of this tutorial, I'll assume you are calling your UserPoints "UserPoints" even though you can brand them however you want.

Step 2.
Create a node flag and call it "Purchase." Leave "Global flag" unchecked and fill out the rest, making sure to check the content types you want to use as store items. Set the link type to "Confirmation form" and adjust the other settings to your liking.

---------------------------------------------------------------------------
Returns:
To allow returns, you'll have to make sure you allow unflagging on the Purchase flag. You can set the unflag link to "Return Item" or something similar.
Also, you'll want to add another flag to keep track of who has purchased something, so that when they return it we can give them their points back. Call it "Can Return" and give it the same settings as the Purchase flag, except uncheck all the display options and instead of "Confirmation form" set the link type to "Javascript toggle."
---------------------------------------------------------------------------

Step 3.
Create a Store Item content type if you haven't yet, and add an Integer field to it. For Widget type select Text field. in the Help text section put "The price in UserPoints you want to charge to download this item." because that's precisely what we're going to use it for. Check "Required" and set the minimum and maximum prices allowed. Leave the Prefix and Suffix fields blank (we're going to use the token for this field later and we need a clean integer with no letters or symbols. You might be able to programatically remove the prefix/suffix from the token if you know how to do that, but you're probably better off just leaving this field as a simple integer and then theming it how you want it). Go to your permissions page and make sure that your users can view that Integer field. Otherwise they won't be charged for the items they purchase.

Step 4.
Add a new rule. We'll call this rule "Purchase." For the Event: select "A node has been flagged, under 'Purchase.'" LEAVE "Weight" AT 0! This is important. Add the condition "Compare current UserPoints." For the UserPoints category, select the category you created earlier. Expand "Token replacement patterns" and then expand "Replacement patterns for flagged content." Towards the bottom, find the token for "Formatted number value" which will be something like [node:field_price-formatted] (this is the token for the UserPoints price integer field we set up earlier). In the Amount to compare, place that token. Add the action "Grant QueryPoints to a user." Of course, ensure that "flagging user" is selected, and for "Number of points:" put a minus sign and then that same token.
Like this: -[node:field_price-formatted]
That's going to charge your customers the amount you specified in the integer field above.

---------------------------------------------------------------------------
Returns:
To allow returns, add another action to this rule - "Flag a node." For the flag select the "Can Return" flag, and leave the rest of the settings alone.

---------------------------------------------------------------------------

Step 5.
Now we need to handle users who try to purchase when they don't have enough points. Add a new rule. We'll call this rule "Cannot Purchase." For the Event: select "A node has been flagged, under 'Purchase.'" CHANGE "Weight" TO -10! This is important. Add the condition "Compare current UserPoints." Leave user as "flagging user" and select "Negate." For the UserPoints category, select the default. In the Amount to compare, place that same token.
Like this: [node:field_price-formatted]
Add the action "Unflag a node." Choose the flagged content and flagging user, and the flag "Purchase." Add the action "Send a message" and for the message put: "You must have [node:field_price-formatted] UserPoints to purchase this item." without the quotes. Replace my token with yours.

---------------------------------------------------------------------------
Returns:
For returns, you're going to add a rule that will occur when "A node has been UNflagged, under "Purchase." Call it "Return" and set the Weight to 10. Add the condition "Flag "Can Return" is flagged, for flagged content." Add the action "Grant UserPoints to a user." User is "flagging user," and for "Number of points:" put that same token, but this time without the minus sign (because we're giving points back not subtracting them). Add another action "Unflag a node." For the flag select our Can Return flag, and leave the rest of the settings alone.

---------------------------------------------------------------------------

Note: The reason the weights are important is because Rules needs to run them in order. Otherwise, when your users purchase an item, it will run the Purchase rule, then it will check again to see if they have enough points when it runs the Cannot Purchase rule. If they don't have enough points to purchase it again then it will give them the Cannot Purchase message even though they just purchased it. You want it to run the Cannot Purchase rule first instead, THEN the Purchase rule. So make sure that on your "Triggered rules" page, the rules you just created are in this order:
1.
Cannot Purchase
2.
Purchase
3.
Return
If these are not in order, go back and fix them.

Step 6.
Create a View for your store, add a page display, and using this tutorial, integrate your Purchase flag so users can click the "Purchase" link from the page view.

Now you're all done! Grant yourself some UserPoints, then try it out.

Note: As UserPoints can't be given to anonymous users, your UserPoints store will only work for logged in users. To grant UserPoints retroactively once they register for things the user did before registering, see this tutorial. You can use the handy but confusingly-named Flag anonymous module to display a "Login to purchase" link to anonymous users. Just make sure that if you have any other flags that anonymous users CAN use, that you fill in the "Anonymous link text:" field of those flags with that flag's normal flag link text. Otherwise, as that module hijacks the flag link display for anonymous users, nothing will display wherever that flag is displayed.

You can try this entire setup out at queryblitz.com. Register and click "STORE" once you validate via email.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

This is phenomenal, and timely for me. Thanks to the author.

I have some notes from my walk through this doc to my now working Ubercart with Purchase with Userpoints.

Install and enable taxonomy and userpoints_nc if you care about categories for points, like if you want to allow using a certain type of points for shopping, and not another.

Where it says Store Item content type, you'll probably find that to be == "Product"

Must enable CCK, including Number, Text, and maybe Groups (not sure)

"On the permissions page"...the specific permissions, I think , are "view * userpoints"

price-formatted...price is the field name you created. Copy the whole bracketed string into your copy buffer with Ctrl-C or whatever, you will use it 5 or so times pretty soon.

In Site Configuration /admin/settings/userpoints ....set Ubercart Payment Options to use the correct category of points.

Install and Enable Better Message Actions for Rules, which seems to be implied, but not stated.

Ubercart, depending whom you ask, may have recommended modules of FileField, ImageField, ImageAPI, ImageCache

I find Plugin Manager to be very helpful in locating and installing.

Generous Thanks, again, to the author.

The tutorial is a bit rough, I was up til 3 a.m. posting it. Yes, I forgot to mention Better Message Action for Rules, or "Rules Better Message" as it displays on your modules page.

Can we see your site? I'm curious.

You're very welcome, btw. Thanks for pointing out some things I missed. I'll edit it to fix that.

Andrew Fisher

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Hey Andrew, I PM'd you a link to my store in progress.

If you get those instructions merged, it should be possible to whiz through them in about an hour, I think, and that would give others an opportunity to help refine these instructions.

Hi Andrew,

Your post was like a dream come true for me, Thank You so much!

I'm building a site for my local community here in Spain. Planning also to use local community "currency" (userpoints) to provide community members a way to trade between each other (mainly services but goods as well). Your "recipe" of functionality seems to be just I've been hoping to be able to accomplish.

Thanks again, I'm seeing the light in the end of the tunnel again, you've been Great Help for me (noncoder newbie)! ...if you like pizza & beer, please provide me with your PayPal email!

Kari from Sunny Spain :)
http://tasapeli.org
(the site in question... sorry for the language, it's Finnish ;)

Glad you were able to get it working! Come back and post any additional tips or questions for me or anyone else if you run into any new challenges.

edit:
Wow thanks! Very much appreciated!

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

I'm glad you liked the pizza & beer ;)

See the child page for the tutorial.

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Thanks for this great tutorial! I followed it word for word and the functionality works. The only thing that I can't seem to get to is the actual transaction between logged in users. I created some fake products with pricing using my admin account then purchased the item with another authenticated user. But I cant seem to see the points moved from one accout to the other, am I missing something?
Thanks!

You don't need to send the points from one user to another. You can charge one user points, and give another user points, but you do it separately. Points are really just a number your system assigns to a user, so you'll just have to change that number by adding to it, or taking away.

We are already charging the user who purchases the item, so we just need to give points to the item node's author when the purchase flag is clicked.

You're going to have to set up a rule that gives points to the author of the "Store Item" node when another user has flagged that node with the purchase flag. You can even do some neat stuff with that, like paying them a percentage of the price the Store Item costs instead of the whole amount. You can do this by editing the Purchase rule and adding two actions.

First, add the action "Load the content author" and choose "flagged content." That's it.

Then, add the action "Grant points to a user." For the user, choose "flagged content author." For the number of points, this is where you can do neat stuff. On my site, I just put the [node:field_price-formatted] token, but you can put whatever token you want. You can even use Custom Tokens to create one that has a mathematical equation in it, I think.

Hope that helps.

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Thanks so the great feedback and direction! The re-distribution of points is working perfectly! Your instruction simple, clear, and exact- just what people need when working with some Drupal's relatively complex mechanisms.
Now for an added level of complexity:
Based on points purchases, do you know of any rules I can apply that can change ownership of the node that is being purchased?
For example: user A 'purchases' a store item created by user B, how can that store item then be now 'owned' by user A and appear in thier profile or store? Is this possible?

Add another Action to that same Purchase Rule. For the Action, choose "Set the content author." For "User, who is set as author:" choose "flagging user."

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Thanks again for the great advice!
If I wanted to"charge" a user points for posting a store item,would I add an action in the same way?
Do rules allow for additional layers of diversity? Say, to distinguish different points "charges" for different store item types? I am thinking that it would have to identify the specific store item type based on a pre-determined selection at the store item menu level, in which case a specific rule would then have to be applied to each.

You can set up a rule to charge users to post an item.

For each rule, choose the Event "After saving new content." Add a condition "Content has type" and then choose the type you want to charge for. Add the action "Grant UserPoints to a user." Just grant a negative number and that will work.

I actually added two Grant UserPoints actions for each of my rules. One I call the pricing fee and one I call the posting fee. The pricing fee is a negative token that depends on the price of the item being posted, and the posting fee is a set fee that is just a negative number.

If you want to charge different amounts for different content types, you'll want to create a rule for each type. Make sure you name all your rules understandably, because it gets confusing when you have lots of them.

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Thats great, the rules apply directly to the content type, but what if I want to set a cost for a particular taxonomy term that has been selected within the store item page? What I am trying to get away from is to create a long list of store item types for users to select, in order to apply points accordingly.
Allow me to illustrate an example:
- Users have the option to create store items (lets say apps) to be "sold" for points.
- They have the option to select the type of app (via taxonomy terms).
- Within the "store item" building page, the user selects the "Apple" product type (from the taxonomy list)
Challenge: how can a rule be set to charge a particular point amount for that specific category, rather than create various (and therefore charge for) store items?
As it stands now, Iam able to charge an amount to the "seller" or user posting the item to sell, but it is based entirely on the Editing Condition of 'Content has type only' which is limted to selecting the Content Type of 'store item'
Does the capability exist to set a rule to lok for a specific term or option selected within the content type in question?

There are two ways to do this. They are both Conditions that you would add to the Fee Rule (the rule you created to charge for posting a store item). On that rule, first ensure the Event is "after saving new content," then add one of these conditions. Here they are, as far as I understand.

1. Add a condition to the Fee rule. Choose "Textual comparison," and click Next. On the next page, where it says "Two texts to compare:" first put the token for the vocabulary term you want to charge for, which is [node:term]. In the next place just write out the term itself. The rule will compare the node's term with the term you typed, and if they match, it will validate as TRUE.

OR

2. Add a condition to the Fee rule. Choose "Execute custom PHP code," and click next. On the next page, where it says "PHP Code:" copy and paste this:

foreach ($node->taxonomy as $term) {
  if (strtolower($term->name) == 'lowercase_taxonomy_term') {
    return true;
  }
}
return false;

Of course you'll need to replace lowercase_taxonomy_term with the actual term you are checking for, in lower case.

One of those should work for you.

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Thanks so much for all your help on this. Everying has work perfectly! I will be adding checkout functionality such as enabling sellers to verify and approve purchases, as well as auctioning options.
Will send along a link when I;ve got it cleaned up for you to take a test drive!
Thanks again!!

I'm trying to do this in D7 and I couldn't find this condition in D7 "Compare current UserPoints". Userpoints conditions simply doesn't exist when the event has to do with flag. has anyone else noticed this?

You should be able to get it to work. Check this thread: http://drupal.org/node/1109992 especially this comment: http://drupal.org/node/1109992#comment-5396204

Do mention if you get it to work. I don't use D7 but I'd like this tutorial to work for everyone.

Thanks!

edit: Oh I noticed you're already there. Any luck?

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Thanks for your response. I took a look at the link,it feels like so many rules steps just to get this one condition working. I'm a bit lazy right now to set it up but I will give a feedback once I do.

Great tutorial thanks a lot. Much appreciated! :-)

I do however experiencing some problems trying to set up a store with userpoints in two categories, default- and bonus-points.
The users have to pay using the default points to begin with, and when they run out it should start deducting from the bonus-points. But I can't seem to get it working properly. I know it is a matter of setting up your rules correct, but this has been bothering me for some time now and can't seem to find the right setup.

Hope somebody might be able to help me sort this out.

create a rule that award points to users when they sign up.

I am not trying to award points when user sign up but deduct in a specific order when purchasing content for them.

This is actually more complicated than one would expect. In order to do what you're asking, Rules has to check to see if the user has enough points, then if not, check to see if after adding their points from both categories, they have enough points. Then it has to calculate how many points they have left and subtract that amount from their account, and see how much of the cost that amount covered. Only then can it calculate the remaining amount owed and subtract that amount from the users bonus points.

There is a lot of math involved, and frankly I don't have the time to figure out how to make Rules do all that math. It seems like a Bonus Points module would be a great project though.

edit: as an alternative to coding a new module, you could perhaps do something on the display level. You might be able to hack the display of the current points and subtract the number of bonus points the user has from their default points before displaying them, so to the user they look like two different types of points. So if the user has twenty points, show them they have ten points and show them separately that they have ten bonus points. You'd have to use PHP or something, and some math, but I bet it's simpler than writing a module.

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

One step further to this, I have not found a way to add an approval step in the purchase process. What I mean is, can a rule be created to require the seller to approve a "purchase request" rather than the buyer being able to simply purhcase the product? This would provide some control in that the seller can be notified and approve the sale of a product.

As far as approval, I am not sure how to do that. I believe the Flag Friend module does this, but even then I'm not sure if you can use it to for nodes. What I'm thinking is you could have a "buy" node flag, and an "approve" user flag, and show the node author a View of all the users who have bought a node, then allow him to approve users. Problem is, if one customer purchases multiple items from the same seller, approving him for one item would approve him for all of the items.

edit: Ok I think I figured out how you can do it. Set up some sort of reference node that references the Store Item content type and set up Automatic Nodetitles for those referencing nodes and use the Token for the Node Author for the automatic title. Also, set up three flags, "Purchase" (not global, available for Store Item nodes), "Approve Purchase" (global flag, available for the referencing nodes), and "Purchase Approved" (not global, available on the Store Item nodes). Make sure customers can view the Purchase flag on the Store Item node view page. Set up a view that displays all the nodes referencing the current Store Item, and add the Approve Purchase flag to the view. Show that view only on the Store Item page, and only to the author of the Store Item node.

Set up a Rule to create a node referencing the Store Item content type whenever someone has flagged the Purchase flag. Set the author as the user who flagged the node. Then create another Rule so when the Store Item author flags the referencing node with the Approve Purchase flag, it flags the Store Item node with the Purchase Approved flag with the flagging user being the author of the referencing node.

Not sure if it will work, but I can't think of a better way, aside from coding a module, which I would avoid at all costs because I don't know how to do that. :)

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Hi Andrew,

Thanks a lot for your reply.

Didn't think it was that complicated to do but after you described it so thoroughly I think I might try the approach you suggested. Change it on the users views so they can see the points as you described.

Thanks a lot for your insights it made me aware of the difficulties trying to achieve this and considering other options. :-)

Thanks so much for all your help on this. Everying has work perfectly! I will be adding checkout functionality such as enabling sellers to verify and approve purchases, as well as auctioning options.
Will send along a link when I;ve got it cleaned up for you to take a test drive!
Thanks again!!

No problem! I'm excited to see what you come up with.

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

andrew,
I am just about ready to show off what i was able to develop, but I've hit a rules-points-based snag that I am hoping you could help with. its alittle off thr wall, but a pretty cool concept:
I have created a proximity view, which is used via gmap to display user nodes nearby based one's geolocation. I am able to also charge users for posting particular nodes, based on your advice on taxonomy rules.
I am looking to set a rule that basically says: if user A sets a location node within the proximity of user B's location node(s), then grant user B a set number of points based on the node type being created (users are able to post location points on a map, which automatically generates Long/Lat data)
my apologies if this is way off baswe for this forum, but I thought since it is an extendtion of the user points discussion, it might a realted (and fun) topic.
have you seen anything like this? I can clarify if anything seems illogical.
thanks!

andrew,
i think i've got it by applying a rule to a proximity search list, then applying points depending on the terms in that list.

And a little bit genius! I can't wait to see what you've got.

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Has anyone been able to implement this in Drupal 7? I first ran into the problem of that condition check how many points a user has was not listed. This was solved here:

http://drupal.org/node/1109992#comment-6634548

Now I am running into the problem that the "Compare the number of points the user has to this number" is an integer and there seems to be no way to select a field from a node where the price is entered. This was used with tokens in this example however I do not have any select token option.

Anyone know of a way to fix this?

SOLUTION:
I should have paid attention to the rules notes:
"The data selector helps you drill down into the data available to Rules. To make entity fields appear in the data selector, you may have to use the condition 'entity has field' (or 'content is of type'). "

I went back and used the "entity has field" condition then used an AND to also add "Compare the number of points the user has to this number". This then populated the field_price for me to select and use.

I refuse to work with Drupal 7 because it's both too easy and too difficult. It seems your problem is a perfect example. Did you run into any other issues getting this to work?

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

I am also having a problem with data selector: I want to grant a user with the negative amount of an integer field of a node. I cant select a negative value using data selector. If switched to direct input, I can't set a value like: -[node:field-price] (this is copy pasted from data selector list). When set, an error is given: Value must be an integer value.

Any ideas?

PS: To make sure of the field, I fetched node and set condition for node is a type having the integer field.

Sorry but I really don't understand what you're asking. Where are you finding this data selector problem? Do you have Token and Custom Token installed? I refuse to use Drupal 7 so I'm not even sure if those are in core or not, but can you give a little more info about your problem?

Oliver "Andrew" McCloud
http://queryblitz.com
Quick and easy feedback for your websites.

Did someone finally solved this problem please? I don't know how to charge points. Adding '-' before '[node:field-price]' doesn't allow me to save it because it doesn't read it as integers value...