Fuukei图片转换器优化

Naseele docker 75 次阅读 7708 字 预计阅读时间: 35 分钟 发布于 2025-12-02 最后更新于 2025-12-08


AI 摘要

嘿,小伙伴!你的博客封面图转换器罢工了?别急,我帮你找到了问题所在! 就像你在聊天时突然被插话,程序在输出“Done!”后还想改HTTP头,结果就报错了。解决方法很简单:把`break`改成`exit`,让程序优雅退场。 不过这只是治标,图片处理逻辑还有隐藏bug。想知道怎么彻底修复吗?继续往下看吧!

1. 排错

这个主题的封面图在一个单独的文件夹/home/naseele/blog/WP/wordpress/wp-content/uploads/iro_gallery/,从后台-iro主题设置-主页设置-封面设置可以看到

初次使用的时候图片优化和索引都没问题,但是后来我再怎么上传图片,怎么点重建索引和优化都没用,删掉索引文件重建也没用,索引文件里面明明白白有我新上传的图。扒拉了一圈日志也没见报错,不过看到了两个警告:

建立索引的时候:
成功建立索引。
Done! Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/themes/Sakurairo/functions.php:3933) in /var/www/html/wp-includes/functions.php on line 7170 Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/themes/Sakurairo/functions.php:3933) in /var/www/html/wp-includes/functions.php on line 7146;
优化图片的时候:
所有图片一被压缩为webp格式。原图已备份至”backup“文件夹

请在重建索引前进行确认。



Done! Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/themes/Sakurairo/functions.php:3940) in /var/www/html/wp-includes/functions.php on line 7170 Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/themes/Sakurairo/functions.php:3940) in /var/www/html/wp-includes/functions.php on line 7146

我第一反应是,我是不是上传图片忘了改权限了,去检查了一下我传的图:

sudo ls -lha /home/naseele/blog/WP/wordpress/wp-content/uploads/iro_gallery/img/

确定图片所有者是www-data没错,甚至还不放心,在容器里又看了一遍:

docker exec -it wordpress ls -lha /var/www/html/wp-content/uploads/iro_gallery/img

确实不是权限问题,那看看是不是处理用的工具缺失了?

进入容器检查 GD 库信息:

docker exec -it wordpress php -r "print_r(gd_info());"

得到输出:

Array
(
    [GD Version] => bundled (2.1.0 compatible)
    [FreeType Support] => 1
    [FreeType Linkage] => with freetype
    [GIF Read Support] => 1
    [GIF Create Support] => 1
    [JPEG Support] => 1
    [PNG Support] => 1
    [WBMP Support] => 1
    [XPM Support] => 
    [XBM Support] => 1
    [WebP Support] => 1
    [BMP Support] => 1
    [AVIF Support] => 1
    [TGA Read Support] => 1
    [JIS-mapped Japanese Font Support] => 
)

2. 检查并修复functions.php

那就只能是他程序写的有问题了,让我看看那个functions.php怎么个事儿。

找到/wp-content/themes/Sakurairo/functions.php,看看他的3933和3940行是什么:

docker exec -it wordpress sed -n '3930,3945p' /var/www/html/wp-content/themes/Sakurairo/functions.php

