calliope-media-import-export
Last commit date
assets
8 months ago
languages
8 months ago
export-import-media.php
8 months ago
importer.js
8 months ago
readme.txt
8 months ago
style.css
8 months ago
style.css.mine
8 months ago
style.css.r0
8 months ago
style.css.r3375314
8 months ago
export-import-media.php
446 lines
| 1 | <?php |
| 2 | /* --- ARCHIVO export-import-media.php COMPLETO Y CORREGIDO --- */ |
| 3 | /* |
| 4 | Plugin Name: Export/Import Media |
| 5 | Description: Exports and imports images with metadata using CSV. Includes real-time batch processing and prevents duplicates. |
| 6 | Version: 1.2.1 |
| 7 | Author: Maira Forest |
| 8 | Author URI: https://calliope.com.ar/ |
| 9 | License: GPLv2 or later |
| 10 | License URI: https://www.gnu.org/licenses/gpl-2.0.html |
| 11 | Text Domain: export-import-media |
| 12 | Domain Path: /languages |
| 13 | */ |
| 14 | |
| 15 | if (!defined('ABSPATH')) exit; |
| 16 | |
| 17 | // Cargar el dominio de texto para traducciones |
| 18 | add_action('plugins_loaded', 'eim_load_textdomain'); |
| 19 | function eim_load_textdomain() { |
| 20 | load_plugin_textdomain('export-import-media', false, dirname(plugin_basename(__FILE__)) . '/languages'); |
| 21 | } |
| 22 | |
| 23 | // Utility functions |
| 24 | if (!function_exists('eim_attachment_exists')) { |
| 25 | function eim_attachment_exists($relative_path, $local_path) { |
| 26 | global $wpdb; |
| 27 | if (file_exists($local_path)) { |
| 28 | $hash = md5_file($local_path); |
| 29 | if ($hash) { |
| 30 | $attachment_id_by_hash = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_eim_file_hash', $hash)); |
| 31 | if ($attachment_id_by_hash) return (int)$attachment_id_by_hash; |
| 32 | } |
| 33 | } |
| 34 | $db_path = ltrim($relative_path, '/'); |
| 35 | $attachment_id_by_path = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_wp_attached_file', $db_path)); |
| 36 | return $attachment_id_by_path ? (int)$attachment_id_by_path : false; |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | if (!function_exists('eim_set_attachment_hash')) { |
| 41 | function eim_set_attachment_hash($attach_id, $file_path) { |
| 42 | if (file_exists($file_path) && $attach_id) { |
| 43 | $hash = md5_file($file_path); |
| 44 | if ($hash) update_post_meta($attach_id, '_eim_file_hash', $hash); |
| 45 | } |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | // Admin menu and script enqueueing |
| 50 | add_action('admin_menu', function () { |
| 51 | add_media_page(esc_html__('Export/Import Media', 'export-import-media'), esc_html__('Export/Import Media', 'export-import-media'), 'manage_options', 'export-import-media', 'eim_render_admin_page'); |
| 52 | }); |
| 53 | |
| 54 | add_action('admin_enqueue_scripts', function($hook) { |
| 55 | if ($hook !== 'media_page_export-import-media') return; |
| 56 | |
| 57 | // --- CORRECCIÓN APLICADA AQUÍ --- |
| 58 | $plugin_version = '1.2.1'; // Usaremos esta versión para el CSS |
| 59 | |
| 60 | wp_enqueue_script('eim-importer-js', plugin_dir_url(__FILE__) . 'importer.js', ['jquery'], $plugin_version, true); |
| 61 | wp_localize_script('eim-importer-js', 'eim_ajax', [ |
| 62 | 'ajax_url' => admin_url('admin-ajax.php'), |
| 63 | 'nonce' => wp_create_nonce('eim_import_nonce'), |
| 64 | 'i18n' => [ |
| 65 | 'select_csv' => esc_html__('Please select a CSV file.', 'export-import-media'), |
| 66 | 'validating' => esc_html__('Validating file...', 'export-import-media'), |
| 67 | 'validation_failed' => esc_html__('Validation Failed:', 'export-import-media'), |
| 68 | 'validation_success' => esc_html__('Validation successful.', 'export-import-media'), |
| 69 | 'ready_to_import' => esc_html__('Ready to import.', 'export-import-media'), |
| 70 | 'uploading_preparing' => esc_html__('Uploading and preparing file...', 'export-import-media'), |
| 71 | 'file_ready' => esc_html__('File ready. Total images:', 'export-import-media'), |
| 72 | 'empty_csv' => esc_html__('The CSV file is empty.', 'export-import-media'), |
| 73 | 'error_prefix' => esc_html__('Error:', 'export-import-media'), |
| 74 | 'server_error' => esc_html__('Server communication error.', 'export-import-media'), |
| 75 | 'stopping_process' => esc_html__('Stopping the process...', 'export-import-media'), |
| 76 | 'invalid_response' => esc_html__('Invalid response from server', 'export-import-media'), |
| 77 | 'request_failed' => esc_html__('Batch request failed', 'export-import-media'), |
| 78 | 'process_complete' => esc_html__('Process completed!', 'export-import-media'), |
| 79 | 'process_stopped' => esc_html__('Process stopped by user.', 'export-import-media'), |
| 80 | 'processing_batch' => esc_html__('Processing batch...', 'export-import-media'), |
| 81 | 'batch_complete' => esc_html__('Batch completed.', 'export-import-media'), |
| 82 | 'click_continue' => esc_html__('Click "Process Next Batch" to continue.', 'export-import-media'), |
| 83 | ] |
| 84 | ]); |
| 85 | |
| 86 | wp_add_inline_script('eim-importer-js', ' |
| 87 | jQuery(document).on("click", ".eim-review-notice-top .notice-dismiss", function() { |
| 88 | jQuery.ajax({ |
| 89 | url: eim_ajax.ajax_url, |
| 90 | type: "POST", |
| 91 | data: { |
| 92 | action: "eim_dismiss_review_notice", |
| 93 | nonce: eim_ajax.nonce |
| 94 | } |
| 95 | }); |
| 96 | }); |
| 97 | '); |
| 98 | |
| 99 | // Se elimina la línea de filemtime y se usa $plugin_version |
| 100 | wp_enqueue_style('eim-custom-styles', plugin_dir_url(__FILE__) . 'style.css', [], $plugin_version); |
| 101 | }); |
| 102 | |
| 103 | // Admin page render |
| 104 | function eim_render_admin_page() { |
| 105 | if (!current_user_can('manage_options')) { |
| 106 | wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'export-import-media')); |
| 107 | } |
| 108 | ?> |
| 109 | <div class="wrap"> |
| 110 | <div class="eim-main-banner"> |
| 111 | <div class="eim-banner-content"> |
| 112 | <div class="eim-banner-logo"><svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-down-circle"><circle cx="12" cy="12" r="10"></circle><polyline points="8 12 12 16 16 12"></polyline><line x1="12" y1="8" x2="12" y2="16"></line></svg></div> |
| 113 | <div class="eim-banner-text"> |
| 114 | <h3><?php esc_html_e('Media Transfer Plugin', 'export-import-media'); ?></h3> |
| 115 | <p><?php esc_html_e('Your complete solution to import and export the media library.', 'export-import-media'); ?></p> |
| 116 | </div> |
| 117 | </div> |
| 118 | <div class="eim-banner-actions"> |
| 119 | <a href="https://calliope.com.ar/documentacion-plugin/" target="_blank" class="eim-banner-link"><?php esc_html_e('Documentation', 'export-import-media'); ?></a> |
| 120 | <a href="https://wordpress.org/support/plugin/calliope-media-import-export/" target="_blank" class="eim-banner-link"><?php esc_html_e('Support', 'export-import-media'); ?></a> |
| 121 | <a href="https://ko-fi.com/O4O21MF4QW" target="_blank" class="button button-primary eim-kofi-button"> |
| 122 | <img src="<?php echo esc_url(plugin_dir_url(__FILE__) . 'assets/images/kofi.svg'); ?>" alt="<?php esc_attr_e('Ko-fi cup', 'export-import-media'); ?>" /> |
| 123 | <?php esc_html_e('Support me on Ko-fi', 'export-import-media'); ?> |
| 124 | </a> |
| 125 | </div> |
| 126 | </div> |
| 127 | |
| 128 | <?php |
| 129 | if (!get_user_meta(get_current_user_id(), 'eim_review_notice_dismissed', true)) { |
| 130 | $review_link = 'https://wordpress.org/support/plugin/calliope-media-import-export/reviews/#new-post'; |
| 131 | ?> |
| 132 | <div class="notice notice-info is-dismissible eim-review-notice-top" style="margin-bottom: 20px;"> |
| 133 | <p> |
| 134 | <?php |
| 135 | printf( |
| 136 | wp_kses( |
| 137 | __('You are using Media Transfer Plugin! If you find it useful, please consider <a href="%s" target="_blank">leaving a positive review</a>. It really helps!', 'export-import-media'), |
| 138 | [ 'a' => [ 'href' => [], 'target' => [] ] ] |
| 139 | ), |
| 140 | esc_url($review_link) |
| 141 | ); |
| 142 | ?> |
| 143 | </p> |
| 144 | </div> |
| 145 | <?php |
| 146 | } |
| 147 | ?> |
| 148 | |
| 149 | <div id="eim-export-section" class="eim-card"> |
| 150 | <h2><?php esc_html_e('1. Export Media Library', 'export-import-media'); ?></h2> |
| 151 | <p><?php esc_html_e('Generate a CSV file with the information of all images in your media library.', 'export-import-media'); ?></p> |
| 152 | <form method="post" action=""> |
| 153 | <?php wp_nonce_field('eim_export_action', 'eim_export_nonce'); ?> |
| 154 | <?php submit_button(esc_html__('Export to CSV', 'export-import-media'), 'secondary', 'eim_export_csv', true, ['id' => 'eim_export_csv']); ?> |
| 155 | </form> |
| 156 | </div> |
| 157 | |
| 158 | <div id="eim-import-section" class="eim-card"> |
| 159 | <h2><?php esc_html_e('2. Import from CSV', 'export-import-media'); ?></h2> |
| 160 | <p><?php esc_html_e('Upload a CSV file. The process will run in batches, showing real-time progress.', 'export-import-media'); ?></p> |
| 161 | <form id="eim-import-form" method="post" enctype="multipart/form-data"> |
| 162 | <p><label for="eim_csv"><strong><?php esc_html_e('Select the CSV file:', 'export-import-media'); ?></strong></label><br><input type="file" name="eim_csv" id="eim_csv" accept=".csv" required /></p> |
| 163 | <p><label for="batch_size"><strong><?php esc_html_e('Images per batch:', 'export-import-media'); ?></strong></label><br> |
| 164 | <select name="batch_size" id="batch_size"><option value="10">10</option><option value="25">25</option><option value="50" selected>50</option><option value="100">100</option><option value="250">250</option><option value="500">500</option></select> |
| 165 | </p> |
| 166 | <p> |
| 167 | <label for="eim_local_import"> |
| 168 | <input type="checkbox" name="eim_local_import" id="eim_local_import" value="1" /> |
| 169 | <span style="font-weight: bold;"><?php esc_html_e('Local Import Mode', 'export-import-media'); ?></span><br> |
| 170 | <small style="margin-left: 22px; display: inline-block;"><?php esc_html_e('Instead of downloading, find images in the local /uploads folder based on the "Relative Path". Files must already exist on this server.', 'export-import-media'); ?></small> |
| 171 | </label> |
| 172 | </p> |
| 173 | <button type="submit" class="button button-primary" id="eim-start-button"><?php esc_html_e('Start Import', 'export-import-media'); ?></button> |
| 174 | <button type="button" class="button button-primary" id="eim-continue-button" style="display:none;"><?php esc_html_e('Process Next Batch', 'export-import-media'); ?></button> |
| 175 | <button type="button" class="button" id="eim-stop-button" style="display:none;"><?php esc_html_e('Stop Process', 'export-import-media'); ?></button> |
| 176 | </form> |
| 177 | </div> |
| 178 | |
| 179 | <div id="eimp-progress-container" class="eim-card" style="display:none; margin-top: 20px;"> |
| 180 | <h3><?php esc_html_e('Import Progress:', 'export-import-media'); ?></h3> |
| 181 | <div style="background: #eee; border: 1px solid #ccc; padding: 5px; border-radius: 5px;"> |
| 182 | <div id="eimp-progress-bar" style="width: 0%; height: 24px; background-color: #0073aa; text-align: center; line-height: 24px; color: white; font-weight: bold; transition: width 0.1s ease; border-radius: 3px;">0%</div> |
| 183 | </div> |
| 184 | <div class="eim-warning-message"><?php esc_html_e('Important! Do not reload or close this page until the process is complete.', 'export-import-media'); ?></div> |
| 185 | <div id="eimp-log" style="background: #fafafa; border: 1px solid #ccc; border-top: none; padding: 10px; max-height: 300px; overflow-y: auto; font-family: monospace; font-size: 13px; margin-top: 5px;"></div> |
| 186 | </div> |
| 187 | |
| 188 | <div class="eim-footer-review"> |
| 189 | <?php |
| 190 | $review_link = 'https://wordpress.org/support/plugin/calliope-media-import-export/reviews/#new-post'; |
| 191 | $stars_svg = '<svg width="18" height="18" viewBox="0 0 24 24"><path fill="#ffb900" d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>'; |
| 192 | $allowed_html = [ |
| 193 | 'a' => [ 'href' => [], 'target' => [], 'aria-label' => [] ], |
| 194 | 'svg' => [ 'width' => [], 'height' => [], 'viewBox' => [] ], |
| 195 | 'path' => [ 'fill' => [], 'd' => [] ], |
| 196 | ]; |
| 197 | printf( |
| 198 | wp_kses( |
| 199 | __('If you like our plugin, a %1$s%3$s%2$s rating will help us a lot, thanks in advance!', 'export-import-media'), |
| 200 | $allowed_html |
| 201 | ), |
| 202 | '<a href="' . esc_url($review_link) . '" target="_blank" aria-label="' . esc_attr__('Rate 5 stars', 'export-import-media') . '">', |
| 203 | '</a>', |
| 204 | str_repeat($stars_svg, 5) |
| 205 | ); |
| 206 | ?> |
| 207 | </div> |
| 208 | </div> |
| 209 | <?php |
| 210 | } |
| 211 | |
| 212 | // Export logic |
| 213 | add_action('admin_init', function () { |
| 214 | if ( ! isset( $_POST['eim_export_csv'] ) ) { return; } |
| 215 | if ( ! isset( $_POST['eim_export_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['eim_export_nonce'] ) ), 'eim_export_action' ) ) { wp_die( esc_html__( 'Security check failed.', 'export-import-media' ) ); } |
| 216 | if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have sufficient permissions.', 'export-import-media' ) ); } |
| 217 | $args = ['post_type' => 'attachment', 'post_mime_type' => 'image', 'post_status' => 'inherit', 'posts_per_page' => -1]; |
| 218 | $images = get_posts($args); |
| 219 | header('Content-Type: text/csv; charset=UTF-8'); |
| 220 | header('Content-Disposition: attachment; filename="media-export.csv"'); |
| 221 | $output = fopen('php://output', 'w'); |
| 222 | if ( ! $output ) { return; } |
| 223 | fputcsv($output, ['ID', 'Absolute URL', 'Relative Path', 'File', 'Alt Text', 'Caption', 'Description', 'Title']); |
| 224 | foreach ($images as $image) { |
| 225 | $path = get_post_meta($image->ID, '_wp_attached_file', true); |
| 226 | fputcsv($output, [$image->ID, wp_get_attachment_url($image->ID), '/' . $path, basename($path), get_post_meta($image->ID, '_wp_attachment_image_alt', true), $image->post_excerpt, $image->post_content, $image->post_title]); |
| 227 | } |
| 228 | fclose($output); |
| 229 | exit; |
| 230 | }); |
| 231 | |
| 232 | // AJAX handlers for import |
| 233 | add_action('wp_ajax_eim_validate_csv', function() { |
| 234 | check_ajax_referer('eim_import_nonce', 'nonce'); |
| 235 | if (empty($_FILES['eim_csv'])) { |
| 236 | wp_send_json_error(['message' => esc_html__('No file received.', 'export-import-media')]); |
| 237 | } |
| 238 | |
| 239 | require_once ABSPATH . 'wp-admin/includes/file.php'; |
| 240 | global $wp_filesystem; |
| 241 | WP_Filesystem(); |
| 242 | |
| 243 | $upload_dir = wp_upload_dir(); |
| 244 | $temp_dir = trailingslashit($upload_dir['basedir']) . 'eim-temp/'; |
| 245 | if (!$wp_filesystem->is_dir($temp_dir)) { |
| 246 | $wp_filesystem->mkdir($temp_dir); |
| 247 | } |
| 248 | |
| 249 | $tmp_name = isset($_FILES['eim_csv']['tmp_name']) ? sanitize_text_field(wp_unslash($_FILES['eim_csv']['tmp_name'])) : ''; |
| 250 | if (!file_exists($tmp_name)) { |
| 251 | wp_send_json_error(['message' => esc_html__('Error with temporary upload file.', 'export-import-media')]); |
| 252 | } |
| 253 | |
| 254 | $content = $wp_filesystem->get_contents($tmp_name); |
| 255 | |
| 256 | if (empty(trim($content))) { |
| 257 | wp_send_json_error(['message' => esc_html__('The selected CSV file is empty.', 'export-import-media')]); |
| 258 | } |
| 259 | |
| 260 | // Validación de cabeceras |
| 261 | $required_headers = ['ID', 'Absolute URL', 'Relative Path', 'File', 'Alt Text', 'Caption', 'Description', 'Title']; |
| 262 | $file_handle_check = fopen($tmp_name, 'r'); |
| 263 | $read_headers = fgetcsv($file_handle_check); |
| 264 | fclose($file_handle_check); |
| 265 | |
| 266 | if (!$read_headers) { |
| 267 | wp_send_json_error(['message' => esc_html__('Cannot read headers from CSV file.', 'export-import-media')]); |
| 268 | } |
| 269 | |
| 270 | $missing_headers = array_diff($required_headers, $read_headers); |
| 271 | if (!empty($missing_headers)) { |
| 272 | wp_send_json_error([ |
| 273 | 'message' => sprintf( |
| 274 | esc_html__('Invalid CSV header. Missing columns: %s', 'export-import-media'), |
| 275 | implode(', ', $missing_headers) |
| 276 | ) |
| 277 | ]); |
| 278 | } |
| 279 | |
| 280 | $temp_filename = 'import-' . uniqid() . '.csv'; |
| 281 | $temp_path = $temp_dir . $temp_filename; |
| 282 | $wp_filesystem->put_contents($temp_path, $content); |
| 283 | |
| 284 | $lines = explode("\n", trim($content)); |
| 285 | $linecount = count($lines) > 1 ? count($lines) - 1 : 0; |
| 286 | |
| 287 | if ($linecount === 0) { |
| 288 | wp_send_json_error(['message' => esc_html__('The CSV file contains headers but no data rows.', 'export-import-media')]); |
| 289 | } |
| 290 | |
| 291 | wp_send_json_success(['file' => $temp_filename, 'total_rows' => $linecount]); |
| 292 | }); |
| 293 | |
| 294 | add_action('wp_ajax_eim_process_batch', function() { |
| 295 | check_ajax_referer('eim_import_nonce', 'nonce'); |
| 296 | set_time_limit(0); |
| 297 | require_once ABSPATH . 'wp-admin/includes/file.php'; |
| 298 | require_once(ABSPATH . 'wp-admin/includes/image.php'); |
| 299 | global $wp_filesystem; WP_Filesystem(); |
| 300 | $file_name_sanitized = isset($_POST['file']) ? sanitize_file_name(wp_unslash($_POST['file'])) : ''; |
| 301 | $start_row = isset($_POST['start_row']) ? intval($_POST['start_row']) : 0; |
| 302 | $batch_size = isset($_POST['batch_size']) ? intval($_POST['batch_size']) : 50; |
| 303 | $local_import = isset($_POST['local_import']) && $_POST['local_import'] === 'true'; |
| 304 | $upload_dir = wp_upload_dir(); |
| 305 | $csv_path = trailingslashit($upload_dir['basedir']) . 'eim-temp/' . $file_name_sanitized; |
| 306 | if (!$wp_filesystem->exists($csv_path)) { |
| 307 | wp_send_json_error(['results' => [['status' => 'ERROR', 'file' => esc_html__("File not found", 'export-import-media'), 'message' => esc_html__('The temporary file has disappeared.', 'export-import-media')]]]); |
| 308 | } |
| 309 | $results = []; |
| 310 | $file_handle = fopen($csv_path, 'r'); |
| 311 | if (!$file_handle) { |
| 312 | wp_send_json_error(['results' => [['status' => 'ERROR', 'file' => 'System', 'message' => 'Could not open CSV file.']]]); |
| 313 | } |
| 314 | fgetcsv($file_handle); |
| 315 | for ($i = 0; $i < $start_row; $i++) { |
| 316 | if (feof($file_handle)) break; |
| 317 | fgetcsv($file_handle); |
| 318 | } |
| 319 | for ($i = 0; $i < $batch_size; $i++) { |
| 320 | if (feof($file_handle)) { |
| 321 | $results[] = ['status' => 'FINISHED']; |
| 322 | break; |
| 323 | } |
| 324 | $row = fgetcsv($file_handle); |
| 325 | if (empty($row) || !is_array($row)) continue; |
| 326 | $row = array_pad($row, 8, ''); |
| 327 | list($id, $url, $rel_path, $file_name, $alt, $caption, $desc, $title) = $row; |
| 328 | if (empty($rel_path)) { |
| 329 | $results[] = ['status' => 'SKIPPED', 'file' => sprintf(esc_html__("Row %d", 'export-import-media'), $start_row + $i + 1), 'message' => esc_html__('Incomplete data: Relative Path is required.', 'export-import-media')]; |
| 330 | continue; |
| 331 | } |
| 332 | $dest_path = $upload_dir['basedir'] . $rel_path; |
| 333 | if ($local_import) { |
| 334 | if (!$wp_filesystem->exists($dest_path)) { |
| 335 | $results[] = ['status' => 'ERROR', 'file' => $file_name, 'message' => esc_html__('Local file not found', 'export-import-media')]; |
| 336 | continue; |
| 337 | } |
| 338 | } else { |
| 339 | if (empty($url)) { |
| 340 | $results[] = ['status' => 'SKIPPED', 'file' => $file_name, 'message' => esc_html__('Incomplete data: Absolute URL is required for remote import.', 'export-import-media')]; |
| 341 | continue; |
| 342 | } |
| 343 | if (!$wp_filesystem->is_dir(dirname($dest_path))) { |
| 344 | wp_mkdir_p(dirname($dest_path)); |
| 345 | } |
| 346 | if (!$wp_filesystem->exists($dest_path)) { |
| 347 | $response = wp_remote_get($url, ['timeout' => 120]); |
| 348 | if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { |
| 349 | $error_message = ''; |
| 350 | if (is_wp_error($response)) { |
| 351 | $error_message = $response->get_error_message(); |
| 352 | } else { |
| 353 | $response_code = wp_remote_retrieve_response_code($response); |
| 354 | $response_message = wp_remote_retrieve_response_message($response); |
| 355 | $error_message = sprintf( |
| 356 | esc_html__('HTTP Error %d: %s', 'export-import-media'), |
| 357 | $response_code, |
| 358 | $response_message |
| 359 | ); |
| 360 | } |
| 361 | $results[] = ['status' => 'ERROR', 'file' => $file_name, 'message' => $error_message]; |
| 362 | continue; |
| 363 | } |
| 364 | $wp_filesystem->put_contents($dest_path, wp_remote_retrieve_body($response)); |
| 365 | } |
| 366 | } |
| 367 | $existing_id = eim_attachment_exists($rel_path, $dest_path); |
| 368 | if ($existing_id) { |
| 369 | $results[] = ['status' => 'SKIPPED', 'file' => $file_name, 'message' => sprintf(esc_html__('Duplicate (ID %d)', 'export-import-media'), $existing_id)]; |
| 370 | continue; |
| 371 | } |
| 372 | $filetype = wp_check_filetype(basename($dest_path), null); |
| 373 | $attachment = ['post_mime_type' => $filetype['type'], 'post_title' => sanitize_text_field($title), 'post_content' => wp_kses_post($desc), 'post_excerpt' => sanitize_text_field($caption), 'post_status' => 'inherit']; |
| 374 | $attach_id = wp_insert_attachment($attachment, $dest_path, 0, true); |
| 375 | if (is_wp_error($attach_id)) { |
| 376 | $results[] = ['status' => 'ERROR', 'file' => $file_name, 'message' => $attach_id->get_error_message()]; |
| 377 | continue; |
| 378 | } |
| 379 | wp_update_attachment_metadata($attach_id, wp_generate_attachment_metadata($attach_id, $dest_path)); |
| 380 | update_post_meta($attach_id, '_wp_attachment_image_alt', sanitize_text_field($alt)); |
| 381 | eim_set_attachment_hash($attach_id, $dest_path); |
| 382 | $results[] = ['status' => 'IMPORTED', 'file' => $file_name, 'message' => sprintf(esc_html__('OK (ID %d)', 'export-import-media'), $attach_id)]; |
| 383 | } |
| 384 | fclose($file_handle); |
| 385 | if (end($results)['status'] === 'FINISHED') { |
| 386 | $wp_filesystem->delete($csv_path); |
| 387 | } |
| 388 | wp_send_json_success(['results' => $results]); |
| 389 | }); |
| 390 | |
| 391 | add_action('wp_ajax_eim_dismiss_review_notice', 'eim_dismiss_review_notice_handler'); |
| 392 | function eim_dismiss_review_notice_handler() { |
| 393 | check_ajax_referer('eim_import_nonce', 'nonce'); |
| 394 | update_user_meta(get_current_user_id(), 'eim_review_notice_dismissed', true); |
| 395 | wp_die(); |
| 396 | } |
| 397 | |
| 398 | register_activation_hook(__FILE__, 'eim_activate_plugin'); |
| 399 | function eim_activate_plugin() { |
| 400 | if (!wp_next_scheduled('eim_daily_cleanup_event')) { |
| 401 | wp_schedule_event(time(), 'daily', 'eim_daily_cleanup_event'); |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | register_deactivation_hook(__FILE__, 'eim_deactivate_plugin'); |
| 406 | function eim_deactivate_plugin() { |
| 407 | wp_clear_scheduled_hook('eim_daily_cleanup_event'); |
| 408 | require_once ABSPATH . 'wp-admin/includes/file.php'; |
| 409 | global $wp_filesystem; |
| 410 | WP_Filesystem(); |
| 411 | $upload_dir = wp_upload_dir(); |
| 412 | $temp_dir = trailingslashit($upload_dir['basedir']) . 'eim-temp/'; |
| 413 | if ($wp_filesystem->is_dir($temp_dir)) { |
| 414 | $wp_filesystem->delete($temp_dir, true); |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | add_action('eim_daily_cleanup_event', 'eim_cleanup_temp_files'); |
| 419 | function eim_cleanup_temp_files() { |
| 420 | require_once ABSPATH . 'wp-admin/includes/file.php'; |
| 421 | global $wp_filesystem; |
| 422 | WP_Filesystem(); |
| 423 | $upload_dir = wp_upload_dir(); |
| 424 | $temp_dir = trailingslashit($upload_dir['basedir']) . 'eim-temp/'; |
| 425 | if (!$wp_filesystem->is_dir($temp_dir)) { |
| 426 | return; |
| 427 | } |
| 428 | $files = $wp_filesystem->dirlist($temp_dir); |
| 429 | $expiration_time = 86400; |
| 430 | if ($files) { |
| 431 | foreach ($files as $file) { |
| 432 | $file_path = $temp_dir . $file['name']; |
| 433 | if ($wp_filesystem->is_file($file_path) && (time() - $file['lastmod']) > $expiration_time) { |
| 434 | $wp_filesystem->delete($file_path); |
| 435 | } |
| 436 | } |
| 437 | } |
| 438 | } |
| 439 | |
| 440 | add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'eim_add_settings_link'); |
| 441 | function eim_add_settings_link($links) { |
| 442 | $settings_link = '<a href="upload.php?page=export-import-media">' . esc_html__('Settings', 'export-import-media') . '</a>'; |
| 443 | array_unshift($links, $settings_link); |
| 444 | return $links; |
| 445 | } |
| 446 | ?> |