New leaderboard CSS class added: achievements-leaderboard-current-user.
[project/achievements.git] / achievements.api.php
CommitLineData
6cdda368
MI
1<?php
2
3/**
4 * @file
5 * Hooks provided by the Achievements module and how to implement them.
6 */
7
8/**
9 * Define an achievement.
10 *
11 * This hook describes your achievements to the base module so that it can
12 * create the pages and caches necessary for site-wide display. The base
09abe3cf
MI
13 * module doesn't know how to unlock any of your achievements... instead, you
14 * use Drupal's existing hooks, the achievement storage tables, and a few
15 * helper functions to complete the workflow. See the remaining documentation
16 * in this file for further code samples.
17 *
18 * There are many different kinds of achievements, and it's accurate enough to
19 * say that if you can measure or respond to an action, it can be made into a
20 * matching achievement. Be creative. Look at what others are doing. Have fun.
21 * Your gamification efforts will fail or be un-fun if you don't have a gamer
22 * helping you, if you make everything a mindless grind, or if you simply
23 * copy achievements from another site or install.
6cdda368
MI
24 *
25 * @return
0d348f03
MI
26 * An array whose keys are internal achievement IDs (32 chars max) and whose
27 * values identify properties of the achievement. These properties are:
6cdda368
MI
28 * - title: (required) The title of the achievement.
29 * - description: (required) A description of the achievement.
30 * - points: (required) How many points the user will earn when unlocked.
0d348f03 31 * - images: (optional) An array of (optional) keys 'locked', 'unlocked',
43551281 32 * and 'hidden' whose values are image file paths. Achievements exist in
0d348f03
MI
33 * three separate display states: unlocked (the user has it), locked (the
34 * user doesn't have it), and hidden (the user doesn't have it, and the
35 * achievement is a secret). Each state can have its own default image
36 * associated with it (which administrators can configure), or achievements
37 * can specify their own images for one, some, or all states.
28acbf3e
MI
38 * - storage: (optional) If you store statistics for your achievement, the
39 * core module assumes you've used the achievement ID for the storage
40 * location. If you haven't, specify the storage location here. This lets
41 * the core module know what to delete when an administrator manually
09abe3cf
MI
42 * removes an achievement unlock from a user. If your achievement
43 * tracks statistics that are NOT set with achievements_storage_get()
44 * or _set, you don't have to define the 'storage' key.
6cdda368 45 * - hidden: (optional) The achievement is a sekrit until it is unlocked.
4fd35678
MI
46 *
47 * Achievements can also be categorized into groups. Groups are simply
48 * arrays whose keys are internal group IDs and whose values identify
49 * the 'title' of the group as well as the array of 'achievements' that
50 * correspond to that group. If some achievements are within a group and
51 * some achievements are without a group, the groupless achievements will
52 * automatically be placed into a "Miscellany" category.
6cdda368
MI
53 */
54function hook_achievements_info() {
512d7719 55 $achievements = array(
6cdda368 56 'comment-count-50' => array(
6cdda368
MI
57 'title' => t('Posted 50 comments!'),
58 'description' => t("We no longer think you're a spam bot. Maybe."),
09abe3cf 59 'storage' => 'comment-count',
6cdda368
MI
60 'points' => 50,
61 ),
62 'comment-count-100' => array(
6cdda368
MI
63 'title' => t('Posted 100 comments!'),
64 'description' => t('But what about the children?!'),
09abe3cf 65 'storage' => 'comment-count',
6cdda368 66 'points' => 100,
0d348f03 67 'images' => array(
512d7719 68 'unlocked' => '/sites/default/files/example1.png',
0d348f03
MI
69 // 'hidden' and 'locked' will use the defaults.
70 ),
6cdda368 71 ),
4fd35678 72
43551281 73 // An example of achievement groups: 'article-creation' is the group ID,
4fd35678
MI
74 // "Article creation" is the group title, and all relevant achievements are
75 // placed in an 'achievements' array. The ungrouped comment achievements
76 // above will be automatically pushed into a "Miscellany" group.
77 'article-creation' => array(
78 'title' => t('Article creation'),
79 'achievements' => array(
80 'node-mondays' => array(
81 'title' => t('Published some content on a Monday'),
82 'description' => t("Go back to bed: it's still the weekend!"),
83 'points' => 5,
84 'images' => array(
85 'unlocked' => '/sites/default/files/example1.png',
86 'locked' => '/sites/default/files/example2.png',
87 'hidden' => '/sites/default/files/example3.png',
88 // all default images have been replaced.
89 ),
90 ),
0d348f03 91 ),
28acbf3e 92 ),
6cdda368 93 );
512d7719
MI
94
95 return $achievements;
6cdda368
MI
96}
97
98/**
99 * Implements hook_comment_insert().
100 */
efac995d 101function example_comment_insert($comment) {
09abe3cf
MI
102 // Most achievements measure some kind of statistical data that must be
103 // aggregated over time. To ease the storage of this data, the achievement
104 // module ships with achievement_storage_get() and _set(), which allow you
105 // to store custom data on a per-user basis. In most cases, the storage
106 // location is the same as your achievement ID but in situations where you
107 // have progressive achievements (1, 2, 50 comments etc.), it's better to
108 // share a single place like we do below. If you don't use the achievement
109 // ID for the storage location, you must specify the new location in the
110 // 'storage' key of hook_achievements_info().
111 //
112 // Here we're grabbing the number of comments that the current commenter has
113 // left in the past (which might be 0), adding 1 (for the current insert),
114 // and then saving the count back to the database. The saved data is
115 // serialized so can be as simple or as complex as you need it to be.
116 $current_count = achievements_storage_get('comment-count', $comment->uid) + 1;
117 achievements_storage_set('comment-count', $current_count, $comment->uid);
6cdda368 118
09abe3cf
MI
119 // Note that we're not checking if the user has previously earned any of the
120 // commenting achievements yet. There are two reasons: first, we might want
121 // to add another commenting achievement for, say, 250 comments, and if we
122 // had stopped the storage counter above at 100, someone who currently has
123 // 300 comments wouldn't unlock the achievement until they added another 150
124 // nuggets of wisdom to the site. Generally speaking, if you need to store
125 // incremental data for an achievement, you should continue to store it even
126 // after the achievement has been unlocked - you never know if you'll want
127 // to add a future milestone that will unlock on higher increments.
128 //
129 // Secondly, the achievements_unlocked() function below automatically checks
130 // if the user has unlocked the achievement already, and will not reward it
28acbf3e
MI
131 // again if they have. This saves you a small bit of repetitive coding but
132 // you're welcome to use achievements_unlocked_already() as needed.
09abe3cf
MI
133 //
134 // Knowing that we currently have 50 and 100 comment achievements, we simply
135 // loop through each milestone and check if the current count value matches.
6cdda368
MI
136 foreach (array(50, 100) as $count) {
137 if ($current_count == $count) {
28acbf3e 138 achievements_unlocked('comment-count-' . $count, $comment->uid);
6cdda368
MI
139 }
140 }
141}
efac995d
MI
142
143/**
144 * Implements hook_node_insert().
145 */
146function example_node_insert($node) {
09abe3cf 147 // Sometimes, we don't need any storage at all.
efac995d 148 if (format_date(REQUEST_TIME, 'custom', 'D') == 'Mon') {
09abe3cf 149 achievements_unlocked('node-mondays', $node->uid);
efac995d 150 }
b830eedf 151}