Question

I have an imagefield per node that's run through imagecache. Since imagecache caches on-demand, cache files/variations aren't created until they're first requested. So if I update a bunch of images, re-deploy, or otherwise blow the whole cache, it's up to first visitor to process that file.

How can I spare that user the load time and manually rebuild the whole cache?

The last time this came up, I programmatically loaded every node link with jquery ...

Seems like a perfect Drush plugin ... should probably look into writing it, but I'm curious if anyone else has a solution for this.

Was it helpful?

Solution

You could create a custom module and then use hook_cron() to rebuild the imagecage.

Update

I've just spent the last hour trying to work out how to do it server-side and I think I've cracked it.

/**
 * Implements hook_cron().
 */
function rebuildimagecache_cron() {
    global $base_url;

    // get published nodes
    $result = db_query('SELECT nid FROM {node} WHERE status = 1');
    while ($nodes = db_fetch_array($result)) {
        $node = node_load($nodes['nid']);
        $node_type = $node->type;

        // get cck fields for the current nodes node_type
        $fields = content_fields(NULL, $node_type);
        foreach ($fields as $key => $value) {

            // only deal with file fields that use the image widegt tyoe
            if ($value['type'] == 'filefield' && $value['widget']['type'] == 'imagefield_widget') {
                $preset_tokens = explode('_', $value['display_settings']['full']['format']);
                $imagecache_preset = $preset_tokens[0];
                $field_name = $value['field_name'];

                // iterate over each field instance 
                foreach ($node->$field_name as $field_instance) {
                    $filepath = $field_instance['filepath'];
                    $cachedpath = imagecache_create_path($imagecache_preset, $filepath);
                    file_get_contents($base_url . base_path() . $cachedpath);
                }
            }
        }       
    }   
}

How it works:

  1. Get all the published nodes
  2. For each node gets the node type
  3. Gets an array of fields for the current node being iterated
  4. Iterates over all the fields and checks if any are image fields
  5. If image field found then get image cache preset associated
  6. Iterate over image field instances of node
  7. For each image field instance get image filepath
  8. Convert image file path into image cache path
  9. Read file path using file_get_contents() over HTTP to force image cache to generate cached image.

I've tested it and it worked great for me in Drupal 6. A Drupal 7 version would be slightly more tricky due to the changes in the underlying File API.

You'll have to create a custom module and paste this function in. Make sure you also change the hook name from rebuildimagecache to the name of your custom module.

I've used hook_cron() so that it will run when cron is ran but you could run it manually via a drush command.

OTHER TIPS

Low tech approach...

  1. Create a new node view.
  2. Set a filter for the content type thatcontains the image fields.
  3. Add your image fields, using whatever ImageCache preset you want to pre-cache.
  4. Set it to not page, with no node count limit.
  5. Load the view.
  6. Watch your server crush under the load. If timeout, reload the view.

Oh, and make sure only admins have permissions on that view.

One performance tip: You don't need to load the whole image contents to trigger imagecache, you can also just request the headers. So this line:

file_get_contents($base_url . base_path() . $cachedpath);

becomes

get_headers($base_url . base_path() . $cachedpath);

My solution:

function example_cron() {
    $result = db_query('SELECT fid, uri FROM {file_managed} WHERE filemime like :mime AND status = :status', array('mime' => 'image/%', 'status' => FILE_STATUS_PERMANENT));
    $queue = DrupalQueue::get('generate_image_styles');
    foreach ($result as $img_info) {
        foreach(image_styles() as $style) {
            $derivative_uri = image_style_path($style['name'], $img_info->uri);
            if (file_exists($derivative_uri)) continue; // skip existing files
            $data = (object) array(
                    'style' => $style,
                    'img_info' => $img_info,
                    'derivative_uri' => $derivative_uri
                     );
        $queue->createItem($data);
        }
    }
}


function example_cron_queue_info(){
    $queues['generate_image_styles'] = array(
        'worker callback' => '_example_generate_image_styles',
        'time' => 30
        );
return $queues;
}

function _example_generate_image_styles($data){
    if (!file_exists($data->derivative_uri)) {
        image_style_create_derivative($data->style, $data->img_info->uri, $data->derivative_uri);
    }
}

There was an attempt to get this kind of thing working, see Imagecache Batch but I'm not sure where the development of these features stand. You don't mention if you're dealing with D6 or D7 but I would look into the actions and rules stuff in 6.x-2.x-dev and see where it's at.

This was done and works well, see here https://drupal.org/node/587086

Try the full file patch at the end of the thread. Make sure you run it inside /sites/all/modules/imagecache/imagecache.drush.inc and not at root, as is standard.

Licensed under: CC-BY-SA with attribution
Not affiliated with drupal.stackexchange
scroll top