acf_field_image_crop

The Advanced Custom Fields: Image Crop Add-on acf field image crop class.

Defined (3)

The class is defined in the following location(s).

/image_crop-v3.php  
  1. class acf_field_image_crop extends acf_Field 
  2.  
  3. // vars 
  4. var $settings, // will hold info such as dir / path 
  5. $defaults; // will hold default field options 
  6.  
  7.  
  8. /**-------------------------------------------------------------------------------------- 
  9. * Constructor 
  10. * - This function is called when the field class is initalized on each page. 
  11. * - Here you can add filters / actions and setup any other functionality for your field 
  12. * @author Elliot Condon 
  13. * @since 2.2.0 
  14. *-------------------------------------------------------------------------------------*/ 
  15.  
  16. function __construct($parent) 
  17.  
  18. // do not delete! 
  19. parent::__construct($parent); 
  20.  
  21. // set name / title 
  22. $this->name = 'image_crop'; 
  23. $this->title = __('Image - Custom crop'); 
  24. $this->defaults = array( 
  25. // add default here to merge into your field. 
  26. // This makes life easy when creating the field options as you don't need to use any if( isset('') ) logic. eg: 
  27. //'preview_size' => 'thumbnail' 
  28. ); 
  29.  
  30. // settings 
  31. $this->settings = array( 
  32. 'path' => $this->helpers_get_path(__FILE__),  
  33. 'dir' => $this->helpers_get_dir(__FILE__),  
  34. 'version' => '1.0.0' 
  35. ); 
  36.  
  37.  
  38.  
  39. /** 
  40. * helpers_get_path 
  41. * @description: calculates the path (works for plugin / theme folders) 
  42. * @since: 3.6 
  43. * @created: 30/01/13 
  44. */ 
  45.  
  46. function helpers_get_path($file) 
  47. return trailingslashit(dirname($file)); 
  48.  
  49.  
  50. /** 
  51. * helpers_get_dir 
  52. * @description: calculates the directory (works for plugin / theme folders) 
  53. * @since: 3.6 
  54. * @created: 30/01/13 
  55. */ 
  56.  
  57. function helpers_get_dir($file) 
  58. $dir = trailingslashit(dirname($file)); 
  59. $count = 0; 
  60.  
  61.  
  62. // sanitize for Win32 installs 
  63. $dir = str_replace('\\', '/', $dir); 
  64.  
  65.  
  66. // if file is in plugins folder 
  67. $wp_plugin_dir = str_replace('\\', '/', WP_PLUGIN_DIR); 
  68. $dir = str_replace($wp_plugin_dir, WP_PLUGIN_URL, $dir, $count); 
  69.  
  70.  
  71. if($count < 1) 
  72. // if file is in wp-content folder 
  73. $wp_content_dir = str_replace('\\', '/', WP_CONTENT_DIR); 
  74. $dir = str_replace($wp_content_dir, WP_CONTENT_URL, $dir, $count); 
  75.  
  76.  
  77. if($count < 1) 
  78. // if file is in ??? folder 
  79. $wp_dir = str_replace('\\', '/', ABSPATH); 
  80. $dir = str_replace($wp_dir, site_url('/'), $dir); 
  81.  
  82. return $dir; 
  83.  
  84.  
  85. /**-------------------------------------------------------------------------------------- 
  86. * create_options 
  87. * - this function is called from core/field_meta_box.php to create extra options 
  88. * for your field 
  89. * @params 
  90. * - $key (int) - the $_POST obejct key required to save the options to the field 
  91. * - $field (array) - the field object 
  92. * @author Elliot Condon 
  93. * @since 2.2.0 
  94. *-------------------------------------------------------------------------------------*/ 
  95.  
  96. function create_options($key, $field) 
  97. // defaults? 
  98. /** 
  99. $field = array_merge($this->defaults, $field); 
  100. */ 
  101.  
  102.  
  103. // Create Field Options HTML 
  104. ?> 
  105. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  106. <td class="label"> 
  107. <label><?php _e("Preview Size", 'acf'); ?></label> 
  108. <p class="description"><?php _e("Thumbnail is advised", 'acf'); ?></p> 
  109. </td> 
  110. <td> 
  111. <?php 
  112.  
  113. $this->parent->create_field(array( 
  114. 'type' => 'radio',  
  115. 'name' => 'fields[' . $key . '][preview_size]',  
  116. 'value' => $field['preview_size'],  
  117. 'layout' => 'horizontal',  
  118. 'choices' => array( 
  119. 'thumbnail' => __('Thumbnail'),  
  120. 'something_else' => __('Something Else'),  
  121. )); 
  122.  
  123. ?> 
  124. </td> 
  125. </tr> 
  126. <?php 
  127.  
  128.  
  129. /**-------------------------------------------------------------------------------------- 
  130. * pre_save_field 
  131. * - this function is called when saving your acf object. Here you can manipulate the 
  132. * field object and it's options before it gets saved to the database. 
  133. * @author Elliot Condon 
  134. * @since 2.2.0 
  135. *-------------------------------------------------------------------------------------*/ 
  136.  
  137. function pre_save_field($field) 
  138. // Note: This function can be removed if not used 
  139.  
  140. // do stuff with field (mostly format options data) 
  141.  
  142. return parent::pre_save_field($field); 
  143.  
  144.  
  145. /**-------------------------------------------------------------------------------------- 
  146. * create_field 
  147. * - this function is called on edit screens to produce the html for this field 
  148. * @author Elliot Condon 
  149. * @since 2.2.0 
  150. *-------------------------------------------------------------------------------------*/ 
  151.  
  152. function create_field($field) 
  153. // defaults? 
  154. /** 
  155. $field = array_merge($this->defaults, $field); 
  156. */ 
  157.  
  158. // perhaps use $field['preview_size'] to alter the markup? 
  159.  
  160.  
  161. // create Field HTML 
  162. ?> 
  163. <div> 
  164.  
  165. </div> 
  166. <?php 
  167.  
  168.  
  169. /**-------------------------------------------------------------------------------------- 
  170. * admin_head 
  171. * - this function is called in the admin_head of the edit screen where your field 
  172. * is created. Use this function to create css and javascript to assist your 
  173. * create_field() function. 
  174. * @author Elliot Condon 
  175. * @since 2.2.0 
  176. *-------------------------------------------------------------------------------------*/ 
  177.  
  178. function admin_head() 
  179. // Note: This function can be removed if not used 
  180.  
  181.  
  182. /**-------------------------------------------------------------------------------------- 
  183. * admin_print_scripts / admin_print_styles 
  184. * - this function is called in the admin_print_scripts / admin_print_styles where 
  185. * your field is created. Use this function to register css and javascript to assist 
  186. * your create_field() function. 
  187. * @author Elliot Condon 
  188. * @since 3.0.0 
  189. *-------------------------------------------------------------------------------------*/ 
  190.  
  191. function admin_print_scripts() 
  192. // Note: This function can be removed if not used 
  193.  
  194.  
  195. // register acf scripts 
  196. wp_register_script('acf-input-image_crop', $this->settings['dir'] . 'js/input.js', array('acf-input'), $this->settings['version']); 
  197.  
  198. // scripts 
  199. wp_enqueue_script(array( 
  200. 'acf-input-image_crop',  
  201. )); 
  202.  
  203.  
  204.  
  205. function admin_print_styles() 
  206. // Note: This function can be removed if not used 
  207.  
  208.  
  209. wp_register_style('acf-input-image_crop', $this->settings['dir'] . 'css/input.css', array('acf-input'), $this->settings['version']); 
  210.  
  211. // styles 
  212. wp_enqueue_style(array( 
  213. 'acf-input-image_crop',  
  214. )); 
  215.  
  216.  
  217. /**-------------------------------------------------------------------------------------- 
  218. * update_value 
  219. * - this function is called when saving a post object that your field is assigned to. 
  220. * the function will pass through the 3 parameters for you to use. 
  221. * @params 
  222. * - $post_id (int) - usefull if you need to save extra data or manipulate the current 
  223. * post object 
  224. * - $field (array) - usefull if you need to manipulate the $value based on a field option 
  225. * - $value (mixed) - the new value of your field. 
  226. * @author Elliot Condon 
  227. * @since 2.2.0 
  228. *-------------------------------------------------------------------------------------*/ 
  229.  
  230. function update_value($post_id, $field, $value) 
  231. // Note: This function can be removed if not used 
  232.  
  233. // do stuff with value 
  234.  
  235. // save value 
  236. parent::update_value($post_id, $field, $value); 
  237.  
  238.  
  239. /**-------------------------------------------------------------------------------------- 
  240. * get_value 
  241. * - called from the edit page to get the value of your field. This function is useful 
  242. * if your field needs to collect extra data for your create_field() function. 
  243. * @params 
  244. * - $post_id (int) - the post ID which your value is attached to 
  245. * - $field (array) - the field object. 
  246. * @author Elliot Condon 
  247. * @since 2.2.0 
  248. *-------------------------------------------------------------------------------------*/ 
  249.  
  250. function get_value($post_id, $field) 
  251. // Note: This function can be removed if not used 
  252.  
  253. // get value 
  254. $value = parent::get_value($post_id, $field); 
  255.  
  256. // format value 
  257.  
  258. // return value 
  259. return $value; 
  260.  
  261.  
  262. /**-------------------------------------------------------------------------------------- 
  263. * get_value_for_api 
  264. * - called from your template file when using the API functions (get_field, etc). 
  265. * This function is useful if your field needs to format the returned value 
  266. * @params 
  267. * - $post_id (int) - the post ID which your value is attached to 
  268. * - $field (array) - the field object. 
  269. * @author Elliot Condon 
  270. * @since 3.0.0 
  271. *-------------------------------------------------------------------------------------*/ 
  272.  
  273. function get_value_for_api($post_id, $field) 
  274. // Note: This function can be removed if not used 
  275.  
  276. // get value 
  277. $value = $this->get_value($post_id, $field); 
  278.  
  279. // format value 
  280.  
  281. // return value 
  282. return $value; 
  283.  
  284.  
/acf-image-crop-v4.php  
  1. class acf_field_image_crop extends acf_field_image 
  2. // vars 
  3. var $settings, // will hold info such as dir / path 
  4. $defaults; // will hold default field options 
  5.  
  6.  
  7. /** 
  8. * __construct 
  9. * Set name / label needed for actions / filters 
  10. * @since 3.6 
  11. * @date 23/01/13 
  12. */ 
  13.  
  14. function __construct() 
  15. // vars 
  16. $this->name = 'image_crop'; 
  17. $this->label = __('Image with user-crop'); 
  18. $this->category = __("Content", 'acf'); // Basic, Content, Choice, etc 
  19. $this->defaults = array( 
  20. 'force_crop' => 'no',  
  21. 'crop_type' => 'hard',  
  22. 'preview_size' => 'medium',  
  23. 'save_format' => 'id',  
  24. 'save_in_media_library' => 'yes',  
  25. 'target_size' => 'thumbnail',  
  26. 'retina_mode' => 'no' 
  27. // add default here to merge into your field. 
  28. // This makes life easy when creating the field options as you don't need to use any if( isset('') ) logic. eg: 
  29. //'preview_size' => 'thumbnail' 
  30. ); 
  31.  
  32. $this->options = get_option( 'acf_image_crop_settings' ); 
  33.  
  34. //Call grandparent cunstructor 
  35. acf_field::__construct(); 
  36.  
  37. // settings 
  38. $this->settings = array( 
  39. 'path' => apply_filters('acf/helpers/get_path', __FILE__),  
  40. 'dir' => apply_filters('acf/helpers/get_dir', __FILE__),  
  41. 'version' => '1.0.0' 
  42. ); 
  43.  
  44. // add ajax action to be able to retrieve full image size via javascript 
  45. add_action( 'wp_ajax_acf_image_crop_get_image_size', array( &$this, 'crop_get_image_size' ) ); 
  46. add_action( 'wp_ajax_acf_image_crop_perform_crop', array( &$this, 'perform_crop' ) ); 
  47.  
  48. // add filter to media query function to hide cropped images from media library 
  49. add_filter('ajax_query_attachments_args', array($this, 'filterMediaQuery')); 
  50.  
  51. // Register extra fields on the media settings page on admin_init 
  52. add_action('admin_init', array($this, 'registerSettings')); 
  53.  
  54.  
  55. // AJAX handler for retieving full image dimensions from ID 
  56. public function crop_get_image_size() 
  57. $img = wp_get_attachment_image_src( $_POST['image_id'], 'full'); 
  58. if($img) { 
  59. echo json_encode( array( 
  60. 'url' => $img[0],  
  61. 'width' => $img[1],  
  62. 'height' => $img[2] 
  63. ) ); 
  64. exit; 
  65.  
  66.  
  67. /** 
  68. * create_options() 
  69. * Create extra options for your field. This is rendered when editing a field. 
  70. * The value of $field['name'] can be used (like bellow) to save extra data to the $field 
  71. * @type action 
  72. * @since 3.6 
  73. * @date 23/01/13 
  74. * @param $field - an array holding all the field's data 
  75. */ 
  76.  
  77. function create_options($field) 
  78. // defaults? 
  79. /** 
  80. $field = array_merge($this->defaults, $field); 
  81. */ 
  82.  
  83. // key is needed in the field names to correctly save the data 
  84. $key = $field['name']; 
  85.  
  86.  
  87. // Create Field Options HTML 
  88. ?> 
  89. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  90. <td class="label"> 
  91. <label><?php _e("Crop type", 'acf'); ?></label> 
  92. <p class="description"><?php _e("Select the type of crop the user should perform", 'acf'); ?></p> 
  93. </td> 
  94. <td> 
  95. <?php 
  96.  
  97. do_action('acf/create_field', array( 
  98. 'type' => 'select',  
  99. 'name' => 'fields[' . $key . '][crop_type]',  
  100. 'value' => $field['crop_type'],  
  101. 'class' => 'crop-type-select',  
  102. 'choices' => array( 
  103. 'hard' => __('Hard crop', 'acf'),  
  104. 'min' => __('Minimal dimensions', 'acf') 
  105. )); 
  106.  
  107. ?> 
  108. </td> 
  109. </tr> 
  110. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  111. <td class="label"> 
  112. <label><?php _e("Target Size", 'acf'); ?></label> 
  113. <p class="description"><?php _e("Select the target size for this field", 'acf'); ?></p> 
  114. </td> 
  115. <td> 
  116. <?php 
  117. $sizes = array_merge(apply_filters('acf/get_image_sizes', array()), array('custom' => __("Custom size", 'acf'))); 
  118. unset($sizes['full']); 
  119. do_action('acf/create_field', array( 
  120. 'type' => 'select',  
  121. 'name' => 'fields[' . $key . '][target_size]',  
  122. 'value' => $field['target_size'],  
  123. 'class' => 'target-size-select',  
  124. 'choices' => $sizes 
  125. )); 
  126.  
  127. ?> 
  128. </td> 
  129. </tr> 
  130. <tr class="field_option field_option_<?php echo $this->name; ?> dimensions-wrap <?php echo ($field['target_size'] == 'custom' ? '' : 'hidden') ?>"> 
  131. <td class="label"> 
  132. <label><?php _e("Dimensions", 'acf'); ?></label> 
  133. <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> 
  134. </td> 
  135. <td> 
  136. <?php 
  137.  
  138. do_action('acf/create_field', array( 
  139. 'type' => 'text',  
  140. 'name' => 'fields[' . $key . '][width]',  
  141. 'value' => isset($field['width']) ? $field['width'] : '',  
  142. 'class' => 'width dimension',  
  143. 'placeholder' => 'Width' 
  144. )); 
  145. ?> 
  146. <div class="acf-input-wrap"> : </div> 
  147. <?php 
  148. do_action('acf/create_field', array( 
  149. 'type' => 'text',  
  150. 'name' => 'fields[' . $key . '][height]',  
  151. 'value' => isset($field['height']) ? $field['height'] : '',  
  152. 'class' => 'height dimension',  
  153. 'placeholder' => 'Height' 
  154. )); 
  155. ?> 
  156. </td> 
  157. </tr> 
  158. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  159. <td class="label"> 
  160. <label><?php _e("Preview Size", 'acf'); ?></label> 
  161. <p class="description"><?php _e("Select the target size for this field", 'acf'); ?></p> 
  162. </td> 
  163. <td> 
  164. <?php 
  165. do_action('acf/create_field', array( 
  166. 'type' => 'select',  
  167. 'name' => 'fields[' . $key . '][preview_size]',  
  168. 'value' => $field['preview_size'],  
  169. 'class' => 'preview-size-select',  
  170. 'choices' => apply_filters('acf/get_image_sizes', array()) 
  171. )); 
  172.  
  173. ?> 
  174. </td> 
  175. </tr> 
  176. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  177. <td class="label"> 
  178. <label><?php _e("Force crop", 'acf'); ?></label> 
  179. <p><?php _e("Force the user to crop the image as soon at it is selected.", 'acf') ?></p> 
  180. </td> 
  181. <td> 
  182. <?php 
  183. do_action('acf/create_field', array( 
  184. 'type' => 'radio',  
  185. 'name' => 'fields['.$key.'][force_crop]',  
  186. 'value' => $field['force_crop'],  
  187. 'layout' => 'horizontal',  
  188. 'choices' => array( 
  189. 'yes' => __("Yes", 'acf'),  
  190. 'no' => __("No", 'acf') 
  191. )); 
  192. ?> 
  193. </td> 
  194. </tr> 
  195. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  196. <td class="label"> 
  197. <label><?php _e("Save cropped image in media library", 'acf'); ?></label> 
  198. <p><?php _e("If the cropped image is not saved in the media library, the \"Image URL\" is the only available return value.", 'acf') ?></p> 
  199. </td> 
  200. <td> 
  201. <?php 
  202. do_action('acf/create_field', array( 
  203. 'type' => 'radio',  
  204. 'name' => 'fields['.$key.'][save_in_media_library]',  
  205. 'value' => $field['save_in_media_library'],  
  206. 'layout' => 'horizontal',  
  207. 'choices' => array( 
  208. 'yes' => __("Yes", 'acf'),  
  209. 'no' => __("No", 'acf') 
  210. ),  
  211. 'class' => 'save-in-media-library-select' 
  212. )); 
  213. ?> 
  214. </td> 
  215. </tr> 
  216. <?php 
  217. $retina_instructions = __('Require and crop double the size set for this image. Enable this if you are using plugins like WP Retina 2x.', 'acf-image_crop'); 
  218. if($this->getOption('retina_mode')) { 
  219. $retina_instructions .= '<br>' . __('NB. You currently have enabled retina mode globally for all fields through <a href="' . admin_url('options-media.php') . '#acf-image-crop-retina-mode' . '">settings</a>, which will override this setting.', 'acf-image_crop'); 
  220. ?> 
  221. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  222. <td class="label"> 
  223. <label><?php _e('Retina/@2x mode ', 'acf-image_crop'); ?></label> 
  224. <p><?php echo $retina_instructions ?></p> 
  225. </td> 
  226. <td> 
  227. <?php 
  228. do_action('acf/create_field', array( 
  229. 'type' => 'radio',  
  230. 'name' => 'fields['.$key.'][retina_mode]',  
  231. 'value' => $field['retina_mode'],  
  232. 'layout' => 'horizontal',  
  233. 'choices' => array( 
  234. 'yes' => __("Yes", 'acf'),  
  235. 'no' => __("No", 'acf') 
  236. ),  
  237. )); 
  238. ?> 
  239. </td> 
  240. </tr> 
  241. <tr class="field_option field_option_<?php echo $this->name; ?>"> 
  242. <td class="label"> 
  243. <label><?php _e("Return Value", 'acf'); ?></label> 
  244. <p><?php _e("Specify the returned value on front end", 'acf') ?></p> 
  245. </td> 
  246. <td> 
  247. <?php 
  248. do_action('acf/create_field', array( 
  249. 'type' => 'radio',  
  250. 'name' => 'fields['.$key.'][save_format]',  
  251. 'value' => $field['save_format'],  
  252. 'layout' => 'horizontal',  
  253. 'choices' => array( 
  254. 'url' => __("Image URL", 'acf'),  
  255. 'id' => __("Image ID", 'acf'),  
  256. 'object' => __("Image Object", 'acf') 
  257. ),  
  258. 'class' => 'return-value-select' 
  259. )); 
  260. ?> 
  261. </td> 
  262. </tr> 
  263. <?php 
  264.  
  265.  
  266.  
  267. /** 
  268. * create_field() 
  269. * Create the HTML interface for your field 
  270. * @param $field - an array holding all the field's data 
  271. * @type action 
  272. * @since 3.6 
  273. * @date 23/01/13 
  274. */ 
  275.  
  276. function create_field( $field ) 
  277. // defaults? 
  278. /** 
  279. $field = array_merge($this->defaults, $field); 
  280. */ 
  281. // perhaps use $field['preview_size'] to alter the markup? 
  282. $data = json_decode($field['value']); 
  283. // create Field HTML 
  284. // vars 
  285. $o = array( 
  286. 'class' => '',  
  287. 'url' => '',  
  288. ); 
  289. // $originalImage = null; 
  290. // if( $data && is_object($data) && is_numeric($data->original_image) ) 
  291. // { 
  292. // $originalImage = wp_get_attachment_image_src($data->original_image, 'full'); 
  293. // $url = wp_get_attachment_image_src($data->original_image, $field['preview_size']); 
  294. // if($field['save_in_media_library'] == 'yes') { 
  295. // if(is_numeric($data->cropped_image)) { 
  296. // $url = wp_get_attachment_image_src($data->cropped_image, $field['preview_size']); 
  297. // } 
  298. // } 
  299. // else{ 
  300. // if($data->cropped_image_url) { 
  301. // $url = $data->cropped_image_url; 
  302. // } 
  303. // else{ 
  304.  
  305. // } 
  306. // } 
  307.  
  308. // $o['class'] = 'active'; 
  309. // $o['url'] = $url[0]; 
  310. // } 
  311. $imageData = $this->get_image_data($field); 
  312. //print_r($field); 
  313. $originalImage = wp_get_attachment_image_src($imageData->original_image, 'full'); 
  314. if($imageData->original_image) { 
  315. $o['class'] = 'active'; 
  316. $o['url'] = $imageData->preview_image_url; 
  317. $width = 0; 
  318. $height = 0; 
  319. if($field['target_size'] == 'custom') { 
  320. $width = $field['width']; 
  321. $height = $field['height']; 
  322. else{ 
  323. global $_wp_additional_image_sizes; 
  324. $s = $field['target_size']; 
  325. if (isset($_wp_additional_image_sizes[$s])) { 
  326. $width = intval($_wp_additional_image_sizes[$s]['width']); 
  327. $height = intval($_wp_additional_image_sizes[$s]['height']); 
  328. } else { 
  329. $width = get_option($s.'_size_w'); 
  330. $height = get_option($s.'_size_h'); 
  331.  
  332. // Retina mode 
  333. if($this->getOption('retina_mode') || $field['retina_mode'] == 'yes') { 
  334. $width = $width * 2; 
  335. $height = $height * 2; 
  336. ?> 
  337. <div class="acf-image-uploader clearfix acf-image-crop <?php echo $o['class']; ?>" data-field-id="<?php echo $field['key'] ?>" data-preview_size="<?php echo $field['preview_size']; ?>" data-library="<?php echo isset($field['library']) ? $field['library'] : 'all'; ?>" data-width="<?php echo $width ?>" data-height="<?php echo $height ?>" data-crop-type="<?php echo $field['crop_type'] ?>" <?php echo ($field['force_crop'] == 'yes' ? 'data-force-crop="true"' : '')?> data-save-to-media-library="<?php echo $field['save_in_media_library'] ?>" > 
  338. <input class="acf-image-value" data-original-image="<?php echo $imageData->original_image ?>" data-cropped-image="<?php echo json_encode($imageData->cropped_image) ?>" type="hidden" name="<?php echo $field['name']; ?>" value="<?php echo htmlspecialchars($field['value']); ?>" /> 
  339. <div class="has-image"> 
  340. <div class="image-section"> 
  341. <div class="hover"> 
  342. <ul class="bl"> 
  343. <li><a class="acf-button-delete ir" href="#"><?php _e("Remove", 'acf'); ?></a></li> 
  344. <li><a class="acf-button-edit ir" href="#"><?php _e("Edit", 'acf'); ?></a></li> 
  345. </ul> 
  346. </div> 
  347. <img class="acf-image-image" src="<?php echo $o['url']; ?>" alt=""/> 
  348. </div> 
  349. <div class="crop-section"> 
  350. <div class="crop-stage"> 
  351. <div class="crop-action"> 
  352. <h4>Crop the image</h4> 
  353. <?php if ($imageData->original_image ): ?> 
  354. <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=""> 
  355. <?php endif ?> 
  356. </div> 
  357. <div class="crop-preview"> 
  358. <h4>Preview</h4> 
  359. <div class="preview"></div> 
  360. <div class="crop-controls"> 
  361. <a href="#" class="button button-large cancel-crop-button">Cancel</a> <a href="#" class="button button-large button-primary perform-crop-button">Crop!</a> 
  362. </div> 
  363. </div> 
  364. <!-- <img src="<?php echo $o['url']; ?>" alt=""/> --> 
  365. </div> 
  366. <a href="#" class="button button-large init-crop-button">Crop</a> 
  367. </div> 
  368. </div> 
  369. <div class="no-image"> 
  370. <p><?php _e('No image selected', 'acf'); ?> <input type="button" class="button add-image" value="<?php _e('Add Image', 'acf'); ?>" /> 
  371. </div> 
  372. </div> 
  373. <?php 
  374.  
  375.  
  376.  
  377. /** 
  378. * format_value_for_api() 
  379. * 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 
  380. * @type filter 
  381. * @since 3.6 
  382. * @date 23/01/13 
  383. * @param $value - the value which was loaded from the database 
  384. * @param $post_id - the $post_id from which the value was loaded 
  385. * @param $field - the field array holding all the field options 
  386. * @return $value - the modified value 
  387. */ 
  388.  
  389. function format_value_for_api( $value, $post_id, $field ) 
  390. // validate 
  391. if( !$value ) 
  392. return false; 
  393. $data = json_decode($value); 
  394. if(is_object($data)) { 
  395. $value = $data->cropped_image; 
  396. else{ 
  397. // We are migrating from a standard image field 
  398. $data = new stdClass(); 
  399. $data->cropped_image = $value; 
  400. $data->original_image = $value; 
  401.  
  402. // format 
  403. if( $field['save_format'] == 'url' ) 
  404. if(is_numeric($data->cropped_image)) { 
  405. $value = wp_get_attachment_url( $data->cropped_image ); 
  406. elseif(is_array($data->cropped_image)) { 
  407.  
  408. $value = $this->getAbsoluteImageUrl($data->cropped_image['image']); 
  409. elseif(is_object($data->cropped_image)) { 
  410. $value = $this->getAbsoluteImageUrl($data->cropped_image->image); 
  411.  
  412. elseif( $field['save_format'] == 'object' ) 
  413. if(is_numeric($data->cropped_image )) { 
  414. $value = $this->getImageArray($data->cropped_image); 
  415. $value['original_image'] = $this->getImageArray($data->original_image); 
  416. // $attachment = get_post( $data->cropped_image ); 
  417. // // validate 
  418. // if( !$attachment ) 
  419. // { 
  420. // return false; 
  421. // } 
  422.  
  423.  
  424. // // create array to hold value data 
  425. // $src = wp_get_attachment_image_src( $attachment->ID, 'full' ); 
  426.  
  427. // $value = array( 
  428. // 'id' => $attachment->ID,  
  429. // 'alt' => get_post_meta($attachment->ID, '_wp_attachment_image_alt', true),  
  430. // 'title' => $attachment->post_title,  
  431. // 'caption' => $attachment->post_excerpt,  
  432. // 'description' => $attachment->post_content,  
  433. // 'mime_type' => $attachment->post_mime_type,  
  434. // 'url' => $src[0],  
  435. // 'width' => $src[1],  
  436. // 'height' => $src[2],  
  437. // 'sizes' => array(),  
  438. // ); 
  439.  
  440.  
  441. // // find all image sizes 
  442. // $image_sizes = get_intermediate_image_sizes(); 
  443.  
  444. // if( $image_sizes ) 
  445. // { 
  446. // foreach( $image_sizes as $image_size ) 
  447. // { 
  448. // // find src 
  449. // $src = wp_get_attachment_image_src( $attachment->ID, $image_size ); 
  450.  
  451. // // add src 
  452. // $value[ 'sizes' ][ $image_size ] = $src[0]; 
  453. // $value[ 'sizes' ][ $image_size . '-width' ] = $src[1]; 
  454. // $value[ 'sizes' ][ $image_size . '-height' ] = $src[2]; 
  455. // } 
  456. // // foreach( $image_sizes as $image_size ) 
  457. // } 
  458. elseif(is_array( $data->cropped_image) || is_object($data->cropped_image)) { 
  459. // Cropped image is not saved to media directory. Get data from original image instead 
  460. $value = $this->getImageArray($data->original_image); 
  461.  
  462. // Get the relative url from data 
  463. $relativeUrl = ''; 
  464. if(is_array( $data->cropped_image)) { 
  465. $relativeUrl = $data->cropped_image['image']; 
  466. else{ 
  467. $relativeUrl = $data->cropped_image->image; 
  468.  
  469. // Replace URL with cropped version 
  470. $value['url'] = $this->getAbsoluteImageUrl($relativeUrl); 
  471.  
  472. // Calculate and replace sizes 
  473. $imagePath = $this->getImagePath($relativeUrl); 
  474. $dimensions = getimagesize($imagePath); 
  475. $value['width'] = $dimensions[0]; 
  476. $value['height'] = $dimensions[1]; 
  477.  
  478. // Add original image info 
  479. $value['original_image'] = $this->getImageArray($data->original_image); 
  480. else{ 
  481.  
  482. //echo 'ELSE'; 
  483.  
  484. return $value; 
  485.  
  486.  
  487.  
  488. function getImageArray($id) { 
  489. $attachment = get_post( $id ); 
  490. // validate 
  491. if( !$attachment ) 
  492. return false; 
  493.  
  494.  
  495. // create array to hold value data 
  496. $src = wp_get_attachment_image_src( $attachment->ID, 'full' ); 
  497.  
  498. $imageArray = array( 
  499. 'id' => $attachment->ID,  
  500. 'alt' => get_post_meta($attachment->ID, '_wp_attachment_image_alt', true),  
  501. 'title' => $attachment->post_title,  
  502. 'caption' => $attachment->post_excerpt,  
  503. 'description' => $attachment->post_content,  
  504. 'mime_type' => $attachment->post_mime_type,  
  505. 'url' => $src[0],  
  506. 'width' => $src[1],  
  507. 'height' => $src[2],  
  508. 'sizes' => array(),  
  509. ); 
  510.  
  511.  
  512. // find all image sizes 
  513. $image_sizes = get_intermediate_image_sizes(); 
  514.  
  515. if( $image_sizes ) 
  516. foreach( $image_sizes as $image_size ) 
  517. // find src 
  518. $src = wp_get_attachment_image_src( $attachment->ID, $image_size ); 
  519.  
  520. // add src 
  521. $imageArray[ 'sizes' ][ $image_size ] = $src[0]; 
  522. $imageArray[ 'sizes' ][ $image_size . '-width' ] = $src[1]; 
  523. $imageArray[ 'sizes' ][ $image_size . '-height' ] = $src[2]; 
  524. return $imageArray; 
  525.  
  526. /** 
  527. * input_admin_enqueue_scripts() 
  528. * This action is called in the admin_enqueue_scripts action on the edit screen where your field is created. 
  529. * Use this action to add css + javascript to assist your create_field() action. 
  530. * $info http://codex.wordpress.org/Plugin_API/Action_Reference/admin_enqueue_scripts 
  531. * @type action 
  532. * @since 3.6 
  533. * @date 23/01/13 
  534. */ 
  535.  
  536. function input_admin_enqueue_scripts() 
  537. // Note: This function can be removed if not used 
  538.  
  539.  
  540. // register acf scripts 
  541. wp_register_script('acf-input-image_crop', $this->settings['dir'] . 'js/input-v4.js', array('acf-input', 'imgareaselect'), $this->settings['version']); 
  542.  
  543. wp_register_style('acf-input-image_crop', $this->settings['dir'] . 'css/input.css', array('acf-input'), $this->settings['version']); 
  544. wp_register_script( 'jcrop', includes_url( 'js/jcrop/jquery.Jcrop.min.css' )); 
  545.  
  546.  
  547. // scripts 
  548. wp_enqueue_script(array( 
  549. 'acf-input-image_crop' 
  550. )); 
  551.  
  552. wp_localize_script( 'acf-input-image_crop', 'ajax', array('nonce' => wp_create_nonce('acf_nonce')) ); 
  553.  
  554. // styles 
  555. wp_enqueue_style(array( 
  556. 'acf-input-image_crop',  
  557. 'imgareaselect' 
  558. )); 
  559.  
  560.  
  561.  
  562. /** 
  563. * field_group_admin_enqueue_scripts() 
  564. * This action is called in the admin_enqueue_scripts action on the edit screen where your field is edited. 
  565. * Use this action to add css + javascript to assist your create_field_options() action. 
  566. * $info http://codex.wordpress.org/Plugin_API/Action_Reference/admin_enqueue_scripts 
  567. * @type action 
  568. * @since 3.6 
  569. * @date 23/01/13 
  570. */ 
  571.  
  572. function field_group_admin_enqueue_scripts() 
  573. // Note: This function can be removed if not used 
  574. wp_register_script('acf-input-image-crop-options', $this->settings['dir'] . 'js/options-v4.js', array('jquery'), $this->settings['version']); 
  575. wp_enqueue_script( 'acf-input-image-crop-options'); 
  576.  
  577. wp_register_style('acf-input-image-crop-options', $this->settings['dir'] . 'css/options.css'); 
  578. wp_enqueue_style( 'acf-input-image-crop-options'); 
  579.  
  580.  
  581. /** 
  582. * update_value() 
  583. * This filter is appied to the $value before it is updated in the db 
  584. * @type filter 
  585. * @since 3.6 
  586. * @date 23/01/13 
  587. * @param $value - the value which will be saved in the database 
  588. * @param $post_id - the $post_id of which the value will be saved 
  589. * @param $field - the field array holding all the field options 
  590. * @return $value - the modified value 
  591. */ 
  592.  
  593. function update_value( $value, $post_id, $field ) 
  594. // array? 
  595. if( is_array($value) && isset($value['id']) ) 
  596. $value = $value['id']; 
  597.  
  598. // object? 
  599. if( is_object($value) && isset($value->ID) ) 
  600. $value = $value->ID; 
  601.  
  602. return $value; 
  603.  
  604. function get_image_data($field) { 
  605. $imageData = new stdClass(); 
  606. $imageData->original_image = ''; 
  607. $imageData->original_image_width = ''; 
  608. $imageData->original_image_height = ''; 
  609. $imageData->cropped_image = ''; 
  610. $imageData->original_image_url = ''; 
  611. $imageData->preview_image_url = ''; 
  612. $imageData->image_url = ''; 
  613.  
  614. if($field['value'] == '') { 
  615. // Field has not yet been saved or is an empty image field 
  616. return $imageData; 
  617.  
  618. $data = json_decode($field['value']); 
  619.  
  620. if(! is_object($data)) { 
  621. // Field was saved as a regular image field 
  622. $imageAtts = wp_get_attachment_image_src($field['value'], 'full'); 
  623. $imageData->original_image = $field['value']; 
  624. $imageData->original_image_width = $imageAtts[1]; 
  625. $imageData->original_image_height = $imageAtts[2]; 
  626. $imageData->preview_image_url = $this->get_image_src($field['value'], $field['preview_size']); 
  627. $imageData->image_url = $this->get_image_src($field['value'], 'full'); 
  628. $imageData->original_image_url = $imageData->image_url; 
  629. return $imageData; 
  630.  
  631. if( !is_numeric($data->original_image) ) 
  632. // The field has been saved, but has no image 
  633. return $imageData; 
  634.  
  635. // By now, we have at least a saved original image 
  636. $imageAtts = wp_get_attachment_image_src($data->original_image, 'full'); 
  637. $imageData->original_image = $data->original_image; 
  638. $imageData->original_image_width = $imageAtts[1]; 
  639. $imageData->original_image_height = $imageAtts[2]; 
  640. $imageData->original_image_url = $this->get_image_src($data->original_image, 'full'); 
  641.  
  642. // Set defaults to original image 
  643. $imageData->image_url = $this->get_image_src($data->original_image, 'full'); 
  644. $imageData->preview_image_url = $this->get_image_src($data->original_image, $field['preview_size']); 
  645.  
  646. // Check if there is a cropped version and set appropriate attributes 
  647. if(is_numeric($data->cropped_image)) { 
  648. // Cropped image was saved to media library ans has an ID 
  649. $imageData->cropped_image = $data->cropped_image; 
  650. $imageData->image_url = $this->get_image_src($data->cropped_image, 'full'); 
  651. $imageData->preview_image_url = $this->get_image_src($data->cropped_image, $field['preview_size']); 
  652. elseif(is_object($data->cropped_image)) { 
  653. // Cropped image was not saved to media library and is only stored by its URL 
  654. $imageData->cropped_image = $data->cropped_image; 
  655.  
  656. // Generate appropriate URLs 
  657. $mediaDir = wp_upload_dir(); 
  658. $imageData->image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->image; 
  659. $imageData->preview_image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->preview; 
  660. return $imageData; 
  661.  
  662. function perform_crop() { 
  663. $targetWidth = $_POST['target_width']; 
  664. $targetHeight = $_POST['target_height']; 
  665. $saveToMediaLibrary = $_POST['save_to_media_library'] == 'yes'; 
  666. $imageData = $this->generate_cropped_image($_POST['id'], $_POST['x1'], $_POST['x2'], $_POST['y1'], $_POST['y2'], $targetWidth, $targetHeight, $saveToMediaLibrary, $_POST['preview_size']); 
  667. // $previewUrl = wp_get_attachment_image_src( $id, $_POST['preview_size']); 
  668. // $fullUrl = wp_get_attachment_image_src( $id, 'full'); 
  669. echo json_encode($imageData); 
  670. die(); 
  671.  
  672. function generate_cropped_image($id, $x1, $x2, $y1, $y2, $targetW, $targetH, $saveToMediaLibrary, $previewSize) {//$id, $x1, $x2, $y$, $y2, $targetW, $targetH) { 
  673. require_once ABSPATH . "/wp-admin/includes/file.php"; 
  674. require_once ABSPATH . "/wp-admin/includes/image.php"; 
  675.  
  676. // Create the variable that will hold the new image data 
  677. $imageData = array(); 
  678.  
  679. // Fetch media library info 
  680. $mediaDir = wp_upload_dir(); 
  681.  
  682. // Get original image info 
  683. $originalImageData = wp_get_attachment_metadata($id); 
  684.  
  685. // Get image editor from original image path to crop the image 
  686. $image = wp_get_image_editor( $mediaDir['basedir'] . '/' . $originalImageData['file'] ); 
  687.  
  688. if(! is_wp_error( $image ) ) { 
  689.  
  690. // Crop the image using the provided measurements 
  691. $image->crop($x1, $y1, $x2 - $x1, $y2 - $y1, $targetW, $targetH); 
  692.  
  693. // Retrieve original filename and seperate it from its file extension 
  694. $originalFileName = explode('.', basename($originalImageData['file'])); 
  695.  
  696. // Retrieve and remove file extension from array 
  697. $originalFileExtension = array_pop($originalFileName); 
  698.  
  699. // Generate new base filename 
  700. $targetFileName = implode('.', $originalFileName) . '_' . $targetW . 'x' . $targetH . apply_filters('acf-image-crop/filename_postfix', '_acf_cropped') . '.' . $originalFileExtension; 
  701.  
  702. // Generate target path new file using existing media library 
  703. $targetFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], $targetFileName); 
  704.  
  705. // Get the relative path to save as the actual image url 
  706. $targetRelativePath = str_replace($mediaDir['basedir'] . '/', '', $targetFilePath); 
  707.  
  708. // Save the image to the target path 
  709. if(is_wp_error($image->save($targetFilePath))) { 
  710. // There was an error saving the image 
  711. //TODO handle it 
  712.  
  713. // If file should be saved to media library, create an attachment for it at get the new attachment ID 
  714. if($saveToMediaLibrary) { 
  715. // Generate attachment from created file 
  716.  
  717. // Get the filetype 
  718. $wp_filetype = wp_check_filetype(basename($targetFilePath), null ); 
  719. $attachment = array( 
  720. 'guid' => $mediaDir['url'] . '/' . basename($targetFilePath),  
  721. 'post_mime_type' => $wp_filetype['type'],  
  722. 'post_title' => preg_replace('/\.[^.]+$/', '', basename($targetFilePath)),  
  723. 'post_content' => '',  
  724. 'post_status' => 'inherit' 
  725. ); 
  726. $attachmentId = wp_insert_attachment( $attachment, $targetFilePath); 
  727. $attachmentData = wp_generate_attachment_metadata( $attachmentId, $targetFilePath ); 
  728. wp_update_attachment_metadata( $attachmentId, $attachmentData ); 
  729. add_post_meta($attachmentId, 'acf_is_cropped', 'true', true); 
  730.  
  731. // Add the id to the imageData-array 
  732. $imageData['value'] = $attachmentId; 
  733.  
  734. // Add the image url 
  735. $imageUrlObject = wp_get_attachment_image_src( $attachmentId, 'full'); 
  736. $imageData['url'] = $imageUrlObject[0]; 
  737.  
  738. // Add the preview url as well 
  739. $previewUrlObject = wp_get_attachment_image_src( $attachmentId, $previewSize); 
  740. $imageData['preview_url'] = $previewUrlObject[0]; 
  741. // Else we need to return the actual path of the cropped image 
  742. else{ 
  743. // Add the image url to the imageData-array 
  744. $imageData['value'] = array('image' => $targetRelativePath); 
  745. $imageData['url'] = $mediaDir['baseurl'] . '/' . $targetRelativePath; 
  746.  
  747. // Get preview size dimensions 
  748. global $_wp_additional_image_sizes; 
  749. $previewWidth = 0; 
  750. $previewHeight = 0; 
  751. $crop = 0; 
  752. if (isset($_wp_additional_image_sizes[$previewSize])) { 
  753. $previewWidth = intval($_wp_additional_image_sizes[$previewSize]['width']); 
  754. $previewHeight = intval($_wp_additional_image_sizes[$previewSize]['height']); 
  755. $crop = $_wp_additional_image_sizes[$previewSize]['crop']; 
  756. } else { 
  757. $previewWidth = get_option($previewSize.'_size_w'); 
  758. $previewHeight = get_option($previewSize.'_size_h'); 
  759. $crop = get_option($previewSize.'_crop'); 
  760.  
  761. // Generate preview file path 
  762. $previewFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], 'preview_' . $targetFileName); 
  763. $previewRelativePath = str_replace($mediaDir['basedir'] . '/', '', $previewFilePath); 
  764.  
  765. // Get image editor from cropped image 
  766. $croppedImage = wp_get_image_editor( $targetFilePath ); 
  767. $croppedImage->resize($previewWidth, $previewHeight, $crop); 
  768.  
  769. // Save the preview 
  770. $croppedImage->save($previewFilePath); 
  771.  
  772. // Add the preview url 
  773. $imageData['preview_url'] = $mediaDir['baseurl'] . '/' . $previewRelativePath; 
  774. $imageData['value']['preview'] = $previewRelativePath; 
  775. $imageData['success'] = true; 
  776. return $imageData; 
  777. else{ 
  778. // Handle WP_ERROR 
  779. $response = array(); 
  780. $response['success'] = false; 
  781. $response['error_message'] = ''; 
  782. foreach($image->error_data as $code => $message) { 
  783. $response['error_message'] .= '<p><strong>' . $code . '</strong>: ' . $message . '</p>'; 
  784. return $response; 
  785.  
  786. function get_image_src($id, $size = 'thumbnail') { 
  787. $atts = wp_get_attachment_image_src( $id, $size); 
  788. return $atts[0]; 
  789.  
  790. function getAbsoluteImageUrl($relativeUrl) { 
  791. $mediaDir = wp_upload_dir(); 
  792. return $mediaDir['baseurl'] . '/' . $relativeUrl; 
  793.  
  794. function getImagePath($relativePath) { 
  795. $mediaDir = wp_upload_dir(); 
  796. return $mediaDir['basedir'] . '/' . $relativePath; 
  797.  
  798. function filterMediaQuery($args) { 
  799. // get options 
  800. $options = get_option( 'acf_image_crop_settings' ); 
  801. $hide = $options['hide_cropped']; 
  802.  
  803. // If hide option is enabled, do not select items with the acf_is_cropped meta-field 
  804. if($hide) { 
  805. $args['meta_query']= array( 
  806. array( 
  807. 'key' => 'acf_is_cropped',  
  808. 'compare' => 'NOT EXISTS' 
  809. ); 
  810. return $args; 
  811.  
  812.  
  813. function registerSettings() { 
  814. add_settings_section( 
  815. 'acf_image_crop_settings',  
  816. __('ACF Image Crop Settings', 'acf-image_crop'),  
  817. array($this, 'displayImageCropSettingsSection'),  
  818. 'media' 
  819. ); 
  820.  
  821. register_setting( 
  822. 'media', // settings page 
  823. 'acf_image_crop_settings' // option name 
  824. ); 
  825.  
  826. add_settings_field( 
  827. 'acf_image_crop_hide_cropped', // id 
  828. __('Hide cropped images from media dialog', 'acf-image_crop'), // setting title 
  829. array($this, 'displayHideFromMediaInput'), // display callback 
  830. 'media', // settings page 
  831. 'acf_image_crop_settings' // settings section 
  832. ); 
  833.  
  834. add_settings_field( 
  835. 'acf_image_crop_retina_mode', // id 
  836. __('Enable global retina mode (beta)', 'acf-image_crop'), // setting title 
  837. array($this, 'displayRetinaModeInput'), // display callback 
  838. 'media', // settings page 
  839. 'acf_image_crop_settings' // settings section 
  840. ); 
  841.  
  842. function displayHideFromMediaInput() { 
  843. // Get plugin options 
  844. $options = get_option( 'acf_image_crop_settings' ); 
  845. $value = $options['hide_cropped']; 
  846.  
  847. // echo the field 
  848. ?> 
  849. <input name='acf_image_crop_settings[hide_cropped]' 
  850. type='checkbox' <?php echo $value ? 'checked' : '' ?> value='true' /> 
  851. <?php 
  852.  
  853. function displayRetinaModeInput() { 
  854. // Get plugin options 
  855. $options = get_option( 'acf_image_crop_settings' ); 
  856. $value = $options['retina_mode']; 
  857.  
  858. // echo the field 
  859. ?> 
  860. <input id="acf-image-crop-retina-mode" name='acf_image_crop_settings[retina_mode]' 
  861. type='checkbox' <?php echo $value ? 'checked' : '' ?> value='true' /> 
  862. <?php 
  863.  
  864. function displayImageCropSettingsSection() { 
  865. echo ''; 
  866.  
  867. function getOption($key) { 
  868. return isset($this->options[$key]) ? $this->options[$key] : null; 
  869.  
/acf-image-crop-v5.php  
  1. class acf_field_image_crop extends acf_field_image { 
  2.  
  3.  
  4. /** 
  5. * __construct 
  6. * This function will setup the field type data 
  7. * @type function 
  8. * @date 5/03/2014 
  9. * @since 5.0.0 
  10. * @param n/a 
  11. * @return n/a 
  12. */ 
  13.  
  14. function __construct() { 
  15.  
  16. /** 
  17. * name (string) Single word, no spaces. Underscores allowed 
  18. */ 
  19.  
  20. $this->name = 'image_crop'; 
  21.  
  22.  
  23. /** 
  24. * label (string) Multiple words, can include spaces, visible when selecting a field type 
  25. */ 
  26.  
  27. $this->label = __('Image with user-crop', 'acf-image_crop'); 
  28.  
  29.  
  30. /** 
  31. * category (string) basic | content | choice | relational | jquery | layout | CUSTOM GROUP NAME 
  32. */ 
  33.  
  34. $this->category = 'content'; 
  35.  
  36.  
  37. /** 
  38. * defaults (array) Array of default settings which are merged into the field object. These are used later in settings 
  39. */ 
  40.  
  41. $this->defaults = array( 
  42. 'force_crop' => 'no',  
  43. 'crop_type' => 'hard',  
  44. 'preview_size' => 'medium',  
  45. 'save_format' => 'id',  
  46. 'save_in_media_library' => 'yes',  
  47. 'target_size' => 'thumbnail',  
  48. 'library' => 'all',  
  49. 'retina_mode' => 'no' 
  50. ); 
  51.  
  52. $this->options = get_option( 'acf_image_crop_settings' ); 
  53.  
  54. // add ajax action to be able to retrieve full image size via javascript 
  55. add_action( 'wp_ajax_acf_image_crop_get_image_size', array( &$this, 'crop_get_image_size' ) ); 
  56. add_action( 'wp_ajax_acf_image_crop_perform_crop', array( &$this, 'perform_crop' ) ); 
  57.  
  58.  
  59. // add filter to media query function to hide cropped images from media library 
  60. add_filter('ajax_query_attachments_args', array($this, 'filterMediaQuery')); 
  61.  
  62. // Register extra fields on the media settings page on admin_init 
  63. add_action('admin_init', array($this, 'registerSettings')); 
  64.  
  65. /** 
  66. * l10n (array) Array of strings that are used in JavaScript. This allows JS strings to be translated in PHP and loaded via: 
  67. * var message = acf._e('image_crop', 'error'); 
  68. */ 
  69.  
  70. $this->l10n = array( 
  71. 'width_should_be' => __( 'Width should be at least: ', 'acf-image_crop' ),  
  72. 'height_should_be' => __( 'Height should be at least: ', 'acf-image_crop' ),  
  73. 'selected_width' => __( 'Selected image width: ', 'acf-image_crop' ),  
  74. 'selected_height' => __( 'Selected image height: ', 'acf-image_crop' ),  
  75. 'size_warning' => __( 'Warning: The selected image is smaller than the required size!', 'acf-image_crop' ),  
  76. 'crop_error' => __( 'Sorry, an error occurred when trying to crop your image:') 
  77. ); 
  78.  
  79.  
  80. // do not delete! 
  81. acf_field::__construct(); 
  82. //parent::__construct(); 
  83.  
  84.  
  85.  
  86. // AJAX handler for retieving full image dimensions from ID 
  87. public function crop_get_image_size() 
  88. $img = wp_get_attachment_image_src( $_POST['image_id'], 'full'); 
  89. if($img) { 
  90. echo json_encode( array( 
  91. 'url' => $img[0],  
  92. 'width' => $img[1],  
  93. 'height' => $img[2] 
  94. ) ); 
  95. exit; 
  96.  
  97.  
  98. /** 
  99. * render_field_settings() 
  100. * Create extra settings for your field. These are visible when editing a field 
  101. * @type action 
  102. * @since 3.6 
  103. * @date 23/01/13 
  104. * @param $field (array) the $field being edited 
  105. * @return n/a 
  106. */ 
  107.  
  108. function render_field_settings( $field ) { 
  109.  
  110. /** 
  111. * acf_render_field_setting 
  112. * This function will create a setting for your field. Simply pass the $field parameter and an array of field settings. 
  113. * The array of settings does not require a `value` or `prefix`; These settings are found from the $field array. 
  114. * More than one setting can be added by copy/paste the above code. 
  115. * Please note that you must also have a matching $defaults value for the field name (font_size) 
  116. */ 
  117.  
  118. // crop_type 
  119. acf_render_field_setting( $field, array( 
  120. 'label' => __('Crop type', 'acf-image_crop'),  
  121. 'instructions' => __('Select the type of crop the user should perform', 'acf-image_crop'),  
  122. 'type' => 'select',  
  123. 'name' => 'crop_type',  
  124. 'layout' => 'horizontal',  
  125. 'class' => 'crop-type-select',  
  126. 'choices' => array( 
  127. 'hard' => __('Hard crop', 'acf-image_crop'),  
  128. 'min' => __('Minimal dimensions', 'acf-image_crop') 
  129. )); 
  130.  
  131. // target_size 
  132. $sizes = acf_get_image_sizes(); 
  133. // added 
  134. $instructions = __('Select the target size for this field', 'acf-image_crop'); 
  135. if ( $this->getOption('retina_mode') ) { 
  136. $instructions .= '<br><br><em><strong>'.__('Retina mode is enabled - user will be required to select an image twice this size', 'acf-image_crop').'</strong></em>'; 
  137. // added END 
  138. $sizes['custom'] = __('Custom size', 'acf-image_crop'); 
  139. acf_render_field_setting( $field, array( 
  140. 'label' => __('Target size', 'acf-image_crop'),  
  141. 'instructions' => $instructions,  
  142. 'type' => 'select',  
  143. 'name' => 'target_size',  
  144. 'class' => 'target-size-select',  
  145. 'choices' => $sizes 
  146. )); 
  147.  
  148. // width - conditional: target_size == 'custom' 
  149. acf_render_field_setting( $field, array( 
  150. 'label' => __('Custom target width', 'acf-image_crop'),  
  151. 'instructions' => __('Leave blank for no restriction (does not work with hard crop option)', 'acf-image_crop'),  
  152. 'type' => 'number',  
  153. 'name' => 'width',  
  154. 'class' => 'custom-target-width custom-target-dimension',  
  155. 'append' => 'px' 
  156. )); 
  157.  
  158. // height - conditional: target_size == 'custom' 
  159. acf_render_field_setting( $field, array( 
  160. 'label' => __('Custom target height', 'acf-image_crop'),  
  161. 'instructions' => __('Leave blank for no restriction (does not work with hard crop option)', 'acf-image_crop'),  
  162. 'type' => 'number',  
  163. 'name' => 'height',  
  164. 'class' => 'custom-target-height custom-target-dimension',  
  165. 'append' => 'px' 
  166. )); 
  167.  
  168. // preview_size 
  169. acf_render_field_setting( $field, array( 
  170. 'label' => __('Preview Size', 'acf'),  
  171. 'instructions' => __('Shown when entering data', 'acf'),  
  172. 'type' => 'select',  
  173. 'name' => 'preview_size',  
  174. 'choices' => acf_get_image_sizes() 
  175. )); 
  176.  
  177. // force_crop 
  178. acf_render_field_setting( $field, array( 
  179. 'label' => __('Force crop', 'acf-image_crop'),  
  180. 'instructions' => __('Force the user to crop the image as soon at it is selected', 'acf-image_crop'),  
  181. 'type' => 'radio',  
  182. 'layout' => 'horizontal',  
  183. 'name' => 'force_crop',  
  184. 'choices' => array('yes' => __('Yes', 'acf'), 'no' => __('No', 'acf')) 
  185. )); 
  186.  
  187. // save_in_media_library 
  188. acf_render_field_setting( $field, array( 
  189. 'label' => __('Save cropped image to media library', 'acf-image_crop'),  
  190. 'instructions' => __('If the cropped image is not saved in the media library, "Image URL" is the only available return value.', 'acf-image_crop'),  
  191. 'type' => 'radio',  
  192. 'layout' => 'horizontal',  
  193. 'name' => 'save_in_media_library',  
  194. 'class' => 'save-in-media-library-select',  
  195. 'choices' => array('yes' => __('Yes', 'acf'), 'no' => __('No', 'acf')) 
  196. )); 
  197.  
  198. // only show this setting if the global option for retina mode is not activated 
  199. // retina mode 
  200. if ( !$this->getOption('retina_mode') ) { 
  201. acf_render_field_setting( $field, array( 
  202. 'label' => __('Retina/@2x mode ', 'acf-image_crop'),  
  203. 'instructions' => __('Require and crop double the size set for this image. Enable this if you are using plugins like WP Retina 2x.', 'acf-image_crop'),  
  204. 'type' => 'radio',  
  205. 'layout' => 'horizontal',  
  206. 'name' => 'retina_mode',  
  207. 'choices' => array('yes' => __('Yes', 'acf'), 'no' => __('No', 'acf')) 
  208. )); 
  209. // return_format 
  210. acf_render_field_setting( $field, array( 
  211. 'label' => __('Return Value', 'acf'),  
  212. 'instructions' => __('Specify the returned value on front end', 'acf'),  
  213. 'type' => 'radio',  
  214. 'name' => 'save_format',  
  215. 'layout' => 'horizontal',  
  216. 'class' => 'return-value-select',  
  217. 'choices' => array( 
  218. 'object' => __("Image Array", 'acf'),  
  219. 'url' => __("Image URL", 'acf'),  
  220. 'id' => __("Image ID", 'acf') 
  221. )); 
  222.  
  223. // library 
  224. acf_render_field_setting( $field, array( 
  225. 'label' => __('Library', 'acf'),  
  226. 'instructions' => __('Limit the media library choice', 'acf'),  
  227. 'type' => 'radio',  
  228. 'name' => 'library',  
  229. 'layout' => 'horizontal',  
  230. 'choices' => array( 
  231. 'all' => __('All', 'acf'),  
  232. 'uploadedTo' => __('Uploaded to post', 'acf') 
  233. )); 
  234.  
  235.  
  236.  
  237.  
  238. /** 
  239. * render_field() 
  240. * Create the HTML interface for your field 
  241. * @param $field (array) the $field being rendered 
  242. * @type action 
  243. * @since 3.6 
  244. * @date 23/01/13 
  245. * @param $field (array) the $field being edited 
  246. * @return n/a 
  247. */ 
  248.  
  249. function render_field( $field ) { 
  250.  
  251.  
  252. // enqueue 
  253. acf_enqueue_uploader(); 
  254.  
  255. // get data from value 
  256. //$data = json_decode($field['value']); 
  257. $imageData = $this->get_image_data($field); 
  258.  
  259. $url = ''; 
  260. $orignialImage = null; 
  261.  
  262. if($imageData->original_image) { 
  263. $originalImage = wp_get_attachment_image_src($imageData->original_image, 'full'); 
  264. $url = $imageData->preview_image_url; 
  265.  
  266. $width = 0; 
  267. $height = 0; 
  268.  
  269. if($field['target_size'] == 'custom') { 
  270. $width = $field['width']; 
  271. $height = $field['height']; 
  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. // Retina mode 
  283. if($this->getOption('retina_mode') || $field['retina_mode'] == 'yes') { 
  284. $width = $width * 2; 
  285. $height = $height * 2; 
  286.  
  287. // vars 
  288. $div_atts = array( 
  289. 'class' => 'acf-image-uploader acf-cf acf-image-crop',  
  290. 'data-field-settings' => json_encode($field),  
  291. 'data-crop_type' => $field['crop_type'],  
  292. 'data-target_size' => $field['target_size'],  
  293. 'data-width' => $width,  
  294. 'data-height' => $height,  
  295. 'data-force_crop' => $field['force_crop'] == 'yes' ? 'true' : 'false',  
  296. 'data-save_to_media_library' => $field['save_in_media_library'],  
  297. 'data-save_format' => $field['save_format'],  
  298. 'data-preview_size' => $field['preview_size'],  
  299. 'data-library' => $field['library'] 
  300. ); 
  301. $input_atts = array( 
  302. 'type' => 'hidden',  
  303. 'name' => $field['name'],  
  304. 'value' => htmlspecialchars($field['value']),  
  305. 'data-name' => 'id',  
  306. 'data-original-image' => $imageData->original_image,  
  307. 'data-cropped-image' => json_encode($imageData->cropped_image),  
  308. 'class' => 'acf-image-value' 
  309. ); 
  310.  
  311. // has value? 
  312. if($imageData->original_image) { 
  313. $url = $imageData->preview_image_url; 
  314. $div_atts['class'] .= ' has-value'; 
  315.  
  316. ?> 
  317. <div <?php acf_esc_attr_e( $div_atts ); ?>> 
  318. <div class="acf-hidden"> 
  319. <input <?php acf_esc_attr_e( $input_atts ); ?>/> 
  320. </div> 
  321. <div class="view show-if-value acf-soh"> 
  322. <ul class="acf-hl acf-soh-target"> 
  323. <li><a class="acf-icon -pencil dark" data-name="edit" href="#"><i class="acf-sprite-edit"></i></a></li> 
  324. <li><a class="acf-icon -cancel dark" data-name="remove" href="#"><i class="acf-sprite-delete"></i></a></li> 
  325. </ul> 
  326. <img data-name="image" src="<?php echo $url; ?>" alt=""/> 
  327. <div class="crop-section"> 
  328. <div class="crop-stage"> 
  329. <div class="crop-action"> 
  330. <h4><?php _e('Crop the image', 'acf-image_crop'); ?></h4> 
  331. <?php if ($imageData->original_image ): ?> 
  332. <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=""> 
  333. <?php endif ?> 
  334. </div> 
  335. <div class="crop-preview"> 
  336. <h4><?php _e('Preview', 'acf-image_crop'); ?></h4> 
  337. <div class="preview"></div> 
  338. <div class="crop-controls"> 
  339. <a href="#" class="button button-large cancel-crop-button"><?php _e('Cancel', 'acf-image_crop'); ?></a> <a href="#" class="button button-large button-primary perform-crop-button"><?php _e('Crop!', 'acf-image_crop'); ?></a> 
  340. </div> 
  341. </div> 
  342. </div> 
  343. <a href="#" class="button button-large init-crop-button"><?php _e('Crop', 'acf-image_crop'); ?></a> 
  344. </div> 
  345. </div> 
  346. <div class="view hide-if-value"> 
  347. <p><?php _e('No image selected', 'acf'); ?> <a data-name="add" class="acf-button button" href="#"><?php _e('Add Image', 'acf'); ?></a></p> 
  348. </div> 
  349. </div> 
  350. <?php 
  351.  
  352.  
  353. /*** 
  354. * Parses the field value into a consistent data object 
  355. ****/ 
  356. function get_image_data($field) { 
  357. $imageData = new stdClass(); 
  358. $imageData->original_image = ''; 
  359. $imageData->original_image_width = ''; 
  360. $imageData->original_image_height = ''; 
  361. $imageData->cropped_image = ''; 
  362. $imageData->original_image_url = ''; 
  363. $imageData->preview_image_url = ''; 
  364. $imageData->image_url = ''; 
  365.  
  366. if($field['value'] == '') { 
  367. // Field has not yet been saved or is an empty image field 
  368. return $imageData; 
  369.  
  370. $data = json_decode($field['value']); 
  371.  
  372. if(! is_object($data)) { 
  373. // Field was saved as a regular image field 
  374. $imageAtts = wp_get_attachment_image_src($field['value'], 'full'); 
  375. $imageData->original_image = $field['value']; 
  376. $imageData->original_image_width = $imageAtts[1]; 
  377. $imageData->original_image_height = $imageAtts[2]; 
  378. $imageData->preview_image_url = $this->get_image_src($field['value'], $field['preview_size']); 
  379. $imageData->image_url = $this->get_image_src($field['value'], 'full'); 
  380. $imageData->original_image_url = $imageData->image_url; 
  381. return $imageData; 
  382.  
  383. if( !is_numeric($data->original_image) ) 
  384. // The field has been saved, but has no image 
  385. return $imageData; 
  386.  
  387. // By now, we have at least a saved original image 
  388. $imageAtts = wp_get_attachment_image_src($data->original_image, 'full'); 
  389. $imageData->original_image = $data->original_image; 
  390. $imageData->original_image_width = $imageAtts[1]; 
  391. $imageData->original_image_height = $imageAtts[2]; 
  392. $imageData->original_image_url = $this->get_image_src($data->original_image, 'full'); 
  393.  
  394. // Set defaults to original image 
  395. $imageData->image_url = $this->get_image_src($data->original_image, 'full'); 
  396. $imageData->preview_image_url = $this->get_image_src($data->original_image, $field['preview_size']); 
  397.  
  398. // Check if there is a cropped version and set appropriate attributes 
  399. if(is_numeric($data->cropped_image)) { 
  400. // Cropped image was saved to media library ans has an ID 
  401. $imageData->cropped_image = $data->cropped_image; 
  402. $imageData->image_url = $this->get_image_src($data->cropped_image, 'full'); 
  403. $imageData->preview_image_url = $this->get_image_src($data->cropped_image, $field['preview_size']); 
  404. elseif(is_object($data->cropped_image)) { 
  405. // Cropped image was not saved to media library and is only stored by its URL 
  406. $imageData->cropped_image = $data->cropped_image; 
  407.  
  408. // Generate appropriate URLs 
  409. $mediaDir = wp_upload_dir(); 
  410. $imageData->image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->image; 
  411. $imageData->preview_image_url = $mediaDir['baseurl'] . '/' . $data->cropped_image->preview; 
  412. return $imageData; 
  413.  
  414.  
  415. /** 
  416. * input_admin_enqueue_scripts() 
  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 render_field() action. 
  419. * @type action (admin_enqueue_scripts) 
  420. * @since 3.6 
  421. * @date 23/01/13 
  422. * @param n/a 
  423. * @return n/a 
  424. */ 
  425.  
  426.  
  427.  
  428. function input_admin_enqueue_scripts() { 
  429. $dir = plugin_dir_url( __FILE__ ); 
  430.  
  431.  
  432. // // register & include JS 
  433. // wp_register_script( 'acf-input-image_crop', "{$dir}js/input.js" ); 
  434. // wp_enqueue_script('acf-input-image_crop'); 
  435.  
  436.  
  437. // // register & include CSS 
  438. // wp_register_style( 'acf-input-image_crop', "{$dir}css/input.css" ); 
  439. // wp_enqueue_style('acf-input-image_crop'); 
  440.  
  441. // register acf scripts 
  442. //wp_register_script('acf-input-image', "{$dir}../advanced-custom-fields-pro/js/input/image.js"); 
  443. wp_register_script('acf-input-image_crop', "{$dir}js/input.js", array('acf-input', 'imgareaselect')); 
  444.  
  445. wp_register_style('acf-input-image_crop', "{$dir}css/input.css", array('acf-input')); 
  446.  
  447. // scripts 
  448. wp_enqueue_script(array( 
  449. 'acf-input-image_crop' 
  450. )); 
  451.  
  452. //wp_localize_script( 'acf-input-image_crop', 'ajax', array('nonce' => wp_create_nonce('acf_nonce')) ); 
  453.  
  454. // styles 
  455. wp_enqueue_style(array( 
  456. 'acf-input-image_crop',  
  457. 'imgareaselect' 
  458. )); 
  459.  
  460.  
  461.  
  462. function perform_crop() { 
  463. $targetWidth = $_POST['target_width']; 
  464. $targetHeight = $_POST['target_height']; 
  465.  
  466. $saveToMediaLibrary = isset($_POST['save_to_media_library']) && $_POST['save_to_media_library'] == 'yes'; 
  467. $imageData = $this->generate_cropped_image($_POST['id'], $_POST['x1'], $_POST['x2'], $_POST['y1'], $_POST['y2'], $targetWidth, $targetHeight, $saveToMediaLibrary, $_POST['preview_size']); 
  468. // $previewUrl = wp_get_attachment_image_src( $id, $_POST['preview_size']); 
  469. // $fullUrl = wp_get_attachment_image_src( $id, 'full'); 
  470. echo json_encode($imageData); 
  471. die(); 
  472.  
  473. function generate_cropped_image($id, $x1, $x2, $y1, $y2, $targetW, $targetH, $saveToMediaLibrary, $previewSize) {//$id, $x1, $x2, $y$, $y2, $targetW, $targetH) { 
  474. require_once ABSPATH . "/wp-admin/includes/file.php"; 
  475. require_once ABSPATH . "/wp-admin/includes/image.php"; 
  476.  
  477. // Create the variable that will hold the new image data 
  478. $imageData = array(); 
  479.  
  480. // Fetch media library info 
  481. $mediaDir = wp_upload_dir(); 
  482.  
  483. // Get original image info 
  484. $originalImageData = wp_get_attachment_metadata($id); 
  485.  
  486. // Get image editor from original image path to crop the image 
  487. $image = wp_get_image_editor( $mediaDir['basedir'] . '/' . $originalImageData['file'] ); 
  488.  
  489. // Set quality 
  490. $image->set_quality( apply_filters('acf-image-crop/image-quality', 100) ); 
  491.  
  492. if(! is_wp_error( $image ) ) { 
  493.  
  494. // Crop the image using the provided measurements 
  495. $image->crop($x1, $y1, $x2 - $x1, $y2 - $y1, $targetW, $targetH); 
  496.  
  497. // Retrieve original filename and seperate it from its file extension 
  498. $originalFileName = explode('.', basename($originalImageData['file'])); 
  499.  
  500. // Retrieve and remove file extension from array 
  501. $originalFileExtension = array_pop($originalFileName); 
  502.  
  503. // Generate new base filename 
  504. $targetFileName = implode('.', $originalFileName) . '_' . $targetW . 'x' . $targetH . apply_filters('acf-image-crop/filename_postfix', '_acf_cropped') . '.' . $originalFileExtension; 
  505.  
  506.  
  507. // Generate target path new file using existing media library 
  508. $targetFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], $targetFileName); 
  509.  
  510. // Get the relative path to save as the actual image url 
  511. $targetRelativePath = str_replace($mediaDir['basedir'] . '/', '', $targetFilePath); 
  512.  
  513. // Save the image to the target path 
  514. if(is_wp_error($image->save($targetFilePath))) { 
  515. // There was an error saving the image 
  516. //TODO handle it 
  517.  
  518. // If file should be saved to media library, create an attachment for it at get the new attachment ID 
  519. if($saveToMediaLibrary) { 
  520. // Generate attachment from created file 
  521.  
  522. // Get the filetype 
  523. $wp_filetype = wp_check_filetype(basename($targetFilePath), null ); 
  524. $attachment = array( 
  525. 'guid' => $mediaDir['url'] . '/' . basename($targetFilePath),  
  526. 'post_mime_type' => $wp_filetype['type'],  
  527. 'post_title' => preg_replace('/\.[^.]+$/', '', basename($targetFilePath)),  
  528. 'post_content' => '',  
  529. 'post_status' => 'inherit' 
  530. ); 
  531. $attachmentId = wp_insert_attachment( $attachment, $targetFilePath); 
  532. $attachmentData = wp_generate_attachment_metadata( $attachmentId, $targetFilePath ); 
  533. wp_update_attachment_metadata( $attachmentId, $attachmentData ); 
  534. add_post_meta($attachmentId, 'acf_is_cropped', 'true', true); 
  535.  
  536. // Add the id to the imageData-array 
  537. $imageData['value'] = $attachmentId; 
  538.  
  539. // Add the image url 
  540. $imageUrlObject = wp_get_attachment_image_src( $attachmentId, 'full'); 
  541. $imageData['url'] = $imageUrlObject[0]; 
  542.  
  543. // Add the preview url as well 
  544. $previewUrlObject = wp_get_attachment_image_src( $attachmentId, $previewSize); 
  545. $imageData['preview_url'] = $previewUrlObject[0]; 
  546. // Else we need to return the actual path of the cropped image 
  547. else{ 
  548. // Add the image url to the imageData-array 
  549. $imageData['value'] = array('image' => $targetRelativePath); 
  550. $imageData['url'] = $mediaDir['baseurl'] . '/' . $targetRelativePath; 
  551.  
  552. // Get preview size dimensions 
  553. global $_wp_additional_image_sizes; 
  554. $previewWidth = 0; 
  555. $previewHeight = 0; 
  556. $crop = 0; 
  557. if (isset($_wp_additional_image_sizes[$previewSize])) { 
  558. $previewWidth = intval($_wp_additional_image_sizes[$previewSize]['width']); 
  559. $previewHeight = intval($_wp_additional_image_sizes[$previewSize]['height']); 
  560. $crop = $_wp_additional_image_sizes[$previewSize]['crop']; 
  561. } else { 
  562. $previewWidth = get_option($previewSize.'_size_w'); 
  563. $previewHeight = get_option($previewSize.'_size_h'); 
  564. $crop = get_option($previewSize.'_crop'); 
  565.  
  566. // Generate preview file path 
  567. $previewFilePath = $mediaDir['path'] . '/' . wp_unique_filename( $mediaDir['path'], 'preview_' . $targetFileName); 
  568. $previewRelativePath = str_replace($mediaDir['basedir'] . '/', '', $previewFilePath); 
  569.  
  570. // Get image editor from cropped image 
  571. $croppedImage = wp_get_image_editor( $targetFilePath ); 
  572. $croppedImage->resize($previewWidth, $previewHeight, $crop); 
  573.  
  574. // Save the preview 
  575. $croppedImage->save($previewFilePath); 
  576.  
  577. // Add the preview url 
  578. $imageData['preview_url'] = $mediaDir['baseurl'] . '/' . $previewRelativePath; 
  579. $imageData['value']['preview'] = $previewRelativePath; 
  580. $imageData['success'] = true; 
  581. return $imageData; 
  582. else{ 
  583. // Handle WP_ERROR 
  584. $response = array(); 
  585. $response['success'] = false; 
  586. $response['error_message'] = ''; 
  587. foreach($image->error_data as $code => $message) { 
  588. $response['error_message'] .= '<p><strong>' . $code . '</strong>: ' . $message . '</p>'; 
  589. return $response; 
  590.  
  591. function get_image_src($id, $size = 'thumbnail') { 
  592. $atts = wp_get_attachment_image_src( $id, $size); 
  593. return $atts[0]; 
  594.  
  595. function getAbsoluteImageUrl($relativeUrl) { 
  596. $mediaDir = wp_upload_dir(); 
  597. return $mediaDir['baseurl'] . '/' . $relativeUrl; 
  598.  
  599. function getImagePath($relativePath) { 
  600. $mediaDir = wp_upload_dir(); 
  601. return $mediaDir['basedir'] . '/' . $relativePath; 
  602.  
  603. function filterMediaQuery($args) { 
  604. // get options 
  605. $options = get_option( 'acf_image_crop_settings' ); 
  606. $hide = ( isset($options['hide_cropped']) && $options['hide_cropped'] ); 
  607.  
  608. // If hide option is enabled, do not select items with the acf_is_cropped meta-field 
  609. if($hide) { 
  610. $args['meta_query']= array( 
  611. array( 
  612. 'key' => 'acf_is_cropped',  
  613. 'compare' => 'NOT EXISTS' 
  614. ); 
  615. return $args; 
  616.  
  617.  
  618. function registerSettings() { 
  619. add_settings_section( 
  620. 'acf_image_crop_settings',  
  621. __('ACF Image Crop Settings', 'acf-image_crop'),  
  622. array($this, 'displayImageCropSettingsSection'),  
  623. 'media' 
  624. ); 
  625.  
  626. register_setting( 
  627. 'media', // settings page 
  628. 'acf_image_crop_settings', // option name 
  629. // added 
  630. // a callback to a new function to set options to false and not to an empty string 
  631. // there was an error if you set an option, save and then unset this option and save again 
  632. // because the option value could be empty if non of the options is activated 
  633. array($this, 'validateImageCropSettingsSection') 
  634. // added END 
  635. ); 
  636.  
  637. add_settings_field( 
  638. 'acf_image_crop_hide_cropped', // id 
  639. __('Hide cropped images from media dialog', 'acf-image_crop'), // setting title 
  640. array($this, 'displayHideFromMediaInput'), // display callback 
  641. 'media', // settings page 
  642. 'acf_image_crop_settings' // settings section 
  643. ); 
  644.  
  645. add_settings_field( 
  646. 'acf_image_crop_retina_mode', // id 
  647. __('Enable global retina mode (beta)', 'acf-image_crop'), // setting title 
  648. array($this, 'displayRetinaModeInput'), // display callback 
  649. 'media', // settings page 
  650. 'acf_image_crop_settings' // settings section 
  651. ); 
  652.  
  653. function displayHideFromMediaInput() { 
  654. // Get plugin options 
  655. $options = get_option( 'acf_image_crop_settings' ); 
  656. $value = $options['hide_cropped']; 
  657.  
  658. // echo the field 
  659. ?> 
  660. <input name='acf_image_crop_settings[hide_cropped]' 
  661. type='checkbox' <?php echo $value ? 'checked' : '' ?> value='true' /> 
  662. <?php 
  663.  
  664. function displayRetinaModeInput() { 
  665. // Get plugin options 
  666. $options = get_option( 'acf_image_crop_settings' ); 
  667. $value = $options['retina_mode']; 
  668.  
  669. // echo the field 
  670. ?> 
  671. <input id="acf-image-crop-retina-mode" name='acf_image_crop_settings[retina_mode]' 
  672. type='checkbox' <?php echo $value ? 'checked' : '' ?> value='true' /> 
  673. <?php 
  674.  
  675. function displayImageCropSettingsSection() { 
  676. echo ''; 
  677.  
  678. // added 
  679. // a function that sets theoptions value to false 
  680. function validateImageCropSettingsSection($input) { 
  681. $input['hide_cropped'] = ( isset( $input['hide_cropped'] ) && $input['hide_cropped'] == true ? true : false ); 
  682. $input['retina_mode'] = ( isset( $input['retina_mode'] ) && $input['retina_mode'] == true ? true : false ); 
  683. return $input; 
  684. // added END 
  685.  
  686.  
  687.  
  688.  
  689. /** 
  690. * input_admin_head() 
  691. * This action is called in the admin_head action on the edit screen where your field is created. 
  692. * Use this action to add CSS and JavaScript to assist your render_field() action. 
  693. * @type action (admin_head) 
  694. * @since 3.6 
  695. * @date 23/01/13 
  696. * @param n/a 
  697. * @return n/a 
  698. */ 
  699.  
  700. /** 
  701.   
  702. function input_admin_head() { 
  703.   
  704.   
  705.   
  706.   
  707. */ 
  708.  
  709.  
  710.  
  711.  
  712. /** 
  713. * input_form_data() 
  714. * This function is called once on the 'input' page between the head and footer 
  715. * There are 2 situations where ACF did not load during the 'acf/input_admin_enqueue_scripts' and 
  716. * 'acf/input_admin_head' actions because ACF did not know it was going to be used. These situations are 
  717. * seen on comments / user edit forms on the front end. This function will always be called, and includes 
  718. * $args that related to the current screen such as $args['post_id'] 
  719. * @type function 
  720. * @date 6/03/2014 
  721. * @since 5.0.0 
  722. * @param $args (array) 
  723. * @return n/a 
  724. */ 
  725.  
  726. /** 
  727.   
  728. function input_form_data( $args ) { 
  729.   
  730.   
  731.   
  732.   
  733. */ 
  734.  
  735.  
  736. /** 
  737. * input_admin_footer() 
  738. * This action is called in the admin_footer action on the edit screen where your field is created. 
  739. * Use this action to add CSS and JavaScript to assist your render_field() action. 
  740. * @type action (admin_footer) 
  741. * @since 3.6 
  742. * @date 23/01/13 
  743. * @param n/a 
  744. * @return n/a 
  745. */ 
  746.  
  747. /** 
  748.   
  749. function input_admin_footer() { 
  750.   
  751.   
  752.   
  753.   
  754. */ 
  755.  
  756.  
  757. /** 
  758. * field_group_admin_enqueue_scripts() 
  759. * This action is called in the admin_enqueue_scripts action on the edit screen where your field is edited. 
  760. * Use this action to add CSS + JavaScript to assist your render_field_options() action. 
  761. * @type action (admin_enqueue_scripts) 
  762. * @since 3.6 
  763. * @date 23/01/13 
  764. * @param n/a 
  765. * @return n/a 
  766. */ 
  767.  
  768.  
  769.  
  770. function field_group_admin_enqueue_scripts() { 
  771.  
  772. $dir = plugin_dir_url( __FILE__ ); 
  773.  
  774. wp_register_script('acf-input-image-crop-options', "{$dir}js/options.js", array('jquery')); 
  775. wp_enqueue_script( 'acf-input-image-crop-options'); 
  776.  
  777. wp_register_style('acf-input-image-crop-options', "{$dir}css/options.css"); 
  778. wp_enqueue_style( 'acf-input-image-crop-options'); 
  779.  
  780.  
  781.  
  782.  
  783. /** 
  784. * field_group_admin_head() 
  785. * This action is called in the admin_head action on the edit screen where your field is edited. 
  786. * Use this action to add CSS and JavaScript to assist your render_field_options() action. 
  787. * @type action (admin_head) 
  788. * @since 3.6 
  789. * @date 23/01/13 
  790. * @param n/a 
  791. * @return n/a 
  792. */ 
  793.  
  794. /** 
  795.   
  796. function field_group_admin_head() { 
  797.   
  798.   
  799. */ 
  800.  
  801.  
  802. /** 
  803. * load_value() 
  804. * This filter is applied to the $value after it is loaded from the db 
  805. * @type filter 
  806. * @since 3.6 
  807. * @date 23/01/13 
  808. * @param $value (mixed) the value found in the database 
  809. * @param $post_id (mixed) the $post_id from which the value was loaded 
  810. * @param $field (array) the field array holding all the field options 
  811. * @return $value 
  812. */ 
  813.  
  814. /** 
  815.   
  816. function load_value( $value, $post_id, $field ) { 
  817.   
  818. return $value; 
  819.   
  820.   
  821. */ 
  822.  
  823.  
  824. /** 
  825. * update_value() 
  826. * This filter is applied to the $value before it is saved in the db 
  827. * @type filter 
  828. * @since 3.6 
  829. * @date 23/01/13 
  830. * @param $value (mixed) the value found in the database 
  831. * @param $post_id (mixed) the $post_id from which the value was loaded 
  832. * @param $field (array) the field array holding all the field options 
  833. * @return $value 
  834. */ 
  835.  
  836. /** 
  837.   
  838. function update_value( $value, $post_id, $field ) { 
  839.   
  840. return $value; 
  841.   
  842.   
  843. */ 
  844.  
  845.  
  846. /** 
  847. * format_value() 
  848. * This filter is appied to the $value after it is loaded from the db and before it is returned to the template 
  849. * @type filter 
  850. * @since 3.6 
  851. * @date 23/01/13 
  852. * @param $value (mixed) the value which was loaded from the database 
  853. * @param $post_id (mixed) the $post_id from which the value was loaded 
  854. * @param $field (array) the field array holding all the field options 
  855. * @return $value (mixed) the modified value 
  856. */ 
  857.  
  858.  
  859.  
  860. function format_value( $value, $post_id, $field ) { 
  861.  
  862. // validate 
  863. if( !$value ) { 
  864. return false; 
  865.  
  866. $data = json_decode($value); 
  867.  
  868. if(is_object($data)) { 
  869. $value = $data->cropped_image; 
  870. else{ 
  871. // We are migrating from a standard image field 
  872. $data = new stdClass(); 
  873. $data->cropped_image = $value; 
  874. $data->original_image = $value; 
  875.  
  876. // format 
  877. if( $field['save_format'] == 'url' ) 
  878. if(is_numeric($data->cropped_image)) { 
  879. $value = wp_get_attachment_url( $data->cropped_image ); 
  880. elseif(is_array($data->cropped_image)) { 
  881.  
  882. $value = $this->getAbsoluteImageUrl($data->cropped_image['image']); 
  883. elseif(is_object($data->cropped_image)) { 
  884. $value = $this->getAbsoluteImageUrl($data->cropped_image->image); 
  885.  
  886. elseif( $field['save_format'] == 'object' ) 
  887. if(is_numeric($data->cropped_image )) { 
  888. $value = $this->getImageArray($data->cropped_image); 
  889. $value['original_image'] = $this->getImageArray($data->original_image); 
  890. // $attachment = get_post( $data->cropped_image ); 
  891. // // validate 
  892. // if( !$attachment ) 
  893. // { 
  894. // return false; 
  895. // } 
  896.  
  897.  
  898. // // create array to hold value data 
  899. // $src = wp_get_attachment_image_src( $attachment->ID, 'full' ); 
  900.  
  901. // $value = array( 
  902. // 'id' => $attachment->ID,  
  903. // 'alt' => get_post_meta($attachment->ID, '_wp_attachment_image_alt', true),  
  904. // 'title' => $attachment->post_title,  
  905. // 'caption' => $attachment->post_excerpt,  
  906. // 'description' => $attachment->post_content,  
  907. // 'mime_type' => $attachment->post_mime_type,  
  908. // 'url' => $src[0],  
  909. // 'width' => $src[1],  
  910. // 'height' => $src[2],  
  911. // 'sizes' => array(),  
  912. // ); 
  913.  
  914.  
  915. // // find all image sizes 
  916. // $image_sizes = get_intermediate_image_sizes(); 
  917.  
  918. // if( $image_sizes ) 
  919. // { 
  920. // foreach( $image_sizes as $image_size ) 
  921. // { 
  922. // // find src 
  923. // $src = wp_get_attachment_image_src( $attachment->ID, $image_size ); 
  924.  
  925. // // add src 
  926. // $value[ 'sizes' ][ $image_size ] = $src[0]; 
  927. // $value[ 'sizes' ][ $image_size . '-width' ] = $src[1]; 
  928. // $value[ 'sizes' ][ $image_size . '-height' ] = $src[2]; 
  929. // } 
  930. // // foreach( $image_sizes as $image_size ) 
  931. // } 
  932. elseif(is_array( $data->cropped_image) || is_object($data->cropped_image)) { 
  933. // Cropped image is not saved to media directory. Get data from original image instead 
  934. $value = $this->getImageArray($data->original_image); 
  935.  
  936. // Get the relative url from data 
  937. $relativeUrl = ''; 
  938. if(is_array( $data->cropped_image)) { 
  939. $relativeUrl = $data->cropped_image['image']; 
  940. else{ 
  941. $relativeUrl = $data->cropped_image->image; 
  942.  
  943. // Replace URL with cropped version 
  944. $value['url'] = $this->getAbsoluteImageUrl($relativeUrl); 
  945.  
  946. // Calculate and replace sizes 
  947. $imagePath = $this->getImagePath($relativeUrl); 
  948. $dimensions = getimagesize($imagePath); 
  949. $value['width'] = $dimensions[0]; 
  950. $value['height'] = $dimensions[1]; 
  951.  
  952. // Add original image info 
  953. $value['original_image'] = $this->getImageArray($data->original_image); 
  954. // elseif(is_object($data->cropped_image)) { 
  955. // $value = $this->getImageArray($data->original_image); 
  956. // $value['url'] = $this->getAbsoluteImageUrl($data->cropped_image->image); 
  957.  
  958. // // Calculate sizes 
  959. // $imagePath = $this->getImagePath($data->cropped_image->image); 
  960. // $dimensions = getimagesize($imagePath); 
  961. // $value['width'] = $dimensions[0]; 
  962. // $value['height'] = $dimensions[1]; 
  963.  
  964. // // Add original image info 
  965. // $value['original_image'] = $this->getImageArray($data->original_image); 
  966. // } 
  967. else{ 
  968. //echo 'ELSE'; 
  969.  
  970. return $value; 
  971.  
  972.  
  973. function getOption($key) { 
  974. return isset($this->options[$key]) ? $this->options[$key] : null; 
  975.  
  976. function getImageArray($id) { 
  977. $attachment = get_post( $id ); 
  978. // validate 
  979. if( !$attachment ) 
  980. return false; 
  981.  
  982.  
  983. // create array to hold value data 
  984. $src = wp_get_attachment_image_src( $attachment->ID, 'full' ); 
  985.  
  986. $imageArray = array( 
  987. 'id' => $attachment->ID,  
  988. 'alt' => get_post_meta($attachment->ID, '_wp_attachment_image_alt', true),  
  989. 'title' => $attachment->post_title,  
  990. 'caption' => $attachment->post_excerpt,  
  991. 'description' => $attachment->post_content,  
  992. 'mime_type' => $attachment->post_mime_type,  
  993. 'url' => $src[0],  
  994. 'width' => $src[1],  
  995. 'height' => $src[2],  
  996. 'sizes' => array(),  
  997. ); 
  998.  
  999.  
  1000. // find all image sizes 
  1001. $image_sizes = get_intermediate_image_sizes(); 
  1002.  
  1003. if( $image_sizes ) 
  1004. foreach( $image_sizes as $image_size ) 
  1005. // find src 
  1006. $src = wp_get_attachment_image_src( $attachment->ID, $image_size ); 
  1007.  
  1008. // add src 
  1009. $imageArray[ 'sizes' ][ $image_size ] = $src[0]; 
  1010. $imageArray[ 'sizes' ][ $image_size . '-width' ] = $src[1]; 
  1011. $imageArray[ 'sizes' ][ $image_size . '-height' ] = $src[2]; 
  1012. return $imageArray; 
  1013.  
  1014.  
  1015.  
  1016. /** 
  1017. * validate_value() 
  1018. * This filter is used to perform validation on the value prior to saving. 
  1019. * All values are validated regardless of the field's required setting. This allows you to validate and return 
  1020. * messages to the user if the value is not correct 
  1021. * @type filter 
  1022. * @date 11/02/2014 
  1023. * @since 5.0.0 
  1024. * @param $valid (boolean) validation status based on the value and the field's required setting 
  1025. * @param $value (mixed) the $_POST value 
  1026. * @param $field (array) the field array holding all the field options 
  1027. * @param $input (string) the corresponding input name for $_POST value 
  1028. * @return $valid 
  1029. */ 
  1030.  
  1031. /** 
  1032.   
  1033. function validate_value( $valid, $value, $field, $input ) { 
  1034.   
  1035. // Basic usage 
  1036. if( $value < $field['custom_minimum_setting'] ) 
  1037. $valid = false; 
  1038.   
  1039.   
  1040. // Advanced usage 
  1041. if( $value < $field['custom_minimum_setting'] ) 
  1042. $valid = __('The value is too little!', 'acf-image_crop'),  
  1043.   
  1044.   
  1045. // return 
  1046. return $valid; 
  1047.   
  1048.   
  1049. */ 
  1050.  
  1051.  
  1052. /** 
  1053. * delete_value() 
  1054. * This action is fired after a value has been deleted from the db. 
  1055. * Please note that saving a blank value is treated as an update, not a delete 
  1056. * @type action 
  1057. * @date 6/03/2014 
  1058. * @since 5.0.0 
  1059. * @param $post_id (mixed) the $post_id from which the value was deleted 
  1060. * @param $key (string) the $meta_key which the value was deleted 
  1061. * @return n/a 
  1062. */ 
  1063.  
  1064. /** 
  1065.   
  1066. function delete_value( $post_id, $key ) { 
  1067.   
  1068.   
  1069.   
  1070.   
  1071. */ 
  1072.  
  1073.  
  1074. /** 
  1075. * load_field() 
  1076. * This filter is applied to the $field after it is loaded from the database 
  1077. * @type filter 
  1078. * @date 23/01/2013 
  1079. * @since 3.6.0 
  1080. * @param $field (array) the field array holding all the field options 
  1081. * @return $field 
  1082. */ 
  1083.  
  1084. /** 
  1085.   
  1086. function load_field( $field ) { 
  1087.   
  1088. return $field; 
  1089.   
  1090.   
  1091. */ 
  1092.  
  1093.  
  1094. /** 
  1095. * update_field() 
  1096. * This filter is applied to the $field before it is saved to the database 
  1097. * @type filter 
  1098. * @date 23/01/2013 
  1099. * @since 3.6.0 
  1100. * @param $field (array) the field array holding all the field options 
  1101. * @return $field 
  1102. */ 
  1103.  
  1104. /** 
  1105.   
  1106. function update_field( $field ) { 
  1107.   
  1108. return $field; 
  1109.   
  1110.   
  1111. */ 
  1112.  
  1113.  
  1114. /** 
  1115. * delete_field() 
  1116. * This action is fired after a field is deleted from the database 
  1117. * @type action 
  1118. * @date 11/02/2014 
  1119. * @since 5.0.0 
  1120. * @param $field (array) the field array holding all the field options 
  1121. * @return n/a 
  1122. */ 
  1123.  
  1124. /** 
  1125.   
  1126. function delete_field( $field ) { 
  1127.   
  1128.   
  1129.   
  1130.   
  1131. */ 
  1132.  
  1133.