Dalibor Votruba 7bcf5b99c2 Merge branch '1.0.0.studiou-wc-free-photo-product' преди 3 месеца
..
.claude f68291158f add claude settings преди 3 месеца
assets 3aa900d91c Auto-mark downloaded, confirmation dialogs, pagination fixes — v1.1.7 -> v1.2.0 преди 3 месеца
includes 7e7030477b Add custom upload info text field to product settings — v1.2.1 -> v1.2.2 преди 3 месеца
languages 43162c13e9 regenerate .mo translation преди 3 месеца
views 7e7030477b Add custom upload info text field to product settings — v1.2.1 -> v1.2.2 преди 3 месеца
CLAUDE.md 5f4489da6c Add min/max image resolution validation — v1.2.0 -> v1.2.1 преди 3 месеца
instructions.txt 4f646728ce compile _cz.mo преди 3 месеца
readme.md 5f4489da6c Add min/max image resolution validation — v1.2.0 -> v1.2.1 преди 3 месеца
studiou-wc-free-photo-product.php 7e7030477b Add custom upload info text field to product settings — v1.2.1 -> v1.2.2 преди 3 месеца

readme.md

QDR - Studiou WC Free Photo Product

WordPress (6.9.4+) / WooCommerce (10.6.2+) plugin that allows publishing special variable products with custom raw image upload for photo printing. Customers select a product variant using WooCommerce's native variation selector and upload their photo file, which gets stored in the WordPress media library under a configurable media category.

Requirements

  • WordPress 6.9.4+
  • WooCommerce 10.0+
  • PHP 8.2+
  • PHP ZipArchive extension (for admin ZIP download)

Installation

  1. Upload the studiou-wc-free-photo-product folder to /wp-content/plugins/
  2. Activate the plugin through the Plugins menu in WordPress
  3. The plugin creates a custom database table {prefix}studiou_fpp_files on activation

Configuration

Creating a Free Photo Product

  1. Create or edit a WooCommerce product and set its type to Variable
  2. Add variations with attributes (e.g. size: 10x15, 20x30, A4) and prices
  3. Go to the Free Photo tab in the product data panel (visible for Variable products)
  4. Check Enable Free Photo
  5. Select or create a Media Category - uploaded files will be assigned to this category
  6. Set Max File Size (MB) - maximum allowed upload size per file (1-500 MB, default 50)
  7. Optionally set Min Image Resolution (px) and Max Image Resolution (px) - width and height are interchangeable (portrait/landscape auto-detected). Leave empty to skip validation. RAW files that cannot be measured are skipped.
  8. Copy the displayed Shortcode for use on custom pages

Product Detail Page

When a variable product has Free Photo enabled, the upload area automatically appears on the WooCommerce single product page below the product summary (below the variation table and Add to Cart buttons). The customer workflow is:

  1. Upload a photo file via drag-and-drop or file browser (below the variation table)
  2. The product gallery image updates to show the uploaded photo preview
  3. Select a variant from the product variation table and click its Add to Cart button
  4. If no photo is uploaded, the server blocks the add-to-cart and shows an error notice
  5. The uploaded photo stays — the same photo can be used for multiple variants without re-uploading

The uploaded file reference is stored in the WooCommerce session, so it works with any add-to-cart method (form POST, AJAX buttons, individual variation buttons). The session persists across add-to-cart actions, allowing the same photo to be used for multiple variants. The session is only cleared when the user explicitly removes the uploaded photo.

Add-to-cart is blocked server-side until a photo is uploaded:

  • Validation: woocommerce_add_to_cart_validation (priority 1) checks the WC session for uploaded file data and blocks with an error notice if missing.
  • Safety net: woocommerce_add_to_cart action removes any FPP cart item that was added without a photo (catches edge cases where validation was bypassed).
  • Product detection uses resolve_fpp_product_id() which checks the product itself, its parent, and the variation's parent to handle all add-to-cart methods.

On page reload, existing session state is restored — the upload preview and product gallery image are reconstructed from the server-side session data. When the photo is removed, the original product image is restored. Add-to-cart buttons always look and behave normally — blocking is entirely server-side.

Shortcode

The shortcode can be used to embed the product with its variation selector and upload area on any page:

[studiou_free_photo_product id="123"]

