Advanced Custom Fields: Image Crop Add-on - Version 0.8

Version Description

  • Fixed an issue resulting in a black image, when image was cropped without moving the crop handles
Download this release

Release Info

Developer andersthorborg
Plugin Icon wp plugin Advanced Custom Fields: Image Crop Add-on
Version 0.8
Comparing to
See all releases

Version 0.8

acf-image-crop.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
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.8
7
+ Author: Anders Thorborg
8
+ Author URI: http://thorb.org
9
+ License: GPLv2 or later
10
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
+ */
12
+
13
+
14
+ class acf_field_image_crop_plugin
15
+ {
16
+ /*
17
+ * Construct
18
+ *
19
+ * @description:
20
+ * @since: 3.6
21
+ * @created: 1/04/13
22
+ */
23
+
24
+ function __construct()
25
+ {
26
+ // set text domain
27
+ /*
28
+ $domain = 'acf-image_crop';
29
+ $mofile = trailingslashit(dirname(__File__)) . 'lang/' . $domain . '-' . get_locale() . '.mo';
30
+ load_textdomain( $domain, $mofile );
31
+ */
32
+
33
+
34
+ // version 4+
35
+ add_action('acf/register_fields', array($this, 'register_fields'));
36
+
37
+
38
+ // version 3-
39
+ add_action('init', array( $this, 'init' ), 5);
40
+ }
41
+
42
+
43
+ /*
44
+ * Init
45
+ *
46
+ * @description:
47
+ * @since: 3.6
48
+ * @created: 1/04/13
49
+ */
50
+
51
+ function init()
52
+ {
53
+ if(function_exists('register_field'))
54
+ {
55
+ register_field('acf_field_image_crop', dirname(__File__) . '/image_crop-v3.php');
56
+ }
57
+ }
58
+
59
+ /*
60
+ * register_fields
61
+ *
62
+ * @description:
63
+ * @since: 3.6
64
+ * @created: 1/04/13
65
+ */
66
+
67
+ function register_fields()
68
+ {
69
+ include_once('image_crop-v4.php');
70
+ }
71
+
72
+ }
73
+
74
+ new acf_field_image_crop_plugin();
75
+
76
+ ?>
assets/screenshot-1.png ADDED
Binary file
assets/screenshot-2.png ADDED
Binary file
assets/screenshot-3.png ADDED
Binary file
assets/screenshot-4.png ADDED
Binary file
assets/screenshot-5.png ADDED
Binary file
assets/screenshot-6.png ADDED
Binary file
css/input.css ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .field_type-image_crop .crop-stage .crop-image{
2
+ max-width:100%;
3
+ }
4
+ .field_type-image_crop .crop-stage .crop-action{
5
+ float:left;
6
+ width:65%;
7
+ }
8
+ .field_type-image_crop .crop-stage .crop-preview{
9
+ float:right;
10
+ width:25%;
11
+ }
12
+ .field_type-image_crop .crop-stage .crop-preview .preview{
13
+ width:100%;
14
+ }
15
+
16
+ .field_type-image_crop .crop-stage .crop-preview .crop-controls{
17
+ padding-top:20px;
18
+ clear: both;
19
+ }
20
+
21
+ .field_type-image_crop .crop-section .crop-stage, .field_type-image_crop.cropping .image-section, .field_type-image_crop.cropping .init-crop-button{
22
+ display:none;
23
+ }
24
+ .field_type-image_crop.cropping .crop-stage {
25
+ display:block;
26
+ position:fixed;
27
+ top:60px;
28
+ width:800px;
29
+ left:50%;
30
+ margin-left:-440px;
31
+ height:auto;
32
+ background-color: #fff;
33
+ box-shadow: 0px 0px 3px rgba(0,0,0,0.5);
34
+ padding:40px;
35
+ z-index: 100;
36
+
37
+ }
38
+ .field_type-image_crop.cropping .has-image, .field_type-image_crop.cropping .crop-section{
39
+ width:100%;
40
+ }
41
+
42
+ .field_type-image_crop .crop-stage.loading .crop-controls{
43
+ -webkit-transition: opacity 300ms;
44
+ -moz-transition: opacity 300ms;
45
+ -ms-transition: opacity 300ms;
46
+ -o-transition: opacity 300ms;
47
+ transition: opacity 300ms;
48
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
49
+ filter: alpha(opacity=20);
50
+ opacity:0.2;
51
+ }
52
+
53
+ .button.init-crop-button{
54
+ margin-top: 20px;
55
+ }
56
+ #acf-image-crop-overlay{
57
+ position:fixed;
58
+ top:0px;
59
+ left:0px;
60
+ right:0px;
61
+ bottom:0px;
62
+ background-color: rgba(0,0,0,0.8);
63
+ }
css/options.css ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ .field_type-image_crop .dimensions-wrap .acf-input-wrap{
2
+ float:left;
3
+ }
4
+ .field_type-image_crop .dimensions-wrap .dimension{
5
+ width:150px;
6
+ }
image_crop-v3.php ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class acf_field_image_crop extends acf_Field
4
+ {
5
+
6
+ // vars
7
+ var $settings, // will hold info such as dir / path
8
+ $defaults; // will hold default field options
9
+
10
+
11
+ /*--------------------------------------------------------------------------------------
12
+ *
13
+ * Constructor
14
+ * - This function is called when the field class is initalized on each page.
15
+ * - Here you can add filters / actions and setup any other functionality for your field
16
+ *
17
+ * @author Elliot Condon
18
+ * @since 2.2.0
19
+ *
20
+ *-------------------------------------------------------------------------------------*/
21
+
22
+ function __construct($parent)
23
+ {
24
+
25
+ // do not delete!
26
+ parent::__construct($parent);
27
+
28
+ // set name / title
29
+ $this->name = 'image_crop';
30
+ $this->title = __('Image - Custom crop');
31
+ $this->defaults = array(
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:
34
+ //'preview_size' => 'thumbnail'
35
+ );
36
+
37
+ // settings
38
+ $this->settings = array(
39
+ 'path' => $this->helpers_get_path(__FILE__),
40
+ 'dir' => $this->helpers_get_dir(__FILE__),
41
+ 'version' => '1.0.0'
42
+ );
43
+
44
+ }
45
+
46
+
47
+ /*
48
+ * helpers_get_path
49
+ *
50
+ * @description: calculates the path (works for plugin / theme folders)
51
+ * @since: 3.6
52
+ * @created: 30/01/13
53
+ */
54
+
55
+ function helpers_get_path($file)
56
+ {
57
+ return trailingslashit(dirname($file));
58
+ }
59
+
60
+
61
+ /*
62
+ * helpers_get_dir
63
+ *
64
+ * @description: calculates the directory (works for plugin / theme folders)
65
+ * @since: 3.6
66
+ * @created: 30/01/13
67
+ */
68
+
69
+ function helpers_get_dir($file)
70
+ {
71
+ $dir = trailingslashit(dirname($file));
72
+ $count = 0;
73
+
74
+
75
+ // sanitize for Win32 installs
76
+ $dir = str_replace('\\', '/', $dir);
77
+
78
+
79
+ // if file is in plugins folder
80
+ $wp_plugin_dir = str_replace('\\', '/', WP_PLUGIN_DIR);
81
+ $dir = str_replace($wp_plugin_dir, WP_PLUGIN_URL, $dir, $count);
82
+
83
+
84
+ if($count < 1)
85
+ {
86
+ // if file is in wp-content folder
87
+ $wp_content_dir = str_replace('\\', '/', WP_CONTENT_DIR);
88
+ $dir = str_replace($wp_content_dir, WP_CONTENT_URL, $dir, $count);
89
+ }
90
+
91
+
92
+ if($count < 1)
93
+ {
94
+ // if file is in ??? folder
95
+ $wp_dir = str_replace('\\', '/', ABSPATH);
96
+ $dir = str_replace($wp_dir, site_url('/'), $dir);
97
+ }
98
+
99
+ return $dir;
100
+ }
101
+
102
+
103
+ /*--------------------------------------------------------------------------------------
104
+ *
105
+ * create_options
106
+ * - this function is called from core/field_meta_box.php to create extra options
107
+ * for your field
108
+ *
109
+ * @params
110
+ * - $key (int) - the $_POST obejct key required to save the options to the field
111
+ * - $field (array) - the field object
112
+ *
113
+ * @author Elliot Condon
114
+ * @since 2.2.0
115
+ *
116
+ *-------------------------------------------------------------------------------------*/
117
+
118
+ function create_options($key, $field)
119
+ {
120
+ // defaults?
121
+ /*
122
+ $field = array_merge($this->defaults, $field);
123
+ */
124
+
125
+
126
+ // Create Field Options HTML
127
+ ?>
128
+ <tr class="field_option field_option_<?php echo $this->name; ?>">
129
+ <td class="label">
130
+ <label><?php _e("Preview Size", 'acf'); ?></label>
131
+ <p class="description"><?php _e("Thumbnail is advised", 'acf'); ?></p>
132
+ </td>
133
+ <td>
134
+ <?php
135
+
136
+ $this->parent->create_field(array(
137
+ 'type' => 'radio',
138
+ 'name' => 'fields[' . $key . '][preview_size]',
139
+ 'value' => $field['preview_size'],
140
+ 'layout' => 'horizontal',
141
+ 'choices' => array(
142
+ 'thumbnail' => __('Thumbnail'),
143
+ 'something_else' => __('Something Else'),
144
+ )
145
+ ));
146
+
147
+ ?>
148
+ </td>
149
+ </tr>
150
+ <?php
151
+ }
152
+
153
+
154
+ /*--------------------------------------------------------------------------------------
155
+ *
156
+ * pre_save_field
157
+ * - this function is called when saving your acf object. Here you can manipulate the
158
+ * field object and it's options before it gets saved to the database.
159
+ *
160
+ * @author Elliot Condon
161
+ * @since 2.2.0
162
+ *
163
+ *-------------------------------------------------------------------------------------*/
164
+
165
+ function pre_save_field($field)
166
+ {
167
+ // Note: This function can be removed if not used
168
+
169
+ // do stuff with field (mostly format options data)
170
+
171
+ return parent::pre_save_field($field);
172
+ }
173
+
174
+
175
+ /*--------------------------------------------------------------------------------------
176
+ *
177
+ * create_field
178
+ * - this function is called on edit screens to produce the html for this field
179
+ *
180
+ * @author Elliot Condon
181
+ * @since 2.2.0
182
+ *
183
+ *-------------------------------------------------------------------------------------*/
184
+
185
+ function create_field($field)
186
+ {
187
+ // defaults?
188
+ /*
189
+ $field = array_merge($this->defaults, $field);
190
+ */
191
+
192
+ // perhaps use $field['preview_size'] to alter the markup?
193
+
194
+
195
+ // create Field HTML
196
+ ?>
197
+ <div>
198
+
199
+ </div>
200
+ <?php
201
+ }
202
+
203
+
204
+ /*--------------------------------------------------------------------------------------
205
+ *
206
+ * admin_head
207
+ * - this function is called in the admin_head of the edit screen where your field
208
+ * is created. Use this function to create css and javascript to assist your
209
+ * create_field() function.
210
+ *
211
+ * @author Elliot Condon
212
+ * @since 2.2.0
213
+ *
214
+ *-------------------------------------------------------------------------------------*/
215
+
216
+ function admin_head()
217
+ {
218
+ // Note: This function can be removed if not used
219
+ }
220
+
221
+
222
+ /*--------------------------------------------------------------------------------------
223
+ *
224
+ * admin_print_scripts / admin_print_styles
225
+ * - this function is called in the admin_print_scripts / admin_print_styles where
226
+ * your field is created. Use this function to register css and javascript to assist
227
+ * your create_field() function.
228
+ *
229
+ * @author Elliot Condon
230
+ * @since 3.0.0
231
+ *
232
+ *-------------------------------------------------------------------------------------*/
233
+
234
+ function admin_print_scripts()
235
+ {
236
+ // Note: This function can be removed if not used
237
+
238
+
239
+ // register acf scripts
240
+ wp_register_script('acf-input-image_crop', $this->settings['dir'] . 'js/input.js', array('acf-input'), $this->settings['version']);
241
+
242
+ // scripts
243
+ wp_enqueue_script(array(
244
+ 'acf-input-image_crop',
245
+ ));
246
+
247
+
248
+ }
249
+
250
+ function admin_print_styles()
251
+ {
252
+ // Note: This function can be removed if not used
253
+
254
+
255
+ wp_register_style('acf-input-image_crop', $this->settings['dir'] . 'css/input.css', array('acf-input'), $this->settings['version']);
256
+
257
+ // styles
258
+ wp_enqueue_style(array(
259
+ 'acf-input-image_crop',
260
+ ));
261
+ }
262
+
263
+
264
+ /*--------------------------------------------------------------------------------------
265
+ *
266
+ * update_value
267
+ * - this function is called when saving a post object that your field is assigned to.
268
+ * the function will pass through the 3 parameters for you to use.
269
+ *
270
+ * @params
271
+ * - $post_id (int) - usefull if you need to save extra data or manipulate the current
272
+ * post object
273
+ * - $field (array) - usefull if you need to manipulate the $value based on a field option
274
+ * - $value (mixed) - the new value of your field.
275
+ *
276
+ * @author Elliot Condon
277
+ * @since 2.2.0
278
+ *
279
+ *-------------------------------------------------------------------------------------*/
280
+
281
+ function update_value($post_id, $field, $value)
282
+ {
283
+ // Note: This function can be removed if not used
284
+
285
+ // do stuff with value
286
+
287
+ // save value
288
+ parent::update_value($post_id, $field, $value);
289
+ }
290
+
291
+
292
+ /*--------------------------------------------------------------------------------------
293
+ *
294
+ * get_value
295
+ * - called from the edit page to get the value of your field. This function is useful
296
+ * if your field needs to collect extra data for your create_field() function.
297
+ *
298
+ * @params
299
+ * - $post_id (int) - the post ID which your value is attached to
300
+ * - $field (array) - the field object.
301
+ *
302
+ * @author Elliot Condon
303
+ * @since 2.2.0
304
+ *
305
+ *-------------------------------------------------------------------------------------*/
306
+
307
+ function get_value($post_id, $field)
308
+ {
309
+ // Note: This function can be removed if not used
310
+
311
+ // get value
312
+ $value = parent::get_value($post_id, $field);
313
+
314
+ // format value
315
+
316
+ // return value
317
+ return $value;
318
+ }
319
+
320
+
321
+ /*--------------------------------------------------------------------------------------
322
+ *
323
+ * get_value_for_api
324
+ * - called from your template file when using the API functions (get_field, etc).
325
+ * This function is useful if your field needs to format the returned value
326
+ *
327
+ * @params
328
+ * - $post_id (int) - the post ID which your value is attached to
329
+ * - $field (array) - the field object.
330
+ *
331
+ * @author Elliot Condon
332
+ * @since 3.0.0
333
+ *
334
+ *-------------------------------------------------------------------------------------*/
335
+
336
+ function get_value_for_api($post_id, $field)
337
+ {
338
+ // Note: This function can be removed if not used
339
+
340
+ // get value
341
+ $value = $this->get_value($post_id, $field);
342
+
343
+ // format value
344
+
345
+ // return value
346
+ return $value;
347
+
348
+ }
349
+
350
+ }
351
+
352
+ ?>
image_crop-v4.php ADDED
@@ -0,0 +1,553 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class acf_field_image_crop extends acf_field_image
4
+ {
5
+ // vars
6
+ var $settings, // will hold info such as dir / path
7
+ $defaults; // will hold default field options
8
+
9
+
10
+ /*
11
+ * __construct
12
+ *
13
+ * Set name / label needed for actions / filters
14
+ *
15
+ * @since 3.6
16
+ * @date 23/01/13
17
+ */
18
+
19
+ function __construct()
20
+ {
21
+ // vars
22
+ $this->name = 'image_crop';
23
+ $this->label = __('Image with user-crop');
24
+ $this->category = __("Content",'acf'); // Basic, Content, Choice, etc
25
+ $this->defaults = array(
26
+ 'force_crop' => 'no',
27
+ 'crop_type' => 'hard',
28
+ 'preview_size' => 'medium',
29
+ 'save_format' => 'object',
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:
33
+ //'preview_size' => 'thumbnail'
34
+ );
35
+
36
+ //Call grandparent cunstructor
37
+ acf_field::__construct();
38
+
39
+ // settings
40
+ $this->settings = array(
41
+ 'path' => apply_filters('acf/helpers/get_path', __FILE__),
42
+ 'dir' => apply_filters('acf/helpers/get_dir', __FILE__),
43
+ 'version' => '1.0.0'
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],
59
+ 'width' => $img[1],
60
+ 'height' => $img[2]
61
+ ) );
62
+ }
63
+ exit;
64
+ }
65
+
66
+
67
+ /*
68
+ * create_options()
69
+ *
70
+ * Create extra options for your field. This is rendered when editing a field.
71
+ * The value of $field['name'] can be used (like bellow) to save extra data to the $field
72
+ *
73
+ * @type action
74
+ * @since 3.6
75
+ * @date 23/01/13
76
+ *
77
+ * @param $field - an array holding all the field's data
78
+ */
79
+
80
+ function create_options($field)
81
+ {
82
+ // defaults?
83
+ /*
84
+ $field = array_merge($this->defaults, $field);
85
+ */
86
+
87
+ // key is needed in the field names to correctly save the data
88
+ $key = $field['name'];
89
+
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>
117
+ <p class="description"><?php _e("Select the type of crop the user should perform", 'acf'); ?></p>
118
+ </td>
119
+ <td>
120
+ <?php
121
+
122
+ do_action('acf/create_field', array(
123
+ 'type' => 'select',
124
+ 'name' => 'fields[' . $key . '][crop_type]',
125
+ 'value' => $field['target_size'],
126
+ 'class' => 'crop-type-select',
127
+ 'choices' => array(
128
+ 'hard' => __('Hard crop', 'acf'),
129
+ 'min' => __('Minimal dimensions', 'acf')
130
+ )
131
+ ));
132
+
133
+ ?>
134
+ </td>
135
+ </tr>
136
+ <tr class="field_option field_option_<?php echo $this->name; ?>">
137
+ <td class="label">
138
+ <label><?php _e("Target Size", 'acf'); ?></label>
139
+ <p class="description"><?php _e("Select the target size for this field", 'acf'); ?></p>
140
+ </td>
141
+ <td>
142
+ <?php
143
+ $sizes = array_merge(apply_filters('acf/get_image_sizes', array()), array('custom' => __("Custom size",'acf')));
144
+ unset($sizes['full']);
145
+ do_action('acf/create_field', array(
146
+ 'type' => 'select',
147
+ 'name' => 'fields[' . $key . '][target_size]',
148
+ 'value' => $field['target_size'],
149
+ 'class' => 'target-size-select',
150
+ 'choices' => $sizes
151
+ ));
152
+
153
+ ?>
154
+ </td>
155
+ </tr>
156
+ <tr class="field_option field_option_<?php echo $this->name; ?> dimensions-wrap <?php echo ($field['target_size'] == 'custom' ? '' : 'hidden') ?>">
157
+ <td class="label">
158
+ <label><?php _e("Dimensions", 'acf'); ?></label>
159
+ <p class="description"><span class="dimensions-description <?php echo ($field['crop_type'] != 'hard' ? 'hidden' : '') ?>" data-type="hard"><?php _e("Enter the dimensions for the image.", 'acf'); ?></span><span class="dimensions-description <?php echo ($field['crop_type'] != 'min' ? 'hidden' : '') ?>" data-type="min"><?php _e("Enter the minimum dimensions for the image. Leave fields blank for no minimum requirement.", 'acf'); ?></span></p>
160
+ </td>
161
+ <td>
162
+ <?php
163
+
164
+ do_action('acf/create_field', array(
165
+ 'type' => 'text',
166
+ 'name' => 'fields[' . $key . '][width]',
167
+ 'value' => $field['width'],
168
+ 'class' => 'width dimension',
169
+ 'placeholder' => 'Width'
170
+ ));
171
+ ?>
172
+ <div class="acf-input-wrap">&nbsp;:&nbsp;</div>
173
+ <?php
174
+ do_action('acf/create_field', array(
175
+ 'type' => 'text',
176
+ 'name' => 'fields[' . $key . '][height]',
177
+ 'value' => $field['height'],
178
+ 'class' => 'height dimension',
179
+ 'placeholder' => 'Height'
180
+ ));
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>
187
+ <p><?php _e("Force the user to crop the image as soon at it is selected.",'acf') ?></p>
188
+ </td>
189
+ <td>
190
+ <?php
191
+ do_action('acf/create_field', array(
192
+ 'type' => 'radio',
193
+ 'name' => 'fields['.$key.'][force_crop]',
194
+ 'value' => $field['force_crop'],
195
+ 'layout' => 'horizontal',
196
+ 'choices' => array(
197
+ 'yes' => __("Yes",'acf'),
198
+ 'no' => __("No",'acf')
199
+ )
200
+ ));
201
+ ?>
202
+ </td>
203
+ </tr>
204
+ <tr class="field_option field_option_<?php echo $this->name; ?>">
205
+ <td class="label">
206
+ <label><?php _e("Preview Size", 'acf'); ?></label>
207
+ <p class="description"><?php _e("Select the target size for this field", 'acf'); ?></p>
208
+ </td>
209
+ <td>
210
+ <?php
211
+ do_action('acf/create_field', array(
212
+ 'type' => 'select',
213
+ 'name' => 'fields[' . $key . '][preview_size]',
214
+ 'value' => $field['preview_size'],
215
+ 'class' => 'preview-size-select',
216
+ 'choices' => apply_filters('acf/get_image_sizes', array())
217
+ ));
218
+
219
+ ?>
220
+ </td>
221
+ </tr>
222
+
223
+ <?php
224
+
225
+ }
226
+
227
+
228
+ /*
229
+ * create_field()
230
+ *
231
+ * Create the HTML interface for your field
232
+ *
233
+ * @param $field - an array holding all the field's data
234
+ *
235
+ * @type action
236
+ * @since 3.6
237
+ * @date 23/01/13
238
+ */
239
+
240
+ function create_field( $field )
241
+ {
242
+ // defaults?
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
+ $originalImage = wp_get_attachment_image_src($data->original_image, 'full');
259
+ $url = wp_get_attachment_image_src($data->original_image, $field['preview_size']);
260
+ if(is_numeric($data->cropped_image)){
261
+ $url = wp_get_attachment_image_src($data->cropped_image, $field['preview_size']);
262
+ }
263
+ $o['class'] = 'active';
264
+ $o['url'] = $url[0];
265
+ }
266
+ $width = 0;
267
+ $height = 0;
268
+ if($field['target_size'] == 'custom'){
269
+ $width = $field['width'];
270
+ $height = $field['height'];
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 ?>" data-cropped-image="<?php echo $data->cropped_image ?>" type="hidden" name="<?php echo $field['name']; ?>" value="<?php echo htmlspecialchars($field['value']); ?>" />
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=""/>
295
+ </div>
296
+ <div class="crop-section">
297
+ <div class="crop-stage">
298
+ <div class="crop-action">
299
+ <h4>Crop the image</h4>
300
+ <?php if ($originalImage ): ?>
301
+ <img class="crop-image" src="<?php echo $originalImage[0] ?>" data-width="<?php echo $originalImage[1] ?>" data-height="<?php echo $originalImage[2] ?>" alt="">
302
+ <?php endif ?>
303
+ </div>
304
+ <div class="crop-preview">
305
+ <h4>Preview</h4>
306
+ <div class="preview"></div>
307
+ <div class="crop-controls">
308
+ <a href="#" class="button button-large cancel-crop-button">Cancel</a> <a href="#" class="button button-large button-primary perform-crop-button">Crop!</a>
309
+ </div>
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">
317
+ <p><?php _e('No image selected','acf'); ?> <input type="button" class="button add-image" value="<?php _e('Add Image','acf'); ?>" />
318
+ </div>
319
+ </div>
320
+ <?php
321
+ }
322
+
323
+
324
+
325
+ /*
326
+ * format_value_for_api()
327
+ *
328
+ * This filter is appied to the $value after it is loaded from the db and before it is passed back to the api functions such as the_field
329
+ *
330
+ * @type filter
331
+ * @since 3.6
332
+ * @date 23/01/13
333
+ *
334
+ * @param $value - the value which was loaded from the database
335
+ * @param $post_id - the $post_id from which the value was loaded
336
+ * @param $field - the field array holding all the field options
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
+ {
347
+ return false;
348
+ }
349
+ $data = json_decode($value);
350
+ if(!is_object($data)){
351
+ return $value;
352
+ }
353
+
354
+ $value = $data->cropped_image;
355
+
356
+ // format
357
+ if( $field['save_format'] == 'url' )
358
+ {
359
+ $value = wp_get_attachment_url( $data->cropped_image );
360
+ }
361
+ elseif( $field['save_format'] == 'object' )
362
+ {
363
+ $attachment = get_post( $data->cropped_image );
364
+
365
+
366
+ // validate
367
+ if( !$attachment )
368
+ {
369
+ return false;
370
+ }
371
+
372
+
373
+ // create array to hold value data
374
+ $src = wp_get_attachment_image_src( $attachment->ID, 'full' );
375
+
376
+ $value = array(
377
+ 'id' => $attachment->ID,
378
+ 'alt' => get_post_meta($attachment->ID, '_wp_attachment_image_alt', true),
379
+ 'title' => $attachment->post_title,
380
+ 'caption' => $attachment->post_excerpt,
381
+ 'description' => $attachment->post_content,
382
+ 'mime_type' => $attachment->post_mime_type,
383
+ 'url' => $src[0],
384
+ 'width' => $src[1],
385
+ 'height' => $src[2],
386
+ 'sizes' => array(),
387
+ );
388
+
389
+
390
+ // find all image sizes
391
+ $image_sizes = get_intermediate_image_sizes();
392
+
393
+ if( $image_sizes )
394
+ {
395
+ foreach( $image_sizes as $image_size )
396
+ {
397
+ // find src
398
+ $src = wp_get_attachment_image_src( $attachment->ID, $image_size );
399
+
400
+ // add src
401
+ $value[ 'sizes' ][ $image_size ] = $src[0];
402
+ $value[ 'sizes' ][ $image_size . '-width' ] = $src[1];
403
+ $value[ 'sizes' ][ $image_size . '-height' ] = $src[2];
404
+ }
405
+ // foreach( $image_sizes as $image_size )
406
+ }
407
+ // if( $image_sizes )
408
+
409
+ }
410
+ return $value;
411
+
412
+ }
413
+
414
+ /*
415
+ * input_admin_enqueue_scripts()
416
+ *
417
+ * This action is called in the admin_enqueue_scripts action on the edit screen where your field is created.
418
+ * Use this action to add css + javascript to assist your create_field() action.
419
+ *
420
+ * $info http://codex.wordpress.org/Plugin_API/Action_Reference/admin_enqueue_scripts
421
+ * @type action
422
+ * @since 3.6
423
+ * @date 23/01/13
424
+ */
425
+
426
+ function input_admin_enqueue_scripts()
427
+ {
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
+
443
+ wp_localize_script( 'acf-input-image_crop', 'ajax', array('nonce' => wp_create_nonce('acf_nonce')) );
444
+
445
+ // styles
446
+ wp_enqueue_style(array(
447
+ 'acf-input-image_crop',
448
+ 'imgareaselect'
449
+ ));
450
+
451
+ }
452
+
453
+
454
+ /*
455
+ * field_group_admin_enqueue_scripts()
456
+ *
457
+ * This action is called in the admin_enqueue_scripts action on the edit screen where your field is edited.
458
+ * Use this action to add css + javascript to assist your create_field_options() action.
459
+ *
460
+ * $info http://codex.wordpress.org/Plugin_API/Action_Reference/admin_enqueue_scripts
461
+ * @type action
462
+ * @since 3.6
463
+ * @date 23/01/13
464
+ */
465
+
466
+ function field_group_admin_enqueue_scripts()
467
+ {
468
+ // Note: This function can be removed if not used
469
+ wp_register_script('acf-input-image-crop-options', $this->settings['dir'] . 'js/options.js', array('jquery'), $this->settings['version']);
470
+ wp_enqueue_script( 'acf-input-image-crop-options');
471
+
472
+ wp_register_style('acf-input-image-crop-options', $this->settings['dir'] . 'css/options.css');
473
+ wp_enqueue_style( 'acf-input-image-crop-options');
474
+ }
475
+
476
+
477
+ /*
478
+ * update_value()
479
+ *
480
+ * This filter is appied to the $value before it is updated in the db
481
+ *
482
+ * @type filter
483
+ * @since 3.6
484
+ * @date 23/01/13
485
+ *
486
+ * @param $value - the value which will be saved in the database
487
+ * @param $post_id - the $post_id of which the value will be saved
488
+ * @param $field - the field array holding all the field options
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
+ $id = $this->generate_cropped_image($_POST['id'], $_POST['x1'], $_POST['x2'], $_POST['y1'], $_POST['y2'], $targetWidth, $targetHeight);
514
+ $previewUrl = wp_get_attachment_image_src( $id, $_POST['preview_size']);
515
+ $fullUrl = wp_get_attachment_image_src( $id, 'full');
516
+ $data = array(
517
+ 'id' => $id,
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
+ $filename = wp_crop_image($id, $x1, $y1, $x2 - $x1, $y2 - $y1, $targetW, $targetH);
530
+ // GENERATE NEW ATTACHMENT FROM NEW FILE
531
+ $wp_filetype = wp_check_filetype(basename($filename), null );
532
+ $attachment = array(
533
+ 'guid' => $filename,
534
+ 'post_mime_type' => $wp_filetype['type'],
535
+ 'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
536
+ 'post_content' => '',
537
+ 'post_status' => 'inherit'
538
+ );
539
+ $attach_id = wp_insert_attachment( $attachment, $filename);
540
+ $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
541
+ wp_update_attachment_metadata( $attach_id, $attach_data );
542
+
543
+ // Return ID of cropped image
544
+ return $attach_id;
545
+ }
546
+
547
+ }
548
+
549
+
550
+ // create field
551
+ new acf_field_image_crop();
552
+
553
+ ?>
js/input.js ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
11
+ * @date 01/01/12
12
+ *
13
+ * @param event e: an event object. This can be ignored
14
+ * @param Element postbox: An element which contains the new HTML
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()){
25
+ $field.removeClass('invalid');
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')){
40
+ warnings.push('Width should be at least: ' + $options.data('width') + 'px (Selected image width: ' + data['width'] + 'px)');
41
+ valid = false;
42
+ }
43
+ if($options.data('height') && data['height'] < $options.data('height')){
44
+ warnings.push('Height should be at least: ' + $options.data('height') + 'px (Selected image height: ' + data['height'] + 'px)');
45
+ valid = false;
46
+ }
47
+ if(!valid){
48
+ $field.addClass('invalid');
49
+ $field.find('.init-crop-button').attr('disabled', 'disabled');
50
+ alert('Warning: The selected image is smaller than the required size:\n' + warnings.join('\n'));
51
+ }
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
+ });
70
+ $field.find('.perform-crop-button').click(function(e){
71
+ e.preventDefault();
72
+ performCrop($field);
73
+ });
74
+ $field.find('.cancel-crop-button').click(function(e){
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'),
92
+ x1: 0,
93
+ y1: 0
94
+ };
95
+ if($options.data('crop-type') == 'hard'){
96
+ options.aspectRatio = $options.data('width') + ':' + $options.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
+ 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});
123
+ }
124
+ }
125
+
126
+ function updateCropData($field, img, selection){
127
+ var $options = $field.find('.acf-image-uploader');
128
+ $options.data('x1', selection.x1);
129
+ $options.data('x2', selection.x2);
130
+ $options.data('y1', selection.y1);
131
+ $options.data('y2', selection.y2);
132
+ }
133
+
134
+ function updateThumbnail($field, img, selection){
135
+ var $options = $field.find('.acf-image-uploader');
136
+ var div = $field.find('.crop-preview .preview');
137
+ var targetWidth = $field.find('.crop-preview .preview').width();
138
+ var factor = targetWidth / (selection.x2 - selection.x1);
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));
147
+ //y offset
148
+ div.css('background-position-y', 0-(selection.y1 * factor));
149
+ div.css('background-size', $options.find('.crop-stage img.crop-image').data('width') * factor + 'px' + ' ' + $options.find('.crop-stage img.crop-image').data('height') * factor + 'px');
150
+ }
151
+
152
+ function generateCropJSON(originalImage, croppedImage){
153
+ var obj = {
154
+ original_image: originalImage,
155
+ cropped_image: croppedImage
156
+ }
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');
169
+ }
170
+ var data = {
171
+ action: 'acf_image_crop_perform_crop',
172
+ id: $field.find('.acf-image-value').data('original-image'),
173
+ x1: $options.data('x1'),
174
+ x2: $options.data('x2'),
175
+ y1: $options.data('y1'),
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.url_preview);
183
+ $field.find('.acf-image-value').data('cropped-image', data.id);
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
+
197
+ function toggleCropView($field){
198
+ if($field.hasClass('cropping')){
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
+
213
+ function getFullImageUrl(id, callback){
214
+ $.post(ajaxurl, {images: []}, function(data, textStatus, xhr) {
215
+ }, 'json');
216
+ }
217
+
218
+ })(jQuery);
js/options.js ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(function($){
2
+ $(document).on('change', '.field_type-image_crop .target-size-select', function(e) {
3
+ if($(this).val() == 'custom'){
4
+ $(this).parents('.field_type-image_crop').find('.dimensions-wrap').removeClass('hidden');
5
+ }
6
+ else{
7
+ $(this).parents('.field_type-image_crop').find('.dimensions-wrap').addClass('hidden');
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
+ });
readme.txt ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Advanced Custom Fields: Image Crop Add-on ===
2
+ Contributors: andersthorborg
3
+ Tags: afc, advanced custom fields, image crop, image, crop
4
+ Requires at least: 3.5
5
+ Tested up to: 3.8.1
6
+ Stable tag: 0.8
7
+ License: GPLv2 or later
8
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ An image field making it possible/required for the user to crop the selected image to the specified image size or dimensions
11
+
12
+ == Description ==
13
+
14
+ ACF image crop is an extended version of the native Image-field in ACF.
15
+ 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.
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 spares the user from dealing with the concept of various image sizes. (This does however have the potential of over-crowding the media-directory with differently cropped versions of images).
22
+
23
+ = Compatibility =
24
+
25
+ This add-on will work with:
26
+
27
+ * version 4 and up
28
+
29
+ == Installation ==
30
+
31
+ This add-on can be treated as both a WP plugin and a theme include.
32
+
33
+ = Plugin =
34
+ 1. Copy the 'acf-image_crop' folder into your plugins folder
35
+ 2. Activate the plugin via the Plugins admin page
36
+
37
+ = Include =
38
+ 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
39
+ 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)
40
+
41
+ `
42
+ add_action('acf/register_fields', 'my_register_fields');
43
+
44
+ function my_register_fields()
45
+ {
46
+ include_once('acf-image-crop/acf-image-crop.php');
47
+ }
48
+ `
49
+
50
+ == Screenshots ==
51
+
52
+ 1. Use a registered image size as the field target size
53
+ 2. Or use custom dimensions on the fly
54
+ 3. On the edit screen, select/upload an image as usual
55
+ 4. A crop-button will appear beneath the image (If desired, use the "Force user crop"-option to initialize the crop as soon as the user selects the image)
56
+ 5. The image is cropped to the desired format, using the restrictions set under field options
57
+ 6. The new format is shown using the specified preview size. The original image is kept with the field, so the image can be re-cropped at any time.
58
+
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
+
65
+ = 0.7 =
66
+ * Fixed return types other than image id causing fatal error
67
+
68
+ = 0.6 =
69
+ * Fix for WP installs with non-standard folder structures
70
+
71
+ = 0.5 =
72
+ * Initial Release.
73
+