|
@@ -0,0 +1,391 @@
|
|
|
|
|
+<?php
|
|
|
|
|
+if (!defined('WPINC')) {
|
|
|
|
|
+ die;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class Studiou_WC_FPP_Upload {
|
|
|
|
|
+
|
|
|
|
|
+ /** @var Studiou_WC_FPP_DB */
|
|
|
|
|
+ private $db;
|
|
|
|
|
+
|
|
|
|
|
+ public function __construct($db) {
|
|
|
|
|
+ $this->db = $db;
|
|
|
|
|
+ add_action('wp_ajax_studiou_wcfpp_upload_chunk', array($this, 'handle_chunk_upload'));
|
|
|
|
|
+ add_action('wp_ajax_nopriv_studiou_wcfpp_upload_chunk', array($this, 'handle_chunk_upload'));
|
|
|
|
|
+ add_action('wp_ajax_studiou_wcfpp_remove_upload', array($this, 'handle_remove_upload'));
|
|
|
|
|
+ add_action('wp_ajax_nopriv_studiou_wcfpp_remove_upload', array($this, 'handle_remove_upload'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function get_chunks_dir() {
|
|
|
|
|
+ $upload_dir = wp_upload_dir();
|
|
|
|
|
+ return $upload_dir['basedir'] . '/studiou-fpp-chunks';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function get_allowed_mime_types() {
|
|
|
|
|
+ return array(
|
|
|
|
|
+ 'jpg|jpeg|jpe' => 'image/jpeg',
|
|
|
|
|
+ 'png' => 'image/png',
|
|
|
|
|
+ 'tiff|tif' => 'image/tiff',
|
|
|
|
|
+ 'bmp' => 'image/bmp',
|
|
|
|
|
+ 'psd' => 'image/vnd.adobe.photoshop',
|
|
|
|
|
+ 'cr2' => 'image/x-canon-cr2',
|
|
|
|
|
+ 'nef' => 'image/x-nikon-nef',
|
|
|
|
|
+ 'arw' => 'image/x-sony-arw',
|
|
|
|
|
+ 'dng' => 'image/x-adobe-dng',
|
|
|
|
|
+ 'orf' => 'image/x-olympus-orf',
|
|
|
|
|
+ 'rw2' => 'image/x-panasonic-rw2',
|
|
|
|
|
+ 'raf' => 'image/x-fuji-raf',
|
|
|
|
|
+ 'webp' => 'image/webp',
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function handle_chunk_upload() {
|
|
|
|
|
+ // Clean output buffers
|
|
|
|
|
+ while (ob_get_level()) {
|
|
|
|
|
+ ob_end_clean();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ check_ajax_referer('studiou-wcfpp-front-nonce', 'nonce');
|
|
|
|
|
+
|
|
|
|
|
+ $product_id = isset($_POST['product_id']) ? absint($_POST['product_id']) : 0;
|
|
|
|
|
+ $upload_id = isset($_POST['upload_id']) ? sanitize_text_field($_POST['upload_id']) : '';
|
|
|
|
|
+ $chunk_index = isset($_POST['chunk_index']) ? absint($_POST['chunk_index']) : 0;
|
|
|
|
|
+ $total_chunks = isset($_POST['total_chunks']) ? absint($_POST['total_chunks']) : 0;
|
|
|
|
|
+ $file_name = isset($_POST['file_name']) ? sanitize_file_name($_POST['file_name']) : '';
|
|
|
|
|
+ $file_size = isset($_POST['file_size']) ? absint($_POST['file_size']) : 0;
|
|
|
|
|
+
|
|
|
|
|
+ // Validate product
|
|
|
|
|
+ if (!$product_id || !Studiou_WC_FPP_Product::is_fpp_product($product_id)) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Invalid product.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Validate file size
|
|
|
|
|
+ $max_size = Studiou_WC_FPP_Product::get_product_max_file_size($product_id);
|
|
|
|
|
+ if ($file_size > ($max_size * 1024 * 1024)) {
|
|
|
|
|
+ wp_send_json_error(array('message' => sprintf(
|
|
|
|
|
+ __('File is too large. Maximum size: %s MB', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ $max_size
|
|
|
|
|
+ )));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Validate upload_id format (should be alphanumeric)
|
|
|
|
|
+ if (!preg_match('/^[a-zA-Z0-9_-]+$/', $upload_id)) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Invalid upload ID.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Validate chunk file exists
|
|
|
|
|
+ if (!isset($_FILES['chunk']) || $_FILES['chunk']['error'] !== UPLOAD_ERR_OK) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Chunk upload failed.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $chunks_dir = $this->get_chunks_dir();
|
|
|
|
|
+ if (!file_exists($chunks_dir)) {
|
|
|
|
|
+ wp_mkdir_p($chunks_dir);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Store the chunk
|
|
|
|
|
+ $chunk_file = $chunks_dir . '/' . $upload_id . '_chunk_' . $chunk_index;
|
|
|
|
|
+ if (!move_uploaded_file($_FILES['chunk']['tmp_name'], $chunk_file)) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Failed to store chunk.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If this is the last chunk, assemble the file
|
|
|
|
|
+ if ($chunk_index === $total_chunks - 1) {
|
|
|
|
|
+ // Clean any output that may have been generated
|
|
|
|
|
+ while (ob_get_level()) {
|
|
|
|
|
+ ob_end_clean();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $result = $this->assemble_chunks($upload_id, $total_chunks, $file_name, $product_id);
|
|
|
|
|
+
|
|
|
|
|
+ // Clean again before sending JSON
|
|
|
|
|
+ while (ob_get_level()) {
|
|
|
|
|
+ ob_end_clean();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (is_wp_error($result)) {
|
|
|
|
|
+ wp_send_json_error(array('message' => $result->get_error_message()));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ wp_send_json_success(array(
|
|
|
|
|
+ 'complete' => true,
|
|
|
|
|
+ 'attachment_id' => $result['attachment_id'],
|
|
|
|
|
+ 'file_record_id' => $result['file_record_id'],
|
|
|
|
|
+ 'thumbnail_url' => $result['thumbnail_url'],
|
|
|
|
|
+ 'preview_url' => $result['preview_url'],
|
|
|
|
|
+ 'file_name' => $result['file_name'],
|
|
|
|
|
+ ));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ wp_send_json_success(array(
|
|
|
|
|
+ 'complete' => false,
|
|
|
|
|
+ 'chunk_index' => $chunk_index,
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function assemble_chunks($upload_id, $total_chunks, $file_name, $product_id) {
|
|
|
|
|
+ $chunks_dir = $this->get_chunks_dir();
|
|
|
|
|
+ $upload_dir = wp_upload_dir();
|
|
|
|
|
+
|
|
|
|
|
+ // Create a subdirectory for free photo uploads
|
|
|
|
|
+ $fpp_dir = $upload_dir['path'] . '/free-photo';
|
|
|
|
|
+ if (!file_exists($fpp_dir)) {
|
|
|
|
|
+ wp_mkdir_p($fpp_dir);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Generate unique filename
|
|
|
|
|
+ $ext = pathinfo($file_name, PATHINFO_EXTENSION);
|
|
|
|
|
+ $base = sanitize_file_name(pathinfo($file_name, PATHINFO_FILENAME));
|
|
|
|
|
+ $unique_name = $base . '_' . uniqid() . '.' . $ext;
|
|
|
|
|
+ $assembled_path = $fpp_dir . '/' . $unique_name;
|
|
|
|
|
+
|
|
|
|
|
+ // Assemble chunks
|
|
|
|
|
+ $output = fopen($assembled_path, 'wb');
|
|
|
|
|
+ if (!$output) {
|
|
|
|
|
+ $this->cleanup_chunks($upload_id, $total_chunks);
|
|
|
|
|
+ return new WP_Error('assemble_failed', __('Failed to create output file.', 'studiou-wc-free-photo-product'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for ($i = 0; $i < $total_chunks; $i++) {
|
|
|
|
|
+ $chunk_file = $chunks_dir . '/' . $upload_id . '_chunk_' . $i;
|
|
|
|
|
+ if (!file_exists($chunk_file)) {
|
|
|
|
|
+ fclose($output);
|
|
|
|
|
+ unlink($assembled_path);
|
|
|
|
|
+ $this->cleanup_chunks($upload_id, $total_chunks);
|
|
|
|
|
+ return new WP_Error('chunk_missing', sprintf(
|
|
|
|
|
+ __('Missing chunk %d.', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ $i
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $chunk_data = file_get_contents($chunk_file);
|
|
|
|
|
+ fwrite($output, $chunk_data);
|
|
|
|
|
+ }
|
|
|
|
|
+ fclose($output);
|
|
|
|
|
+
|
|
|
|
|
+ // Clean up chunk files
|
|
|
|
|
+ $this->cleanup_chunks($upload_id, $total_chunks);
|
|
|
|
|
+
|
|
|
|
|
+ // Validate file extension
|
|
|
|
|
+ $allowed = $this->get_allowed_mime_types();
|
|
|
|
|
+ $ext_lower = strtolower($ext);
|
|
|
|
|
+ $valid = false;
|
|
|
|
|
+ foreach ($allowed as $exts => $mime) {
|
|
|
|
|
+ $ext_list = explode('|', $exts);
|
|
|
|
|
+ if (in_array($ext_lower, $ext_list)) {
|
|
|
|
|
+ $valid = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!$valid) {
|
|
|
|
|
+ unlink($assembled_path);
|
|
|
|
|
+ return new WP_Error('invalid_type', __('File type not allowed.', 'studiou-wc-free-photo-product'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Validate image resolution (if limits are set)
|
|
|
|
|
+ $res_error = $this->validate_image_resolution($assembled_path, $product_id);
|
|
|
|
|
+ if (is_wp_error($res_error)) {
|
|
|
|
|
+ unlink($assembled_path);
|
|
|
|
|
+ return $res_error;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create WP attachment
|
|
|
|
|
+ $relative_path = str_replace($upload_dir['basedir'] . '/', '', $assembled_path);
|
|
|
|
|
+ $filetype = wp_check_filetype($unique_name, $allowed);
|
|
|
|
|
+
|
|
|
|
|
+ $attachment_data = array(
|
|
|
|
|
+ 'post_mime_type' => $filetype['type'] ?: 'application/octet-stream',
|
|
|
|
|
+ 'post_title' => sanitize_file_name($file_name),
|
|
|
|
|
+ 'post_content' => '',
|
|
|
|
|
+ 'post_status' => 'inherit',
|
|
|
|
|
+ 'post_parent' => $product_id,
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $attachment_id = wp_insert_attachment($attachment_data, $assembled_path, $product_id);
|
|
|
|
|
+ if (is_wp_error($attachment_id)) {
|
|
|
|
|
+ unlink($assembled_path);
|
|
|
|
|
+ return $attachment_id;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Generate metadata (wrapped in output buffer to prevent stray output corrupting JSON)
|
|
|
|
|
+ require_once(ABSPATH . 'wp-admin/includes/image.php');
|
|
|
|
|
+ ob_start();
|
|
|
|
|
+ try {
|
|
|
|
|
+ @set_time_limit(120);
|
|
|
|
|
+ $metadata = @wp_generate_attachment_metadata($attachment_id, $assembled_path);
|
|
|
|
|
+ if (!empty($metadata)) {
|
|
|
|
|
+ wp_update_attachment_metadata($attachment_id, $metadata);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU FPP: metadata generation failed - ' . $e->getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ob_end_clean();
|
|
|
|
|
+
|
|
|
|
|
+ // Assign media category
|
|
|
|
|
+ $media_cat_id = Studiou_WC_FPP_Product::get_product_media_category($product_id);
|
|
|
|
|
+ if ($media_cat_id) {
|
|
|
|
|
+ wp_set_object_terms($attachment_id, array((int) $media_cat_id), 'studiou_media_category');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Get thumbnail URL (small - for upload preview)
|
|
|
|
|
+ $thumbnail_url = '';
|
|
|
|
|
+ $image_src = wp_get_attachment_image_src($attachment_id, 'thumbnail');
|
|
|
|
|
+ if ($image_src) {
|
|
|
|
|
+ $thumbnail_url = $image_src[0];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $thumbnail_url = wp_mime_type_icon($attachment_id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Get preview URL (larger - for product gallery replacement)
|
|
|
|
|
+ $preview_url = '';
|
|
|
|
|
+ $preview_src = wp_get_attachment_image_src($attachment_id, 'woocommerce_single');
|
|
|
|
|
+ if ($preview_src) {
|
|
|
|
|
+ $preview_url = $preview_src[0];
|
|
|
|
|
+ } elseif ($image_src) {
|
|
|
|
|
+ $preview_url = $image_src[0];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Get session key for guests
|
|
|
|
|
+ $session_key = '';
|
|
|
|
|
+ if (!is_user_logged_in()) {
|
|
|
|
|
+ if (WC()->session) {
|
|
|
|
|
+ $session_key = WC()->session->get_customer_id();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Insert file record
|
|
|
|
|
+ $file_record_id = $this->db->insert_file_record(array(
|
|
|
|
|
+ 'product_id' => $product_id,
|
|
|
|
|
+ 'attachment_id' => $attachment_id,
|
|
|
|
|
+ 'customer_id' => get_current_user_id(),
|
|
|
|
|
+ 'session_key' => $session_key,
|
|
|
|
|
+ 'file_name' => $file_name,
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ if (!$file_record_id) {
|
|
|
|
|
+ wp_delete_attachment($attachment_id, true);
|
|
|
|
|
+ return new WP_Error('record_failed', __('Failed to create file record.', 'studiou-wc-free-photo-product'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return array(
|
|
|
|
|
+ 'attachment_id' => $attachment_id,
|
|
|
|
|
+ 'file_record_id' => $file_record_id,
|
|
|
|
|
+ 'thumbnail_url' => $thumbnail_url,
|
|
|
|
|
+ 'preview_url' => $preview_url,
|
|
|
|
|
+ 'file_name' => $file_name,
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Validate image resolution against product limits.
|
|
|
|
|
+ * Width/height are commutable — a 3000x2000 image matches both 3000x2000 and 2000x3000 limits.
|
|
|
|
|
+ */
|
|
|
|
|
+ private function validate_image_resolution($file_path, $product_id) {
|
|
|
|
|
+ $limits = Studiou_WC_FPP_Product::get_product_resolution_limits($product_id);
|
|
|
|
|
+
|
|
|
|
|
+ // Skip if no limits set
|
|
|
|
|
+ $has_min = ($limits['min_width'] > 0 || $limits['min_height'] > 0);
|
|
|
|
|
+ $has_max = ($limits['max_width'] > 0 || $limits['max_height'] > 0);
|
|
|
|
|
+ if (!$has_min && !$has_max) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Get image dimensions
|
|
|
|
|
+ $size = @getimagesize($file_path);
|
|
|
|
|
+ if (!$size || !isset($size[0], $size[1])) {
|
|
|
|
|
+ // Cannot determine dimensions (e.g. RAW files) — skip validation
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $img_w = $size[0];
|
|
|
|
|
+ $img_h = $size[1];
|
|
|
|
|
+
|
|
|
|
|
+ // Normalize: always compare min(w,h) vs min(limit_w,limit_h) and max(w,h) vs max(limit_w,limit_h)
|
|
|
|
|
+ // This makes portrait/landscape interchangeable
|
|
|
|
|
+ $img_short = min($img_w, $img_h);
|
|
|
|
|
+ $img_long = max($img_w, $img_h);
|
|
|
|
|
+
|
|
|
|
|
+ // Minimum resolution check
|
|
|
|
|
+ if ($has_min) {
|
|
|
|
|
+ $min_short = min($limits['min_width'] ?: 0, $limits['min_height'] ?: 0);
|
|
|
|
|
+ $min_long = max($limits['min_width'] ?: 0, $limits['min_height'] ?: 0);
|
|
|
|
|
+ // If only one dimension is set, use it for both
|
|
|
|
|
+ if ($min_short === 0) $min_short = $min_long;
|
|
|
|
|
+
|
|
|
|
|
+ if ($img_short < $min_short || $img_long < $min_long) {
|
|
|
|
|
+ return new WP_Error('resolution_too_small', sprintf(
|
|
|
|
|
+ __('Image resolution %1$dx%2$d px is too small. Minimum required: %3$dx%4$d px.', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ $img_w, $img_h, $limits['min_width'] ?: $limits['min_height'], $limits['min_height'] ?: $limits['min_width']
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Maximum resolution check
|
|
|
|
|
+ if ($has_max) {
|
|
|
|
|
+ $max_short = min($limits['max_width'] ?: PHP_INT_MAX, $limits['max_height'] ?: PHP_INT_MAX);
|
|
|
|
|
+ $max_long = max($limits['max_width'] ?: PHP_INT_MAX, $limits['max_height'] ?: PHP_INT_MAX);
|
|
|
|
|
+ if ($max_short === PHP_INT_MAX) $max_short = $max_long;
|
|
|
|
|
+
|
|
|
|
|
+ if ($img_short > $max_short || $img_long > $max_long) {
|
|
|
|
|
+ return new WP_Error('resolution_too_large', sprintf(
|
|
|
|
|
+ __('Image resolution %1$dx%2$d px is too large. Maximum allowed: %3$dx%4$d px.', 'studiou-wc-free-photo-product'),
|
|
|
|
|
+ $img_w, $img_h, $limits['max_width'] ?: $limits['max_height'], $limits['max_height'] ?: $limits['max_width']
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function cleanup_chunks($upload_id, $total_chunks) {
|
|
|
|
|
+ $chunks_dir = $this->get_chunks_dir();
|
|
|
|
|
+ for ($i = 0; $i < $total_chunks; $i++) {
|
|
|
|
|
+ $chunk_file = $chunks_dir . '/' . $upload_id . '_chunk_' . $i;
|
|
|
|
|
+ if (file_exists($chunk_file)) {
|
|
|
|
|
+ unlink($chunk_file);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function handle_remove_upload() {
|
|
|
|
|
+ check_ajax_referer('studiou-wcfpp-front-nonce', 'nonce');
|
|
|
|
|
+
|
|
|
|
|
+ $file_record_id = isset($_POST['file_record_id']) ? absint($_POST['file_record_id']) : 0;
|
|
|
|
|
+ if (!$file_record_id) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Invalid file.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $record = $this->db->get_file_record($file_record_id);
|
|
|
|
|
+ if (!$record) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('File not found.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Only allow removal if not yet linked to an order
|
|
|
|
|
+ if ($record->order_id > 0) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Cannot remove a file linked to an order.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Verify ownership
|
|
|
|
|
+ $current_user_id = get_current_user_id();
|
|
|
|
|
+ if ($current_user_id > 0 && (int) $record->customer_id !== $current_user_id) {
|
|
|
|
|
+ wp_send_json_error(array('message' => __('Permission denied.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $this->db->delete_file_record($file_record_id);
|
|
|
|
|
+
|
|
|
|
|
+ wp_send_json_success(array('message' => __('File removed.', 'studiou-wc-free-photo-product')));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|