从csv文件导入自定义分类

<?php
/**
 * Plugin Name: Product Category Importer
 * Description: Import product categories from CSV into WordPress custom taxonomy
 * Version: 1.0.1
 * Author: Your Name
 */

// Exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}

class Product_Category_Importer {
    private $taxonomy = 'product_category';
    private $upload_dir = '';
    private $notices = array();

    public function __construct() {
        // Set upload directory
        $upload_dir = wp_upload_dir();
        $this->upload_dir = $upload_dir['basedir'] . '/product-category-imports/';
        
        // Create directory if it doesn't exist
        if (!file_exists($this->upload_dir)) {
            wp_mkdir_p($this->upload_dir);
            // Create an index.php file to prevent directory listing
            file_put_contents($this->upload_dir . 'index.php', '<?php // Silence is golden.');
        }
        
        // Register hooks
        add_action('admin_menu', array($this, 'add_admin_menu'));
        add_action('admin_init', array($this, 'handle_form_submission'));
        add_action('admin_notices', array($this, 'display_admin_notices'));
        add_action('init', array($this, 'register_term_meta'));
    }

    /**
     * Register custom term meta field
     */
    public function register_term_meta() {
        register_meta('term', 'pc_content', array(
            'type' => 'string',
            'description' => 'Product category detailed content',
            'single' => true,
            'show_in_rest' => true,
            'sanitize_callback' => 'wp_kses_post',
        ));
    }

    /**
     * Add the admin menu item
     */
    public function add_admin_menu() {
        add_submenu_page(
            'tools.php',
            'Import Product Categories',
            'Import Product Categories',
            'manage_options',
            'product-category-importer',
            array($this, 'render_admin_page')
        );
    }

    /**
     * Display admin notices
     */
    public function display_admin_notices() {
        foreach ($this->notices as $notice) {
            echo '<div class="notice notice-' . esc_attr($notice['type']) . ' is-dismissible"><p>' . wp_kses_post($notice['message']) . '</p></div>';
        }
    }

    /**
     * Add a notice message
     */
    private function add_notice($message, $type = 'success') {
        $this->notices[] = array(
            'message' => $message,
            'type' => $type
        );
    }

    /**
     * Handle form submissions
     */
    public function handle_form_submission() {
        // Only run on our admin page
        if (!isset($_GET['page']) || $_GET['page'] !== 'product-category-importer') {
            return;
        }

        // File upload handling
        if (isset($_POST['upload_csv']) && check_admin_referer('upload_csv_nonce', 'upload_csv_nonce')) {
            if (!empty($_FILES['csv_file']['name'])) {
                // Validate file type
                $file_info = wp_check_filetype(basename($_FILES['csv_file']['name']), array('csv' => 'text/csv'));
                
                if (empty($file_info['ext'])) {
                    $this->add_notice('Error: Please upload a valid CSV file.', 'error');
                    return;
                }
                
                // Handle the upload
                $upload_result = $this->handle_file_upload();
                if (is_wp_error($upload_result)) {
                    $this->add_notice('Error: ' . $upload_result->get_error_message(), 'error');
                } else {
                    $this->add_notice('CSV file uploaded successfully. You can now import the categories.', 'success');
                }
            } else {
                $this->add_notice('Error: Please select a CSV file to upload.', 'error');
            }
        }

        // Import processing
        if (isset($_POST['process_import']) && check_admin_referer('process_import_nonce', 'process_import_nonce')) {
            if (isset($_POST['csv_file_path']) && !empty($_POST['csv_file_path'])) {
                $file_path = sanitize_text_field($_POST['csv_file_path']);
                
                // Verify file exists and is in our upload directory
                if (!file_exists($file_path)) {
                    $this->add_notice('Error: File does not exist.', 'error');
                    return;
                }
                
                // Additional security check - ensure the file is in our directory
                $real_upload_dir = realpath($this->upload_dir);
                $real_file_path = realpath($file_path);
                
                if (!$real_file_path || strpos($real_file_path, $real_upload_dir) !== 0) {
                    $this->add_notice('Error: Invalid file location.', 'error');
                    return;
                }
                
                $import_result = $this->import_categories($file_path);
                if (is_wp_error($import_result)) {
                    $this->add_notice('Import failed: ' . $import_result->get_error_message(), 'error');
                } else {
                    $this->add_notice(
                        sprintf(
                            'Import completed: %d terms added, %d terms updated, %d errors.',
                            $import_result['imported'],
                            $import_result['updated'],
                            $import_result['errors']
                        ),
                        'success'
                    );
                }
            } else {
                $this->add_notice('Error: No CSV file selected for import.', 'error');
            }
        }
    }