Replace 123 with your product ID. The shortcode renders:

  • Product image, name, and short description
  • WooCommerce native variation selector and Add to Cart form
  • Upload area with drag-and-drop, progress bar, and preview (injected into the form)

Accepted File Formats

JPEG, PNG, TIFF, BMP, PSD, WebP, and camera RAW formats: CR2 (Canon), NEF (Nikon), ARW (Sony), DNG (Adobe), ORF (Olympus), RW2 (Panasonic), RAF (Fuji).

Chunked Upload

Files are uploaded in 1 MB chunks via AJAX to bypass PHP upload_max_filesize and post_max_size limits. The server assembles chunks into the final file, creates a WordPress media attachment, and assigns it to the configured media category. The chunk size is defined by the STUDIOU_WCFPP_CHUNK_SIZE constant.

Admin Summary Page

Navigate to Products > Free Photo Files to manage uploaded files.

Features

  • Filter by status (Ready / Downloaded / Solved), product, or file name search
  • Inline status change per file via dropdown
  • Single file download (automatically marks status as "downloaded" if currently "ready")
  • Single file delete with media attachment cleanup
  • Bulk actions with confirmation dialogs: Download as ZIP, Set Status (Ready / Downloaded / Solved), Delete
  • Order number links (HPOS-compatible)
  • Customer name display
  • Pagination (30 files per page, preserves active filters across pages)

File Statuses

Status Meaning
Ready File uploaded, awaiting processing
Downloaded File has been downloaded by admin (set automatically on download)
Solved File has been printed / order fulfilled

Cart and Order Integration

The plugin integrates with WooCommerce's native add-to-cart flow using WC session storage. When a photo is uploaded, the file reference is stored in the WC session via AJAX. When any add-to-cart button is clicked, woocommerce_add_cart_item_data reads the file data from the session and attaches it to the cart item. The session persists so the same photo can be reused for multiple variants. The woocommerce_add_to_cart_validation filter ensures a photo is uploaded before the item can be added. This approach works with any theme or plugin that handles variable product display (individual variation buttons, dropdowns, tables, etc.).

When a customer adds a photo product to the cart:

  • The cart item thumbnail shows the uploaded photo — works with both classic cart (woocommerce_cart_item_thumbnail filter) and block cart (woocommerce_product_get_image_id / woocommerce_product_variation_get_image_id filters that override the product image for the Store API)
  • The uploaded file name is shown as "Uploaded Photo" in the cart
  • On checkout, the file record is linked to the order and order item
  • In the order admin, order item thumbnails show the uploaded photo instead of the product image
  • The uploaded photo file name appears as order item metadata
  • A Download uploaded photo button with the original file name is shown below the order item meta in admin (downloading automatically marks the file status as "downloaded")
  • Files linked to orders cannot be removed by the customer

Media Categories

The plugin registers a custom taxonomy studiou_media_category on the attachment post type. Categories are visible in the Media Library admin column and can be managed from:

  • Free Photo product tab (inline add via "+" button)
  • Media Library sidebar

Each product has one assigned media category. All files uploaded for that product are tagged with it.

HPOS Support

The plugin declares full compatibility with WooCommerce High-Performance Order Storage (HPOS / Custom Order Tables). Order edit links in the admin summary page use the correct URL format based on whether HPOS is enabled.

Localization

Supported languages:

  • English (default)
  • Czech (cs_CZ)

Translation files are in the languages/ directory.

To compile the .mo file from .po:

# Using the included helper script
php languages/generate-mo.php

# Or using WP-CLI
wp i18n make-mo languages/

# Or using gettext
msgfmt languages/studiou-wc-free-photo-product-cs_CZ.po -o languages/studiou-wc-free-photo-product-cs_CZ.mo

Text domain: studiou-wc-free-photo-product

Database

The plugin creates one custom table on activation:

{prefix}studiou_fpp_files

Column Type Description
id bigint Primary key
product_id bigint WC product ID
variation_id bigint WC variation ID
order_id bigint WC order ID (set on checkout)
order_item_id bigint WC order item ID (set on checkout)
attachment_id bigint WP media attachment ID
customer_id bigint WP user ID (0 for guests)
session_key varchar(64) WC session key for guest users
file_name varchar(255) Original uploaded file name
status varchar(20) ready / downloaded / solved
created_at datetime Upload timestamp
updated_at datetime Last update timestamp

