class-studiou-wcmp-admin.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <?php
  2. /**
  3. * StudioU WC Mandatory Products Admin
  4. *
  5. * @package StudioU_WC_Mandatory_Products
  6. */
  7. // Exit if accessed directly
  8. if (!defined('ABSPATH')) {
  9. exit;
  10. }
  11. class StudioU_WCMP_Admin {
  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 fields to product category edit page
  23. add_action('product_cat_edit_form_fields', array($this, 'add_category_fields'), 20);
  24. // Add fields to product category add page
  25. add_action('product_cat_add_form_fields', array($this, 'add_category_fields_new'), 20);
  26. // Save category fields
  27. add_action('edited_product_cat', array($this, 'save_category_fields'), 20);
  28. add_action('created_product_cat', array($this, 'save_category_fields'), 20);
  29. // Add admin scripts and styles
  30. add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
  31. // Add product meta box to show mandatory products info
  32. add_action('add_meta_boxes', array($this, 'add_product_meta_boxes'));
  33. }
  34. /**
  35. * Add fields to product category edit form
  36. *
  37. * @param object $term The term object
  38. */
  39. public function add_category_fields($term) {
  40. // Get current value
  41. $mandatory_products = get_term_meta($term->term_id, 'mandatory_products', true);
  42. // If not array, initialize it
  43. if (!is_array($mandatory_products)) {
  44. $mandatory_products = array();
  45. }
  46. ?>
  47. <tr class="form-field">
  48. <th scope="row" valign="top">
  49. <label><?php _e('Mandatory Products', 'studiou-wc-product-cat-manage'); ?></label>
  50. </th>
  51. <td>
  52. <div id="studiou_mandatory_products_container">
  53. <?php if (!empty($mandatory_products)) : ?>
  54. <?php foreach ($mandatory_products as $index => $mandatory_product) :
  55. $product_id = isset($mandatory_product['product_id']) ? absint($mandatory_product['product_id']) : 0;
  56. $quantity = isset($mandatory_product['quantity']) ? absint($mandatory_product['quantity']) : 1;
  57. $type = isset($mandatory_product['type']) ? sanitize_text_field($mandatory_product['type']) : 'OnePerCart';
  58. $product_title = '';
  59. if ($product_id > 0) {
  60. $product = wc_get_product($product_id);
  61. if ($product) {
  62. $product_title = $product->get_formatted_name();
  63. }
  64. }
  65. ?>
  66. <div class="mandatory-product-row" style="margin-bottom: 10px; padding: 10px; border: 1px solid #ddd; background: #f9f9f9;">
  67. <p>
  68. <label><?php _e('Product:', 'studiou-wc-product-cat-manage'); ?></label>
  69. <select
  70. class="wc-product-search"
  71. style="width: 50%;"
  72. name="mandatory_product_id[]"
  73. data-placeholder="<?php esc_attr_e('Search for a product&hellip;', 'studiou-wc-product-cat-manage'); ?>"
  74. data-action="woocommerce_json_search_products_and_variations"
  75. data-allow_clear="true"
  76. >
  77. <?php if ($product_id && $product_title) : ?>
  78. <option value="<?php echo esc_attr($product_id); ?>" selected="selected"><?php echo esc_html($product_title); ?></option>
  79. <?php endif; ?>
  80. </select>
  81. </p>
  82. <p>
  83. <label><?php _e('Quantity:', 'studiou-wc-product-cat-manage'); ?></label>
  84. <input type="number" name="mandatory_product_quantity[]" value="<?php echo esc_attr($quantity); ?>" min="1" step="1" style="width: 80px;" />
  85. </p>
  86. <p>
  87. <label><?php _e('Type:', 'studiou-wc-product-cat-manage'); ?></label>
  88. <select name="mandatory_product_type[]">
  89. <option value="OnePerCart" <?php selected($type, 'OnePerCart'); ?>><?php _e('One Per Cart', 'studiou-wc-product-cat-manage'); ?></option>
  90. <option value="OnePerProduct" <?php selected($type, 'OnePerProduct'); ?>><?php _e('One Per Product', 'studiou-wc-product-cat-manage'); ?></option>
  91. </select>
  92. </p>
  93. <p>
  94. <button type="button" class="button remove-mandatory-product"><?php _e('Remove', 'studiou-wc-product-cat-manage'); ?></button>
  95. </p>
  96. </div>
  97. <?php endforeach; ?>
  98. <?php endif; ?>
  99. </div>
  100. <p>
  101. <button type="button" class="button add-mandatory-product"><?php _e('Add Mandatory Product', 'studiou-wc-mandatory-products'); ?></button>
  102. </p>
  103. <p class="description">
  104. <?php _e('These products will be automatically added to the cart when a product from this category is added.', 'studiou-wc-product-cat-manage'); ?>
  105. <br>
  106. <?php _e('Note: Child categories will inherit these settings.', 'studiou-wc-product-cat-manage'); ?>
  107. </p>
  108. </td>
  109. </tr>
  110. <script type="text/template" id="tmpl-mandatory-product-row">
  111. <div class="mandatory-product-row" style="margin-bottom: 10px; padding: 10px; border: 1px solid #ddd; background: #f9f9f9;">
  112. <p>
  113. <label><?php _e('Product:', 'studiou-wc-mandatory-products'); ?></label>
  114. <select
  115. class="wc-product-search"
  116. style="width: 50%;"
  117. name="mandatory_product_id[]"
  118. data-placeholder="<?php esc_attr_e('Search for a product&hellip;', 'studiou-wc-mandatory-products'); ?>"
  119. data-action="woocommerce_json_search_products_and_variations"
  120. data-allow_clear="true"
  121. ></select>
  122. </p>
  123. <p>
  124. <label><?php _e('Quantity:', 'studiou-wc-mandatory-products'); ?></label>
  125. <input type="number" name="mandatory_product_quantity[]" value="1" min="1" step="1" style="width: 80px;" />
  126. </p>
  127. <p>
  128. <label><?php _e('Type:', 'studiou-wc-mandatory-products'); ?></label>
  129. <select name="mandatory_product_type[]">
  130. <option value="OnePerCart"><?php _e('One Per Cart', 'studiou-wc-mandatory-products'); ?></option>
  131. <option value="OnePerProduct"><?php _e('One Per Product', 'studiou-wc-mandatory-products'); ?></option>
  132. </select>
  133. </p>
  134. <p>
  135. <button type="button" class="button remove-mandatory-product"><?php _e('Remove', 'studiou-wc-mandatory-products'); ?></button>
  136. </p>
  137. </div>
  138. </script>
  139. <?php
  140. }
  141. /**
  142. * Add fields to product category add form
  143. */
  144. public function add_category_fields_new() {
  145. ?>
  146. <div class="form-field">
  147. <label><?php _e('Mandatory Products', 'studiou-wc-mandatory-products'); ?></label>
  148. <div id="studiou_mandatory_products_container">
  149. <!-- Empty container for new category -->
  150. </div>
  151. <p>
  152. <button type="button" class="button add-mandatory-product"><?php _e('Add Mandatory Product', 'studiou-wc-mandatory-products'); ?></button>
  153. </p>
  154. <p class="description">
  155. <?php _e('These products will be automatically added to the cart when a product from this category is added.', 'studiou-wc-mandatory-products'); ?>
  156. <br>
  157. <?php _e('Note: Child categories will inherit these settings.', 'studiou-wc-mandatory-products'); ?>
  158. </p>
  159. </div>
  160. <script type="text/template" id="tmpl-mandatory-product-row">
  161. <div class="mandatory-product-row" style="margin-bottom: 10px; padding: 10px; border: 1px solid #ddd; background: #f9f9f9;">
  162. <p>
  163. <label><?php _e('Product:', 'studiou-wc-mandatory-products'); ?></label>
  164. <select
  165. class="wc-product-search"
  166. style="width: 50%;"
  167. name="mandatory_product_id[]"
  168. data-placeholder="<?php esc_attr_e('Search for a product&hellip;', 'studiou-wc-mandatory-products'); ?>"
  169. data-action="woocommerce_json_search_products_and_variations"
  170. data-allow_clear="true"
  171. ></select>
  172. </p>
  173. <p>
  174. <label><?php _e('Quantity:', 'studiou-wc-mandatory-products'); ?></label>
  175. <input type="number" name="mandatory_product_quantity[]" value="1" min="1" step="1" style="width: 80px;" />
  176. </p>
  177. <p>
  178. <label><?php _e('Type:', 'studiou-wc-mandatory-products'); ?></label>
  179. <select name="mandatory_product_type[]">
  180. <option value="OnePerCart"><?php _e('One Per Cart', 'studiou-wc-mandatory-products'); ?></option>
  181. <option value="OnePerProduct"><?php _e('One Per Product', 'studiou-wc-mandatory-products'); ?></option>
  182. </select>
  183. </p>
  184. <p>
  185. <button type="button" class="button remove-mandatory-product"><?php _e('Remove', 'studiou-wc-mandatory-products'); ?></button>
  186. </p>
  187. </div>
  188. </script>
  189. <?php
  190. }
  191. /**
  192. * Save category fields
  193. *
  194. * @param int $term_id The term ID
  195. */
  196. public function save_category_fields($term_id) {
  197. $mandatory_products = array();
  198. if (isset($_POST['mandatory_product_id']) && is_array($_POST['mandatory_product_id'])) {
  199. $product_ids = array_map('absint', $_POST['mandatory_product_id']);
  200. $quantities = isset($_POST['mandatory_product_quantity']) ? array_map('absint', $_POST['mandatory_product_quantity']) : array();
  201. $types = isset($_POST['mandatory_product_type']) ? array_map('sanitize_text_field', $_POST['mandatory_product_type']) : array();
  202. foreach ($product_ids as $index => $product_id) {
  203. // Skip if product ID is empty
  204. if (empty($product_id)) {
  205. continue;
  206. }
  207. $quantity = isset($quantities[$index]) ? max(1, $quantities[$index]) : 1;
  208. $type = isset($types[$index]) ? $types[$index] : 'OnePerCart';
  209. // Validate type
  210. if (!in_array($type, array('OnePerCart', 'OnePerProduct'))) {
  211. $type = 'OnePerCart';
  212. }
  213. $mandatory_products[] = array(
  214. 'product_id' => $product_id,
  215. 'quantity' => $quantity,
  216. 'type' => $type
  217. );
  218. }
  219. }
  220. update_term_meta($term_id, 'mandatory_products', $mandatory_products);
  221. }
  222. /**
  223. * Enqueue admin scripts and styles
  224. *
  225. * @param string $hook Current admin page
  226. */
  227. public function enqueue_admin_scripts($hook) {
  228. // Only on category edit page
  229. if ('edit-tags.php' !== $hook && 'term.php' !== $hook) {
  230. return;
  231. }
  232. // Check if we're on the product category screen
  233. $screen = get_current_screen();
  234. if (!$screen || 'product_cat' !== $screen->taxonomy) {
  235. return;
  236. }
  237. // WooCommerce admin scripts
  238. wp_enqueue_style('woocommerce_admin_styles');
  239. wp_enqueue_script('wc-enhanced-select');
  240. // Add our custom JS to properly initialize SelectWoo
  241. wp_enqueue_script(
  242. 'studiou-wcmp-admin-js',
  243. STUDIOU_WCMP_PLUGIN_URL . 'assets/js/admin.js',
  244. array('jquery', 'wc-enhanced-select', 'wp-util'),
  245. STUDIOU_WCMP_VERSION,
  246. true
  247. );
  248. }
  249. /**
  250. * Add product meta boxes
  251. */
  252. public function add_product_meta_boxes() {
  253. add_meta_box(
  254. 'studiou-wcmp-mandatory-products',
  255. __('Mandatory Products Info', 'studiou-wc-product-cat-manage'),
  256. array($this, 'render_product_meta_box'),
  257. 'product',
  258. 'side',
  259. 'default'
  260. );
  261. }
  262. /**
  263. * Render product meta box
  264. *
  265. * @param WP_Post $post The post object
  266. */
  267. public function render_product_meta_box($post) {
  268. $product_id = $post->ID;
  269. // Get plugin instance
  270. $plugin = new StudioU_WC_Mandatory_Products();
  271. // Get mandatory products
  272. $mandatory_products = $plugin->get_mandatory_products($product_id);
  273. if (empty($mandatory_products)) {
  274. echo '<p>' . __('No mandatory products set for this product\'s categories.', 'studiou-wc-mandatory-products') . '</p>';
  275. return;
  276. }
  277. echo '<p>' . __('This product has mandatory products set in its categories:', 'studiou-wc-mandatory-products') . '</p>';
  278. echo '<ul>';
  279. foreach ($mandatory_products as $mandatory_product) {
  280. $product_id = absint($mandatory_product['product_id']);
  281. $quantity = absint($mandatory_product['quantity']);
  282. $type = sanitize_text_field($mandatory_product['type']);
  283. $mandatory_product_obj = wc_get_product($product_id);
  284. if ($mandatory_product_obj) {
  285. echo '<li>';
  286. echo sprintf(
  287. '%s x %d (%s)',
  288. $mandatory_product_obj->get_name(),
  289. $quantity,
  290. $type === 'OnePerCart' ? __('One per cart', 'studiou-wc-mandatory-products') : __('One per product', 'studiou-wc-mandatory-products')
  291. );
  292. echo '</li>';
  293. }
  294. }
  295. echo '</ul>';
  296. echo '<p class="description">' . __('These products will be automatically added to the customer\'s cart when this product is added.', 'studiou-wc-mandatory-products') . '</p>';
  297. }
  298. }