settings = [ 'version' => get_plugin_data(__FILE__)['Version'], 'url' => plugin_dir_url(__FILE__), 'path' => plugin_dir_path(__FILE__), ]; $this->temp_path = null; // set text domain // https://codex.wordpress.org/Function_Reference/load_plugin_textdomain load_plugin_textdomain('acf-image-aspect-ratio-crop'); add_action('plugins_loaded', [$this, 'initialize_settings']); // include field add_action('acf/include_field_types', [$this, 'include_field_types']); // v5 add_action('rest_api_init', [$this, 'rest_api_init']); add_action( 'acf/save_post', function ($post_id) { if ($post_id === 'options' && !empty($_GET['page'])) { // Options page needs an unique id $post_id = $_GET['page']; } $temp_post_id = $_POST['aiarc_temp_post_id']; // Bail early if we don't have data to process if (empty($temp_post_id)) { return; } // Let's find all posts with temp post id $temp_attachments = get_posts([ 'post_type' => 'attachment', 'posts_per_page' => -1, 'meta_query' => [ [ 'key' => 'acf_image_aspect_ratio_crop_temp_post_id', 'value' => $temp_post_id, 'compare' => '=', ], ], ]); foreach ($temp_attachments as $attachment) { // Attach parent post id to temporary attachments update_post_meta( $attachment->ID, 'acf_image_aspect_ratio_crop_parent_post_id', $post_id ); // Remove temporary data delete_post_meta( $attachment->ID, 'acf_image_aspect_ratio_crop_temp_post_id' ); delete_post_meta( $attachment->ID, 'acf_image_aspect_ratio_crop_timestamp' ); } // Bail early if unused attachment deletion is disabled if (!$this->user_settings['delete_unused']) { return; } $post_attachments = get_posts([ 'post_type' => 'attachment', 'posts_per_page' => -1, 'meta_query' => [ [ 'key' => 'acf_image_aspect_ratio_crop_parent_post_id', 'value' => $post_id, 'compare' => '=', ], ], ]); // Find crop field names // Compare crop field names to post input // Delete unused posts $current_post = get_post($post_id); if (function_exists('parse_blocks') && $current_post) { $this->debug('parse blocks'); $blocks = parse_blocks($current_post->post_content); $this->debug($blocks); } $this->debug('found following post attachments'); $this->debug($post_attachments); $this->debug('found following fields'); $fields = $_POST['acf']; $this->debug($fields); $preserve_ids = []; $this->check_fields($fields, $preserve_ids); $post_attachment_ids = array_map(function ($attachment) { return $attachment->ID; }, $post_attachments); $delete_ids = array_diff($post_attachment_ids, $preserve_ids); $this->debug('preserve ids'); $this->debug($preserve_ids); $this->debug('all ids'); $this->debug($post_attachment_ids); $this->debug('delete ids'); $this->debug($delete_ids); foreach ($delete_ids as $delete_id) { wp_delete_attachment($delete_id, true); } }, 15 ); add_action('wp_ajax_acf_image_aspect_ratio_crop_crop', function () { // WTF WordPress $post = array_map('stripslashes_deep', $_POST); $data = json_decode($post['data'], true); $attachment_id = $this->create_crop($data); wp_send_json(['id' => $attachment_id]); wp_die(); }); // Old WPML 4.2.9 compat add_action( 'wpml_media_create_duplicate_attachment', [$this, 'wpml_copy_fields_old'], 25, 2 ); // New 4.3.19, 4.4.3 WPML compat add_action( 'wpml_after_update_attachment_texts', [$this, 'wpml_copy_fields_new'], 25, 2 ); // Enable Media Replace compat: if file is replaced using Enable Media Replace, wipe the coordinate data add_filter('wp_handle_upload', function ($data) { $id = attachment_url_to_postid($data['url']); if ($id !== 0) { $posts = get_posts([ 'post_type' => 'attachment', 'posts_per_page' => -1, 'meta_query' => [ [ 'key' => 'acf_image_aspect_ratio_crop_original_image_id', 'value' => $id, 'compare' => '=', ], [ 'key' => 'acf_image_aspect_ratio_crop_coordinates', 'compare' => 'EXISTS', ], ], ]); if (!empty($posts)) { foreach ($posts as $post) { delete_post_meta( $post->ID, 'acf_image_aspect_ratio_crop_coordinates' ); } } } return $data; }); // Hide cropped images in media library grid view add_filter('ajax_query_attachments_args', function ($args) { // post__in is only defined when clicking edit button in attachment if (empty($args['post__in'])) { $args['meta_query'] = [ [ 'key' => 'acf_image_aspect_ratio_crop', 'compare' => 'NOT EXISTS', ], ]; } return $args; }); // Add plugin to WordPress admin menu add_action('admin_menu', function () { add_submenu_page( null, __( 'ACF Image Aspect Ratio Crop', 'acf-image-aspect-ratio-crop' ), __( 'ACF Image Aspect Ratio Crop', 'acf-image-aspect-ratio-crop' ), 'manage_options', 'acf-image-aspect-ratio-crop', [$this, 'settings_page'] ); }); // Add settings link on the plugin page add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), function ($links) { $settings_link = '' . __('Settings', 'acf-image-aspect-ratio-crop') . ''; array_unshift($links, $settings_link); return $links; } ); // Donate link add_filter( 'plugin_row_meta', function ($links, $file) { if ($file === plugin_basename(__FILE__)) { array_push( $links, '' . esc_html__( 'Support development on GitHub Sponsors', 'acf-image-aspect-ratio-crop' ) . '' ); } return $links; }, 10, 2 ); if (!wp_next_scheduled('aiarc_delete_unused_attachments')) { wp_schedule_event( time(), 'daily', 'aiarc_delete_unused_attachments' ); } add_action('aiarc_delete_unused_attachments', [ $this, 'delete_unused_attachments', ]); add_filter('wpgraphql_acf_supported_fields', function ( $supported_fields ) { array_push($supported_fields, 'image_aspect_ratio_crop'); return $supported_fields; }); add_filter( 'wpgraphql_acf_register_graphql_field', function ($field_config, $type_name, $field_name, $config) { // How to add new WPGraphQL fields is super undocumented, I used this code as a base // https://github.com/wp-graphql/wp-graphql/issues/214#issuecomment-653141685 $acf_field = isset($config['acf_field']) ? $config['acf_field'] : null; $acf_type = isset($acf_field['type']) ? $acf_field['type'] : null; $resolve = $field_config['resolve']; if ($acf_type == 'image_aspect_ratio_crop') { $field_config = [ 'type' => 'MediaItem', 'resolve' => function ( $root, $args, $context, $info ) use ($resolve) { $value = $resolve($root, $args, $context, $info); return WPGraphQL\Data\DataSource::resolve_post_object( (int) $value, $context ); }, ]; } return $field_config; }, 10, 4 ); add_filter( 'pll_translate_post_meta', [$this, 'translate_post_meta_polylang'], 10, 5 ); add_filter( 'wpml_duplicate_generic_string', [$this, 'translate_post_meta_wpml'], 10, 3 ); } /* * include_field_types * * This function will include the field type class * * @type function * @date 17/02/2016 * @since 1.0.0 * * @param $version (int) major ACF version. Defaults to false * @return n/a */ function include_field_types() { // include include_once 'fields/class-npx-acf-field-image-aspect-ratio-crop-v5.php'; } /** * Render WordPress plugin settings page */ public function settings_page() { $updated = false; $settings = $this->user_settings; if (!empty($_POST)) { check_admin_referer('acf-image-aspect-ratio-crop'); if (!empty($_POST['modal_type'])) { $settings['modal_type'] = $_POST['modal_type']; } if (!empty($_POST['delete_unused'])) { $settings['delete_unused'] = filter_var( $_POST['delete_unused'], FILTER_VALIDATE_BOOLEAN ); } update_option('acf-image-aspect-ratio-crop-settings', $settings); $updated = true; } $modal_type = $settings['modal_type']; $delete_unused = $settings['delete_unused']; echo '
'; echo '

