5

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.

1
  • Just updated my original answer with a possible solution.
    – Camsoft
    Mar 2, 2011 at 23:49

6 Answers 6

12

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.

4
  • awesome ;) Have you considered to make a module with that? Could be shipped with Devel module to help testing imagecache.
    – Strae
    Mar 3, 2011 at 0:08
  • Yeah I might tidy it up slightly and make it into a proper module if there is a demand for it.
    – Camsoft
    Mar 3, 2011 at 0:15
  • Nice well done. Made a couple changes to only affect a given node type (else very slow!), and had to restructure the base paths to work with my site... but this works well!
    – ack
    Mar 3, 2011 at 23:47
  • It really look pretty cool, but it doesn't work for me. No images are generated.
    – Mr_DeLeTeD
    Dec 5, 2012 at 11:46
5

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.

1
  • lol, this is probably the easiest way for non-developers.
    – Merrick
    May 17, 2012 at 19:39
4

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

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);
    }
}
1
  • pretty cool. Could you please explain how the queue works?
    – uwe
    Feb 24, 2012 at 5:09
2

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.

0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.