Main menu

User points - Rules style

  • הדיון נעול: אין אפשרות לפרסם תגובות חדשות.
  • הדיון נעול: אין אפשרות לפרסם תגובות חדשות.
  • הדיון נעול: אין אפשרות לפרסם תגובות חדשות.

Nick Lewis wrote about his 40+ essential modules, and I really missed two modules there - Rules and Flag.
I commented that

My top 5 are: Views, CCK, Flag, Rules, Panels. I think that the Flag & Rules combo is less known in the community, but there are so many use cases they can cover. Because they are a bit abstracted it's hard for newbies to realize their potential.

I think there's no better way to show my point, than a tutorial. Lazy people can even download the feature from here. This tutorial will be about having "User points" functionality without using the user points module. I'm not saying that module is bad, but sometimes I need multiple user points per user. Also, re-using existing modules always feels me with great joy. GREAT joy! Also, thinking about Drupal 7 with fields API, suddenly user points can become any-fieldable-entity points...
The tutorial will cover the "Rule sets" concept in Rules module, which is also considered by many as a great mystery. Let's define our mission:

  1. Every time a user creates a story content type, one point is deducted
  2. When no points are left, user should not be able to create more stories
  3. Upon content profile creation, the user receives three points
  4. Site admin should be able to "reset" the points of users back to three points

If your eyes no longer see the above list as words, but as Drupal modules, then you probably think CCK, Content profile, Rules and Flag.
We will add a content profile to each user. That profile will have a CCK field that will hold the user points. When user points reach zero, a "story editor" role will be removed from the user - denying access to creating new story content.
For "reseting" the user points, we will use a flag on the user, that a site admin can click on.
First preparations:

  1. Download and enable modules (is there still anybody not using Drush?)
    drush dl cck content_profile rules flag-6.x-2.x-dev features ctools strongarm-6.x-2.0-beta3
    drush en -y content number content_permissions content_profile rules rules_admin flag features php ctools strongarm
  2. Make the new "Profile" content type a user profile through admin/content/node-type/profile >> Content Profile >> Use this content type as a content profile for users
  3. Add a new Integer type field called field_user_points to the profile content type
  4. In admin/user/roles add a new role called "story editor".
  5. We should carefully take care of the permissions. In admin/user/permissions - allow "authenticated user" role to view field_user_points and create profile content; and allow "story editor" role to create story content

Before we set up our logic using Rules Let's go over a bit about the concept of "Rule sets".
You should think of a rule sets as an API function. That function gets arguments and processes them. It's up to an implementing module to use the API function properly. Like API functions rule sets are there in order to prevent duplication and to centralize actions. Let's make the idea clear by thinking about points 1 and 2 in our mission. We have here two rules - one will deduct points from the user's profile, and the other should remove the "story editor" role.

We could create two triggered rules both with the event "After saving new content", and check in both rules that the content type is story. As you can see, there's a duplication in the event and in the conditions. If our logic will change and be more complex the duplication might increase.

So, for such a case we will use the rule sets. We'll define two arguments that are mandatory one is a node, in which we'll pass the content profile. The other is the user. If you are a developer then think of it as function user_points_logic($profile_content, $account).

In this rule sets we will add our two rules without even bothering to check if the new created content is indeed "story". For that we'll have a third rule, that will not be a rule inside a rule sets, but a triggered rule. This rule will be executed "After saving new content", will check the condition of the content type is story, and then willload the user's profile content and invoke our rule sets.

In terms of code, think of it as calling user_points_logic() from hook_nodeapi() upon node insert. Now that the concept should be clear, let's see how we do it:

  1. Make sure you enabled the "PHP filter" core module, as we'll need few lines of PHP
  2. Add a new rule sets (admin/rules/rule_sets) labeled "User points" with content and user arguments.
  3. Add a new rule in the "User points" rule sets labeled "Deduct points on story creation" and add the action Populate a field, select the field field_user_points and continue
  4. Under "Advanced: Specify the fields value with PHP code" enter the following code (without the <?php ?> delimiters):

    <?php
    // Current user points.
    $current_points = $profile_node->field_user_points[0]['value'];

    // Remove one point.
    return array(
     
    // Rules will make sure the content profile is saved
      // after all rules have finished executing.
     
    0 => array('value' => ($current_points - 1)),
    );
    ?>

  5. Create the second rule in the rule sets labeled "Remove role when no user points left" with the condition Field has value, and again select field_user_points. In the field value enter 0
  6. Add action Remove user role and select "story editor" role
  7. Points 1 and 2 in our mission are almost complete, we only need to call the rule sets when appropriate. Create a triggered rule (admin/rules/trigger) labeled "Invoke user points" with the event After saving new content (we don't want to deduct point when user is just updating an existing content). Add condition Content has type to check it's a story. Add action Load content profile and make sure the argument User, whose profile should be loaded is set to content's author - we do that as the acting user might be an admin manually creating a new user. Second action is User points which is our rule sets. Also here make sure you pass the correct arguments (i.e. content profile for the content argument and content's author for the user argument).

