abstract-wc-order-item-type-data-store.php
<?php
/**
* Class Abstract_WC_Order_Item_Type_Data_Store file.
*
* @package WooCommerce\DataStores
*/
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC Order Item Data Store
*
* @version 3.0.0
*/
abstract class Abstract_WC_Order_Item_Type_Data_Store extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface {
use CogsAwareTrait;
/**
* Meta type. This should match up with
* the types available at https://developer.wordpress.org/reference/functions/add_metadata/.
* WP defines 'post', 'user', 'comment', and 'term'.
*
* @var string
*/
protected $meta_type = 'order_item';
/**
* This only needs set if you are using a custom metadata type (for example payment tokens.
* This should be the name of the field your table uses for associating meta with objects.
* For example, in payment_tokenmeta, this would be payment_token_id.
*
* @var string
*/
protected $object_id_field_for_meta = 'order_item_id';
/**
* Indicates if the Cost of Goods Sold feature is enabled.
*
* @var bool
*/
private bool $cogs_is_enabled;
/**
* The instance of WC_Order_Item_Data_Store to use for COGS related operations.
*
* @var WC_Order_Item_Data_Store
*/
private WC_Data_Store $order_item_data_store;
/**
* Class constructor.
*/
public function __construct() {
$this->cogs_is_enabled = $this->cogs_is_enabled();
if ( $this->cogs_is_enabled ) {
$this->order_item_data_store = WC_Data_Store::load( 'order-item' );
}
}
/**
* Create a new order item in the database.
*
* @param WC_Order_Item $item Order item object.
* @since 3.0.0
*/
public function create( &$item ) {
global $wpdb;
$wpdb->insert(
$wpdb->prefix . 'woocommerce_order_items',
array(
'order_item_name' => $item->get_name(),
'order_item_type' => $item->get_type(),
'order_id' => $item->get_order_id(),
)
);
$item->set_id( $wpdb->insert_id );
$this->save_item_data( $item );
$item->save_meta_data();
if ( $this->cogs_is_enabled && $item->has_cogs() ) {
$this->save_cogs_data( $item );
}
$item->apply_changes();
$this->clear_cache( $item );
do_action( 'woocommerce_new_order_item', $item->get_id(), $item, $item->get_order_id() );
}
/**
* Update a order item in the database.
*
* @param WC_Order_Item $item Order item object.
* @since 3.0.0
*/
public function update( &$item ) {
global $wpdb;
$changes = $item->get_changes();
if ( array_intersect( array( 'name', 'order_id' ), array_keys( $changes ) ) ) {
$wpdb->update(
$wpdb->prefix . 'woocommerce_order_items',
array(
'order_item_name' => $item->get_name(),
'order_item_type' => $item->get_type(),
'order_id' => $item->get_order_id(),
),
array( 'order_item_id' => $item->get_id() )
);
}
$this->save_item_data( $item );
$item->save_meta_data();
if ( $this->cogs_is_enabled && $item->has_cogs() ) {
$this->save_cogs_data( $item );
}
$item->apply_changes();
$this->clear_cache( $item );
do_action( 'woocommerce_update_order_item', $item->get_id(), $item, $item->get_order_id() );
}
/**
* Remove an order item from the database.
*
* @param WC_Order_Item $item Order item object.
* @param array $args Array of args to pass to the delete method.
* @since 3.0.0
*/
public function delete( &$item, $args = array() ) {
if ( $item->get_id() ) {
global $wpdb;
do_action( 'woocommerce_before_delete_order_item', $item->get_id() );
$wpdb->delete( $wpdb->prefix . 'woocommerce_order_items', array( 'order_item_id' => $item->get_id() ) );
$wpdb->delete( $wpdb->prefix . 'woocommerce_order_itemmeta', array( 'order_item_id' => $item->get_id() ) );
do_action( 'woocommerce_delete_order_item', $item->get_id() );
$this->clear_cache( $item );
}
}
/**
* Read a order item from the database.
*
* @param WC_Order_Item $item Order item object.
*
* @throws Exception If invalid order item.
* @since 3.0.0
*/
public function read( &$item ) {
global $wpdb;
$item->set_defaults();
// Get from cache if available.
$data = wp_cache_get( 'item-' . $item->get_id(), 'order-items' );
if ( false === $data ) {
$data = $wpdb->get_row( $wpdb->prepare( "SELECT order_id, order_item_name FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d LIMIT 1;", $item->get_id() ) );
wp_cache_set( 'item-' . $item->get_id(), $data, 'order-items' );
}
if ( ! $data ) {
throw new Exception( __( 'Invalid order item.', 'woocommerce' ) );
}
$item->set_props(
array(
'order_id' => $data->order_id,
'name' => $data->order_item_name,
)
);
$item->read_meta_data();
if ( $this->cogs_is_enabled && $item->has_cogs() ) {
$cogs_value = (float) $this->order_item_data_store->get_metadata( $item->get_id(), '_cogs_value', true );
/**
* Filter to customize the Cost of Goods Sold value that gets loaded for a given order item.
*
* @since 9.5.0
*
* @param float $cogs_value The value as read from the database.
* @param WC_Order_Item $product The order item for which the value is being loaded.
*/
$cogs_value = apply_filters( 'woocommerce_load_order_item_cogs_value', $cogs_value, $item );
$item->set_cogs_value( (float) $cogs_value );
}
}
/**
* Saves an item's data to the database / item meta.
* Ran after both create and update, so $item->get_id() will be set.
*
* @param WC_Order_Item $item Order item object.
* @since 3.0.0
*/
public function save_item_data( &$item ) {
}
/**
* Clear meta cache.
*
* @param WC_Order_Item $item Order item object.
*/
public function clear_cache( &$item ) {
wp_cache_delete( 'item-' . $item->get_id(), 'order-items' );
wp_cache_delete( 'order-items-' . $item->get_order_id(), 'orders' );
wp_cache_delete( $item->get_id(), $this->meta_type . '_meta' );
}
/**
* Persist the Cost of Goods Sold related data to the database.
*
* @param WC_Order_Item $item The order item for which the data will be persisted.
*/
private function save_cogs_data( WC_Order_Item $item ) {
$cogs_value = $item->get_cogs_value();
/**
* Filter to customize the Cost of Goods Sold value that gets saved for a given order item,
* or to suppress the saving of the value (so that custom storage can be used).
*
* @since 9.5.0
*
* @param float|null $cogs_value The value to be written to the database. If returned as null, nothing will be written.
* @param WC_Order_Item $item The order item for which the value is being saved.
*/
$cogs_value = apply_filters( 'woocommerce_save_order_item_cogs_value', $cogs_value, $item );
if ( is_null( $cogs_value ) ) {
return;
}
$cogs_value = (float) $cogs_value;
if ( 0.0 === $cogs_value ) {
$this->order_item_data_store->delete_metadata( $item->get_id(), '_cogs_value', '', true );
} else {
$this->order_item_data_store->update_metadata( $item->get_id(), '_cogs_value', $cogs_value );
}
}
}