PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.19.4
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.19.4
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / classes / Integration / Plugin / WooCommerce.php
nitropack / classes / Integration / Plugin Last commit date
ACF.php 4 months ago AdvancedMathCaptcha.php 1 year ago AeliaCurrencySwitcher.php 11 months ago BeaverBuilder.php 1 year ago CF_Helper.php 5 months ago CURCY_MultiCurrency.php 1 year ago Cloudflare.php 5 months ago CommonHelpers.php 1 year ago CookieNotice.php 1 year ago DownloadManager.php 1 year ago Elementor.php 5 months ago Ezoic.php 1 year ago FusionBuilder.php 1 year ago GeoTargetingWP.php 1 year ago GravityForms.php 2 months ago JetPackNP.php 1 year ago MPG.php 11 months ago NginxHelper.php 1 year ago RC.php 11 months ago RankMathNP.php 1 year ago ShortPixel.php 1 year ago SquirrlySEO.php 1 year ago TheEventsCalendar.php 2 months ago ThriveTheme.php 1 year ago WCML.php 1 year ago WPBakeryNP.php 1 year ago WPCacheHelper.php 1 year ago WPForms.php 1 year ago WPML.php 1 year ago WPRocket.php 1 year ago WooCommerce.php 11 months ago WoocommerceCacheHandler.php 1 year ago YoastSEO.php 1 year ago
WooCommerce.php
283 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 //update transient on post status change
24 add_action( 'transition_post_status', [ $this, 'update_product_from_transient' ], 10, 3 );
25 //delete transient on post delete
26 add_action( 'delete_post', [ $this, 'remove_deleted_product_from_transient' ] );
27 if ( nitropack_is_optimizer_request() ) {
28 add_action( 'template_redirect', [ $this, 'purge_site_cache_on_sale_start_and_end' ] );
29 }
30 add_filter( 'wc_product_post_type_link_product_cat', [ $this, 'uppercase_product_cat_links' ] );
31
32 }
33
34 /**
35 * Convert %product_cat% links to uppercase due to https://github.com/woocommerce/woocommerce/pull/51637
36 *
37 * This function checks if the category slug starts with a '%' character.
38 * If it does, the slug is converted to uppercase.
39 *
40 * @param object $cat The product category object.
41 * @return object The modified product category object.
42 */
43 public function uppercase_product_cat_links( $cat ) {
44 if ( $cat->slug && strpos( $cat->slug, '%' ) === 0 ) {
45 $cat->slug = strtoupper( $cat->slug );
46 }
47 return $cat;
48 }
49 /**
50 * Retrieves the sale dates for a given WooCommerce product.
51 *
52 * @param \WC_Product $product The WooCommerce product object.
53 * @return array An associative array containing the start and end dates of the sale.
54 */
55 private function get_sale_dates( $product ) {
56 $sale_start = $product->get_date_on_sale_from();
57 $sale_end = $product->get_date_on_sale_to();
58 $result = [];
59
60 if ( $sale_start ) {
61 $sale_start = strtotime( date( 'Y-m-d', $sale_start->getTimestamp() ) );
62 $result['from'] = $sale_start;
63 }
64 if ( $sale_end ) {
65 $sale_end = strtotime( date( 'Y-m-d', $sale_end->getTimestamp() ) );
66 $result['to'] = $sale_end;
67 }
68
69 return $result;
70 }
71 /**
72 * This method sets the expiration date for the cache.
73 *
74 * @param int $date The expiration date as a timestamp.
75 * @return void
76 */
77 private function add_cache_expiration( $date ) {
78 global $np_customExpirationTimes;
79
80 $np_customExpirationTimes[] = $date;
81 nitropack_set_custom_expiration();
82 }
83 /**
84 * Update cached products when post meta is updated, deleted, or added.
85 *
86 * This function updates the cached sale product dates when the post meta
87 * keys '_sale_price_dates_from' or '_sale_price_dates_to' are modified.
88 * It ensures that the cached products are updated accordingly and removes
89 * the product from the cache if both dates are empty.
90 *
91 * @param int $meta_id The ID of the meta entry being updated.
92 * @param int $post_id The ID of the post being updated.
93 * @param string $meta_key The meta key being updated.
94 * @param string $meta_value The new value of the meta key.
95 * @return void
96 */
97 public function update_cached_sale_products( $meta_id, $post_id, $meta_key, $meta_value ) {
98 //bail if we dont update future sale dates
99 if ( $meta_key != '_sale_price_dates_from' && $meta_key != '_sale_price_dates_to' )
100 return;
101
102 $cached_products = get_transient( 'nitropack_sale_product_dates' );
103 // If $cached_products is empty, initialize it as an array
104 if ( empty( $cached_products ) ) {
105 $cached_products = [];
106 }
107
108 // Ensure that the $post_id key exists in the $cached_products array
109 if ( ! isset( $cached_products[ $post_id ] ) ) {
110 $cached_products[ $post_id ] = [];
111 }
112 //update
113 if ( $meta_key === '_sale_price_dates_from' ) {
114 $cached_products[ $post_id ]['from'] = $meta_value;
115 }
116 if ( $meta_key === '_sale_price_dates_to' ) {
117 $cached_products[ $post_id ]['to'] = $meta_value;
118 }
119 //delete product
120 if ( empty( $cached_products[ $post_id ]['from'] ) && empty( $cached_products[ $post_id ]['to'] ) ) {
121 unset( $cached_products[ $post_id ] );
122 }
123 set_transient( 'nitropack_sale_product_dates', $cached_products );
124 }
125 /**
126 * Cache all products with sale dates.
127 *
128 * This method identifies all products that have sale dates and caches them
129 * to improve performance and reduce load times for users viewing sale items.
130 *
131 * @return void
132 */
133 public function cache_sale_products() {
134 $cached_products = get_transient( 'nitropack_sale_product_dates' );
135 if ( $cached_products !== false )
136 return;
137
138 $scheduled_sale_products = $this->get_products_with_sale();
139 $sale_dates = array();
140 if ( ! empty( $scheduled_sale_products ) ) {
141
142 foreach ( $scheduled_sale_products as $scheduled_sale_product_id ) {
143 $current_product_sale_dates = $this->get_sale_dates( wc_get_product( $scheduled_sale_product_id ) );
144 $sale_dates[ $scheduled_sale_product_id ] = $current_product_sale_dates;
145 }
146 }
147 /*
148 * If there are no products with sale dates, set the transient to false
149 * to avoid unnecessary queries in the future.
150 */
151 set_transient( 'nitropack_sale_product_dates', $sale_dates );
152 }
153
154 /**
155 * Purges the site cache when a sale starts or ends.
156 *
157 * This function sets the X-Nitro-Expire header to the earliest future date
158 * based on the sale start or end date. It ensures that the cache is
159 * appropriately purged to reflect the changes in sale status.
160 */
161 public function purge_site_cache_on_sale_start_and_end() {
162 $sale_dates = get_transient( 'nitropack_sale_product_dates' );
163 if ( $sale_dates === false )
164 return;
165
166 $current_time = time();
167 $valid_timestamps = [];
168 foreach ( $sale_dates as $product_id => $dates ) {
169 $timestamps = [];
170
171 if ( isset( $dates['from'] ) && $dates['from'] >= $current_time ) {
172 $timestamps[] = $dates['from'];
173 }
174
175 if ( isset( $dates['to'] ) && $dates['to'] >= $current_time ) {
176 $timestamps[] = $dates['to'];
177 }
178
179 if ( ! empty( $timestamps ) ) {
180 // Use the earliest timestamp that is greater than or equal to the current time
181 $valid_timestamps[ $product_id ] = min( $timestamps );
182 }
183 }
184
185 // Find the earliest date from the valid timestamps
186 if ( ! empty( $valid_timestamps ) ) {
187 $earliest_key = array_search( min( $valid_timestamps ), $valid_timestamps );
188 $earliest_date = $valid_timestamps[ $earliest_key ];
189
190
191 $this->add_cache_expiration( $earliest_date );
192 }
193 }
194 /**
195 * Retrieves all products that have sale dates.
196 *
197 * @return array An array of products that are currently on sale.
198 */
199 public function get_products_with_sale() {
200
201 $product_ids = [];
202 $args = array(
203 'post_type' => array( 'product', 'product_variation' ),
204 'post_status' => 'publish',
205 'posts_per_page' => -1,
206 'meta_query' => array(
207 'relation' => 'OR',
208 array(
209 'key' => '_sale_price_dates_from',
210 'value' => time(),
211 'compare' => '>=',
212 'type' => 'NUMERIC',
213 ),
214 array(
215 'key' => '_sale_price_dates_to',
216 'value' => time(),
217 'compare' => '>=',
218 'type' => 'NUMERIC',
219 ),
220 ),
221 );
222
223 $query = new \WP_Query( $args );
224
225 if ( $query->have_posts() ) {
226 while ( $query->have_posts() ) {
227 global $post;
228 $query->the_post();
229 $product_ids[] = $post->ID;
230 }
231 }
232 wp_reset_postdata();
233
234 return $product_ids;
235 }
236 /**
237 * Updates the product in the transient cache when its status changes.
238 *
239 * This function updates the cached sale product dates when the product's
240 * status changes. It ensures that the cached products are updated accordingly
241 * and removes the product from the cache if it is moved to trash.
242 *
243 * @param string $new The new status of the post.
244 * @param string $old The old status of the post.
245 * @param \WP_Post $post The post object being updated.
246 * @return void
247 */
248 public function update_product_from_transient( $new, $old, $post ) {
249 if ( $new === "auto-draft" || ( $new === "draft" && $old === "auto-draft" ) || ( $new === "draft" && $old != "publish" ) || $new === "inherit" ) { // Creating a new post or draft, don't do anything for now.
250 return;
251 }
252 $post_id = $post->ID;
253 $cached_products = get_transient( 'nitropack_sale_product_dates' );
254
255 if ( $new === "trash" && ! empty( $cached_products[ $post_id ] ) ) {
256 unset( $cached_products[ $post_id ] );
257 set_transient( 'nitropack_sale_product_dates', $cached_products );
258 }
259 if ( $new === "publish" ) {
260 $meta = get_post_meta( $post_id );
261 if ( ! empty( $meta['_sale_price_dates_from'] ) ) {
262 $cached_products[ $post_id ]['from'] = $meta['_sale_price_dates_from'][0];
263 }
264 if ( ! empty( $meta['_sale_price_dates_to'] ) ) {
265 $cached_products[ $post_id ]['to'] = $meta['_sale_price_dates_to'][0];
266 }
267 set_transient( 'nitropack_sale_product_dates', $cached_products );
268 }
269 }
270 /**
271 * Deletes the product from the transient cache when it is force/fully deleted.
272 * @param int $post_id The ID of the post being deleted.
273 * @return void
274 */
275 public function remove_deleted_product_from_transient( $post_id ) {
276 $cached_products = get_transient( 'nitropack_sale_product_dates' );
277 if ( empty( $cached_products[ $post_id ] ) ) {
278 return;
279 }
280 unset( $cached_products[ $post_id ] );
281 set_transient( 'nitropack_sale_product_dates', $cached_products );
282 }
283 }