{"id":371873,"date":"2026-09-24T19:26:48","date_gmt":"2026-09-24T19:26:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/zloj-s3\/"},"modified":"2026-09-24T19:26:16","modified_gmt":"2026-09-24T19:26:16","slug":"zloj-s3","status":"publish","type":"plugin","link":"https:\/\/frp.wordpress.org\/plugins\/zloj-s3\/","author":14555966,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.4.7","stable_tag":"1.4.7","tested":"7.1.2","requires":"6.2","requires_php":"8.1","requires_plugins":null,"header_name":"Zloj S3","header_author":"zloj.ru","header_description":"Offload WordPress media to S3-compatible object storage.","assets_banners_color":"090c11","last_updated":"2026-09-24 19:26:16","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":49,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.4.7":{"tag":"1.4.7","author":"zloj.ru","date":"2026-09-24 19:26:16","revision":3711921}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3712689,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3712689,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3712689,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3712689,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.4.7"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[84,46891,217,2216,85],"plugin_category":[50,59],"plugin_contributors":[282554],"plugin_business_model":[],"class_list":["post-371873","plugin","type-plugin","status-publish","hentry","plugin_tags-media","plugin_tags-offload","plugin_tags-s3","plugin_tags-storage","plugin_tags-uploads","plugin_category-media","plugin_category-utilities-and-tools","plugin_contributors-zlojru","plugin_committers-zlojru"],"banners":{"banner":"https:\/\/ps.w.org\/zloj-s3\/assets\/banner-772x250.png?rev=3712689","banner_2x":"https:\/\/ps.w.org\/zloj-s3\/assets\/banner-1544x500.png?rev=3712689","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/zloj-s3\/assets\/icon-128x128.png?rev=3712689","icon_2x":"https:\/\/ps.w.org\/zloj-s3\/assets\/icon-256x256.png?rev=3712689","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Zloj S3 sends uploaded media to an S3-compatible bucket, rewrites attachment URLs, and removes objects when attachments are deleted.<\/p>\n\n<p>It is built for any S3-compatible endpoint (not only Amazon), can lock credentials with PHP constants, and can migrate existing uploads in AJAX batches with an optional cleanup of identical local copies.<\/p>\n\n<p>The plugin stays idle until the required settings are filled: API host, public host, bucket, access key, and secret key.<\/p>\n\n<p>You can lock any setting with a PHP constant. When a constant is defined it wins over the value on the settings screen, and that field becomes read-only.<\/p>\n\n<p>Access and secret keys are shown as asterisks in the admin, not as the real values.<\/p>\n\n<h4>Constants<\/h4>\n\n<ul>\n<li><code>ZLOJ_S3_ENABLED<\/code><\/li>\n<li><code>ZLOJ_S3_PRIVATE_UPLOAD<\/code><\/li>\n<li><code>ZLOJ_S3_TRASH<\/code> (move the primary attachment to a trash prefix; default on)<\/li>\n<li><code>ZLOJ_S3_API_URL<\/code><\/li>\n<li><code>ZLOJ_S3_API_HTTPS<\/code> (HTTPS for the API host; default on; <code>ZLOJ_S3_HTTPS_URL<\/code> is used if this is not defined)<\/li>\n<li><code>ZLOJ_S3_API_PATH_STYLE<\/code> (set to <code>path<\/code> for path-style API URLs: <code>host\/bucket\/key<\/code>; default <code>path<\/code>)<\/li>\n<li><code>ZLOJ_S3_REGION<\/code> (signing region; default <code>us-east-1<\/code>)<\/li>\n<li><code>ZLOJ_S3_PUBLIC_URL<\/code><\/li>\n<li><code>ZLOJ_S3_PUBLIC_HTTPS<\/code> (HTTPS for public URLs; default on; <code>ZLOJ_S3_HTTPS_URL<\/code> is used if this is not defined)<\/li>\n<li><code>ZLOJ_S3_BUCKET<\/code><\/li>\n<li><code>ZLOJ_S3_ACCESS_KEY<\/code><\/li>\n<li><code>ZLOJ_S3_SECRET_KEY<\/code><\/li>\n<li><code>ZLOJ_S3_PUBLIC_PATH_STYLE<\/code> (set to <code>path<\/code> for path-style public URLs: <code>host\/bucket\/key<\/code>)<\/li>\n<li><code>ZLOJ_S3_COMPAT_NO_CHECKSUM<\/code> (skip CRC32 checksum headers)<\/li>\n<li><code>ZLOJ_S3_COMPAT_NO_TAGGING<\/code> (do not send object tags)<\/li>\n<li><code>ZLOJ_S3_COMPAT_CANNED_ACL<\/code> (send public-read \/ private ACL)<\/li>\n<li><code>ZLOJ_S3_COMPAT_NO_EXPECT<\/code> (disable Expect: 100-continue)<\/li>\n<\/ul>\n\n<h4>AWS SDK<\/h4>\n\n<p>If <code>Aws\\S3\\S3Client<\/code> is already loaded, that copy is used. Otherwise the plugin loads the trimmed AWS SDK bundled under <code>vendor\/<\/code> (S3 only, not the full 40+ MB package).<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin is an interface to the S3-compatible object storage <strong>you configure<\/strong>. It does not send files or credentials to the plugin author.<\/p>\n\n<p>When offload is enabled, or when you run a connection test or a bulk upload, the plugin contacts the API host and public host you entered. It sends media file contents and the access key \/ secret key needed to authenticate to that storage.<\/p>\n\n<p>If you use Amazon S3:<\/p>\n\n<ul>\n<li>Service: https:\/\/aws.amazon.com\/s3\/<\/li>\n<li>Terms of Service: https:\/\/aws.amazon.com\/service-terms\/<\/li>\n<li>Privacy Policy: https:\/\/aws.amazon.com\/privacy\/<\/li>\n<\/ul>\n\n<p>If you use another S3-compatible provider, read that provider\u2019s terms of service and privacy policy before saving credentials. An account with the storage provider is required.<\/p>\n\n<h3>Copyright<\/h3>\n\n<p>Zloj S3, Copyright 2026 zloj.ru.<\/p>\n\n<p>Free to use. Copies and modifications must keep this license and all copyright notices. Licensed under GPLv2 or later; see <code>license.txt<\/code>. Third-party libraries keep their own GPL-compatible licenses and copyright files.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>zloj-s3<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Open Settings \u2192 Zloj S3 and fill in the storage details, or define the constants above.<\/li>\n<li>Use the connection test button (no page reload). It uploads a random file, checks the public URL body for the random hash, then deletes the file.<\/li>\n<li>To migrate existing files, use <strong>Upload, keep local files<\/strong> or <strong>Upload and remove local files<\/strong>. Cleanup deletes the local file after a successful upload (or when it already matches storage). <strong>Find conflicts<\/strong> only compares local files with storage. The job runs in AJAX batches.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20the%20plugin%20run%20without%20settings%3F\"><h3>Does the plugin run without settings?<\/h3><\/dt>\n<dd><p>No. Offload does nothing until the required fields are filled and offload is enabled.<\/p><\/dd>\n<dt id=\"why%20are%20some%20fields%20read-only%3F\"><h3>Why are some fields read-only?<\/h3><\/dt>\n<dd><p>Those values are defined as PHP constants. Remove or undefine the constant to edit the field on the settings screen.<\/p><\/dd>\n<dt id=\"do%20i%20need%20the%20full%20aws%20sdk%3F\"><h3>Do I need the full AWS SDK?<\/h3><\/dt>\n<dd><p>No. The bundled copy is reduced to the S3 client. If your site already provides <code>aws\/aws-sdk-php<\/code>, the bundled copy is not loaded.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.4.7<\/h4>\n\n<ul>\n<li>Move the SDK trim script out of the plugin package into the separate builder repo.<\/li>\n<li>Drop vendor development files from the distribution, including format-check.py.<\/li>\n<\/ul>\n\n<h4>1.4.6<\/h4>\n\n<ul>\n<li>Let WordPress.org load translations; do not ship locale files or call load_plugin_textdomain.<\/li>\n<li>Register settings with an explicit sanitize callback and check AJAX nonces via check_ajax_referer.<\/li>\n<li>Block direct HTTP access to the SDK trim script.<\/li>\n<\/ul>\n\n<h4>1.4.5<\/h4>\n\n<ul>\n<li>Rewrite srcset, intermediate sizes, and MetaSlider crop URLs, not only wp_get_attachment_url.<\/li>\n<li>Upload MetaSlider custom crops that skip image_make_intermediate_size.<\/li>\n<\/ul>\n\n<h4>1.4.4<\/h4>\n\n<ul>\n<li>Do not resume a bulk upload just because the settings page was opened.<\/li>\n<li>Clear a stale running flag when no sync lock is held.<\/li>\n<li>Do not stop a bulk upload when a step lock is still held; send the next request.<\/li>\n<li>Overwrite a sync lock older than twice the PHP max execution time.<\/li>\n<\/ul>\n\n<h4>1.4.3<\/h4>\n\n<ul>\n<li>Lock public path-style with <code>ZLOJ_S3_PUBLIC_PATH_STYLE<\/code>, not <code>ZLOJ_S3_PATH_STYLE<\/code>.<\/li>\n<\/ul>\n\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>Retry failed sync batches with an idempotent request id and a single in-flight handler.<\/li>\n<li>Keep separate progress per mode and ask whether to continue or start over.<\/li>\n<li>Drop the 40-file batch cap; each request now uses most of the PHP time limit.<\/li>\n<li>Show a file progress bar counted once at job start when attachments change.<\/li>\n<li>Let the settings form, compatibility spoiler, and sync blocks use the full width.<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>Do not treat a custom API endpoint as a bucket hostname.<\/li>\n<li>Drop empty request headers before signing.<\/li>\n<li>Show a fuller S3 error (headers, ArgumentName, which compatibility option to use).<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Load plugin classes via PSR-4 from <code>src\/<\/code> instead of WordPress-style <code>includes\/class-*.php<\/code> files.<\/li>\n<li>Add a signing region setting and <code>ZLOJ_S3_REGION<\/code> (default <code>us-east-1<\/code>).<\/li>\n<li>Add optional compatibility workarounds behind a collapsed settings panel.<\/li>\n<li>Split API path-style into its own setting (<code>ZLOJ_S3_API_PATH_STYLE<\/code>, default on).<\/li>\n<li>Do not prepend the bucket as a subdomain when path-style is off; use the host field as entered.<\/li>\n<\/ul>\n\n<h4>1.3.3<\/h4>\n\n<ul>\n<li>Rewrite attachment URLs when offload is enabled, without requiring the SDK.<\/li>\n<li>Build public URLs as <code>host\/key<\/code>. Honor legacy <code>ZLOJ_S3_HTTPS_URL<\/code>.<\/li>\n<\/ul>\n\n<h4>1.3.2<\/h4>\n\n<ul>\n<li>Optional object trash: checkbox and <code>ZLOJ_S3_TRASH<\/code> (default on). Off deletes objects immediately.<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Register media offload hooks even when idle.<\/li>\n<li>Primary attachment objects can be intercepted via <code>zloj_s3_discard_object<\/code> before delete.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Split HTTPS into <code>ZLOJ_S3_API_HTTPS<\/code> and <code>ZLOJ_S3_PUBLIC_HTTPS<\/code> (default on). <code>ZLOJ_S3_HTTPS_URL<\/code> is ignored.<\/li>\n<li>Put the HTTPS toggles under the API and public host fields.<\/li>\n<li>Include the bucket in public URLs when path-style is enabled.<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Fix Find conflicts doing nothing when a cached script expected a separate Stop button.<\/li>\n<li>Turn the active job button into Stop; the current batch finishes, the next one does not start.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Hide storage keys in the admin and encrypt them at rest.<\/li>\n<li>Document the configured S3 endpoint as an external service.<\/li>\n<li>Always verify TLS; tighten AJAX sanitization; keep Plugin Check notices on the settings screen.<\/li>\n<li>Add a find-conflicts scan that compares local files with storage without uploading.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Add AJAX bulk upload of local uploads, with optional cleanup of identical local copies and a conflict resolver.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Offload WordPress media to S3-compatible object storage.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/371873","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=371873"}],"author":[{"embeddable":true,"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/zlojru"}],"wp:attachment":[{"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=371873"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=371873"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=371873"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=371873"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=371873"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/frp.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=371873"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}