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->uid)) {
  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->nid, $GLOBALS['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.
?>

Getting a list of items a user has flagged

This give you an array of NIDs that the specified user has flagged with a given flag.

    $query = $this->entityTypeManager()->getStorage('flagging')->getQuery();
    $query->accessCheck(FALSE);
    $query->condition('flag_id', FLAG_ID);
    $query->condition('uid', UID);
    $nids = $query->execute();

Getting the number of items a user has flagged

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.');
}

The non-OO alternative is:

$flag = flag_get_flag('votes');
if ($flag) {
  flag_get_user_flag_counts($flag, $user);
}

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');

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

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

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

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

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() or devel-generate 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_flag(), and to the removal of a flag from a piece of content by implementing hook_flag_unflag().

mymodule_flag_flag($flag, $content_id, $account, $flagging) {
  // Do something in response to the flagging.
}

mymodule_flag_unflag($flag, $content_id, $account, $flagging) {
  // Do something in response to the unflagging.
}

Flag module actually implements its own hook in the flag_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_entity_type('node');

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

  $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(),
    '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.

To avoid conflicts with other modules that might provide a flag with the same name, developers should prefix the names of default flags with their module's name.

function mymodule_flag_default_flags() {
  $flags = array();
  $flags[] = array(
    'content_type' => 'node',
    'name' => 'mymodule_starred',
    'title' => 'Starred',
    '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', 'global'),
  );
  return $flags;
}

Write a flagging field value

The 3.X version introduced the ability to attach fields to a flagging entity, just like any entity (see http://drupal.org/node/917576). These flagging field values can be set directly (using stdClass) or with the Entity API (using entity_create() and entity_metadata_wrapper()). After the flagging field values are set, the flagging entity is saved via the Flag API, through the use of $flag->flag():

Setting/Saving Flagging Field Values Directly

$flag_name = 'my_flag';
$nid = 138;
$field_name = 'my_field';

// Create an array containing the flagging entity values.
$values = array(
  'flag_name' => $flag_name,
);
// Cast the array as a stdClass object.
$flagging = (object) $values;
// Set field values directly:
$flagging->{$field_name}['und'][0]['value'] = 'foo';

// Invoke the Flag API to set the flagging. This also saves the flagging entity.
$flag = flag_get_flag($flag_name);
$flag->flag('flag', $nid, NULL, FALSE, $flagging);

Setting/Saving Flagging Field Values With The Entity API

global $user;
$flag = flag_get_flag('my_flag');
$nid = 138;
$field_name = 'my_field';

// Create an array containing the flagging entity values.
$values = array(
  'fid' => $flag->fid,
  'entity_type' => $flag->entity_type,
  'entity_id' => $nid,
);
// Create the flagging using Entity API.
$flagging = entity_create('flagging', $values);

// Set field values using the Entity API.
$flagging_wrapper = entity_metadata_wrapper('flagging', $flagging);
$flagging_wrapper->{$field_name}->set('some text!');

// Invoke the Flag API to set the flagging. This also saves the flagging entity.
$flag->flag('flag', $nid, $user, FALSE, $flagging);

Notes:

  • do not use entity_save() to save a flagging entity, since this will bypass the Flag API
  • When using entity_create() to create a flagging entity, the $values array must contain, at minimum, a 'fid' an 'entity_type', and an 'entity_id'.

Comments

reptilex’s picture

Beware the Documentations states that the roles would be set when you add the row:

$flag->roles = array(2);

This is NOT true, you have to set your own roles.

I filed an issue here and was told that this is not used anymore so you have to do your own:

$permissions = array(
        "flag $flag->name" =>1,
        "unflag $flag->name" => 1,
    );
    user_role_change_permissions($role_id, $permissions);

I find it very counter intuitive and cumbersome, but there must be a good reason for it!?!

Elin Yordanov’s picture

I couldn't figure out how to check if a flagging is flagged programmatically.

For example, i have a flag 'subscribe' to flag a term, and another flag 'approve_subscription' to flag the flagging.

I have placed following code snippets into my custom module, but I don't know how to use the is_flagged method to check if $flag_sub is flagged with $flag_ok.

  $flag_sub = flag_get_flag('subscribe');
  $flag_ok = flag_get_flag('approve_subscription');

Old usernames: pc-wurm, Елин Й.

joachim’s picture

Please file a support request instead of commenting here.

noahott’s picture

How do you specifify the values of attached fields when flagging a node programmatically. For example, in a custom module, if I run,

      $flag = flag_get_flag('question_viewed');
      $flag->flag('flag', $node->nid, $user_obj);

none of the attached fields are saved, or assigned their default value. These attached field do not even appear blank in the database. The default values I've set for the fields appear fine, and save correctly when flagging the link through a confirmation form link.

Thanks for you help,

joachim’s picture

Please file a support request instead of commenting here.

priceh’s picture

Is there a way to get a list of flagged nodes (nids) of a certain flag machine-name?
I see that you can get the users, but it doesn't seem like you can get the nid from a function call.

Strutsagget’s picture

Hi

How do i get a list of users flagged a node.

If i have a flag has_read and then i want to list all users that has flagged has_read it.

//PiJa Media & Management AB din apputvecklare

atari82’s picture

How would i print $flag->get_count() for each flagged field_collection item?

For example in field-collection-item.tpl.php in field-field-collection.tpl.php.
field-field-collection.tpl.php provides probably a correct item_id in $items but i can't figure out how to access it in $item :-/

Thanks :-)

Kodiak’s picture

The key for entity type is "entity_type", not "content_type" as written on this page.

waqarit’s picture

"Getting the number of times an item is flagged" perfectly worked.

Sagar Ramgade’s picture

$flag_service = \Drupal::service('flag');
$flag = $flag_service->getFlagById('flag_machine_name');
// $entity can be $node or user, $account is the acting user.
$flag_service->flag($flag, $entity, $account);

Acquia certified Developer, Back end and Front specialist
Need help? Please use my contact form