Index: wp-admin/includes/image-edit.php
===================================================================
--- wp-admin/includes/image-edit.php	(revision 26953)
+++ wp-admin/includes/image-edit.php	(working copy)
@@ -6,6 +6,16 @@
  * @subpackage Administration
  */
 
+$image_editor_groups = array();
+
+/**
+ * @uses do_action( 'add_image_editor_groups' ) to allow plugins / themes to register / unregister image editor groups
+ * @uses apply_filters( 'image_editor_groups' ) to allow direct filtering of the $image_editor_groups global array
+ *
+ * @global array $image_editor_groups
+ * @param type $post_id
+ * @param type $msg
+ */
 function wp_image_editor($post_id, $msg = false) {
 	$nonce = wp_create_nonce("image_editor-$post_id");
 	$meta = wp_get_attachment_metadata($post_id);
@@ -13,6 +23,46 @@
 	$sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
 	$note = '';
 
+	if ( $thumb && $sub_sizes ) {
+		$thumb_img = wp_constrain_dimensions( $thumb['width'], $thumb['height'], 160, 120 );
+
+		add_image_edit_group (
+			'thumbnail-settings',
+			__( 'Thumbnail Settings' ),
+			'imgedit_group_thumbnail_settings',
+			'default',
+			__('The thumbnail image can be cropped differently. For example it can be square or contain only a portion of the original image to showcase it better. Here you can select whether to apply changes to all image sizes or make the thumbnail different.'),
+			'imgedit-applyto',
+			compact( 'thumb', 'thumb_img', 'sub_sizes' )
+		);
+	}
+
+	add_image_edit_group(
+		'image-scale',
+		__( 'Scale Image' ),
+		'imgedit_group_scale_image',
+		'default',
+		__( 'You can proportionally scale the original image. For best results the scaling should be done before performing any other operations on it like crop, rotate, etc. Note that images can only be scaled down, not up.' ),
+		'',
+		compact( 'meta' )
+	);
+
+
+	add_image_edit_group(
+		'image-crop',
+		__( 'Crop Image' ),
+		'imgedit_group_crop_image',
+		'default',
+		sprintf(
+			'<p>%1$s</p><p><strong>%2$s</strong><br />%3$s</p><p><strong>%4s</strong><br />%5$s</p>',
+			__('The image can be cropped by clicking on it and dragging to select the desired part. While dragging the dimensions of the selection are displayed below.'),
+			__('Crop Aspect Ratio'),
+			__('You can specify the crop selection aspect ratio then hold down the Shift key while dragging to lock it. The values can be 1:1 (square), 4:3, 16:9, etc. If there is a selection, specifying aspect ratio will set it immediately.'),
+			__('Crop Selection'),
+			__('Once started, the selection can be adjusted by entering new values (in pixels). Note that these values are scaled to approximately match the original image dimensions. The minimum selection size equals the thumbnail size as set in the Media settings.')
+		)
+	);
+
 	if ( isset( $meta['width'], $meta['height'] ) )
 		$big = max( $meta['width'], $meta['height'] );
 	else
@@ -25,6 +75,18 @@
 	if ( ! empty( $backup_sizes ) && isset( $backup_sizes['full-orig'], $meta['file'] ) )
 		$can_restore = $backup_sizes['full-orig']['file'] != basename( $meta['file'] );
 
+	if ( $can_restore ) {
+		add_image_edit_group(
+			'image-restore',
+			__( 'Restore Original Image'),
+			'imgedit_group_restore_image',
+			'default',
+			__('Discard any changes and restore the original image.'),
+			''
+		);
+	}
+
+
 	if ( $msg ) {
 		if ( isset($msg->error) )
 			$note = "<div class='error'><p>$msg->error</p></div>";
@@ -35,160 +97,68 @@
 	?>
 	<div class="imgedit-wrap">
 	<?php echo $note; ?>
-	<table id="imgedit-panel-<?php echo $post_id; ?>"><tbody>
-	<tr><td>
-	<div class="imgedit-menu">
-		<div onclick="imageEdit.crop(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-crop disabled" title="<?php esc_attr_e( 'Crop' ); ?>"></div><?php
+		<table id="imgedit-panel-<?php echo $post_id; ?>"><tbody>
+			<tr><td>
+				<div class="imgedit-menu">
+					<div onclick="imageEdit.crop(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-crop disabled" title="<?php esc_attr_e( 'Crop' ); ?>"></div><?php
 
-	// On some setups GD library does not provide imagerotate() - Ticket #11536
-	if ( wp_image_editor_supports( array( 'mime_type' => get_post_mime_type( $post_id ), 'methods' => array( 'rotate' ) ) ) ) { ?>
-		<div class="imgedit-rleft"  onclick="imageEdit.rotate( 90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate counter-clockwise' ); ?>"></div>
-		<div class="imgedit-rright" onclick="imageEdit.rotate(-90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate clockwise' ); ?>"></div>
-<?php } else {
-		$note_no_rotate = esc_attr__('Image rotation is not supported by your web host.');
-?>
-	    <div class="imgedit-rleft disabled"  title="<?php echo $note_no_rotate; ?>"></div>
-	    <div class="imgedit-rright disabled" title="<?php echo $note_no_rotate; ?>"></div>
-<?php } ?>
+				// On some setups GD library does not provide imagerotate() - Ticket #11536
+				if ( wp_image_editor_supports( array( 'mime_type' => get_post_mime_type( $post_id ), 'methods' => array( 'rotate' ) ) ) ) { ?>
+					<div class="imgedit-rleft"  onclick="imageEdit.rotate( 90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate counter-clockwise' ); ?>"></div>
+					<div class="imgedit-rright" onclick="imageEdit.rotate(-90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate clockwise' ); ?>"></div>
+			<?php } else {
+					$note_no_rotate = esc_attr__('Image rotation is not supported by your web host.');
+			?>
+					<div class="imgedit-rleft disabled"  title="<?php echo $note_no_rotate; ?>"></div>
+					<div class="imgedit-rright disabled" title="<?php echo $note_no_rotate; ?>"></div>
+			<?php } ?>
 
-		<div onclick="imageEdit.flip(1, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-flipv" title="<?php esc_attr_e( 'Flip vertically' ); ?>"></div>
-		<div onclick="imageEdit.flip(2, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-fliph" title="<?php esc_attr_e( 'Flip horizontally' ); ?>"></div>
+					<div onclick="imageEdit.flip(1, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-flipv" title="<?php esc_attr_e( 'Flip vertically' ); ?>"></div>
+					<div onclick="imageEdit.flip(2, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-fliph" title="<?php esc_attr_e( 'Flip horizontally' ); ?>"></div>
 
-		<div id="image-undo-<?php echo $post_id; ?>" onclick="imageEdit.undo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-undo disabled" title="<?php esc_attr_e( 'Undo' ); ?>"></div>
-		<div id="image-redo-<?php echo $post_id; ?>" onclick="imageEdit.redo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-redo disabled" title="<?php esc_attr_e( 'Redo' ); ?>"></div>
-		<br class="clear" />
-	</div>
+					<div id="image-undo-<?php echo $post_id; ?>" onclick="imageEdit.undo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-undo disabled" title="<?php esc_attr_e( 'Undo' ); ?>"></div>
+					<div id="image-redo-<?php echo $post_id; ?>" onclick="imageEdit.redo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-redo disabled" title="<?php esc_attr_e( 'Redo' ); ?>"></div>
+					<br class="clear" />
+				</div>
 
-	<input type="hidden" id="imgedit-sizer-<?php echo $post_id; ?>" value="<?php echo $sizer; ?>" />
-	<input type="hidden" id="imgedit-minthumb-<?php echo $post_id; ?>" value="<?php echo ( get_option('thumbnail_size_w') . ':' . get_option('thumbnail_size_h') ); ?>" />
-	<input type="hidden" id="imgedit-history-<?php echo $post_id; ?>" value="" />
-	<input type="hidden" id="imgedit-undone-<?php echo $post_id; ?>" value="0" />
-	<input type="hidden" id="imgedit-selection-<?php echo $post_id; ?>" value="" />
-	<input type="hidden" id="imgedit-x-<?php echo $post_id; ?>" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
-	<input type="hidden" id="imgedit-y-<?php echo $post_id; ?>" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
+				<input type="hidden" id="imgedit-sizer-<?php echo $post_id; ?>" value="<?php echo $sizer; ?>" />
+				<input type="hidden" id="imgedit-minthumb-<?php echo $post_id; ?>" value="<?php echo ( get_option('thumbnail_size_w') . ':' . get_option('thumbnail_size_h') ); ?>" />
+				<input type="hidden" id="imgedit-history-<?php echo $post_id; ?>" value="" />
+				<input type="hidden" id="imgedit-undone-<?php echo $post_id; ?>" value="0" />
+				<input type="hidden" id="imgedit-selection-<?php echo $post_id; ?>" value="" />
+				<input type="hidden" id="imgedit-x-<?php echo $post_id; ?>" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
+				<input type="hidden" id="imgedit-y-<?php echo $post_id; ?>" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
 
-	<div id="imgedit-crop-<?php echo $post_id; ?>" class="imgedit-crop-wrap">
-	<img id="image-preview-<?php echo $post_id; ?>" onload="imageEdit.imgLoaded('<?php echo $post_id; ?>')" src="<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>?action=imgedit-preview&amp;_ajax_nonce=<?php echo $nonce; ?>&amp;postid=<?php echo $post_id; ?>&amp;rand=<?php echo rand(1, 99999); ?>" />
-	</div>
+				<div id="imgedit-crop-<?php echo $post_id; ?>" class="imgedit-crop-wrap">
+				<img id="image-preview-<?php echo $post_id; ?>" onload="imageEdit.imgLoaded('<?php echo $post_id; ?>')" src="<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>?action=imgedit-preview&amp;_ajax_nonce=<?php echo $nonce; ?>&amp;postid=<?php echo $post_id; ?>&amp;rand=<?php echo rand(1, 99999); ?>" />
+				</div>
 
-	<div class="imgedit-submit">
-		<input type="button" onclick="imageEdit.close(<?php echo $post_id; ?>, 1)" class="button" value="<?php esc_attr_e( 'Cancel' ); ?>" />
-		<input type="button" onclick="imageEdit.save(<?php echo "$post_id, '$nonce'"; ?>)" disabled="disabled" class="button-primary imgedit-submit-btn" value="<?php esc_attr_e( 'Save' ); ?>" />
-	</div>
-	</td>
+				<?php do_action( 'image_editor_below_image' ) ?>
+			</td>
 
-	<td class="imgedit-settings">
-	<div class="imgedit-group">
-	<div class="imgedit-group-top">
-		<a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><strong><?php _e('Scale Image'); ?></strong></a>
-		<div class="imgedit-help">
-		<p><?php _e('You can proportionally scale the original image. For best results the scaling should be done before performing any other operations on it like crop, rotate, etc. Note that images can only be scaled down, not up.'); ?></p>
-		<?php if ( isset( $meta['width'], $meta['height'] ) ): ?>
-		<p><?php printf( __('Original dimensions %s'), $meta['width'] . '&times;' . $meta['height'] ); ?></p>
-		<?php endif ?>
-		<div class="imgedit-submit">
-		<span class="nowrap"><input type="text" id="imgedit-scale-width-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" style="width:4em;" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />&times;<input type="text" id="imgedit-scale-height-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" style="width:4em;" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
-		<span class="imgedit-scale-warn" id="imgedit-scale-warn-<?php echo $post_id; ?>">!</span></span>
-		<input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'scale')" class="button-primary" value="<?php esc_attr_e( 'Scale' ); ?>" />
-		</div>
-		</div>
-	</div>
+			<td class="imgedit-settings">
 
-<?php if ( $can_restore ) { ?>
+			<?php
+				/* Image Editor Groups */
+				do_action( 'add_image_editor_groups', $post_id );
 
-	<div class="imgedit-group-top">
-		<a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><strong><?php _e('Restore Original Image'); ?></strong></a>
-		<div class="imgedit-help">
-		<p><?php _e('Discard any changes and restore the original image.');
+				do_image_edit_groups( $post_id, $nonce );
+			?>
 
-		if ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE )
-			echo ' '.__('Previously edited copies of the image will not be deleted.');
+				<div class="imgedit-submit">
+					<input type="button" onclick="imageEdit.close(<?php echo $post_id; ?>, 1)" class="button" value="<?php esc_attr_e( 'Cancel' ); ?>" />
+					<input type="button" onclick="imageEdit.save(<?php echo "$post_id, '$nonce'"; ?>)" disabled="disabled" class="button-primary imgedit-submit-btn" value="<?php esc_attr_e( 'Save' ); ?>" />
+				</div>
 
-		?></p>
-		<div class="imgedit-submit">
-		<input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'restore')" class="button-primary" value="<?php esc_attr_e( 'Restore image' ); ?>" <?php echo $can_restore; ?> />
-		</div>
-		</div>
-	</div>
 
