/**
  * This method looks for images that don't have copies of the sizes defined by this plugin, and
  * then tries to make those copies. It returns an array of messages divided into error messages and
  * success messages. It only makes copies for X images at a time based on form selection.
  *
  * Also the same routine (for now) for deleting images and cleaning the attachment metadata
  *
  * @since       0.1
  * @uses        global $_wp_additional_image_sizes WP since 0.1.5
  * @uses        ZUI_WpAdditionalImageSizes::getAllImageAttachments()
  * @uses        ZUI_WpAdditionalImageSizes::getSizesWp()
  * @uses        ZUI_WpAdditionalImageSizes::getSizesCustom()  since 0.1.3
  * @uses        ZUI_WpAdditionalImageSizes::getAllImageSizes() since 0.1.3
  * @uses        ZUI_WpAdditionalImageSizes::mightBreakScriptToAvoidTimeout()
  * @uses        wp_upload_dir() WP function
  * @uses        wp_get_attachment_metadata() WP function
  * @uses        wp_update_attachment_metadata() WP function
  * @uses        get_post_meta() WP function
  * @uses        image_make_intermediate_size() WP function
  * @uses        get_option() WP function
  * @return      array
  * @todo        abstract create/delete better
  * @todo        minimize the number of variables, especially the flags
  */
 function regenerateImages()
 {
     global $_wp_additional_image_sizes;
     // Need this to prevent deleting legit set_post_thumbnail_size() and add_image_size() images
     // Set it up
     $start = strtotime('now');
     $max_execution_time = ini_get('max_execution_time');
     $max_execution_time = round($max_execution_time / 1.25);
     // Let's divide that max_execution_time by 1.25 just to play it a little bit safe (we don't know when WordPress started to run so $now is off as well)
     $did_increase_time_limit = FALSE;
     // Flag to be able to let them know we had to increase the time limit and still tell them we succeeded - clumsy as hell
     $did_finish_batch = TRUE;
     // Flag to know if we finished the batch or aborted - set to FALSE if we break the processing loop
     $did_delete_an_image = FALSE;
     // Flag to know if we deleted (or would have) any images or attacment metadata
     $did_resize_an_image = FALSE;
     // Flag to know if we resized (or would have) any images to customize success message in conjunction with $did_finish_all
     $did_finish_all = FALSE;
     // Flag to know if we finished them ALL - set to TRUE if a query for images comes up empty
     $messages = array();
     // Sent back to managePost() and viewOptionsPage() to print results
     $i = 0;
     // How many images we managed to process before we stopped the script to prevent a timeout
     $offset = isset($_POST['offset']) && 0 < $_POST['offset'] ? $_POST['offset'] - 1 : 0;
     // Where we should start from; for get_post() in getAllImageAttachments()
     $numberposts = isset($_POST['numberposts']) && 0 < $_POST['numberposts'] ? $_POST['numberposts'] : 50;
     $basedir = wp_upload_dir();
     $basedir = $basedir['basedir'];
     $sizes_wp = self::getSizesWp();
     // Set the sizes we are going to do based on site/blog owner choice
     // For delete this defaults to all
     if (isset($_POST['sizes_to_check']) && 'all' != $_POST['sizes_to_check']) {
         switch ($_POST['sizes_to_check']) {
             case "custom_only":
                 $sizes_to_check = self::getSizesCustom();
                 $messages['success'][] = 'Checked custom image sizes only.';
                 break;
             case "wordpress_only":
                 $sizes_to_check = $sizes_wp;
                 $messages['success'][] = 'Checked WordPress sizes (thumbnail, medium, large) only.';
                 break;
             default:
                 $sizes_to_check = array_intersect_key(self::getSizesCustom(), array($_POST['sizes_to_check'] => array()));
                 // This is super sloppy but for now there can be only one
                 $messages['success'][] = "Checked <strong>{$_POST['sizes_to_check']}</strong> image size only.";
                 break;
         }
     } else {
         if (isset($_POST['sizes_to_check']) && 'all' == $_POST['sizes_to_check']) {
             $sizes_to_check = self::getAllImageSizes();
             $messages['success'][] = 'Checked all custom and WordPress (thumbnail, medium, large) image sizes.';
         } else {
             if (isset($_POST['delete_images_for_deleted_sizes'])) {
                 $sizes_to_check = self::getAllImageSizes();
                 $messages['success'][] = 'Checked all images metadata.';
             }
         }
     }
     // Get an image batch with the quantity they requested
     $images = self::getAllImageAttachments(array('offset' => $offset, 'numberposts' => $numberposts));
     // Get image attachements starting at the offset
     // Loop the batch and resize as necessary
     if (!empty($images)) {
         foreach ($images as $image) {
             $metadata = wp_get_attachment_metadata($image->ID);
             $file = get_post_meta($image->ID, '_wp_attached_file', true);
             if (isset($_POST['regenerate_images'])) {
                 // We can skip this if not regenerating - abstract and separate regenerate/delete
                 foreach ($sizes_to_check as $size => $values) {
                     // Check to see if we are close to timing out - GRRR redundancy - we have to check this in the image loop as well if this is a delete - we need to abstract and separate regenerate/delete
                     $do_break_script = self::mightBreakScriptToAvoidTimeout($start, $max_execution_time);
                     if (TRUE === $do_break_script) {
                         $did_finish_batch = FALSE;
                         $did_finish_all = FALSE;
                         break 2;
                     } else {
                         if ('extended' === $do_break_script) {
                             $messages['success'][] = 'We increased the time limit at your request.';
                             $did_increase_time_limit = TRUE;
                         }
                     }
                     $size_width = $sizes_to_check[$size]['size_w'];
                     $size_height = $sizes_to_check[$size]['size_h'];
                     $size_crop = $sizes_to_check[$size]['crop'];
                     // We will try to make the size if:
                     //      size does not exist in the image meta data yet
                     //      OR if the size DOES exist in the image meta data but has changed (new size has a width AND metadata width doesn't match new width AND metadata height doesn't match new height)
                     if (isset($_POST['regenerate_images']) && (!isset($metadata['sizes'][$size]) || !empty($sizes_to_check[$size]['size_w']) && ($metadata['sizes'][$size]['width'] != $sizes_to_check[$size]['size_w'] && $metadata['sizes'][$size]['height'] != $sizes_to_check[$size]['size_h']))) {
                         $image_path = $basedir . '/' . $file;
                         // Simulate resize or do it for real?
                         if (isset($_POST['simulate_resize'])) {
                             $result = self::simulate_image_make_intermediate_size($image_path, $size_width, $size_height, $size_crop);
                         } else {
                             $result = image_make_intermediate_size($image_path, $size_width, $size_height, $size_crop);
                         }
                         // If the image was (or would be) resized
                         if ($result) {
                             if (isset($_POST['simulate_resize'])) {
                                 // Just a simulation
                                 if (isset($_POST['replace_sizes']) && array_key_exists($size, $sizes_wp)) {
                                     $messages['success'][] = "WOULD REPLACE: {$metadata['sizes'][$size]['file']} for new {$size} size";
                                 }
                                 $messages['success'][] = '<strong>WOULD CREATE:</strong> "' . $image->post_title . '" to size "' . $size . '"';
                             } else {
                                 // WP sizes cannot be deleted later so clean up as we go is in order
                                 // If they want us to and this size is a WP size
                                 if (isset($_POST['replace_sizes']) && array_key_exists($size, $sizes_wp)) {
                                     $path_parts = pathinfo($basedir . '/' . $file);
                                     $delete_wp_file = $path_parts['dirname'] . "/" . $metadata['sizes'][$size]['file'];
                                     //$delete_wp_file = $basedir . '/' . $metadata['sizes'][$size]['file'];
                                     $delete_wp_file = str_replace("\\", "/", $delete_wp_file);
                                     // Attempt to delete this old WP size
                                     if (@unlink($delete_wp_file)) {
                                         $messages['success'][] = "REPLACED: {$metadata['sizes'][$size]['file']} for new {$size} size";
                                     }
                                     // No alternate message on fail for now
                                 }
                                 // Update the metadata - if a wp replaced size named key is overwritten anyway
                                 $metadata['sizes'][$size] = array('file' => $result['file'], 'width' => $result['width'], 'height' => $result['height']);
                                 wp_update_attachment_metadata($image->ID, $metadata);
                                 $messages['success'][] = '<strong>CREATED:</strong> "' . $image->post_title . '" to size "' . $size . '"';
                             }
                             $did_resize_an_image = TRUE;
                         } else {
                             // Sick of looking at the skipped messages
                             if (isset($_POST['show_skipped'])) {
                                 // Assumed the image was too small to be created/resized so just send a tentative success message
                                 $messages['success'][] = 'SKIPPED: "' . $image->post_title . '" is already smaller than the requested size "' . $size . '"';
                             }
                         }
                     } else {
                         // Sick of looking at the skipped messages and we all know the predefined sizes exist anyway
                         if (isset($_POST['show_skipped']) && isset($_POST['simulate_resize'])) {
                             $messages['success'][] = 'WOULD SKIP: "' . $size . '" already exists for "' . $image->post_title . '"';
                         } else {
                             if (isset($_POST['show_skipped'])) {
                                 $messages['success'][] = 'SKIPPED: "' . $size . '" already exists for "' . $image->post_title . '"';
                             }
                         }
                     }
                     // End if we resized or not
                 }
                 // End sizes loop
             }
             if (!empty($_wp_additional_image_sizes)) {
                 $sizes_to_check_plus_additional = array_merge(array_keys($sizes_to_check), array_keys($_wp_additional_image_sizes));
             } else {
                 $sizes_to_check_plus_additional = array_keys($sizes_to_check);
             }
             $metadata_sizes_not_in_current_all_sizes = array_diff(array_keys($metadata['sizes']), $sizes_to_check_plus_additional);
             //sizes_to_check
             if (isset($_POST['delete_images_for_deleted_sizes'])) {
                 $metadata_after = $metadata;
                 // Leaving in some of this testing stuff for a couple of versions
                 /*
                 echo "<br />metadata before<pre>";
                 print_r($metadata);
                 echo "</pre><br />";
                 */
                 if (0 < count($metadata_sizes_not_in_current_all_sizes)) {
                     foreach ($metadata_sizes_not_in_current_all_sizes as $defunct_size) {
                         if ('post-thumbnail' == $defunct_size) {
                             continue;
                         }
                         // kludge to protect known named size created by set_post_thumbnail_size()
                         $path_parts = pathinfo($basedir . '/' . $file);
                         $delete_current_file = $path_parts['dirname'] . "/" . $metadata_after['sizes'][$defunct_size]['file'];
                         $delete_current_file = str_replace("\\", "/", $delete_current_file);
                         if (isset($_POST['simulate_delete'])) {
                             $image = wp_load_image($delete_current_file);
                             if (is_resource($image)) {
                                 $messages['success'][] = "<strong>WOULD DELETE:</strong> {$defunct_size} {$delete_current_file}";
                                 imagedestroy($image);
                                 // Free up memory
                             } else {
                                 $messages['errors'][] = "<strong>Can't find:</strong> {$delete_current_file}<br /><em>The attachment metadata would be deleted</em>";
                                 $messages['success'][] = "WOULD DELETE METADATA: for {$delete_current_file}";
                             }
                         } else {
                             if (@unlink($delete_current_file)) {
                                 $messages['success'][] = "<strong>DELETED:</strong> {$defunct_size} {$delete_current_file}";
                                 unset($metadata_after['sizes'][$defunct_size]);
                                 // We unset this in a copy of the metadata array to be sure (and for testing)
                             } else {
                                 $messages['success'][] = "Deleted metadata only:  {$defunct_size} {$delete_current_file}";
                                 unset($metadata_after['sizes'][$defunct_size]);
                                 // We unset this in a copy of the metadata array to be sure (and for testing)
                             }
                         }
                         $did_delete_an_image = TRUE;
                         // Check to see if we are close to timing out - GRRR redundancy - we have to check this in the size loop as well
                         $do_break_script = self::mightBreakScriptToAvoidTimeout($start, $max_execution_time);
                         if (TRUE === $do_break_script) {
                             $did_finish_batch = FALSE;
                             $did_finish_all = FALSE;
                             break 2;
                         } else {
                             if ('extended' === $do_break_script) {
                                 $messages['success'][] = 'We increased the time limit at your request.';
                                 $did_increase_time_limit = TRUE;
                             }
                         }
                     }
                 } else {
                     $messages['success'][] = "No sizes to delete for {$image->post_title}";
                 }
                 // UPDATE THE METADATA with the removed/deleted sizes
                 if (!isset($_POST['simulate_delete'])) {
                     wp_update_attachment_metadata($image->ID, $metadata_after);
                 }
                 /* // Leaving in some of this testing stuff for a couple of versions
                    echo "<br />metadata after<pre>";
                    print_r($metadata_after);
                    echo "</pre><br />";
                    */
             }
             $i++;
             $offset++;
         }
         // End images loop
     } else {
         $did_finish_all = TRUE;
     }
     // End if we have images
     // Since we finished the batch we should did a quick check for one more
     if ($did_finish_batch) {
         $images = self::getAllImageAttachments(array('offset' => $offset, 'numberposts' => 1));
         // we might have finished with this batch
         if (empty($images)) {
             $did_finish_all = TRUE;
         }
         // Yay we are done!
     }
     // Set the number of images we got to this attempt
     self::$_images_regenerated_this_attempt = $i;
     // Set the continue form "submit/click" link
     if (isset($_POST['delete_images_for_deleted_sizes'])) {
         $continue_link = "<a id='continue_deleting'>Continue deleting where we left off with the same settings</a>";
     } else {
         $continue_link = "<a id='continue_creating'>Continue creating where we left off with the same settings</a>";
     }
     // Give them a final status message for this batch
     if (!$did_resize_an_image && $did_finish_all && !isset($_POST['delete_images_for_deleted_sizes'])) {
         $messages['success'][] = 'All is well, no new copies created.';
         $i = 0;
         // Reset because we are done!
     } else {
         if (!$did_delete_an_image && $did_finish_all && isset($_POST['delete_images_for_deleted_sizes'])) {
             $messages['success'][] = 'All is well, no images to delete.';
             $i = 0;
             // Reset because we are done!
         } else {
             if ($did_finish_all) {
                 $messages['success'][] = '<strong>All done!</strong>';
                 $i = 0;
                 // Reset because we finished!
             } else {
                 if ($did_finish_batch) {
                     // We finished the request batch quantity but not all of the images
                     $messages['success'][] = "We finished checking a whole batch of {$i}.<br />Consider increasing the number of images per batch until you start seeing the friendly 'we had to stop the script message'.";
                     $messages['success'][] = "<strong>But...we're not quite finished yet. {$continue_link} or use the form to adjust settings and continue.</strong>";
                     self::$_images_regenerate_from_offset = $offset;
                 } else {
                     // We aborted the script to avoid timing out
                     $messages['success'][] = "We checked {$i} images out of an attempted {$numberposts}.";
                     $messages['success'][] = "<strong>Not quite finished yet. {$continue_link} or use the form to adjust settings and continue.</strong>";
                     self::$_images_regenerate_from_offset = $offset;
                 }
             }
         }
     }
     return $messages;
 }
Example #2
0
/**
 * Callback for viewing this plugin admin page
 *
 * @since       0.1
 * @uses        ZUI_WpAdditionalImageSizes::viewOptionsPage()
*/
function aiszViewOptionsPage()
{
    echo "<div class='wrap'>";
    echo "<h2>Additional image sizes</h2>";
    ZUI_WpAdditionalImageSizes::viewOptionsPage();
    echo "</div>";
}