本文详解如何将WordPress媒体库迁移到Cloudflare R2,实现低成本、高速度的全球CDN分发。

为什么用Cloudflare R2(而非AWS S3)

| 方案 | 存储成本 | 流量成本 | 速度 |
|------|----------|
| 服务器本地 | 低(含服务器) | 高(服务器带宽) | 中 |
| Cloudflare R2 | $0.015/GB | 免费(无出口费!) | 快(全球CDN) |
| AWS S3 | $0.023/GB | $0.09/GB 出口 | 快 |
| 阿里云OSS | 低 | 中 | 快(国内) |

核心优势:R2无出口费! 这是相比S3的最大优势。

安装WP Offload Media插件(推荐)

购买与安装

WP Offload Media插件$190/年(支持R2
下载:wp-offload-media.zip
cd wp-content/plugins
unzip wp-offload-media.zip
wp plugin activate wp-offload-media

配置R2凭证

后台  Settings  WP Offload Media  Storage Providers  Cloudflare R2

1. 获取R2 API Token
   访问:https://dash.cloudflare.com/  R2  Create API Token
   - Name: wordpress-media
   - Permissions: Object Read & Write
   - TTL: Never

2. 填入凭证:
   Access Key ID: xxxxxxxxxxxxxxxx
   Secret Access Key: xxxxxxxxxxxxxxxxxxxxxxxx
   Bucket: wp-media
   Region: autoR2无需指定区域

3. 保存设置

自定义R2集成(无插件)

安装AWS SDK(R2兼容S3 API)

cd wp-content/plugins
mkdir r2-media
cd r2-media
composer require aws/aws-sdk-php

创建插件核心文件

<?php
/**
 * Plugin Name: R2 Media Offload
 * Description: 将WordPress媒体文件上传到Cloudflare R2
 */

require_once __DIR__ . '/vendor/autoload.php';

use Aws\S3\S3Client;

function get_r2_client() {
    return new S3Client([
        'version' => 'latest',
        'region'  => 'auto',
        'endpoint' => 'https://<account_id>.r2.cloudflarestorage.com',
        'credentials' => [
            'key'    => R2_ACCESS_KEY,
            'secret' => R2_SECRET_KEY,
        ],
    ]);
}

// 上传文件到R2
add_filter('wp_handle_upload', 'upload_to_r2');

function upload_to_r2($upload) {
    $file_path = $upload['file'];
    $file_name = basename($file_path);

    $s3 = get_r2_client();
    $s3->putObject([
        'Bucket' => 'wp-media',
        'Key'    => 'uploads/' . date('Y/m') . '/' . $file_name,
        'Body'   => fopen($file_path, 'rb'),
        'ACL'    => 'public-read',
    ]);

    // 删除本地文件(可选)
    unlink($file_path);

    // 修改附件URL
    $upload['url'] = 'https://<account_id>.r2.cloudflarestorage.com/wp-media/uploads/' . date('Y/m') . '/' . $file_name;

    return $upload;
}

配置wp-config.php

// R2凭证
define('R2_ACCESS_KEY', 'xxxxxxxxxxxxxxxx');
define('R2_SECRET_KEY', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx');
define('R2_BUCKET', 'wp-media');
define('R2_ENDPOINT', 'https://<account_id>.r2.cloudflarestorage.com');
define('R2_URL', 'https://<account_id>.r2.cloudflarestorage.com');

迁移已有媒体库到R2

使用WP-CLI批量迁移

# 安装WP Offload Media CLI扩展
wp package install deliciousbrains/wp-offload-media-wp-cli

# 迁移所有媒体文件到R2
wp offload media migrate --library --bucket=wp-media

# 输出:
# Analyzing media library...
# Found 1234 attachments to migrate.
# Migrating attachment 1/1234: image.jpg... done!
# Migrating attachment 2/1234: document.pdf... done!
# ...
# Migration complete!

自定义迁移脚本(无插件)

add_action('admin_init', 'migrate_existing_media_to_r2');

function migrate_existing_media_to_r2() {
    if (!isset($_GET['migrate_to_r2'])) return;

    $args = [
        'post_type'      => 'attachment',
        'posts_per_page' => -1,
        'post_status'     => 'inherit',
    ];

    $attachments = get_posts($args);
    $s3 = get_r2_client();

    foreach ($attachments as $attachment) {
        $file_path = get_attached_file($attachment->ID);
        $file_name = basename($file_path);

        // 上传到R2
        $s3->putObject([
            'Bucket' => 'wp-media',
            'Key'    => 'uploads/' . date('Y/m', strtotime($attachment->post_date)) . '/' . $file_name,
            'Body'   => fopen($file_path, 'rb'),
            'ACL'    => 'public-read',
        ]);

        // 更新附件URL
        update_post_meta($attachment->ID, '_wp_attached_file', 'uploads/' . date('Y/m') . '/' . $file_name);

        echo 'Migrated: ' . $file_name . '<br>';
    }

    exit;
}

访问:https://example.com/wp-admin/?migrate_to_r2=1

配置R2 + Cloudflare CDN

创建R2 Bucket并启用CDN

1. 访问Cloudflare Dashboard  R2
2. Create Bucketwp-media
3. Settings  Public Access  Enable
4. Copy Bucket URLhttps://<account_id>.r2.cloudflarestorage.com/wp-media

使用Cloudflare CDN加速(无需额外配置)

R2自带Cloudflare CDN!
→ 所有通过R2 URL访问的文件自动走Cloudflare CDN
→ 全球边缘节点缓存
→ 无需配置CNAME

自定义域名(可选)

1. Cloudflare R2  Bucket Settings  Custom Domains
2. 添加自定义域名media.example.com
3. Cloudflare自动配置SSL免费

现在媒体URL变为:https://media.example.com/uploads/2026/05/image.jpg

删除本地文件(节省服务器空间)

配置WP Offload Media

后台  Settings  WP Offload Media  Media Offload

- Remove Files from Server:   (上传后删除本地文件)
- Rewrite Attachment URLs:   (附件URL指向R2)
- Force HTTPS:   (强制HTTPS)

验证本地文件已删除

# 检查uploads目录大小
du -sh wp-content/uploads/
# 输出:4.0K(几乎为空,文件已迁移到R2)

# 检查数据库中的附件URL
SELECT guid FROM wp_posts WHERE post_type='attachment' LIMIT 5;
# 输出:https://<account_id>.r2.cloudflarestorage.com/...

故障排除

问题一:上传失败(凭证错误)

# 测试R2连接
aws s3 ls --endpoint-url https://<account_id>.r2.cloudflarestorage.com

# 错误:Unable to locate credentials
# 解决:检查R2_ACCESS_KEY和R2_SECRET_KEY是否正确

问题二:图片不显示(URL错误)

// 调试附件URL
add_action('wp_head', function() {
    $upload_dir = wp_upload_dir();
    echo '<!-- Upload Base URL: ' . $upload_dir['baseurl'] . ' -->';
});

// 应该输出:https://<account_id>.r2.cloudflarestorage.com/wp-media

问题三:缩略图未生成

// R2不自动生成缩略图!
// 解决:使用WP Offload Media的Image Editing功能
// 或:在本地生成缩略图后再上传到R2

2026年R2 + WordPress趋势

趋势一:R2作为主存储(替代服务器磁盘)

传统架构:
服务器磁盘 → 定期备份到S3

现代架构:
服务器 → 直接上传到R2 → Cloudflare CDN分发
(服务器磁盘只存代码,不存媒体)

趋势二:R2 + Cloudflare Images(智能图片处理)

Cloudflare Images:
- 自动调整尺寸(?width=800)
- 自动转换格式(WebP/AVIF)
- 自动压缩(节省带宽)

URL示例:
https://imagedelivery.net/<account_hash>/<image_id>/width=800

趋势三:R2 + WordPress多站点(共享存储)

// 多站点共享同一个R2 Bucket
// 通过路径区分站点:
// Site 1 → wp-media/site1/uploads/...
// Site 2 → wp-media/site2/uploads/...

define('R2_PATH_PREFIX', 'site' . get_current_blog_id() . '/');

决策建议

  • < 10GB媒体 → 服务器本地存储(简单)
  • 10GB-100GB → R2(省钱,无出口费)
  • > 100GB → R2 + Cloudflare Images(智能处理)
  • 多站点 → R2(共享存储,路径隔离)

总结

Cloudflare R2让WordPress媒体存储成本降低90%。2026年,对于图片/视频密集型网站,R2是必选项。

立即行动:注册Cloudflare R2,将你的媒体库迁移到对象存储!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。