-<?php } ?>
+			</td><!-- /.imgedit-settings --></tr>
 
-	</div>
+		</tbody></table>
 
-	<div class="imgedit-group">
-	<div class="imgedit-group-top">
-		<strong><?php _e('Image Crop'); ?></strong>
-		<a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><?php _e('(help)'); ?></a>
-		<div class="imgedit-help">
-		<p><?php _e('The image can be cropped by clicking on it and dragging to select the desired part. While dragging the dimensions of the selection are displayed below.'); ?></p>
-
-		<p><strong><?php _e('Crop Aspect Ratio'); ?></strong><br />
-		<?php _e('You can specify the crop selection aspect ratio then hold down the Shift key while dragging to lock it. The values can be 1:1 (square), 4:3, 16:9, etc. If there is a selection, specifying aspect ratio will set it immediately.'); ?></p>
-
-		<p><strong><?php _e('Crop Selection'); ?></strong><br />
-		<?php _e('Once started, the selection can be adjusted by entering new values (in pixels). Note that these values are scaled to approximately match the original image dimensions. The minimum selection size equals the thumbnail size as set in the Media settings.'); ?></p>
-		</div>
+		<div class="imgedit-wait" id="imgedit-wait-<?php echo $post_id; ?>"></div>
+		<script type="text/javascript">jQuery( function() { imageEdit.init(<?php echo $post_id; ?>); });</script>
+		<div class="hidden" id="imgedit-leaving-<?php echo $post_id; ?>"><?php _e("There are unsaved changes that will be lost. 'OK' to continue, 'Cancel' to return to the Image Editor."); ?></div>
 	</div>
