[This page contains some random notes. When more material is gathered, it will be revised.]

Contents:

First and foremost

Flag provides some API functions. At some point we switched to use object oriented programming (OOP). Some functions don't have equivalent methods (yet?).

To work with a flag you first need to get your hands on a "flag handler":

$flag = flag_get_flag('bookmarks');

The parameter to flag_get_flag() is the machine-name of the flag. If no such flag exists, NULL will be returned.

Discovering whether a piece of content is flagged

Use the is_flagged() method to find out if an item is flagged.

This can be very useful in 'node.tpl.php', when you want to theme flagged nodes differently than non-flagged ones.

Examples:

<?php
$flag = flag_get_flag('bookmarks');

if ($flag && $flag->is_flagged($node->nid)) {
  print "This node is bookmarked!";
}


$flag = flag_get_flag('idiots');

if ($flag && $flag->is_flagged($node->nid)) {
  print "The author of this node isn't very smart!";
}


$flag = flag_get_flag('idols');

// Note the optional second parameter to is_flagged(), which allows
// us to ask if an item is flagged on behalf of a certain user. If this
// parameter isn't provided, the check is made against the current user.
//
// If the flag is "global", this second parameter is ignored.
//
if ($flag && $flag->is_flagged($node->uid, $GLOBAL['user']->uid)) {
  print "This author venerates you!";
}

// flag::is_flagged() uses a caching mechanism so it's efficient.
?>

You use flag_create_link() for this. See the separate page, Placing a flag link on a page.

Getting the number of times an item is flagged

Whenever an item is flagged, or unflagged, a counter field is updated. To read this counter, use the get_count() method:

<?php
$flag = flag_get_flag('votes');

if ($flag) {
  print "The number of people who voted for this proposal:";
  print $flag->get_count($node->nid);
}
?>

A different approach is to use tokens. This module provides a count token for each flag, and you can use it in email messages, for example, and in every place that accepts tokens:

<?php
Hello, [node-author].
Your post has been bookmarked [flag-bookmarks-count] times.
?>

A different method, get_user_count(), is used for counting the items a user has flagged. This method is less efficient than get_count() because an SQL COUNT query is issued.

$flag = flag_get_flag('votes');

// We assume an $account variable exists in this template.

if ($flag) {
  print format_plural($flag->get_user_count($account->uid),
    'This user has participated in 1 voting.',
    'This user has participated in @count votings.');
}

Flagging or Unflagging an item

You use the $flag->flag() method to either flag or unflag an item. Example:

<?php
$flag = flag_get_flag('bookmarks');

// Flag node #456:
if ($flag) {
  $flag->flag('flag', 456); 
}

// Unflag node #456:
if ($flag) {
  $flag->flag('unflag', 456); 
}
?>

The signature of this $this->flag() method is:

<?php
function flag($action, $content_id, $account = NULL, $skip_permission_check = FALSE)
?>

A complete and up-to-date documentation of it is in the Doxygen. But, in short: $action is the action you want to carry out; either 'flag' or 'unflag'. $content_id is the identifier of the item. $account is the user on whose behalf you want to carry out the action (This parameter is only meaningful when using a non-global flag). Please note that this is the user object, not the uid. The last parameter of this method is important when flagging/unflagging a node as an non-privileged user, such as in a hook_cron() implementation where the server runs as anonymous and permission checks would fail silently without $skip_permission_check = TRUE.

