We have set up a node type for flagging by anonymous users.
We have a view that lists all nodes flagged by a particular user.
This view gets displayed in a block where we allow the user to unflag all flagged nodes.

Users are able to "remember" pieces of content.

Flagging works. But sometimes (on some pages) the unflag link is not displayed for a particular nodeID (user 0, page caching turned on). On other pages the link shows.

Maybe a hint: Is there a place to start debugging this?

Comments

manuelBS’s picture

I dont' exactely now but drupal doesnt have sessions for anonymous user so flagging wont really work. Does flagging work if you have the caching disabled?

quicksketch’s picture

Priority: Major » Normal

Flag does work with both anonymous users and page caching enabled. It gives anonymous users a cookie to store which content they have flagged, then uses JavaScript after the page has loaded to swap out all the "Flag" links with "Unflag" links for content they have already flagged.

We'll need more specific instructions on how to reproduce this problem. There's likely a pattern here that can be reproduced at will, right now saying "some pages work but others don't" isn't very helpful.

derjochenmeyer’s picture

We use flagging as a "remember these products" feature. We display the flagged products in a block. We update the block via AJAX using the Component module. We eliminated the Component module as a possible reason, because the links are not present even after a full page reload.

The pattern:
1. On a product page (node/ID) we hit the AJAX "remember me" flag link.
2. The product is flagged, the block gets updated, the unflag link is present.
3. The unflag link is present on all non-product nodes AND on its own node view (node/ID)
4. The unflag link does not show on all other product nodes.

The block that we use is a node-view that uses the flag-link field in a table.

The pattern dissolves:
1. On a product page of a flagged product we hit the AJAX "UNremember me" flag link.
2. All unflag links are displayed on all product pages
3. We hit the AJAX "remember me" flag link on a different product.
4. the unflaglinks for all products with a certain taxonomy term are lost.

>> The unflag link on the product page (not the one displayed in the block) is always working.
>> There are no watchdog errors related to this problem.
>> If the link is displayed it looks like thishttp://www.domain.com/flag/unflag/rememberme/12360?destination=node%2F12360&token=4612d4fd1758780876489e4730b49757c&has_js=1
>> If the link is NOT displayed the table cell is empty

It seems to be related to some kind of taxonomy/access issue (we dont use any taxonomy access control modules)

mooffie’s picture

Maybe this is related: #986840: Removing flag for anonymous users returns error: javascript and cookies disabled

It's probably not related.

mooffie’s picture

Is there a place to start debugging this?

Yes.