-
-	<p>
-		<?php _e('Aspect ratio:'); ?>
-		<span  class="nowrap">
-		<input type="text" id="imgedit-crop-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 0, this)" style="width:3em;" />
-		:
-		<input type="text" id="imgedit-crop-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 1, this)" style="width:3em;" />
-		</span>
-	</p>
-
-	<p id="imgedit-crop-sel-<?php echo $post_id; ?>">
-		<?php _e('Selection:'); ?>
-		<span  class="nowrap">
-		<input type="text" id="imgedit-sel-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" style="width:4em;" />
-		:
-		<input type="text" id="imgedit-sel-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" style="width:4em;" />
-		</span>
-	</p>
-	</div>
-
-	<?php if ( $thumb && $sub_sizes ) {
-		$thumb_img = wp_constrain_dimensions( $thumb['width'], $thumb['height'], 160, 120 );
-	?>
-
-	<div class="imgedit-group imgedit-applyto">
-	<div class="imgedit-group-top">
-		<strong><?php _e('Thumbnail Settings'); ?></strong>
-		<a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><?php _e('(help)'); ?></a>
-		<p class="imgedit-help"><?php _e('The thumbnail image can be cropped differently. For example it can be square or contain only a portion of the original image to showcase it better. Here you can select whether to apply changes to all image sizes or make the thumbnail different.'); ?></p>
-	</div>
-
-	<p>
-		<img src="<?php echo $thumb['url']; ?>" width="<?php echo $thumb_img[0]; ?>" height="<?php echo $thumb_img[1]; ?>" class="imgedit-size-preview" alt="" /><br /><?php _e('Current thumbnail'); ?>
-	</p>
-
-	<p id="imgedit-save-target-<?php echo $post_id; ?>">
-		<strong><?php _e('Apply changes to:'); ?></strong><br />
-
-		<label class="imgedit-label">
-		<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="all" checked="checked" />
-		<?php _e('All image sizes'); ?></label>
-
-		<label class="imgedit-label">
-		<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="thumbnail" />
-		<?php _e('Thumbnail'); ?></label>
-
-		<label class="imgedit-label">
-		<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="nothumb" />
-		<?php _e('All sizes except thumbnail'); ?></label>
-	</p>
-	</div>
-
-	<?php } ?>
-
-	</td></tr>
-	</tbody></table>
-	<div class="imgedit-wait" id="imgedit-wait-<?php echo $post_id; ?>"></div>
-	<script type="text/javascript">jQuery( function() { imageEdit.init(<?php echo $post_id; ?>); });</script>
-	<div class="hidden" id="imgedit-leaving-<?php echo $post_id; ?>"><?php _e("There are unsaved changes that will be lost. 'OK' to continue, 'Cancel' to return to the Image Editor."); ?></div>
-	</div>
 <?php
 }
 