可以看到:


        case 'gallery_init':
            include_once('inc/classes/gallery.php');
            $gallery = new Sakura\API\gallery();
            echo $gallery->init();
            echo 'Done!';
            break;

        case 'gallery_webp':
            include_once('inc/classes/gallery.php');
            $gallery = new Sakura\API\gallery();
            echo $gallery->webp();
            echo 'Done!';
            break;
            
        case 'del_exist_theme':
            $current_theme_folder = basename(get_template_directory());
            if ($current_theme_folder != 'Sakurairo') {

看来那个Headers already sent警告是这么来的,在输出文字("Done!")后 WordPress 继续运行并发送 HTTP 头。而HTTP 协议规定,一旦有任何内容被打印(echo),Header就不能再被修改了。

我们把第7行和第14行的break;改成exit;

改完记得确认一下文件所有者,以免出现权限错误。

如果直接修改感觉有危险,可以先备份再修改
# 1. 创建备份目录(如果不存在)
mkdir -p /home/naseele/back

# 2. 从容器中复制文件出来备份
docker cp wordpress:/var/www/html/wp-content/themes/Sakurairo/functions.php /home/naseele/back/functions.php.bak

# 3. 确认备份成功
ls -lh /home/naseele/back/functions.php.bak

然后再修改

# 复制一份用于修改
cp /home/naseele/back/functions.php.bak /home/naseele/back/functions.php.new
# 编辑文件
nano /home/naseele/back/functions.php.new

改完覆盖回去

docker cp /home/naseele/back/functions.php.new wordpress:/var/www/html/wp-content/themes/Sakurairo/functions.php

记得改权限

sudo chown -R 33:33 /home/naseele/blog/WP/wordpress/wp-content/themes/Sakurairo/

3. 修复图片处理逻辑

3.1 错误排查

刚才改那个只是让报错没了,而他处理图片的逻辑好像不太对,我们再看看处理图片的逻辑文件/var/www/html/wp-content/themes/Sakurairo/inc/classes/gallery.php(容器内路径)

看了看他的文件内容

docker exec -it wordpresscat /var/www/html/wp-content/themes/Sakurairo/inc/classes/gallery.php
gallery.php
<?php

// 内建随机图api
// 工作目录在wp-content/uploads/iro_gallery

namespace Sakura\API;

class gallery
{
    private $image_dir;
    private $image_list;
    private $image_folder;
    private $backup_folder;
    private $log = '';

    //定义工作目录
    public function __construct() {
        $upload_dir = wp_get_upload_dir()['basedir'];
        $this->image_dir = $upload_dir . '/iro_gallery';
        $this->image_list = $this->image_dir . '/imglist.json';
        $this->image_folder = $this->image_dir . '/img';
        $this->backup_folder = $this->image_dir . '/backup';
        //创建目录和索引
        $this->init_dirs();
    }

    private function init_dirs() {
        //初始化工作目录
        $dirs = [$this->image_dir, $this->image_folder, $this->backup_folder];

        foreach ($dirs as $dir) {
            if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
                $this->log .= __("Unable to create directory: $dir. Please check permissions.", "sakurairo") . '<br>';
                return $this->log;
            }
        }
        //初始化索引
        if (!file_exists($this->image_list)) {
            if (!touch($this->image_list)) {
                $this->log .= __("Unable to create file: {$this->image_list}. Please check permissions.", "sakurairo") . '<br>';
                return $this->log;
            }
        }
    }

    //生成索引并进行分拣
    public function init() {
        $allowedExtensions = ['jpg', 'jpeg', 'bmp', 'png', 'webp', 'gif'];
        $imageFiles = ['long' => [], 'wide' => []];

        $allFiles = $this->get_all_files($this->image_folder);

        foreach ($allFiles as $filePath) {
            if (in_array(strtolower(pathinfo($filePath, PATHINFO_EXTENSION)), $allowedExtensions)) {
                //获取图片信息进行分拣
                $imageSize = @getimagesize($filePath);

                if ($imageSize === false) {
                    continue;
                }

                $width = $imageSize[0];
                $height = $imageSize[1];

                $filePath = str_replace($this->image_folder, '/iro_gallery/img', $filePath);

                //根据比例分拣图片
                if ($width / $height < 9 / 10) {
                    $imageFiles['long'][] = $filePath;
                } else {
                    $imageFiles['wide'][] = $filePath;
                }
            }
        }

        //保存索引
        file_put_contents($this->image_list, json_encode($imageFiles));

        $this->log .= __("Successfully initialized the index.", "sakurairo") . '<br>';
        return $this->log;
    }

    //遍历目录方法
    private function get_all_files($directory) {
        $result = [];
        $files = scandir($directory);

        foreach ($files as $file) {
            if ($file === '.' || $file === '..') {
                continue;
            }

            $filePath = $directory . '/' . $file;
            if (is_dir($filePath)) {
                $result = array_merge($result, $this->get_all_files($filePath));
            } else {
                $result[] = $filePath;
            }
        }

        return $result;
    }

    //webp优化步骤
    public function webp() {
        $this->log = '';
        $allowedExtensions = ['jpg', 'jpeg', 'png', 'webp', 'gif'];

        //检查backup目录是否有内容
        if (!is_dir($this->backup_folder) || count(scandir($this->backup_folder)) <= 2) {
            //没有则执行备份步骤
            if (!rename($this->image_folder, $this->backup_folder)) {
                $this->log .= __("The target directory is not accessible. Please check the permission settings.", "sakurairo") . '<br>';
                return $this->log;
            }
            if (!mkdir($this->image_folder, 0755, true)) {
                $this->log .= __("The target directory is not accessible. Please check the permission settings.", "sakurairo") . '<br>';
                return $this->log;
            }
            $this->log .= __("Successfully backed up images from the 'img' folder to the 'backup' folder.", "sakurairo") . '<br>';
        } else {
            $this->log .= __("Detected content in the 'backup' folder. Verifying and attempting to restore conversion operations.", "sakurairo") . '<br>';
        }

        $allFiles = $this->get_all_files($this->backup_folder);

        foreach ($allFiles as $backupPath) {
            if (!in_array(strtolower(pathinfo($backupPath, PATHINFO_EXTENSION)), $allowedExtensions)) {
                continue;
            }

            //生成 WebP 文件的相对路径和目标路径
            $relativePath = str_replace($this->backup_folder . '/', '', $backupPath);  //相对路径
            $pathInfo = pathinfo($relativePath);
            $webpPath = $this->image_folder . '/' . $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '.webp';

            //跳过已存在的WebP文件(从上个断点继续转换)
            if (file_exists($webpPath)) {
                $this->log .= __("Skipped file: {$relativePath}, a webp image with the same name already exists.", "sakurairo") . '<br>';
                continue;
            }

            //确保目标子目录存在
            $targetDir = dirname($webpPath);
            if (!is_dir($targetDir)) {
                mkdir($targetDir, 0755, true);
            }

            //转换文件
            $this->convert_to_webp($backupPath, $webpPath);
        }

        $this->log .= __("All images have been compressed to WebP format. The original files are stored in the 'backup' folder.<br> Please confirm correctness before reinitializing the index.<br>", "sakurairo") . '<br>';

        return $this->log;
    }

    //webp优化方法
    private function convert_to_webp($source, $webpPath) {
        $extension = strtolower(pathinfo($source, PATHINFO_EXTENSION));

        switch ($extension) {
            case 'jpg':
            case 'jpeg':
                $image = imagecreatefromjpeg($source);
                break;
            case 'png':
                $image = imagecreatefrompng($source);
                break;
            case 'gif':
                $image = imagecreatefromgif($source);
                break;
            case 'webp':
                $image = imagecreatefromwebp($source);
                break;
            default:
                $this->log .= __("Unsupported file type: $source .", "sakurairo") . '<br>';
        }

        if ($image) {
            imagewebp($image, $webpPath, 80);
            imagedestroy($image);
            $this->log .= __("Successfully converted to WebP: $source .", "sakurairo") . '<br>';
            return $this->log;
        } else {
            $this->log .= __("Failed to convert file: $source .", "sakurairo") . '<br>';
            return $this->log;
        }
    }

    //获取图片
    public function get_image() {
        $imgParam = isset($_GET['img']) ? sanitize_text_field($_GET['img']) : '';
        $imageList = json_decode(file_get_contents($this->image_list), true);

        if (empty($imageList)) {
            $this->init(true);
        }

        $error_info = array(
            'status' => 500,
            "success" => false,
            'message' => __("No images found. Please contact the administrator to check if images exist in the 'iro_gallary' directory and ensure the directory is readable and writable.", "sakurairo") . '<br>',
        );
        $error = new \WP_REST_Response($error_info, 500);
        $error->set_status(500);

        if (!empty($imageList)) {
            //img参数优先获取long或wide
            if ($imgParam == 'l' && !empty($imageList['long'])) {
                $random_image = $imageList['long'][array_rand($imageList['long'])];
            } else {
                if ($imgParam == 'w' && !empty($imageList['wide'])) {
                    $random_image = $imageList['wide'][array_rand($imageList['wide'])];
                } else {
                    $all_images = array_merge($imageList['long'] ?? [], $imageList['wide'] ?? []);
                    if (!empty($all_images)) {
                        $random_image = $all_images[array_rand($all_images)];
                    } else {
                        return $error;
                    }
                }
            }

            $random_image = wp_get_upload_dir()['baseurl'] . $random_image;

            wp_redirect($random_image, 302);
            exit;
        } else {
            return $error;
        }
    }
}
?>