First, here's a description of how Flag implements anonymous flagging:

  1. The HTML document the server sends your browser contains only "Flag this!" links (when you're anonymous). Surprise!
  2. But this document also contains, in a JavaScript array (Drupal.settings.flag.templates), a rendition of every possible "Unflag this!" link.
  3. A cookie in your browser keeps a record of all the content IDs you've flagged.
  4. JavaScript code then runs: it reads the cookie and for each content ID replaces its "Flag this!" link with the "Unflag link!" link from the aforementioned JavaScript array.

(Nate basically explained this in comment #2.)

Now,

You say:

the unflag link is not displayed

This means that the problem is in step #4. Because if we omit this step the page will be full of "Flag this!" links. (Verify this: disable JavaScript and refresh the page.)

And it probably means that Drupal.settings.flag.templates doesn't contain a rendition for all the links. In other words, some "Flag this!" links are replaced by a null string.

We update the block via AJAX using the Component module

Perhaps your setup doesn't merge the new link renditions into Drupal.settings? This seems the likely reason. On the other hand, you say "[w]e eliminated the Component module as a possible reason, because the links are not present even after a full page reload."

Whatever, to get you started hacking, locate this line...

$('.flag-' + flagName + '-' + contentId, context).after(Drupal.settings.flag.templates[flagName + '_' + contentId]).remove();

...and add the following code before it:

if (!Drupal.settings.flag.templates[flagName + '_' + contentId]) {
  alert('Item #' + contentId + ' is flagged, but I wasn't told how its unflag link looks like.');
}
derjochenmeyer’s picture

As an anonymous user:
1. I hit the "flag this" link on a product
-- it is flagged, the block gets updated + everything looks good after a page refresh
-- the on page Link now reads "unflag this"
-- the unflag link is present in my block
2. I disable javascript, and refresh
-- the on page Link still reads "unflag this"
-- the unflag link is present in my block
-- the link returns an error because it misses the has_js=1 querystring

3. I navigate to a different product
-- the unflag link in my block is gone (table cell is empty)

4. I disable javascript, and refresh on the same different page
-- the unflag link is there, the table cell contains

<span class="flag-wrapper flag-rememberme flag-rememberme-360">
      <a rel="nofollow" class="flag unflag-action flag-link-normal" title="Some Text" href="/flag/unflag/rememberme/12360?destination=node%2F696&amp;token=4612d4fd158780876489e4730b49757c">unrememberme</a><span class="flag-throbber">&nbsp;</span>
    </span>

5. I enable javascript, and refresh on the same different page
-- the unflag link is gone (table cell is empty)

mooffie’s picture

2. I disable javascript, and refresh
-- the on page Link still reads "unflag this"
[...]
4. I disable javascript, and refresh on the same different page
-- the unflag link is there,

(This seems to contradict what I said earlier, that the page the server sends contains only "Flag this!" links, but it might be that we have a bug in that mechanism as well. However, it's unrelated to the "disappearing links" we're discussing in this issue, so for the time being it's best to ignore it.)

=======

3. I navigate to a different product
-- the unflag link in my block is gone (table cell is empty)
[...]
5. I enable javascript, and refresh on the same different page
-- the unflag link is gone (table cell is empty)

Do "View Source". Do you see a "rememberme_XYZ" entry in the Drupal.settings.flag.templates array? (replace "XYZ" with the content ID of the item whose link is gone).

-- the link returns an error because it misses the has_js=1 querystring

(That's a different issue altogether. (You may ask how come we have so many bugs in our module. It's a good question. I guess it could be explained by the Bicycle Shed example: since the anonymous flagging feature was relatively big it might have got a light inspection only.))

derjochenmeyer’s picture

You may ask how come we have so many bugs in our module.

Hey mooffie, I don't ask how come we have so many bugs in this module. I'm happy to help with testing and debugging. Its a very cool module!

Drupal.settings.flag looks like this

"flag": { "anonymous": 1, "templates": { "rememberme_812": "\x3cspan class=\"flag-wrapper flag-rememberme flag-rememberme-812\"\x3e\n      \x3ca href=\"/flag/unflag/rememberme/812?destination=node%2F812\x26amp;token=d0256a706cf24c7f58f3ad18326477f0\" title=\"Some text\" class=\"flag unflag-action flag-link-toggle\" rel=\"nofollow\"\x3eUn-rememberme\x3c/a\x3e\x3cspan class=\"flag-throbber\"\x3e\x26nbsp;\x3c/span\x3e\n    \x3c/span\x3e\n" } }

But I am on node/812 !!! I only flagged node/360 and the unflag link for node/360 is gone in the block. I didn't flag node/812.

mooffie’s picture

(I think I know what the problem is.)

"flag": { "anonymous": 1, "templates": { "rememberme_812":

But I am on node/812 !!!

This part is actually fine: When Flag is asked to print the flag link (whatever the status of the item: flagged or not), it prints the "Flag this!" version of it and it also adds the "Unflag this!" version of the link to the JS array.

the unflag link for node/360 [which is in] the block [is missing].

That's the only problem: the JS array doesn't contain the renditions for the links you have in your block.

And I suspect I know what's the problem: are your blocks cached? Go to your "admin / performance" settings page (I don't know the exact menu path) and turn off caching for the blocks. (Drupal has several levels of caching.)

Because if the blocks are cached, there are times when Flag isn't actually run when they're called for and it doesn't have a chance to add the renditions to the JS array. (We'll think of a workaround later; first let's verify that's indeed the problem.)

derjochenmeyer’s picture

And I suspect I know what's the problem: are your blocks cached?

They are not cached, and they were not while debugging this.

We have
- Page cache: "Normal (recommended for production sites, no side effects)" active
- no "Minimum cache lifetime"
- "Page compression" active
- "Block cache" disabled
- "Optimize CSS files" active (with CSS Gzip)
- "Optimize and Minify JavaScript files" active (with Javascript Aggregator)

I disabled CSS and JS optimisation. Thats not the problem.

derjochenmeyer’s picture

The strange thing is: It works on ALL pages and nodes with no flagging (all unflag links are there). The problem is only present on product-nodes.

mooffie’s picture

(I'll try to check that next week.)

(BTW, turning on a block that runs a view involving some anon flag [is supposed to] turn[s] off the caching for that page. So eventually you'll instead want to fetch the block/view in an onload JavaScript event.)

derjochenmeyer’s picture

Thanks for the Tipp. That means if we show the views-block on all pages, we thereby disable page caching for all pages :)

mooffie’s picture

Status: Active » Fixed

OK, I found the problem. I opened a new issue:

#996700: Anon flagging: Views may make some flag links "disappear"

(There's another bug that awaits a fix, #996710: Anon flagging: Output of "flag this!" links only isn't enforced)

HOWEVER, as I mention in #13, you shouldn't turn on the block of this view because it will turn off caching for the page (it's a feature, not a bug; because otherwise anon users will see the (stale) state of some other anon user). You don't want this to happen: you want page caching. So instead you'll have to display the block using JS: pull it from the server in the page's onload event.

(Tip: add "<? print 'Time: ' . date('H:i:s', time()); ?>" to your page.tpl.php to know whether the page is cached or not: if the time is current you know the page isn't cached (because, e.g., a view turned caching off (as it should!)).)

derjochenmeyer’s picture

Thanks mooffie! The patch in #996700: Anon flagging: Views may make some flag links "disappear" fixes this issue.

Also thanks a lot for the js pull tip! We now use the component module to load the block...

    drupal_add_js('
      $(document).ready(function() {
        $.get("http://www.domain.com/component/block/views/rememberme-block_1", function(data) {
          $("#header-region").prepend(data);
          if (Drupal.attachBehaviors) {
            Drupal.attachBehaviors("#block-views-rememberme-block_1");
          }
        });
      });
    ', 'inline');
derjochenmeyer’s picture

Followup: Hi mooffie, I dont know if this is a flag issue. After pulling in the block with AJAX the destination of the generated unflag link is obviously wrong. Lets say the block is displayed on /node/123 the AJAX-callback points to some other URL (in our case /component/block/views/rememberme-block_1).

/flag/unflag/rememberme/398?destination=component%2Fblock%2Fviews%2Frememberme-block_1&token=256279e14f4578102da273803cf3d5c0
mooffie’s picture

Jochen, this isn't quite a bug.

Flag (and many other modules) tell themselves where they need to redirect after they complete some operation (this is usually used only when JS isn't used: either when it's disabled or when using the right mouse button). They default to the path of the "current page". Which is actually the path of the HTTP request being currently served. In your case, since the request is "component/block/...", it's the destination.

You need to override this destination:

    $view_name = 'rememberme-block_1';
    $remember_me_fetcher = url('component/block/views/' . $view_name, array('query' => drupal_get_destination()));
    drupal_add_js(array('jochen' => array('remember_me_fetcher' => $remember_me_fetcher)), 'setting');

    drupal_add_js('
      $(document).ready(function() {
        $.get(Drupal.settings.jochen.remember_me_fetcher , function(data) {

(I may have typos here.)

(I'd move the drupal_add_js() snippet into a JS file (You probably have one anyway if you're using our JS API to refresh things upon flagging).)

derjochenmeyer’s picture

Thanks mooffie, for your help! It works!

mooffie’s picture

(You're welcome. Note that I updated my reply to use Drupal.settings (mainly to make it possible to move the JS into its own file). You may have missed it if you read it before I updated it.)

derjochenmeyer’s picture

Followup: This might be relevant for other users.

Patch #986840: Removing flag for anonymous users returns error: javascript and cookies disabled does not seem to work with above AJAX pulling on pages that have no flag links. For example our frontpage has no flag links, but it also pulls in the rememberme block via AJAX.

mooffie’s picture

Patch #986840: Removing flag for anonymous users returns error: javascript and cookies disabled does not seem to work with above AJAX pulling on pages that have no flag links.

Mmm. That's right. To fix this, add "Drupal.settings.flag.anonymous = true;" to your JS (before the call to Drupal.attachBehaviors). This will tell Flag's JS (the anti-crawlers mechanism) that it needs to kick in.

(Ideally, the 'Component' module should merge whatever JS settings were generated during the page request into the page's Drupal.settings.)

mooffie’s picture

To fix this, add "Drupal.settings.flag.anonymous = true;" to your JS

On second thought, this will result in JS error because the '.flag' slot doesn't exist.

So, instead, add this to your PHP:

if ($GLOBALS['user']->uid  == 0) {
  drupal_add_js(array('flag' => array('anonymous' => 1)), 'setting');
}
derjochenmeyer’s picture

Wow, thanks. I could create a doc page summing up all of this.

mooffie’s picture

Indeed. I started a doc page:

Technical notes about "anonymous" flaggings

Feel free to edit it.

(Note: I added a note about efficiency. Search that page for "@todo".)

I've fixed two more bugs related to anon flagging. It will probably take a couple of hours before it's reflected in the 'dev' release. Please use it (in a few hours) and let me know if you encounter any more problems.

derjochenmeyer’s picture

I added a detailed description to Technical notes about "anonymous" flaggings

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.