{"id":284210,"date":"2026-03-02T21:09:48","date_gmt":"2026-03-02T21:09:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/images-sync-for-cloudflare\/"},"modified":"2026-03-08T08:00:57","modified_gmt":"2026-03-08T08:00:57","slug":"images-sync-for-cloudflare","status":"publish","type":"plugin","link":"https:\/\/ewe.wordpress.org\/plugins\/images-sync-for-cloudflare\/","author":23448903,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"1.0.8","stable_tag":"1.0.8","tested":"7.0","requires":"6.2","requires_php":"8.0","requires_plugins":null,"header_name":"Images Sync for Cloudflare","header_author":"301.st","header_description":"Sync WordPress images to Cloudflare Images with flexible mappings, presets, and variant delivery.","assets_banners_color":"ac826c","last_updated":"2026-03-08 08:00:57","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/investblog\/cloudflare-images-sync","header_author_uri":"https:\/\/301.st","rating":0,"author_block_rating":0,"active_installs":0,"downloads":233,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.7":{"tag":"1.0.7","author":"301st","date":"2026-03-02 21:09:11"},"1.0.8":{"tag":"1.0.8","author":"301st","date":"2026-03-08 08:00:57"}},"upgrade_notice":{"1.0.8":"<p>Developer filters, test suite, and WordPress 7.0 compatibility.<\/p>","1.0.7":"<p>Prefix renamed from <code>cfi<\/code> to <code>cfimg<\/code> per WP.org review. Database keys migrate automatically.<\/p>","1.0.5":"<p>Text domain and plugin file renamed to match WP.org assigned slug <code>images-sync-for-cloudflare<\/code>.<\/p>","1.0.4":"<p>WP.org review compliance: external services section, prepared SQL, ACF tag.<\/p>","1.0.3":"<p>Complete uninstall cleanup \u2014 encrypted token and migration version removed.<\/p>","1.0.2":"<p>New content_1200w preset, fit modes FAQ, improved settings UX.<\/p>","1.0.1":"<p>WordPress.org Plugin Check compliance, %i placeholders, external services disclosure.<\/p>","1.0.0":"<p>First stable release with encrypted token storage and WordPress.org assets.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3477304,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3477304,"resolution":"256x256","location":"assets","locale":""},"icon.svg":{"filename":"icon.svg","revision":3477304,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3477304,"resolution":"1544x500","location":"assets","locale":""},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3477304,"resolution":"772x250","location":"assets","locale":""}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.7","1.0.8"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Dashboard widget showing connection status at a glance","2":"Settings page with API configuration and Flexible Variants status","3":"Presets page with recommended presets and Universal\/Flexible badges","4":"Mapping configuration with source, target, and preset selection","5":"Preview Studio for testing presets with live images"},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[2211,3863,3882,141196,163],"plugin_category":[50,59],"plugin_contributors":[255945],"plugin_business_model":[],"class_list":["post-284210","plugin","type-plugin","status-publish","hentry","plugin_tags-acf","plugin_tags-cdn","plugin_tags-cloudflare","plugin_tags-headless","plugin_tags-images","plugin_category-media","plugin_category-utilities-and-tools","plugin_contributors-301st","plugin_committers-301st"],"banners":{"banner":"https:\/\/ps.w.org\/images-sync-for-cloudflare\/assets\/banner-772x250.png?rev=3477304","banner_2x":"https:\/\/ps.w.org\/images-sync-for-cloudflare\/assets\/banner-1544x500.png?rev=3477304","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/images-sync-for-cloudflare\/assets\/icon.svg?rev=3477304","icon":"https:\/\/ps.w.org\/images-sync-for-cloudflare\/assets\/icon.svg?rev=3477304","icon_2x":false,"generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p><strong>Images Sync for Cloudflare<\/strong> automatically uploads your WordPress images to Cloudflare Images and stores optimized delivery URLs directly in post meta. Perfect for headless setups, JAMstack sites, or anyone who wants fast, globally-distributed images without changing their workflow.<\/p>\n\n<h4>Why Use This Plugin?<\/h4>\n\n<p>Headless frontends need stable, cacheable CDN URLs. This plugin makes WordPress the source of truth while Cloudflare Images handles delivery and optimization. No custom resolvers needed \u2014 just query the meta field.<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li><strong>Flexible Mappings<\/strong> \u2014 Map any image source (Featured Image, ACF fields, post meta) to Cloudflare Images with customizable delivery URL storage<\/li>\n<li><strong>Preset System<\/strong> \u2014 Define reusable presets for OG images, thumbnails, heroes, squares \u2014 consistent URLs across your site<\/li>\n<li><strong>Preview Studio<\/strong> \u2014 Visually test how images look with different presets before going live<\/li>\n<li><strong>Auto-Sync<\/strong> \u2014 Images sync automatically on post save, or bulk-process existing content via Action Scheduler<\/li>\n<li><strong>Flexible Variants<\/strong> \u2014 Smart detection prevents broken images and 9429 errors<\/li>\n<li><strong>Headless-Ready<\/strong> \u2014 URLs stored in post meta, perfect for GraphQL\/REST API consumption<\/li>\n<li><strong>WP-CLI Support<\/strong> \u2014 <code>wp cfimg sync<\/code> commands for scripted workflows<\/li>\n<li><strong>Secure Storage<\/strong> \u2014 API token encrypted with libsodium (AES-256 fallback)<\/li>\n<li><strong>No Lock-in<\/strong> \u2014 Your images stay in WordPress Media Library; Cloudflare URLs are plain meta values<\/li>\n<\/ul>\n\n<h4>Security<\/h4>\n\n<p>Your Cloudflare API token is encrypted at rest using modern cryptography (libsodium or AES-256-CBC with HMAC). The token is never stored in plain text and is only decrypted when making API requests.<\/p>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>Cloudflare account with <a href=\"https:\/\/www.cloudflare.com\/products\/cloudflare-images\/\">Cloudflare Images<\/a> subscription<\/li>\n<li>API Token with \"Cloudflare Images: Edit\" permission<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>This plugin optionally connects to external Cloudflare services to upload, manage, and deliver images. No connection is made until the user configures API credentials and explicitly triggers a sync, test, or preview action.<\/p>\n\n<h4>Cloudflare Images API<\/h4>\n\n<p>This plugin sends requests to the <a href=\"https:\/\/api.cloudflare.com\/\">Cloudflare API<\/a> (<code>api.cloudflare.com<\/code>).<\/p>\n\n<p>Data sent to Cloudflare (only when the user configures credentials and triggers actions):<\/p>\n\n<ul>\n<li>API token \u2014 for authentication (sent as a Bearer token header, never logged or stored in plain text)<\/li>\n<li>Image files \u2014 binary content of WordPress media attachments<\/li>\n<li>Image metadata \u2014 WordPress attachment ID and a purpose label (e.g. \"preview\")<\/li>\n<li><p>Configuration updates \u2014 Flexible Variants enable\/disable flag<\/p><\/li>\n<li><p><a href=\"https:\/\/www.cloudflare.com\/terms\/\">Cloudflare Terms of Service<\/a><\/p><\/li>\n<li><a href=\"https:\/\/www.cloudflare.com\/privacypolicy\/\">Cloudflare Privacy Policy<\/a><\/li>\n<li><a href=\"https:\/\/developers.cloudflare.com\/api\/\">Cloudflare API Documentation<\/a><\/li>\n<\/ul>\n\n<h4>Cloudflare Image Delivery<\/h4>\n\n<p>Delivery URLs use the <a href=\"https:\/\/imagedelivery.net\/\">Cloudflare Image Delivery<\/a> CDN (<code>imagedelivery.net<\/code>). These URLs are stored in post meta and served directly to site visitors by their browsers. The plugin itself makes one request to this service to detect Flexible Variants support (canary check).<\/p>\n\n<p>No visitor data, IP addresses, cookies, or personal information is ever sent to Cloudflare by this plugin.<\/p>\n\n<ul>\n<li><a href=\"https:\/\/www.cloudflare.com\/terms\/\">Cloudflare Terms of Service<\/a><\/li>\n<li><a href=\"https:\/\/www.cloudflare.com\/privacypolicy\/\">Cloudflare Privacy Policy<\/a><\/li>\n<li><a href=\"https:\/\/developers.cloudflare.com\/images\/\">Cloudflare Images Documentation<\/a><\/li>\n<\/ul>\n\n<h3>Privacy Policy<\/h3>\n\n<p>This plugin does not collect, store, or transmit any personal user data. Only image files and technical metadata (attachment IDs, image hashes) are sent to Cloudflare.<\/p>\n\n<h3>Credits<\/h3>\n\n<p>Developed by <a href=\"https:\/\/301.st\">301st<\/a> with <a href=\"https:\/\/claude.ai\">Claude AI<\/a>.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin folder to <code>\/wp-content\/plugins\/<\/code> or install via WordPress admin<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> menu<\/li>\n<li>Go to <strong>CF Images \u2192 Settings<\/strong> and enter your Cloudflare credentials<\/li>\n<li>Create presets under <strong>CF Images \u2192 Presets<\/strong> (or install recommended presets)<\/li>\n<li>Set up mappings under <strong>CF Images \u2192 Mappings<\/strong> to define sync rules<\/li>\n<\/ol>\n\n<h4>Quick Start<\/h4>\n\n<ol>\n<li><strong>Credentials<\/strong> \u2014 Get your Account ID, Account Hash, and API Token from Cloudflare dashboard<\/li>\n<li><strong>Preset<\/strong> \u2014 Create a preset like <code>og_1200x630<\/code> with variant <code>w=1200,h=630,fit=cover,f=auto<\/code><\/li>\n<li><strong>Mapping<\/strong> \u2014 Map your CPT's featured image to a meta field like <code>_og_image_url<\/code><\/li>\n<li><strong>Done<\/strong> \u2014 Images sync on save, URLs available via <code>get_post_meta()<\/code><\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"what%20cloudflare%20plan%20do%20i%20need%3F\"><h3>What Cloudflare plan do I need?<\/h3><\/dt>\n<dd><p>Cloudflare Images is a paid add-on available on all Cloudflare plans. Pricing is based on images stored and served.<\/p><\/dd>\n<dt id=\"does%20this%20modify%20my%20original%20images%3F\"><h3>Does this modify my original images?<\/h3><\/dt>\n<dd><p>No. The plugin uploads a copy to Cloudflare Images. Your WordPress media files remain unchanged.<\/p><\/dd>\n<dt id=\"can%20i%20use%20this%20with%20acf%3F\"><h3>Can I use this with ACF?<\/h3><\/dt>\n<dd><p>Yes. The plugin supports ACF image fields with ID, array, and URL return formats.<\/p><\/dd>\n<dt id=\"what%20are%20flexible%20variants%3F\"><h3>What are Flexible Variants?<\/h3><\/dt>\n<dd><p>Flexible Variants allow on-the-fly image transformations via URL parameters (width, height, quality, format). The plugin detects if this feature is enabled on your account and adjusts the UI accordingly.<\/p><\/dd>\n<dt id=\"what%20fit%20modes%20are%20available%3F\"><h3>What fit modes are available?<\/h3><\/dt>\n<dd><p>Cloudflare Images supports several fit modes for resizing:<\/p>\n\n<ul>\n<li><strong>scale-down<\/strong> \u2014 Shrinks to fit within dimensions but never upscales. Best for content images where originals may be smaller than the target.<\/li>\n<li><strong>cover<\/strong> \u2014 Crops to fill exact dimensions. Best for OG images, thumbnails, and heroes where consistent sizing matters.<\/li>\n<li><strong>contain<\/strong> \u2014 Scales to fit within dimensions, adding letterboxing if needed. Preserves the full image.<\/li>\n<li><strong>crop<\/strong> \u2014 Crops to exact dimensions from the center (or custom gravity).<\/li>\n<\/ul>\n\n<p>Most presets use <code>fit=cover<\/code> for consistent sizing. Use <code>fit=scale-down<\/code> when you want to limit max width without stretching small images.<\/p><\/dd>\n<dt id=\"do%20i%20need%20action%20scheduler%3F\"><h3>Do I need Action Scheduler?<\/h3><\/dt>\n<dd><p>Action Scheduler is optional but recommended for bulk syncing. It offloads image uploads to background jobs, avoiding timeouts on large sites. Action Scheduler is bundled with WooCommerce, or you can install it as a <a href=\"https:\/\/wordpress.org\/plugins\/action-scheduler\/\">standalone plugin<\/a>.<\/p><\/dd>\n<dt id=\"is%20this%20good%20for%20headless%20wordpress%3F\"><h3>Is this good for headless WordPress?<\/h3><\/dt>\n<dd><p>Absolutely. Delivery URLs are stored as standard post meta, so they're immediately available via REST API or WPGraphQL without any custom resolvers.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20deactivate%20the%20plugin%3F\"><h3>What happens if I deactivate the plugin?<\/h3><\/dt>\n<dd><p>Your Cloudflare Images remain on Cloudflare, and the delivery URLs stay in post meta. You can continue using them or migrate to another solution.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.8<\/h4>\n\n<ul>\n<li>Added: Developer filters <code>cfimg_delivery_url<\/code> and <code>cfimg_resolve_source<\/code> for customizing sync behavior<\/li>\n<li>Added: PHPUnit test suite \u2014 35 tests covering admin security, sync engine, and validators<\/li>\n<li>Added: SECURITY.md with vulnerability reporting policy<\/li>\n<li>Improved: Plugin description updated for clarity<\/li>\n<li>Tested: WordPress 7.0 compatibility verified<\/li>\n<\/ul>\n\n<h4>1.0.7<\/h4>\n\n<ul>\n<li>Changed: Internal prefix renamed from <code>cfi<\/code> to <code>cfimg<\/code> (4+ chars required by WP.org)<\/li>\n<li>Changed: External services section restructured with inline ToS\/Privacy links per service<\/li>\n<li>Added: Automatic database migration from <code>cfi_<\/code> to <code>cfimg_<\/code> option\/meta keys<\/li>\n<li>Fixed: Uninstall cleans up both old (<code>cfi_<\/code>) and new (<code>cfimg_<\/code>) prefixed data<\/li>\n<li>Fixed: Asset enqueue guard referenced stale prefix, preventing CSS\/JS on subpages<\/li>\n<\/ul>\n\n<h4>1.0.5<\/h4>\n\n<ul>\n<li>Changed: Text domain renamed to <code>images-sync-for-cloudflare<\/code> to match WP.org slug<\/li>\n<li>Changed: Main plugin file renamed to <code>images-sync-for-cloudflare.php<\/code><\/li>\n<\/ul>\n\n<h4>1.0.4<\/h4>\n\n<ul>\n<li>Fixed: readme.txt uses required == External services == section heading (WP.org review)<\/li>\n<li>Fixed: Uninstall SQL uses $wpdb-&gt;prepare() with %i placeholder<\/li>\n<li>Fixed: Release ZIP filename without version suffix<\/li>\n<li>Removed: GitHub Plugin URI headers (not needed for WP.org)<\/li>\n<li>Added: acf tag for better discoverability<\/li>\n<li>Added: == Upgrade Notice == section<\/li>\n<\/ul>\n\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>Fixed: Uninstall now removes encrypted API token and migration version<\/li>\n<li>Fixed: Uninstall cleans up all plugin post meta from database<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>New: content_1200w recommended preset (fit=scale-down, never upscales small images)<\/li>\n<li>New: FAQ \u2014 available fit modes (scale-down, cover, contain, crop)<\/li>\n<li>New: FAQ \u2014 Action Scheduler as optional dependency<\/li>\n<li>Improved: Settings page UX \u2014 API Access section moved above Delivery for logical onboarding flow<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Improved: WordPress.org Plugin Check compliance (inline styles \u2192 enqueued CSS)<\/li>\n<li>Improved: SQL queries use %i placeholder for table names (WP 6.2+)<\/li>\n<li>Improved: Third-party service disclosure per Guideline 7<\/li>\n<li>Removed: load_plugin_textdomain (automatic since WP 4.6 for .org plugins)<\/li>\n<li>Changed: Minimum WordPress version raised to 6.2<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>New: Encrypted API token storage (libsodium\/AES-256)<\/li>\n<li>New: Settings link on Plugins page<\/li>\n<li>New: Translation template (.pot file) for localization<\/li>\n<li>New: WordPress.org assets (icons and banners)<\/li>\n<li>Improved: Dashboard widget with connection status<\/li>\n<li>First stable release<\/li>\n<\/ul>\n\n<h4>0.2.5<\/h4>\n\n<ul>\n<li>New: Dashboard widget on main WP Dashboard with connection status<\/li>\n<li>Improved: Plugin descriptions and documentation<\/li>\n<li>Improved: Author info updated for WordPress.org<\/li>\n<\/ul>\n\n<h4>0.2.4<\/h4>\n\n<ul>\n<li>Fixed: Dashboard widget error \u2014 added missing LogsRepo::recent() method<\/li>\n<\/ul>\n\n<h4>0.2.3<\/h4>\n\n<ul>\n<li>New: Dashboard widget with Connection Status, quick stats, and links<\/li>\n<li>New: Cloudflare icon in widget header<\/li>\n<\/ul>\n\n<h4>0.2.2<\/h4>\n\n<ul>\n<li>Fixed: Auto-sync URL persistence when ACF clears target field<\/li>\n<li>Added: wp_after_insert_post fallback for maximum compatibility<\/li>\n<li>Improved: Hook priorities increased to 999<\/li>\n<\/ul>\n\n<h4>0.2.1<\/h4>\n\n<ul>\n<li>Fixed: Auto-sync URL write on ACF save<\/li>\n<li>Improved: Debug logging verifies meta writes<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>New: Universal \"public\" preset (works without Flexible Variants)<\/li>\n<li>New: Attachment ID validation with suggestions in Preview<\/li>\n<li>Improved: Settings page with collapsible sections<\/li>\n<li>Improved: Connection Status indicators<\/li>\n<\/ul>\n\n<h4>0.1.10-beta<\/h4>\n\n<ul>\n<li>New: Flexible Variants detection and one-click enable<\/li>\n<li>New: Smart UI gating \u2014 no broken previews<\/li>\n<\/ul>\n\n<h4>0.1.0-beta<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<\/ul>","raw_excerpt":"Auto-sync WordPress images to Cloudflare Images. Stores optimized CDN URLs in post meta \u2014 ready for headless, ACF, or classic themes.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/284210","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=284210"}],"author":[{"embeddable":true,"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/301st"}],"wp:attachment":[{"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=284210"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=284210"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=284210"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=284210"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=284210"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ewe.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=284210"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}