You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改WooCommerce订单发票上传界面:替换媒体上传器并指定存储目录

解决方案:自定义WooCommerce订单发票上传至私有目录

以下是修改后的完整代码,替换原有的媒体库上传逻辑,实现直接将PDF发票上传至受.htaccess保护的私有目录,且不进入媒体库:

<?php
defined( 'ABSPATH' ) || exit;

class AttachFilesToWooCommerceOrderEmail {
    private static $instance;
    private $privateUploads;
    private $uploadDir; // 自定义上传目录服务器绝对路径

    public static function get_instance() {
        if ( null == self::$instance ) {
            self::$instance = new self;
        } 
        return self::$instance;
    }

    private function __construct() {
        $this->privateUploads = true; // 启用私有上传模式
        $this->uploadDir = WP_CONTENT_DIR . '/woocommerce_upload/invoices';
        
        // 自动创建目录及保护文件
        if ( !file_exists( $this->uploadDir ) ) {
            wp_mkdir_p( $this->uploadDir );
            // 写入.htaccess禁止直接访问
            file_put_contents( $this->uploadDir . '/.htaccess', "deny from all\n" );
        }

        $this->init();
    }

    private function init() {
        add_action( 'admin_notices', array( $this, 'verify_cmb2_active' ) );
        add_action( 'cmb2_admin_init', array( $this, 'order_files_metabox' ) );
        add_filter( 'woocommerce_email_attachments', array( $this, 'conditionally_attach_order_files_to_order_email' ), 10, 4 );
        
        // 注册AJAX上传处理
        add_action( 'wp_ajax_order_invoice_upload', array( $this, 'handle_invoice_upload' ) );
        // 加载后台上传脚本
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
    }

    function verify_cmb2_active() {
        if ( ! defined( 'CMB2_LOADED' ) ) {
            $plugin_data = get_plugin_data( __FILE__ );
            $plugin_name = $plugin_data['Name'];
?>
<div class="notice notice-warning is-dismissible"><p>插件 <strong><?php echo $plugin_name; ?></strong> 需要 CMB2 插件。</p></div>
<?php
        }
    }

    function order_files_metabox() {
        $cmb = new_cmb2_box( array(
            'id'            => 'order_attachments',
            'title'         => '订单发票附件',
            'object_types'  => array( 'shop_order', ),
            'context'       => 'side',
            'priority'      => 'high',
            'show_names'    => true,
        ) );

        // 自定义上传字段:只读文本框+上传按钮
        $cmb->add_field( array(
            'desc' => '上传PDF发票,文件将附加到「订单完成」邮件中。<br/><br/>* 文件仅存储在私有目录,不会进入媒体库',
            'id'   => 'order_invoice_file',
            'type' => 'text',
            'attributes' => array(
                'readonly' => 'readonly',
                'class' => 'order-invoice-path',
            ),
            'after_field' => '<button type="button" class="button order-invoice-upload-btn">上传发票</button>',
        ) );
    }

    function enqueue_admin_scripts( $hook ) {
        // 仅在订单编辑页面加载上传脚本
        if ( 'post.php' !== $hook || get_post_type() !== 'shop_order' ) {
            return;
        }

        wp_enqueue_script( 'plupload' );
        wp_add_inline_script( 'plupload', "
            jQuery(document).ready(function($) {
                $('.order-invoice-upload-btn').on('click', function(e) {
                    e.preventDefault();
                    var uploader = new plupload.Uploader({
                        runtimes: 'html5,flash,silverlight,html4',
                        browse_button: this,
                        url: ajaxurl + '?action=order_invoice_upload',
                        filters: {
                            mime_types: [{title: 'PDF文件', extensions: 'pdf'}],
                            max_file_size: '10mb'
                        },
                        multipart_params: {
                            order_id: $('#post_ID').val(),
                            security: '".wp_create_nonce('order_invoice_upload_nonce')."'
                        }
                    });

                    uploader.init();

                    uploader.bind('FilesAdded', function(up, files) {
                        up.start();
                    });

                    uploader.bind('FileUploaded', function(up, file, response) {
                        var res = JSON.parse(response.response);
                        if (res.success) {
                            $('.order-invoice-path').val(res.data.file_path);
                            alert('上传成功');
                        } else {
                            alert('上传失败:' + res.data.message);
                        }
                        up.destroy();
                    });
                });
            });
        " );
    }

    function handle_invoice_upload() {
        // 权限验证
        if ( !current_user_can( 'edit_shop_orders' ) || !wp_verify_nonce( $_POST['security'], 'order_invoice_upload_nonce' ) ) {
            wp_send_json_error( array( 'message' => '权限不足' ) );
        }

        $order_id = intval( $_POST['order_id'] );
        if ( !$order_id || get_post_type( $order_id ) !== 'shop_order' ) {
            wp_send_json_error( array( 'message' => '无效订单ID' ) );
        }

        // 文件上传验证
        if ( !isset( $_FILES['file'] ) || $_FILES['file']['error'] !== UPLOAD_ERR_OK ) {
            wp_send_json_error( array( 'message' => '文件上传错误' ) );
        }

        $file = $_FILES['file'];
        // 仅允许PDF文件
        $mime_type = wp_check_filetype( $file['name'] )['type'];
        if ( $mime_type !== 'application/pdf' ) {
            wp_send_json_error( array( 'message' => '仅支持PDF文件' ) );
        }

        // 生成唯一文件名,避免重复
        $file_ext = pathinfo( $file['name'], PATHINFO_EXTENSION );
        $file_name = 'invoice-order-' . $order_id . '-' . time() . '.' . $file_ext;
        $target_path = $this->uploadDir . '/' . $file_name;

        // 保存文件到私有目录
        if ( move_uploaded_file( $file['tmp_name'], $target_path ) ) {
            update_post_meta( $order_id, 'order_invoice_file', $target_path );
            wp_send_json_success( array( 'file_path' => $target_path ) );
        } else {
            wp_send_json_error( array( 'message' => '无法保存文件' ) );
        }
    }

    function conditionally_attach_order_files_to_order_email( $attachments, $email_id, $object, $email_obj ) {
        if ( 'customer_completed_order' != $email_id ) {
            return $attachments;
        }

        $invoice_path = get_post_meta( $object->get_id(), 'order_invoice_file', true );
        if ( $invoice_path && file_exists( $invoice_path ) ) {
            $attachments[] = $invoice_path;
        }

        return $attachments;
    }
}

$AttachFilesToWooCommerceOrderEmail = AttachFilesToWooCommerceOrderEmail::get_instance();

核心修改说明

  1. 私有目录自动创建与保护

    • 启用私有上传模式,自动创建/wp-content/woocommerce_upload/invoices目录
    • 自动生成.htaccess文件禁止外部直接访问该目录
  2. 替换媒体库上传逻辑

    • 移除原CMB2的file_list字段,改用自定义上传按钮+只读文本框
    • 利用WordPress内置的Plupload库实现文件上传,限制仅支持PDF格式
  3. AJAX上传处理

    • 注册AJAX接口处理文件上传,验证权限、文件类型后保存到私有目录
    • 生成包含订单ID和时间戳的唯一文件名,避免文件覆盖
  4. 邮件附件逻辑调整

    • 直接从订单元数据读取私有目录的文件路径,添加到邮件附件列表

内容的提问来源于stack exchange,提问作者Karnak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 00:05:33