class-studiou-wc-fpp-cart.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <?php
  2. if (!defined('WPINC')) {
  3. die;
  4. }
  5. class Studiou_WC_FPP_Cart {
  6. /** @var Studiou_WC_FPP_DB */
  7. private $db;
  8. public function __construct($db) {
  9. $this->db = $db;
  10. // Capture file data from WC session on add-to-cart
  11. add_filter('woocommerce_add_cart_item_data', array($this, 'add_cart_item_data'), 10, 3);
  12. // Display uploaded file info in cart
  13. add_filter('woocommerce_get_item_data', array($this, 'display_cart_item_data'), 10, 2);
  14. // Replace cart item thumbnail with uploaded image (classic cart)
  15. add_filter('woocommerce_cart_item_thumbnail', array($this, 'cart_item_thumbnail'), 10, 3);
  16. // Show uploaded photo preview directly after item name in cart (classic cart)
  17. add_action('woocommerce_after_cart_item_name', array($this, 'show_cart_item_photo_preview'), 10, 2);
  18. // Override product image for block cart (Store API) — returns uploaded photo as product image
  19. add_filter('woocommerce_product_get_image_id', array($this, 'override_product_image_for_cart'), 10, 2);
  20. add_filter('woocommerce_product_variation_get_image_id', array($this, 'override_product_image_for_cart'), 10, 2);
  21. // Save file reference to order item
  22. add_action('woocommerce_checkout_create_order_line_item', array($this, 'save_order_item_meta'), 10, 4);
  23. // Link file records to order after checkout (classic + block checkout)
  24. add_action('woocommerce_checkout_order_processed', array($this, 'link_files_to_order'), 10, 3);
  25. add_action('woocommerce_store_api_checkout_order_processed', array($this, 'link_files_to_order_from_store_api'), 10, 1);
  26. add_action('woocommerce_thankyou', array($this, 'link_files_to_order_fallback'), 10, 1);
  27. // Replace order item thumbnail with uploaded image (admin)
  28. add_filter('woocommerce_admin_order_item_thumbnail', array($this, 'admin_order_item_thumbnail'), 10, 3);
  29. // Add download link to order item in admin
  30. add_action('woocommerce_after_order_itemmeta', array($this, 'admin_order_item_download_link'), 10, 3);
  31. }
  32. public function add_cart_item_data($cart_item_data, $product_id, $variation_id) {
  33. // Check if this product (or its parent) is FPP enabled
  34. $fpp_product_id = $product_id;
  35. if (!Studiou_WC_FPP_Product::is_fpp_product($product_id)) {
  36. $product = wc_get_product($product_id);
  37. if ($product && $product->get_parent_id() && Studiou_WC_FPP_Product::is_fpp_product($product->get_parent_id())) {
  38. $fpp_product_id = $product->get_parent_id();
  39. } else {
  40. return $cart_item_data;
  41. }
  42. }
  43. // Read file data from WC session
  44. if (!WC()->session) {
  45. return $cart_item_data;
  46. }
  47. $attachment_id = WC()->session->get('studiou_fpp_attachment_id');
  48. $file_record_id = WC()->session->get('studiou_fpp_file_record_id');
  49. $file_name = WC()->session->get('studiou_fpp_file_name');
  50. $thumb_url = WC()->session->get('studiou_fpp_thumb_url');
  51. if (!$attachment_id || !$file_record_id) {
  52. return $cart_item_data;
  53. }
  54. // Verify the file record exists
  55. $record = $this->db->get_file_record($file_record_id);
  56. if (!$record || (int) $record->attachment_id !== (int) $attachment_id) {
  57. return $cart_item_data;
  58. }
  59. $cart_item_data['studiou_fpp_attachment_id'] = $attachment_id;
  60. $cart_item_data['studiou_fpp_file_record_id'] = $file_record_id;
  61. $cart_item_data['studiou_fpp_file_name'] = $file_name ?: $record->file_name;
  62. $cart_item_data['studiou_fpp_thumb_url'] = $thumb_url ?: '';
  63. // Update file record with variation
  64. $actual_variation_id = $variation_id ?: $product_id;
  65. $this->db->update_file_record($file_record_id, array(
  66. 'variation_id' => $actual_variation_id,
  67. ));
  68. // Keep session data so the same photo can be used for multiple variants
  69. return $cart_item_data;
  70. }
  71. public function cart_item_thumbnail($thumbnail, $cart_item, $cart_item_key) {
  72. $url = $this->get_cart_item_thumb_url($cart_item);
  73. if ($url) {
  74. $alt = isset($cart_item['studiou_fpp_file_name']) ? esc_attr($cart_item['studiou_fpp_file_name']) : '';
  75. return '<img src="' . esc_url($url) . '" alt="' . $alt . '" class="attachment-woocommerce_thumbnail" />';
  76. }
  77. return $thumbnail;
  78. }
  79. /**
  80. * Override product/variation image_id when rendered in cart context (block cart / Store API).
  81. * Returns the uploaded photo attachment_id so the block cart shows it instead of placeholder.
  82. */
  83. public function override_product_image_for_cart($image_id, $product) {
  84. if (!WC()->cart) {
  85. return $image_id;
  86. }
  87. $product_id = $product->get_id();
  88. foreach (WC()->cart->get_cart() as $cart_item) {
  89. if (empty($cart_item['studiou_fpp_attachment_id'])) {
  90. continue;
  91. }
  92. $match = false;
  93. if (isset($cart_item['variation_id']) && $cart_item['variation_id'] == $product_id) {
  94. $match = true;
  95. } elseif ($cart_item['product_id'] == $product_id) {
  96. $match = true;
  97. }
  98. if ($match) {
  99. return (int) $cart_item['studiou_fpp_attachment_id'];
  100. }
  101. }
  102. return $image_id;
  103. }
  104. public function display_cart_item_data($item_data, $cart_item) {
  105. if (isset($cart_item['studiou_fpp_file_name'])) {
  106. $item_data[] = array(
  107. 'name' => __('Uploaded Photo', 'studiou-wc-free-photo-product'),
  108. 'value' => esc_html($cart_item['studiou_fpp_file_name']),
  109. 'display' => '',
  110. );
  111. }
  112. return $item_data;
  113. }
  114. public function show_cart_item_photo_preview($cart_item, $cart_item_key) {
  115. $url = $this->get_cart_item_thumb_url($cart_item);
  116. if ($url) {
  117. echo '<div class="studiou-fpp-cart-preview">';
  118. echo '<img src="' . esc_url($url) . '" alt="' . esc_attr($cart_item['studiou_fpp_file_name'] ?? '') . '" />';
  119. echo '</div>';
  120. }
  121. }
  122. private function get_cart_item_thumb_url($cart_item) {
  123. // 1. Use stored URL from session (most reliable)
  124. if (!empty($cart_item['studiou_fpp_thumb_url'])) {
  125. return $cart_item['studiou_fpp_thumb_url'];
  126. }
  127. // 2. Try WP attachment lookup
  128. if (!empty($cart_item['studiou_fpp_attachment_id'])) {
  129. $att_id = (int) $cart_item['studiou_fpp_attachment_id'];
  130. $thumb = wp_get_attachment_image_src($att_id, 'thumbnail');
  131. if ($thumb) {
  132. return $thumb[0];
  133. }
  134. $url = wp_get_attachment_url($att_id);
  135. if ($url) {
  136. return $url;
  137. }
  138. }
  139. return '';
  140. }
  141. public function save_order_item_meta($item, $cart_item_key, $values, $order) {
  142. if (isset($values['studiou_fpp_attachment_id'])) {
  143. $item->add_meta_data('_studiou_fpp_attachment_id', $values['studiou_fpp_attachment_id']);
  144. }
  145. if (isset($values['studiou_fpp_file_record_id'])) {
  146. $item->add_meta_data('_studiou_fpp_file_record_id', $values['studiou_fpp_file_record_id']);
  147. }
  148. if (isset($values['studiou_fpp_file_name'])) {
  149. $item->add_meta_data('_studiou_fpp_file_name', $values['studiou_fpp_file_name']);
  150. $item->add_meta_data(__('Uploaded Photo', 'studiou-wc-free-photo-product'), $values['studiou_fpp_file_name']);
  151. }
  152. if (isset($values['studiou_fpp_thumb_url'])) {
  153. $item->add_meta_data('_studiou_fpp_thumb_url', $values['studiou_fpp_thumb_url']);
  154. }
  155. }
  156. public function link_files_to_order($order_id, $posted_data, $order) {
  157. $this->do_link_files($order);
  158. }
  159. /**
  160. * Block checkout fires this hook with only the $order parameter.
  161. */
  162. public function link_files_to_order_from_store_api($order) {
  163. $this->do_link_files($order);
  164. }
  165. /**
  166. * Fallback: runs on thank-you page to catch any missed linking.
  167. */
  168. public function link_files_to_order_fallback($order_id) {
  169. $order = wc_get_order($order_id);
  170. if ($order) {
  171. $this->do_link_files($order);
  172. }
  173. }
  174. private function do_link_files($order) {
  175. if (!$order) {
  176. return;
  177. }
  178. $order_id = $order->get_id();
  179. foreach ($order->get_items() as $item_id => $item) {
  180. $file_record_id = $item->get_meta('_studiou_fpp_file_record_id');
  181. if ($file_record_id) {
  182. // Only link if not already linked
  183. $record = $this->db->get_file_record((int) $file_record_id);
  184. if ($record && (int) $record->order_id === 0) {
  185. $this->db->link_file_to_order((int) $file_record_id, $order_id, $item_id);
  186. }
  187. }
  188. }
  189. }
  190. public function admin_order_item_thumbnail($thumbnail, $item_id, $item) {
  191. // Try stored URL first
  192. $thumb_url = $item->get_meta('_studiou_fpp_thumb_url');
  193. if ($thumb_url) {
  194. return '<img src="' . esc_url($thumb_url) . '" alt="" class="wc-block-components-product-image" width="50" height="50" />';
  195. }
  196. // Fallback to attachment lookup
  197. $attachment_id = $item->get_meta('_studiou_fpp_attachment_id');
  198. if ($attachment_id) {
  199. $image = wp_get_attachment_image($attachment_id, 'thumbnail');
  200. if ($image) {
  201. return $image;
  202. }
  203. $url = wp_get_attachment_url($attachment_id);
  204. if ($url) {
  205. return '<img src="' . esc_url($url) . '" alt="" width="50" height="50" />';
  206. }
  207. }
  208. return $thumbnail;
  209. }
  210. public function admin_order_item_download_link($item_id, $item, $product) {
  211. $attachment_id = $item->get_meta('_studiou_fpp_attachment_id');
  212. if (!$attachment_id) {
  213. return;
  214. }
  215. $file_url = wp_get_attachment_url($attachment_id);
  216. $file_name = $item->get_meta('_studiou_fpp_file_name');
  217. if (!$file_url) {
  218. return;
  219. }
  220. $file_record_id = $item->get_meta('_studiou_fpp_file_record_id');
  221. // Build download URL that also marks file as downloaded
  222. $download_url = add_query_arg(array(
  223. 'studiou_fpp_download_file' => 1,
  224. 'file_record_id' => $file_record_id ?: 0,
  225. 'attachment_id' => $attachment_id,
  226. '_wpnonce' => wp_create_nonce('studiou-fpp-download-file'),
  227. ), admin_url('admin.php'));
  228. echo '<p class="studiou-fpp-order-download">';
  229. echo '<a href="' . esc_url($download_url) . '" class="button button-small">';
  230. echo '<span class="dashicons dashicons-download" style="line-height:1.4;vertical-align:middle;"></span> ';
  231. echo esc_html__('Download uploaded photo', 'studiou-wc-free-photo-product');
  232. echo '</a>';
  233. if ($file_name) {
  234. echo ' <small>(' . esc_html($file_name) . ')</small>';
  235. }
  236. echo '</p>';
  237. }
  238. }