Selaa lähdekoodia

Auto-mark downloaded, confirmation dialogs, pagination fixes — v1.1.7 -> v1.2.0

- Download button (order item + photo files view) now serves file
  via admin handler that marks status from ready to downloaded
- All bulk actions have confirmation dialogs (delete, status changes,
  ZIP download)
- Pagination preserves active filters (status, product, search)
- Pagination shows total count
- New admin handler handle_file_download() serves file + updates status
- Order item download uses nonce-protected admin URL instead of direct
  attachment URL
- Add Czech translations for new confirmation messages
- Update documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dalibor Votruba 3 kuukautta sitten
vanhempi
commit
3aa900d91c

+ 1 - 1
studiou-wc-free-photo-product/CLAUDE.md

@@ -2,7 +2,7 @@
 
 ## Project Overview
 
-WordPress/WooCommerce plugin called **studiou-wc-free-photo-product** (QDR - Studiou WC Free Photo Product) v1.1.7.
+WordPress/WooCommerce plugin called **studiou-wc-free-photo-product** (QDR - Studiou WC Free Photo Product) v1.2.0.
 Allows publishing special variable products where customers upload custom raw images to be printed for a price.
 
 ## Initial Requirements

+ 13 - 3
studiou-wc-free-photo-product/assets/js/admin.js

@@ -152,12 +152,22 @@
                     return;
                 }
 
