Version Description
- Added ACF5 compatibility.
- Please report any compatibility issues. As this has been an urgent feature request I have not had as much time for testing as I would have liked.
Download this release
Release Info
Developer | andersthorborg |
Plugin | Advanced Custom Fields: Image Crop Add-on |
Version | 1.1 |
Comparing to | |
See all releases |
Code changes from version 1.0 to 1.1
- image_crop-v4.php → acf-image-crop-v4.php +2 -2
- acf-image-crop-v5.php +1037 -0
- acf-image-crop.php +25 -59
- js/input-v4.js +226 -0
- js/input.js +124 -78
- js/options-v4.js +31 -0
- js/options.js +59 -22
- lang/README.md +5 -0
- readme.txt +5 -1
image_crop-v4.php → acf-image-crop-v4.php
RENAMED
@@ -485,7 +485,7 @@ class acf_field_image_crop extends acf_field_image
|
|
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' ));
|
@@ -522,7 +522,7 @@ class acf_field_image_crop extends acf_field_image
|
|
522 |
function field_group_admin_enqueue_scripts()
|
523 |
{
|
524 |
// Note: This function can be removed if not used
|
525 |
-
wp_register_script('acf-input-image-crop-options', $this->settings['dir'] . 'js/options.js', array('jquery'), $this->settings['version']);
|
526 |
wp_enqueue_script( 'acf-input-image-crop-options');
|
527 |
|
528 |
wp_register_style('acf-input-image-crop-options', $this->settings['dir'] . 'css/options.css');
|
485 |
|
486 |
|
487 |
// register acf scripts
|
488 |
+
wp_register_script('acf-input-image_crop', $this->settings['dir'] . 'js/input-v4.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' ));
|
522 |
function field_group_admin_enqueue_scripts()
|
523 |
{
|
524 |
// Note: This function can be removed if not used
|
525 |
+
wp_register_script('acf-input-image-crop-options', $this->settings['dir'] . 'js/options-v4.js', array('jquery'), $this->settings['version']);
|
526 |
wp_enqueue_script( 'acf-input-image-crop-options');
|
527 |
|
528 |
wp_register_style('acf-input-image-crop-options', $this->settings['dir'] . 'css/options.css');
|
acf-image-crop-v5.php
ADDED
@@ -0,0 +1,1037 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class acf_field_image_crop extends acf_field_image {
|
4 |
+
|
5 |
+
|
6 |
+
/*
|
7 |
+
* __construct
|
8 |
+
*
|
9 |
+
* This function will setup the field type data
|
10 |
+
*
|
11 |
+
* @type function
|
12 |
+
* @date 5/03/2014
|
13 |
+
* @since 5.0.0
|
14 |
+
*
|
15 |
+
* @param n/a
|
16 |
+
* @return n/a
|
17 |
+
*/
|
18 |
+
|
19 |
+
function __construct() {
|
20 |
+
|
21 |
+
/*
|
22 |
+
* name (string) Single word, no spaces. Underscores allowed
|
23 |
+
*/
|
24 |
+
|
25 |
+
$this->name = 'image_crop';
|
26 |
+
|
27 |
+
|
28 |
+
/*
|
29 |
+
* label (string) Multiple words, can include spaces, visible when selecting a field type
|
30 |
+
*/
|
31 |
+
|
32 |
+
$this->label = __('Image with user-crop', 'acf-image_crop');
|
33 |
+
|
34 |
+
|
35 |
+
/*
|
36 |
+
* category (string) basic | content | choice | relational | jquery | layout | CUSTOM GROUP NAME
|
37 |
+
*/
|
38 |
+
|
39 |
+
$this->category = 'content';
|
40 |
+
|
41 |
+
|
42 |
+
/*
|
43 |
+
* defaults (array) Array of default settings which are merged into the field object. These are used later in settings
|
44 |
+
*/
|
45 |
+
|
46 |
+
$this->defaults = array(
|
47 |
+
'force_crop' => 'no',
|
48 |
+
'crop_type' => 'hard',
|
49 |
+
'preview_size' => 'medium',
|
50 |
+
'save_format' => 'id',
|
51 |
+
'save_in_media_library' => 'yes',
|
52 |
+
'target_size' => 'thumbnail'
|
53 |
+
);
|
54 |
+
|
55 |
+
// add ajax action to be able to retrieve full image size via javascript
|
56 |
+
add_action( 'wp_ajax_acf_image_crop_get_image_size', array( &$this, 'crop_get_image_size' ) );
|
57 |
+
add_action( 'wp_ajax_acf_image_crop_perform_crop', array( &$this, 'perform_crop' ) );
|
58 |
+
|
59 |
+
|
60 |
+
/*
|
61 |
+
* l10n (array) Array of strings that are used in JavaScript. This allows JS strings to be translated in PHP and loaded via:
|
62 |
+
* var message = acf._e('image_crop', 'error');
|
63 |
+
*/
|
64 |
+
|
65 |
+
$this->l10n = array(
|
66 |
+
'error' => __('Error! Please enter a higher value', 'acf-image_crop'),
|
67 |
+
);
|
68 |
+
|
69 |
+
|
70 |
+
// do not delete!
|
71 |
+
acf_field::__construct();
|
72 |
+
//parent::__construct();
|
73 |
+
|
74 |
+
}
|
75 |
+
|
76 |
+
|
77 |
+
// AJAX handler for retieving full image dimensions from ID
|
78 |
+
public function crop_get_image_size()
|
79 |
+
{
|
80 |
+
$img = wp_get_attachment_image_src( $_POST['image_id'], 'full');
|
81 |
+
if($img){
|
82 |
+
echo json_encode( array(
|
83 |
+
'url' => $img[0],
|
84 |
+
'width' => $img[1],
|
85 |
+
'height' => $img[2]
|
86 |
+
) );
|
87 |
+
}
|
88 |
+
exit;
|
89 |
+
}
|
90 |
+
|
91 |
+
|
92 |
+
/*
|
93 |
+
* render_field_settings()
|
94 |
+
*
|
95 |
+
* Create extra settings for your field. These are visible when editing a field
|
96 |
+
*
|
97 |
+
* @type action
|
98 |
+
* @since 3.6
|
99 |
+
* @date 23/01/13
|
100 |
+
*
|
101 |
+
* @param $field (array) the $field being edited
|
102 |
+
* @return n/a
|
103 |
+
*/
|
104 |
+
|
105 |
+
function render_field_settings( $field ) {
|
106 |
+
|
107 |
+
/*
|
108 |
+
* acf_render_field_setting
|
109 |
+
*
|
110 |
+
* This function will create a setting for your field. Simply pass the $field parameter and an array of field settings.
|
111 |
+
* The array of settings does not require a `value` or `prefix`; These settings are found from the $field array.
|
112 |
+
*
|
113 |
+
* More than one setting can be added by copy/paste the above code.
|
114 |
+
* Please note that you must also have a matching $defaults value for the field name (font_size)
|
115 |
+
*/
|
116 |
+
|
117 |
+
// crop_type
|
118 |
+
acf_render_field_setting( $field, array(
|
119 |
+
'label' => __('Crop type','acf-image_crop'),
|
120 |
+
'instructions' => __('Select the type of crop the user should perform','acf-image_crop'),
|
121 |
+
'type' => 'select',
|
122 |
+
'name' => 'crop_type',
|
123 |
+
'layout' => 'horizontal',
|
124 |
+
'class' => 'crop-type-select',
|
125 |
+
'choices' => array(
|
126 |
+
'hard' => __('Hard crop', 'acf-image_crop'),
|
127 |
+
'min' => __('Minimal dimensions', 'acf-image_crop')
|
128 |
+
)
|
129 |
+
));
|
130 |
+
|
131 |
+
// target_size
|
132 |
+
$sizes = acf_get_image_sizes();
|
133 |
+
$sizes['custom'] = __('Custom size', 'acf-image_crop');
|
134 |
+
acf_render_field_setting( $field, array(
|
135 |
+
'label' => __('Target size','acf-image_crop'),
|
136 |
+
'instructions' => __('Select the target size for this field','acf-image_crop'),
|
137 |
+
'type' => 'select',
|
138 |
+
'name' => 'target_size',
|
139 |
+
'class' => 'target-size-select',
|
140 |
+
'choices' => $sizes
|
141 |
+
));
|
142 |
+
|
143 |
+
// width - conditional: target_size == 'custom'
|
144 |
+
acf_render_field_setting( $field, array(
|
145 |
+
'label' => __('Custom target width','acf-image_crop'),
|
146 |
+
'instructions' => __('Leave blank for no restriction (does not work with hard crop option)','acf-image_crop'),
|
147 |
+
'type' => 'number',
|
148 |
+
'name' => 'width',
|
149 |
+
'class' => 'custom-target-width custom-target-dimension'
|
150 |
+
));
|
151 |
+
|
152 |
+
// height - conditional: target_size == 'custom'
|
153 |
+
acf_render_field_setting( $field, array(
|
154 |
+
'label' => __('Custom target height','acf-image_crop'),
|
155 |
+
'instructions' => __('Leave blank for no restriction (does not work with hard crop option)','acf-image_crop'),
|
156 |
+
'type' => 'number',
|
157 |
+
'name' => 'height',
|
158 |
+
'class' => 'custom-target-height custom-target-dimension'
|
159 |
+
));
|
160 |
+
|
161 |
+
// preview_size
|
162 |
+
acf_render_field_setting( $field, array(
|
163 |
+
'label' => __('Preview size','acf-image_crop'),
|
164 |
+
'instructions' => __('Select the preview size for this field','acf-image_crop'),
|
165 |
+
'type' => 'select',
|
166 |
+
'name' => 'preview_size',
|
167 |
+
'choices' => acf_get_image_sizes()
|
168 |
+
));
|
169 |
+
|
170 |
+
// force_crop
|
171 |
+
acf_render_field_setting( $field, array(
|
172 |
+
'label' => __('Force crop','acf-image_crop'),
|
173 |
+
'instructions' => __('Force the user to crop the image as soon at it is selected','acf-image_crop'),
|
174 |
+
'type' => 'radio',
|
175 |
+
'layout' => 'horizontal',
|
176 |
+
'name' => 'force_crop',
|
177 |
+
'choices' => array('yes' => 'Yes', 'no' => 'No')
|
178 |
+
));
|
179 |
+
|
180 |
+
// save_in_media_library
|
181 |
+
acf_render_field_setting( $field, array(
|
182 |
+
'label' => __('Save cropped image to media library','acf-image_crop'),
|
183 |
+
'instructions' => __('If the cropped image is not saved in the media library, "Image URL" is the only available return value.','acf-image_crop'),
|
184 |
+
'type' => 'radio',
|
185 |
+
'layout' => 'horizontal',
|
186 |
+
'name' => 'save_in_media_library',
|
187 |
+
'class' => 'save-in-media-library-select',
|
188 |
+
'choices' => array('yes' => 'Yes', 'no' => 'No')
|
189 |
+
));
|
190 |
+
|
191 |
+
|
192 |
+
// return_format
|
193 |
+
acf_render_field_setting( $field, array(
|
194 |
+
'label' => __('Return Value','acf-image_crop'),
|
195 |
+
'instructions' => __('Specify the returned value on front end','acf-image_crop'),
|
196 |
+
'type' => 'radio',
|
197 |
+
'name' => 'save_format',
|
198 |
+
'layout' => 'horizontal',
|
199 |
+
'class' => 'return-value-select',
|
200 |
+
'choices' => array(
|
201 |
+
'url' => __("Image URL",'acf'),
|
202 |
+
'id' => __("Image ID",'acf'),
|
203 |
+
'object' => __("Image Object",'acf')
|
204 |
+
)
|
205 |
+
));
|
206 |
+
|
207 |
+
// library
|
208 |
+
acf_render_field_setting( $field, array(
|
209 |
+
'label' => __('Library','acf'),
|
210 |
+
'instructions' => __('Limit the media library choice','acf'),
|
211 |
+
'type' => 'radio',
|
212 |
+
'name' => 'library',
|
213 |
+
'layout' => 'horizontal',
|
214 |
+
'choices' => array(
|
215 |
+
'all' => __('All', 'acf'),
|
216 |
+
'uploadedTo' => __('Uploaded to post', 'acf')
|
217 |
+
)
|
218 |
+
));
|
219 |
+
|
220 |
+
}
|
221 |
+
|
222 |
+
|
223 |
+
|
224 |
+
/*
|
225 |
+
* render_field()
|
226 |
+
*
|
227 |
+
* Create the HTML interface for your field
|
228 |
+
*
|
229 |
+
* @param $field (array) the $field being rendered
|
230 |
+
*
|
231 |
+
* @type action
|
232 |
+
* @since 3.6
|
233 |
+
* @date 23/01/13
|
234 |
+
*
|
235 |
+
* @param $field (array) the $field being edited
|
236 |
+
* @return n/a
|
237 |
+
*/
|
238 |
+
|
239 |
+
function render_field( $field ) {
|
240 |
+
|
241 |
+
|
242 |
+
// enqueue
|
243 |
+
acf_enqueue_uploader();
|
244 |
+
|
245 |
+
// get data from value
|
246 |
+
//$data = json_decode($field['value']);
|
247 |
+
$imageData = $this->get_image_data($field);
|
248 |
+
|
249 |
+
$url = '';
|
250 |
+
$orignialImage = null;
|
251 |
+
|
252 |
+
if($imageData->original_image){
|
253 |
+
$originalImage = wp_get_attachment_image_src($imageData->original_image, 'full');
|
254 |
+
$url = $imageData->preview_image_url;
|
255 |
+
}
|
256 |
+
|
257 |
+
$width = 0;
|
258 |
+
$height = 0;
|
259 |
+
|
260 |
+
if($field['target_size'] == 'custom'){
|
261 |
+
$width = $field['width'];
|
262 |
+
$height = $field['height'];
|
263 |
+
}
|
264 |
+
else{
|
265 |
+
global $_wp_additional_image_sizes;
|
266 |
+
$s = $field['target_size'];
|
267 |
+
if (isset($_wp_additional_image_sizes[$s])) {
|
268 |
+
$width = intval($_wp_additional_image_sizes[$s]['width']);
|
269 |
+
$height = intval($_wp_additional_image_sizes[$s]['height']);
|
270 |
+
} else {
|
271 |
+
$width = get_option($s.'_size_w');
|
272 |
+
$height = get_option($s.'_size_h');
|
273 |
+
}
|
274 |
+
}
|
275 |
+
|
276 |
+
// vars
|
277 |
+
$div_atts = array(
|
278 |
+
'class' => 'acf-image-uploader acf-cf acf-image-crop',
|
279 |
+
'data-crop_type' => $field['crop_type'],
|
280 |
+
'data-target_size' => $field['target_size'],
|
281 |
+
'data-width' => $width,
|
282 |
+
'data-height' => $height,
|
283 |
+
'data-force_crop' => $field['force_crop'] == 'yes' ? 'true' : 'false',
|
284 |
+
'data-save_in_media_library' => $field['save_in_media_library'] == 'yes' ? 'true' : 'false',
|
285 |
+
'data-save_format' => $field['save_format'],
|
286 |
+
'data-preview_size' => $field['preview_size'],
|
287 |
+
'data-library' => $field['library']
|
288 |
+
);
|
289 |
+
$input_atts = array(
|
290 |
+
'type' => 'hidden',
|
291 |
+
'name' => $field['name'],
|
292 |
+
'value' => htmlspecialchars($field['value']),
|
293 |
+
'data-name' => 'value-id',
|
294 |
+
'data-original-image' => $imageData->original_image,
|
295 |
+
'data-cropped-image' => json_encode($imageData->cropped_image),
|
296 |
+
'class' => 'acf-image-value'
|
297 |
+
);
|
298 |
+
|
299 |
+
// has value?
|
300 |
+
if($imageData->original_image){
|
301 |
+
$url = $imageData->preview_image_url;
|
302 |
+
$div_atts['class'] .= ' has-value';
|
303 |
+
}
|
304 |
+
|
305 |
+
?>
|
306 |
+
<div <?php acf_esc_attr_e( $div_atts ); ?>>
|
307 |
+
<div class="acf-hidden">
|
308 |
+
<input <?php acf_esc_attr_e( $input_atts ); ?>/>
|
309 |
+
</div>
|
310 |
+
<div class="view show-if-value acf-soh">
|
311 |
+
<ul class="acf-hl acf-soh-target">
|
312 |
+
<li><a class="acf-icon dark" data-name="edit-button" href="#"><i class="acf-sprite-edit"></i></a></li>
|
313 |
+
<li><a class="acf-icon dark" data-name="remove-button" href="#"><i class="acf-sprite-delete"></i></a></li>
|
314 |
+
</ul>
|
315 |
+
<img data-name="value-url" src="<?php echo $url; ?>" alt=""/>
|
316 |
+
<div class="crop-section">
|
317 |
+
<div class="crop-stage">
|
318 |
+
<div class="crop-action">
|
319 |
+
<h4>Crop the image</h4>
|
320 |
+
<?php if ($imageData->original_image ): ?>
|
321 |
+
<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="">
|
322 |
+
<?php endif ?>
|
323 |
+
</div>
|
324 |
+
<div class="crop-preview">
|
325 |
+
<h4>Preview</h4>
|
326 |
+
<div class="preview"></div>
|
327 |
+
<div class="crop-controls">
|
328 |
+
<a href="#" class="button button-large cancel-crop-button">Cancel</a> <a href="#" class="button button-large button-primary perform-crop-button">Crop!</a>
|
329 |
+
</div>
|
330 |
+
</div>
|
331 |
+
<!-- <img src="<?php echo $o['url']; ?>" alt=""/> -->
|
332 |
+
</div>
|
333 |
+
<a href="#" class="button button-large init-crop-button">Crop</a>
|
334 |
+
</div>
|
335 |
+
</div>
|
336 |
+
<div class="view hide-if-value">
|
337 |
+
<p><?php _e('No image selected','acf'); ?> <a data-name="add-button" class="acf-button" href="#"><?php _e('Add Image','acf'); ?></a></p>
|
338 |
+
</div>
|
339 |
+
</div>
|
340 |
+
<?php
|
341 |
+
|
342 |
+
}
|
343 |
+
|
344 |
+
/***
|
345 |
+
* Parses the field value into a consistent data object
|
346 |
+
****/
|
347 |
+
function get_image_data($field){
|
348 |
+
$imageData = new stdClass();
|
349 |
+
$imageData->original_image = '';
|
350 |
+
$imageData->original_image_width = '';
|
351 |
+
$imageData->original_image_height = '';
|
352 |
+
$imageData->cropped_image = '';
|
353 |
+
$imageData->original_image_url = '';
|
354 |
+
$imageData->preview_image_url = '';
|
355 |
+
$imageData->image_url = '';
|
356 |
+
|
357 |
+
if($field['value'] == ''){
|
358 |
+
// Field has not yet been saved or is an empty image field
|
359 |
+
return $imageData;
|
360 |
+
}
|
361 |
+
|
362 |
+
$data = json_decode($field['value']);
|
363 |
+
|
364 |
+
if(! is_object($data)){
|
365 |
+
// Field was saved as a regular image field
|
366 |
+
$imageAtts = wp_get_attachment_image_src($field['value'], 'full');
|
367 |
+
$imageData->original_image = $field['value'];
|
368 |
+
$imageData->original_image_width = $imageAtts[1];
|
369 |
+
$imageData->original_image_height = $imageAtts[2];
|
370 |
+
$imageData->preview_image_url = $this->get_image_src($field['value'], $field['preview_size']);
|
371 |
+
$imageData->image_url = $this->get_image_src($field['value'], 'full');
|
372 |
+
return $imageData;
|
373 |
+
}
|
374 |
+
|
375 |
+
if( !is_numeric($data->original_image) )
|
376 |
+
{
|
377 |
+
// The field has been saved, but has no image
|
378 |
+
return $imageData;
|
379 |
+
}
|
380 |
+
|
381 |
+
// By now, we have at least a saved original image
|
382 |
+
$imageAtts = wp_get_attachment_image_src($data->original_image, 'full');
|
383 |
+
$imageData->original_image = $data->original_image;
|
384 |
+
$imageData->original_image_width = $imageAtts[1];
|
385 |
+
$imageData->original_image_height = $imageAtts[2];
|
386 |
+
$imageData->original_image_url = $this->get_image_src($data->original_image, 'full');
|
387 |
+
|
388 |
+
// Set defaults to original image
|
389 |
+
$imageData->image_url = $this->get_image_src($data->original_image, 'full');
|
390 |
+
$imageData->preview_image_url = $this->get_image_src($data->original_image, $field['preview_size']);
|
391 |
+
|
392 |
+
// Check if there is a cropped version and set appropriate attributes
|
393 |
+
if(is_numeric($data->cropped_image)){
|
394 |
+
// Cropped image was saved to media library ans has an ID
|
395 |
+
$imageData->cropped_image = $data->cropped_image;
|
396 |
+
$imageData->image_url = $this->get_image_src($data->cropped_image, 'full');
|
397 |
+
$imageData->preview_image_url = $this->get_image_src($data->cropped_image, $field['preview_size']);
|
398 |
+
}
|
399 |
+
elseif(is_object($data->cropped_image)){
|
400 |
+
// Cropped image was not saved to media library and is only stored by its URL
|
401 |
+
$imageData->cropped_image = $data->cropped_image;
|
402 |
+
|
403 |
+
// Generate appropriate URLs
|
404 |
+
$mediaDir = wp_upload_dir();
|
405 |
+
$imageData->image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->image;
|
406 |
+
$imageData->preview_image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->preview;
|
407 |
+
}
|
408 |
+
return $imageData;
|
409 |
+
}
|
410 |
+
|
411 |
+
|
412 |
+
/*
|
413 |
+
* input_admin_enqueue_scripts()
|
414 |
+
*
|
415 |
+
* This action is called in the admin_enqueue_scripts action on the edit screen where your field is created.
|
416 |
+
* Use this action to add CSS + JavaScript to assist your render_field() action.
|
417 |
+
*
|
418 |
+
* @type action (admin_enqueue_scripts)
|
419 |
+
* @since 3.6
|
420 |
+
* @date 23/01/13
|
421 |
+
*
|
422 |
+
* @param n/a
|
423 |
+
* @return n/a
|
424 |
+
*/
|
425 |
+
|
426 |
+
|
427 |
+
|
428 |
+
function input_admin_enqueue_scripts() {
|
429 |
+
|
430 |
+
$dir = plugin_dir_url( __FILE__ );
|
431 |
+
|
432 |
+
|
433 |
+
// // register & include JS
|
434 |
+
// wp_register_script( 'acf-input-image_crop', "{$dir}js/input.js" );
|
435 |
+
// wp_enqueue_script('acf-input-image_crop');
|
436 |
+
|
437 |
+
|
438 |
+
// // register & include CSS
|
439 |
+
// wp_register_style( 'acf-input-image_crop', "{$dir}css/input.css" );
|
440 |
+
// wp_enqueue_style('acf-input-image_crop');
|
441 |
+
|
442 |
+
// register acf scripts
|
443 |
+
wp_register_script('acf-input-image_crop', "{$dir}js/input.js", array('acf-input', 'imgareaselect'), $this->settings['version']);
|
444 |
+
|
445 |
+
wp_register_style('acf-input-image_crop', "{$dir}css/input.css", array('acf-input'), $this->settings['version']);
|
446 |
+
//wp_register_script( 'jcrop', includes_url( 'js/jcrop/jquery.Jcrop.min.css' ));
|
447 |
+
|
448 |
+
|
449 |
+
// scripts
|
450 |
+
wp_enqueue_script(array(
|
451 |
+
'acf-input-image_crop'
|
452 |
+
));
|
453 |
+
|
454 |
+
//wp_localize_script( 'acf-input-image_crop', 'ajax', array('nonce' => wp_create_nonce('acf_nonce')) );
|
455 |
+
|
456 |
+
// styles
|
457 |
+
wp_enqueue_style(array(
|
458 |
+
'acf-input-image_crop',
|
459 |
+
'imgareaselect'
|
460 |
+
));
|
461 |
+
|
462 |
+
|
463 |
+
}
|
464 |
+
|
465 |
+
function perform_crop(){
|
466 |
+
$targetWidth = $_POST['target_width'];
|
467 |
+
$targetHeight = $_POST['target_height'];
|
468 |
+
$saveToMediaLibrary = $_POST['save_to_media_library'] == 'yes';
|
469 |
+
$imageData = $this->generate_cropped_image($_POST['id'], $_POST['x1'], $_POST['x2'], $_POST['y1'], $_POST['y2'], $targetWidth, $targetHeight, $saveToMediaLibrary, $_POST['preview_size']);
|
470 |
+
// $previewUrl = wp_get_attachment_image_src( $id, $_POST['preview_size']);
|
471 |
+
// $fullUrl = wp_get_attachment_image_src( $id, 'full');
|
472 |
+
echo json_encode($imageData);
|
473 |
+
die();
|
474 |
+
}
|
475 |
+
|
476 |
+
function generate_cropped_image($id, $x1, $x2, $y1, $y2, $targetW, $targetH, $saveToMediaLibrary, $previewSize){//$id, $x1, $x2, $y$, $y2, $targetW, $targetH){
|
477 |
+
require_once ABSPATH . "/wp-admin/includes/file.php";
|
478 |
+
require_once ABSPATH . "/wp-admin/includes/image.php";
|
479 |
+
|
480 |
+
// Create the variable that will hold the new image data
|
481 |
+
$imageData = array();
|
482 |
+
|
483 |
+
// Fetch media library info
|
484 |
+
$mediaDir = wp_upload_dir();
|
485 |
+
|
486 |
+
// Get original image info
|
487 |
+
$originalImageData = wp_get_attachment_metadata($id);
|
488 |
+
|
489 |
+
// Get image editor from original image path to crop the image
|
490 |
+
$image = wp_get_image_editor( $mediaDir['basedir'] . '/' . $originalImageData['file'] );
|
491 |
+
|
492 |
+
// Crop the image using the provided measurements
|
493 |
+
$image->crop($x1, $y1, $x2 - $x1, $y2 - $y1, $targetW, $targetH);
|
494 |
+
|
495 |
+
// Retrieve original filename and seperate it from its file extension
|
496 |
+
$originalFileName = explode('.', basename($originalImageData['file']));
|
497 |
+
|
498 |
+
// Generate new base filename
|
499 |
+
$targetFileName = $originalFileName[0] . '_' . $targetW . 'x' . $targetH . '_acf_cropped' . '.' . $originalFileName[1];
|
500 |
+
|
501 |
+
// Generate target path new file using existing media library
|
502 |
+
$targetFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], $targetFileName);
|
503 |
+
|
504 |
+
// Get the relative path to save as the actual image url
|
505 |
+
$targetRelativePath = str_replace($mediaDir['basedir'] . '/', '', $targetFilePath);
|
506 |
+
|
507 |
+
// Save the image to the target path
|
508 |
+
if(is_wp_error($image->save($targetFilePath))){
|
509 |
+
// There was an error saving the image
|
510 |
+
//TODO handle it
|
511 |
+
}
|
512 |
+
|
513 |
+
// If file should be saved to media library, create an attachment for it at get the new attachment ID
|
514 |
+
if($saveToMediaLibrary){
|
515 |
+
// Generate attachment from created file
|
516 |
+
|
517 |
+
// Get the filetype
|
518 |
+
$wp_filetype = wp_check_filetype(basename($targetFilePath), null );
|
519 |
+
$attachment = array(
|
520 |
+
'guid' => $targetFilePath,
|
521 |
+
'post_mime_type' => $wp_filetype['type'],
|
522 |
+
'post_title' => preg_replace('/\.[^.]+$/', '', basename($targetFilePath)),
|
523 |
+
'post_content' => '',
|
524 |
+
'post_status' => 'inherit'
|
525 |
+
);
|
526 |
+
$attachmentId = wp_insert_attachment( $attachment, $targetFilePath);
|
527 |
+
$attachmentData = wp_generate_attachment_metadata( $attachmentId, $targetFilePath );
|
528 |
+
wp_update_attachment_metadata( $attachmentId, $attachmentData );
|
529 |
+
|
530 |
+
// Add the id to the imageData-array
|
531 |
+
$imageData['value'] = $attachmentId;
|
532 |
+
|
533 |
+
// Add the image url
|
534 |
+
$imageUrlObject = wp_get_attachment_image_src( $attachmentId, 'full');
|
535 |
+
$imageData['url'] = $imageUrlObject[0];
|
536 |
+
|
537 |
+
// Add the preview url as well
|
538 |
+
$previewUrlObject = wp_get_attachment_image_src( $attachmentId, $previewSize);
|
539 |
+
$imageData['preview_url'] = $previewUrlObject[0];
|
540 |
+
}
|
541 |
+
// Else we need to return the actual path of the cropped image
|
542 |
+
else{
|
543 |
+
// Add the image url to the imageData-array
|
544 |
+
$imageData['value'] = array('image' => $targetRelativePath);
|
545 |
+
$imageData['url'] = $mediaDir['baseurl'] . '/' . $targetRelativePath;
|
546 |
+
|
547 |
+
// Get preview size dimensions
|
548 |
+
global $_wp_additional_image_sizes;
|
549 |
+
$previewWidth = 0;
|
550 |
+
$previewHeight = 0;
|
551 |
+
$crop = 0;
|
552 |
+
if (isset($_wp_additional_image_sizes[$previewSize])) {
|
553 |
+
$previewWidth = intval($_wp_additional_image_sizes[$previewSize]['width']);
|
554 |
+
$previewHeight = intval($_wp_additional_image_sizes[$previewSize]['height']);
|
555 |
+
$crop = $_wp_additional_image_sizes[$previewSize]['crop'];
|
556 |
+
} else {
|
557 |
+
$previewWidth = get_option($previewSize.'_size_w');
|
558 |
+
$previewHeight = get_option($previewSize.'_size_h');
|
559 |
+
$crop = get_option($previewSize.'_crop');
|
560 |
+
}
|
561 |
+
|
562 |
+
// Generate preview file path
|
563 |
+
$previewFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], 'preview_' . $targetFileName);
|
564 |
+
$previewRelativePath = str_replace($mediaDir['basedir'] . '/', '', $previewFilePath);
|
565 |
+
|
566 |
+
// Get image editor from cropped image
|
567 |
+
$croppedImage = wp_get_image_editor( $targetFilePath );
|
568 |
+
$croppedImage->resize($previewWidth, $previewHeight, $crop);
|
569 |
+
|
570 |
+
// Save the preview
|
571 |
+
$croppedImage->save($previewFilePath);
|
572 |
+
|
573 |
+
// Add the preview url
|
574 |
+
$imageData['preview_url'] = $mediaDir['baseurl'] . '/' . $previewRelativePath;
|
575 |
+
$imageData['value']['preview'] = $previewRelativePath;
|
576 |
+
}
|
577 |
+
return $imageData;
|
578 |
+
}
|
579 |
+
|
580 |
+
function get_image_src($id, $size = 'thumbnail'){
|
581 |
+
$atts = wp_get_attachment_image_src( $id, $size);
|
582 |
+
return $atts[0];
|
583 |
+
}
|
584 |
+
|
585 |
+
function getAbsoluteImageUrl($relativeUrl){
|
586 |
+
$mediaDir = wp_upload_dir();
|
587 |
+
return $mediaDir['baseurl'] . '/' . $relativeUrl;
|
588 |
+
}
|
589 |
+
|
590 |
+
|
591 |
+
|
592 |
+
|
593 |
+
/*
|
594 |
+
* input_admin_head()
|
595 |
+
*
|
596 |
+
* This action is called in the admin_head action on the edit screen where your field is created.
|
597 |
+
* Use this action to add CSS and JavaScript to assist your render_field() action.
|
598 |
+
*
|
599 |
+
* @type action (admin_head)
|
600 |
+
* @since 3.6
|
601 |
+
* @date 23/01/13
|
602 |
+
*
|
603 |
+
* @param n/a
|
604 |
+
* @return n/a
|
605 |
+
*/
|
606 |
+
|
607 |
+
/*
|
608 |
+
|
609 |
+
function input_admin_head() {
|
610 |
+
|
611 |
+
|
612 |
+
|
613 |
+
}
|
614 |
+
|
615 |
+
*/
|
616 |
+
|
617 |
+
|
618 |
+
|
619 |
+
|
620 |
+
/*
|
621 |
+
* input_form_data()
|
622 |
+
*
|
623 |
+
* This function is called once on the 'input' page between the head and footer
|
624 |
+
* There are 2 situations where ACF did not load during the 'acf/input_admin_enqueue_scripts' and
|
625 |
+
* 'acf/input_admin_head' actions because ACF did not know it was going to be used. These situations are
|
626 |
+
* seen on comments / user edit forms on the front end. This function will always be called, and includes
|
627 |
+
* $args that related to the current screen such as $args['post_id']
|
628 |
+
*
|
629 |
+
* @type function
|
630 |
+
* @date 6/03/2014
|
631 |
+
* @since 5.0.0
|
632 |
+
*
|
633 |
+
* @param $args (array)
|
634 |
+
* @return n/a
|
635 |
+
*/
|
636 |
+
|
637 |
+
/*
|
638 |
+
|
639 |
+
function input_form_data( $args ) {
|
640 |
+
|
641 |
+
|
642 |
+
|
643 |
+
}
|
644 |
+
|
645 |
+
*/
|
646 |
+
|
647 |
+
|
648 |
+
/*
|
649 |
+
* input_admin_footer()
|
650 |
+
*
|
651 |
+
* This action is called in the admin_footer action on the edit screen where your field is created.
|
652 |
+
* Use this action to add CSS and JavaScript to assist your render_field() action.
|
653 |
+
*
|
654 |
+
* @type action (admin_footer)
|
655 |
+
* @since 3.6
|
656 |
+
* @date 23/01/13
|
657 |
+
*
|
658 |
+
* @param n/a
|
659 |
+
* @return n/a
|
660 |
+
*/
|
661 |
+
|
662 |
+
/*
|
663 |
+
|
664 |
+
function input_admin_footer() {
|
665 |
+
|
666 |
+
|
667 |
+
|
668 |
+
}
|
669 |
+
|
670 |
+
*/
|
671 |
+
|
672 |
+
|
673 |
+
/*
|
674 |
+
* field_group_admin_enqueue_scripts()
|
675 |
+
*
|
676 |
+
* This action is called in the admin_enqueue_scripts action on the edit screen where your field is edited.
|
677 |
+
* Use this action to add CSS + JavaScript to assist your render_field_options() action.
|
678 |
+
*
|
679 |
+
* @type action (admin_enqueue_scripts)
|
680 |
+
* @since 3.6
|
681 |
+
* @date 23/01/13
|
682 |
+
*
|
683 |
+
* @param n/a
|
684 |
+
* @return n/a
|
685 |
+
*/
|
686 |
+
|
687 |
+
|
688 |
+
|
689 |
+
function field_group_admin_enqueue_scripts() {
|
690 |
+
|
691 |
+
$dir = plugin_dir_url( __FILE__ );
|
692 |
+
|
693 |
+
wp_register_script('acf-input-image-crop-options', "{$dir}js/options.js", array('jquery'), $this->settings['version']);
|
694 |
+
wp_enqueue_script( 'acf-input-image-crop-options');
|
695 |
+
|
696 |
+
wp_register_style('acf-input-image-crop-options', "{$dir}css/options.css");
|
697 |
+
wp_enqueue_style( 'acf-input-image-crop-options');
|
698 |
+
}
|
699 |
+
|
700 |
+
|
701 |
+
|
702 |
+
|
703 |
+
/*
|
704 |
+
* field_group_admin_head()
|
705 |
+
*
|
706 |
+
* This action is called in the admin_head action on the edit screen where your field is edited.
|
707 |
+
* Use this action to add CSS and JavaScript to assist your render_field_options() action.
|
708 |
+
*
|
709 |
+
* @type action (admin_head)
|
710 |
+
* @since 3.6
|
711 |
+
* @date 23/01/13
|
712 |
+
*
|
713 |
+
* @param n/a
|
714 |
+
* @return n/a
|
715 |
+
*/
|
716 |
+
|
717 |
+
/*
|
718 |
+
|
719 |
+
function field_group_admin_head() {
|
720 |
+
|
721 |
+
}
|
722 |
+
|
723 |
+
*/
|
724 |
+
|
725 |
+
|
726 |
+
/*
|
727 |
+
* load_value()
|
728 |
+
*
|
729 |
+
* This filter is applied to the $value after it is loaded from the db
|
730 |
+
*
|
731 |
+
* @type filter
|
732 |
+
* @since 3.6
|
733 |
+
* @date 23/01/13
|
734 |
+
*
|
735 |
+
* @param $value (mixed) the value found in the database
|
736 |
+
* @param $post_id (mixed) the $post_id from which the value was loaded
|
737 |
+
* @param $field (array) the field array holding all the field options
|
738 |
+
* @return $value
|
739 |
+
*/
|
740 |
+
|
741 |
+
/*
|
742 |
+
|
743 |
+
function load_value( $value, $post_id, $field ) {
|
744 |
+
|
745 |
+
return $value;
|
746 |
+
|
747 |
+
}
|
748 |
+
|
749 |
+
*/
|
750 |
+
|
751 |
+
|
752 |
+
/*
|
753 |
+
* update_value()
|
754 |
+
*
|
755 |
+
* This filter is applied to the $value before it is saved in the db
|
756 |
+
*
|
757 |
+
* @type filter
|
758 |
+
* @since 3.6
|
759 |
+
* @date 23/01/13
|
760 |
+
*
|
761 |
+
* @param $value (mixed) the value found in the database
|
762 |
+
* @param $post_id (mixed) the $post_id from which the value was loaded
|
763 |
+
* @param $field (array) the field array holding all the field options
|
764 |
+
* @return $value
|
765 |
+
*/
|
766 |
+
|
767 |
+
/*
|
768 |
+
|
769 |
+
function update_value( $value, $post_id, $field ) {
|
770 |
+
|
771 |
+
return $value;
|
772 |
+
|
773 |
+
}
|
774 |
+
|
775 |
+
*/
|
776 |
+
|
777 |
+
|
778 |
+
/*
|
779 |
+
* format_value()
|
780 |
+
*
|
781 |
+
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
782 |
+
*
|
783 |
+
* @type filter
|
784 |
+
* @since 3.6
|
785 |
+
* @date 23/01/13
|
786 |
+
*
|
787 |
+
* @param $value (mixed) the value which was loaded from the database
|
788 |
+
* @param $post_id (mixed) the $post_id from which the value was loaded
|
789 |
+
* @param $field (array) the field array holding all the field options
|
790 |
+
*
|
791 |
+
* @return $value (mixed) the modified value
|
792 |
+
*/
|
793 |
+
|
794 |
+
|
795 |
+
|
796 |
+
function format_value( $value, $post_id, $field ) {
|
797 |
+
|
798 |
+
// validate
|
799 |
+
if( !$value )
|
800 |
+
{
|
801 |
+
return false;
|
802 |
+
}
|
803 |
+
$data = json_decode($value);
|
804 |
+
if(!is_object($data)){
|
805 |
+
return $value;
|
806 |
+
}
|
807 |
+
|
808 |
+
$value = $data->cropped_image;
|
809 |
+
|
810 |
+
// format
|
811 |
+
if( $field['save_format'] == 'url' )
|
812 |
+
{
|
813 |
+
if(is_numeric($data->cropped_image)){
|
814 |
+
$value = wp_get_attachment_url( $data->cropped_image );
|
815 |
+
}
|
816 |
+
elseif(is_array($data->cropped_image)){
|
817 |
+
|
818 |
+
$value = $this->getAbsoluteImageUrl($data->cropped_image['image']);
|
819 |
+
}
|
820 |
+
elseif(is_object($data->cropped_image)){
|
821 |
+
$value = $this->getAbsoluteImageUrl($data->cropped_image->image);
|
822 |
+
}
|
823 |
+
|
824 |
+
}
|
825 |
+
elseif( $field['save_format'] == 'object' )
|
826 |
+
{
|
827 |
+
if(is_numeric($data->cropped_image )){
|
828 |
+
$attachment = get_post( $data->cropped_image );
|
829 |
+
// validate
|
830 |
+
if( !$attachment )
|
831 |
+
{
|
832 |
+
return false;
|
833 |
+
}
|
834 |
+
|
835 |
+
|
836 |
+
// create array to hold value data
|
837 |
+
$src = wp_get_attachment_image_src( $attachment->ID, 'full' );
|
838 |
+
|
839 |
+
$value = array(
|
840 |
+
'id' => $attachment->ID,
|
841 |
+
'alt' => get_post_meta($attachment->ID, '_wp_attachment_image_alt', true),
|
842 |
+
'title' => $attachment->post_title,
|
843 |
+
'caption' => $attachment->post_excerpt,
|
844 |
+
'description' => $attachment->post_content,
|
845 |
+
'mime_type' => $attachment->post_mime_type,
|
846 |
+
'url' => $src[0],
|
847 |
+
'width' => $src[1],
|
848 |
+
'height' => $src[2],
|
849 |
+
'sizes' => array(),
|
850 |
+
);
|
851 |
+
|
852 |
+
|
853 |
+
// find all image sizes
|
854 |
+
$image_sizes = get_intermediate_image_sizes();
|
855 |
+
|
856 |
+
if( $image_sizes )
|
857 |
+
{
|
858 |
+
foreach( $image_sizes as $image_size )
|
859 |
+
{
|
860 |
+
// find src
|
861 |
+
$src = wp_get_attachment_image_src( $attachment->ID, $image_size );
|
862 |
+
|
863 |
+
// add src
|
864 |
+
$value[ 'sizes' ][ $image_size ] = $src[0];
|
865 |
+
$value[ 'sizes' ][ $image_size . '-width' ] = $src[1];
|
866 |
+
$value[ 'sizes' ][ $image_size . '-height' ] = $src[2];
|
867 |
+
}
|
868 |
+
// foreach( $image_sizes as $image_size )
|
869 |
+
}
|
870 |
+
}
|
871 |
+
elseif(is_array( $data->cropped_image)){
|
872 |
+
$value = array(
|
873 |
+
'url' => $this->getAbsoluteImageUrl($data->cropped_image['image']),
|
874 |
+
);
|
875 |
+
}
|
876 |
+
else{
|
877 |
+
|
878 |
+
//echo 'ELSE';
|
879 |
+
}
|
880 |
+
|
881 |
+
}
|
882 |
+
return $value;
|
883 |
+
|
884 |
+
}
|
885 |
+
|
886 |
+
|
887 |
+
|
888 |
+
|
889 |
+
/*
|
890 |
+
* validate_value()
|
891 |
+
*
|
892 |
+
* This filter is used to perform validation on the value prior to saving.
|
893 |
+
* All values are validated regardless of the field's required setting. This allows you to validate and return
|
894 |
+
* messages to the user if the value is not correct
|
895 |
+
*
|
896 |
+
* @type filter
|
897 |
+
* @date 11/02/2014
|
898 |
+
* @since 5.0.0
|
899 |
+
*
|
900 |
+
* @param $valid (boolean) validation status based on the value and the field's required setting
|
901 |
+
* @param $value (mixed) the $_POST value
|
902 |
+
* @param $field (array) the field array holding all the field options
|
903 |
+
* @param $input (string) the corresponding input name for $_POST value
|
904 |
+
* @return $valid
|
905 |
+
*/
|
906 |
+
|
907 |
+
/*
|
908 |
+
|
909 |
+
function validate_value( $valid, $value, $field, $input ){
|
910 |
+
|
911 |
+
// Basic usage
|
912 |
+
if( $value < $field['custom_minimum_setting'] )
|
913 |
+
{
|
914 |
+
$valid = false;
|
915 |
+
}
|
916 |
+
|
917 |
+
|
918 |
+
// Advanced usage
|
919 |
+
if( $value < $field['custom_minimum_setting'] )
|
920 |
+
{
|
921 |
+
$valid = __('The value is too little!','acf-image_crop'),
|
922 |
+
}
|
923 |
+
|
924 |
+
|
925 |
+
// return
|
926 |
+
return $valid;
|
927 |
+
|
928 |
+
}
|
929 |
+
|
930 |
+
*/
|
931 |
+
|
932 |
+
|
933 |
+
/*
|
934 |
+
* delete_value()
|
935 |
+
*
|
936 |
+
* This action is fired after a value has been deleted from the db.
|
937 |
+
* Please note that saving a blank value is treated as an update, not a delete
|
938 |
+
*
|
939 |
+
* @type action
|
940 |
+
* @date 6/03/2014
|
941 |
+
* @since 5.0.0
|
942 |
+
*
|
943 |
+
* @param $post_id (mixed) the $post_id from which the value was deleted
|
944 |
+
* @param $key (string) the $meta_key which the value was deleted
|
945 |
+
* @return n/a
|
946 |
+
*/
|
947 |
+
|
948 |
+
/*
|
949 |
+
|
950 |
+
function delete_value( $post_id, $key ) {
|
951 |
+
|
952 |
+
|
953 |
+
|
954 |
+
}
|
955 |
+
|
956 |
+
*/
|
957 |
+
|
958 |
+
|
959 |
+
/*
|
960 |
+
* load_field()
|
961 |
+
*
|
962 |
+
* This filter is applied to the $field after it is loaded from the database
|
963 |
+
*
|
964 |
+
* @type filter
|
965 |
+
* @date 23/01/2013
|
966 |
+
* @since 3.6.0
|
967 |
+
*
|
968 |
+
* @param $field (array) the field array holding all the field options
|
969 |
+
* @return $field
|
970 |
+
*/
|
971 |
+
|
972 |
+
/*
|
973 |
+
|
974 |
+
function load_field( $field ) {
|
975 |
+
|
976 |
+
return $field;
|
977 |
+
|
978 |
+
}
|
979 |
+
|
980 |
+
*/
|
981 |
+
|
982 |
+
|
983 |
+
/*
|
984 |
+
* update_field()
|
985 |
+
*
|
986 |
+
* This filter is applied to the $field before it is saved to the database
|
987 |
+
*
|
988 |
+
* @type filter
|
989 |
+
* @date 23/01/2013
|
990 |
+
* @since 3.6.0
|
991 |
+
*
|
992 |
+
* @param $field (array) the field array holding all the field options
|
993 |
+
* @return $field
|
994 |
+
*/
|
995 |
+
|
996 |
+
/*
|
997 |
+
|
998 |
+
function update_field( $field ) {
|
999 |
+
|
1000 |
+
return $field;
|
1001 |
+
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
*/
|
1005 |
+
|
1006 |
+
|
1007 |
+
/*
|
1008 |
+
* delete_field()
|
1009 |
+
*
|
1010 |
+
* This action is fired after a field is deleted from the database
|
1011 |
+
*
|
1012 |
+
* @type action
|
1013 |
+
* @date 11/02/2014
|
1014 |
+
* @since 5.0.0
|
1015 |
+
*
|
1016 |
+
* @param $field (array) the field array holding all the field options
|
1017 |
+
* @return n/a
|
1018 |
+
*/
|
1019 |
+
|
1020 |
+
/*
|
1021 |
+
|
1022 |
+
function delete_field( $field ) {
|
1023 |
+
|
1024 |
+
|
1025 |
+
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
*/
|
1029 |
+
|
1030 |
+
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
|
1034 |
+
// create field
|
1035 |
+
new acf_field_image_crop();
|
1036 |
+
|
1037 |
+
?>
|
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: 1.
|
7 |
Author: Anders Thorborg
|
8 |
Author URI: http://thorb.org
|
9 |
License: GPLv2 or later
|
@@ -11,66 +11,32 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
|
11 |
*/
|
12 |
|
13 |
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
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 |
-
|
75 |
|
76 |
?>
|
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.1
|
7 |
Author: Anders Thorborg
|
8 |
Author URI: http://thorb.org
|
9 |
License: GPLv2 or later
|
11 |
*/
|
12 |
|
13 |
|
14 |
+
// 1. set text domain
|
15 |
+
// Reference: https://codex.wordpress.org/Function_Reference/load_plugin_textdomain
|
16 |
+
load_plugin_textdomain( 'acf-image_crop', false, dirname( plugin_basename(__FILE__) ) . '/lang/' );
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
// 2. Include field type for ACF5
|
22 |
+
// $version = 5 and can be ignored until ACF6 exists
|
23 |
+
function include_field_types_image_crop( $version ) {
|
24 |
+
include_once('acf-image-crop-v5.php');
|
25 |
+
|
26 |
+
}
|
27 |
+
|
28 |
+
add_action('acf/include_field_types', 'include_field_types_image_crop');
|
29 |
+
|
30 |
+
|
31 |
+
|
32 |
+
|
33 |
+
// 3. Include field type for ACF4
|
34 |
+
function register_fields_image_crop() {
|
35 |
+
|
36 |
+
include_once('acf-image-crop-v4.php');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
|
38 |
}
|
39 |
|
40 |
+
add_action('acf/register_fields', 'register_fields_image_crop');
|
41 |
|
42 |
?>
|
js/input-v4.js
ADDED
@@ -0,0 +1,226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
// 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});
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
function updateCropData($field, img, selection){
|
133 |
+
var $options = $field.find('.acf-image-uploader');
|
134 |
+
$options.data('x1', selection.x1);
|
135 |
+
$options.data('x2', selection.x2);
|
136 |
+
$options.data('y1', selection.y1);
|
137 |
+
$options.data('y2', selection.y2);
|
138 |
+
}
|
139 |
+
|
140 |
+
function updateThumbnail($field, img, selection){
|
141 |
+
var $options = $field.find('.acf-image-uploader');
|
142 |
+
var div = $field.find('.crop-preview .preview');
|
143 |
+
var targetWidth = $field.find('.crop-preview .preview').width();
|
144 |
+
var factor = targetWidth / (selection.x2 - selection.x1);
|
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));
|
153 |
+
//y offset
|
154 |
+
div.css('background-position-y', 0-(selection.y1 * factor));
|
155 |
+
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');
|
156 |
+
}
|
157 |
+
|
158 |
+
function generateCropJSON(originalImage, croppedImage){
|
159 |
+
var obj = {
|
160 |
+
original_image: originalImage,
|
161 |
+
cropped_image: croppedImage
|
162 |
+
}
|
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');
|
176 |
+
}
|
177 |
+
var data = {
|
178 |
+
action: 'acf_image_crop_perform_crop',
|
179 |
+
id: $field.find('.acf-image-value').data('original-image'),
|
180 |
+
x1: $options.data('x1'),
|
181 |
+
x2: $options.data('x2'),
|
182 |
+
y1: $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 |
+
|
205 |
+
function toggleCropView($field){
|
206 |
+
if($field.hasClass('cropping')){
|
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 |
+
|
221 |
+
function getFullImageUrl(id, callback){
|
222 |
+
$.post(ajaxurl, {images: []}, function(data, textStatus, xhr) {
|
223 |
+
}, 'json');
|
224 |
+
}
|
225 |
+
|
226 |
+
})(jQuery);
|
js/input.js
CHANGED
@@ -1,83 +1,68 @@
|
|
1 |
(function($){
|
2 |
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
$
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
$
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
$field.
|
35 |
-
$field.find('
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
if($options.data('
|
40 |
-
|
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 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
});
|
78 |
});
|
79 |
|
80 |
-
}
|
81 |
|
82 |
function initCrop($field){
|
83 |
var $options = $field.find('.acf-image-uploader');
|
@@ -92,14 +77,14 @@
|
|
92 |
x1: 0,
|
93 |
y1: 0
|
94 |
};
|
95 |
-
if($options.data('
|
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('
|
103 |
if($options.data('width')){
|
104 |
options.minWidth = $options.data('width');
|
105 |
options.x2 = $options.data('width');
|
@@ -169,8 +154,8 @@
|
|
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('
|
173 |
-
if($options.data('
|
174 |
targetWidth = $options.data('x2') - $options.data('x1');
|
175 |
targetHeight = $options.data('y2') - $options.data('y1');
|
176 |
}
|
@@ -187,7 +172,7 @@
|
|
187 |
save_to_media_library: saveToMediaLibrary
|
188 |
}
|
189 |
$.post(ajaxurl, data, function(data, textStatus, xhr) {
|
190 |
-
$field.find('
|
191 |
$field.find('.acf-image-value').data('cropped-image', data.value);
|
192 |
$field.find('.acf-image-value').data('cropped', true);
|
193 |
updateFieldValue($field);
|
@@ -223,4 +208,65 @@
|
|
223 |
}, 'json');
|
224 |
}
|
225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
})(jQuery);
|
1 |
(function($){
|
2 |
|
3 |
|
4 |
+
function initialize_field( $el ) {
|
5 |
+
var $field = $el, $options = $el.find('.acf-image-uploader');
|
6 |
+
$field.find('.acf-image-value').on('change', function(){
|
7 |
+
var originalImage = $(this).val();
|
8 |
+
if($(this).val()){
|
9 |
+
$field.removeClass('invalid');
|
10 |
+
$field.find('.init-crop-button').removeAttr('disabled');
|
11 |
+
$field.find('.acf-image-value').data('original-image', originalImage);
|
12 |
+
$field.find('.acf-image-value').data('cropped-image', originalImage);
|
13 |
+
$field.find('.acf-image-value').data('cropped', false);
|
14 |
+
$.post(ajaxurl, {action: 'acf_image_crop_get_image_size', image_id: originalImage}, function(data, textStatus, xhr) {
|
15 |
+
console.log('response', data);
|
16 |
+
if($field.find('img.crop-image').length == 0){
|
17 |
+
$field.find('.crop-action').append($('<img class="crop-image" src="#"/>'));
|
18 |
+
}
|
19 |
+
$field.find('img.crop-image').attr('src', data['url']);
|
20 |
+
console.log(data['width']);
|
21 |
+
$field.find('img.crop-image').data('width', data['width']);
|
22 |
+
$field.find('img.crop-image').data('height', data['height']);
|
23 |
+
var warnings = [];
|
24 |
+
var valid = true;
|
25 |
+
if($options.data('width') && data['width'] < $options.data('width')){
|
26 |
+
warnings.push('Width should be at least: ' + $options.data('width') + 'px (Selected image width: ' + data['width'] + 'px)');
|
27 |
+
valid = false;
|
28 |
+
}
|
29 |
+
if($options.data('height') && data['height'] < $options.data('height')){
|
30 |
+
warnings.push('Height should be at least: ' + $options.data('height') + 'px (Selected image height: ' + data['height'] + 'px)');
|
31 |
+
valid = false;
|
32 |
+
}
|
33 |
+
if(!valid){
|
34 |
+
$field.addClass('invalid');
|
35 |
+
$field.find('.init-crop-button').attr('disabled', 'disabled');
|
36 |
+
alert('Warning: The selected image is smaller than the required size:\n' + warnings.join('\n'));
|
37 |
+
}
|
38 |
+
else{
|
39 |
+
if($options.data('force-crop')){
|
40 |
+
initCrop($field);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
}
|
42 |
+
}
|
43 |
|
44 |
+
}, 'json');
|
45 |
+
updateFieldValue($field);
|
46 |
+
}
|
47 |
+
else{
|
48 |
+
//Do nothing
|
49 |
+
}
|
50 |
+
|
51 |
+
});
|
52 |
+
$field.find('.init-crop-button').click(function(e){
|
53 |
+
e.preventDefault();
|
54 |
+
initCrop($field);
|
55 |
+
});
|
56 |
+
$field.find('.perform-crop-button').click(function(e){
|
57 |
+
e.preventDefault();
|
58 |
+
performCrop($field);
|
59 |
+
});
|
60 |
+
$field.find('.cancel-crop-button').click(function(e){
|
61 |
+
e.preventDefault();
|
62 |
+
cancelCrop($field);
|
|
|
63 |
});
|
64 |
|
65 |
+
}
|
66 |
|
67 |
function initCrop($field){
|
68 |
var $options = $field.find('.acf-image-uploader');
|
77 |
x1: 0,
|
78 |
y1: 0
|
79 |
};
|
80 |
+
if($options.data('crop_type') == 'hard'){
|
81 |
options.aspectRatio = $options.data('width') + ':' + $options.data('height');
|
82 |
options.minWidth = $options.data('width');
|
83 |
options.minHeight = $options.data('height');
|
84 |
options.x2 = $options.data('width');
|
85 |
options.y2 = $options.data('height');
|
86 |
}
|
87 |
+
else if($options.data('crop_type') == 'min'){
|
88 |
if($options.data('width')){
|
89 |
options.minWidth = $options.data('width');
|
90 |
options.x2 = $options.data('width');
|
154 |
var $options = $field.find('.acf-image-uploader');
|
155 |
var targetWidth = $options.data('width');
|
156 |
var targetHeight = $options.data('height');
|
157 |
+
var saveToMediaLibrary = $options.data('save_to_media_library');
|
158 |
+
if($options.data('crop_type') == 'min'){
|
159 |
targetWidth = $options.data('x2') - $options.data('x1');
|
160 |
targetHeight = $options.data('y2') - $options.data('y1');
|
161 |
}
|
172 |
save_to_media_library: saveToMediaLibrary
|
173 |
}
|
174 |
$.post(ajaxurl, data, function(data, textStatus, xhr) {
|
175 |
+
$field.find('[data-name=value-url]').attr('src', data.preview_url);
|
176 |
$field.find('.acf-image-value').data('cropped-image', data.value);
|
177 |
$field.find('.acf-image-value').data('cropped', true);
|
178 |
updateFieldValue($field);
|
208 |
}, 'json');
|
209 |
}
|
210 |
|
211 |
+
|
212 |
+
if( typeof acf.add_action !== 'undefined' ) {
|
213 |
+
|
214 |
+
/*
|
215 |
+
* ready append (ACF5)
|
216 |
+
*
|
217 |
+
* These are 2 events which are fired during the page load
|
218 |
+
* ready = on page load similar to $(document).ready()
|
219 |
+
* append = on new DOM elements appended via repeater field
|
220 |
+
*
|
221 |
+
* @type event
|
222 |
+
* @date 20/07/13
|
223 |
+
*
|
224 |
+
* @param $el (jQuery selection) the jQuery element which contains the ACF fields
|
225 |
+
* @return n/a
|
226 |
+
*/
|
227 |
+
|
228 |
+
acf.add_action('ready append', function( $el ){
|
229 |
+
|
230 |
+
// search $el for fields of type 'image_crop'
|
231 |
+
acf.get_fields({ type : 'image_crop'}, $el).each(function(){
|
232 |
+
|
233 |
+
initialize_field( $(this) );
|
234 |
+
|
235 |
+
});
|
236 |
+
|
237 |
+
});
|
238 |
+
|
239 |
+
|
240 |
+
} else {
|
241 |
+
|
242 |
+
|
243 |
+
/*
|
244 |
+
* acf/setup_fields (ACF4)
|
245 |
+
*
|
246 |
+
* This event is triggered when ACF adds any new elements to the DOM.
|
247 |
+
*
|
248 |
+
* @type function
|
249 |
+
* @since 1.0.0
|
250 |
+
* @date 01/01/12
|
251 |
+
*
|
252 |
+
* @param event e: an event object. This can be ignored
|
253 |
+
* @param Element postbox: An element which contains the new HTML
|
254 |
+
*
|
255 |
+
* @return n/a
|
256 |
+
*/
|
257 |
+
|
258 |
+
$(document).live('acf/setup_fields', function(e, postbox){
|
259 |
+
|
260 |
+
$(postbox).find('.field[data-field_type="image_crop"]').each(function(){
|
261 |
+
|
262 |
+
initialize_field( $(this) );
|
263 |
+
|
264 |
+
});
|
265 |
+
|
266 |
+
});
|
267 |
+
|
268 |
+
|
269 |
+
}
|
270 |
+
|
271 |
+
|
272 |
})(jQuery);
|
js/options-v4.js
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
$(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 |
+
});
|
js/options.js
CHANGED
@@ -1,31 +1,68 @@
|
|
1 |
jQuery(function($){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
$(document).on('change', '.field_type-image_crop .target-size-select', function(e) {
|
3 |
-
|
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 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
});
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
$returnValueField
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
}
|
23 |
else{
|
24 |
-
$
|
25 |
}
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
30 |
});
|
|
|
31 |
});
|
1 |
jQuery(function($){
|
2 |
+
acf.add_action('append', function(){
|
3 |
+
$('.field_type-image_crop .target-size-select').each(function() {
|
4 |
+
toggleCustomDimensions(this);
|
5 |
+
});
|
6 |
+
$('.field_type-image_crop .save-in-media-library-select input').each(function() {
|
7 |
+
console.log(this);
|
8 |
+
toggleSaveFormats(this);
|
9 |
+
});
|
10 |
+
});
|
11 |
+
|
12 |
$(document).on('change', '.field_type-image_crop .target-size-select', function(e) {
|
13 |
+
toggleCustomDimensions(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
});
|
15 |
+
|
16 |
+
// $(document).on('change', '.field_type-image_crop .crop-type-select', function(e) {
|
17 |
+
// $(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description').addClass('hidden');
|
18 |
+
// $(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description[data-type=' + $(this).val() + ']').removeClass('hidden');
|
19 |
+
// });
|
20 |
+
|
21 |
+
$(document).on('click', '.field_type-image_crop .save-in-media-library-select input', function(e) {
|
22 |
+
toggleSaveFormats(this);
|
23 |
+
// var saveToMedia = $(this).val() == 'yes';
|
24 |
+
// var $returnValueField = $(this).parents('.field_type-image_crop').find('.return-value-select');
|
25 |
+
// if(! saveToMedia){
|
26 |
+
// $returnValueField.find('input[value=id], input[value=object]').attr('disabled', true).parents('label').addClass('disabled');
|
27 |
+
// $returnValueField.find('input[value=url]').attr('checked', true);
|
28 |
+
// }
|
29 |
+
// else{
|
30 |
+
// $returnValueField.find('input').removeAttr('disabled').parents('label').removeClass('disabled');
|
31 |
+
// }
|
32 |
+
|
33 |
+
// $(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description').addClass('hidden');
|
34 |
+
// $(this).parents('.field_type-image_crop').find('.dimensions-wrap .dimensions-description[data-type=' + $(this).val() + ']').removeClass('hidden');
|
35 |
+
|
36 |
});
|
37 |
+
|
38 |
+
function toggleSaveFormats(saveToMediaSelect){
|
39 |
+
if($(saveToMediaSelect).is(':checked')){
|
40 |
+
var saveToMedia = $(saveToMediaSelect).val() == 'yes';
|
41 |
+
var $returnValueField = $(saveToMediaSelect).parents('.field_type-image_crop').find('.return-value-select');
|
42 |
+
if(! saveToMedia){
|
43 |
+
$returnValueField.find('input[value=id], input[value=object]').attr('disabled', true).parents('label').addClass('disabled');
|
44 |
+
$returnValueField.find('input[value=url]').attr('checked', true);
|
45 |
+
}
|
46 |
+
else{
|
47 |
+
$returnValueField.find('input').removeAttr('disabled').parents('label').removeClass('disabled');
|
48 |
+
}
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
function toggleCustomDimensions(targetSizeSelect){
|
53 |
+
if($(targetSizeSelect).val() == 'custom'){
|
54 |
+
$(targetSizeSelect).parents('.field_type-image_crop').find('.custom-target-dimension').parents('tr.acf-field').removeClass('hidden');
|
55 |
}
|
56 |
else{
|
57 |
+
$(targetSizeSelect).parents('.field_type-image_crop').find('.custom-target-dimension').parents('tr.acf-field').addClass('hidden');
|
58 |
}
|
59 |
+
}
|
60 |
+
|
61 |
+
$('.field_type-image_crop .target-size-select').each(function() {
|
62 |
+
toggleCustomDimensions(this);
|
63 |
+
});
|
64 |
+
$('.field_type-image_crop .save-in-media-library-select input').each(function() {
|
65 |
+
toggleSaveFormats(this);
|
66 |
});
|
67 |
+
|
68 |
});
|
lang/README.md
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Translations directory
|
2 |
+
|
3 |
+
Use this directory to store .po and .mo files.
|
4 |
+
|
5 |
+
This directory can be removed if not used.
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ 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.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -61,6 +61,10 @@ function my_register_fields()
|
|
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)
|
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.1
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
61 |
|
62 |
== Changelog ==
|
63 |
|
64 |
+
= 1.1 =
|
65 |
+
* Added ACF5 compatibility.
|
66 |
+
* Please report any compatibility issues. As this has been an urgent feature request I have not had as much time for testing as I would have liked.
|
67 |
+
|
68 |
= 1.0 =
|
69 |
* Added option to save the image to media library or refer directly to the created image, not using the media library.
|
70 |
* 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)
|