    /**
     * Handle file upload
     */
    private function handle_file_upload() {
        // Security checks
        if (!function_exists('wp_handle_upload')) {
            require_once(ABSPATH . 'wp-admin/includes/file.php');
        }
        
        $upload_overrides = array(
            'test_form' => false,
            'test_type' => true,
            'mimes' => array('csv' => 'text/csv')
        );
        
        // Process the upload
        $uploaded_file = wp_handle_upload($_FILES['csv_file'], $upload_overrides);
        
        if (isset($uploaded_file['error'])) {
            return new WP_Error('upload_error', $uploaded_file['error']);
        }
        
        if (!isset($uploaded_file['file']) || !file_exists($uploaded_file['file'])) {
            return new WP_Error('upload_error', 'Upload failed. File not found.');
        }
        
        // Move to our plugin's directory for better management
        $file_name = basename($uploaded_file['file']);
        $new_file_path = $this->upload_dir . $file_name;
        
        // Ensure directory exists before copying
        if (!is_dir($this->upload_dir)) {
            if (!wp_mkdir_p($this->upload_dir)) {
                return new WP_Error('directory_error', 'Failed to create upload directory.');
            }
        }
        
        // Copy instead of move to avoid permission issues
        if (@copy($uploaded_file['file'], $new_file_path)) {
            @unlink($uploaded_file['file']); // Try to remove the original file
            return $new_file_path;
        } else {
            return new WP_Error('move_error', 'Failed to copy uploaded file to plugin directory.');
        }
    }

    /**
     * List uploaded CSV files
     */
    private function get_uploaded_files() {
        $files = array();
        
        if (is_dir($this->upload_dir)) {
            $dir_files = scandir($this->upload_dir);
            
            if ($dir_files) {
                foreach ($dir_files as $file) {
                    $file_path = $this->upload_dir . $file;
                    if ($file !== '.' && $file !== '..' && pathinfo($file, PATHINFO_EXTENSION) === 'csv' && file_exists($file_path)) {
                        $files[] = array(
                            'name' => $file,
                            'path' => $file_path,
                            'date' => date('Y-m-d H:i:s', filemtime($file_path))
                        );
                    }
                }
            }
        }
        
        // Sort by newest first
        usort($files, function($a, $b) {
            return strtotime($b['date']) - strtotime($a['date']);
        });
        
        return $files;
    }

    /**
     * Import categories from CSV
     */
    private function import_categories($file_path) {
        // Check if file exists
        if (!file_exists($file_path)) {
            return new WP_Error('file_not_found', 'CSV file not found.');
        }
        
        // Check if taxonomy exists
        if (!taxonomy_exists($this->taxonomy)) {
            return new WP_Error('taxonomy_not_exists', "The taxonomy '{$this->taxonomy}' does not exist.");
        }
        
        // Open the file
        $handle = fopen($file_path, 'r');
        if (!$handle) {
            return new WP_Error('file_open_failed', 'Could not open the CSV file.');
        }
        
        // Get headers
        $headers = fgetcsv($handle, 0, ',');
        
        if (!$headers) {
            fclose($handle);
            return new WP_Error('invalid_csv', 'Could not parse CSV headers.');
        }
        
        // Find the indices of the columns we need
        $title_index = array_search('title', $headers);
        $name_index = array_search('name', $headers);
        $content_index = array_search('content', $headers);
        
        if ($title_index === false || $name_index === false || $content_index === false) {
            fclose($handle);
            return new WP_Error('missing_columns', 'Required columns (title, name, content) not found in CSV. Found: ' . implode(', ', $headers));
        }
        
        $stats = array(
            'imported' => 0,
            'updated' => 0,
            'errors' => 0
        );
        
        // Loop through the rows
        while (($data = fgetcsv($handle, 0, ',')) !== false) {
            // Skip if required data is missing or row doesn't have enough columns
            if (!isset($data[$title_index]) || !isset($data[$name_index]) || empty($data[$title_index]) || empty($data[$name_index])) {
                $stats['errors']++;
                continue;
            }
            
            $term_name = sanitize_text_field($data[$title_index]);
            $term_slug = sanitize_title($data[$name_index]);
            $term_content = isset($data[$content_index]) ? $data[$content_index] : '';
            
            // Check if the term already exists
            $existing_term = term_exists($term_slug, $this->taxonomy);
            
            if ($existing_term) {
                // Update existing term
                $term_id = $existing_term['term_id'];
                $update_result = wp_update_term($term_id, $this->taxonomy, array(
                    'name' => $term_name,
                    'slug' => $term_slug,
                ));
                
                if (!is_wp_error($update_result)) {
                    // Update custom field
                    update_term_meta($term_id, 'pc_content', $term_content);
                    $stats['updated']++;
                } else {
                    $stats['errors']++;
                }
            } else {
                // Create new term
                $term = wp_insert_term($term_name, $this->taxonomy, array(
                    'slug' => $term_slug
                ));
                
                if (!is_wp_error($term)) {
                    // Add custom field
                    add_term_meta($term['term_id'], 'pc_content', $term_content, true);
                    $stats['imported']++;
                } else {
                    $stats['errors']++;
                }
            }
        }
        
        fclose($handle);
        return $stats;
    }

