ACF.php
1 year ago
AdvancedMathCaptcha.php
3 years ago
AeliaCurrencySwitcher.php
3 years ago
BeaverBuilder.php
4 years ago
CF_Helper.php
3 years ago
CURCY_MultiCurrency.php
1 year ago
Cloudflare.php
2 years ago
CommonHelpers.php
3 years ago
CookieNotice.php
4 years ago
DownloadManager.php
4 years ago
Elementor.php
3 years ago
Ezoic.php
4 years ago
FusionBuilder.php
4 years ago
GeoTargetingWP.php
1 year ago
GravityForms.php
2 years ago
JetPackNP.php
3 years ago
NginxHelper.php
2 years ago
RC.php
3 years ago
RankMathNP.php
3 years ago
ShortPixel.php
4 years ago
SquirrlySEO.php
3 years ago
TheEventsCalendar.php
3 years ago
ThriveTheme.php
4 years ago
WCML.php
1 year ago
WPBakeryNP.php
3 years ago
WPCacheHelper.php
3 years ago
WPForms.php
3 years ago
WPML.php
1 year ago
WPRocket.php
4 years ago
WooCommerce.php
1 year ago
WoocommerceCacheHandler.php
4 years ago
YoastSEO.php
3 years ago
WooCommerce.php
231 lines
| 1 | <?php |
| 2 | |
| 3 | namespace NitroPack\Integration\Plugin; |
| 4 | |
| 5 | class WooCommerce { |
| 6 | const STAGE = "late"; |
| 7 | |
| 8 | public static function isActive() { |
| 9 | if ( class_exists( 'WooCommerce' ) ) { |
| 10 | return true; |
| 11 | } |
| 12 | return false; |
| 13 | } |
| 14 | |
| 15 | public function init( $stage ) { |
| 16 | if ( ! self::isActive() ) |
| 17 | return; |
| 18 | |
| 19 | add_action( 'init', [ $this, 'cache_sale_products' ] ); |
| 20 | add_action( 'updated_post_meta', [ $this, 'update_cached_sale_products' ], 10, 4 ); |
| 21 | add_action( 'added_post_meta', [ $this, 'update_cached_sale_products' ], 10, 4 ); |
| 22 | add_action( 'deleted_post_meta', [ $this, 'update_cached_sale_products' ], 10, 4 ); |
| 23 | if ( nitropack_is_optimizer_request() ) { |
| 24 | add_action( 'template_redirect', [ $this, 'purge_site_cache_on_sale_start_and_end' ] ); |
| 25 | } |
| 26 | add_filter( 'wc_product_post_type_link_product_cat', [ $this, 'uppercase_product_cat_links' ] ); |
| 27 | |
| 28 | } |
| 29 | |
| 30 | /** |
| 31 | * Convert %product_cat% links to uppercase due to https://github.com/woocommerce/woocommerce/pull/51637 |
| 32 | * |
| 33 | * This function checks if the category slug starts with a '%' character. |
| 34 | * If it does, the slug is converted to uppercase. |
| 35 | * |
| 36 | * @param object $cat The product category object. |
| 37 | * @return object The modified product category object. |
| 38 | */ |
| 39 | public function uppercase_product_cat_links( $cat ) { |
| 40 | if ( $cat->slug && strpos( $cat->slug, '%' ) === 0 ) { |
| 41 | $cat->slug = strtoupper( $cat->slug ); |
| 42 | } |
| 43 | return $cat; |
| 44 | } |
| 45 | /** |
| 46 | * Retrieves the sale dates for a given WooCommerce product. |
| 47 | * |
| 48 | * @param \WC_Product $product The WooCommerce product object. |
| 49 | * @return array An associative array containing the start and end dates of the sale. |
| 50 | */ |
| 51 | private function get_sale_dates( $product ) { |
| 52 | $sale_start = $product->get_date_on_sale_from(); |
| 53 | $sale_end = $product->get_date_on_sale_to(); |
| 54 | $result = []; |
| 55 | |
| 56 | if ( $sale_start ) { |
| 57 | $sale_start = strtotime( date( 'Y-m-d', $sale_start->getTimestamp() ) ); |
| 58 | $result['from'] = $sale_start; |
| 59 | } |
| 60 | if ( $sale_end ) { |
| 61 | $sale_end = strtotime( date( 'Y-m-d', $sale_end->getTimestamp() ) ); |
| 62 | $result['to'] = $sale_end; |
| 63 | } |
| 64 | |
| 65 | return $result; |
| 66 | } |
| 67 | /** |
| 68 | * This method sets the expiration date for the cache. |
| 69 | * |
| 70 | * @param int $date The expiration date as a timestamp. |
| 71 | * @return void |
| 72 | */ |
| 73 | private function add_cache_expiration( $date ) { |
| 74 | global $np_customExpirationTimes; |
| 75 | |
| 76 | $np_customExpirationTimes[] = $date; |
| 77 | nitropack_set_custom_expiration(); |
| 78 | } |
| 79 | /** |
| 80 | * Update cached products when post meta is updated, deleted, or added. |
| 81 | * |
| 82 | * This function updates the cached sale product dates when the post meta |
| 83 | * keys '_sale_price_dates_from' or '_sale_price_dates_to' are modified. |
| 84 | * It ensures that the cached products are updated accordingly and removes |
| 85 | * the product from the cache if both dates are empty. |
| 86 | * |
| 87 | * @param int $meta_id The ID of the meta entry being updated. |
| 88 | * @param int $post_id The ID of the post being updated. |
| 89 | * @param string $meta_key The meta key being updated. |
| 90 | * @param string $meta_value The new value of the meta key. |
| 91 | * @return void |
| 92 | */ |
| 93 | public function update_cached_sale_products( $meta_id, $post_id, $meta_key, $meta_value ) { |
| 94 | //bail if we dont update future sale dates |
| 95 | if ( $meta_key != '_sale_price_dates_from' && $meta_key != '_sale_price_dates_to' ) |
| 96 | return; |
| 97 | |
| 98 | $cached_products = get_transient( 'nitropack_sale_product_dates' ); |
| 99 | // If $cached_products is empty, initialize it as an array |
| 100 | if ( empty( $cached_products ) ) { |
| 101 | $cached_products = []; |
| 102 | } |
| 103 | |
| 104 | // Ensure that the $post_id key exists in the $cached_products array |
| 105 | if ( ! isset( $cached_products[ $post_id ] ) ) { |
| 106 | $cached_products[ $post_id ] = []; |
| 107 | } |
| 108 | //update |
| 109 | if ( $meta_key === '_sale_price_dates_from' ) { |
| 110 | $cached_products[ $post_id ]['from'] = $meta_value; |
| 111 | } |
| 112 | if ( $meta_key === '_sale_price_dates_to' ) { |
| 113 | $cached_products[ $post_id ]['to'] = $meta_value; |
| 114 | } |
| 115 | //delete product |
| 116 | if ( empty( $cached_products[ $post_id ]['from'] ) && empty( $cached_products[ $post_id ]['to'] ) ) { |
| 117 | unset( $cached_products[ $post_id ] ); |
| 118 | } |
| 119 | set_transient( 'nitropack_sale_product_dates', $cached_products ); |
| 120 | } |
| 121 | /** |
| 122 | * Cache all products with sale dates. |
| 123 | * |
| 124 | * This method identifies all products that have sale dates and caches them |
| 125 | * to improve performance and reduce load times for users viewing sale items. |
| 126 | * |
| 127 | * @return void |
| 128 | */ |
| 129 | public function cache_sale_products() { |
| 130 | $cached_products = get_transient( 'nitropack_sale_product_dates' ); |
| 131 | if ( $cached_products !== false ) |
| 132 | return; |
| 133 | |
| 134 | $scheduled_sale_products = $this->get_products_with_sale(); |
| 135 | $sale_dates = array(); |
| 136 | if ( ! empty( $scheduled_sale_products ) ) { |
| 137 | |
| 138 | foreach ( $scheduled_sale_products as $scheduled_sale_product_id ) { |
| 139 | $current_product_sale_dates = $this->get_sale_dates( wc_get_product( $scheduled_sale_product_id ) ); |
| 140 | $sale_dates[ $scheduled_sale_product_id ] = $current_product_sale_dates; |
| 141 | } |
| 142 | } |
| 143 | //mostly it will be empty array |
| 144 | set_transient( 'nitropack_sale_product_dates', $sale_dates ); |
| 145 | } |
| 146 | |
| 147 | /** |
| 148 | * Purges the site cache when a sale starts or ends. |
| 149 | * |
| 150 | * This function sets the X-Nitro-Expire header to the earliest future date |
| 151 | * based on the sale start or end date. It ensures that the cache is |
| 152 | * appropriately purged to reflect the changes in sale status. |
| 153 | */ |
| 154 | public function purge_site_cache_on_sale_start_and_end() { |
| 155 | $sale_dates = get_transient( 'nitropack_sale_product_dates' ); |
| 156 | if ( $sale_dates === false ) |
| 157 | return; |
| 158 | |
| 159 | $current_time = time(); |
| 160 | $valid_timestamps = []; |
| 161 | foreach ( $sale_dates as $product_id => $dates ) { |
| 162 | $timestamps = []; |
| 163 | |
| 164 | if ( isset( $dates['from'] ) && $dates['from'] >= $current_time ) { |
| 165 | $timestamps[] = $dates['from']; |
| 166 | } |
| 167 | |
| 168 | if ( isset( $dates['to'] ) && $dates['to'] >= $current_time ) { |
| 169 | $timestamps[] = $dates['to']; |
| 170 | } |
| 171 | |
| 172 | if ( ! empty( $timestamps ) ) { |
| 173 | // Use the earliest timestamp that is greater than or equal to the current time |
| 174 | $valid_timestamps[ $product_id ] = min( $timestamps ); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | // Find the earliest date from the valid timestamps |
| 179 | if ( ! empty( $valid_timestamps ) ) { |
| 180 | $earliest_key = array_search( min( $valid_timestamps ), $valid_timestamps ); |
| 181 | $earliest_date = $valid_timestamps[ $earliest_key ]; |
| 182 | |
| 183 | |
| 184 | $this->add_cache_expiration( $earliest_date ); |
| 185 | } |
| 186 | } |
| 187 | /** |
| 188 | * Retrieves all products that have sale dates. |
| 189 | * |
| 190 | * @return array An array of products that are currently on sale. |
| 191 | */ |
| 192 | public function get_products_with_sale() { |
| 193 | |
| 194 | $product_ids = []; |
| 195 | $args = array( |
| 196 | 'post_type' => array( 'product', 'product_variation' ), |
| 197 | 'post_status' => 'publish', |
| 198 | 'posts_per_page' => -1, |
| 199 | 'meta_query' => array( |
| 200 | 'relation' => 'OR', |
| 201 | array( |
| 202 | 'key' => '_sale_price_dates_from', |
| 203 | 'value' => time(), |
| 204 | 'compare' => '>=', |
| 205 | 'type' => 'NUMERIC', |
| 206 | ), |
| 207 | array( |
| 208 | 'key' => '_sale_price_dates_to', |
| 209 | 'value' => time(), |
| 210 | 'compare' => '>=', |
| 211 | 'type' => 'NUMERIC', |
| 212 | ), |
| 213 | ), |
| 214 | ); |
| 215 | |
| 216 | $query = new \WP_Query( $args ); |
| 217 | |
| 218 | if ( $query->have_posts() ) { |
| 219 | while ( $query->have_posts() ) { |
| 220 | global $post; |
| 221 | $query->the_post(); |
| 222 | $product_ids[] = $post->ID; |
| 223 | } |
| 224 | } |
| 225 | wp_reset_postdata(); |
| 226 | |
| 227 | return $product_ids; |
| 228 | } |
| 229 | |
| 230 | } |
| 231 |