WordPress多站点重写上传目录结构,删除子站点所有站点上传图片被删除,怎么回事?

问题出现在当删除子站点时,WordPress 会递归删除该站点的上传目录。

假设您的上传目录结构被重写到了根目录的 images 文件夹中,WordPress 可能会误删整个 images 目录。

下面我们以上传目录结构被重写到了根目录的 images 文件夹中为例进行解释,并给出解决方案。

我们现在需要实现:让删除子站点时,仅仅删除images中对应的站点目录(如images/site1、images/site2….,删除ID为2的子站点时,仅仅删除images中的site2目录)。

以下是解决方案:

方法1:禁用自动删除上传目录

// 在删除站点时禁用自动删除上传目录
if ( ! function_exists( 'qianmuti_prevent_upload_dir_deletion' ) ) :
    function qianmuti_prevent_upload_dir_deletion($paths, $blog_id) {
        // 获取自定义上传目录
        $upload_dir = wp_upload_dir();
        $custom_upload_path = $upload_dir['basedir'];

        // 从要删除的路径中移除自定义上传目录
        foreach ($paths as $key => $path) {
            if (strpos($path, $custom_upload_path) !== false) {
                unset($paths[$key]);
            }
        }

        return $paths;
    }
endif;
add_filter('wpmu_delete_blog_upload_dir', 'qianmuti_prevent_upload_dir_deletion', 10, 2);

方法2:精确删除对应站点目录

// 在删除站点时只删除对应的站点目录
if ( ! function_exists( 'qianmuti_custom_blog_delete' ) ) :
    function qianmuti_custom_blog_delete($blog_id) {
        $root_path = ABSPATH;
        $custom_dir = '/images';
        $site_specific_dir = $root_path . $custom_dir . '/sites' . $blog_id;

        // 只删除该站点对应的目录
        if (file_exists($site_specific_dir)) {
            // 递归删除目录
            qianmuti_recursive_remove_directory($site_specific_dir);
        }
    }

    function qianmuti_recursive_remove_directory($directory) {
        if (is_dir($directory)) {
            $objects = scandir($directory);
            foreach ($objects as $object) {
                if ($object != "." && $object != "..") {
                    if (is_dir($directory . "/" . $object)) {
                        qianmuti_recursive_remove_directory($directory . "/" . $object);
                    } else {
                        unlink($directory . "/" . $object);
                    }
                }
            }
            rmdir($directory);
        }
    }
endif;

// 在删除博客时触发
add_action('delete_blog', 'qianmuti_custom_blog_delete', 10, 1);

方法3:修改您的上传目录函数(推荐)

同时,建议修改您的上传目录函数,使其更加安全:

if ( ! function_exists( 'qianmuti_revise_upload_dir' ) ) :
    function qianmuti_revise_upload_dir($upload) {
        // 只在需要时修改上传目录(如图片上传)
        if (isset($_POST['action']) && $_POST['action'] === 'upload-attachment') {
            $site_url = get_home_url(get_main_site_id());
            $site_url = str_replace('www', 'img', $site_url);
            $site_id = get_current_blog_id();
            $root_path = ABSPATH;
            $custom_dir = '/images';

            $relpath = ABSPATH;

            // 确保基础目录存在
            if (!file_exists($relpath . $custom_dir)) { 
                wp_mkdir_p($relpath . $custom_dir);
            }

            // 确保站点目录存在
            $site_dir = $relpath . $custom_dir . '/sites' . $site_id;
            if (!file_exists($site_dir)) { 
                wp_mkdir_p($site_dir);
            }

            $upload['path'] = $site_dir . $upload['subdir'];
            $upload['url'] = $site_url . $custom_dir . '/sites' . $site_id . $upload['subdir'];
            $upload['basedir'] = $site_dir;
            $upload['baseurl'] = $site_url . $custom_dir . '/sites' . $site_id;
        }

        return $upload;
    }
endif;
add_filter('upload_dir', 'qianmuti_revise_upload_dir');

完整的解决方案

将以下代码添加到您的主题的 functions.php 文件中:

// 修改上传目录
if ( ! function_exists( 'qianmuti_revise_upload_dir' ) ) :
    function qianmuti_revise_upload_dir($upload) {
        $site_url = get_home_url(get_main_site_id());
        $site_url = str_replace('www', 'img', $site_url);
        $site_id = get_current_blog_id();
        $root_path = ABSPATH;
        $custom_dir = '/images';

        $relpath = ABSPATH;

        if (!file_exists($relpath . $custom_dir)) { 
            wp_mkdir_p($relpath . $custom_dir);
        }

        $site_specific_dir = $relpath . $custom_dir . '/sites' . $site_id;
        if (!file_exists($site_specific_dir)) { 
            wp_mkdir_p($site_specific_dir);
        }

        $upload['path'] = $site_specific_dir . $upload['subdir'];
        $upload['url'] = $site_url . $custom_dir . '/sites' . $site_id . $upload['subdir'];
        $upload['basedir'] = $site_specific_dir;
        $upload['baseurl'] = $site_url . $custom_dir . '/sites' . $site_id;

        return $upload;
    }
endif;
add_filter('upload_dir', 'qianmuti_revise_upload_dir');

// 【选用】删除站点时只删除对应的站点目录,也可以放弃,这样imgages下被删除子站点的目录(如site1、site2、site3....)保留且为空,并无影响
if ( ! function_exists( 'qianmuti_handle_blog_deletion' ) ) :
    function qianmuti_handle_blog_deletion($blog_id) {
        $root_path = ABSPATH;
        $custom_dir = '/images';
        $site_specific_dir = $root_path . $custom_dir . '/sites' . $blog_id;

        if (file_exists($site_specific_dir)) {
            // 使用WP_Filesystem来安全删除目录
            if (!function_exists('WP_Filesystem')) {
                require_once(ABSPATH . 'wp-admin/includes/file.php');
            }
            WP_Filesystem();
            global $wp_filesystem;

            if ($wp_filesystem->exists($site_specific_dir)) {
                $wp_filesystem->delete($site_specific_dir, true);
            }
        }
    }
endif;

add_action('delete_blog', 'qianmuti_handle_blog_deletion', 10, 1);

这样配置后,当删除子站点时,只会删除该站点对应的目录(如 images/sites2),而不会影响其他站点的文件和根目录的 images 文件夹。