|
|
||
|---|---|---|
| config | ||
| src | ||
| .gitignore | ||
| README.md | ||
| composer.json | ||
| flysystem-offload.php | ||
README.md
Flysystem Offload
Flysystem Offload es un plugin minimalista de WordPress que sustituye el almacenamiento local por un backend remoto usando Flysystem v3. Inspirado por el estilo ligero de “S3 Uploads”, se concentra en proporcionar una integración transparente, sin panel de administración, y con compatibilidad total con el flujo estándar de medios de WordPress.
Características
- Registro temprano del stream wrapper para redirigir
wp-content/uploadsa almacenamiento remoto. - Generación automática de URLs públicas coherentes con el prefijo de bucket.
- Cabeceras
Cache-ControlyExpiresaplicadas en las subidas. - Limpieza remota de adjuntos al eliminarlos desde WordPress.
- Configuración declarativa vía
config/flysystem-offload.php.
Requisitos
- WordPress 6.5 o superior.
- PHP 8.2 o superior (probado en PHP 8.4).
- Extensiones PHP:
json,curl,mbstring. - Credenciales válidas para un servicio S3 compatible.
- Composer para instalar dependencias (AWS SDK).
Instalación
- Clona el repositorio en
wp-content/plugins/flysystem-offload. - Ejecuta
composer installdentro del plugin si el SDK no está en el proyecto. - Copia
config/flysystem-offload.example.phpaconfig/flysystem-offload.php. - Ajusta las claves del archivo de configuración.
- Activa el plugin desde el dashboard de WordPress o vía
wp plugin activate flysystem-offload.
Configuración básica (config/flysystem-offload.php)
<?php
return [
'driver' => 's3',
'visibility' => 'public',
'stream' => [
'protocol' => 'flysystem',
'root_prefix' => '',
'host' => 'uploads',
],
'uploads' => [
'base_url' => getenv('FLYSYSTEM_OFFLOAD_BASE_URL') ?: 'https://offload.brasdrive.com.br',
'delete_remote' => true,
'prefer_local_for_missing' => false,
'cache_control' => 'public, max-age=31536000, immutable',
'expires_ttl' => 31536000,
'expires' => null,
],
'admin' => [
'enabled' => false,
],
's3' => [
'key' => getenv('AWS_ACCESS_KEY_ID') ?: null,
'secret' => getenv('AWS_SECRET_ACCESS_KEY') ?: null,
'session_token' => getenv('AWS_SESSION_TOKEN') ?: null,
'region' => getenv('AWS_DEFAULT_REGION') ?: 'us-east-1',
'bucket' => getenv('FLYSYSTEM_OFFLOAD_BUCKET') ?: 'your-bucket-name',
'prefix' => getenv('FLYSYSTEM_OFFLOAD_PREFIX') ?: 'wordpress',
'endpoint' => getenv('FLYSYSTEM_OFFLOAD_ENDPOINT') ?: null,
'use_path_style_endpoint' => (bool) (getenv('AWS_USE_PATH_STYLE_ENDPOINT') ?: false),
'version' => 'latest',
'options' => [],
'default_options' => [],
'acl_public' => 'public-read',
'acl_private' => 'private',
],
];
Normalización de configuración
Plugin::normaliseConfig() establece valores por defecto, garantiza que uploads.base_url termine sin /, y fusiona s3.prefix, stream.root_prefix y stream.host para producir el prefijo remoto final.
Funcionamiento del stream wrapper
- El filtro
upload_dirdevuelve rutas comoflysystem://uploads/2025/01. MediaHooksreescribe automáticamentewp_get_attachment_urlpara apuntar a la ruta remota (base_url + prefijo + archivo).- El prefijo remoto resultante combina
s3.prefix,stream.root_prefixystream.hostpara reflejar exactamente la clave almacenada en el bucket (ej.:wordpress/uploads/2025/01/file.jpg).
Cabeceras de caché
El adaptador S3 añade Cache-Control y Expires a través de las opciones por defecto de Flysystem:
$defaultOptions['CacheControl'] = 'public, max-age=31536000, immutable';
$defaultOptions['Expires'] = gmdate('D, d M Y H:i:s \G\M\T', time() + 31536000);
Puede personalizarse mediante el filtro flysystem_offload_s3_default_write_options.
Escenario bucket público (probado con IDrive e2)
- Marcar bucket como público en la consola de IDrive e2.
- Aplicar policy simple (la UI sólo acepta una versión sin
Condition).
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicReadUploads",
"Effect": "Allow",
"Principal": { "AWS": "*" },
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::flysystem-offload/wordpress/uploads/*"
]
}
]
}
- Configurar CORS si el panel o el frontend cargan las imágenes desde otro origen.
[
{
"AllowedOrigins": [
"https://offload.brasdrive.com.br"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedHeaders": [
"*"
],
"ExposeHeaders": [
"ETag",
"Last-Modified",
"x-amz-request-id",
"x-amz-id-2"
],
"AllowCredentials": false,
"MaxAgeSeconds": 86400
}
]
Escenario recomendado: bucket privado + Cloudflare
- Bucket privado
- Mantenerlo cerrado; permitir
s3:GetObjectsólo a IPs de Cloudflare. - Aplicar policy vía CLI (
aws s3api put-bucket-policy). Ejemplo conConditionpor IP (mantén la lista actualizada con la APIGET /client/v4/ips):
- Mantenerlo cerrado; permitir
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudflareAccess",
"Effect": "Allow",
"Principal": { "AWS": "*" },
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::flysystem-offload/wordpress/uploads/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"173.245.48.0/20",
"103.21.244.0/22"
// ...
]
}
}
}
]
}
-
Cloudflare
- CNAME
offload.brasdrive.com.br→ endpoint IDrive (ej.u8k6.va11.idrivee2-9.com). - Proxy naranja activado; SSL universal.
- Reglas WAF o Rate Limiting opcionales.
- CNAME
-
WordPress
uploads.base_url = 'https://offload.brasdrive.com.br'.- Mantener
prefer_local_for_missing = false.
-
Automatización
- Script/cron que consulte la API de Cloudflare, regenere la policy con los nuevos rangos IP y la aplique (controlando con
etag).
- Script/cron que consulte la API de Cloudflare, regenere la policy con los nuevos rangos IP y la aplique (controlando con
-
Caché y purgas
- Cloudflare respeta las cabeceras
Cache-ControlyExpires. - Purgar desde la consola de Cloudflare cuando sea necesario (por URL o caché completa).
- Cloudflare respeta las cabeceras
Compatibilidad de backends
Actualmente Flysystem Offload proporciona el adaptador S3. El código está preparado para admitir otros backends soportados por Flysystem (WebDAV, SFTP, etc.), pero aún deben agregarse adaptadores específicos (WebdavAdapter, SftpAdapter, etc.) y sus respectivas configuraciones. Esto forma parte del plan inmediato de ampliación: se crearán clases adicionales en src/Filesystem/Adapters/, se extenderá la factoría de adaptadores y se actualizará la documentación para cada backend.
Notas sobre IDrive e2
- Para habilitar un bucket público reciente, es necesario contactar soporte.
- El editor web de políticas no soporta
Condition; aplicar policies complejas via CLI/API. - CORS sí puede configurarse desde la UI mientras se respete el formato simple.
- Usa el endpoint regional del bucket como
endpointen configuración y CLI.
Solución de problemas
- URLs sin prefijo: actualizar a la versión reciente de
MediaHooks.php.- Confirmar
s3.prefix,stream.root_prefix,stream.host.
- Confirmar
- Falta de
Cache-Control/Expires: revisarconfigys3.default_options. - Error
_.filteren la UI: bug del formulario; usar CLI. - Archivos inaccesibles con bucket privado: verificar policy, rangos Cloudflare, CNAME activo.
Contribuciones
Se aceptan PRs. Mantén el enfoque minimalista, sin panel de administración, y prioriza compatibilidad con el flujo nativo de WordPress. Roadmap cercano: añadir adaptadores para otros drivers Flysystem.
Licencia
MIT. Revisa el archivo LICENSE.