This method returns FALSE if some error occured (e.g., the user has no permission to use this flag; flag isn't applicable to the item; etc.). Note that it isn't an error to flag an item that is already flagged (in this case the method will do nothing, but it will not return FALSE).

Responding to a flagging

Any module may react to a piece of content being flagged by implementing hook_flag().

mymodule_flag($action, $flag, $content_id, $account) {
  if ($action == 'flag') { // Or $action == 'unflag'.
    // Do something in response to the flagging.
  }

  if ($flag->name == 'yourflagname') {
    //Do something if the flag is "yourflagname". Example "Bookmark".
  }

}

Flag module actually implements its own hook in the flag_flag() function in flag.module. You might use it for reference when creating your own version.

Creating a Flag in the Database

To create a node flag in the database, create a flag from the flag_flag class, modify the defaults, then save with the $flag->save() method. Note that you can also create

  $flag = flag_flag::factory_by_content_type('node');

  // Absolutely required, will break your site if not added properties.
  $flag->name = 'my_flag_name';
  $flag->title = 'My Title';

  // Properties required by the UI.
  $flag->roles = array(2); // An array of role IDs. 2 is for "authenticated users".
  //in D6 and D7 : $flag->roles = array( 'flag' => array('2'), 'unflag' => array('2') );
  $flag->types = array('story', 'page'); // An array of node types.
  $flag->flag_short = 'Flag this';
  $flag->unflag_short = 'Unflag this';

  // Optional properties, defaults are defined for these (and more).
  // Use a print_r() or dsm() to see all the available flag properties.
  $flag->global = TRUE;
  $flag->flag_long = '';
  $flag->flag_message = '';
  $flag->show_on_form = TRUE;
  $flag->show_on_node = TRUE;
  $flag->show_on_teaser = TRUE;
  $flag->link_type = 'toggle'; // For JS link. Other options: 'normal' and 'confirm'.

  // Save the flag.
  $flag->save(); 

Can do something similar for user flags (here's an example in an update function) - and can also use a values array instead of setting attributes:

function mymodule_update_6100() {
  $ret = array();
  $flag = flag_flag::factory_by_entity_type('user');
  // Unique, machine-readable name.
  $flag->name = 'unverified_user';
  $values = array(
    'flag_short' => 'mark as unverified',
    'flag_long' => '',
    'flag_message' => '',
    'flag_confirmation' => '',
    'unflag_short' => 'mark as verified',
    'unflag_long' => '',
    'unflag_message' => '',
    'unflag_confirmation' => '',
    'link_type' => 'normal',
    'show_on_profile' => 1,
    'global' => 1,
    // A user flag doesn't support node types.
    'types' => array(),
    'roles' => array(2),
    'title' => 'Unverified user',
  );
  $flag->form_input($values);
  $flag->save();
  $flag->enable();
  $ret[] = array('success' => !empty($flag->fid), 'query' => 'Created user flag ' . $flag->name);
  return $ret;
}

Note: If you create a flag in an update hook or in hook_install() and want to immediately use it you must first call flag_get_flags() to reload Flag's static cache of flags, otherwise flag_get_flag() won't find your new one. E.g.:

...
$flag->save();
flag_get_flags(NULL, NULL, NULL, TRUE);  // Force the new flag to be loaded
...

Creating a Module-Based Default Flag

Flags can be included in modules by implementing hook_flag_default_flags(). By defining a flag in code, the developer can "lock" certain properties of a flag and ensure that a flag is available for the module to use. Any "locked" properties will not be shown on the flag configuration form.

function mymodule_flag_default_flags() {
  $flags = array();
  $flags[] = array(
    'content_type' => 'node',
    'name' => 'starred',
    'title' => 'Starred',
    'roles' => array('2'),
    'global' => FALSE,
    'types' => array('story', 'blog'),
    'flag_short' => 'Star',
    'flag_long' => 'Add this your starred list',
    'flag_message' => 'Added to your starred list.',
    'unflag_short' => 'Unstar',
    'unflag_long' => 'Remove this issue from your starred list',
    'unflag_message' => 'Removed from your starred list.',
    'show_on_page' => TRUE,
    'show_on_teaser' => TRUE,
    'show_on_form' => FALSE,
    'status' => FALSE,
    'locked' => array('show_on_teaser', 'name', 'types', 'roles', 'global'),
  );
  return $flags;
}

How to Delete a Flag

If you create a module which creates a Flag you would also want to be able to delete that flag when the Module is Uninstalled. The code below will allow you to delete a flag:

<?php
//First you have to load the flag that needs to be deleted:
$flag = flag_get_flag('bookmarks');

//If the flag does not exist then NULL is returned
if($flag) {
     $flag->delete(); // If the flag exist then delete the flag
}
?>

Comments

vertazzar’s picture

Im trying to make this code work...

<?php 
function popups_admin_flag($action, $flag, $content_id, $account) {
  //Example values.
  $points = 10;
  $my_flag_name = 'aplauz';

  //Pseudo-code.
  if (module_exists('userpoints')) {
    if ($flag->name == $my_flag_name) {
      //If unflagging, remove userpoints.
      if ($flag_status == 'unflag') {
        $points = -$points;
      }
	    if ($flag_status == 'flag') {
        $points = $points;
      }
      if ($flag_type == 'comment') {
        $comment = comment_load(array('cid' => $flagged_item_id));
        $uid = $comment->uid;
        $account = user_load(array('uid' => $uid));
      }
      else if ($flag_type == 'user') {
        $account = user_load(array('uid' => $flagged_item_id));
        $uid = $node->uid;
      }
      else {
        return;
      }
      userpoints_userpointsapi('points', $points, $uid, 'flag-'. $flag->name) ;
      drupal_set_message(check_plain($account->name) .' was awarded '. $points .' points thanks to your '. $my_flag_name .'.');
    }
  }
}

?>

what im doing wrong ?

edit:
nvm issue fixed.

mikey_p’s picture

Couldn't you just use

<?php

if ($flag = flag_get_flag('flagname')) {

// do flag stuff here

}

as the simplest conditional?

vertazzar’s picture

its ok i found the way, that code i pasted was posted long time ago by someone...

YK85’s picture

hi vertazzar,

can you please share the code you ended up using for the benefit of the community?
i'm trying to learn all of this at the moment and having a hard time.

thanks!

vertazzar’s picture

I found the way with rules module. You can http://drupal.org/project/userpoints_contrib to get userpoints rule integration, than after that you can set

e.g.

After comment is flagged by XXX Flag.

DO:

user_load - echo $comment->uid;

userpoints +10 or -10 whatever.

You can also use

<?php
mymodule_flag($action, $flag, $content_id, $account) {
$user_id = db_result(db_query("SELECT uid FROM {comments) WHERE cid = %d", $content_id));
  if ($action == 'flag' && $flag->name == 'yourflagname') { // Or $action == 'unflag'.
    // Do something in response to the flagging. e.g. db_query
 // just to know , while im typing this, i dont know name of userpoints table and its fields, so you can find for yourself and replace.
 db_query("UPDATE {userpoints} SET points = points +10 WHERE uid = %d", $user_id);
drupal_set_message(' '.$account->name.', your flag '.$flag->name.' awarded User ID '.$user_id.' with 10 points. ');
  }
}
?>
YK85’s picture

thank you very much!

Gabriel R.’s picture

In addition to this http://drupal.org/node/305086#flag-counts, it's worth noting that if you are using tokens on the Flag definition labels, you can create a dynamic counter for the total number of likes.

[flag-like-count] Like will return you 123 Like with the 123 changed with Ajax as you use the link.

schvili’s picture

Hi!

I must be doing the most simple thing possible with flags. I want to unflag a content as another user.

The flag exist, since it outputs on print_r($flag); I am using Flags 1.12 Any idea?

$flag = flag_get_flag('interested') or die('no "interested" flag defined');
$flag->flag('unflag',3576,888,TRUE);
 
mooffie’s picture

You have to pass (as the 3rd argument) the user object. You're passing the user ID instead (888). Do user_load() to get the user object.

schvili’s picture

Thank you! It worked just fine. Amazingly fast response :)

moejarv’s picture

I am trying to create a link that will flag two flags at the same time. I know that likely I will need to do it in customfield as I need the link in a view, but even after reading the API docs for PHP, I can't find a simple way to flag two things at once.

Is there an easy way to create one link that flags two flags with AJAX refresh in views?

Thanks!

----
Edit:

I wasn't paying attention while reading the docs. Enabling the trigger module is one solution, and the section of Responding to a flagging also works perfectly.

Gabriel R.’s picture

Is this code supposed to be called from inside a module.install file?
I tried that, and had no success. No flag is created, and no error messages.

function mymodule_flag_default_flags() {
  $flags = array();
  $flags[] = array(
    'content_type' => 'node',
    'name' => 'read',
    'title' => 'Unlock a premium article.',
    'roles' => array('2'),
    'global' => FALSE,
    'types' => array('blog', 'company', 'report', 'link', 'news', 'page', 'people', 'poll', 'project'),

    'flag_short' => 'mark read',
    'flag_long' => 'Read this premium article?',
    'flag_message' => 'Added to your Premium read list.',
    'flag_confirmation' => 'Are you sure you want to add this article to your Premium reading list?',

    'unflag_short' => 'mark unread',
    'unflag_long' => 'Remove this issue from your Premium articles list',
    'unflag_message' => 'Article removed from your Premium list.',
    'unflag_confirmation' => 'Read articles cannot be marked as unread. ',
    
    'show_on_page' => FALSE,
    'show_on_teaser' => FALSE,
    'show_on_form' => FALSE,
    'status' => FALSE,
    'locked' => array('show_on_teaser', 'show_on_teaser', 'show_on_page', 'name', 'roles', 'global'),
  );
  return $flags;
}
schultetwin’s picture

No, it should be in your .module file, and unless your module is named "my_module", you should change the function name to reflect that.

nocean’s picture

Anyone looking to print $flag->get_user_count($account->uid) will likely encounter the same problem I did -- namely, that the result is a db_select() object, not a string or standard array. The example above uses format_plural(), which doesn't seem to mind that the result isn't a string, but if you don't want to use format_plural(), it can be sticky.

There is a patch available that will output this more appropriately as a string, but an equally easy way to handle this until that's committed is to use

print $flag->get_user_count($account->uid)->fetchField();

Hope that saves someone else the time it took me to figure that out :)

