Widget Caching
Widget output can be cached in memory on the server using the BlockCache (requires a memory cache like APC to be installed).
Because the output of a widget can differ depending on several things like the current user or the category being currently browsed or the collection being currently viewed or even vs. identified vs anonymous users, relevant "cache keys" must be coded into each widget in order to allow it to be cached separately depending on the context that matters.
Furthermore, if some settings change, a cached output may become obsolete. This is why BlockCache has a cache invalidation system (function invalidate_key( $key, $val )
).
If a widget is poorly programmed and you notice a cached version is used in a wrong context, you can disable the caching of that widget by unchecking the ‘’Allow caching" checkbox in that widget’s settings.
Defining Cache Keys for a Widget
By default a widget has the following cache keys:
/**
* Maybe be overridden by some widgets, depending on what THEY depend on..
*
* @return array of keys this widget depends on
*/
function get_cache_keys()
{
global $Blog;
return array(
'wi_ID' => $this->ID, // Have the widget settings changed ?
'set_coll_ID' => $Blog->ID, // Have the settings of the blog changed ? (ex: new skin)
);
}
This will generate a cache key like b2evo+widget+wi_ID=123+set_coll_ID=45
and the output of the widget will be cached under that key.
This means the output of the widget will be keyed in the BlockCache to make it specific to
- the current instance of b2evolution (in this example it appears as
b2evo
at the beginning of the key). - the widget instance itself (wi_ID), i-e: if you have 2 different universal item lists in your sidebar, they will be cached separately
- the collection (’set_coll_ID’), i-e: the cached output can never be shared between different collections
Here are some additional possibilities to use as cache keys:
'wi_ID' => $this->ID
: Have the widget settings changed ?'set_coll_ID' => $Blog->ID
: Have the settings of the current blog changed ? (ex: new owner, new skin)'set_coll_ID' =>'any'
: Have the settings of ANY blog changed ? (ex: new skin here, new name on another)'user_ID' => $Blog->get_owner_User()->ID
: Has the owner of the current blog changed? (name, avatar, etc..)'user_ID' => (is_logged_in() ? $current_User->ID : 0)
: Has the current User changed? (note that we use the same "cache key" name as in the previous example, but this time for a completely different purpose. The unicity of the key name is only relative to the current widget. Another widget may use the same key name for something different).'cont_coll_ID' => empty($this->disp_params['blog_ID']) ? $Blog->ID : $this->disp_params['blog_ID']
: Has the content of the displayed blog changed ?'loggedin' => (is_logged_in() ? 1 : 0)
: Is a user logged in at the time this widget is cached/displayed'item_ID' => $Item->ID
: Has the current Item changed?'item_page' => isset( $GLOBALS['page'] ) ? $GLOBALS['page'] : 1
: Cache each Item page separately (This cache key CANNOT be used to invalidate. Because if you invalidate "page 2" for example, you will invalidate page 2 of all items in the block cache, which makes no sense.)'intro_feat_coll_ID' => empty( $this->disp_params['blog_ID'] ) ? $Blog->ID : $this->disp_params['blog_ID']
: Has the content of the intro/featured post changed ?'media_coll_ID' => empty( $this->disp_params['blog_ID'] ) ? $Blog->ID : $this->disp_params['blog_ID']
: Have some media files attached to one of the collection items?
Cache Invalidation
You may have noticed the above pose questions like "has x changed?". This is because, in addition to separating cache outputs for different contexts, BlockCache can invalidate some cached elements if some relevant configuration (or other) element changes.
The way this works is that when something important changes, b2evolution should call
BlockCache::invalidate_key( $key, $value );
This is currently implemented in the following situations:
When a widget itself is edited (trivial case)
// This widget has been modified, cached content depending on it should be invalidated:
BlockCache::invalidate_key( 'wi_ID', $this->ID );
When collection settings or advanced permissions are updated
BlockCache::invalidate_key( 'set_coll_ID', $this->ID ); // Settings have changed
BlockCache::invalidate_key( 'set_coll_ID', 'any' ); // Settings of a have changed (for widgets tracking a change on ANY collection)
// cont_coll_ID // Content has not changed
When an item is updated OR deleted (content update)
BlockCache::invalidate_key( 'cont_coll_ID', $Blog->ID ); // Content has changed
if( $this->is_intro() || $this->is_featured() )
{ // Content of intro or featured post has changed
BlockCache::invalidate_key( 'intro_feat_coll_ID', $Blog->ID );
}
// set_coll_ID // Settings have not changed
When a user is edited OR deleted
// This User has been modified, cached content depending on it should be invalidated:
BlockCache::invalidate_key( 'user_ID', $this->ID );
When a chapter or category is edited
// BLOCK CACHE INVALIDATION:
$chapter_Blog = $this->get_Blog();
BlockCache::invalidate_key( 'cont_coll_ID', $chapter_Blog->ID ); // Content has changed
BlockCache::invalidate_key( 'cat_ID', $this->ID ); // Chapter has changed
When the item type is updated
// BLOCK CACHE INVALIDATION:
BlockCache::invalidate_key( 'item_type_'.$this->ID, 1 ); // Item Type has changed (useful for compare widget which needs to check several item_IDs, including from different collections)
When a new link is added to an Item
// New link was added to the item, invalidate blog's media BlockCache:
BlockCache::invalidate_key( 'media_coll_ID', $this->Item->get_blog_ID() );