Нет описания

class-wc-post-data.php 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. <?php
  2. /**
  3. * Post Data
  4. *
  5. * Standardises certain post data on save.
  6. *
  7. * @package WooCommerce\Classes\Data
  8. * @version 2.2.0
  9. */
  10. use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore as ProductAttributesLookupDataStore;
  11. use Automattic\WooCommerce\Proxies\LegacyProxy;
  12. defined( 'ABSPATH' ) || exit;
  13. /**
  14. * Post data class.
  15. */
  16. class WC_Post_Data {
  17. /**
  18. * Editing term.
  19. *
  20. * @var object
  21. */
  22. private static $editing_term = null;
  23. /**
  24. * Hook in methods.
  25. */
  26. public static function init() {
  27. add_filter( 'post_type_link', array( __CLASS__, 'variation_post_link' ), 10, 2 );
  28. add_action( 'shutdown', array( __CLASS__, 'do_deferred_product_sync' ), 10 );
  29. add_action( 'set_object_terms', array( __CLASS__, 'force_default_term' ), 10, 5 );
  30. add_action( 'set_object_terms', array( __CLASS__, 'delete_product_query_transients' ) );
  31. add_action( 'deleted_term_relationships', array( __CLASS__, 'delete_product_query_transients' ) );
  32. add_action( 'woocommerce_product_set_stock_status', array( __CLASS__, 'delete_product_query_transients' ) );
  33. add_action( 'woocommerce_product_set_visibility', array( __CLASS__, 'delete_product_query_transients' ) );
  34. add_action( 'woocommerce_product_type_changed', array( __CLASS__, 'product_type_changed' ), 10, 3 );
  35. add_action( 'edit_term', array( __CLASS__, 'edit_term' ), 10, 3 );
  36. add_action( 'edited_term', array( __CLASS__, 'edited_term' ), 10, 3 );
  37. add_filter( 'update_order_item_metadata', array( __CLASS__, 'update_order_item_metadata' ), 10, 5 );
  38. add_filter( 'update_post_metadata', array( __CLASS__, 'update_post_metadata' ), 10, 5 );
  39. add_filter( 'wp_insert_post_data', array( __CLASS__, 'wp_insert_post_data' ) );
  40. add_filter( 'oembed_response_data', array( __CLASS__, 'filter_oembed_response_data' ), 10, 2 );
  41. add_filter( 'wp_untrash_post_status', array( __CLASS__, 'wp_untrash_post_status' ), 10, 3 );
  42. // Status transitions.
  43. add_action( 'transition_post_status', array( __CLASS__, 'transition_post_status' ), 10, 3 );
  44. add_action( 'delete_post', array( __CLASS__, 'delete_post' ) );
  45. add_action( 'wp_trash_post', array( __CLASS__, 'trash_post' ) );
  46. add_action( 'untrashed_post', array( __CLASS__, 'untrash_post' ) );
  47. add_action( 'before_delete_post', array( __CLASS__, 'before_delete_order' ) );
  48. // Meta cache flushing.
  49. add_action( 'updated_post_meta', array( __CLASS__, 'flush_object_meta_cache' ), 10, 4 );
  50. add_action( 'updated_order_item_meta', array( __CLASS__, 'flush_object_meta_cache' ), 10, 4 );
  51. }
  52. /**
  53. * Link to parent products when getting permalink for variation.
  54. *
  55. * @param string $permalink Permalink.
  56. * @param WP_Post $post Post data.
  57. *
  58. * @return string
  59. */
  60. public static function variation_post_link( $permalink, $post ) {
  61. if ( isset( $post->ID, $post->post_type ) && 'product_variation' === $post->post_type ) {
  62. $variation = wc_get_product( $post->ID );
  63. if ( $variation && $variation->get_parent_id() ) {
  64. return $variation->get_permalink();
  65. }
  66. }
  67. return $permalink;
  68. }
  69. /**
  70. * Sync products queued to sync.
  71. */
  72. public static function do_deferred_product_sync() {
  73. global $wc_deferred_product_sync;
  74. if ( ! empty( $wc_deferred_product_sync ) ) {
  75. $wc_deferred_product_sync = wp_parse_id_list( $wc_deferred_product_sync );
  76. array_walk( $wc_deferred_product_sync, array( __CLASS__, 'deferred_product_sync' ) );
  77. }
  78. }
  79. /**
  80. * Sync a product.
  81. *
  82. * @param int $product_id Product ID.
  83. */
  84. public static function deferred_product_sync( $product_id ) {
  85. $product = wc_get_product( $product_id );
  86. if ( is_callable( array( $product, 'sync' ) ) ) {
  87. $product->sync( $product );
  88. }
  89. }
  90. /**
  91. * When a post status changes.
  92. *
  93. * @param string $new_status New status.
  94. * @param string $old_status Old status.
  95. * @param WP_Post $post Post data.
  96. */
  97. public static function transition_post_status( $new_status, $old_status, $post ) {
  98. if ( ( 'publish' === $new_status || 'publish' === $old_status ) && in_array( $post->post_type, array( 'product', 'product_variation' ), true ) ) {
  99. self::delete_product_query_transients();
  100. }
  101. }
  102. /**
  103. * Delete product view transients when needed e.g. when post status changes, or visibility/stock status is modified.
  104. */
  105. public static function delete_product_query_transients() {
  106. WC_Cache_Helper::get_transient_version( 'product_query', true );
  107. }
  108. /**
  109. * Handle type changes.
  110. *
  111. * @since 3.0.0
  112. *
  113. * @param WC_Product $product Product data.
  114. * @param string $from Origin type.
  115. * @param string $to New type.
  116. */
  117. public static function product_type_changed( $product, $from, $to ) {
  118. /**
  119. * Filter to prevent variations from being deleted while switching from a variable product type to a variable product type.
  120. *
  121. * @since 5.0.0
  122. *
  123. * @param bool A boolean value of true will delete the variations.
  124. * @param WC_Product $product Product data.
  125. * @return string $from Origin type.
  126. * @param string $to New type.
  127. */
  128. if ( apply_filters( 'woocommerce_delete_variations_on_product_type_change', 'variable' === $from && 'variable' !== $to, $product, $from, $to ) ) {
  129. // If the product is no longer variable, we should ensure all variations are removed.
  130. $data_store = WC_Data_Store::load( 'product-variable' );
  131. $data_store->delete_variations( $product->get_id(), true );
  132. }
  133. }
  134. /**
  135. * When editing a term, check for product attributes.
  136. *
  137. * @param int $term_id Term ID.
  138. * @param int $tt_id Term taxonomy ID.
  139. * @param string $taxonomy Taxonomy slug.
  140. */
  141. public static function edit_term( $term_id, $tt_id, $taxonomy ) {
  142. if ( strpos( $taxonomy, 'pa_' ) === 0 ) {
  143. self::$editing_term = get_term_by( 'id', $term_id, $taxonomy );
  144. } else {
  145. self::$editing_term = null;
  146. }
  147. }
  148. /**
  149. * When a term is edited, check for product attributes and update variations.
  150. *
  151. * @param int $term_id Term ID.
  152. * @param int $tt_id Term taxonomy ID.
  153. * @param string $taxonomy Taxonomy slug.
  154. */
  155. public static function edited_term( $term_id, $tt_id, $taxonomy ) {
  156. if ( ! is_null( self::$editing_term ) && strpos( $taxonomy, 'pa_' ) === 0 ) {
  157. $edited_term = get_term_by( 'id', $term_id, $taxonomy );
  158. if ( $edited_term->slug !== self::$editing_term->slug ) {
  159. global $wpdb;
  160. $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = %s WHERE meta_key = %s AND meta_value = %s;", $edited_term->slug, 'attribute_' . sanitize_title( $taxonomy ), self::$editing_term->slug ) );
  161. $wpdb->query(
  162. $wpdb->prepare(
  163. "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE( meta_value, %s, %s ) WHERE meta_key = '_default_attributes'",
  164. serialize( self::$editing_term->taxonomy ) . serialize( self::$editing_term->slug ),
  165. serialize( $edited_term->taxonomy ) . serialize( $edited_term->slug )
  166. )
  167. );
  168. }
  169. } else {
  170. self::$editing_term = null;
  171. }
  172. }
  173. /**
  174. * Ensure floats are correctly converted to strings based on PHP locale.
  175. *
  176. * @param null $check Whether to allow updating metadata for the given type.
  177. * @param int $object_id Object ID.
  178. * @param string $meta_key Meta key.
  179. * @param mixed $meta_value Meta value. Must be serializable if non-scalar.
  180. * @param mixed $prev_value If specified, only update existing metadata entries with the specified value. Otherwise, update all entries.
  181. * @return null|bool
  182. */
  183. public static function update_order_item_metadata( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
  184. if ( ! empty( $meta_value ) && is_float( $meta_value ) ) {
  185. // Convert float to string.
  186. $meta_value = wc_float_to_string( $meta_value );
  187. // Update meta value with new string.
  188. update_metadata( 'order_item', $object_id, $meta_key, $meta_value, $prev_value );
  189. return true;
  190. }
  191. return $check;
  192. }
  193. /**
  194. * Ensure floats are correctly converted to strings based on PHP locale.
  195. *
  196. * @param null $check Whether to allow updating metadata for the given type.
  197. * @param int $object_id Object ID.
  198. * @param string $meta_key Meta key.
  199. * @param mixed $meta_value Meta value. Must be serializable if non-scalar.
  200. * @param mixed $prev_value If specified, only update existing metadata entries with the specified value. Otherwise, update all entries.
  201. * @return null|bool
  202. */
  203. public static function update_post_metadata( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
  204. // Delete product cache if someone uses meta directly.
  205. if ( in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ), true ) ) {
  206. wp_cache_delete( 'product-' . $object_id, 'products' );
  207. }
  208. if ( ! empty( $meta_value ) && is_float( $meta_value ) && ! registered_meta_key_exists( 'post', $meta_key ) && in_array( get_post_type( $object_id ), array_merge( wc_get_order_types(), array( 'shop_coupon', 'product', 'product_variation' ) ), true ) ) {
  209. // Convert float to string.
  210. $meta_value = wc_float_to_string( $meta_value );
  211. // Update meta value with new string.
  212. update_metadata( 'post', $object_id, $meta_key, $meta_value, $prev_value );
  213. return true;
  214. }
  215. return $check;
  216. }
  217. /**
  218. * Forces the order posts to have a title in a certain format (containing the date).
  219. * Forces certain product data based on the product's type, e.g. grouped products cannot have a parent.
  220. *
  221. * @param array $data An array of slashed post data.
  222. * @return array
  223. */
  224. public static function wp_insert_post_data( $data ) {
  225. if ( 'shop_order' === $data['post_type'] && isset( $data['post_date'] ) ) {
  226. $order_title = 'Order';
  227. if ( $data['post_date'] ) {
  228. $order_title .= ' &ndash; ' . date_i18n( 'F j, Y @ h:i A', strtotime( $data['post_date'] ) );
  229. }
  230. $data['post_title'] = $order_title;
  231. } elseif ( 'product' === $data['post_type'] && isset( $_POST['product-type'] ) ) { // WPCS: input var ok, CSRF ok.
  232. $product_type = wc_clean( wp_unslash( $_POST['product-type'] ) ); // WPCS: input var ok, CSRF ok.
  233. switch ( $product_type ) {
  234. case 'grouped':
  235. case 'variable':
  236. $data['post_parent'] = 0;
  237. break;
  238. }
  239. } elseif ( 'product' === $data['post_type'] && 'auto-draft' === $data['post_status'] ) {
  240. $data['post_title'] = 'AUTO-DRAFT';
  241. } elseif ( 'shop_coupon' === $data['post_type'] ) {
  242. // Coupons should never allow unfiltered HTML.
  243. $data['post_title'] = wp_filter_kses( $data['post_title'] );
  244. }
  245. return $data;
  246. }
  247. /**
  248. * Change embed data for certain post types.
  249. *
  250. * @since 3.2.0
  251. * @param array $data The response data.
  252. * @param WP_Post $post The post object.
  253. * @return array
  254. */
  255. public static function filter_oembed_response_data( $data, $post ) {
  256. if ( in_array( $post->post_type, array( 'shop_order', 'shop_coupon' ), true ) ) {
  257. return array();
  258. }
  259. return $data;
  260. }
  261. /**
  262. * Removes variations etc belonging to a deleted post, and clears transients.
  263. *
  264. * @param mixed $id ID of post being deleted.
  265. */
  266. public static function delete_post( $id ) {
  267. $container = wc_get_container();
  268. if ( ! $container->get( LegacyProxy::class )->call_function( 'current_user_can', 'delete_posts' ) || ! $id ) {
  269. return;
  270. }
  271. $post_type = self::get_post_type( $id );
  272. switch ( $post_type ) {
  273. case 'product':
  274. $data_store = WC_Data_Store::load( 'product-variable' );
  275. $data_store->delete_variations( $id, true );
  276. $data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
  277. $container->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
  278. $parent_id = wp_get_post_parent_id( $id );
  279. if ( $parent_id ) {
  280. wc_delete_product_transients( $parent_id );
  281. }
  282. break;
  283. case 'product_variation':
  284. $data_store = WC_Data_Store::load( 'product' );
  285. $data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
  286. wc_delete_product_transients( wp_get_post_parent_id( $id ) );
  287. $container->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
  288. break;
  289. case 'shop_order':
  290. global $wpdb;
  291. $refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
  292. if ( ! is_null( $refunds ) ) {
  293. foreach ( $refunds as $refund ) {
  294. wp_delete_post( $refund->ID, true );
  295. }
  296. }
  297. break;
  298. }
  299. }
  300. /**
  301. * Trash post.
  302. *
  303. * @param mixed $id Post ID.
  304. */
  305. public static function trash_post( $id ) {
  306. if ( ! $id ) {
  307. return;
  308. }
  309. $post_type = self::get_post_type( $id );
  310. // If this is an order, trash any refunds too.
  311. if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
  312. global $wpdb;
  313. $refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
  314. foreach ( $refunds as $refund ) {
  315. $wpdb->update( $wpdb->posts, array( 'post_status' => 'trash' ), array( 'ID' => $refund->ID ) );
  316. }
  317. wc_delete_shop_order_transients( $id );
  318. // If this is a product, trash children variations.
  319. } elseif ( 'product' === $post_type ) {
  320. $data_store = WC_Data_Store::load( 'product-variable' );
  321. $data_store->delete_variations( $id, false );
  322. wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
  323. } elseif ( 'product_variation' === $post_type ) {
  324. wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_deleted( $id );
  325. }
  326. }
  327. /**
  328. * Untrash post.
  329. *
  330. * @param mixed $id Post ID.
  331. */
  332. public static function untrash_post( $id ) {
  333. if ( ! $id ) {
  334. return;
  335. }
  336. $post_type = self::get_post_type( $id );
  337. if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
  338. global $wpdb;
  339. $refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
  340. foreach ( $refunds as $refund ) {
  341. $wpdb->update( $wpdb->posts, array( 'post_status' => 'wc-completed' ), array( 'ID' => $refund->ID ) );
  342. }
  343. wc_delete_shop_order_transients( $id );
  344. } elseif ( 'product' === $post_type ) {
  345. $data_store = WC_Data_Store::load( 'product-variable' );
  346. $data_store->untrash_variations( $id );
  347. wc_product_force_unique_sku( $id );
  348. wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_changed( $id );
  349. } elseif ( 'product_variation' === $post_type ) {
  350. wc_get_container()->get( ProductAttributesLookupDataStore::class )->on_product_changed( $id );
  351. }
  352. }
  353. /**
  354. * Get the post type for a given post.
  355. *
  356. * @param int $id The post id.
  357. * @return string The post type.
  358. */
  359. private static function get_post_type( $id ) {
  360. return wc_get_container()->get( LegacyProxy::class )->call_function( 'get_post_type', $id );
  361. }
  362. /**
  363. * Before deleting an order, do some cleanup.
  364. *
  365. * @since 3.2.0
  366. * @param int $order_id Order ID.
  367. */
  368. public static function before_delete_order( $order_id ) {
  369. if ( in_array( get_post_type( $order_id ), wc_get_order_types(), true ) ) {
  370. // Clean up user.
  371. $order = wc_get_order( $order_id );
  372. // Check for `get_customer_id`, since this may be e.g. a refund order (which doesn't implement it).
  373. $customer_id = is_callable( array( $order, 'get_customer_id' ) ) ? $order->get_customer_id() : 0;
  374. if ( $customer_id > 0 && 'shop_order' === $order->get_type() ) {
  375. $customer = new WC_Customer( $customer_id );
  376. $order_count = $customer->get_order_count();
  377. $order_count --;
  378. if ( 0 === $order_count ) {
  379. $customer->set_is_paying_customer( false );
  380. $customer->save();
  381. }
  382. // Delete order count and last order meta.
  383. delete_user_meta( $customer_id, '_order_count' );
  384. delete_user_meta( $customer_id, '_last_order' );
  385. }
  386. // Clean up items.
  387. self::delete_order_items( $order_id );
  388. self::delete_order_downloadable_permissions( $order_id );
  389. }
  390. }
  391. /**
  392. * Remove item meta on permanent deletion.
  393. *
  394. * @param int $postid Post ID.
  395. */
  396. public static function delete_order_items( $postid ) {
  397. global $wpdb;
  398. if ( in_array( get_post_type( $postid ), wc_get_order_types(), true ) ) {
  399. do_action( 'woocommerce_delete_order_items', $postid );
  400. $wpdb->query(
  401. "
  402. DELETE {$wpdb->prefix}woocommerce_order_items, {$wpdb->prefix}woocommerce_order_itemmeta
  403. FROM {$wpdb->prefix}woocommerce_order_items
  404. JOIN {$wpdb->prefix}woocommerce_order_itemmeta ON {$wpdb->prefix}woocommerce_order_items.order_item_id = {$wpdb->prefix}woocommerce_order_itemmeta.order_item_id
  405. WHERE {$wpdb->prefix}woocommerce_order_items.order_id = '{$postid}';
  406. "
  407. ); // WPCS: unprepared SQL ok.
  408. do_action( 'woocommerce_deleted_order_items', $postid );
  409. }
  410. }
  411. /**
  412. * Remove downloadable permissions on permanent order deletion.
  413. *
  414. * @param int $postid Post ID.
  415. */
  416. public static function delete_order_downloadable_permissions( $postid ) {
  417. if ( in_array( get_post_type( $postid ), wc_get_order_types(), true ) ) {
  418. do_action( 'woocommerce_delete_order_downloadable_permissions', $postid );
  419. $data_store = WC_Data_Store::load( 'customer-download' );
  420. $data_store->delete_by_order_id( $postid );
  421. do_action( 'woocommerce_deleted_order_downloadable_permissions', $postid );
  422. }
  423. }
  424. /**
  425. * Flush meta cache for CRUD objects on direct update.
  426. *
  427. * @param int $meta_id Meta ID.
  428. * @param int $object_id Object ID.
  429. * @param string $meta_key Meta key.
  430. * @param string $meta_value Meta value.
  431. */
  432. public static function flush_object_meta_cache( $meta_id, $object_id, $meta_key, $meta_value ) {
  433. WC_Cache_Helper::invalidate_cache_group( 'object_' . $object_id );
  434. }
  435. /**
  436. * Ensure default category gets set.
  437. *
  438. * @since 3.3.0
  439. * @param int $object_id Product ID.
  440. * @param array $terms Terms array.
  441. * @param array $tt_ids Term ids array.
  442. * @param string $taxonomy Taxonomy name.
  443. * @param bool $append Are we appending or setting terms.
  444. */
  445. public static function force_default_term( $object_id, $terms, $tt_ids, $taxonomy, $append ) {
  446. if ( ! $append && 'product_cat' === $taxonomy && empty( $tt_ids ) && 'product' === get_post_type( $object_id ) ) {
  447. $default_term = absint( get_option( 'default_product_cat', 0 ) );
  448. $tt_ids = array_map( 'absint', $tt_ids );
  449. if ( $default_term && ! in_array( $default_term, $tt_ids, true ) ) {
  450. wp_set_post_terms( $object_id, array( $default_term ), 'product_cat', true );
  451. }
  452. }
  453. }
  454. /**
  455. * Ensure statuses are correctly reassigned when restoring orders and products.
  456. *
  457. * @param string $new_status The new status of the post being restored.
  458. * @param int $post_id The ID of the post being restored.
  459. * @param string $previous_status The status of the post at the point where it was trashed.
  460. * @return string
  461. */
  462. public static function wp_untrash_post_status( $new_status, $post_id, $previous_status ) {
  463. $post_types = array( 'shop_order', 'shop_coupon', 'product', 'product_variation' );
  464. if ( in_array( get_post_type( $post_id ), $post_types, true ) ) {
  465. $new_status = $previous_status;
  466. }
  467. return $new_status;
  468. }
  469. /**
  470. * When setting stock level, ensure the stock status is kept in sync.
  471. *
  472. * @param int $meta_id Meta ID.
  473. * @param int $object_id Object ID.
  474. * @param string $meta_key Meta key.
  475. * @param mixed $meta_value Meta value.
  476. * @deprecated 3.3
  477. */
  478. public static function sync_product_stock_status( $meta_id, $object_id, $meta_key, $meta_value ) {}
  479. /**
  480. * Update changed downloads.
  481. *
  482. * @deprecated 3.3.0 No action is necessary on changes to download paths since download_id is no longer based on file hash.
  483. * @param int $product_id Product ID.
  484. * @param int $variation_id Variation ID. Optional product variation identifier.
  485. * @param array $downloads Newly set files.
  486. */
  487. public static function process_product_file_download_paths( $product_id, $variation_id, $downloads ) {
  488. wc_deprecated_function( __FUNCTION__, '3.3' );
  489. }
  490. /**
  491. * Delete transients when terms are set.
  492. *
  493. * @deprecated 3.6
  494. * @param int $object_id Object ID.
  495. * @param mixed $terms An array of object terms.
  496. * @param array $tt_ids An array of term taxonomy IDs.
  497. * @param string $taxonomy Taxonomy slug.
  498. * @param mixed $append Whether to append new terms to the old terms.
  499. * @param array $old_tt_ids Old array of term taxonomy IDs.
  500. */
  501. public static function set_object_terms( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
  502. if ( in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ), true ) ) {
  503. self::delete_product_query_transients();
  504. }
  505. }
  506. }
  507. WC_Post_Data::init();