看了之后大受震撼,这里有两个大问题:

首先是逻辑死穴: 这段代码的设计逻辑是一次性迁移,而非 “持续优化”

  • 首先是代码第110行:if (!is_dir($this->backup_folder) || count(scandir($this->backup_folder)) <= 2)。它的逻辑是:只有当 backup 文件夹是的时候,它才会把 img文件夹里的原图移进去。而我们现在已经第执行过一次图片优化,backup 文件夹里已经有老图了。所以脚本运行到这里,判断backup文件夹不为空,直接跳过了移动新图片到backup文件夹的步骤。但是文档明明写的是“初始化后将图片放置在 `wp-content/uploads/iro_gallery/img` 文件夹,然后点击重建索引。”好怪,改一下吧……
  • 然后是第126行:它开始遍历 backup 文件夹进行转换。但我们的新图片还在 img 文件夹里傻等着呢,它根本不看 img 文件夹……

其次(这一点我没看出来,毕竟php我不熟,gemini 3.0 pro复盘的时候给我指出来了,还提了优化建议)这样写还有性能隐患: 代码第 164-180行 使用的是 PHP 自带的 imagecreatefromjpeg 等函数:

  • 这非常消耗内存。处理一张 4K 图片可能瞬间耗尽 Docker 容器默认分配的 PHP 内存(通常 128MB),导致脚本静默中断。
  • 建议安装并使用 cwebp 工具,它的效率要高 100 倍,而且不会爆内存。

