class-studiou-wcmp-frontend.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <?php
  2. /**
  3. * StudioU WC Mandatory Products Frontend
  4. *
  5. * @package StudioU_WC_Mandatory_Products
  6. */
  7. // Exit if accessed directly
  8. if (!defined('ABSPATH')) {
  9. exit;
  10. }
  11. class StudioU_WCMP_Frontend {
  12. /**
  13. * Constructor
  14. */
  15. public function __construct() {
  16. // Nothing to do at constructor
  17. }
  18. /**
  19. * Initialize hooks
  20. */
  21. public function init() {
  22. // Add CSS for frontend
  23. add_action('wp_enqueue_scripts', array($this, 'enqueue_styles'));
  24. // Add custom item data to cart item
  25. add_filter('woocommerce_get_item_data', array($this, 'add_cart_item_data'), 10, 2);
  26. // Prevent quantity changes for mandatory products
  27. add_filter('woocommerce_cart_item_quantity', array($this, 'adjust_cart_item_quantity'), 10, 3);
  28. // Make mandatory products non-removable if needed
  29. add_filter('woocommerce_cart_item_remove_link', array($this, 'adjust_cart_item_remove_link'), 10, 2);
  30. // Validate cart to ensure mandatory products are present
  31. add_action('woocommerce_check_cart_items', array($this, 'validate_cart_has_mandatory_products'));
  32. }
  33. /**
  34. * Enqueue frontend styles
  35. */
  36. public function enqueue_styles() {
  37. if (is_product() || is_cart()) {
  38. wp_enqueue_style(
  39. 'studiou-wcmp-styles',
  40. STUDIOU_WCMP_PLUGIN_URL . 'assets/css/frontend.css',
  41. array(),
  42. STUDIOU_WCMP_VERSION
  43. );
  44. }
  45. }
  46. /**
  47. * Add custom item data to cart item
  48. *
  49. * @param array $item_data Cart item data
  50. * @param array $cart_item Cart item
  51. * @return array Modified item data
  52. */
  53. public function add_cart_item_data($item_data, $cart_item) {
  54. if (isset($cart_item['mandatory_product']) && $cart_item['mandatory_product']) {
  55. $item_data[] = array(
  56. 'key' => __('Mandatory Item', 'studiou-wc-product-cat-manage'),
  57. 'value' => __('This item was automatically added', 'studiou-wc-product-cat-manage')
  58. );
  59. }
  60. return $item_data;
  61. }
  62. /**
  63. * Adjust cart item quantity field for mandatory products
  64. *
  65. * @param string $product_quantity HTML of quantity field
  66. * @param string $cart_item_key Cart item key
  67. * @param array $cart_item Cart item
  68. * @return string Modified quantity field HTML
  69. */
  70. public function adjust_cart_item_quantity($product_quantity, $cart_item_key, $cart_item) {
  71. // If this is a mandatory product, make quantity field readonly
  72. if (isset($cart_item['mandatory_product']) && $cart_item['mandatory_product']) {
  73. // Get current quantity
  74. $quantity = $cart_item['quantity'];
  75. // Return readonly quantity field
  76. return sprintf(
  77. '<div class="quantity"><input type="text" value="%s" class="input-text qty text" readonly="readonly" /></div>',
  78. esc_attr($quantity)
  79. );
  80. }
  81. return $product_quantity;
  82. }
  83. /**
  84. * Adjust remove link for mandatory products
  85. *
  86. * @param string $link The cart item remove link
  87. * @param string $cart_item_key The cart item key
  88. * @return string Modified remove link
  89. */
  90. public function adjust_cart_item_remove_link($link, $cart_item_key) {
  91. $cart_item = WC()->cart->get_cart()[$cart_item_key];
  92. // If this is a mandatory product, remove the ability to remove it
  93. if (isset($cart_item['mandatory_product']) && $cart_item['mandatory_product']) {
  94. return '<span class="mandatory-product-info" title="' .
  95. esc_attr__('This is a mandatory product and cannot be removed directly', 'studiou-wc-product-cat-manage') .
  96. '"><i class="dashicons dashicons-lock"></i></span>';
  97. }
  98. return $link;
  99. }
  100. /**
  101. * Validate cart to ensure mandatory products are present
  102. */
  103. public function validate_cart_has_mandatory_products() {
  104. if (is_admin()) {
  105. return;
  106. }
  107. $cart_contents = WC()->cart->get_cart();
  108. $plugin = new StudioU_WC_Mandatory_Products();
  109. $required_mandatory_products = array();
  110. // First, get all mandatory products that should be in the cart
  111. foreach ($cart_contents as $cart_item) {
  112. // Skip if this is already a mandatory product
  113. if (isset($cart_item['mandatory_product']) && $cart_item['mandatory_product']) {
  114. continue;
  115. }
  116. $product_id = $cart_item['product_id'];
  117. $mandatory_products = $plugin->get_mandatory_products($product_id);
  118. foreach ($mandatory_products as $mandatory_product) {
  119. $mandatory_product_id = $mandatory_product['product_id'];
  120. $mandatory_product_type = $mandatory_product['type'];
  121. $mandatory_product_quantity = $mandatory_product['quantity'];
  122. // For OnePerCart, add once to requirements
  123. if ($mandatory_product_type === 'OnePerCart') {
  124. $key = 'cart_' . $mandatory_product_id;
  125. if (!isset($required_mandatory_products[$key])) {
  126. $required_mandatory_products[$key] = array(
  127. 'product_id' => $mandatory_product_id,
  128. 'quantity' => $mandatory_product_quantity,
  129. 'type' => $mandatory_product_type
  130. );
  131. }
  132. }
  133. // For OnePerProduct, add for each product
  134. else if ($mandatory_product_type === 'OnePerProduct') {
  135. $key = 'product_' . $product_id . '_' . $mandatory_product_id;
  136. if (!isset($required_mandatory_products[$key])) {
  137. $required_mandatory_products[$key] = array(
  138. 'product_id' => $mandatory_product_id,
  139. 'quantity' => $mandatory_product_quantity,
  140. 'type' => $mandatory_product_type,
  141. 'for_product_id' => $product_id
  142. );
  143. }
  144. }
  145. }
  146. }
  147. // Now check if all required mandatory products are in the cart
  148. $missing_products = array();
  149. foreach ($required_mandatory_products as $key => $required_product) {
  150. $found = false;
  151. foreach ($cart_contents as $cart_item) {
  152. if (isset($cart_item['product_id']) && $cart_item['product_id'] == $required_product['product_id']) {
  153. // For OnePerCart, just check it exists
  154. if ($required_product['type'] === 'OnePerCart') {
  155. $found = true;
  156. break;
  157. }
  158. // For OnePerProduct, check it exists for the specific product
  159. else if ($required_product['type'] === 'OnePerProduct' &&
  160. isset($cart_item['mandatory_for']) &&
  161. $cart_item['mandatory_for'] == $required_product['for_product_id']) {
  162. $found = true;
  163. break;
  164. }
  165. }
  166. }
  167. if (!$found) {
  168. $missing_products[] = $required_product;
  169. }
  170. }
  171. // If we have missing products, add them and show notice
  172. if (!empty($missing_products)) {
  173. foreach ($missing_products as $missing_product) {
  174. $product_id = $missing_product['product_id'];
  175. $quantity = $missing_product['quantity'];
  176. $type = $missing_product['type'];
  177. $extra_data = array(
  178. 'mandatory_product' => true
  179. );
  180. // For OnePerProduct, add the for_product_id
  181. if ($type === 'OnePerProduct' && isset($missing_product['for_product_id'])) {
  182. $extra_data['mandatory_for'] = $missing_product['for_product_id'];
  183. }
  184. // Add the product to cart
  185. WC()->cart->add_to_cart(
  186. $product_id,
  187. $quantity,
  188. 0, // No variation
  189. array(), // No variation data
  190. $extra_data
  191. );
  192. // Get product name
  193. $product = wc_get_product($product_id);
  194. $product_name = $product ? $product->get_name() : __('A product', 'studiou-wc-mandatory-products');
  195. // Add notice
  196. wc_add_notice(
  197. sprintf(
  198. __('%s has been automatically added to your cart as it is required.', 'studiou-wc-mandatory-products'),
  199. $product_name
  200. ),
  201. 'notice'
  202. );
  203. }
  204. }
  205. }