@@ -675,6 +645,10 @@
 	} elseif ( 'thumbnail' == $target ) {
 		$sizes = array( 'thumbnail' );
 		$success = $delete = $nocrop = true;
+	} else {
+		// Allow custom intermediate sizes to be individually targeted
+		$sizes = array( $target );
+		$success = $delete = true;
 	}
 
 	if ( isset( $sizes ) ) {
@@ -695,7 +669,19 @@
 			}
 
 			$crop = $nocrop ? false : get_option("{$size}_crop");
-			$_sizes[ $size ] = array( 'width' => get_option("{$size}_size_w"), 'height' => get_option("{$size}_size_h"), 'crop' => $crop );
+
+			// Accommodate custom defined sizes defined with add_image_size()
+			global $_wp_additional_image_sizes;
+			if ( isset( $_wp_additional_image_sizes[$size] ) ){
+				$size_w = $_wp_additional_image_sizes[$size]['width'];
+				$size_h = $_wp_additional_image_sizes[$size]['height'];
+				$crop = $_wp_additional_image_sizes[$size]['crop'];
+			} else {
+				$size_w = get_option("{$size}_size_w");
+				$size_h = get_option("{$size}_size_h");
+			}
+
+			$_sizes[ $size ] = array( 'width' => $size_w, 'height' => $size_h, 'crop' => $crop );
 		}
 
 		$meta['sizes'] = array_merge( $meta['sizes'], $img->multi_resize( $_sizes ) );
