set_date_created( current_time( 'timestamp' ) ); $coupon_id = wp_insert_post( apply_filters( 'woocommerce_new_coupon_data', array( 'post_type' => 'shop_coupon', 'post_status' => 'publish', 'post_author' => get_current_user_id(), 'post_title' => $coupon->get_code(), 'post_content' => '', 'post_excerpt' => $coupon->get_description(), 'post_date' => date( 'Y-m-d H:i:s', $coupon->get_date_created() ), 'post_date_gmt' => get_gmt_from_date( date( 'Y-m-d H:i:s', $coupon->get_date_created() ) ), ) ), true ); if ( $coupon_id ) { $coupon->set_id( $coupon_id ); $this->update_post_meta( $coupon, true ); $coupon->save_meta_data(); $coupon->apply_changes(); do_action( 'woocommerce_new_coupon', $coupon_id ); } } /** * Method to read a coupon. * * @since 2.7.0 * @param WC_Coupon */ public function read( &$coupon ) { $coupon->set_defaults(); if ( ! $coupon->get_id() || ! ( $post_object = get_post( $coupon->get_id() ) ) || 'shop_coupon' !== $post_object->post_type ) { throw new Exception( __( 'Invalid coupon.', 'woocommerce' ) ); } $coupon_id = $coupon->get_id(); $coupon->set_props( array( 'code' => $post_object->post_title, 'description' => $post_object->post_excerpt, 'date_created' => $post_object->post_date, 'date_modified' => $post_object->post_modified, 'date_expires' => get_post_meta( $coupon_id, 'expiry_date', true ), 'discount_type' => get_post_meta( $coupon_id, 'discount_type', true ), 'amount' => get_post_meta( $coupon_id, 'coupon_amount', true ), 'usage_count' => get_post_meta( $coupon_id, 'usage_count', true ), 'individual_use' => 'yes' === get_post_meta( $coupon_id, 'individual_use', true ), 'product_ids' => array_filter( (array) explode( ',', get_post_meta( $coupon_id, 'product_ids', true ) ) ), 'excluded_product_ids' => array_filter( (array) explode( ',', get_post_meta( $coupon_id, 'exclude_product_ids', true ) ) ), 'usage_limit' => get_post_meta( $coupon_id, 'usage_limit', true ), 'usage_limit_per_user' => get_post_meta( $coupon_id, 'usage_limit_per_user', true ), 'limit_usage_to_x_items' => get_post_meta( $coupon_id, 'limit_usage_to_x_items', true ), 'free_shipping' => 'yes' === get_post_meta( $coupon_id, 'free_shipping', true ), 'product_categories' => array_filter( (array) get_post_meta( $coupon_id, 'product_categories', true ) ), 'excluded_product_categories' => array_filter( (array) get_post_meta( $coupon_id, 'exclude_product_categories', true ) ), 'exclude_sale_items' => 'yes' === get_post_meta( $coupon_id, 'exclude_sale_items', true ), 'minimum_amount' => get_post_meta( $coupon_id, 'minimum_amount', true ), 'maximum_amount' => get_post_meta( $coupon_id, 'maximum_amount', true ), 'email_restrictions' => array_filter( (array) get_post_meta( $coupon_id, 'customer_email', true ) ), 'used_by' => array_filter( (array) get_post_meta( $coupon_id, '_used_by' ) ), ) ); $coupon->read_meta_data(); $coupon->set_object_read( true ); do_action( 'woocommerce_coupon_loaded', $coupon ); } /** * Updates a coupon in the database. * * @since 2.7.0 * @param WC_Coupon */ public function update( &$coupon ) { $post_data = array( 'ID' => $coupon->get_id(), 'post_title' => $coupon->get_code(), 'post_excerpt' => $coupon->get_description(), ); wp_update_post( $post_data ); $this->update_post_meta( $coupon ); $coupon->save_meta_data(); $coupon->apply_changes(); do_action( 'woocommerce_update_coupon', $coupon->get_id() ); } /** * Deletes a coupon from the database. * * @since 2.7.0 * @param WC_Coupon * @param array $args Array of args to pass to the delete method. */ public function delete( &$coupon, $args = array() ) { $args = wp_parse_args( $args, array( 'force_delete' => false, ) ); $id = $coupon->get_id(); if ( $args['force_delete'] ) { wp_delete_post( $coupon->get_id() ); $coupon->set_id( 0 ); do_action( 'woocommerce_delete_coupon', $id ); } else { wp_trash_post( $coupon->get_id() ); do_action( 'woocommerce_trash_coupon', $id ); } } /** * Helper method that updates all the post meta for a coupon based on it's settings in the WC_Coupon class. * * @param WC_Coupon * @param bool $force Force all props to be written even if not changed. This is used during creation. * @since 2.7.0 */ private function update_post_meta( &$coupon, $force = false ) { $updated_props = array(); $changed_props = array_keys( $coupon->get_changes() ); $meta_key_to_props = array( 'discount_type' => 'discount_type', 'coupon_amount' => 'amount', 'individual_use' => 'individual_use', 'product_ids' => 'product_ids', 'exclude_product_ids' => 'excluded_product_ids', 'usage_limit' => 'usage_limit', 'usage_limit_per_user' => 'usage_limit_per_user', 'limit_usage_to_x_items' => 'limit_usage_to_x_items', 'usage_count' => 'usage_count', 'expiry_date' => 'date_expires', 'free_shipping' => 'free_shipping', 'product_categories' => 'product_categories', 'exclude_product_categories' => 'excluded_product_categories', 'exclude_sale_items' => 'exclude_sale_items', 'minimum_amount' => 'minimum_amount', 'maximum_amount' => 'maximum_amount', 'customer_email' => 'email_restrictions', ); foreach ( $meta_key_to_props as $meta_key => $prop ) { if ( ! in_array( $prop, $changed_props ) && ! $force ) { continue; } $value = $coupon->{"get_$prop"}( 'edit' ); switch ( $prop ) { case 'individual_use' : case 'free_shipping' : case 'exclude_sale_items' : $updated = update_post_meta( $coupon->get_id(), $meta_key, wc_bool_to_string( $value ) ); break; case 'product_ids' : case 'excluded_product_ids' : $updated = update_post_meta( $coupon->get_id(), $meta_key, implode( ',', array_filter( array_map( 'intval', $value ) ) ) ); break; case 'product_categories' : case 'excluded_product_categories' : $updated = update_post_meta( $coupon->get_id(), $meta_key, array_filter( array_map( 'intval', $value ) ) ); break; case 'email_restrictions' : $updated = update_post_meta( $coupon->get_id(), $meta_key, array_filter( array_map( 'sanitize_email', $value ) ) ); break; default : $updated = update_post_meta( $coupon->get_id(), $meta_key, $value ); break; } if ( $updated ) { $updated_props[] = $prop; } } } /** * Increase usage count for current coupon. * * @since 2.7.0 * @param WC_Coupon * @param string $used_by Either user ID or billing email */ public function increase_usage_count( &$coupon, $used_by = '' ) { update_post_meta( $coupon->get_id(), 'usage_count', $coupon->get_usage_count( 'edit' ) ); if ( $used_by ) { add_post_meta( $coupon->get_id(), '_used_by', strtolower( $used_by ) ); $coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) ); } } /** * Decrease usage count for current coupon. * * @since 2.7.0 * @param WC_Coupon * @param string $used_by Either user ID or billing email */ public function decrease_usage_count( &$coupon, $used_by = '' ) { global $wpdb; update_post_meta( $coupon->get_id(), 'usage_count', $coupon->get_usage_count() ); if ( $used_by ) { /** * We're doing this the long way because `delete_post_meta( $id, $key, $value )` deletes. * all instances where the key and value match, and we only want to delete one. */ $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() ) ); if ( $meta_id ) { delete_metadata_by_mid( 'post', $meta_id ); $coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) ); } } } /** * Get the number of uses for a coupon by user ID. * * @since 2.7.0 * @param WC_Coupon * @param id $user_id * @return int */ public function get_usage_by_user_id( &$coupon, $user_id ) { global $wpdb; 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 ) ); } /** * Return a coupon code for a specific ID. * * @since 2.7.0 * @param int $id * @return string Coupon Code */ public function get_code_by_id( $id ) { global $wpdb; return $wpdb->get_var( $wpdb->prepare( " SELECT post_title FROM $wpdb->posts WHERE ID = %d AND post_type = 'shop_coupon' AND post_status = 'publish'; ", $id ) ); } /** * Return an array of IDs for for a specific coupon code. * Can return multiple to check for existence. * * @since 2.7.0 * @param string $code * @return array Array of IDs. */ public function get_ids_by_code( $code ) { global $wpdb; 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 ) ); } }