+                var confirmMsg = '';
+                if (action === 'delete') {
+                    confirmMsg = studiouWcfpp.i18n.confirmDelete;
+                } else if (action === 'download_zip') {
+                    confirmMsg = studiouWcfpp.i18n.confirmDownloadZip;
+                } else if (action.startsWith('status_')) {
+                    confirmMsg = studiouWcfpp.i18n.confirmStatusChange;
+                }
+
+                if (confirmMsg && !confirm(confirmMsg)) {
+                    return;
+                }
+
                 if (action === 'download_zip') {
                     bulkDownloadZip(fileIds);
                 } else if (action === 'delete') {
-                    if (!confirm(studiouWcfpp.i18n.confirmDelete)) {
-                        return;
-                    }
                     bulkDelete(fileIds);
                 } else if (action.startsWith('status_')) {
                     var status = action.replace('status_', '');

+ 51 - 1
studiou-wc-free-photo-product/includes/class-studiou-wc-fpp-admin.php

@@ -17,8 +17,9 @@ class Studiou_WC_FPP_Admin {
         add_action('wp_ajax_studiou_wcfpp_download_zip', array($this, 'ajax_download_zip'));
         add_action('wp_ajax_studiou_wcfpp_bulk_status', array($this, 'ajax_bulk_status'));
 
-        // Handle direct ZIP download
+        // Handle direct ZIP download and file download (marks as downloaded)
         add_action('admin_init', array($this, 'handle_zip_download'));
+        add_action('admin_init', array($this, 'handle_file_download'));
     }
 
     public function render_summary_page() {
@@ -251,6 +252,55 @@ class Studiou_WC_FPP_Admin {
         exit;
     }
 
+    /**
+     * Handle single file download — serves the file and marks status as "downloaded".
+     */
+    public function handle_file_download() {
+        if (!isset($_GET['studiou_fpp_download_file'])) {
+            return;
+        }
+
+        if (!wp_verify_nonce($_GET['_wpnonce'] ?? '', 'studiou-fpp-download-file')) {
+            wp_die(__('Security check failed.', 'studiou-wc-free-photo-product'));
+        }
+
+        if (!current_user_can('manage_woocommerce')) {
+            wp_die(__('Insufficient permissions.', 'studiou-wc-free-photo-product'));
+        }
+
+        $file_record_id = isset($_GET['file_record_id']) ? absint($_GET['file_record_id']) : 0;
+        $attachment_id = isset($_GET['attachment_id']) ? absint($_GET['attachment_id']) : 0;
+
+        if (!$attachment_id) {
+            wp_die(__('File not found.', 'studiou-wc-free-photo-product'));
+        }
+
+        // Mark as downloaded
+        if ($file_record_id) {
+            $record = $this->db->get_file_record($file_record_id);
+            if ($record && $record->status === 'ready') {
+                $this->db->update_file_status($file_record_id, 'downloaded');
+            }
+        }
+
+        // Serve the file
+        $file_path = get_attached_file($attachment_id);
+        if (!$file_path || !file_exists($file_path)) {
+            wp_die(__('File not found.', 'studiou-wc-free-photo-product'));
+        }
+
+        $file_name = basename($file_path);
+        $mime_type = mime_content_type($file_path) ?: 'application/octet-stream';
+
+        header('Content-Type: ' . $mime_type);
+        header('Content-Disposition: attachment; filename="' . $file_name . '"');
+        header('Content-Length: ' . filesize($file_path));
+        header('Pragma: no-cache');
+
+        readfile($file_path);
+        exit;
+    }
+
     public static function get_status_label($status) {
         $labels = array(
             'ready'      => __('Ready', 'studiou-wc-free-photo-product'),

+ 11 - 1
studiou-wc-free-photo-product/includes/class-studiou-wc-fpp-cart.php

@@ -259,8 +259,18 @@ class Studiou_WC_FPP_Cart {
             return;
         }
 
+        $file_record_id = $item->get_meta('_studiou_fpp_file_record_id');
+
+        // Build download URL that also marks file as downloaded
+        $download_url = add_query_arg(array(
+            'studiou_fpp_download_file' => 1,
+            'file_record_id' => $file_record_id ?: 0,
+            'attachment_id' => $attachment_id,
+            '_wpnonce' => wp_create_nonce('studiou-fpp-download-file'),
+        ), admin_url('admin.php'));
+
         echo '<p class="studiou-fpp-order-download">';
-        echo '<a href="' . esc_url($file_url) . '" download class="button button-small">';
+        echo '<a href="' . esc_url($download_url) . '" class="button button-small">';
         echo '<span class="dashicons dashicons-download" style="line-height:1.4;vertical-align:middle;"></span> ';
         echo esc_html__('Download uploaded photo', 'studiou-wc-free-photo-product');
         echo '</a>';

+ 7 - 1
studiou-wc-free-photo-product/languages/studiou-wc-free-photo-product-cs_CZ.po

@@ -3,7 +3,7 @@
 # This file is distributed under the GPL v2 or later.
 msgid ""
 msgstr ""
-"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.1.7\n"
+"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.2.0\n"
 "Report-Msgid-Bugs-To: https://www.quadarax.com\n"
 "POT-Creation-Date: 2026-04-02 00:00+0000\n"
 "PO-Revision-Date: 2026-04-02 00:00+0000\n"
@@ -28,6 +28,12 @@ msgstr "Opravdu chcete smazat vybrané soubory?"
 msgid "Are you sure you want to delete this file?"
 msgstr "Opravdu chcete smazat tento soubor?"
 
+msgid "Download selected files as ZIP archive?"
+msgstr "Stáhnout vybrané soubory jako ZIP archiv?"
+
+msgid "Are you sure you want to change the status of the selected files?"
+msgstr "Opravdu chcete změnit stav vybraných souborů?"
+
 msgid "No files selected."
 msgstr "Nejsou vybrány žádné soubory."
 

+ 9 - 1
studiou-wc-free-photo-product/languages/studiou-wc-free-photo-product.pot

@@ -2,7 +2,7 @@
 # This file is distributed under the GPL v2 or later.
 msgid ""
 msgstr ""
-"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.1.7\n"
+"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.2.0\n"
 "Report-Msgid-Bugs-To: https://www.quadarax.com\n"
 "POT-Creation-Date: 2026-04-02 00:00+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
@@ -30,6 +30,14 @@ msgstr ""
 msgid "Are you sure you want to delete this file?"
 msgstr ""
 
+#: studiou-wc-free-photo-product.php
+msgid "Download selected files as ZIP archive?"
+msgstr ""
+
+#: studiou-wc-free-photo-product.php
+msgid "Are you sure you want to change the status of the selected files?"
+msgstr ""
+
 #: studiou-wc-free-photo-product.php
 msgid "No files selected."
 msgstr ""

+ 6 - 2
studiou-wc-free-photo-product/studiou-wc-free-photo-product.php

@@ -3,7 +3,7 @@
  * Plugin Name: QDR - Studiou WC Free Photo Product
  * Plugin URI: https://www.quadarax.com/plugins/studiou-wc-free-photo-product
  * Description: Allows publishing special WooCommerce products with variants and custom raw image upload for photo printing
- * Version: 1.1.7
+ * Version: 1.2.0
  * Requires at least: 6.9.4
  * Requires PHP: 8.2
  * Author: Dalibor Votruba
@@ -21,7 +21,7 @@ if (!defined('WPINC')) {
     die;
 }
 
-if (!defined('STUDIOU_WCFPP_VERSION')) define('STUDIOU_WCFPP_VERSION', '1.1.7');
+if (!defined('STUDIOU_WCFPP_VERSION')) define('STUDIOU_WCFPP_VERSION', '1.2.0');
 if (!defined('STUDIOU_WCFPP_PLUGIN_DIR')) define('STUDIOU_WCFPP_PLUGIN_DIR', plugin_dir_path(__FILE__));
 if (!defined('STUDIOU_WCFPP_PLUGIN_URL')) define('STUDIOU_WCFPP_PLUGIN_URL', plugin_dir_url(__FILE__));
 if (!defined('STUDIOU_WCFPP_PLUGIN_BASENAME')) define('STUDIOU_WCFPP_PLUGIN_BASENAME', plugin_basename(__FILE__));
@@ -136,6 +136,8 @@ class Studiou_WC_Free_Photo_Product {
                 'i18n' => array(
                     'confirmDelete' => __('Are you sure you want to delete the selected files?', 'studiou-wc-free-photo-product'),
                     'confirmDeleteSingle' => __('Are you sure you want to delete this file?', 'studiou-wc-free-photo-product'),
+                    'confirmDownloadZip' => __('Download selected files as ZIP archive?', 'studiou-wc-free-photo-product'),
+                    'confirmStatusChange' => __('Are you sure you want to change the status of the selected files?', 'studiou-wc-free-photo-product'),
                     'noFilesSelected' => __('No files selected.', 'studiou-wc-free-photo-product'),
                     'statusUpdated' => __('Status updated.', 'studiou-wc-free-photo-product'),
                     'error' => __('An error occurred.', 'studiou-wc-free-photo-product'),
@@ -166,6 +168,8 @@ class Studiou_WC_Free_Photo_Product {
                 'i18n' => array(
                     'confirmDelete' => __('Are you sure you want to delete the selected files?', 'studiou-wc-free-photo-product'),
                     'confirmDeleteSingle' => __('Are you sure you want to delete this file?', 'studiou-wc-free-photo-product'),
+                    'confirmDownloadZip' => __('Download selected files as ZIP archive?', 'studiou-wc-free-photo-product'),
+                    'confirmStatusChange' => __('Are you sure you want to change the status of the selected files?', 'studiou-wc-free-photo-product'),
                     'noFilesSelected' => __('No files selected.', 'studiou-wc-free-photo-product'),
                     'statusUpdated' => __('Status updated.', 'studiou-wc-free-photo-product'),
                     'error' => __('An error occurred.', 'studiou-wc-free-photo-product'),

+ 25 - 2
studiou-wc-free-photo-product/views/admin-summary.php

@@ -110,6 +110,14 @@ $base_url = admin_url('edit.php?post_type=product&page=studiou-fpp-summary');
                     } else {
                         $order_link = '<span class="studiou-fpp-no-order">—</span>';
                     }
+
+                    // Download URL that also marks file as downloaded
+                    $download_url = add_query_arg(array(
+                        'studiou_fpp_download_file' => 1,
+                        'file_record_id' => $record->id,
+                        'attachment_id' => $record->attachment_id,
+                        '_wpnonce' => wp_create_nonce('studiou-fpp-download-file'),
+                    ), admin_url('admin.php'));
                     ?>
                     <tr data-file-id="<?php echo esc_attr($record->id); ?>">
                         <th scope="row" class="check-column">
@@ -146,7 +154,7 @@ $base_url = admin_url('edit.php?post_type=product&page=studiou-fpp-summary');
                         </td>
                         <td class="column-actions">
                             <?php if ($attachment_url) : ?>
-                                <a href="<?php echo esc_url($attachment_url); ?>" class="button button-small" download title="<?php esc_attr_e('Download', 'studiou-wc-free-photo-product'); ?>">
+                                <a href="<?php echo esc_url($download_url); ?>" class="button button-small" title="<?php esc_attr_e('Download', 'studiou-wc-free-photo-product'); ?>">
                                     <span class="dashicons dashicons-download" style="line-height:1.4;"></span>
                                 </a>
                             <?php endif; ?>
@@ -164,9 +172,24 @@ $base_url = admin_url('edit.php?post_type=product&page=studiou-fpp-summary');
     <?php if ($total_pages > 1) : ?>
         <div class="tablenav bottom">
             <div class="tablenav-pages">
+                <span class="displaying-num">
+                    <?php echo esc_html(sprintf(
+                        _n('%d file', '%d files', $total, 'studiou-wc-free-photo-product'),
+                        $total
+                    )); ?>
+                </span>
                 <?php
+                // Preserve filters in pagination links
+                $pagination_args = array(
+                    'post_type'  => 'product',
+                    'page'       => 'studiou-fpp-summary',
+                );
+                if ($current_status) $pagination_args['status'] = $current_status;
+                if ($current_product) $pagination_args['product_id'] = $current_product;
+                if ($current_search) $pagination_args['s'] = $current_search;
+
                 $pagination = paginate_links(array(
-                    'base'      => add_query_arg('paged', '%#%'),
+                    'base'      => add_query_arg('paged', '%#%', admin_url('edit.php?' . http_build_query($pagination_args))),
                     'format'    => '',
                     'current'   => $current_page,
                     'total'     => $total_pages,