@@ -733,3 +719,204 @@
 	$return->msg = esc_js( __('Image saved') );
 	return $return;
 }
+
+/**
+ * Adds a new image editor group to the Edit Image view.
+ *
+ * Should be called before {@link do_image_edit_groups()}, preferably from a 'add_image_edit_group' action callback.
+ *
+ * @global array $image_editor_groups
+ *
+ * @param int $id Unique ID for this editor group
+ * @param string $title Title that appears in the editor group box
+ * @param string|array $callback Function to be called to render the editor group content. Function signature is `( $post_id, $imgedit_group, $args )`
+ * @param string $tab Optional. Default "default". The name of the tab this group appears in
+ * @param string $help_text Optional. Help text that appears in the editor box content
+ * @param string $class Optional. CSS class to be added to the editor group DIV
+ * @param array $callback_args Optional. Additional arguments to be passed to the callback function.
+ */
+function add_image_edit_group( $id, $title, $callback, $tab = "default", $help_text = "", $class = "", $callback_args = null ){
+	global $image_editor_groups;
+
+	/** @TODO make sure $id is unique **/
+	$image_editor_groups[$tab][$id] = array(
+		'id' => $id,
+		'title' => $title,
+		'callback' => $callback,
+		'class' => $class,
+		'help' => $help_text,
+		'callback_args' => $callback_args
+	);
+}
+
+function remove_image_edit_group( $remove_id ){
+	global $image_editor_groups;
+
+	foreach ( $image_editor_groups as $tab_group => &$groups ){
+		foreach ( $groups as $id => $group ){
+			if ( $id == $remove_id ){
+				unset ( $groups[$id] );
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+function imgedit_group_scale_image( $post_id, $imgedit_group, $args ){
+	extract( $args );
+	?>
+
+		<?php if ( isset( $meta['width'], $meta['height'] ) ): ?>
+		<p><?php printf( __('Original dimensions %s'), $meta['width'] . '&times;' . $meta['height'] ); ?></p>
+		<?php endif ?>
+		<div class="imgedit-submit">
+			<span class="nowrap"><input type="text" id="imgedit-scale-width-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" style="width:4em;" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />&times;<input type="text" id="imgedit-scale-height-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" style="width:4em;" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
+			<span class="imgedit-scale-warn" id="imgedit-scale-warn-<?php echo $post_id; ?>">!</span></span>
+			<input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'scale')" class="button-primary" value="<?php esc_attr_e( 'Scale' ); ?>" />
+		</div>
+		</div>
+
+	<?php
+}
+
+function imgedit_group_crop_image( $post_id, $imgedit_group, $args ){
+	extract( $args );
+	?>
+		<p>
+			<?php _e('Aspect ratio:'); ?>
+			<span  class="nowrap">
+			<input type="text" id="imgedit-crop-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 0, this)" style="width:3em;" />
+			:
+			<input type="text" id="imgedit-crop-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 1, this)" style="width:3em;" />
+			</span>
+		</p>
+
+		<p id="imgedit-crop-sel-<?php echo $post_id; ?>">
+			<?php _e('Selection:'); ?>
+			<span  class="nowrap">
+			<input type="text" id="imgedit-sel-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" style="width:4em;" />
+			&times;
+			<input type="text" id="imgedit-sel-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" style="width:4em;" />
+			</span>
+		</p>
+	<?php
+}
+
+function imgedit_group_thumbnail_settings( $post_id, $imgedit_group, $args ){
+	extract( $args );
+	?>
+
+	<?php if ( isset( $thumb ) ): ?>
+	<p>
+		<img src="<?php echo $thumb['url']; ?>" width="<?php echo $thumb_img[0]; ?>" height="<?php echo $thumb_img[1]; ?>" class="imgedit-size-preview" alt="" /><br /><?php _e('Current thumbnail'); ?>
+	</p>
+	<?php endif; ?>
+
+	<p id="imgedit-save-target-<?php echo $post_id; ?>">
+		<strong><?php _e('Apply changes to:'); ?></strong><br />
+
+		<label class="imgedit-label">
+		<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="all" checked="checked" />
+		<?php _e('All image sizes'); ?></label>
+
+		<label class="imgedit-label">
+		<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="thumbnail" />
+		<?php _e('Thumbnail'); ?></label>
+
+		<label class="imgedit-label">
+		<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="nothumb" />
+		<?php _e('All sizes except thumbnail'); ?></label>
+	</p>
+
+	<?php
+}
+
+function imgedit_group_restore_image( $post_id, $imgedit_group, $args ){
+	extract( $args );
+	?>
+
+	<p>
+	<?php
+		if ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE )
+		echo ' '.__('Previously edited copies of the image will not be deleted.');
+	?>
+	</p>
+
+	<div class="imgedit-submit">
+		<input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'restore')" class="button-primary" value="<?php esc_attr_e( 'Restore image' ); ?>" />
+	</div>
+
+	<?php
+}
+
+/**
+ * @global array $image_editor_groups
+ *
+ * @param int $post_id
+ * @param string $nonce
+ *
+ * @TODO Currently, tabs auto-create themselves just by defining them in add_image_edit_group(). Eventually we'll want a add_editor_tab() suite of functions so we can better control these tabs.
+ */
+function do_image_edit_groups( $post_id, $nonce ){
+	global $image_editor_groups;
+
+	/**
+	 * Allow modification of image editor groups.
+	 *
+	 * @since 3.9
+	 *
+	 * @param int $post_id The ID of the WP_Post (attachment) currently being edited.
+	 */
+	$editor_groups = apply_filters( 'image_editor_groups', $image_editor_groups, $post_id );
+
+	// Only create the tabs structure if needed
+	$has_tabs = count( $editor_groups ) > 1;
+
+	if ( $has_tabs ){
+		echo '<div id="image-editor-group-tabs"><ul>';
+
+		foreach ( $editor_groups as $tab => $tab_groups ){
+			if ( $has_tabs ){
+				$tab_title = str_replace( array( '-', '_' ), ' ', strtoupper( $tab ) );
+				echo '<li><a href="#imgedit-group-tab-' . $tab . '">' . $tab_title . '</a></li>';
+			}
+		}
+
+		echo '</ul>';
+	}
+
+	foreach ( $editor_groups as $tab => $tab_groups ){
+		if ( $has_tabs ) echo '<div id="#imgedit-group-tab-' . $tab . '">';
+
+		foreach ( $tab_groups as $imgedit_group ){
+			?>
+			<div class="imgedit-group <?php echo $imgedit_group['class']?>">
+				<div class="imgedit-group-top">
+					<strong><?php echo $imgedit_group['title'] ?></strong>
+					<?php if ( ! empty( $imgedit_group['help'] ) ): ?>
+						<a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><?php _e('(help)'); ?></a>
+						<div class="imgedit-help"><?php echo $imgedit_group['help'] ?></div>
+					<?php endif; ?>
+				</div>
+
+				<?php
+					$imgedit_group['callback_args']['nonce'] = $nonce; // Add the nonce to the callback args of each item, in case it has a submit button
+					call_user_func( $imgedit_group['callback'], $post_id, $imgedit_group, $imgedit_group['callback_args'] );
+				?>
+
+			</div>
+			<?php
+		}
+
+		if ( $has_tabs ) echo '</div><!-- /#imgedit-group-tab-' . $tab . ' -->';
+	}
+
+	if ( $has_tabs ) {
+		echo '</div><!-- /#image-editor-group-tabs -->';
+		?>
+		<script>jQuery( '#image-editor-group-tabs' ).tabs();</script>
+		<?php
+	}
+
+}