    /**
     * Render the admin page
     */
    public function render_admin_page() {
        // Get uploaded files
        $uploaded_files = $this->get_uploaded_files();
        ?>
        <div class="wrap">
            <h1>Import Product Categories</h1>
            
            <?php
            // Check if the custom taxonomy exists
            if (!taxonomy_exists($this->taxonomy)) {
                echo '<div class="notice notice-error"><p>The product_category taxonomy does not exist. Please create it first.</p></div>';
                return;
            }
            ?>
            
            <div class="card" style="padding: 15px; margin-top: 15px;">
                <h2>Step 1: Upload CSV File</h2>
                <p>Upload a CSV file containing your product categories. The file must include 'title', 'name', and 'content' columns.</p>
                
                <form method="post" enctype="multipart/form-data">
                    <?php wp_nonce_field('upload_csv_nonce', 'upload_csv_nonce'); ?>
                    <table class="form-table">
                        <tr>
                            <th scope="row"><label for="csv_file">Select CSV File</label></th>
                            <td>
                                <input type="file" name="csv_file" id="csv_file" accept=".csv" required>
                                <p class="description">File must be in CSV format</p>
                            </td>
                        </tr>
                    </table>
                    <p class="submit">
                        <input type="submit" name="upload_csv" class="button button-primary" value="Upload CSV">
                    </p>
                </form>
            </div>
            
            <?php if (!empty($uploaded_files)): ?>
            <div class="card" style="padding: 15px; margin-top: 20px;">
                <h2>Step 2: Process Import</h2>
                <p>Select a CSV file to import from the list below.</p>
                
                <table class="wp-list-table widefat fixed striped">
                    <thead>
                        <tr>
                            <th>File Name</th>
                            <th>Upload Date</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($uploaded_files as $file): ?>
                        <tr>
                            <td><?php echo esc_html($file['name']); ?></td>
                            <td><?php echo esc_html($file['date']); ?></td>
                            <td>
                                <form method="post">
                                    <?php wp_nonce_field('process_import_nonce', 'process_import_nonce'); ?>
                                    <input type="hidden" name="csv_file_path" value="<?php echo esc_attr($file['path']); ?>">
                                    <button type="submit" name="process_import" class="button button-secondary">Import</button>
                                </form>
                            </td>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
            <?php endif; ?>
            
            <div class="card" style="padding: 15px; margin-top: 20px;">
                <h2>CSV Format Requirements</h2>
                <p>Your CSV file should include the following columns:</p>
                <ul style="list-style-type: disc; margin-left: 20px;">
                    <li><strong>title</strong> - Will be used as the term name</li>
                    <li><strong>name</strong> - Will be used as the term slug</li>
                    <li><strong>content</strong> - Will be added as custom field 'pc_content'</li>
                </ul>
                <p>Example:</p>
                <pre style="background: #f5f5f5; padding: 10px; overflow: auto;">id,title,name,content
1,"Power Inverter","power-inverter","&lt;h5&gt;Product description here&lt;/h5&gt;"
2,"Modified Sine Wave","modified-sine-wave","&lt;p&gt;Details about this product category&lt;/p&gt;"</pre>
            </div>
        </div>
        <?php
    }
}

// Initialize the plugin
new Product_Category_Importer();
×
从csv文件导入自定义分类

从csv文件导入自定义分类

<?php /** * Plugi...