File Structure

studiou-wc-free-photo-product/
├── studiou-wc-free-photo-product.php        Main plugin file
├── includes/
│   ├── class-studiou-wc-fpp-db.php          Database + media taxonomy
│   ├── class-studiou-wc-fpp-product.php     Product data tab
│   ├── class-studiou-wc-fpp-upload.php      Chunked upload handler
│   ├── class-studiou-wc-fpp-shortcode.php   Shortcode renderer
│   ├── class-studiou-wc-fpp-single-product.php  Product page upload area
│   ├── class-studiou-wc-fpp-cart.php        Cart/order integration (native WC flow)
│   └── class-studiou-wc-fpp-admin.php       Admin summary page
├── views/
│   ├── frontend-product.php                 Shortcode template
│   ├── single-product-upload.php            Upload area for product page
│   └── admin-summary.php                    Admin file list template
├── assets/
│   ├── css/admin.css                        Admin styles
│   ├── css/frontend.css                     Frontend styles
│   ├── js/admin.js                          Admin JS
│   └── js/frontend.js                       Frontend JS (chunked upload)
└── languages/
    ├── studiou-wc-free-photo-product.pot    Translation template
    ├── studiou-wc-free-photo-product-cs_CZ.po  Czech translation
    └── generate-mo.php                      MO file generator

Hooks and Filters

AJAX Actions

Action Auth Description
studiou_wcfpp_upload_chunk Both Upload a file chunk
studiou_wcfpp_remove_upload Both Remove an uploaded file (pre-order)
studiou_wcfpp_set_upload_session Both Store uploaded file reference in WC session
studiou_wcfpp_clear_upload_session Both Clear uploaded file reference from WC session
studiou_wcfpp_add_media_category Admin Create a new media category
studiou_wcfpp_update_status Admin Update single file status
studiou_wcfpp_bulk_status Admin Bulk update file statuses
studiou_wcfpp_delete_files Admin Delete files (single or bulk)
studiou_wcfpp_download_zip Admin Generate ZIP of selected files

WooCommerce Hooks Used

Hook Type Description
woocommerce_single_product_summary (priority 35) Action Renders upload area below the variation table
woocommerce_add_to_cart_validation Filter Validates photo is uploaded
woocommerce_add_cart_item_data Filter Captures file data into cart item
woocommerce_cart_item_thumbnail Filter Replaces cart item thumbnail (classic cart)
woocommerce_product_get_image_id Filter Returns uploaded photo as product image (block cart)
woocommerce_product_variation_get_image_id Filter Returns uploaded photo as variation image (block cart)
woocommerce_get_item_data Filter Displays file name in cart
woocommerce_checkout_create_order_line_item Action Saves file meta to order item
woocommerce_checkout_order_processed Action Links file record to order (classic checkout)
woocommerce_store_api_checkout_order_processed Action Links file record to order (block checkout)
woocommerce_thankyou Action Fallback linking on thank-you page
woocommerce_admin_order_item_thumbnail Filter Replaces order item thumbnail with uploaded photo
woocommerce_after_order_itemmeta Action Shows download link for uploaded photo in order admin
woocommerce_product_data_tabs Filter Adds Free Photo product tab
woocommerce_product_data_panels Action Renders Free Photo settings panel
woocommerce_process_product_meta Action Saves Free Photo product meta

Product Meta Keys

Key Description
_studiou_fpp_enabled "yes" / "no"
_studiou_fpp_media_category Term ID of media category
_studiou_fpp_max_file_size Max upload size in MB
_studiou_fpp_min_width Min image width in px (0 = no limit)
_studiou_fpp_min_height Min image height in px (0 = no limit)
_studiou_fpp_max_width Max image width in px (0 = no limit)
_studiou_fpp_max_height Max image height in px (0 = no limit)

Order Item Meta Keys

Key Description
_studiou_fpp_attachment_id WP attachment ID
_studiou_fpp_file_record_id File record ID in custom table
_studiou_fpp_file_name Original file name
_studiou_fpp_thumb_url Thumbnail URL (for reliable display)

License

GPL v2 or later

Author

Dalibor Votruba - quadarax.com