3.2 修复

3.2.1 安装cwebp

那我们先搞一个cwebp吧。

先找个地方放,我放到/home/naseele/bin了。

mkdir -p /home/naseele/bin
cd /home/naseele/bin

# 下载预编译好的 webp 工具 (Google 官方提供的 Linux 版)
wget https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.3.2-linux-x86-64.tar.gz

# 解压
tar -xzf libwebp-1.3.2-linux-x86-64.tar.gz

# 把 cwebp 拿出来
mv libwebp-1.3.2-linux-x86-64/bin/cwebp .

# 给执行权限
chmod +x cwebp

# 清理垃圾(清理前请确保名字正确,建议别用这个通配符而是手动删掉压缩包和解压出来的文件夹)
# 只保留我们单独拎出来的cwebp即可
rm -rf libwebp-1.3.2-linux-x86-64*

修改我们的docker-compose.yml,找到 wordpress 服务部分,在 volumes 下面加一行映射,把cwebp所在的路径映射进去:

services:
  wordpress:
    # ... 其他配置不变 ...
    volumes:
      - ./wordpress:/var/www/html
      # ... 其他映射 ...
      # 【新增这一行】把宿主机的 cwebp 直接映射到容器的 /usr/bin/cwebp
      - /home/naseele/bin/cwebp:/usr/bin/cwebp

注意缩进,不要搞错了!

3.2.2 覆写图片处理逻辑

然后改一下 gallery.php 文件,把逻辑改成:

// 旧代码思维:
如果 (backup文件夹是空的) {
     img 里的图移到 backup;
} 否则 {
    // 认为“由于 backup 不为空,说明之前已经移动过了”
    // 于是直接开始转换 backup 里的图,完全不看 img 里有没有新图!
}

// 我们修改后的思维:
不管 backup 空不空,先去 img 里巡逻一遍;
如果 (img 里有新 jpg/png) {
    把它搬到 backup ; // 确保新图入库
}
然后遍历 backup,把还没转成 webp 的图转出来。

新建一个名为gallery_new.php的文件,然后写入以下内容(请自行展开查看)

gallery_new.php

<?php

// 内建随机图api
// 工作目录在wp-content/uploads/iro_gallery

namespace Sakura\API;

class gallery
{
    private $image_dir;
    private $image_list;
    private $image_folder;
    private $backup_folder;
    private $log = '';

    //定义工作目录
    public function __construct() {
        $upload_dir = wp_get_upload_dir()['basedir'];
        $this->image_dir = $upload_dir . '/iro_gallery';
        $this->image_list = $this->image_dir . '/imglist.json';
        $this->image_folder = $this->image_dir . '/img';
        $this->backup_folder = $this->image_dir . '/backup';
        //创建目录和索引
        $this->init_dirs();
    }

