# 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. 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. Select a variant from the product variation table 3. Click the variant's **Add to Cart** button 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 plugin validates that a photo is uploaded before allowing add-to-cart. The upload area is rendered via `woocommerce_single_product_summary` hook (priority 35, after the add-to-cart section). ### 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 - Single file download link - Single file delete with media attachment cleanup - Bulk actions: Download as ZIP, Set Status, Delete - Order number links (HPOS-compatible) - Customer name display - Pagination (30 files per page) ### File Statuses | Status | Meaning | |---|---| | Ready | File uploaded, awaiting processing | | Downloaded | File has been downloaded by admin | | 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 data is cleared after use. 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 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, the uploaded photo file name appears as order item metadata - 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`: ```bash # 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_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 | | `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 | ### 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 | ## License GPL v2 or later ## Author Dalibor Votruba - [quadarax.com](https://www.quadarax.com)