WC_Coupon_Data_Store_CPT

WC Coupon Data Store: Custom Post Type.

Defined (1)

The class is defined in the following location(s).

/includes/data-stores/class-wc-coupon-data-store-cpt.php  
  1. class WC_Coupon_Data_Store_CPT extends WC_Data_Store_WP implements WC_Coupon_Data_Store_Interface, WC_Object_Data_Store_Interface { 
  2.  
  3. /** 
  4. * Internal meta type used to store coupon data. 
  5. * @since 3.0.0 
  6. * @var string 
  7. */ 
  8. protected $meta_type = 'post'; 
  9.  
  10. /** 
  11. * Data stored in meta keys, but not considered "meta" for a coupon. 
  12. * @since 3.0.0 
  13. * @var array 
  14. */ 
  15. protected $internal_meta_keys = array( 
  16. 'discount_type',  
  17. 'coupon_amount',  
  18. 'expiry_date',  
  19. 'date_expires',  
  20. 'usage_count',  
  21. 'individual_use',  
  22. 'product_ids',  
  23. 'exclude_product_ids',  
  24. 'usage_limit',  
  25. 'usage_limit_per_user',  
  26. 'limit_usage_to_x_items',  
  27. 'free_shipping',  
  28. 'product_categories',  
  29. 'exclude_product_categories',  
  30. 'exclude_sale_items',  
  31. 'minimum_amount',  
  32. 'maximum_amount',  
  33. 'customer_email',  
  34. '_used_by',  
  35. '_edit_lock',  
  36. '_edit_last',  
  37. ); 
  38.  
  39. /** 
  40. * Method to create a new coupon in the database. 
  41. * @since 3.0.0 
  42. * @param WC_Coupon 
  43. */ 
  44. public function create( &$coupon ) { 
  45. $coupon->set_date_created( current_time( 'timestamp', true ) ); 
  46.  
  47. $coupon_id = wp_insert_post( apply_filters( 'woocommerce_new_coupon_data', array( 
  48. 'post_type' => 'shop_coupon',  
  49. 'post_status' => 'publish',  
  50. 'post_author' => get_current_user_id(),  
  51. 'post_title' => $coupon->get_code( 'edit' ),  
  52. 'post_content' => '',  
  53. 'post_excerpt' => $coupon->get_description( 'edit' ),  
  54. 'post_date' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created()->getOffsetTimestamp() ),  
  55. 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created()->getTimestamp() ),  
  56. ) ), true ); 
  57.  
  58. if ( $coupon_id ) { 
  59. $coupon->set_id( $coupon_id ); 
  60. $this->update_post_meta( $coupon ); 
  61. $coupon->save_meta_data(); 
  62. $coupon->apply_changes(); 
  63. do_action( 'woocommerce_new_coupon', $coupon_id ); 
  64.  
  65. /** 
  66. * Method to read a coupon. 
  67. * @since 3.0.0 
  68. * @param WC_Coupon 
  69. */ 
  70. public function read( &$coupon ) { 
  71. $coupon->set_defaults(); 
  72.  
  73. if ( ! $coupon->get_id() || ! ( $post_object = get_post( $coupon->get_id() ) ) || 'shop_coupon' !== $post_object->post_type ) { 
  74. throw new Exception( __( 'Invalid coupon.', 'woocommerce' ) ); 
  75.  
  76. $coupon_id = $coupon->get_id(); 
  77. $coupon->set_props( array( 
  78. 'code' => $post_object->post_title,  
  79. 'description' => $post_object->post_excerpt,  
  80. 'date_created' => 0 < $post_object->post_date_gmt ? wc_string_to_timestamp( $post_object->post_date_gmt ) : null,  
  81. 'date_modified' => 0 < $post_object->post_modified_gmt ? wc_string_to_timestamp( $post_object->post_modified_gmt ) : null,  
  82. 'date_expires' => metadata_exists( 'post', $coupon_id, 'date_expires' ) ? get_post_meta( $coupon_id, 'date_expires', true ) : get_post_meta( $coupon_id, 'expiry_date', true ),  
  83. 'discount_type' => get_post_meta( $coupon_id, 'discount_type', true ),  
  84. 'amount' => get_post_meta( $coupon_id, 'coupon_amount', true ),  
  85. 'usage_count' => get_post_meta( $coupon_id, 'usage_count', true ),  
  86. 'individual_use' => 'yes' === get_post_meta( $coupon_id, 'individual_use', true ),  
  87. 'product_ids' => array_filter( (array) explode( ', ', get_post_meta( $coupon_id, 'product_ids', true ) ) ),  
  88. 'excluded_product_ids' => array_filter( (array) explode( ', ', get_post_meta( $coupon_id, 'exclude_product_ids', true ) ) ),  
  89. 'usage_limit' => get_post_meta( $coupon_id, 'usage_limit', true ),  
  90. 'usage_limit_per_user' => get_post_meta( $coupon_id, 'usage_limit_per_user', true ),  
  91. 'limit_usage_to_x_items' => 0 < get_post_meta( $coupon_id, 'limit_usage_to_x_items', true ) ? get_post_meta( $coupon_id, 'limit_usage_to_x_items', true ) : null,  
  92. 'free_shipping' => 'yes' === get_post_meta( $coupon_id, 'free_shipping', true ),  
  93. 'product_categories' => array_filter( (array) get_post_meta( $coupon_id, 'product_categories', true ) ),  
  94. 'excluded_product_categories' => array_filter( (array) get_post_meta( $coupon_id, 'exclude_product_categories', true ) ),  
  95. 'exclude_sale_items' => 'yes' === get_post_meta( $coupon_id, 'exclude_sale_items', true ),  
  96. 'minimum_amount' => get_post_meta( $coupon_id, 'minimum_amount', true ),  
  97. 'maximum_amount' => get_post_meta( $coupon_id, 'maximum_amount', true ),  
  98. 'email_restrictions' => array_filter( (array) get_post_meta( $coupon_id, 'customer_email', true ) ),  
  99. 'used_by' => array_filter( (array) get_post_meta( $coupon_id, '_used_by' ) ),  
  100. ) ); 
  101. $coupon->read_meta_data(); 
  102. $coupon->set_object_read( true ); 
  103. do_action( 'woocommerce_coupon_loaded', $coupon ); 
  104.  
  105. /** 
  106. * Updates a coupon in the database. 
  107. * @since 3.0.0 
  108. * @param WC_Coupon 
  109. */ 
  110. public function update( &$coupon ) { 
  111. $coupon->save_meta_data(); 
  112. $changes = $coupon->get_changes(); 
  113.  
  114. if ( array_intersect( array( 'code', 'description', 'date_created', 'date_modified' ), array_keys( $changes ) ) ) { 
  115. $post_data = array( 
  116. 'post_title' => $coupon->get_code( 'edit' ),  
  117. 'post_excerpt' => $coupon->get_description( 'edit' ),  
  118. 'post_date' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created( 'edit' )->getOffsetTimestamp() ),  
  119. 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created( 'edit' )->getTimestamp() ),  
  120. 'post_modified' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $coupon->get_date_modified( 'edit' )->getOffsetTimestamp() ) : current_time( 'mysql' ),  
  121. 'post_modified_gmt' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $coupon->get_date_modified( 'edit' )->getTimestamp() ) : current_time( 'mysql', 1 ),  
  122. ); 
  123.  
  124. /** 
  125. * When updating this object, to prevent infinite loops, use $wpdb 
  126. * to update data, since wp_update_post spawns more calls to the 
  127. * save_post action. 
  128. * This ensures hooks are fired by either WP itself (admin screen save),  
  129. * or an update purely from CRUD. 
  130. */ 
  131. if ( doing_action( 'save_post' ) ) { 
  132. $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $coupon->get_id() ) ); 
  133. clean_post_cache( $coupon->get_id() ); 
  134. } else { 
  135. wp_update_post( array_merge( array( 'ID' => $coupon->get_id() ), $post_data ) ); 
  136. $coupon->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook. 
  137. $this->update_post_meta( $coupon ); 
  138. $coupon->apply_changes(); 
  139. do_action( 'woocommerce_update_coupon', $coupon->get_id() ); 
  140.  
  141. /** 
  142. * Deletes a coupon from the database. 
  143. * @since 3.0.0 
  144. * @param WC_Coupon 
  145. * @param array $args Array of args to pass to the delete method. 
  146. */ 
  147. public function delete( &$coupon, $args = array() ) { 
  148. $args = wp_parse_args( $args, array( 
  149. 'force_delete' => false,  
  150. ) ); 
  151.  
  152. $id = $coupon->get_id(); 
  153.  
  154. if ( $args['force_delete'] ) { 
  155. wp_delete_post( $coupon->get_id() ); 
  156. $coupon->set_id( 0 ); 
  157. do_action( 'woocommerce_delete_coupon', $id ); 
  158. } else { 
  159. wp_trash_post( $coupon->get_id() ); 
  160. do_action( 'woocommerce_trash_coupon', $id ); 
  161.  
  162. /** 
  163. * Helper method that updates all the post meta for a coupon based on it's settings in the WC_Coupon class. 
  164. * @param WC_Coupon 
  165. * @since 3.0.0 
  166. */ 
  167. private function update_post_meta( &$coupon ) { 
  168. $updated_props = array(); 
  169. $meta_key_to_props = array( 
  170. 'discount_type' => 'discount_type',  
  171. 'coupon_amount' => 'amount',  
  172. 'individual_use' => 'individual_use',  
  173. 'product_ids' => 'product_ids',  
  174. 'exclude_product_ids' => 'excluded_product_ids',  
  175. 'usage_limit' => 'usage_limit',  
  176. 'usage_limit_per_user' => 'usage_limit_per_user',  
  177. 'limit_usage_to_x_items' => 'limit_usage_to_x_items',  
  178. 'usage_count' => 'usage_count',  
  179. 'date_expires' => 'date_expires',  
  180. 'free_shipping' => 'free_shipping',  
  181. 'product_categories' => 'product_categories',  
  182. 'exclude_product_categories' => 'excluded_product_categories',  
  183. 'exclude_sale_items' => 'exclude_sale_items',  
  184. 'minimum_amount' => 'minimum_amount',  
  185. 'maximum_amount' => 'maximum_amount',  
  186. 'customer_email' => 'email_restrictions',  
  187. ); 
  188.  
  189. $props_to_update = $this->get_props_to_update( $coupon, $meta_key_to_props ); 
  190. foreach ( $props_to_update as $meta_key => $prop ) { 
  191. $value = $coupon->{"get_$prop"}( 'edit' ); 
  192. switch ( $prop ) { 
  193. case 'individual_use' : 
  194. case 'free_shipping' : 
  195. case 'exclude_sale_items' : 
  196. $updated = update_post_meta( $coupon->get_id(), $meta_key, wc_bool_to_string( $value ) ); 
  197. break; 
  198. case 'product_ids' : 
  199. case 'excluded_product_ids' : 
  200. $updated = update_post_meta( $coupon->get_id(), $meta_key, implode( ', ', array_filter( array_map( 'intval', $value ) ) ) ); 
  201. break; 
  202. case 'product_categories' : 
  203. case 'excluded_product_categories' : 
  204. $updated = update_post_meta( $coupon->get_id(), $meta_key, array_filter( array_map( 'intval', $value ) ) ); 
  205. break; 
  206. case 'email_restrictions' : 
  207. $updated = update_post_meta( $coupon->get_id(), $meta_key, array_filter( array_map( 'sanitize_email', $value ) ) ); 
  208. break; 
  209. case 'date_expires' : 
  210. $updated = update_post_meta( $coupon->get_id(), $meta_key, ( $value ? $value->getTimestamp() : null ) ); 
  211. update_post_meta( $coupon->get_id(), 'expiry_date', ( $value ? $value->date( 'Y-m-d' ) : '' ) ); // Update the old meta key for backwards compatibility. 
  212. break; 
  213. default : 
  214. $updated = update_post_meta( $coupon->get_id(), $meta_key, $value ); 
  215. break; 
  216. if ( $updated ) { 
  217. $updated_props[] = $prop; 
  218.  
  219. do_action( 'woocommerce_coupon_object_updated_props', $coupon, $updated_props ); 
  220.  
  221. /** 
  222. * Increase usage count for current coupon. 
  223. * @since 3.0.0 
  224. * @param WC_Coupon 
  225. * @param string $used_by Either user ID or billing email 
  226. * @return int New usage count 
  227. */ 
  228. public function increase_usage_count( &$coupon, $used_by = '' ) { 
  229. $new_count = $this->update_usage_count_meta( $coupon, 'increase' ); 
  230. if ( $used_by ) { 
  231. add_post_meta( $coupon->get_id(), '_used_by', strtolower( $used_by ) ); 
  232. $coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) ); 
  233. return $new_count; 
  234.  
  235. /** 
  236. * Decrease usage count for current coupon. 
  237. * @since 3.0.0 
  238. * @param WC_Coupon 
  239. * @param string $used_by Either user ID or billing email 
  240. * @return int New usage count 
  241. */ 
  242. public function decrease_usage_count( &$coupon, $used_by = '' ) { 
  243. global $wpdb; 
  244. $new_count = $this->update_usage_count_meta( $coupon, 'decrease' ); 
  245. if ( $used_by ) { 
  246. /** 
  247. * We're doing this the long way because `delete_post_meta( $id, $key, $value )` deletes. 
  248. * all instances where the key and value match, and we only want to delete one. 
  249. */ 
  250. $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_used_by' AND meta_value = %s AND post_id = %d LIMIT 1;", $used_by, $coupon->get_id() ) ); 
  251. if ( $meta_id ) { 
  252. delete_metadata_by_mid( 'post', $meta_id ); 
  253. $coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) ); 
  254. return $new_count; 
  255.  
  256. /** 
  257. * Increase or decrease the usage count for a coupon by 1. 
  258. * @since 3.0.0 
  259. * @param WC_Coupon 
  260. * @param string $operation 'increase' or 'decrease' 
  261. * @return int New usage count 
  262. */ 
  263. private function update_usage_count_meta( &$coupon, $operation = 'increase' ) { 
  264. global $wpdb; 
  265. $id = $coupon->get_id(); 
  266. $operator = ( 'increase' === $operation ) ? '+' : '-'; 
  267.  
  268. add_post_meta( $id, 'usage_count', $coupon->get_usage_count( 'edit' ), true ); 
  269. $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = meta_value {$operator} 1 WHERE meta_key = 'usage_count' AND post_id = %d;", $id ) ); 
  270.  
  271. // Get the latest value direct from the DB, instead of possibly the WP meta cache. 
  272. return (int) $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key = 'usage_count' AND post_id = %d;", $id ) ); 
  273.  
  274. /** 
  275. * Get the number of uses for a coupon by user ID. 
  276. * @since 3.0.0 
  277. * @param WC_Coupon 
  278. * @param id $user_id 
  279. * @return int 
  280. */ 
  281. public function get_usage_by_user_id( &$coupon, $user_id ) { 
  282. global $wpdb; 
  283. return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( meta_id ) FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = '_used_by' AND meta_value = %d;", $coupon->get_id(), $user_id ) ); 
  284.  
  285. /** 
  286. * Return a coupon code for a specific ID. 
  287. * @since 3.0.0 
  288. * @param int $id 
  289. * @return string Coupon Code 
  290. */ 
  291. public function get_code_by_id( $id ) { 
  292. global $wpdb; 
  293. return $wpdb->get_var( $wpdb->prepare( " 
  294. SELECT post_title 
  295. FROM $wpdb->posts 
  296. WHERE ID = %d 
  297. AND post_type = 'shop_coupon' 
  298. AND post_status = 'publish'; 
  299. ", $id ) ); 
  300.  
  301. /** 
  302. * Return an array of IDs for for a specific coupon code. 
  303. * Can return multiple to check for existence. 
  304. * @since 3.0.0 
  305. * @param string $code 
  306. * @return array Array of IDs. 
  307. */ 
  308. public function get_ids_by_code( $code ) { 
  309. global $wpdb; 
  310. return $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' ORDER BY post_date DESC;", $code ) );