    private function init_dirs() {
        //初始化工作目录
        $dirs = [$this->image_dir, $this->image_folder, $this->backup_folder];

        foreach ($dirs as $dir) {
            if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
                $this->log .= __("Unable to create directory: $dir. Please check permissions.", "sakurairo") . '<br>';
                return $this->log;
            }
        }
        //初始化索引
        if (!file_exists($this->image_list)) {
            if (!touch($this->image_list)) {
                $this->log .= __("Unable to create file: {$this->image_list}. Please check permissions.", "sakurairo") . '<br>';
                return $this->log;
            }
        }
    }

    //生成索引并进行分拣
    public function init() {
        $allowedExtensions = ['jpg', 'jpeg', 'bmp', 'png', 'webp', 'gif'];
        $imageFiles = ['long' => [], 'wide' => []];

        $allFiles = $this->get_all_files($this->image_folder);

        foreach ($allFiles as $filePath) {
            if (in_array(strtolower(pathinfo($filePath, PATHINFO_EXTENSION)), $allowedExtensions)) {
                //获取图片信息进行分拣
                $imageSize = @getimagesize($filePath);

                if ($imageSize === false) {
                    continue;
                }

                $width = $imageSize[0];
                $height = $imageSize[1];

                $filePath = str_replace($this->image_folder, '/iro_gallery/img', $filePath);

                //根据比例分拣图片
                if ($width / $height < 9 / 10) {
                    $imageFiles['long'][] = $filePath;
                } else {
                    $imageFiles['wide'][] = $filePath;
                }
            }
        }

        //保存索引
        file_put_contents($this->image_list, json_encode($imageFiles));

        $this->log .= __("Successfully initialized the index.", "sakurairo") . '<br>';
        return $this->log;
    }

    //遍历目录方法
    private function get_all_files($directory) {
        $result = [];
        $files = scandir($directory);

        foreach ($files as $file) {
            if ($file === '.' || $file === '..') {
                continue;
            }

            $filePath = $directory . '/' . $file;
            if (is_dir($filePath)) {
                $result = array_merge($result, $this->get_all_files($filePath));
            } else {
                $result[] = $filePath;
            }
        }

        return $result;
    }

    //webp优化步骤
    public function webp() {
        $this->log = '';
        $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif']; // 原图格式,不需要webp

        // 【修改1】 增加主动扫描 img 目录逻辑,把新上传的图片移动到 backup
        $newFiles = $this->get_all_files($this->image_folder);
        $moved_count = 0;
        
        foreach ($newFiles as $newFile) {
            $ext = strtolower(pathinfo($newFile, PATHINFO_EXTENSION));
            // 如果是原图格式 (不是webp)
            if (in_array($ext, $allowedExtensions)) {
                // 计算相对路径,保持目录结构
                $relativePath = str_replace($this->image_folder . '/', '', $newFile);
                $targetBackupPath = $this->backup_folder . '/' . $relativePath;
                
                // 确保 backup 中的子目录存在
                $targetBackupDir = dirname($targetBackupPath);
                if (!is_dir($targetBackupDir)) {
                    mkdir($targetBackupDir, 0755, true);
                }

                // 移动文件
                if (rename($newFile, $targetBackupPath)) {
                    $moved_count++;
                }
            }
        }
        
        if ($moved_count > 0) {
            $this->log .= "Moved $moved_count new images from 'img' to 'backup'.<br>";
        }

        // 开始处理 backup 目录
        $allFiles = $this->get_all_files($this->backup_folder);

        foreach ($allFiles as $backupPath) {
            if (!in_array(strtolower(pathinfo($backupPath, PATHINFO_EXTENSION)), $allowedExtensions)) {
                continue;
            }

            //生成 WebP 文件的相对路径和目标路径
            $relativePath = str_replace($this->backup_folder . '/', '', $backupPath);  //相对路径
            $pathInfo = pathinfo($relativePath);
            $webpPath = $this->image_folder . '/' . $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '.webp';

            //跳过已存在的WebP文件(从上个断点继续转换)
            if (file_exists($webpPath)) {
                // $this->log .= __("Skipped file: {$relativePath}, a webp image with the same name already exists.", "sakurairo") . '<br>';
                continue;
            }

            //确保目标子目录存在
            $targetDir = dirname($webpPath);
            if (!is_dir($targetDir)) {
                mkdir($targetDir, 0755, true);
            }

            //转换文件
            $this->convert_to_webp($backupPath, $webpPath);
        }

        $this->log .= __("All images have been compressed to WebP format. The original files are stored in the 'backup' folder.<br> Please confirm correctness before reinitializing the index.<br>", "sakurairo") . '<br>';

        return $this->log;
    }

    //webp优化方法
    private function convert_to_webp($source, $webpPath) {
        // 【修改2】 使用 cwebp 命令行工具,效率更高,支持 4K
        // 使用 escapeshellarg 防止文件名中的空格导致命令失效
        $cmd = "cwebp -q 75 " . escapeshellarg($source) . " -o " . escapeshellarg($webpPath) . " 2>&1";
        
        $output = [];
        $return_var = 0;
        exec($cmd, $output, $return_var);

        if ($return_var === 0) {
            $this->log .= __("Successfully converted to WebP: $source .", "sakurairo") . '<br>';
            return $this->log;
        } else {
            // 如果 cwebp 失败 (比如不是受支持的图片),尝试降级回 PHP 处理 (或者直接报错)
            $this->log .= __("Failed to convert file (cwebp error): $source .", "sakurairo") . '<br>';
            return $this->log;
        }
    }

    //获取图片
    public function get_image() {
        $imgParam = isset($_GET['img']) ? sanitize_text_field($_GET['img']) : '';
        $imageList = json_decode(file_get_contents($this->image_list), true);

        if (empty($imageList)) {
            $this->init(true);
        }

        $error_info = array(
            'status' => 500,
            'success' => false,
            'message' => __("No images found. Please contact the administrator to check if images exist in the 'iro_gallary' directory and ensure the directory is readable and writable.", "sakurairo") . '<br>',
        );
        $error = new \WP_REST_Response($error_info, 500);
        $error->set_status(500);

        if (!empty($imageList)) {
            //img参数优先获取long或wide
            if ($imgParam == 'l' && !empty($imageList['long'])) {
                $random_image = $imageList['long'][array_rand($imageList['long'])];
            } else {
                if ($imgParam == 'w' && !empty($imageList['wide'])) {
                    $random_image = $imageList['wide'][array_rand($imageList['wide'])];
                } else {
                    $all_images = array_merge($imageList['long'] ?? [], $imageList['wide'] ?? []);
                    if (!empty($all_images)) {
                        $random_image = $all_images[array_rand($all_images)];
                    } else {
                        return $error;
                    }
                }
            }

            $random_image = wp_get_upload_dir()['baseurl'] . $random_image;

            wp_redirect($random_image, 302);
            exit;
        } else {
            return $error;
        }
    }
}
?>

