Hi,
I have just spent a day trying to fix a caching-related issue with a block on one of our client websites. It's a weird one which I can't explain, but I probably don't understand fully how Drupal caching works, so perhaps this is a documentation issue rather than a code one. I've marked this up as base system, rather than block.module, because the issue seems to be caching in general rather than blocks, but mark it back to block.module if I'm wrong.
Anyway, I used the jQuery Countdown module (http://drupal.org/project/jquery_countdown) to create a block loading a CCK date field on a node and showing a counter down to the display date. Page cache is set to Normal and Block cache is enabled. The code looks like this:
// FIRST THE HOOK_BLOCK
// Note, BLOCK_NO_CACHE is explicitly set:
function economistconferences_features_block($op = 'list', $delta = 0) {
switch ($op) {
case 'list':
$blocks['countdown']['info'] = t('Event countdown');
$blocks['countdown']['cache'] = BLOCK_NO_CACHE;
return $blocks;
break;
case 'view':
switch ($delta) {
case 'countdown':
$block['subject'] = t('Countdown');
$block['content'] = theme('economistconferences_features_countdown');
return $block;
}
break;
}
}
// THEN THE THEME FUNCTION CALLED
// This just loads our date, does some simple maths and then calls a theme function
// over at the jQuery Countdown module for return:
function theme_economistconferences_features_countdown() {
if (module_exists('jquery_countdown') && arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1));
$field = $node->field_events_date;
if ($field[0]['value']) {
$difference = strtotime($field[0]['value']) - time();
if ($difference < 0) {
$passed = 1;
$difference = abs($difference);
}
if (!$passed) {
return theme('jquery_countdown', array(
'until' => $difference,
'format' => 'DHMS',
'description' => t('to go until event'),
'layout' => '<div class="countdown-clock"><div class="day">{dn}</div><div class="clock">{hnn} {sep} {mnn} {sep} {snn}</div></div><div class="clearfix"></div><div class="countdown-text"><div class="text">{dl}</div><div class="desc">{desc}</div></div><div class="clearfix"></div>',
));
}
}
}
else {
return t('To use this block you must install and enable !link', array('!link' => l(t('jQuery Countdown'), 'http://drupal.org/project/jquery_countdown')));
}
}
This code works fine for logged in users, without exception. That makes sense, I guess, because the page cache is not doing anything for logged in users. And even if the block is cached, it shouldn't matter because the date is normally static data anyway.
However, for anonymous users, after a period of time (I guess the cache expiry time) the block stops rendering correctly. It doesn't even add the JS for jQuery Countdown any more (which happens in the theme function called within my theme function). It just renders a grey box. Again, this kinda makes sense - with page caching on, perhaps the additional function would not be fired, because Drupal would use the stale JavaScript, except that block is not containing stale data - it's complete empty. Now that makes NO sense to me...?
And it gets weirder. If you disable block cache (which, until today, I thought had no effect on anonymous users when page cache was enabled) the problem goes away. I cannot begin to tell you why, it just does. All of a sudden, that block starts rendering perfectly. Which is mad for a couple of reasons:
1. Block cache shouldn't matter because page cache is on and the block should be cached in the page?
2. Anyway, the block is set to BLOCK_NO_CACHE, so why is it being cached at all - it should already be disabled for that block!
So, muchos weirdiness. Any ideas?
Comments
Comment #1
greg.harveyI should also note I tried all sorts of tricks, including moving the code above to a template preprocess function and using a template instead of a theme function *and* not making that function a theme function at all, hoping it would then fall outside any possibly caching, with BLOCK_NO_CACHE set too, but both these approaches yielded the same result. Only totally disabling block caching made normal service resume.
Comment #2
marcvangendsubscribe, I've had similar issues once, I'll see if I can post some more info later.
Comment #3
damienmckennaIn theory, if there are any blocks on a page that set the caching to BLOCK_NO_CACHE then that page should not be cached. Am I right that it seems you're running into a bug in that logic?
Comment #4
greg.harveyHi Damien,
It would seem so. The page is evidently being cached anyway. Or something in the caching mechanism is messing with that block. Disabling block caching (but not normal page caching) appears to fix the issue. I can reproduce it, but I'm really struggling to work out at which point, and in which cache, things are getting stuck! =/
Comment #5
aren cambre commentedSubscribe. Having similar problem.
Is it really true that a page with one non-cached block is not cached?
Comment #6
morbus iffThis appears to happen in Drupal 7 too - I have a number of blocks set to DRUPAL_NO_CACHE (the correct approach in Drupal 7), and as soon as I turn on Block caching under Performance, these blocks work once, and then fail *for anonymous users*, under two known cases:
1) If a block uses a drupal_add_library() or drupal_add_js(), the JS is not loaded, even with $options 'cache' FALSE (which can only be done on drupal_add_js and not drupal_add_library()).
2) If the block doesn't use any JS, but changes per page load (like a random image), the image no longer changes - it retains the value shown on the second page load, forever after.
My expectation is that DRUPAL_NO_CACHE will exempt the block from caching. I can understand 1) failing (since JS is loaded at page header time, and not in the block itself), but 2) is definitely a bug as I can see it.
Comment #7
aren cambre commentedNot critical since the product is functional even with this bug.
Comment #8
morbus iffI tend to disagree. If the administrator/developer is doing everything right, and the site malfunctions in a way that adversely affects the end-users of the site (versus the administrator/developer), then the product isn't working as advertised. But, eh, I'll concede that "just disable it" is an undesirable, but fixing, workaround. I'll also point a sad finger to the number of other bugs, spread across many contrib modules, of folks lamenting that a module doesn't work with Block Cache enabled, the worse attempts to fix it (which often involve hook_init()), and the fact that we're going onto two releases (6 and the forthcoming 7) where It Doesn't Work As Documented.
Comment #9
greg.harveyHmm, I'm inclined to agree with Morbus Iff - since this still exists it really *needs* to be fixed in D7. Not being able to remove a block from the cache makes certain use cases (e.g. shopping basket blocks) impossible to implement with block caching on, so no, the product does not work - and in some use cases it does not work in a CRITICAL way. And as Morbus Iff pointed out, some of the contrib workarounds are eye-watering.
This bug needs squishing. There is still time, and marking it critical might get it the right attention. (I'm way out of my depth from a coding perspective, so pointless me even attempting a patch here!)
Comment #10
alexkb commentedSubscribing.
Comment #11
carlos8f commentedNot sure, but this could be a duplicate of #235673: Changes to block caching mode not caught.
Comment #12
greg.harvey@carlos8f: Could be - I don't remember any more if I initially had it set to defaults and *added* NO_CACHE ... if so, that might be the same bug.
Comment #13
catchI'm going to mark this as a duplicate of #235673: Changes to block caching mode not caught - if you have steps to reproduce other than that bug report, please re-open this. Also bumping other issue to critical.
Comment #14
MakeOnlineShop commentedHello,
On an DRUPAL UBERCART shop, do you know how I could exclude CART BLOCK from caching for anonymous users ?
Because this block doesn't show cart content for anonymous users.
Thank you so much for your help.
Comment #15
marcvangend@make-online-shop, this is a (closed) thread about fixing a specific bug, not a support forum for slightly related questions. I see that you have been cross-posting your question in a number of more-or-less related threads. Please do not cross-post, but ask your question in the most appropriate place and stick to it. I wish you good luck finding the answer to your question and happy Drupalling.