Version Description
- Added option to save the image to media library or refer directly to the created image, not using the media library.
- Added better compatibility with the native image field making it possible to migrate from the regular image field to the crop-image field without losing the images currently attached. (It doesn't work the other way around)
Download this release
Release Info
Developer | andersthorborg |
Plugin | Advanced Custom Fields: Image Crop Add-on |
Version | 1.0 |
Comparing to | |
See all releases |
Code changes from version 0.8 to 1.0
- README.md +70 -0
- acf-image-crop.php +1 -1
- css/options.css +3 -0
- image_crop-v4.php +354 -146
- js/input.js +47 -39
- js/options.js +16 -2
- readme.txt +10 -4
- screenshot-1.png +0 -0
- screenshot-2.png +0 -0
- screenshot-3.png +0 -0
- screenshot-4.png +0 -0
- screenshot-5.png +0 -0
- screenshot-6.png +0 -0
README.md
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
-----------------------
|
2 |
+
|
3 |
+
# ACF { Image Crop Add-on
|
4 |
+
|
5 |
+
Adds an 'Image with user-crop' field type for the [Advanced Custom Fields](http://wordpress.org/extend/plugins/advanced-custom-fields/) WordPress plugin.
|
6 |
+
|
7 |
+
|
8 |
+
|
9 |
+
-----------------------
|
10 |
+
|
11 |
+
### Overview
|
12 |
+
ACF image crop is an extended version of the native Image-field in ACF.
|
13 |
+
The field gives the developer/administrator the option to predefine a size for the image, which the user is prompted to crop on the various edit screens. This solves the common issue of images being cropped inappropriately by the automated center-crop, that wordpress performs.
|
14 |
+
|
15 |
+
The plugin supports the defined image sizes as well as a custom option, enabling the developer to specify the dimensions from within the field edit screen.
|
16 |
+
|
17 |
+
The field can be configured to enforce a hard crop or a minimal-dimension-based crop. The hard crop will lock the aspect ratio of the crop where as the minimal-dimension-based crop will not allow the user to crop the image below the specified dimensions.
|
18 |
+
|
19 |
+
This plugin diverts from plugins like [Manual Image Crop](http://wordpress.org/plugins/manual-image-crop/) in that when the user crops an image, a new attachment is generated, so that the relevant crop only applies in the context it is edited. It also spares the user from dealing with the concept of various image sizes.
|
20 |
+
|
21 |
+
As of version 1.0 the field can be configured to either create the cropped image as a media-item (the default behavior) or simply create it and refer directly to the file without adding it to the media library. This will prevent the media library from being cluttered with several cropped versions of the same image. When this option is selected the only available return type for the field is URL.
|
22 |
+
|
23 |
+
|
24 |
+
|
25 |
+
### Compatibility
|
26 |
+
|
27 |
+
This add-on will work with:
|
28 |
+
|
29 |
+
* version 4 and up
|
30 |
+
|
31 |
+
### Installation
|
32 |
+
|
33 |
+
This add-on can be treated as both a WP plugin and a theme include.
|
34 |
+
|
35 |
+
**Install as Plugin**
|
36 |
+
|
37 |
+
1. Copy the 'acf-image_crop' folder into your plugins folder
|
38 |
+
2. Activate the plugin via the Plugins admin page
|
39 |
+
|
40 |
+
**Include within theme**
|
41 |
+
|
42 |
+
1. Copy the 'acf-image_crop' folder into your theme folder (can use sub folders). You can place the folder anywhere inside the 'wp-content' directory
|
43 |
+
2. Edit your functions.php file and add the code below (Make sure the path is correct to include the acf-image_crop.php file)
|
44 |
+
|
45 |
+
```php
|
46 |
+
include_once('acf-image_crop/acf-image_crop.php');
|
47 |
+
```
|
48 |
+
|
49 |
+
### Setup
|
50 |
+
|
51 |
+
The field has the same options as the standard image field. Besides from these, other options are available:
|
52 |
+
|
53 |
+
**Crop type**
|
54 |
+
|
55 |
+
Defines what kind of crop the user is going to perform. If the *Hard crop* option is selected, the aspect ratio of the selected size will be maintained.
|
56 |
+
|
57 |
+
The *Minimal dimensions* option uses the specified size as minima requirements. With this option, the user will not be able to crop the image below the specified dimensions. If a dimension is not specified, the user will be able to crop that dimension to any value.
|
58 |
+
|
59 |
+
**Target size**
|
60 |
+
|
61 |
+
The size, that the image will ultimately be cropped into. This list includes the currently defined image sizes as well as the custom option. If the custom option is selected, a *dimension* opition will become available asking for width:height. NB. When using a custom target size along with the hard crop option **both width and height must be specified**.
|
62 |
+
|
63 |
+
**Force crop**
|
64 |
+
|
65 |
+
On the image field will be a *Crop*-button triggering the crop dialog. If the force crop option is enabled, the crop dialog will show up as soon as the user selects an image.
|
66 |
+
|
67 |
+
###Further Details
|
68 |
+
Whenever the user selects an image, the original image is stored, so whenever the user decides to re-crop the image the user will see the image first selected, and not the cropped one. Every crop made creates a seperate media item, which allows for multiple uses of the same image wihtout overwriting previous crops.
|
69 |
+
|
70 |
+
The plugin has only been tested with Chrome for Mac, and still needs a lot of work. Please let me know of any issues or feature requests.
|
acf-image-crop.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
Plugin Name: Advanced Custom Fields: Image Crop Add-on
|
4 |
Plugin URI: https://github.com/andersthorborg/ACF-Image-Crop
|
5 |
Description: An image field making it possible/required for the user to crop the selected image to the specified image size or dimensions
|
6 |
-
Version: 0
|
7 |
Author: Anders Thorborg
|
8 |
Author URI: http://thorb.org
|
9 |
License: GPLv2 or later
|
3 |
Plugin Name: Advanced Custom Fields: Image Crop Add-on
|
4 |
Plugin URI: https://github.com/andersthorborg/ACF-Image-Crop
|
5 |
Description: An image field making it possible/required for the user to crop the selected image to the specified image size or dimensions
|
6 |
+
Version: 1.0
|
7 |
Author: Anders Thorborg
|
8 |
Author URI: http://thorb.org
|
9 |
License: GPLv2 or later
|
css/options.css
CHANGED
@@ -3,4 +3,7 @@
|
|
3 |
}
|
4 |
.field_type-image_crop .dimensions-wrap .dimension{
|
5 |
width:150px;
|
|
|
|
|
|
|
6 |
}
|
3 |
}
|
4 |
.field_type-image_crop .dimensions-wrap .dimension{
|
5 |
width:150px;
|
6 |
+
}
|
7 |
+
.field_type-image_crop label.disabled{
|
8 |
+
color: #ccc;
|
9 |
}
|
image_crop-v4.php
CHANGED
@@ -26,7 +26,8 @@ class acf_field_image_crop extends acf_field_image
|
|
26 |
'force_crop' => 'no',
|
27 |
'crop_type' => 'hard',
|
28 |
'preview_size' => 'medium',
|
29 |
-
'save_format' => '
|
|
|
30 |
'target_size' => 'thumbnail'
|
31 |
// add default here to merge into your field.
|
32 |
// This makes life easy when creating the field options as you don't need to use any if( isset('') ) logic. eg:
|
@@ -44,15 +45,15 @@ class acf_field_image_crop extends acf_field_image
|
|
44 |
);
|
45 |
|
46 |
// add ajax action to be able to retrieve full image size via javascript
|
47 |
-
add_action( 'wp_ajax_acf_image_crop_get_image_size', array( &$this, 'crop_get_image_size' ) );
|
48 |
add_action( 'wp_ajax_acf_image_crop_perform_crop', array( &$this, 'perform_crop' ) );
|
49 |
|
50 |
}
|
51 |
|
52 |
// AJAX handler for retieving full image dimensions from ID
|
53 |
public function crop_get_image_size()
|
54 |
-
{
|
55 |
-
$img = wp_get_attachment_image_src( $_POST['image_id'], 'full');
|
56 |
if($img){
|
57 |
echo json_encode( array(
|
58 |
'url' => $img[0],
|
@@ -90,27 +91,6 @@ class acf_field_image_crop extends acf_field_image
|
|
90 |
|
91 |
// Create Field Options HTML
|
92 |
?>
|
93 |
-
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
94 |
-
<td class="label">
|
95 |
-
<label><?php _e("Return Value",'acf'); ?></label>
|
96 |
-
<p><?php _e("Specify the returned value on front end",'acf') ?></p>
|
97 |
-
</td>
|
98 |
-
<td>
|
99 |
-
<?php
|
100 |
-
do_action('acf/create_field', array(
|
101 |
-
'type' => 'radio',
|
102 |
-
'name' => 'fields['.$key.'][save_format]',
|
103 |
-
'value' => $field['save_format'],
|
104 |
-
'layout' => 'horizontal',
|
105 |
-
'choices' => array(
|
106 |
-
'object' => __("Image Object",'acf'),
|
107 |
-
'url' => __("Image URL",'acf'),
|
108 |
-
'id' => __("Image ID",'acf')
|
109 |
-
)
|
110 |
-
));
|
111 |
-
?>
|
112 |
-
</td>
|
113 |
-
</tr>
|
114 |
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
115 |
<td class="label">
|
116 |
<label><?php _e("Crop type", 'acf'); ?></label>
|
@@ -122,11 +102,11 @@ class acf_field_image_crop extends acf_field_image
|
|
122 |
do_action('acf/create_field', array(
|
123 |
'type' => 'select',
|
124 |
'name' => 'fields[' . $key . '][crop_type]',
|
125 |
-
'value' => $field['
|
126 |
'class' => 'crop-type-select',
|
127 |
'choices' => array(
|
128 |
'hard' => __('Hard crop', 'acf'),
|
129 |
-
'min' => __('Minimal dimensions', 'acf')
|
130 |
)
|
131 |
));
|
132 |
|
@@ -181,6 +161,24 @@ class acf_field_image_crop extends acf_field_image
|
|
181 |
?>
|
182 |
</td>
|
183 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
185 |
<td class="label">
|
186 |
<label><?php _e("Force crop",'acf'); ?></label>
|
@@ -203,23 +201,47 @@ class acf_field_image_crop extends acf_field_image
|
|
203 |
</tr>
|
204 |
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
205 |
<td class="label">
|
206 |
-
<label><?php _e("
|
207 |
-
<p
|
208 |
</td>
|
209 |
<td>
|
210 |
<?php
|
211 |
do_action('acf/create_field', array(
|
212 |
-
'type'
|
213 |
-
'name'
|
214 |
-
'value'
|
215 |
-
'
|
216 |
-
'choices'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
));
|
218 |
-
|
219 |
?>
|
220 |
</td>
|
221 |
</tr>
|
222 |
-
|
223 |
<?php
|
224 |
|
225 |
}
|
@@ -243,25 +265,42 @@ class acf_field_image_crop extends acf_field_image
|
|
243 |
/*
|
244 |
$field = array_merge($this->defaults, $field);
|
245 |
*/
|
246 |
-
|
247 |
-
// perhaps use $field['preview_size'] to alter the markup?
|
248 |
$data = json_decode($field['value']);
|
249 |
// create Field HTML
|
250 |
// vars
|
251 |
$o = array(
|
252 |
'class' => '',
|
253 |
'url' => '',
|
254 |
-
);
|
255 |
-
$originalImage = null;
|
256 |
-
if( $data && is_object($data) && is_numeric($data->original_image) )
|
257 |
-
{
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
$o['class'] = 'active';
|
264 |
-
$o['url'] = $
|
265 |
}
|
266 |
$width = 0;
|
267 |
$height = 0;
|
@@ -271,24 +310,24 @@ class acf_field_image_crop extends acf_field_image
|
|
271 |
}
|
272 |
else{
|
273 |
global $_wp_additional_image_sizes;
|
274 |
-
$s = $field['target_size'];
|
275 |
if (isset($_wp_additional_image_sizes[$s])) {
|
276 |
$width = intval($_wp_additional_image_sizes[$s]['width']);
|
277 |
$height = intval($_wp_additional_image_sizes[$s]['height']);
|
278 |
} else {
|
279 |
$width = get_option($s.'_size_w');
|
280 |
$height = get_option($s.'_size_h');
|
281 |
-
}
|
282 |
-
}
|
283 |
?>
|
284 |
-
<div class="acf-image-uploader clearfix <?php echo $o['class']; ?>" data-preview_size="<?php echo $field['preview_size']; ?>" data-library="<?php echo $field['library']; ?>" data-width="<?php echo $width ?>" data-height="<?php echo $height ?>" data-crop-type="<?php echo $field['crop_type'] ?>" <?php echo ($field['force_crop'] == 'yes' ? 'data-force-crop="true"' : '') ?>
|
285 |
-
<input class="acf-image-value" data-original-image="<?php echo $data->original_image ?>"
|
286 |
-
<div class="has-image">
|
287 |
<div class="image-section">
|
288 |
<div class="hover">
|
289 |
<ul class="bl">
|
290 |
<li><a class="acf-button-delete ir" href="#"><?php _e("Remove",'acf'); ?></a></li>
|
291 |
-
<li><a class="acf-button-edit ir" href="#"><?php _e("Edit",'acf'); ?></a></li>
|
292 |
</ul>
|
293 |
</div>
|
294 |
<img class="acf-image-image" src="<?php echo $o['url']; ?>" alt=""/>
|
@@ -297,8 +336,8 @@ class acf_field_image_crop extends acf_field_image
|
|
297 |
<div class="crop-stage">
|
298 |
<div class="crop-action">
|
299 |
<h4>Crop the image</h4>
|
300 |
-
<?php if ($
|
301 |
-
<img class="crop-image" src="<?php echo $
|
302 |
<?php endif ?>
|
303 |
</div>
|
304 |
<div class="crop-preview">
|
@@ -310,7 +349,7 @@ class acf_field_image_crop extends acf_field_image
|
|
310 |
</div>
|
311 |
<!-- <img src="<?php echo $o['url']; ?>" alt=""/> -->
|
312 |
</div>
|
313 |
-
<a href="#" class="button button-large init-crop-button">Crop</a>
|
314 |
</div>
|
315 |
</div>
|
316 |
<div class="no-image">
|
@@ -320,7 +359,7 @@ class acf_field_image_crop extends acf_field_image
|
|
320 |
<?php
|
321 |
}
|
322 |
|
323 |
-
|
324 |
|
325 |
/*
|
326 |
* format_value_for_api()
|
@@ -337,10 +376,9 @@ class acf_field_image_crop extends acf_field_image
|
|
337 |
*
|
338 |
* @return $value - the modified value
|
339 |
*/
|
340 |
-
|
341 |
function format_value_for_api( $value, $post_id, $field )
|
342 |
{
|
343 |
-
|
344 |
// validate
|
345 |
if( !$value )
|
346 |
{
|
@@ -352,63 +390,81 @@ class acf_field_image_crop extends acf_field_image
|
|
352 |
}
|
353 |
|
354 |
$value = $data->cropped_image;
|
355 |
-
|
356 |
// format
|
357 |
if( $field['save_format'] == 'url' )
|
358 |
{
|
359 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
360 |
}
|
361 |
elseif( $field['save_format'] == 'object' )
|
362 |
{
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
if( $image_sizes )
|
394 |
-
{
|
395 |
-
foreach( $image_sizes as $image_size )
|
396 |
{
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
|
|
|
|
|
|
|
|
404 |
}
|
405 |
-
// foreach( $image_sizes as $image_size )
|
406 |
}
|
407 |
-
|
408 |
-
|
409 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
410 |
return $value;
|
411 |
-
|
412 |
}
|
413 |
|
414 |
/*
|
@@ -428,15 +484,15 @@ class acf_field_image_crop extends acf_field_image
|
|
428 |
// Note: This function can be removed if not used
|
429 |
|
430 |
|
431 |
-
// register acf scripts
|
432 |
wp_register_script('acf-input-image_crop', $this->settings['dir'] . 'js/input.js', array('acf-input', 'imgareaselect'), $this->settings['version']);
|
433 |
|
434 |
-
wp_register_style('acf-input-image_crop', $this->settings['dir'] . 'css/input.css', array('acf-input'), $this->settings['version']);
|
435 |
wp_register_script( 'jcrop', includes_url( 'js/jcrop/jquery.Jcrop.min.css' ));
|
436 |
|
437 |
|
438 |
-
// scripts
|
439 |
-
wp_enqueue_script(array(
|
440 |
'acf-input-image_crop'
|
441 |
));
|
442 |
|
@@ -473,7 +529,7 @@ class acf_field_image_crop extends acf_field_image
|
|
473 |
wp_enqueue_style( 'acf-input-image-crop-options');
|
474 |
}
|
475 |
|
476 |
-
|
477 |
/*
|
478 |
* update_value()
|
479 |
*
|
@@ -489,59 +545,211 @@ class acf_field_image_crop extends acf_field_image
|
|
489 |
*
|
490 |
* @return $value - the modified value
|
491 |
*/
|
492 |
-
|
493 |
function update_value( $value, $post_id, $field )
|
494 |
{
|
495 |
// array?
|
496 |
if( is_array($value) && isset($value['id']) )
|
497 |
{
|
498 |
-
$value = $value['id'];
|
499 |
}
|
500 |
-
|
501 |
// object?
|
502 |
if( is_object($value) && isset($value->ID) )
|
503 |
{
|
504 |
$value = $value->ID;
|
505 |
}
|
506 |
-
|
507 |
return $value;
|
508 |
}
|
509 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
510 |
function perform_crop(){
|
511 |
$targetWidth = $_POST['target_width'];
|
512 |
-
$targetHeight = $_POST['target_height'];
|
513 |
-
$
|
514 |
-
$
|
515 |
-
$
|
516 |
-
$
|
517 |
-
|
518 |
-
'url_preview' => $previewUrl[0],
|
519 |
-
'url_full' => $fullUrl[0]
|
520 |
-
);
|
521 |
-
echo json_encode($data);
|
522 |
die();
|
523 |
}
|
524 |
|
525 |
-
function generate_cropped_image($id, $x1, $x2, $y1, $y2, $targetW, $targetH){//$id, $x1, $x2, $y$, $y2, $targetW, $targetH){
|
526 |
require_once ABSPATH . "/wp-admin/includes/file.php";
|
527 |
-
require_once ABSPATH . "/wp-admin/includes/image.php";
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
$
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
545 |
}
|
546 |
|
547 |
}
|
26 |
'force_crop' => 'no',
|
27 |
'crop_type' => 'hard',
|
28 |
'preview_size' => 'medium',
|
29 |
+
'save_format' => 'id',
|
30 |
+
'save_in_media_library' => 'yes',
|
31 |
'target_size' => 'thumbnail'
|
32 |
// add default here to merge into your field.
|
33 |
// This makes life easy when creating the field options as you don't need to use any if( isset('') ) logic. eg:
|
45 |
);
|
46 |
|
47 |
// add ajax action to be able to retrieve full image size via javascript
|
48 |
+
add_action( 'wp_ajax_acf_image_crop_get_image_size', array( &$this, 'crop_get_image_size' ) );
|
49 |
add_action( 'wp_ajax_acf_image_crop_perform_crop', array( &$this, 'perform_crop' ) );
|
50 |
|
51 |
}
|
52 |
|
53 |
// AJAX handler for retieving full image dimensions from ID
|
54 |
public function crop_get_image_size()
|
55 |
+
{
|
56 |
+
$img = wp_get_attachment_image_src( $_POST['image_id'], 'full');
|
57 |
if($img){
|
58 |
echo json_encode( array(
|
59 |
'url' => $img[0],
|
91 |
|
92 |
// Create Field Options HTML
|
93 |
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
95 |
<td class="label">
|
96 |
<label><?php _e("Crop type", 'acf'); ?></label>
|
102 |
do_action('acf/create_field', array(
|
103 |
'type' => 'select',
|
104 |
'name' => 'fields[' . $key . '][crop_type]',
|
105 |
+
'value' => $field['crop_type'],
|
106 |
'class' => 'crop-type-select',
|
107 |
'choices' => array(
|
108 |
'hard' => __('Hard crop', 'acf'),
|
109 |
+
'min' => __('Minimal dimensions', 'acf')
|
110 |
)
|
111 |
));
|
112 |
|
161 |
?>
|
162 |
</td>
|
163 |
</tr>
|
164 |
+
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
165 |
+
<td class="label">
|
166 |
+
<label><?php _e("Preview Size", 'acf'); ?></label>
|
167 |
+
<p class="description"><?php _e("Select the target size for this field", 'acf'); ?></p>
|
168 |
+
</td>
|
169 |
+
<td>
|
170 |
+
<?php
|
171 |
+
do_action('acf/create_field', array(
|
172 |
+
'type' => 'select',
|
173 |
+
'name' => 'fields[' . $key . '][preview_size]',
|
174 |
+
'value' => $field['preview_size'],
|
175 |
+
'class' => 'preview-size-select',
|
176 |
+
'choices' => apply_filters('acf/get_image_sizes', array())
|
177 |
+
));
|
178 |
+
|
179 |
+
?>
|
180 |
+
</td>
|
181 |
+
</tr>
|
182 |
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
183 |
<td class="label">
|
184 |
<label><?php _e("Force crop",'acf'); ?></label>
|
201 |
</tr>
|
202 |
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
203 |
<td class="label">
|
204 |
+
<label><?php _e("Save cropped image in media library",'acf'); ?></label>
|
205 |
+
<p><?php _e("If the cropped image is not saved in the media library, the \"Image URL\" is the only available return value.", 'acf') ?></p>
|
206 |
</td>
|
207 |
<td>
|
208 |
<?php
|
209 |
do_action('acf/create_field', array(
|
210 |
+
'type' => 'radio',
|
211 |
+
'name' => 'fields['.$key.'][save_in_media_library]',
|
212 |
+
'value' => $field['save_in_media_library'],
|
213 |
+
'layout' => 'horizontal',
|
214 |
+
'choices' => array(
|
215 |
+
'yes' => __("Yes",'acf'),
|
216 |
+
'no' => __("No",'acf')
|
217 |
+
),
|
218 |
+
'class' => 'save-in-media-library-select'
|
219 |
+
));
|
220 |
+
?>
|
221 |
+
</td>
|
222 |
+
</tr>
|
223 |
+
<tr class="field_option field_option_<?php echo $this->name; ?>">
|
224 |
+
<td class="label">
|
225 |
+
<label><?php _e("Return Value",'acf'); ?></label>
|
226 |
+
<p><?php _e("Specify the returned value on front end",'acf') ?></p>
|
227 |
+
</td>
|
228 |
+
<td>
|
229 |
+
<?php
|
230 |
+
do_action('acf/create_field', array(
|
231 |
+
'type' => 'radio',
|
232 |
+
'name' => 'fields['.$key.'][save_format]',
|
233 |
+
'value' => $field['save_format'],
|
234 |
+
'layout' => 'horizontal',
|
235 |
+
'choices' => array(
|
236 |
+
'url' => __("Image URL",'acf'),
|
237 |
+
'id' => __("Image ID",'acf'),
|
238 |
+
'object' => __("Image Object",'acf')
|
239 |
+
),
|
240 |
+
'class' => 'return-value-select'
|
241 |
));
|
|
|
242 |
?>
|
243 |
</td>
|
244 |
</tr>
|
|
|
245 |
<?php
|
246 |
|
247 |
}
|
265 |
/*
|
266 |
$field = array_merge($this->defaults, $field);
|
267 |
*/
|
268 |
+
// perhaps use $field['preview_size'] to alter the markup?
|
|
|
269 |
$data = json_decode($field['value']);
|
270 |
// create Field HTML
|
271 |
// vars
|
272 |
$o = array(
|
273 |
'class' => '',
|
274 |
'url' => '',
|
275 |
+
);
|
276 |
+
// $originalImage = null;
|
277 |
+
// if( $data && is_object($data) && is_numeric($data->original_image) )
|
278 |
+
// {
|
279 |
+
// $originalImage = wp_get_attachment_image_src($data->original_image, 'full');
|
280 |
+
// $url = wp_get_attachment_image_src($data->original_image, $field['preview_size']);
|
281 |
+
// if($field['save_in_media_library'] == 'yes'){
|
282 |
+
// if(is_numeric($data->cropped_image)){
|
283 |
+
// $url = wp_get_attachment_image_src($data->cropped_image, $field['preview_size']);
|
284 |
+
// }
|
285 |
+
// }
|
286 |
+
// else{
|
287 |
+
// if($data->cropped_image_url){
|
288 |
+
// $url = $data->cropped_image_url;
|
289 |
+
// }
|
290 |
+
// else{
|
291 |
+
|
292 |
+
// }
|
293 |
+
// }
|
294 |
+
|
295 |
+
// $o['class'] = 'active';
|
296 |
+
// $o['url'] = $url[0];
|
297 |
+
// }
|
298 |
+
$imageData = $this->get_image_data($field);
|
299 |
+
//print_r($field);
|
300 |
+
$originalImage = wp_get_attachment_image_src($imageData->original_image, 'full');
|
301 |
+
if($imageData->original_image){
|
302 |
$o['class'] = 'active';
|
303 |
+
$o['url'] = $imageData->preview_image_url;
|
304 |
}
|
305 |
$width = 0;
|
306 |
$height = 0;
|
310 |
}
|
311 |
else{
|
312 |
global $_wp_additional_image_sizes;
|
313 |
+
$s = $field['target_size'];
|
314 |
if (isset($_wp_additional_image_sizes[$s])) {
|
315 |
$width = intval($_wp_additional_image_sizes[$s]['width']);
|
316 |
$height = intval($_wp_additional_image_sizes[$s]['height']);
|
317 |
} else {
|
318 |
$width = get_option($s.'_size_w');
|
319 |
$height = get_option($s.'_size_h');
|
320 |
+
}
|
321 |
+
}
|
322 |
?>
|
323 |
+
<div class="acf-image-uploader clearfix <?php echo $o['class']; ?>" data-field-id="<?php echo $field['key'] ?>" data-preview_size="<?php echo $field['preview_size']; ?>" data-library="<?php echo $field['library']; ?>" data-width="<?php echo $width ?>" data-height="<?php echo $height ?>" data-crop-type="<?php echo $field['crop_type'] ?>" <?php echo ($field['force_crop'] == 'yes' ? 'data-force-crop="true"' : '')?> data-save-to-media-library="<?php echo $field['save_in_media_library'] ?>" >
|
324 |
+
<input class="acf-image-value" data-original-image="<?php echo $data->original_image ?>" data-cropped-image="<?php echo json_encode($data->cropped_image) ?>" type="hidden" name="<?php echo $field['name']; ?>" value="<?php echo htmlspecialchars($field['value']); ?>" />
|
325 |
+
<div class="has-image">
|
326 |
<div class="image-section">
|
327 |
<div class="hover">
|
328 |
<ul class="bl">
|
329 |
<li><a class="acf-button-delete ir" href="#"><?php _e("Remove",'acf'); ?></a></li>
|
330 |
+
<li><a class="acf-button-edit ir" href="#"><?php _e("Edit",'acf'); ?></a></li>
|
331 |
</ul>
|
332 |
</div>
|
333 |
<img class="acf-image-image" src="<?php echo $o['url']; ?>" alt=""/>
|
336 |
<div class="crop-stage">
|
337 |
<div class="crop-action">
|
338 |
<h4>Crop the image</h4>
|
339 |
+
<?php if ($imageData->original_image ): ?>
|
340 |
+
<img class="crop-image" src="<?php echo $imageData->original_image_url ?>" data-width="<?php echo $imageData->original_image_width ?>" data-height="<?php echo $imageData->original_image_height ?>" alt="">
|
341 |
<?php endif ?>
|
342 |
</div>
|
343 |
<div class="crop-preview">
|
349 |
</div>
|
350 |
<!-- <img src="<?php echo $o['url']; ?>" alt=""/> -->
|
351 |
</div>
|
352 |
+
<a href="#" class="button button-large init-crop-button">Crop</a>
|
353 |
</div>
|
354 |
</div>
|
355 |
<div class="no-image">
|
359 |
<?php
|
360 |
}
|
361 |
|
362 |
+
|
363 |
|
364 |
/*
|
365 |
* format_value_for_api()
|
376 |
*
|
377 |
* @return $value - the modified value
|
378 |
*/
|
379 |
+
|
380 |
function format_value_for_api( $value, $post_id, $field )
|
381 |
{
|
|
|
382 |
// validate
|
383 |
if( !$value )
|
384 |
{
|
390 |
}
|
391 |
|
392 |
$value = $data->cropped_image;
|
393 |
+
|
394 |
// format
|
395 |
if( $field['save_format'] == 'url' )
|
396 |
{
|
397 |
+
if(is_numeric($data->cropped_image)){
|
398 |
+
$value = wp_get_attachment_url( $data->cropped_image );
|
399 |
+
}
|
400 |
+
elseif(is_array($data->cropped_image)){
|
401 |
+
|
402 |
+
$value = $this->getAbsoluteImageUrl($data->cropped_image['image']);
|
403 |
+
}
|
404 |
+
elseif(is_object($data->cropped_image)){
|
405 |
+
$value = $this->getAbsoluteImageUrl($data->cropped_image->image);
|
406 |
+
}
|
407 |
+
|
408 |
}
|
409 |
elseif( $field['save_format'] == 'object' )
|
410 |
{
|
411 |
+
if(is_numeric($data->cropped_image )){
|
412 |
+
$attachment = get_post( $data->cropped_image );
|
413 |
+
// validate
|
414 |
+
if( !$attachment )
|
415 |
+
{
|
416 |
+
return false;
|
417 |
+
}
|
418 |
+
|
419 |
+
|
420 |
+
// create array to hold value data
|
421 |
+
$src = wp_get_attachment_image_src( $attachment->ID, 'full' );
|
422 |
+
|
423 |
+
$value = array(
|
424 |
+
'id' => $attachment->ID,
|
425 |
+
'alt' => get_post_meta($attachment->ID, '_wp_attachment_image_alt', true),
|
426 |
+
'title' => $attachment->post_title,
|
427 |
+
'caption' => $attachment->post_excerpt,
|
428 |
+
'description' => $attachment->post_content,
|
429 |
+
'mime_type' => $attachment->post_mime_type,
|
430 |
+
'url' => $src[0],
|
431 |
+
'width' => $src[1],
|
432 |
+
'height' => $src[2],
|
433 |
+
'sizes' => array(),
|
434 |
+
);
|
435 |
+
|
436 |
+
|
437 |
+
// find all image sizes
|
438 |
+
$image_sizes = get_intermediate_image_sizes();
|
439 |
+
|
440 |
+
if( $image_sizes )
|
|
|
|
|
|
|
441 |
{
|
442 |
+
foreach( $image_sizes as $image_size )
|
443 |
+
{
|
444 |
+
// find src
|
445 |
+
$src = wp_get_attachment_image_src( $attachment->ID, $image_size );
|
446 |
+
|
447 |
+
// add src
|
448 |
+
$value[ 'sizes' ][ $image_size ] = $src[0];
|
449 |
+
$value[ 'sizes' ][ $image_size . '-width' ] = $src[1];
|
450 |
+
$value[ 'sizes' ][ $image_size . '-height' ] = $src[2];
|
451 |
+
}
|
452 |
+
// foreach( $image_sizes as $image_size )
|
453 |
}
|
|
|
454 |
}
|
455 |
+
elseif(is_array( $data->cropped_image)){
|
456 |
+
$value = array(
|
457 |
+
'url' => $this->getAbsoluteImageUrl($data->cropped_image['image']),
|
458 |
+
);
|
459 |
+
}
|
460 |
+
else{
|
461 |
+
|
462 |
+
//echo 'ELSE';
|
463 |
+
}
|
464 |
+
|
465 |
+
}
|
466 |
return $value;
|
467 |
+
|
468 |
}
|
469 |
|
470 |
/*
|
484 |
// Note: This function can be removed if not used
|
485 |
|
486 |
|
487 |
+
// register acf scripts
|
488 |
wp_register_script('acf-input-image_crop', $this->settings['dir'] . 'js/input.js', array('acf-input', 'imgareaselect'), $this->settings['version']);
|
489 |
|
490 |
+
wp_register_style('acf-input-image_crop', $this->settings['dir'] . 'css/input.css', array('acf-input'), $this->settings['version']);
|
491 |
wp_register_script( 'jcrop', includes_url( 'js/jcrop/jquery.Jcrop.min.css' ));
|
492 |
|
493 |
|
494 |
+
// scripts
|
495 |
+
wp_enqueue_script(array(
|
496 |
'acf-input-image_crop'
|
497 |
));
|
498 |
|
529 |
wp_enqueue_style( 'acf-input-image-crop-options');
|
530 |
}
|
531 |
|
532 |
+
|
533 |
/*
|
534 |
* update_value()
|
535 |
*
|
545 |
*
|
546 |
* @return $value - the modified value
|
547 |
*/
|
548 |
+
|
549 |
function update_value( $value, $post_id, $field )
|
550 |
{
|
551 |
// array?
|
552 |
if( is_array($value) && isset($value['id']) )
|
553 |
{
|
554 |
+
$value = $value['id'];
|
555 |
}
|
556 |
+
|
557 |
// object?
|
558 |
if( is_object($value) && isset($value->ID) )
|
559 |
{
|
560 |
$value = $value->ID;
|
561 |
}
|
562 |
+
|
563 |
return $value;
|
564 |
}
|
565 |
|
566 |
+
function get_image_data($field){
|
567 |
+
$imageData = new stdClass();
|
568 |
+
$imageData->original_image = '';
|
569 |
+
$imageData->original_image_width = '';
|
570 |
+
$imageData->original_image_height = '';
|
571 |
+
$imageData->cropped_image = '';
|
572 |
+
$imageData->original_image_url = '';
|
573 |
+
$imageData->preview_image_url = '';
|
574 |
+
$imageData->image_url = '';
|
575 |
+
|
576 |
+
if($field['value'] == ''){
|
577 |
+
// Field has not yet been saved or is an empty image field
|
578 |
+
return $imageData;
|
579 |
+
}
|
580 |
+
|
581 |
+
$data = json_decode($field['value']);
|
582 |
+
|
583 |
+
if(! is_object($data)){
|
584 |
+
// Field was saved as a regular image field
|
585 |
+
$imageAtts = wp_get_attachment_image_src($field['value'], 'full');
|
586 |
+
$imageData->original_image = $field['value'];
|
587 |
+
$imageData->original_image_width = $imageAtts[1];
|
588 |
+
$imageData->original_image_height = $imageAtts[2];
|
589 |
+
$imageData->preview_image_url = $this->get_image_src($field['value'], $field['preview_size']);
|
590 |
+
$imageData->image_url = $this->get_image_src($field['value'], 'full');
|
591 |
+
return $imageData;
|
592 |
+
}
|
593 |
+
|
594 |
+
if( !is_numeric($data->original_image) )
|
595 |
+
{
|
596 |
+
// The field has been saved, but has no image
|
597 |
+
return $imageData;
|
598 |
+
}
|
599 |
+
|
600 |
+
// By now, we have at least a saved original image
|
601 |
+
$imageAtts = wp_get_attachment_image_src($data->original_image, 'full');
|
602 |
+
$imageData->original_image = $data->original_image;
|
603 |
+
$imageData->original_image_width = $imageAtts[1];
|
604 |
+
$imageData->original_image_height = $imageAtts[2];
|
605 |
+
$imageData->original_image_url = $this->get_image_src($data->original_image, 'full');
|
606 |
+
|
607 |
+
// Set defaults to original image
|
608 |
+
$imageData->image_url = $this->get_image_src($data->original_image, 'full');
|
609 |
+
$imageData->preview_image_url = $this->get_image_src($data->original_image, $field['preview_size']);
|
610 |
+
|
611 |
+
// Check if there is a cropped version and set appropriate attributes
|
612 |
+
if(is_numeric($data->cropped_image)){
|
613 |
+
// Cropped image was saved to media library ans has an ID
|
614 |
+
$imageData->cropped_image = $data->cropped_image;
|
615 |
+
$imageData->image_url = $this->get_image_src($data->cropped_image, 'full');
|
616 |
+
$imageData->preview_image_url = $this->get_image_src($data->cropped_image, $field['preview_size']);
|
617 |
+
}
|
618 |
+
elseif(is_object($data->cropped_image)){
|
619 |
+
// Cropped image was not saved to media library and is only stored by its URL
|
620 |
+
$imageData->cropped_image = $data->cropped_image;
|
621 |
+
|
622 |
+
// Generate appropriate URLs
|
623 |
+
$mediaDir = wp_upload_dir();
|
624 |
+
$imageData->image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->image;
|
625 |
+
$imageData->preview_image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->preview;
|
626 |
+
}
|
627 |
+
return $imageData;
|
628 |
+
}
|
629 |
+
|
630 |
function perform_crop(){
|
631 |
$targetWidth = $_POST['target_width'];
|
632 |
+
$targetHeight = $_POST['target_height'];
|
633 |
+
$saveToMediaLibrary = $_POST['save_to_media_library'] == 'yes';
|
634 |
+
$imageData = $this->generate_cropped_image($_POST['id'], $_POST['x1'], $_POST['x2'], $_POST['y1'], $_POST['y2'], $targetWidth, $targetHeight, $saveToMediaLibrary, $_POST['preview_size']);
|
635 |
+
// $previewUrl = wp_get_attachment_image_src( $id, $_POST['preview_size']);
|
636 |
+
// $fullUrl = wp_get_attachment_image_src( $id, 'full');
|
637 |
+
echo json_encode($imageData);
|
|
|
|
|
|
|
|
|
638 |
die();
|
639 |
}
|
640 |
|
641 |
+
function generate_cropped_image($id, $x1, $x2, $y1, $y2, $targetW, $targetH, $saveToMediaLibrary, $previewSize){//$id, $x1, $x2, $y$, $y2, $targetW, $targetH){
|
642 |
require_once ABSPATH . "/wp-admin/includes/file.php";
|
643 |
+
require_once ABSPATH . "/wp-admin/includes/image.php";
|
644 |
+
|
645 |
+
// Create the variable that will hold the new image data
|
646 |
+
$imageData = array();
|
647 |
+
|
648 |
+
// Fetch media library info
|
649 |
+
$mediaDir = wp_upload_dir();
|
650 |
+
|
651 |
+
// Get original image info
|
652 |
+
$originalImageData = wp_get_attachment_metadata($id);
|
653 |
+
|
654 |
+
// Get image editor from original image path to crop the image
|
655 |
+
$image = wp_get_image_editor( $mediaDir['basedir'] . '/' . $originalImageData['file'] );
|
656 |
+
|
657 |
+
// Crop the image using the provided measurements
|
658 |
+
$image->crop($x1, $y1, $x2 - $x1, $y2 - $y1, $targetW, $targetH);
|
659 |
+
|
660 |
+
// Retrieve original filename and seperate it from its file extension
|
661 |
+
$originalFileName = explode('.', basename($originalImageData['file']));
|
662 |
+
|
663 |
+
// Generate new base filename
|
664 |
+
$targetFileName = $originalFileName[0] . '_' . $targetW . 'x' . $targetH . '_acf_cropped' . '.' . $originalFileName[1];
|
665 |
+
|
666 |
+
// Generate target path new file using existing media library
|
667 |
+
$targetFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], $targetFileName);
|
668 |
+
|
669 |
+
// Get the relative path to save as the actual image url
|
670 |
+
$targetRelativePath = str_replace($mediaDir['basedir'] . '/', '', $targetFilePath);
|
671 |
+
|
672 |
+
// Save the image to the target path
|
673 |
+
if(is_wp_error($image->save($targetFilePath))){
|
674 |
+
// There was an error saving the image
|
675 |
+
//TODO handle it
|
676 |
+
}
|
677 |
+
|
678 |
+
// If file should be saved to media library, create an attachment for it at get the new attachment ID
|
679 |
+
if($saveToMediaLibrary){
|
680 |
+
// Generate attachment from created file
|
681 |
+
|
682 |
+
// Get the filetype
|
683 |
+
$wp_filetype = wp_check_filetype(basename($targetFilePath), null );
|
684 |
+
$attachment = array(
|
685 |
+
'guid' => $targetFilePath,
|
686 |
+
'post_mime_type' => $wp_filetype['type'],
|
687 |
+
'post_title' => preg_replace('/\.[^.]+$/', '', basename($targetFilePath)),
|
688 |
+
'post_content' => '',
|
689 |
+
'post_status' => 'inherit'
|
690 |
+
);
|
691 |
+
$attachmentId = wp_insert_attachment( $attachment, $targetFilePath);
|
692 |
+
$attachmentData = wp_generate_attachment_metadata( $attachmentId, $targetFilePath );
|
693 |
+
wp_update_attachment_metadata( $attachmentId, $attachmentData );
|
694 |
+
|
695 |
+
// Add the id to the imageData-array
|
696 |
+
$imageData['value'] = $attachmentId;
|
697 |
+
|
698 |
+
// Add the image url
|
699 |
+
$imageUrlObject = wp_get_attachment_image_src( $attachmentId, 'full');
|
700 |
+
$imageData['url'] = $imageUrlObject[0];
|
701 |
+
|
702 |
+
// Add the preview url as well
|
703 |
+
$previewUrlObject = wp_get_attachment_image_src( $attachmentId, $previewSize);
|
704 |
+
$imageData['preview_url'] = $previewUrlObject[0];
|
705 |
+
}
|
706 |
+
// Else we need to return the actual path of the cropped image
|
707 |
+
else{
|
708 |
+
// Add the image url to the imageData-array
|
709 |
+
$imageData['value'] = array('image' => $targetRelativePath);
|
710 |
+
$imageData['url'] = $mediaDir['baseurl'] . '/' . $targetRelativePath;
|
711 |
+
|
712 |
+
// Get preview size dimensions
|
713 |
+
global $_wp_additional_image_sizes;
|
714 |
+
$previewWidth = 0;
|
715 |
+
$previewHeight = 0;
|
716 |
+
$crop = 0;
|
717 |
+
if (isset($_wp_additional_image_sizes[$previewSize])) {
|
718 |
+
$previewWidth = intval($_wp_additional_image_sizes[$previewSize]['width']);
|
719 |
+
$previewHeight = intval($_wp_additional_image_sizes[$previewSize]['height']);
|
720 |
+
$crop = $_wp_additional_image_sizes[$previewSize]['crop'];
|
721 |
+
} else {
|
722 |
+
$previewWidth = get_option($previewSize.'_size_w');
|
723 |
+
$previewHeight = get_option($previewSize.'_size_h');
|
724 |
+
$crop = get_option($previewSize.'_crop');
|
725 |
+
}
|
726 |
+
|
727 |
+
// Generate preview file path
|
728 |
+
$previewFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], 'preview_' . $targetFileName);
|
729 |
+
$previewRelativePath = str_replace($mediaDir['basedir'] . '/', '', $previewFilePath);
|
730 |
+
|
731 |
+
// Get image editor from cropped image
|
732 |
+
$croppedImage = wp_get_image_editor( $targetFilePath );
|
733 |
+
$croppedImage->resize($previewWidth, $previewHeight, $crop);
|
734 |
+
|
735 |
+
// Save the preview
|
736 |
+
$croppedImage->save($previewFilePath);
|
737 |
+
|
738 |
+
// Add the preview url
|
739 |
+
$imageData['preview_url'] = $mediaDir['baseurl'] . '/' . $previewRelativePath;
|
740 |
+
$imageData['value']['preview'] = $previewRelativePath;
|
741 |
+
}
|
742 |
+
return $imageData;
|
743 |
+
}
|
744 |
+
|
745 |
+
function get_image_src($id, $size = 'thumbnail'){
|
746 |
+
$atts = wp_get_attachment_image_src( $id, $size);
|
747 |
+
return $atts[0];
|
748 |
+
}
|
749 |
+
|
750 |
+
function getAbsoluteImageUrl($relativeUrl){
|
751 |
+
$mediaDir = wp_upload_dir();
|
752 |
+
return $mediaDir['baseurl'] . '/' . $relativeUrl;
|
753 |
}
|
754 |
|
755 |
}
|
js/input.js
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
(function($){
|
2 |
-
|
3 |
-
|
4 |
/*
|
5 |
* acf/setup_fields
|
6 |
*
|
7 |
-
* This event is triggered when ACF adds any new elements to the DOM.
|
8 |
*
|
9 |
* @type function
|
10 |
* @since 1.0.0
|
@@ -15,10 +15,10 @@
|
|
15 |
*
|
16 |
* @return N/A
|
17 |
*/
|
18 |
-
|
19 |
-
$(document).on('acf/setup_fields', function(e, postbox){
|
20 |
$(postbox).find('.field_type-image_crop').each(function(){
|
21 |
-
var $field = $(this), $options = $field.find('.acf-image-uploader');
|
22 |
$field.find('.acf-image-value').on('change', function(){
|
23 |
var originalImage = $(this).val();
|
24 |
if($(this).val()){
|
@@ -26,14 +26,14 @@
|
|
26 |
$field.find('.init-crop-button').removeAttr('disabled');
|
27 |
$field.find('.acf-image-value').data('original-image', originalImage);
|
28 |
$field.find('.acf-image-value').data('cropped-image', originalImage);
|
29 |
-
$field.find('.acf-image-value').data('cropped', false);
|
30 |
$.post(ajaxurl, {action: 'acf_image_crop_get_image_size', image_id: originalImage}, function(data, textStatus, xhr) {
|
31 |
if($field.find('img.crop-image').length == 0){
|
32 |
$field.find('.crop-action').append($('<img class="crop-image" src="#"/>'));
|
33 |
}
|
34 |
-
$field.find('img.crop-image').attr('src', data['url']);
|
35 |
-
$field.find('img.crop-image').data('width', data['width']);
|
36 |
-
$field.find('img.crop-image').data('height', data['height']);
|
37 |
var warnings = [];
|
38 |
var valid = true;
|
39 |
if($options.data('width') && data['width'] < $options.data('width')){
|
@@ -52,18 +52,18 @@
|
|
52 |
else{
|
53 |
if($options.data('force-crop')){
|
54 |
initCrop($field);
|
55 |
-
}
|
56 |
}
|
57 |
-
|
58 |
}, 'json');
|
59 |
updateFieldValue($field);
|
60 |
}
|
61 |
else{
|
62 |
//Do nothing
|
63 |
}
|
64 |
-
|
65 |
-
})
|
66 |
-
$field.find('.init-crop-button').click(function(e){
|
67 |
e.preventDefault();
|
68 |
initCrop($field);
|
69 |
});
|
@@ -75,17 +75,17 @@
|
|
75 |
e.preventDefault();
|
76 |
cancelCrop($field);
|
77 |
});
|
78 |
-
});
|
79 |
-
|
80 |
});
|
81 |
|
82 |
function initCrop($field){
|
83 |
var $options = $field.find('.acf-image-uploader');
|
84 |
var options = {
|
85 |
handles: true,
|
86 |
-
onSelectEnd: function (img, selection) {
|
87 |
-
updateThumbnail($field, img, selection);
|
88 |
-
updateCropData($field, img, selection);
|
89 |
},
|
90 |
imageWidth:$options.find('.crop-stage img.crop-image').data('width'),
|
91 |
imageHeight:$options.find('.crop-stage img.crop-image').data('height'),
|
@@ -97,26 +97,32 @@
|
|
97 |
options.minWidth = $options.data('width');
|
98 |
options.minHeight = $options.data('height');
|
99 |
options.x2 = $options.data('width');
|
100 |
-
options.y2 = $options.data('height');
|
101 |
}
|
102 |
else if($options.data('crop-type') == 'min'){
|
103 |
if($options.data('width')){
|
104 |
-
options.minWidth = $options.data('width');
|
105 |
options.x2 = $options.data('width');
|
106 |
}
|
107 |
else{
|
108 |
options.x2 = options.imageWidth;
|
109 |
}
|
110 |
if($options.data('height')){
|
111 |
-
options.minHeight = $options.data('height');
|
112 |
options.y2 = $options.data('height');
|
113 |
}
|
114 |
else{
|
115 |
options.y2 = options.imageHeight;
|
116 |
-
}
|
117 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
if(!$field.hasClass('invalid')){
|
119 |
-
toggleCropView($field);
|
120 |
$field.find('.crop-stage img.crop-image').imgAreaSelect(options);
|
121 |
updateCropData($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
|
122 |
updateThumbnail($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
|
@@ -139,8 +145,8 @@
|
|
139 |
//image
|
140 |
div.css('background-image', 'url(' + img.src + ')');
|
141 |
//width
|
142 |
-
div.css('width', (selection.x2 - selection.x1) * factor);
|
143 |
-
//height
|
144 |
div.css('height', (selection.y2 - selection.y1) * factor);
|
145 |
//x offset
|
146 |
div.css('background-position-x', 0-(selection.x1 * factor));
|
@@ -157,12 +163,13 @@
|
|
157 |
return JSON.stringify(obj);
|
158 |
}
|
159 |
|
160 |
-
function performCrop($field){
|
161 |
if(!$field.find('.crop-stage').hasClass('loading')){
|
162 |
$field.find('.crop-stage').addClass('loading');
|
163 |
var $options = $field.find('.acf-image-uploader');
|
164 |
var targetWidth = $options.data('width');
|
165 |
var targetHeight = $options.data('height');
|
|
|
166 |
if($options.data('crop-type') == 'min'){
|
167 |
targetWidth = $options.data('x2') - $options.data('x1');
|
168 |
targetHeight = $options.data('y2') - $options.data('y1');
|
@@ -176,21 +183,22 @@
|
|
176 |
y2: $options.data('y2'),
|
177 |
target_width: targetWidth,
|
178 |
target_height: targetHeight,
|
179 |
-
preview_size: $options.data('preview_size')
|
180 |
-
|
|
|
181 |
$.post(ajaxurl, data, function(data, textStatus, xhr) {
|
182 |
-
$field.find('.acf-image-image').attr('src', data.
|
183 |
-
$field.find('.acf-image-value').data('cropped-image', data.
|
184 |
-
$field.find('.acf-image-value').data('cropped', true);
|
185 |
-
updateFieldValue($field);
|
186 |
-
$field.find('.crop-stage').removeClass('loading');
|
187 |
cancelCrop($field);
|
188 |
}, 'json');
|
189 |
}
|
190 |
}
|
191 |
|
192 |
function cancelCrop($field){
|
193 |
-
toggleCropView($field);
|
194 |
$field.find('.crop-stage img.crop-image').imgAreaSelect({remove:true});
|
195 |
}
|
196 |
|
@@ -199,14 +207,14 @@
|
|
199 |
$('#acf-image-crop-overlay').remove();
|
200 |
}
|
201 |
else{
|
202 |
-
$('body').append($('<div id="acf-image-crop-overlay"></div>'));
|
203 |
}
|
204 |
-
$field.toggleClass('cropping');
|
205 |
|
206 |
}
|
207 |
|
208 |
function updateFieldValue($field){
|
209 |
-
var $input = $field.find('.acf-image-value');
|
210 |
$input.val(generateCropJSON($input.data('original-image'), $input.data('cropped-image')));
|
211 |
}
|
212 |
|
1 |
(function($){
|
2 |
+
|
3 |
+
|
4 |
/*
|
5 |
* acf/setup_fields
|
6 |
*
|
7 |
+
* This event is triggered when ACF adds any new elements to the DOM.
|
8 |
*
|
9 |
* @type function
|
10 |
* @since 1.0.0
|
15 |
*
|
16 |
* @return N/A
|
17 |
*/
|
18 |
+
|
19 |
+
$(document).on('acf/setup_fields', function(e, postbox){
|
20 |
$(postbox).find('.field_type-image_crop').each(function(){
|
21 |
+
var $field = $(this), $options = $field.find('.acf-image-uploader');
|
22 |
$field.find('.acf-image-value').on('change', function(){
|
23 |
var originalImage = $(this).val();
|
24 |
if($(this).val()){
|
26 |
$field.find('.init-crop-button').removeAttr('disabled');
|
27 |
$field.find('.acf-image-value').data('original-image', originalImage);
|
28 |
$field.find('.acf-image-value').data('cropped-image', originalImage);
|
29 |
+
$field.find('.acf-image-value').data('cropped', false);
|
30 |
$.post(ajaxurl, {action: 'acf_image_crop_get_image_size', image_id: originalImage}, function(data, textStatus, xhr) {
|
31 |
if($field.find('img.crop-image').length == 0){
|
32 |
$field.find('.crop-action').append($('<img class="crop-image" src="#"/>'));
|
33 |
}
|
34 |
+
$field.find('img.crop-image').attr('src', data['url']);
|
35 |
+
$field.find('img.crop-image').data('width', data['width']);
|
36 |
+
$field.find('img.crop-image').data('height', data['height']);
|
37 |
var warnings = [];
|
38 |
var valid = true;
|
39 |
if($options.data('width') && data['width'] < $options.data('width')){
|
52 |
else{
|
53 |
if($options.data('force-crop')){
|
54 |
initCrop($field);
|
55 |
+
}
|
56 |
}
|
57 |
+
|
58 |
}, 'json');
|
59 |
updateFieldValue($field);
|
60 |
}
|
61 |
else{
|
62 |
//Do nothing
|
63 |
}
|
64 |
+
|
65 |
+
})
|
66 |
+
$field.find('.init-crop-button').click(function(e){
|
67 |
e.preventDefault();
|
68 |
initCrop($field);
|
69 |
});
|
75 |
e.preventDefault();
|
76 |
cancelCrop($field);
|
77 |
});
|
78 |
+
});
|
79 |
+
|
80 |
});
|
81 |
|
82 |
function initCrop($field){
|
83 |
var $options = $field.find('.acf-image-uploader');
|
84 |
var options = {
|
85 |
handles: true,
|
86 |
+
onSelectEnd: function (img, selection) {
|
87 |
+
updateThumbnail($field, img, selection);
|
88 |
+
updateCropData($field, img, selection);
|
89 |
},
|
90 |
imageWidth:$options.find('.crop-stage img.crop-image').data('width'),
|
91 |
imageHeight:$options.find('.crop-stage img.crop-image').data('height'),
|
97 |
options.minWidth = $options.data('width');
|
98 |
options.minHeight = $options.data('height');
|
99 |
options.x2 = $options.data('width');
|
100 |
+
options.y2 = $options.data('height');
|
101 |
}
|
102 |
else if($options.data('crop-type') == 'min'){
|
103 |
if($options.data('width')){
|
104 |
+
options.minWidth = $options.data('width');
|
105 |
options.x2 = $options.data('width');
|
106 |
}
|
107 |
else{
|
108 |
options.x2 = options.imageWidth;
|
109 |
}
|
110 |
if($options.data('height')){
|
111 |
+
options.minHeight = $options.data('height');
|
112 |
options.y2 = $options.data('height');
|
113 |
}
|
114 |
else{
|
115 |
options.y2 = options.imageHeight;
|
116 |
+
}
|
117 |
}
|
118 |
+
// Center crop - disabled needs more testing
|
119 |
+
// options.x1 = options.imageWidth/2 - (options.minWidth/2);
|
120 |
+
// options.y1 = options.imageHeight/2 - (options.minHeight/2)
|
121 |
+
// options.x2 = options.minWidth + options.x1;
|
122 |
+
// options.y2 = options.minHeight + options.y1;
|
123 |
+
//options.y1 = (options.imageHeight - options.minHeight) / 2;
|
124 |
if(!$field.hasClass('invalid')){
|
125 |
+
toggleCropView($field);
|
126 |
$field.find('.crop-stage img.crop-image').imgAreaSelect(options);
|
127 |
updateCropData($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
|
128 |
updateThumbnail($field, $field.find('.crop-stage img.crop-image').get(0), {y1: options.y1, y2: options.y2, x1: options.x1, x2: options.x2});
|
145 |
//image
|
146 |
div.css('background-image', 'url(' + img.src + ')');
|
147 |
//width
|
148 |
+
div.css('width', (selection.x2 - selection.x1) * factor);
|
149 |
+
//height
|
150 |
div.css('height', (selection.y2 - selection.y1) * factor);
|
151 |
//x offset
|
152 |
div.css('background-position-x', 0-(selection.x1 * factor));
|
163 |
return JSON.stringify(obj);
|
164 |
}
|
165 |
|
166 |
+
function performCrop($field){
|
167 |
if(!$field.find('.crop-stage').hasClass('loading')){
|
168 |
$field.find('.crop-stage').addClass('loading');
|
169 |
var $options = $field.find('.acf-image-uploader');
|
170 |
var targetWidth = $options.data('width');
|
171 |
var targetHeight = $options.data('height');
|
172 |
+
var saveToMediaLibrary = $options.data('save-to-media-library');
|
173 |
if($options.data('crop-type') == 'min'){
|
174 |
targetWidth = $options.data('x2') - $options.data('x1');
|
175 |
targetHeight = $options.data('y2') - $options.data('y1');
|
183 |
y2: $options.data('y2'),
|
184 |
target_width: targetWidth,
|
185 |
target_height: targetHeight,
|
186 |
+
preview_size: $options.data('preview_size'),
|
187 |
+
save_to_media_library: saveToMediaLibrary
|
188 |
+
}
|
189 |
$.post(ajaxurl, data, function(data, textStatus, xhr) {
|
190 |
+
$field.find('.acf-image-image').attr('src', data.preview_url);
|
191 |
+
$field.find('.acf-image-value').data('cropped-image', data.value);
|
192 |
+
$field.find('.acf-image-value').data('cropped', true);
|
193 |
+
updateFieldValue($field);
|
194 |
+
$field.find('.crop-stage').removeClass('loading');
|
195 |
cancelCrop($field);
|
196 |
}, 'json');
|
197 |
}
|
198 |
}
|
199 |
|
200 |
function cancelCrop($field){
|
201 |
+
toggleCropView($field);
|
202 |
$field.find('.crop-stage img.crop-image').imgAreaSelect({remove:true});
|
203 |
}
|
204 |
|
207 |
$('#acf-image-crop-overlay').remove();
|
208 |
}
|
209 |
else{
|
210 |
+
$('body').append($('<div id="acf-image-crop-overlay"></div>'));
|
211 |
}
|
212 |
+
$field.toggleClass('cropping');
|
213 |
|
214 |
}
|
215 |
|
216 |
function updateFieldValue($field){
|
217 |
+
var $input = $field.find('.acf-image-value');
|
218 |
$input.val(generateCropJSON($input.data('original-image'), $input.data('cropped-image')));
|
219 |
}
|
220 |
|
js/options.js
CHANGED
@@ -8,10 +8,24 @@ jQuery(function($){
|
|
8 |
}
|
9 |
|
10 |
});
|
11 |
-
$(document).on('change', '.field_type-image_crop .crop-type-select', function(e) {
|
12 |
-
|
13 |
$(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description').addClass('hidden');
|
14 |
$(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description[data-type=' + $(this).val() + ']').removeClass('hidden');
|
15 |
|
16 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
});
|
8 |
}
|
9 |
|
10 |
});
|
11 |
+
$(document).on('change', '.field_type-image_crop .crop-type-select', function(e) {
|
|
|
12 |
$(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description').addClass('hidden');
|
13 |
$(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description[data-type=' + $(this).val() + ']').removeClass('hidden');
|
14 |
|
15 |
});
|
16 |
+
$(document).on('click', '.field_type-image_crop .save-in-media-library-select input', function(e) {
|
17 |
+
var saveToMedia = $(this).val() == 'yes';
|
18 |
+
var $returnValueField = $(this).parents('.field_type-image_crop').find('.return-value-select');
|
19 |
+
if(! saveToMedia){
|
20 |
+
$returnValueField.find('input[value=id], input[value=object]').attr('disabled', true).parents('label').addClass('disabled');
|
21 |
+
$returnValueField.find('input[value=url]').attr('checked', true);
|
22 |
+
}
|
23 |
+
else{
|
24 |
+
$returnValueField.find('input').removeAttr('disabled').parents('label').removeClass('disabled');
|
25 |
+
}
|
26 |
+
|
27 |
+
// $(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description').addClass('hidden');
|
28 |
+
// $(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description[data-type=' + $(this).val() + ']').removeClass('hidden');
|
29 |
+
|
30 |
+
});
|
31 |
});
|
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
Contributors: andersthorborg
|
3 |
Tags: afc, advanced custom fields, image crop, image, crop
|
4 |
Requires at least: 3.5
|
5 |
-
Tested up to: 3.
|
6 |
-
Stable tag: 0
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -16,9 +16,11 @@ The field gives the developer/administrator the option to predefine a size for t
|
|
16 |
|
17 |
The plugin supports the defined image sizes as well as a custom option, enabling the developer to specify the dimensions from within the field edit screen.
|
18 |
|
19 |
-
The field can be configured to enforce a hard crop or a minimal-dimension-based crop. The hard crop will lock the aspect ratio of the crop where as the minimal-dimension-based crop will not allow the user to crop the image below the specified dimensions.
|
20 |
|
21 |
-
This plugin diverts from plugins like [Manual Image Crop](http://wordpress.org/plugins/manual-image-crop/) in that when the user crops an image, a new attachment is generated, so that the relevant crop only applies in the context it is edited. It also
|
|
|
|
|
22 |
|
23 |
= Compatibility =
|
24 |
|
@@ -59,6 +61,10 @@ function my_register_fields()
|
|
59 |
|
60 |
== Changelog ==
|
61 |
|
|
|
|
|
|
|
|
|
62 |
= 0.8 =
|
63 |
* Fixed an issue resulting in a black image, when image was cropped without moving the crop handles
|
64 |
|
2 |
Contributors: andersthorborg
|
3 |
Tags: afc, advanced custom fields, image crop, image, crop
|
4 |
Requires at least: 3.5
|
5 |
+
Tested up to: 3.9.1
|
6 |
+
Stable tag: 1.0
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
16 |
|
17 |
The plugin supports the defined image sizes as well as a custom option, enabling the developer to specify the dimensions from within the field edit screen.
|
18 |
|
19 |
+
The field can be configured to enforce a hard crop or a minimal-dimension-based crop. The hard crop will lock the aspect ratio of the crop where as the minimal-dimension-based crop will not allow the user to crop the image below the specified dimensions.
|
20 |
|
21 |
+
This plugin diverts from plugins like [Manual Image Crop](http://wordpress.org/plugins/manual-image-crop/) in that when the user crops an image, a new attachment is generated, so that the relevant crop only applies in the context it is edited. It also keeps the user from dealing with the concept of various image sizes.
|
22 |
+
|
23 |
+
As of version 1.0 the field can be configured to either create the cropped image as a media-item (the default behavior) or simply create it and refer directly to the file without adding it to the media library. This will prevent the media library from being cluttered with several cropped versions of the same image. When this option is selected the only available return type for the field is URL.
|
24 |
|
25 |
= Compatibility =
|
26 |
|
61 |
|
62 |
== Changelog ==
|
63 |
|
64 |
+
= 1.0 =
|
65 |
+
* Added option to save the image to media library or refer directly to the created image, not using the media library.
|
66 |
+
* Added better compatibility with the native image field making it possible to migrate from the regular image field to the crop-image field without losing the images currently attached. (It doesn't work the other way around)
|
67 |
+
|
68 |
= 0.8 =
|
69 |
* Fixed an issue resulting in a black image, when image was cropped without moving the crop handles
|
70 |
|
screenshot-1.png
ADDED
Binary file
|
screenshot-2.png
ADDED
Binary file
|
screenshot-3.png
ADDED
Binary file
|
screenshot-4.png
ADDED
Binary file
|
screenshot-5.png
ADDED
Binary file
|
screenshot-6.png
ADDED
Binary file
|