The implementation of "reset" points and grant points on user registration is similar in concept to our previous mission. We create a rule sets labeled "User points grant" which will set the field value to 3 and grant "story editor" role. This rule sets will be called from two different triggered rules - once upon content profile creation, and second when a site admin will "reset" the user points. How will the site admin "reset"? Easily - we'll create a new user type flag called "Reset user points", and in Rules create a triggered rule that is invoked on the event A user has been flagged, under "Reset user points".

That's it. Download the feature, and add your own logic.

--
Notice if you download the modules manually to use Flag module with version 6.x-2.x or higher and strongarm version 6.x-2.x or higher.

תגובות

Performance of rules vs userpoints

I too already have flags and rules installed and I like the idea of using existing modules vs adding userpoints. However how does the performance compare if we were to create a lot of rules to handle userpoints vs the userpoints module?

why?

Now the question that pops to my mind is what's the goal?

And i answer to myself (it's late and no one else is here) the goal is to create the system with minimal complexity.
(which is relevant ofcourse to the people maintaining the system and their preferences)

Not to implement the given spec with minimal coding - because at a certain point you're just coding with drupal modules + rules + sets
which is harder to debug & maintain.

The triggering is brilliant
but i would rather have some simple code saying
deduct a point - if 0 - take off the storyEditorRole

wouldn't it be more clear?
maybe not?
first comment @here
ראשון שולתת

@hed, > you're just coding

@hed,
> you're just coding with drupal modules + rules + sets

I agree, as I later export it to code, just as I do with Views, I consider it coding.

> ...which is harder to debug & maintain.

Debug isn't necessarily harder thanks to Rules debug -- which I find sometimes faster than starting to xDebug code.
About maintaining I disagree. When you are used to working with Rules you can also do the changes directly via the code export. Also to maintain it I don't need to hire a developer, as no coding is involved.

> but i would rather have some simple code saying

Same argument for why using Views even if it would be faster for you to write a simple SQL query.

"Also to maintain it I don't

"Also to maintain it I don't need to hire a developer, as no coding is involved."
this i feel to some extent is self disillusioning.

Coding is not just the language, but is also complexity, debugging and mental state.

If giving a client a complex site in which there is a lot of business logic made up from Rules.
The client will not only be needed to hire a developer, a drupal developer but as well one who is acquainted with the module.
And i bet that even for this developer it would have been easier if it was debuggable code.

Complexity is physical entity.
Nothing can become simpler than it really is.
חוק שימור הסבוכיות

Rules debugging is GOOD.
Any decent rules engine has to have a debugger.

Need to really touch it to know better
Maybe at your course!

> this i feel to some extent

> this i feel to some extent is self disillusioning.

You say "self disillusioning" like it's a bad thing! ;)
But seriously, I used Views way before I knew how to write SQL queries. Views can also become complex and need some knowledge.

With that said, my goal in this tutorial wasn't to talk only about the "user points" use case, but more about showing it's true power. Now it's up to you to decide if you join the ride -- yeah, come to my course (Tel-Aviv) and we can argue some more :P

Great tutorial

Flag is a powerful module - even without Rules. Your tutorial shows how much can be achieved by connecting these modules intelligently.

At www.GlobeDweller.com we use Flag to connect user with content so choosing a particular country will show the users that have flagged it (i.e. chosen it as a country they have been to), that way people not finding the help they need from the content itself will have a list of people with actual experience of the country. On the other hand if people go to the user profiles they can see where people have been.

Ideal for business directories

Thanks for the tutorial. This seems like an excellent solution for restricting paid accounts to making a single entry in, for instance, a business directory.

Yap, it also works great in

Yap, it also works great in complex e-commerce sites.

Relative link

the link to nick lewis is relative, make it absolute!

10x, fixed.

10x, fixed.