{"id":32280,"date":"2014-10-21T09:43:35","date_gmt":"2014-10-21T09:43:35","guid":{"rendered":"https:\/\/wordpress.org\/plugins-wp\/wp-force-images-download\/"},"modified":"2026-05-07T20:40:45","modified_gmt":"2026-05-07T20:40:45","slug":"wp-force-images-download","status":"publish","type":"plugin","link":"https:\/\/th.wordpress.org\/plugins\/wp-force-images-download\/","author":13395348,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"2.6","stable_tag":"trunk","tested":"6.9.4","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"WP-Force Images Download","header_author":"Nazakat Ali","header_description":"","assets_banners_color":"41507e","last_updated":"2026-05-07 20:40:45","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/buymeacoffee.com\/nazakatali","header_plugin_uri":"https:\/\/wordpress.org\/plugins\/wp-force-image-download\/","header_author_uri":"https:\/\/profiles.wordpress.org\/nazakatali32","rating":4.9,"author_block_rating":0,"active_installs":80,"downloads":9558,"num_ratings":8,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"nazakatali32","date":"2015-01-05 15:25:33"},"1.1.0":{"tag":"1.1.0","author":"nazakatali32","date":"2015-01-06 12:50:55"},"1.1.1":{"tag":"1.1.1","author":"nazakatali32","date":"2015-05-26 03:46:52"},"1.2":{"tag":"1.2","author":"nazakatali32","date":"2015-05-26 03:46:52"},"1.2.1":{"tag":"1.2.1","author":"nazakatali32","date":"2015-05-26 03:46:52"},"1.3":{"tag":"1.3","author":"nazakatali32","date":"2015-05-31 03:28:44"},"1.3.1":{"tag":"1.3.1","author":"nazakatali32","date":"2015-07-23 16:54:51"},"1.4":{"tag":"1.4","author":"nazakatali32","date":"2015-08-16 11:33:57"},"1.5":{"tag":"1.5","author":"nazakatali32","date":"2017-11-01 09:39:05"},"1.6":{"tag":"1.6","author":"nazakatali32","date":"2019-06-06 10:52:43"},"1.7":{"tag":"1.7","author":"nazakatali32","date":"2022-03-25 10:41:13"},"1.8":{"tag":"1.8","author":"nazakatali32","date":"2026-03-28 17:21:40"},"1.9":{"tag":"1.9","author":"nazakatali32","date":"2026-03-28 17:21:40"},"2.5":{"tag":"2.5","author":"nazakatali32","date":"2026-05-07 20:26:37"}},"upgrade_notice":{"2.6":"<p>Major bug fix release: fixes broken downloads for all WordPress upload images (same-site loopback issue), email gate authentication, AJAX in-page download intercept, live preview consistency, and multiple security hardening changes. No breaking changes \u2014 all existing shortcodes and settings are preserved. Highly recommended update.<\/p>","2.5":"<p>Major update: Adds Email Gate, Login Gate, tabbed settings UI, graceful image fallback, conflict-safe admin notices, and critical JS cache-busting version bump. Recommended for all users. No breaking changes \u2014 all existing shortcodes and settings are preserved.<\/p>","2.0":"<p>Major update adding AJAX downloads, download tracking, stats dashboard, auto-attach, size picker, and 4 premium button styles. Highly recommended upgrade.<\/p>"},"ratings":{"1":0,"2":0,"3":0,"4":1,"5":7},"assets_icons":{"icon-128x128.jpg":{"filename":"icon-128x128.jpg","revision":3493497,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3525886,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3525886,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.jpg":{"filename":"banner-772x250.jpg","revision":3493497,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":{"wpfid\/download-button":{"name":"wpfid\/download-button","title":"Image Download Button"}},"tagged_versions":["1.0.0","1.1.0","1.1.1","1.2","1.2.1","1.3","1.3.1","1.4","1.5","1.6","1.7","1.8","1.9","2.5"],"block_files":[],"assets_screenshots":{"screenshot-2.png":{"filename":"screenshot-2.png","revision":3493497,"resolution":"2","location":"assets","locale":"","width":409,"height":595}},"screenshots":{"1":"<strong>Tabbed Settings Page<\/strong> \u2014 Clean 3-tab admin UI: Button Design, Behaviour &amp; Features, Shortcode Help.","2":"<strong>Live Button Preview<\/strong> \u2014 Real-time sticky preview widget that updates as you change colors and styles.","3":"<strong>Button Design Tab<\/strong> \u2014 Pick from 4 styles, set global colors with the WP Color Picker, toggle icon and file size display.","4":"<strong>Behaviour &amp; Features Tab<\/strong> \u2014 Organized section cards for Auto-Attach, Download Options, Access Control (Login\/Email Gate), and Watermark.","5":"<strong>Email Gate in Action<\/strong> \u2014 Visitors enter their email before the download starts. Fully AJAX, no page reload.","6":"<strong>Stats Dashboard<\/strong> \u2014 Sortable download analytics table with per-post tracking and timestamps.","7":"<strong>Solid Style Button<\/strong> \u2014 Bold filled CTA with hover animation.","8":"<strong>Soft \/ Ghost Style Button<\/strong> \u2014 Subtle tinted background effect using CSS <code>color-mix()<\/code>."}},"plugin_section":[],"plugin_tags":[258872,10142,18284,24636,23093],"plugin_category":[50],"plugin_contributors":[258875],"plugin_business_model":[],"class_list":["post-32280","plugin","type-plugin","status-publish","hentry","plugin_tags-ajax-download","plugin_tags-download-button","plugin_tags-download-counter","plugin_tags-force-download","plugin_tags-image-download","plugin_category-media","plugin_contributors-nazakatali32","plugin_committers-nazakatali32"],"banners":{"banner":"https:\/\/ps.w.org\/wp-force-images-download\/assets\/banner-772x250.jpg?rev=3493497","banner_2x":"https:\/\/ps.w.org\/wp-force-images-download\/assets\/banner-1544x500.png?rev=3525886","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/wp-force-images-download\/assets\/icon-128x128.jpg?rev=3493497","icon_2x":"https:\/\/ps.w.org\/wp-force-images-download\/assets\/icon-256x256.png?rev=3525886","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/wp-force-images-download\/assets\/screenshot-2.png?rev=3493497","caption":"<strong>Live Button Preview<\/strong> \u2014 Real-time sticky preview widget that updates as you change colors and styles."}],"raw_content":"<!--section=description-->\n<p><strong>WP-Force Images Download<\/strong> is the most complete, lightweight, and developer-friendly image download plugin for WordPress. Designed for photographers, wallpaper sites, digital asset stores, creative agencies, and content creators \u2014 it transforms any image into a secure, one-click force download with a pixel-perfect branded button.<\/p>\n\n<p>Whether you need a simple <code>[wpfid]<\/code> shortcode or full programmatic control with PHP template tags, this plugin covers every use case with zero performance overhead.<\/p>\n\n\n\n<h3>\ud83d\ude80 Why WP-Force Images Download?<\/h3>\n\n<p>Most download plugins are bloated. This one is different:<\/p>\n\n<ul>\n<li><strong>Featherweight<\/strong> \u2014 Loads only one CSS file + one JS file on the frontend. No jQuery dependency for core functionality.<\/li>\n<li><strong>SaaS-grade Admin UI<\/strong> \u2014 Tabbed settings page with Live Button Preview so you see exactly what visitors will see before saving.<\/li>\n<li><strong>Future-proof<\/strong> \u2014 Uses <code>wp_check_filetype()<\/code> instead of hardcoded whitelists, so WebP, AVIF, HEIC and any new format WordPress adds is automatically supported.<\/li>\n<li><strong>Accessible<\/strong> \u2014 Buttons are semantic <code>&lt;button&gt;<\/code> elements with ARIA labels, full keyboard support, and WCAG 2.1 AA contrast compliance across all 4 styles.<\/li>\n<li><strong>Conflict-safe<\/strong> \u2014 All hooks, query args, nonce actions, and option keys use the <code>wpfid_<\/code> namespace to eliminate conflicts with any other plugin.<\/li>\n<\/ul>\n\n\n\n<h3>\u2728 Core Features<\/h3>\n\n<p><strong>\ud83c\udfa8 4 Premium Button Styles<\/strong>\nChoose from four professionally engineered CSS button styles \u2014 all powered by CSS custom properties (<code>--wpfid-color<\/code>, <code>--wpfid-text<\/code>) for effortless theming:<\/p>\n\n<ul>\n<li><strong>Solid<\/strong> \u2014 Bold, filled CTA button with subtle elevation shadow.<\/li>\n<li><strong>Outline<\/strong> \u2014 Transparent background with a crisp colored border. Text color adapts on hover.<\/li>\n<li><strong>Soft \/ Ghost<\/strong> \u2014 Tinted semi-transparent background (powered by <code>color-mix()<\/code>). Elegant and modern.<\/li>\n<li><strong>Text Only<\/strong> \u2014 Minimal styled link, zero background or borders. Perfect for inline usage.<\/li>\n<\/ul>\n\n<p><strong>\ud83d\uddbc\ufe0f Universal Color System<\/strong>\nSet a global button color and text color once in the settings. Override them per-post using shortcode attributes. Supports HEX (#2271b1), RGB (rgb(255,0,0)), RGBA, and natural language color names (MidnightBlue, Tomato, DodgerBlue).<\/p>\n\n<p><strong>\ud83d\udc41\ufe0f AJAX Live Preview<\/strong>\nThe settings page features a real-time sticky preview widget powered by WordPress's native <code>wpColorPicker<\/code>. Every change you make \u2014 style, color, icon, file size toggle \u2014 reflects instantly in the preview. No save \u2192 reload \u2192 check cycle.<\/p>\n\n<p><strong>\u26a1 AJAX Downloads (Zero Reload)<\/strong>\nWhen AJAX Downloads are enabled, visitors click the button and the file downloads immediately in-page using the Fetch API + Blob URL approach. No new tab opens. No page reloads. No redirect confusion.<\/p>\n\n<p><strong>\ud83d\udcca Download Stats Dashboard<\/strong>\nEvery download is tracked using WordPress post meta. View a sortable, paginated analytics table from <strong>WPFID &gt; Stats Dashboard<\/strong> in your admin. See which images are most popular, filter by date, and export data.<\/p>\n\n<p><strong>\ud83e\udd16 Auto-Attach Button<\/strong>\nZero coding required. Enable Auto-Attach and the download button is automatically injected before or after post content on any public post type that has a featured image. Toggle per post type (Post, Page, custom CPTs).<\/p>\n\n<p><strong>\ud83d\udd10 Email Gate<\/strong>\nRequire visitors to enter their email address before the download begins. The email is captured via AJAX (no page reload), securely saved to the database, and then the download starts automatically. Collected emails are viewable in the database or Stats page.<\/p>\n\n<p><em>Note: The Email Gate uses a server-signed token cookie (HMAC via <code>wp_hash()<\/code>) to verify submissions \u2014 not a plain cookie that could be forged.<\/em><\/p>\n\n<p><strong>\ud83d\udd12 Login Gate \/ Require Login<\/strong>\nRestrict downloads to logged-in users only. Unauthenticated visitors are redirected to the WordPress login page and returned to the download after successful authentication.<\/p>\n\n<p><strong>\ud83d\udcd0 Image Size Picker<\/strong>\nWhen enabled, a dropdown appears on the download button allowing visitors to choose between registered WordPress image sizes (Thumbnail, Medium, Large, Full, or any custom size registered by your theme).<\/p>\n\n<p><strong>\ud83d\udd22 Download Counter<\/strong>\nOptionally display the total download count directly below the button. Powered by post meta for instant reads and lightweight writes.<\/p>\n\n<p><strong>\ud83d\udcc1 Bulk Rename \/ Filename Templates<\/strong>\nControl exactly what filename visitors receive when they download, using a powerful variable templating system:\n    %site_name%, <code>%post_title%<\/code>, <code>%post_id%<\/code>, <code>%filename%<\/code>, <code>%timestamp%<\/code>, <code>%rand%<\/code>, <code>%md5%<\/code><\/p>\n\n<p>Example: <code>[wpfid new_name=\"%post_title%_%rand%\"]<\/code> produces <code>My-Post-Title_48291.jpg<\/code><\/p>\n\n<p><strong>\ud83c\udf10 Modern Format Support<\/strong>\nPowered by native <code>wp_check_filetype()<\/code>. The plugin automatically supports every image MIME type WordPress recognizes \u2014 including WebP, AVIF, HEIC, SVG, PNG, JPEG, GIF, BMP, ICO, and any future format added to WordPress Core. No configuration required.<\/p>\n\n<p><strong>\ud83d\udee1\ufe0f Enterprise-Grade Security<\/strong>\n- All form submissions verified with WordPress nonces (dual nonce on every download)\n- Email gate uses HMAC-signed cookies \u2014 immune to cookie-forgery attacks\n- Rate limiting: 30 requests per minute per IP prevents download abuse\n- Full input sanitization and output escaping on every field\n- PHP-level MIME type verification via <code>finfo_open()<\/code> on actual file contents\n- Session-aware download handler via <code>admin-post.php<\/code> + <code>admin-ajax.php<\/code>\n- <code>defined('ABSPATH') || die()<\/code> guard on every file<\/p>\n\n<p><strong>\ud83d\uddbc\ufe0f Watermarking (Advanced)<\/strong>\nAutomatically composite a watermark image onto downloaded photos. Supports PNG transparency. Preserves original image format (JPEG stays JPEG, PNG stays PNG).<\/p>\n\n<p><strong>\ud83d\udddc\ufe0f Gallery \/ ZIP Download<\/strong>\nUse the <code>[wpfid_gallery ids=\"1,2,3\"]<\/code> shortcode to let visitors download multiple images as a single ZIP bundle.<\/p>\n\n<p><strong>\ud83e\udde9 Gutenberg Block<\/strong>\nA native block available in the WordPress block editor. Configure button title, color, custom link, size picker, and download count toggle \u2014 all from the Inspector sidebar.<\/p>\n\n<p><strong>\ud83d\udd0c Elementor Widget<\/strong>\nA dedicated Elementor widget lets Elementor users insert download buttons with full control from the Elementor panel \u2014 no shortcode knowledge required.<\/p>\n\n\n\n<h3>\ud83d\udee0\ufe0f Usage<\/h3>\n\n<p><strong>Basic Shortcode<\/strong>\nPlace in any Post, Page, or Widget:\n    [wpfid]<\/p>\n\n<p><strong>With Custom Label<\/strong>\n    [wpfid title=\"Download HD Wallpaper\"]<\/p>\n\n<p><strong>With Specific Image URL<\/strong>\n    [wpfid link=\"https:\/\/example.com\/my-image.jpg\"]<\/p>\n\n<p><strong>With Color Overrides<\/strong>\n    [wpfid color=\"#e83e8c\" textcolor=\"#ffffff\"]<\/p>\n\n<p><strong>Combined Example<\/strong>\n    [wpfid title=\"Get the Image\" color=\"MidnightBlue\" textcolor=\"white\" new_name=\"%post_title%\"]<\/p>\n\n<p><strong>Gallery \/ ZIP Download<\/strong>\n    [wpfid_gallery ids=\"10,20,30\" title=\"Download All Images (ZIP)\"]<\/p>\n\n<p><strong>PHP Template Tag (for theme developers)<\/strong>\n    <\/p>\n\n<p>Or use the direct function call:\n    <\/p>\n\n\n\n<h3>\ud83d\udccb Shortcode Attributes Reference<\/h3>\n\n\n\n\n  Attribute\n  Default\n  Description\n\n\n\n\n  <code>title<\/code>\n  <code>Download<\/code>\n  Button label text\n\n\n  <code>link<\/code>\n  (featured image)\n  Direct URL to the image to download\n\n\n  <code>color<\/code>\n  Settings value\n  Button background color (HEX, RGB, or color name)\n\n\n  <code>textcolor<\/code>\n  Settings value\n  Button text\/icon color\n\n\n  <code>new_name<\/code>\n  Settings value\n  Filename template for the downloaded file\n\n\n  <code>class<\/code>\n  (empty)\n  Additional CSS class(es) on the button wrapper\n\n\n  <code>size_picker<\/code>\n  Settings value\n  <code>\"true\"<\/code> \/ <code>\"false\"<\/code> \u2014 show image size dropdown\n\n\n  <code>show_count<\/code>\n  Settings value\n  <code>\"true\"<\/code> \/ <code>\"false\"<\/code> \u2014 show download count below button\n\n\n\n\n\n\n<h3>\ud83d\udcc8 SEO, GEO &amp; AI Optimization<\/h3>\n\n<p><strong>Semantic HTML5 Output<\/strong>\nEvery download button is a native <code>&lt;button&gt;<\/code> or <code>&lt;a&gt;<\/code> element with descriptive <code>title<\/code> attributes and <code>aria-label<\/code> support. No div-soup, no generic onClick handlers \u2014 pure semantic markup that search engine crawlers and AI language models can interpret correctly.<\/p>\n\n<p><strong>Schema &amp; Structured Data Ready<\/strong>\nThe plugin output is compatible with <code>DigitalDocument<\/code> and <code>ImageObject<\/code> schema markup. You can wrap the shortcode output in your own schema markup to signal to Google that this is a downloadable asset.<\/p>\n\n<p><strong>Core Web Vitals Safe<\/strong>\n- CSS is loaded with <code>wp_enqueue_style()<\/code> with versioned cache-busting\n- JavaScript is deferred (loaded in footer) and only runs on pages with the shortcode\n- Zero render-blocking resources introduced\n- No external font or icon CDN calls \u2014 uses WordPress Dashicons (already loaded)\n- File-size display is transient-cached (6 hours) \u2014 no live HTTP request on every page view<\/p>\n\n<p><strong>Translation Ready (GEO \/ i18n)<\/strong>\nEvery user-facing string is wrapped in <code>__()<\/code>, <code>esc_html__()<\/code>, or <code>esc_html_e()<\/code> translation functions with the <code>wp-force-images-download<\/code> text domain. Compatible with WPML, Polylang, Loco Translate, and TranslatePress for multilingual and geographic market targeting.<\/p>\n\n<p><strong>AI \/ LLM Crawler Compatibility<\/strong>\nThe plugin generates standard HTML anchor elements with meaningful <code>title<\/code> and <code>download<\/code> attributes, making button intent clear to AI-powered crawlers (GPTBot, Google Bard, Applebot) without requiring additional structured data.<\/p>\n\n<!--section=installation-->\n<p><strong>Method 1: WordPress Plugin Repository (Recommended)<\/strong>\n1. Go to <strong>Plugins &gt; Add New<\/strong> in your WordPress Dashboard.\n2. Search for <code>WP Force Images Download<\/code>.\n3. Click <strong>Install Now<\/strong>, then <strong>Activate<\/strong>.<\/p>\n\n<p><strong>Method 2: Manual Upload<\/strong>\n1. Download the plugin <code>.zip<\/code> file.\n2. Go to <strong>Plugins &gt; Add New &gt; Upload Plugin<\/strong>.\n3. Choose the zip file and click <strong>Install Now<\/strong>.\n4. Click <strong>Activate Plugin<\/strong>.<\/p>\n\n<p><strong>Method 3: FTP\/SFTP<\/strong>\n1. Unzip and upload the <code>wp-force-images-download<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.\n2. Activate via <strong>Plugins<\/strong> in WordPress admin.<\/p>\n\n<p><strong>After Activation<\/strong>\n- A branded notification banner appears welcoming you to v2.6.\n- Navigate to <strong>WPFID &gt; Settings<\/strong> in your admin sidebar.\n- Use the <strong>\ud83c\udfa8 Button Design<\/strong> tab to style your button with the Live Preview.\n- Use the <strong>\u2699\ufe0f Behaviour &amp; Features<\/strong> tab to enable Email Gate, Login Gate, Auto-Attach, etc.\n- Deploy <code>[wpfid]<\/code> anywhere in your content.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20do%20i%20add%20a%20download%20button%20to%20a%20post%3F\"><h3>How do I add a download button to a post?<\/h3><\/dt>\n<dd><p>Simply add the shortcode <code>[wpfid]<\/code> to any post or page. The plugin will automatically detect the post's featured image and force-download it. If you want a specific image, use <code>[wpfid link=\"https:\/\/your-image-url.com\/image.jpg\"]<\/code>.<\/p><\/dd>\n<dt id=\"where%20do%20i%20find%20the%20settings%3F\"><h3>Where do I find the settings?<\/h3><\/dt>\n<dd><p>Navigate to <strong>WPFID &gt; Settings<\/strong> in your WordPress admin sidebar. The settings page has three tabs: Button Design, Behaviour &amp; Features, and Shortcode Help.<\/p><\/dd>\n<dt id=\"how%20do%20i%20track%20downloads%3F\"><h3>How do I track downloads?<\/h3><\/dt>\n<dd><p>Go to <strong>WPFID &gt; Stats Dashboard<\/strong>. Every download is tracked automatically. You'll see a table with post titles, download counts, last downloaded time, and direct links.<\/p><\/dd>\n<dt id=\"how%20does%20the%20email%20gate%20work%3F\"><h3>How does the Email Gate work?<\/h3><\/dt>\n<dd><p>When \"Require Email\" is enabled, visitors see an email input field next to the download button. After entering a valid email and clicking the button, the email is saved to the database and the download starts automatically \u2014 all without any page reload. Collected emails are stored in <code>wp_options<\/code> under <code>wpfid_collected_emails<\/code>. The gate uses a cryptographically signed cookie token so it cannot be bypassed by simply setting a cookie manually.<\/p><\/dd>\n<dt id=\"how%20does%20the%20login%20gate%20work%3F\"><h3>How does the Login Gate work?<\/h3><\/dt>\n<dd><p>When \"Require Login\" is enabled, clicking the download button redirects unauthenticated users to the WordPress login page. After a successful login, they are returned to the original page.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20support%20webp%2C%20avif%2C%20heic%20images%3F\"><h3>Does this plugin support WebP, AVIF, HEIC images?<\/h3><\/dt>\n<dd><p>Yes. The plugin uses WordPress's native <code>wp_check_filetype()<\/code> function instead of a hardcoded whitelist. This means it automatically supports every image format WordPress recognizes \u2014 including WebP, AVIF, HEIC, PNG, JPEG, GIF, SVG, BMP, ICO, and any format added in future WordPress updates.<\/p><\/dd>\n<dt id=\"can%20i%20customize%20the%20button%20colors%3F\"><h3>Can I customize the button colors?<\/h3><\/dt>\n<dd><p>Yes, in two ways: (1) Set universal colors in <strong>WPFID &gt; Settings &gt; Button Design<\/strong> \u2014 this applies to all buttons site-wide. (2) Override per-post using shortcode attributes: <code>[wpfid color=\"#ff0000\" textcolor=\"#ffffff\"]<\/code>. Color values can be HEX, RGB, RGBA, or English color names like <code>Tomato<\/code>, <code>MidnightBlue<\/code>, <code>DodgerBlue<\/code>.<\/p><\/dd>\n<dt id=\"can%20i%20rename%20the%20downloaded%20file%3F\"><h3>Can I rename the downloaded file?<\/h3><\/dt>\n<dd><p>Yes. Use the <code>new_name<\/code> attribute in the shortcode: <code>[wpfid new_name=\"%post_title%_%rand%\"]<\/code>. Or set a global rename pattern in <strong>WPFID &gt; Settings &gt; Behaviour &amp; Features &gt; Rename Pattern<\/strong>. Available variables: <code>%site_name%<\/code>, <code>%post_title%<\/code>, <code>%post_id%<\/code>, <code>%filename%<\/code>, <code>%timestamp%<\/code>, <code>%rand%<\/code>, <code>%md5%<\/code>.<\/p><\/dd>\n<dt id=\"does%20ajax%20download%20mode%20work%20for%20all%20file%20types%3F\"><h3>Does AJAX download mode work for all file types?<\/h3><\/dt>\n<dd><p>Yes. AJAX download mode uses the Fetch API to retrieve the file as a binary blob and triggers the download via a programmatic anchor click. It works for all image formats and falls back gracefully to a normal form POST in older browsers.<\/p><\/dd>\n<dt id=\"will%20the%20plugin%20slow%20down%20my%20site%20or%20hurt%20seo%3F\"><h3>Will the plugin slow down my site or hurt SEO?<\/h3><\/dt>\n<dd><p>No. The plugin is carefully optimized: CSS and JS only load on pages where the shortcode is used, all assets are versioned for cache efficiency, no render-blocking scripts, no external CDN calls, and the button output is pure semantic HTML5. File-size display results are cached in transients for 6 hours.<\/p><\/dd>\n<dt id=\"is%20the%20plugin%20compatible%20with%20gutenberg%3F\"><h3>Is the plugin compatible with Gutenberg?<\/h3><\/dt>\n<dd><p>Yes. A native <strong>Gutenberg block<\/strong> (WPFID Download Button) is available directly in the block inserter under the Widgets category. Configure all button settings directly in the Inspector sidebar. You can also use the Shortcode block with <code>[wpfid]<\/code>.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20woocommerce%20or%20custom%20post%20types%3F\"><h3>Does it work with WooCommerce or custom post types?<\/h3><\/dt>\n<dd><p>Yes. The shortcode works in any content area. Auto-Attach can be enabled for any registered public post type, including WooCommerce products. WooCommerce purchase gating is also available via the <code>product_id<\/code> parameter.<\/p><\/dd>\n<dt id=\"how%20do%20i%20display%20the%20button%20in%20my%20theme%27s%20php%20files%3F\"><h3>How do I display the button in my theme's PHP files?<\/h3><\/dt>\n<dd><p>Use <code>&lt;?php echo do_shortcode('[wpfid]'); ?&gt;<\/code> anywhere in your template files. Or use the direct template tag: <code>&lt;?php wp_fid( 'Download', '#2271b1' ); ?&gt;<\/code>.<\/p><\/dd>\n<dt id=\"is%20the%20plugin%20gdpr%20compliant%20regarding%20email%20collection%3F\"><h3>Is the plugin GDPR compliant regarding email collection?<\/h3><\/dt>\n<dd><p>The Require Email feature collects email addresses entered voluntarily by users. You are responsible for disclosing this in your privacy policy. The emails are stored in your own WordPress database (never sent to a third party). We recommend adding a consent checkbox or linking to your privacy policy near the email field using Custom CSS or hooks.<\/p><\/dd>\n<dt id=\"is%20there%20a%20rest%20api%3F\"><h3>Is there a REST API?<\/h3><\/dt>\n<dd><p>Yes. The endpoint <code>GET \/wp-json\/wpfid\/v1\/download\/{attachment_id}<\/code> returns a signed download URL for headless or external clients. If \"Require Login\" is enabled in settings, the endpoint automatically requires authentication. The returned URL includes valid nonces for 24 hours.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>2.6 \u2014 Security, Bug Fixes &amp; Download Engine<\/h4>\n\n<p><strong>Download<\/strong>\n* Fixed: Same-site images (WordPress uploads) were fetched via <code>wp_remote_get()<\/code> instead of served from disk \u2014 downloads failed on all standard installs.\n* Fixed: <code>Content-Length<\/code> used <code>strlen()<\/code> on binary data; changed to <code>mb_strlen($data, '8bit')<\/code> for correct byte count under <code>mbstring.func_overload<\/code>.\n* Fixed: Temp directory used core constant <code>WP_TEMP_DIR<\/code>; now uses plugin-specific <code>WPFID_TEMP_DIR<\/code> to avoid conflicts on managed hosts.\n* Fixed: PHP extension check ran against the full URL instead of only the file extension, causing false 403s on URLs with <code>.php<\/code> in the domain\/path.\n* Fixed: URL\u2192path mapping broke when stored URL scheme (http) differed from <code>home_url()<\/code> scheme (https); scheme is now stripped before comparing.\n* Added: Files over 5 MB are streamed in 64 KB chunks via <code>fread()<\/code> to avoid PHP memory exhaustion.<\/p>\n\n<p><strong>Email Gate<\/strong>\n* Fixed: <code>wpfid_handle_save_email()<\/code> never set the HMAC auth cookie after saving the email \u2014 every subsequent download was rejected with 403.\n* Fixed: AJAX fetch calls missing <code>credentials: 'same-origin'<\/code>; browser discarded the <code>Set-Cookie<\/code> response so the cookie never reached Step 2.\n* Fixed: Server HTML error pages (e.g. <code>wp_die()<\/code>) were being offered as a download blob instead of surfacing as a user-facing error.\n* Fixed: Returning visitors triggered duplicate rows in <code>wpfid_collected_emails<\/code>; both AJAX handlers now check before inserting.\n* Security: Email Gate cookie replaced from a plain <code>1<\/code> flag (forgeable) to a server-signed HMAC token (<code>wp_hash(email|expiry)<\/code>), verified server-side.\n* Security: Legacy <code>wpfid_submit_email<\/code> AJAX action had no nonce; nonce now generated, localized, and verified before processing.\n* Security: Email gate modal was rendered on every frontend page even when the feature was disabled; now skipped when inactive.<\/p>\n\n<p><strong>JavaScript<\/strong>\n* Fixed: Unclosed JSDoc comment (<code>*\/<\/code> removed by a prior edit) turned <code>wpfidHandleEmailGate()<\/code> and the entire IIFE into a comment block \u2014 email gate crashed and AJAX download intercept never registered, causing all forms to open in a new tab.\n* Fixed: Stray <code>e;\\n}<\/code> after the catch block created a syntax error; <code>wpfid-ajax.js<\/code> rewritten from scratch.\n* Fixed: AJAX <code>catch<\/code> fallback used <code>arguments.callee<\/code> (illegal in strict mode); replaced with named function <code>handleWpfidSubmit<\/code>.<\/p>\n\n<p><strong>Admin<\/strong>\n* Fixed: Live Button Preview showed inconsistent results across tabs \u2014 on Features\/Help tabs form fields are absent so <code>updatePreview()<\/code> fell back to hardcoded defaults. PHP now injects saved values as <code>wpfidSavedPreview<\/code>; used as fallback when fields are not in the DOM.\n* Fixed: Duplicate <code>wpfid_verify_advanced_features()<\/code> filter caused the login gate check to run twice per download; removed the redundant registration.\n* Fixed: <code>wpfid_admin_scripts()<\/code> used <code>$_GET['page']<\/code> instead of the <code>$hook_suffix<\/code> parameter; corrected.\n* Fixed: Admin notice dismiss URL echoed without <code>esc_url()<\/code>.<\/p>\n\n<p><strong>REST API<\/strong>\n* Security: <code>\/wpfid\/v1\/download\/{id}<\/code> had no authentication (<code>__return_true<\/code>); now respects the global Require Login setting.<\/p>\n\n<p><strong>Download Handler<\/strong>\n* Fixed: <code>Content-Type<\/code> set twice \u2014 <code>application\/force-download<\/code> silently overwrote the correct MIME type; legacy header removed.\n* Fixed: Download counter incremented before confirming a successful file stream; now increments only after the file is fully served.<\/p>\n\n<p><strong>Watermark<\/strong>\n* Fixed: Watermark processor always output JPEG regardless of source format, destroying PNG transparency; now outputs the matching format (JPEG\/PNG\/WebP).<\/p>\n\n<p><strong>Gutenberg Block<\/strong>\n* Fixed: Block registered with deprecated <code>category: 'common'<\/code> (removed WP 5.5.3); changed to <code>'widgets'<\/code>.\n* Fixed: Block script dependency listed deprecated <code>'wp-editor'<\/code>; changed to <code>'wp-block-editor'<\/code>.<\/p>\n\n<p><strong>Core \/ Misc<\/strong>\n* Fixed: <code>register_activation_hook()<\/code> called from <code>inc.php<\/code> (included file) instead of the main plugin file; moved to <code>wp_fid.php<\/code>.\n* Performance: <code>get_option('wp_force_images_download_options')<\/code> cached in a static variable \u2014 at most one DB query per PHP request instead of 6+.\n* Performance: File-size display cached in transients for 6 hours; no longer fires a live <code>wp_remote_head()<\/code> on every page load.\n* Consistency: Both email-saving handlers now use the same <code>['email','post_id','time']<\/code> object format with duplicate-entry checks.<\/p>\n\n<h4>2.5 \u2014 Major Platform Update<\/h4>\n\n<ul>\n<li><strong>NEW:<\/strong> Completely redesigned admin settings into a <strong>3-tab interface<\/strong> (Button Design \/ Behaviour &amp; Features \/ Shortcode Help) for dramatically improved UX.<\/li>\n<li><strong>NEW:<\/strong> <strong>Email Gate<\/strong> \u2014 Visitors must enter an email address before downloading. Email is captured via AJAX, stored in the database, and the file downloads immediately \u2014 no page reload.<\/li>\n<li><strong>NEW:<\/strong> <strong>Login Gate<\/strong> \u2014 Restrict downloads to logged-in users. Unauthenticated visitors are redirected to the login page and returned after authentication.<\/li>\n<li><strong>NEW:<\/strong> <strong>Version-aware admin activation notice<\/strong> \u2014 A modern branded notice appears for new installs and upgrades, linking directly to the correct WPFID settings menu.<\/li>\n<li><strong>NEW:<\/strong> <strong>Graceful fallback<\/strong> \u2014 If no image exists for a post and no <code>link=<\/code> attribute is provided, a styled info notice is displayed instead of a broken download or HTML file.<\/li>\n<li><strong>NEW:<\/strong> Section cards in the Behaviour &amp; Features tab with icon headings and v2.5 version badges for quick scanning.<\/li>\n<li><strong>NEW:<\/strong> Shortcode Help tab with a full reference table \u2014 always accessible without scrolling.<\/li>\n<li><strong>IMPROVED:<\/strong> Live Button Preview widget is now sticky in the sidebar and works across both settings tabs.<\/li>\n<li><strong>IMPROVED:<\/strong> Dismiss handler for admin notices is now conflict-safe \u2014 bails immediately on every other admin page with zero performance overhead.<\/li>\n<li><strong>IMPROVED:<\/strong> All nonces scoped with descriptive action names \u2014 zero conflict with any other plugin or theme using generic nonce names.<\/li>\n<li><strong>FIX:<\/strong> Settings were not propagating correctly for logged-out users. Root cause was WordPress\/browser JS caching due to version number staying at <code>2.0<\/code>. Version bumped to <code>2.5<\/code> to bust all caches.<\/li>\n<li><strong>FIX:<\/strong> <code>settings_fields()<\/code> \/ <code>do_settings_sections()<\/code> pattern replaced with direct callback invocations inside tabs, eliminating rendering artifacts from the legacy WordPress Settings API output.<\/li>\n<li><strong>SECURITY:<\/strong> All <code>$_GET<\/code> and <code>$_POST<\/code> superglobals in new handlers properly passed through <code>sanitize_text_field( wp_unslash() )<\/code> before use.<\/li>\n<\/ul>\n\n<h4>2.0 \u2014 Feature Expansion<\/h4>\n\n<ul>\n<li><strong>NEW:<\/strong> Download Counter \u2014 Track every download with post meta. Displays inline below the button.<\/li>\n<li><strong>NEW:<\/strong> Stats Dashboard \u2014 Dedicated admin sub-page showing most downloaded images sorted by count.<\/li>\n<li><strong>NEW:<\/strong> AJAX Downloads \u2014 Seamless in-page downloads using Fetch API + Blob URL. No new tab, no page redirect.<\/li>\n<li><strong>NEW:<\/strong> Image Size Picker \u2014 Dropdown lets visitors choose registered WordPress image sizes (Thumbnail, Medium, Large, Full).<\/li>\n<li><strong>NEW:<\/strong> Auto-Attach Button \u2014 Inject download button before or after post content automatically based on post type.<\/li>\n<li><strong>NEW:<\/strong> Rate Limiting \u2014 Built-in protection (30 downloads\/minute\/IP) using WordPress transients.<\/li>\n<li><strong>NEW:<\/strong> Universal Color System \u2014 Set site-wide button color and text color from the admin dashboard using WP Color Picker.<\/li>\n<li><strong>NEW:<\/strong> Real-Time Live Preview \u2014 Preview button appearance in the admin sidebar as you change settings.<\/li>\n<li><strong>NEW:<\/strong> 4 Button Styles \u2014 Solid, Outline, Soft\/Ghost, Text-only. All CSS variable driven with hover animations.<\/li>\n<li><strong>NEW:<\/strong> <code>textcolor<\/code> shortcode attribute \u2014 Override text\/icon color per button.<\/li>\n<li><strong>IMPROVED:<\/strong> Replaced hardcoded MIME type whitelist with <code>wp_check_filetype()<\/code> for automatic WebP, AVIF, HEIC support.<\/li>\n<li><strong>IMPROVED:<\/strong> Replaced deprecated <code>current_time('timestamp')<\/code> with <code>time()<\/code>.<\/li>\n<li><strong>IMPROVED:<\/strong> Replaced custom byte formatter with native WordPress <code>size_format()<\/code>.<\/li>\n<li><strong>REMOVED:<\/strong> Legacy <code>fd.php<\/code> direct download handler (replaced by secure <code>admin-post.php<\/code> handler).<\/li>\n<li><strong>SECURITY:<\/strong> Added nonce verification to all form handlers.<\/li>\n<li><strong>SECURITY:<\/strong> Added dedicated top-level WPFID admin menu to replace the settings under Settings &gt; General.<\/li>\n<\/ul>\n\n<h4>1.9<\/h4>\n\n<ul>\n<li><strong>SECURITY:<\/strong> Fixed CVE-2025-11809 \u2014 Added full sanitization and escaping for all shortcode attributes.<\/li>\n<li>Codebase reviewed and passed WordPress Plugin Check (plugin-check) standards.<\/li>\n<\/ul>\n\n<h4>1.8<\/h4>\n\n<ul>\n<li>Added detailed inline documentation for all functions.<\/li>\n<li>Improved plugin architecture and loading performance.<\/li>\n<\/ul>\n\n<h4>1.7<\/h4>\n\n<ul>\n<li><strong>NEW:<\/strong> Custom CSS class support in shortcode (<code>class<\/code> attribute).<\/li>\n<li><strong>NEW:<\/strong> Template tag support for renaming downloaded files.<\/li>\n<li><strong>FIX:<\/strong> Zero-byte downloaded files bug resolved.<\/li>\n<li><strong>FIX:<\/strong> Template tag not downloading picture bug resolved.<\/li>\n<li>Added detailed inline documentation.<\/li>\n<\/ul>\n\n<h4>1.6<\/h4>\n\n<ul>\n<li>Fixed remote file inclusion (RFI) vulnerability.<\/li>\n<li>Security hardened throughout.<\/li>\n<li>Custom CSS textarea added in admin to style the download button.<\/li>\n<\/ul>\n\n<h4>1.5<\/h4>\n\n<ul>\n<li>Bulk rename feature introduced.<\/li>\n<li>Basic button theming and style options added.<\/li>\n<li>Improved security and performance.<\/li>\n<\/ul>\n\n<h4>1.4<\/h4>\n\n<ul>\n<li>Shortcode <code>new_name<\/code> attribute for per-post file renaming.<\/li>\n<li>Global rename pattern option in admin settings.<\/li>\n<li>Admin settings page introduced.<\/li>\n<\/ul>\n\n<h4>1.3<\/h4>\n\n<ul>\n<li>Expanded MIME type support (additional image types).<\/li>\n<li>Security hardened.<\/li>\n<\/ul>\n\n<h4>1.2<\/h4>\n\n<ul>\n<li>Added <code>link<\/code> attribute to <code>[wpfid]<\/code> shortcode for custom image URLs.<\/li>\n<\/ul>\n\n<h4>1.1<\/h4>\n\n<ul>\n<li>Shortcode support introduced.<\/li>\n<li>Basic button styling and color options.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial public release.<\/li>\n<\/ul>","raw_excerpt":"Force any image download with beautiful buttons, email gate, download tracking, AJAX, and more.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/32280","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=32280"}],"author":[{"embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/nazakatali32"}],"wp:attachment":[{"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=32280"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=32280"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=32280"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=32280"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=32280"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/th.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=32280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}