abstracts
6 months ago
admin
6 months ago
blocks
10 months ago
cli
8 months ago
customizer
6 months ago
data-stores
5 months ago
emails
6 months ago
export
1 year ago
gateways
5 months ago
import
11 months ago
integrations
2 years ago
interfaces
1 year ago
legacy
1 year ago
libraries
1 year ago
log-handlers
1 year ago
payment-tokens
5 years ago
product-usage
1 year ago
queue
4 years ago
react-admin
6 months ago
rest-api
6 months ago
shipping
6 months ago
shortcodes
10 months ago
theme-support
2 years ago
tracks
6 months ago
traits
5 years ago
walkers
5 years ago
wccom-site
9 months ago
widgets
6 months ago
class-wc-ajax.php
6 months ago
class-wc-auth.php
1 year ago
class-wc-autoloader.php
8 months ago
class-wc-background-emailer.php
5 years ago
class-wc-background-updater.php
5 years ago
class-wc-brands-brand-settings-manager.php
1 year ago
class-wc-brands-coupons.php
1 year ago
class-wc-brands.php
6 months ago
class-wc-breadcrumb.php
5 years ago
class-wc-cache-helper.php
8 months ago
class-wc-cart-fees.php
2 years ago
class-wc-cart-session.php
6 months ago
class-wc-cart-totals.php
10 months ago
class-wc-cart.php
8 months ago
class-wc-checkout.php
1 year ago
class-wc-cli.php
9 months ago
class-wc-comments.php
9 months ago
class-wc-countries.php
7 months ago
class-wc-coupon.php
6 months ago
class-wc-customer-download-log.php
5 years ago
class-wc-customer-download.php
1 year ago
class-wc-customer.php
9 months ago
class-wc-data-exception.php
8 years ago
class-wc-data-store.php
3 years ago
class-wc-datetime.php
4 years ago
class-wc-deprecated-action-hooks.php
2 years ago
class-wc-deprecated-filter-hooks.php
3 years ago
class-wc-discounts.php
10 months ago
class-wc-download-handler.php
1 year ago
class-wc-emails.php
10 months ago
class-wc-embed.php
1 year ago
class-wc-form-handler.php
6 months ago
class-wc-frontend-scripts.php
6 months ago
class-wc-geo-ip.php
8 months ago
class-wc-geolite-integration.php
6 years ago
class-wc-geolocation.php
1 year ago
class-wc-https.php
2 years ago
class-wc-install.php
6 months ago
class-wc-integrations.php
5 years ago
class-wc-log-levels.php
2 years ago
class-wc-logger.php
1 year ago
class-wc-meta-data.php
4 years ago
class-wc-order-factory.php
2 years ago
class-wc-order-item-coupon.php
4 years ago
class-wc-order-item-fee.php
1 year ago
class-wc-order-item-meta.php
4 years ago
class-wc-order-item-product.php
7 months ago
class-wc-order-item-shipping.php
1 year ago
class-wc-order-item-tax.php
4 years ago
class-wc-order-item.php
8 months ago
class-wc-order-query.php
4 years ago
class-wc-order-refund.php
1 year ago
class-wc-order.php
6 months ago
class-wc-payment-gateways.php
8 months ago
class-wc-payment-tokens.php
3 years ago
class-wc-post-data.php
6 months ago
class-wc-post-types.php
1 year ago
class-wc-privacy-background-process.php
1 year ago
class-wc-privacy-erasers.php
9 months ago
class-wc-privacy-exporters.php
4 years ago
class-wc-privacy.php
11 months ago
class-wc-product-attribute.php
4 years ago
class-wc-product-download.php
2 years ago
class-wc-product-external.php
1 year ago
class-wc-product-factory.php
1 year ago
class-wc-product-grouped.php
10 months ago
class-wc-product-query.php
1 year ago
class-wc-product-simple.php
10 months ago
class-wc-product-variable.php
10 months ago
class-wc-product-variation.php
1 year ago
class-wc-query.php
6 months ago
class-wc-rate-limiter.php
4 years ago
class-wc-regenerate-images-request.php
3 years ago
class-wc-regenerate-images.php
1 year ago
class-wc-register-wp-admin-settings.php
4 years ago
class-wc-rest-authentication.php
1 year ago
class-wc-rest-exception.php
5 years ago
class-wc-session-handler.php
8 months ago
class-wc-shipping-rate.php
11 months ago
class-wc-shipping-zone.php
5 years ago
class-wc-shipping-zones.php
6 months ago
class-wc-shipping.php
1 year ago
class-wc-shortcodes.php
1 year ago
class-wc-structured-data.php
6 months ago
class-wc-tax.php
10 months ago
class-wc-template-loader.php
6 months ago
class-wc-tracker.php
8 months ago
class-wc-validation.php
2 years ago
class-wc-webhook.php
8 months ago
class-woocommerce.php
5 months ago
wc-account-functions.php
6 months ago
wc-attribute-functions.php
9 months ago
wc-brands-functions.php
1 year ago
wc-cart-functions.php
9 months ago
wc-conditional-functions.php
10 months ago
wc-core-functions.php
5 months ago
wc-coupon-functions.php
10 months ago
wc-deprecated-functions.php
9 months ago
wc-formatting-functions.php
6 months ago
wc-notice-functions.php
11 months ago
wc-order-functions.php
6 months ago
wc-order-item-functions.php
3 years ago
wc-order-step-logger-functions.php
6 months ago
wc-page-functions.php
1 year ago
wc-product-functions.php
8 months ago
wc-rest-functions.php
6 months ago
wc-stock-functions.php
6 months ago
wc-template-functions.php
8 months ago
wc-template-hooks.php
9 months ago
wc-term-functions.php
6 months ago
wc-update-functions.php
6 months ago
wc-user-functions.php
6 months ago
wc-webhook-functions.php
1 year ago
wc-widget-functions.php
5 years ago
wc-coupon-functions.php
218 lines
| 1 | <?php |
| 2 | /** |
| 3 | * WooCommerce Coupons Functions |
| 4 | * |
| 5 | * Functions for coupon specific things. |
| 6 | * |
| 7 | * @package WooCommerce\Functions |
| 8 | * @version 3.0.0 |
| 9 | */ |
| 10 | |
| 11 | defined( 'ABSPATH' ) || exit; |
| 12 | |
| 13 | use Automattic\WooCommerce\Utilities\StringUtil; |
| 14 | use Automattic\WooCommerce\Admin\API\Reports\Coupons\DataStore as CouponsDataStore; |
| 15 | |
| 16 | /** |
| 17 | * Get coupon types. |
| 18 | * |
| 19 | * @return array |
| 20 | */ |
| 21 | function wc_get_coupon_types() { |
| 22 | return (array) apply_filters( |
| 23 | 'woocommerce_coupon_discount_types', |
| 24 | array( |
| 25 | 'percent' => __( 'Percentage discount', 'woocommerce' ), |
| 26 | 'fixed_cart' => __( 'Fixed cart discount', 'woocommerce' ), |
| 27 | 'fixed_product' => __( 'Fixed product discount', 'woocommerce' ), |
| 28 | ) |
| 29 | ); |
| 30 | } |
| 31 | |
| 32 | /** |
| 33 | * Get a coupon type's name. |
| 34 | * |
| 35 | * @param string $type Coupon type. |
| 36 | * @return string |
| 37 | */ |
| 38 | function wc_get_coupon_type( $type = '' ) { |
| 39 | $types = wc_get_coupon_types(); |
| 40 | return isset( $types[ $type ] ) ? $types[ $type ] : ''; |
| 41 | } |
| 42 | |
| 43 | /** |
| 44 | * Coupon types that apply to individual products. Controls which validation rules will apply. |
| 45 | * |
| 46 | * @since 2.5.0 |
| 47 | * @return array |
| 48 | */ |
| 49 | function wc_get_product_coupon_types() { |
| 50 | return (array) apply_filters( 'woocommerce_product_coupon_types', array( 'fixed_product', 'percent' ) ); |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * Coupon types that apply to the cart as a whole. Controls which validation rules will apply. |
| 55 | * |
| 56 | * @since 2.5.0 |
| 57 | * @return array |
| 58 | */ |
| 59 | function wc_get_cart_coupon_types() { |
| 60 | return (array) apply_filters( 'woocommerce_cart_coupon_types', array( 'fixed_cart' ) ); |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * Check if coupons are enabled. |
| 65 | * Filterable. |
| 66 | * |
| 67 | * @since 2.5.0 |
| 68 | * |
| 69 | * @return bool |
| 70 | */ |
| 71 | function wc_coupons_enabled() { |
| 72 | return apply_filters( 'woocommerce_coupons_enabled', 'yes' === get_option( 'woocommerce_enable_coupons' ) ); |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Check if two coupon codes are the same. |
| 77 | * Lowercasing to ensure case-insensitive comparison. |
| 78 | * |
| 79 | * @since 9.9.0 |
| 80 | * |
| 81 | * @param string $coupon_1 Coupon code 1. |
| 82 | * @param string $coupon_2 Coupon code 2. |
| 83 | * @return bool |
| 84 | */ |
| 85 | function wc_is_same_coupon( $coupon_1, $coupon_2 ) { |
| 86 | return wc_strtolower( $coupon_1 ) === wc_strtolower( $coupon_2 ); |
| 87 | } |
| 88 | |
| 89 | /** |
| 90 | * Get coupon code by ID. |
| 91 | * |
| 92 | * @since 3.0.0 |
| 93 | * @param int $id Coupon ID. |
| 94 | * @return string |
| 95 | */ |
| 96 | function wc_get_coupon_code_by_id( $id ) { |
| 97 | $data_store = WC_Data_Store::load( 'coupon' ); |
| 98 | return empty( $id ) ? '' : (string) $data_store->get_code_by_id( $id ); |
| 99 | } |
| 100 | |
| 101 | /** |
| 102 | * Get coupon ID by code. |
| 103 | * |
| 104 | * @since 3.0.0 |
| 105 | * @param string $code Coupon code. |
| 106 | * @param int $exclude Used to exclude an ID from the check if you're checking existence. |
| 107 | * @return int |
| 108 | */ |
| 109 | function wc_get_coupon_id_by_code( $code, $exclude = 0 ) { |
| 110 | |
| 111 | if ( StringUtil::is_null_or_whitespace( $code ) ) { |
| 112 | return 0; |
| 113 | } |
| 114 | |
| 115 | $data_store = WC_Data_Store::load( 'coupon' ); |
| 116 | // Coupon code allows spaces, which doesn't work well with some cache engines (e.g. memcached). |
| 117 | $hashed_code = md5( $code ); |
| 118 | $cache_key = WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $hashed_code; |
| 119 | |
| 120 | $ids = wp_cache_get( $cache_key, 'coupons' ); |
| 121 | |
| 122 | if ( false === $ids ) { |
| 123 | $ids = $data_store->get_ids_by_code( $code ); |
| 124 | if ( $ids ) { |
| 125 | wp_cache_set( $cache_key, $ids, 'coupons' ); |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | $ids = array_diff( array_filter( array_map( 'absint', (array) $ids ) ), array( $exclude ) ); |
| 130 | |
| 131 | return apply_filters( 'woocommerce_get_coupon_id_from_code', absint( current( $ids ) ), $code, $exclude ); |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * Repair coupon lookup entries with zero discount_amount. A bug in WC 9.9 (fixed in 10.0) |
| 136 | * caused discount_amount to be set to zero when a coupon code was used with |
| 137 | * different case (e.g. "10-off" vs "10-OFF"). |
| 138 | * |
| 139 | * @since 10.1.0 |
| 140 | * @return array Array with 'success' boolean and 'message' string. |
| 141 | */ |
| 142 | function wc_repair_zero_discount_coupons_lookup_table() { |
| 143 | global $wpdb; |
| 144 | |
| 145 | $table_name = $wpdb->prefix . 'wc_order_coupon_lookup'; |
| 146 | |
| 147 | // Check if table exists. |
| 148 | // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared |
| 149 | if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) !== $table_name ) { |
| 150 | return array( |
| 151 | 'success' => false, |
| 152 | 'message' => __( 'Coupons lookup table does not exist.', 'woocommerce' ), |
| 153 | ); |
| 154 | } |
| 155 | |
| 156 | // Get entries with zero discount_amount. |
| 157 | $zero_discount_entries = $wpdb->get_results( |
| 158 | $wpdb->prepare( |
| 159 | // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared |
| 160 | "SELECT order_id, coupon_id FROM $table_name WHERE discount_amount = %f", |
| 161 | 0.0 |
| 162 | ), |
| 163 | ARRAY_A |
| 164 | ); |
| 165 | |
| 166 | if ( empty( $zero_discount_entries ) ) { |
| 167 | return array( |
| 168 | 'success' => true, |
| 169 | 'message' => __( 'No entries with zero discount amount found. Coupons lookup table is up to date.', 'woocommerce' ), |
| 170 | ); |
| 171 | } |
| 172 | |
| 173 | $processed_count = 0; |
| 174 | $error_count = 0; |
| 175 | |
| 176 | foreach ( $zero_discount_entries as $entry ) { |
| 177 | try { |
| 178 | $result = CouponsDataStore::sync_order_coupons( $entry['order_id'] ); |
| 179 | if ( false !== $result ) { |
| 180 | ++$processed_count; |
| 181 | } else { |
| 182 | ++$error_count; |
| 183 | } |
| 184 | } catch ( Exception $e ) { |
| 185 | ++$error_count; |
| 186 | $logger = wc_get_logger(); |
| 187 | $logger->error( |
| 188 | sprintf( |
| 189 | 'Error fixing coupon lookup entry for order %d: %s', |
| 190 | $entry['order_id'], |
| 191 | $e->getMessage() |
| 192 | ), |
| 193 | array( |
| 194 | 'source' => 'coupons-lookup-fix', |
| 195 | 'order_id' => $entry['order_id'], |
| 196 | 'error' => $e, |
| 197 | ) |
| 198 | ); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | // Clear any related caches. |
| 203 | wp_cache_flush_group( 'coupons' ); |
| 204 | WC_Cache_Helper::get_transient_version( 'woocommerce_reports', true ); |
| 205 | |
| 206 | $message = sprintf( |
| 207 | /* translators: %1$d: number of entries processed, %2$d: number of errors */ |
| 208 | __( 'Coupons lookup table entries with zero discount amount repaired successfully. Processed %1$d entries with %2$d errors.', 'woocommerce' ), |
| 209 | $processed_count, |
| 210 | $error_count |
| 211 | ); |
| 212 | |
| 213 | return array( |
| 214 | 'success' => true, |
| 215 | 'message' => $message, |
| 216 | ); |
| 217 | } |
| 218 |