eta->key, $meta->value ); } self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) ); } return $delete_meta; } /** * Add new piece of meta. * * @param WC_Data $object WC_Data object. * @param \stdClass $meta (containing ->key and ->value). * * @return int|bool meta ID or false on failure */ public function add_meta( &$object, $meta ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound $add_meta = $this->data_store_meta->add_meta( $object, $meta ); $meta->id = $add_meta; $changes_applied = $this->after_meta_change( $object, $meta ); if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() ) { self::$backfilling_order_ids[] = $object->get_id(); add_post_meta( $object->get_id(), $meta->key, $meta->value ); self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) ); } return $add_meta; } /** * Update meta. * * @param WC_Data $object WC_Data object. * @param \stdClass $meta (containing ->id, ->key and ->value). * * @return bool The number of rows updated, or false on error. */ public function update_meta( &$object, $meta ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound $update_meta = $this->data_store_meta->update_meta( $object, $meta ); $changes_applied = $this->after_meta_change( $object, $meta ); if ( ! $changes_applied && $object instanceof WC_Abstract_Order && $this->should_backfill_post_record() ) { self::$backfilling_order_ids[] = $object->get_id(); update_post_meta( $object->get_id(), $meta->key, $meta->value ); self::$backfilling_order_ids = array_diff( self::$backfilling_order_ids, array( $object->get_id() ) ); } return $update_meta; } /** * Perform after meta change operations, including updating the date_modified field, clearing caches and applying changes. * * @param WC_Abstract_Order $order Order object. * @param \WC_Meta_Data $meta Metadata object. * * @return bool True if changes were applied, false otherwise. */ protected function after_meta_change( &$order, $meta ) { method_exists( $meta, 'apply_changes' ) && $meta->apply_changes(); // Prevent this happening multiple time in same request. if ( $this->should_save_after_meta_change( $order, $meta ) ) { $order->set_date_modified( current_time( 'mysql' ) ); $order->save(); return true; } else { $order_cache = wc_get_container()->get( OrderCache::class ); $order_cache->remove( $order->get_id() ); $this->clear_cached_data( array( $order->get_id() ) ); } return false; } /** * Helper function to check whether the modified date needs to be updated after a meta save. * * This method prevents order->save() call multiple times in the same request after any meta update by checking if: * 1. Order modified date is already the current date, no updates needed in this case. * 2. If there are changes already queued for order object, then we don't need to update the modified date as it will be updated ina subsequent save() call. * * @param WC_Order $order Order object. * @param \WC_Meta_Data|null $meta Metadata object. * * @return bool Whether the modified date needs to be updated. */ private function should_save_after_meta_change( $order, $meta = null ) { $current_time = $this->legacy_proxy->call_function( 'current_time', 'mysql', 1 ); $current_date_time = new \WC_DateTime( $current_time, new \DateTimeZone( 'GMT' ) ); $should_save = $order->get_date_modified() < $current_date_time && empty( $order->get_changes() ) && ( ! is_object( $meta ) || ! in_array( $meta->key, $this->ephemeral_meta_keys, true ) ); /** * Allows code to skip a full order save() when metadata is changed. * * @since 8.8.0 * * @param bool $should_save Whether to trigger a full save after metadata is changed. */ return apply_filters( 'woocommerce_orders_table_datastore_should_save_after_meta_change', $should_save ); } }