之后覆盖容器内文件:

docker cp gallery_new.php wordpress:/var/www/html/wp-content/themes/Sakurairo/inc/classes/gallery.php

记得改新文件的权限:

sudo chown -R 33:33 wordpress/wp-content/themes/Sakurairo/inc/classes/gallery.php

3.2.3 重启容器

之后我们可以重启容器了:

cd 我们的docker-compose.yml所在路径
docker compose down
docker compose up -d 

大功告成,可以手动测试一下,原图片正确的被移动到backup文件夹,压缩效果也很好。

4. 修改压缩质量(可选)

如果感觉压缩效果不满意,可以改压缩质量:

直接改那个gallery_new.php文件,找到倒数20行左右的convert_to_webp(nano可以使用ctrl+v快速到文件结尾,太长的文件可能要多敲几次,甚至是长按)

//webp优化方法
    private function convert_to_webp($source, $webpPath) {
        // 【修改这里】  -q 后面的 75 改成 80  85
        $cmd = "cwebp -q 75 " . escapeshellarg($source) . " -o " . escapeshellarg($webpPath) . " 2>&1";
        
        // ...

把75改成80或者85,看你个人需求。

之后覆盖回去

docker cp ~/b/WP/gallery_new.php wordpress:/var/www/html/wp-content/themes/Sakurairo/inc/classes/gallery.php

修改文件权限:

docker exec wordpress chown -R www-data:www-data /var/www/html/wp-content/themes/Sakurairo/inc/classes/gallery.php

5. 尾声

最后的最后,提醒一下

每次上传图片的时候记得执行一下

docker exec wordpress chown -R www-data:www-data /var/www/html/wp-content/uploads/iro_gallery