PluginProbe ʕ •ᴥ•ʔ
Export/Import Media – CSV Media Library Import & Export / 1.2.1
Export/Import Media – CSV Media Library Import & Export v1.2.1
1.7.28 1.7.27 1.7.20 1.7.26 1.7.10 1.7.9 1.7.1 1.7 trunk 1.0 1.0.3 1.2.1 1.2.2 1.2.3 1.6.15 1.6.4
calliope-media-import-export / export-import-media.php
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 ?>