' . __('ACF Image Aspect Ratio Crop', 'acf-image-aspect-ratio-crop') . '

'; echo '
'; if ($updated) { echo '
'; echo '

' . __('Options have been updated', 'acf-image-aspect-ratio-crop') . '

'; echo '
'; } echo '
'; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo '
'; echo ''; echo ''; echo '

'; echo '

'; echo '
'; echo ''; echo ''; echo '

'; echo '

'; echo '
'; echo '

' . __( 'Please note that "Delete unused cropped images" feature is a beta feature because it requires more testing. Please do not enable the option without first backing up your database and uploads in order to prevent potential data loss.', 'acf-image-aspect-ratio-crop' ) . '

'; echo '

'; echo ''; echo '

'; wp_nonce_field('acf-image-aspect-ratio-crop'); echo '
'; echo '
'; } function initialize_settings() { $database_version = get_option('acf-image-aspect-ratio-crop-version'); $plugin_version = $this->settings['version']; $settings = get_option('acf-image-aspect-ratio-crop-settings') ? get_option('acf-image-aspect-ratio-crop-settings') : []; // Initialize database settings if (empty($database_version)) { update_option( 'acf-image-aspect-ratio-crop-version', $plugin_version ); } if ( version_compare( get_option('acf-image-aspect-ratio-crop-version'), $plugin_version, 'lt' ) ) { // Database migrations here update_option( 'acf-image-aspect-ratio-crop-version', $plugin_version ); } $default_user_settings = [ 'modal_type' => 'cropped', 'delete_unused' => false, ]; $this->user_settings = array_merge($default_user_settings, $settings); $this->settings['user_settings'] = $this->user_settings; } /** * Clean up any temporary files */ private function cleanup() { if ($this->temp_path) { @unlink($this->temp_path); } } public function delete_unused_attachments() { $this->debug('delete unused attachments cron'); // Bail early if unused attachment deletion is disabled if (!$this->user_settings['delete_unused']) { $this->debug('user has disabled unused attachment deletion'); return; } $timestamp = (new DateTime())->modify('-7 days')->format('U'); $posts = get_posts([ 'post_type' => 'attachment', 'meta_query' => [ [ 'key' => 'acf_image_aspect_ratio_crop_timestamp', 'compare' => '<', 'value' => $timestamp, 'type' => 'numeric', ], ], ]); foreach ($posts as $post) { $this->debug('deleting unused attachment ' . $post->ID); wp_delete_attachment($post->ID, true); } } function debug($message) { if (defined('WP_DEBUG') && WP_DEBUG === true) { error_log(print_r($message, true)); } } private function crop(WP_Image_Editor $image, $data) { $image->crop($data['x'], $data['y'], $data['width'], $data['height']); } public function check_fields($fields, &$preserve_ids) { $this->debug($preserve_ids); foreach ($fields as $key => $field) { if (is_array($field)) { $this->check_fields($field, $preserve_ids); } // This is kinda of a hack but nested fields are named like field_59416ac78945f_field_59217cf6eb710 in the // POST request and we are only interested in the last part so we just use a regex here to chop off the // last part preg_match_all('/field_[a-z0-9]+/', $key, $matches); if (!empty($matches[0])) { $last = array_values(array_slice($matches[0], -1))[0]; $definition = get_field_object($last); if ( !empty($field) && !empty($definition) && $definition['type'] === 'image_aspect_ratio_crop' ) { array_push($preserve_ids, $field); } } } } public function jpeg_quality($jpeg_quality) { return apply_filters('aiarc_jpeg_quality', $jpeg_quality); } public function translate_post_meta_polylang( $value, $key, $lang, $from, $to ) { // When creating translated duplicated attachment if there is a translated version of // the original image, use it if (get_post_type($from) === 'attachment') { if ($key === 'acf_image_aspect_ratio_crop_original_image_id') { return pll_get_post($value, $lang) ? pll_get_post($value, $lang) : $value; } } // When creating translated copy of any post if there is a translated version of the // cropped image, use it if (get_post_type($from) !== 'attachment') { $original_field = get_field_object($key, $from); if ( $value && $original_field && $original_field['type'] && $original_field['type'] === 'image_aspect_ratio_crop' ) { $translated_value = pll_get_post($value, $lang); if ($translated_value) { return $translated_value; } } } return $value; } public function translate_post_meta_wpml($value, $lang, $meta_data) { if ($meta_data['context'] !== 'custom_field') { return $value; } $key = $meta_data['key']; $to = $meta_data['post_id']; $from = $meta_data['master_post_id']; // When creating translated copy of any post if there is a translated version of the // cropped image, use it if (get_post_type($from) !== 'attachment') { $original_field = get_field_object($key, $from); if ( $value && $original_field && $original_field['type'] && $original_field['type'] === 'image_aspect_ratio_crop' ) { $translated_value = apply_filters( 'wpml_object_id', $value, 'attachment', false, $lang ); if ($translated_value) { return $translated_value; } } } return $value; } public function wpml_copy_fields_old( $attachment_id, $duplicate_attachment_id ) { $this->wpml_copy_fields($attachment_id, $duplicate_attachment_id); } public function wpml_copy_fields_new($attachment_id, $duplicate_attachment) { $duplicate_attachment_id = $duplicate_attachment->element_id; $this->wpml_copy_fields($attachment_id, $duplicate_attachment_id); } public function wpml_copy_fields($attachment_id, $duplicate_attachment_id) { $keys = [ 'acf_image_aspect_ratio_crop', 'acf_image_aspect_ratio_crop_original_image_id', 'acf_image_aspect_ratio_crop_coordinates', ]; foreach ($keys as $key) { $value = get_post_meta($attachment_id, $key, true); if ($value) { update_post_meta($duplicate_attachment_id, $key, $value); } } } public function rest_api_init() { register_rest_route('aiarc/v1', '/upload', [ 'methods' => 'POST', 'callback' => [$this, 'rest_api_upload_callback'], 'permission_callback' => function () { return true; }, ]); register_rest_route('aiarc/v1', '/crop', [ 'methods' => 'POST', 'callback' => [$this, 'rest_api_crop_callback'], 'permission_callback' => function () { return true; }, ]); register_rest_route('aiarc/v1', '/get/(?P\d+)', [ 'methods' => 'GET', 'callback' => [$this, 'rest_api_get_callback'], 'args' => ['id'], 'permission_callback' => function () { return true; }, ]); } public function rest_api_get_callback(WP_REST_Request $data) { // TODO: validate nonce $attachment_id = $data->get_param('id'); $attachment = get_post($attachment_id); if (!$attachment) { wp_send_json_error( new WP_Error( 'attachment_not_found', __('Attachment not found', 'acf-image-aspect-ratio-crop') ), 404 ); } $attachment = wp_prepare_attachment_for_js($attachment); return new WP_REST_Response($attachment); } public function rest_api_crop_callback(WP_REST_Request $data) { $this->rest_api_check_nonce($data); $parameters = $data->get_json_params(); $attachment_id = $this->create_crop($parameters); return [ 'id' => $attachment_id, ]; } public function rest_api_upload_callback(WP_REST_Request $data) { $this->rest_api_check_nonce($data); if (empty($data->get_file_params()['image'])) { return new WP_Error( 'image_field_missing', __('Image field missing.', 'acf-image-aspect-ratio-crop') ); } if (empty($data->get_param('key'))) { return new WP_Error( 'key_field_missing', __('Key field missing.', 'acf-image-aspect-ratio-crop') ); } $key = $data->get_param('key'); $field_object = get_field_object($key); $mime_types = $field_object['mime_types']; $min_size = $field_object['min_size']; $max_size = $field_object['max_size']; $min_width = $field_object['min_width']; $max_width = $field_object['max_width']; $min_height = $field_object['min_height']; $max_height = $field_object['max_height']; // MIME validation $file_mime = mime_content_type( $data->get_file_params()['image']['tmp_name'] ); $allowed_mime_types = $this->extension_list_to_mime_array($mime_types); if (!in_array($file_mime, $allowed_mime_types)) { return new WP_Error( 'invalid_mime_type', __('Invalid file type.', 'acf-image-aspect-ratio-crop') ); } // File size validation if ( !empty($max_size) && $data->get_file_params()['image']['size'] > $max_size * 1000000 ) { return new WP_Error( 'file_too_large', __( sprintf( __( 'File size too large. Maximum file size is %d megabytes.', 'acf-image-aspect-ratio-crop' ), $max_size ), 'acf-image-aspect-ratio-crop' ) ); } if ( !empty($min_size) && $data->get_file_params()['image']['size'] < $min_size * 1000000 ) { return new WP_Error( 'file_too_small', __( sprintf( __( 'File size too small. Minimum file size is %d megabytes.', 'acf-image-aspect-ratio-crop' ), $min_size ), 'acf-image-aspect-ratio-crop' ) ); } // Image size validation $image_size = @getimagesize( $data->get_file_params()['image']['tmp_name'] ); if (!$image_size) { return new WP_Error( 'failed_to_parse_image', __('Failed to parse image.', 'acf-image-aspect-ratio-crop') ); } $image_width = $image_size[0]; $image_height = $image_size[1]; if ( !empty($min_width) && !empty($min_height) && ($image_width < $min_width || $image_height < $min_height) ) { return new WP_Error( 'image_too_small', __( sprintf( __( 'Image too small. Minimum image dimensions are %d×%d pixels.', 'acf-image-aspect-ratio-crop' ), $min_width, $min_height ), 'acf-image-aspect-ratio-crop' ) ); } if ( !empty($max_width) && !empty($max_height) && ($image_width > $max_width || $image_height > $max_height) ) { return new WP_Error( 'image_too_large', __( sprintf( __( 'Image too large. Maximum image dimensions are %d×%d pixels.', 'acf-image-aspect-ratio-crop' ), $max_width, $max_height ), 'acf-image-aspect-ratio-crop' ) ); } $upload = wp_upload_bits( $data->get_file_params()['image']['name'], null, file_get_contents($data->get_file_params()['image']['tmp_name']) ); $wp_filetype = wp_check_filetype(basename($upload['file']), null); $wp_upload_dir = wp_upload_dir(); $attachment = [ 'post_mime_type' => $wp_filetype['type'], 'post_title' => preg_replace( '/\.[^.]+$/', '', basename($upload['file']) ), 'post_content' => '', 'post_status' => 'inherit', ]; $attachment_id = wp_insert_attachment($attachment, $upload['file']); require_once ABSPATH . 'wp-admin/includes/image.php'; $attachment_data = wp_generate_attachment_metadata( $attachment_id, $upload['file'] ); wp_update_attachment_metadata($attachment_id, $attachment_data); return new WP_REST_Response(['attachment_id' => $attachment_id]); } /** * @param $data * @return array */ public function create_crop($data) { $image_data = apply_filters( 'aiarc_image_data', wp_get_attachment_metadata($data['id']), $data['id'] ); // If the difference between the images is less than half a percentage, use the original image // prettier-ignore if ($image_data['height'] - $data['height'] < $image_data['height'] * 0.005 && $image_data['width'] - $data['width'] < $image_data['width'] * 0.005 && $data['cropType'] !== 'pixel_size' ) { wp_send_json(['id' => $data['id']]); wp_die(); } do_action('aiarc_pre_customize_upload_dir'); $media_dir = apply_filters( 'aiarc_upload_dir', wp_upload_dir(), $data['id'] ); do_action('aiarc_after_customize_upload_dir'); // WP Smush compat: use original image if it exists $file = $media_dir['basedir'] . '/' . $image_data['file']; $parts = explode('.', $file); $extension = array_pop($parts); $backup_file = implode('.', $parts) . '.bak.' . $extension; add_filter('jpeg_quality', [$this, 'jpeg_quality']); $image = null; $scaled_data = null; if ( file_exists($file) && function_exists('wp_get_original_image_path') && wp_get_original_image_path($data['id']) && wp_get_original_image_path($data['id']) !== $file && file_exists(wp_get_original_image_path($data['id'])) ) { // Handle the new asinine feature in WP 5.3 which resizes images without asking the user. We want the // original image so we do "original_image -> crop" instead of "original_image -> resized_image -> crop" $resized_image = wp_get_image_editor($file); $image = wp_get_image_editor( wp_get_original_image_path($data['id']) ); // Handle case with EXIF rotation where image size exceeds big_image_size_threshold // so the scaled image is rotated but original is not. Rotate original before // calculating co-ordinates and performing crop. // https://wordpress.org/support/topic/srgb-image-turned-into-1x1-white-image/ if (method_exists($image, 'maybe_exif_rotate')) { $image->maybe_exif_rotate(); } $resized_width = $resized_image->get_size()['width']; $original_width = $image->get_size()['width']; // Get the scale $scale = $original_width / $resized_width; // Clone data array $scaled_data = $data; // Scale crop coordinates to fit larger image $scaled_data['x'] = floor($data['x'] * $scale); $scaled_data['y'] = floor($data['y'] * $scale); $scaled_data['width'] = floor($data['width'] * $scale); $scaled_data['height'] = floor($data['height'] * $scale); } elseif (file_exists($backup_file)) { $image = wp_get_image_editor($backup_file); } elseif (file_exists($file)) { $image = wp_get_image_editor($file); } else { // Let's attempt to get the file by URL $temp_name = wp_generate_uuid4(); $temp_directory = get_temp_dir(); $this->temp_path = $temp_directory . $temp_name; try { $url = wp_get_attachment_url($data['id']); $url = apply_filters('aiarc_request_url', $url, $data['id']); $request_options = [ 'stream' => true, 'filename' => $this->temp_path, 'timeout' => 25, ]; $result = wp_remote_get($url, $request_options); if (is_wp_error($result)) { throw new Exception('Failed to save image'); } $image = wp_get_image_editor($this->temp_path); } catch (Exception $exception) { $this->cleanup(); wp_send_json('Failed fetch remote image', 500); wp_die(); } } if (is_wp_error($image)) { $this->cleanup(); $this->debug($image); wp_send_json('Failed to open image', 500); wp_die(); } // Use scaled coordinates if we have those $this->crop($image, $scaled_data ? $scaled_data : $data); if ($data['cropType'] === 'pixel_size') { $image->resize( $data['aspectRatioWidth'], $data['aspectRatioHeight'], true ); } // Retrieve original filename and seperate it from its file extension $original_file_name = explode('.', basename($image_data['file'])); // Retrieve and remove file extension from array $original_file_extension = array_pop($original_file_name); $width = $data['aspectRatioWidth']; $height = $data['aspectRatioHeight']; if ($data['cropType'] === 'free_crop') { $width = $data['width']; $height = $data['height']; } // Generate new base filename $target_file_name = implode('.', $original_file_name) . '-aspect-ratio-' . $width . '-' . $height . '.' . $original_file_extension; // Generate target path new file using existing media library $target_file_path = $media_dir['path'] . '/' . wp_unique_filename($media_dir['path'], $target_file_name); // Get the relative path to save as the actual image url $target_relative_path = str_replace( $media_dir['basedir'] . '/', '', $target_file_path ); $save = $image->save($target_file_path); remove_filter('jpeg_quality', [$this, 'jpeg_quality']); if (is_wp_error($save)) { $this->cleanup(); wp_send_json('Failed to crop', 500); wp_die(); } $wp_filetype = wp_check_filetype($target_relative_path, null); $attachment = [ 'post_mime_type' => $wp_filetype['type'], 'post_title' => preg_replace('/\.[^.]+$/', '', $target_file_name), 'post_content' => '', 'post_status' => 'publish', ]; $attachment_id = wp_insert_attachment( $attachment, $target_relative_path ); if (is_wp_error($attachment_id)) { $this->cleanup(); wp_send_json('Failed to save attachment', 500); wp_die(); } add_post_meta( $attachment_id, 'acf_image_aspect_ratio_crop', true, true ); add_post_meta( $attachment_id, 'acf_image_aspect_ratio_crop_original_image_id', $data['id'], true ); add_post_meta( $attachment_id, 'acf_image_aspect_ratio_crop_coordinates', [ 'x' => $data['x'], 'y' => $data['y'], 'width' => $data['width'], 'height' => $data['height'], ], true ); /* Timestamp so we can purge unattached crop attachments periodically after specific time (like a week or so) */ add_post_meta( $attachment_id, 'acf_image_aspect_ratio_crop_timestamp', (new DateTime())->format('U'), true ); add_post_meta( $attachment_id, 'acf_image_aspect_ratio_crop_temp_post_id', $data['temp_post_id'], true ); require_once ABSPATH . 'wp-admin' . '/includes/image.php'; $attachment_data = wp_generate_attachment_metadata( $attachment_id, $target_file_path ); wp_update_attachment_metadata($attachment_id, $attachment_data); // WPML compat do_action('wpml_sync_all_custom_fields', $attachment_id); $this->cleanup(); return $attachment_id; } /** * @param WP_REST_Request $data */ public function rest_api_check_nonce(WP_REST_Request $data) { $nonce = $data->get_header('X-Aiarc-Nonce'); if (empty($nonce)) { wp_send_json_error( new WP_Error( 'nonce_missing', __('Nonce missing.', 'acf-image-aspect-ratio-crop') ), 400 ); } if (!wp_verify_nonce($nonce, 'aiarc')) { wp_send_json_error( new WP_Error( 'invalid_nonce', __('Invalid nonce.', 'acf-image-aspect-ratio-crop') ), 400 ); } } /** * @param $mime_types * @return array */ public static function extension_list_to_mime_array($mime_types) { $extension_array = explode(',', $mime_types); $extension_array = array_map(function ($extension) { return trim($extension); }, $extension_array); $allowed_mime_types = []; foreach ($extension_array as $extension) { if ($extension === 'jpeg' || $extension === 'jpg') { array_push($allowed_mime_types, 'image/jpeg'); } if ($extension === 'png') { array_push($allowed_mime_types, 'image/png'); } if ($extension === 'gif') { array_push($allowed_mime_types, 'image/gif'); } } $allowed_mime_types = array_unique($allowed_mime_types); return $allowed_mime_types; } } // initialize new npx_acf_plugin_image_aspect_ratio_crop();