medden’s picture

In the 'Discovering whether a piece of content is flagged' section example:

$flag = flag_get_flag('bookmarks') or die('no "bookmarks" flag defined');
if ($flag->is_flagged($node->nid)) {
  print "This node is bookmarked!";
}

This does nothing in Flags-7.x-2.0
These doesn't seem to be any is_flagged function any more.

Can anyone explain how I can check if a flag is set via code in D7 ?

shafiul’s picture

I'm trying to implement "My Followers" - where a user may "follow" another user (kind of like Twitter)

How do I get list of users who flagged any user (an user is a flag I guess)?

I need this to code using my modules.

Thanks

tebdilikiyafet’s picture

http://drupal.org/node/305086#flag-counts

I added this code to node.tpl.php and it works.

But when a user flag a node, the flag count does not change until page is refreshed. I want to do this simultaneously. How can I do this with javascript or another way?

alexmoreno’s picture

how can be a flag updated in your schema?

Imagine i've created a flag in my module, and now I want to change,

$flag->global = TRUE;

to

$flag->global = FALSE;

How can i load my flag in hook update ?

function mymodule_update_6100() {
.....

thats what i get if i try to use the same code (obviously, im duplicating the flag):

user warning: Duplicate entry 'like_product' for key 'name' query: INSERT INTO flags (content_type, name, title, global, options) VALUES ('node', 'like_product', 'Like product', 0, 'a:15:{s:10:\"flag_short\";s:8:\"Fav this\";s:9:\"flag_long\";s:0:\"\";s:12:\"flag_message\";s:0:\"\";s:12:\"unflag_short\";s:10:\"Unfav this\";s:11:\"unflag_long\";s:0:\"\";s:14:\"unflag_message\";s:0:\"\";s:18:\"unflag_denied_text\";s:0:\"\";s:9:\"link_type\";s:6:\"toggle\";s:5:\"roles\";a:2:{s:4:\"flag\";a:1:{i:0;s:1:\"2\";}s:6:\"unflag\";a:1:{i:0;s:1:\"2\";}}s:6:\"weight\";i:0;s:12:\"show_on_page\";b:1;s:14:\"show_on_teaser\";b:1;s:12:\"show_on_form\";b:1;s:13:\"access_author\";s:0:\"\";s:4:\"i18n\";i:0;}') in C:\xampp\htdocs\drupal6\sites\all\modules\flag\flag.inc on line 1074.

Thanks a lot in advance.

tpchris’s picture

I'm flagging a node for a particular user and would like to get the fcid of the flag_content.

$flag = $this->flag->flag('flag', $nid, $user);

I expected that $flag would contain either the flag_content object or the fcid for the flag_content. Instead it contains the "true".

Is it possible to get the flag_content fcid with the API?

MattDanger’s picture

$flag_content = flag_get_content_flags($content_type, $content_id, $flag_name);
print $flag_content->fcid;
nicodv’s picture

Hi there, I´ve added the snippet below to my node.tpl.php:

global $user;
$flag = flag_get_flag('like_this_offer') or die('no "like_this_offer" flag');
$flag_limit = $flag->get_count($node->nid);
if ($flag_limit < 3):

print flag_create_link('like_this_offer', $node->nid);

endif;

I need to inlcude an if statement that together with the present one does this:
A. If the number of times a node has been flagged is < 3 ---- PRINT THE FLAG LINK (This 'if' statement works)
B. If the the number of times is exactly 3, BUT current user is flagging user ----- (also) PRINT THE FLAG LINK (tried but undone)

I´ve tried some approaches for B but didn´t succeed, can anyone tell me how to include the flagging user condition? Thanks in advance.

Nico

THE VERY LITTLE AGENCY

kaztur’s picture

So if I use in my comment.tpl such code:

<?php $flag = flag_get_flag('approved_comment');
		if ($flag && $flag->is_flagged($comment->cid)) { 
print "Approved!";

}
?>

"Approved!" is shown only for me as administrator. Nothing is shown for anonimous.

Skype: kaztur.ru
Phone: +7 917 871 09 85