class-studiou-wc-product-manage-product-db.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <?php
  2. /**
  3. * Product database operations class
  4. *
  5. * Handles database operations related to products
  6. *
  7. * @since 1.4.0
  8. * @package Studiou_WC_Product_Cat_Manage
  9. * @subpackage Studiou_WC_Product_Cat_Manage/includes
  10. */
  11. // If this file is called directly, abort.
  12. if (!defined('WPINC')) {
  13. die;
  14. }
  15. class Studiou_WC_Product_Manage_Product_DB {
  16. /**
  17. * Constructor
  18. */
  19. public function __construct() {
  20. }
  21. /**
  22. * Get all product categories with hierarchy and product counts
  23. *
  24. * @return array Array of product categories with hierarchy
  25. */
  26. public function get_categories_with_hierarchy() {
  27. $args = array(
  28. 'taxonomy' => 'product_cat',
  29. 'orderby' => 'name',
  30. 'hide_empty' => false,
  31. 'hierarchical' => true,
  32. );
  33. $categories = get_terms($args);
  34. $formatted_categories = array();
  35. if (!is_wp_error($categories) && !empty($categories)) {
  36. // Build hierarchy
  37. $formatted_categories = $this->build_category_hierarchy($categories);
  38. }
  39. return $formatted_categories;
  40. }
  41. /**
  42. * Build category hierarchy with indentation
  43. *
  44. * @param array $categories Array of WP_Term objects
  45. * @param int $parent_id Parent category ID
  46. * @param string $prefix Indentation prefix
  47. * @return array Formatted category hierarchy
  48. */
  49. private function build_category_hierarchy($categories, $parent_id = 0, $prefix = '') {
  50. $result = array();
  51. foreach ($categories as $category) {
  52. if ($category->parent == $parent_id) {
  53. $result[] = array(
  54. 'term_id' => $category->term_id,
  55. 'name' => $prefix . $category->name,
  56. 'count' => $category->count
  57. );
  58. // Recursively add children with increased indentation
  59. $children = $this->build_category_hierarchy($categories, $category->term_id, $prefix . '— ');
  60. $result = array_merge($result, $children);
  61. }
  62. }
  63. return $result;
  64. }
  65. /**
  66. * Get products by category IDs
  67. *
  68. * @param array $category_ids Array of category IDs
  69. * @return array Array of product IDs
  70. */
  71. public function get_products_by_categories($category_ids) {
  72. if (empty($category_ids)) {
  73. return array();
  74. }
  75. $args = array(
  76. 'post_type' => 'product',
  77. 'post_status' => 'any',
  78. 'posts_per_page' => -1,
  79. 'fields' => 'ids',
  80. 'tax_query' => array(
  81. array(
  82. 'taxonomy' => 'product_cat',
  83. 'field' => 'term_id',
  84. 'terms' => $category_ids,
  85. 'operator' => 'IN'
  86. )
  87. )
  88. );
  89. $query = new WP_Query($args);
  90. $product_ids = $query->posts;
  91. // Also get variations
  92. foreach ($product_ids as $product_id) {
  93. $product = wc_get_product($product_id);
  94. if ($product && $product->is_type('variable')) {
  95. $variations = $product->get_children();
  96. $product_ids = array_merge($product_ids, $variations);
  97. }
  98. }
  99. return array_unique($product_ids);
  100. }
  101. /**
  102. * Get product by SKU
  103. *
  104. * @param string $sku Product SKU
  105. * @return WC_Product|null Product object or null if not found
  106. */
  107. public function get_product_by_sku($sku) {
  108. $product_id = wc_get_product_id_by_sku($sku);
  109. if ($product_id) {
  110. return wc_get_product($product_id);
  111. }
  112. return null;
  113. }
  114. /**
  115. * Check if SKU is unique (excluding specific product ID)
  116. *
  117. * @param string $sku Product SKU
  118. * @param int $exclude_id Product ID to exclude from check
  119. * @return bool True if unique, false otherwise
  120. */
  121. public function is_sku_unique($sku, $exclude_id = 0) {
  122. $product_id = wc_get_product_id_by_sku($sku);
  123. if (!$product_id) {
  124. return true; // SKU doesn't exist
  125. }
  126. if ($exclude_id > 0 && $product_id == $exclude_id) {
  127. return true; // SKU belongs to the product we're updating
  128. }
  129. return false; // SKU exists and belongs to another product
  130. }
  131. /**
  132. * Validate image URL
  133. *
  134. * @param string $url Image URL
  135. * @return bool True if valid, false otherwise
  136. */
  137. public function validate_image_url($url) {
  138. if (empty($url)) {
  139. return false;
  140. }
  141. // Check if URL is valid format
  142. if (!filter_var($url, FILTER_VALIDATE_URL)) {
  143. return false;
  144. }
  145. // Check if URL has common image extensions (optional check)
  146. $valid_extensions = array('jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp');
  147. $path_info = pathinfo(parse_url($url, PHP_URL_PATH));
  148. $extension = isset($path_info['extension']) ? strtolower($path_info['extension']) : '';
  149. // If URL has extension, verify it's an image extension
  150. // If no extension, allow it (might be dynamic URL)
  151. if (!empty($extension) && !in_array($extension, $valid_extensions)) {
  152. return false;
  153. }
  154. // Don't make HTTP request during validation - let the actual download handle failures
  155. // This prevents timeout issues during validation phase
  156. return true;
  157. }
  158. /**
  159. * Get product attribute by name
  160. *
  161. * @param string $attribute_name Attribute name
  162. * @return int|null Attribute ID or null if not found
  163. */
  164. public function get_attribute_by_name($attribute_name) {
  165. global $wpdb;
  166. $attribute_id = $wpdb->get_var($wpdb->prepare(
  167. "SELECT attribute_id FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name = %s",
  168. wc_sanitize_taxonomy_name($attribute_name)
  169. ));
  170. return $attribute_id ? intval($attribute_id) : null;
  171. }
  172. /**
  173. * Create product attribute if it doesn't exist
  174. *
  175. * @param string $attribute_name Attribute name
  176. * @return int Attribute ID
  177. */
  178. public function create_attribute_if_not_exists($attribute_name) {
  179. $attribute_id = $this->get_attribute_by_name($attribute_name);
  180. if ($attribute_id) {
  181. return $attribute_id;
  182. }
  183. // Create attribute
  184. $attribute = array(
  185. 'slug' => wc_sanitize_taxonomy_name($attribute_name),
  186. 'name' => $attribute_name,
  187. 'type' => 'select',
  188. 'order_by' => 'menu_order',
  189. 'has_archives' => false,
  190. );
  191. $attribute_id = wc_create_attribute($attribute);
  192. if (is_wp_error($attribute_id)) {
  193. return 0;
  194. }
  195. // Register taxonomy
  196. register_taxonomy(
  197. wc_attribute_taxonomy_name($attribute_name),
  198. array('product'),
  199. array()
  200. );
  201. return $attribute_id;
  202. }
  203. }