Woocommerce Object Caching

Data Handling Classes

Class List

# Class Name Extends Uses
1 WC_Product_Factory WC_Product_Simple
2 WC_Product_Simple WC_Product
3 WC_Product WC_Abstract_Legacy_Product WC_Data_Store
4 WC_Abstract_Legacy_Product WC_Data
5 WC_Data WC_Cache_Helper, WC_Meta_Data
6 WC_Data_Store WC_Product_Data_Store_CPT
7 WC_Product_Data_Store_CPT WC_Data_Store_WP
8 WC_Data_Store_WP
9 WC_Cache_Helper
10 WC_Meta_Data

WC_Product_Factory

/**
 * Product Factory
 *
 * The WooCommerce product factory creating the right product object.
 *
 * @package WooCommerce/Classes
 * @version 3.0.0
 */

/**
 * Product factory class.
 */
class WC_Product_Factory {}

Overview

This class is used to find the targeted product class by the product type using product ID.

The get_product() is the main method in this class which retrieves the right product class using the given product ID.

Method: get_product()


/**
 * Get a product.
 *
 * @param mixed $product_id WC_Product|WP_Post|int|bool $product Product instance, post instance, numeric or false to use global $post.
 * @param array $deprecated Previously used to pass arguments to the factory, e.g. to force a type.
 * @return WC_Product|bool Product object or false if the product cannot be loaded.
 */
public function get_product( $product_id = false, $deprecated = array() ) {
    $product_id = $this->get_product_id( $product_id );

	if ( ! $product_id ) {
		return false;
	}

	$product_type = $this->get_product_type( $product_id );

	// Backwards compatibility.
	if ( ! empty( $deprecated ) ) {
		wc_deprecated_argument( 'args', '3.0', 'Passing args to the product factory is deprecated. If you need to force a type, construct the product class directly.' );

		if ( isset( $deprecated['product_type'] ) ) {
			$product_type = $this->get_classname_from_product_type( $deprecated['product_type'] );
		}
	}

	$classname = $this->get_product_classname( $product_id, $product_type );

	try {
		return new $classname( $product_id, $deprecated );
	} catch ( Exception $e ) {
		return false;
	}
}

WC_Product_Simple

/**
 * Simple Product Class.
 *
 * The default product type kinda product.
 *
 * @package WooCommerce/Classes/Products
 */

/**
 * Simple product class.
 */
class WC_Product_Simple extends WC_Product {}

Overview

This is the default product class which handles the data processing of the default product type by extending the WC_Product class.

The main data processing tasks are maintained in the parent class. So, only the helper functions used in the product loop are maintained here.

Method: Constructor

/**
 * Initialize simple product.
 *
 * @param WC_Product|int $product Product instance or ID.
 */
public function __construct( $product = 0 ) {
	$this->supports[] = 'ajax_add_to_cart';
	parent::__construct( $product );
}

WC_Product

/**
 * WooCommerce product base class.
 *
 * @package WooCommerce/Abstracts
 */

/**
 * Abstract Product Class
 *
 * The WooCommerce product class handles individual product data.
 *
 * @version 3.0.0
 * @package WooCommerce/Abstracts
 */
class WC_Product extends WC_Abstract_Legacy_Product {}

Overview

This class handles individual product data

Class Data Variables

/**
 * This is the name of this object type.
 *
 * @var string
 */
protected $object_type = 'product';

/**
 * Post type.
 *
 * @var string
 */
protected $post_type = 'product';

/**
 * Cache group.
 *
 * @var string
 */
protected $cache_group = 'products';

/**
 * Stores product data.
 *
 * @var array
 */
protected $data = array(
    'name'               => '',
    'slug'               => '',
    'date_created'       => null,
    'date_modified'      => null,
    'status'             => false,
    'featured'           => false,
    'catalog_visibility' => 'visible',
    'description'        => '',
    'short_description'  => '',
    'sku'                => '',
    'price'              => '',
    'regular_price'      => '',
    'sale_price'         => '',
    'date_on_sale_from'  => null,
    'date_on_sale_to'    => null,
    'total_sales'        => '0',
    'tax_status'         => 'taxable',
    'tax_class'          => '',
    'manage_stock'       => false,
    'stock_quantity'     => null,
    'stock_status'       => 'instock',
    'backorders'         => 'no',
    'low_stock_amount'   => '',
    'sold_individually'  => false,
    'weight'             => '',
    'length'             => '',
    'width'              => '',
    'height'             => '',
    'upsell_ids'         => array(),
    'cross_sell_ids'     => array(),
    'parent_id'          => 0,
    'reviews_allowed'    => true,
    'purchase_note'      => '',
    'attributes'         => array(),
    'default_attributes' => array(),
    'menu_order'         => 0,
    'post_password'      => '',
    'virtual'            => false,
    'downloadable'       => false,
    'category_ids'       => array(),
    'tag_ids'            => array(),
    'shipping_class_id'  => 0,
    'downloads'          => array(),
    'image_id'           => '',
    'gallery_image_ids'  => array(),
    'download_limit'     => -1,
    'download_expiry'    => -1,
    'rating_counts'      => array(),
    'average_rating'     => 0,
    'review_count'       => 0,
);

/**
 * Supported features such as 'ajax_add_to_cart'.
 *
 * @var array
 */
protected $supports = array();

Method: Constructor

/**
 * Get the product if ID is passed, otherwise the product is new and empty.
 * This class should NOT be instantiated, but the wc_get_product() function
 * should be used. It is possible, but the wc_get_product() is preferred.
 *
 * @param int|WC_Product|object $product Product to init.
 */
public function __construct( $product = 0 ) {
	parent::__construct( $product );
	if ( is_numeric( $product ) && $product > 0 ) {
		$this->set_id( $product );
	} elseif ( $product instanceof self ) {
		$this->set_id( absint( $product->get_id() ) );
	} elseif ( ! empty( $product->ID ) ) {
		$this->set_id( absint( $product->ID ) );
	} else {
		$this->set_object_read( true );
	}

	$this->data_store = WC_Data_Store::load( 'product-' . $this->get_type() );
	if ( $this->get_id() > 0 ) {
		$this->data_store->read( $this );
	}
}

Template Hierarchy

Shortcode Template

WC_Shortcodes

// Path: wp-content\plugins\woocommerce\includes\class-wc-shortcodes.php

/**
 * Shortcodes
 *
 * @package WooCommerce/Classes
 * @version 3.2.0
 */

/**
 * WooCommerce Shortcodes class.
 */
class WC_Shortcodes {}

Method: init()

/**
 * Init shortcodes.
 */
public static function init() {
	$shortcodes = array(
		'product'                    => __CLASS__ . '::product',
		'product_page'               => __CLASS__ . '::product_page',
		'product_category'           => __CLASS__ . '::product_category',
		'product_categories'         => __CLASS__ . '::product_categories',
		'add_to_cart'                => __CLASS__ . '::product_add_to_cart',
		'add_to_cart_url'            => __CLASS__ . '::product_add_to_cart_url',
		'products'                   => __CLASS__ . '::products',
		'recent_products'            => __CLASS__ . '::recent_products',
		'sale_products'              => __CLASS__ . '::sale_products',
		'best_selling_products'      => __CLASS__ . '::best_selling_products',
		'top_rated_products'         => __CLASS__ . '::top_rated_products',
		'featured_products'          => __CLASS__ . '::featured_products',
		'product_attribute'          => __CLASS__ . '::product_attribute',
		'related_products'           => __CLASS__ . '::related_products',
		'shop_messages'              => __CLASS__ . '::shop_messages',
		'woocommerce_order_tracking' => __CLASS__ . '::order_tracking',
		'woocommerce_cart'           => __CLASS__ . '::cart',
		'woocommerce_checkout'       => __CLASS__ . '::checkout',
		'woocommerce_my_account'     => __CLASS__ . '::my_account',
	);

	foreach ( $shortcodes as $shortcode => $function ) {
		add_shortcode( apply_filters( "{$shortcode}_shortcode_tag", $shortcode ), $function );
	}

	// Alias for pre 2.1 compatibility.
	add_shortcode( 'woocommerce_messages', __CLASS__ . '::shop_messages' );
}

Method: products()

/**
 * List multiple products shortcode.
 *
 * @param array $atts Attributes.
 * @return string
 */
public static function products( $atts ) {
	$atts = (array) $atts;
	$type = 'products';

	// Allow list product based on specific cases.
	if ( isset( $atts['on_sale'] ) && wc_string_to_bool( $atts['on_sale'] ) ) {
		$type = 'sale_products';
	} elseif ( isset( $atts['best_selling'] ) && wc_string_to_bool( $atts['best_selling'] ) ) {
		$type = 'best_selling_products';
	} elseif ( isset( $atts['top_rated'] ) && wc_string_to_bool( $atts['top_rated'] ) ) {
		$type = 'top_rated_products';
	}

	$shortcode = new WC_Shortcode_Products( $atts, $type );

	return $shortcode->get_content();
}

WC_Shortcode_Products

// Path: 

/**
 * Products shortcode
 *
 * @package  WooCommerce/Shortcodes
 * @version  3.2.4
 */

/**
 * Products shortcode class.
 */
class WC_Shortcode_Products {}

Method: __construct()

/**
 * Initialize shortcode.
 *
 * @since 3.2.0
 * @param array  $attributes Shortcode attributes.
 * @param string $type       Shortcode type.
 */
public function __construct( $attributes = array(), $type = 'products' ) {
	$this->type       = $type;
	$this->attributes = $this->parse_attributes( $attributes );
	$this->query_args = $this->parse_query_args();
}

Method: get_content()

/**
 * Get shortcode content.
 *
 * @since  3.2.0
 * @return string
 */
public function get_content() {
	return $this->product_loop();
}

Method: product_loop()

/**
 * Loop over found products.
 *
 * @since  3.2.0
 * @return string
 */
protected function product_loop() {
	$columns  = absint( $this->attributes['columns'] );
	$classes  = $this->get_wrapper_classes( $columns );
	$products = $this->get_query_results();

	ob_start();

	if ( $products && $products->ids ) {
		// Prime caches to reduce future queries.
		if ( is_callable( '_prime_post_caches' ) ) {
			_prime_post_caches( $products->ids );
		}

		// Setup the loop.
		wc_setup_loop(
			array(
				'columns'      => $columns,
				'name'         => $this->type,
				'is_shortcode' => true,
				'is_search'    => false,
				'is_paginated' => wc_string_to_bool( $this->attributes['paginate'] ),
				'total'        => $products->total,
				'total_pages'  => $products->total_pages,
				'per_page'     => $products->per_page,
				'current_page' => $products->current_page,
			)
		);

		$original_post = $GLOBALS['post'];

		do_action( "woocommerce_shortcode_before_{$this->type}_loop", $this->attributes );

		// Fire standard shop loop hooks when paginating results so we can show result counts and so on.
		if ( wc_string_to_bool( $this->attributes['paginate'] ) ) {
			do_action( 'woocommerce_before_shop_loop' );
		}

		woocommerce_product_loop_start();

		if ( wc_get_loop_prop( 'total' ) ) {
			foreach ( $products->ids as $product_id ) {
				$GLOBALS['post'] = get_post( $product_id ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
				setup_postdata( $GLOBALS['post'] );

				// Set custom product visibility when quering hidden products.
				add_action( 'woocommerce_product_is_visible', array( $this, 'set_product_as_visible' ) );

				// Render product template.
				wc_get_template_part( 'content', 'product' );

				// Restore product visibility.
				remove_action( 'woocommerce_product_is_visible', array( $this, 'set_product_as_visible' ) );
			}
		}

		$GLOBALS['post'] = $original_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
		woocommerce_product_loop_end();

		// Fire standard shop loop hooks when paginating results so we can show result counts and so on.
		if ( wc_string_to_bool( $this->attributes['paginate'] ) ) {
			do_action( 'woocommerce_after_shop_loop' );
		}

		do_action( "woocommerce_shortcode_after_{$this->type}_loop", $this->attributes );

		wp_reset_postdata();
		wc_reset_loop();
	} else {
		do_action( "woocommerce_shortcode_{$this->type}_loop_no_results", $this->attributes );
	}

	return '<div class="' . esc_attr( implode( ' ', $classes ) ) . '">' . ob_get_clean() . '</div>';
}
$products = $this->get_query_results();
// Prime caches to reduce future queries.
if ( is_callable( '_prime_post_caches' ) ) {
	_prime_post_caches( $products->ids );
}
// Render product template.
wc_get_template_part( 'content', 'product' );

Method: get_query_results()

/**
 * Run the query and return an array of data, including queried ids and pagination information.
 *
 * @since  3.3.0
 * @return object Object with the following props; ids, per_page, found_posts, max_num_pages, current_page
 */
protected function get_query_results() {
	$transient_name    = $this->get_transient_name();
	$transient_version = WC_Cache_Helper::get_transient_version( 'product_query' );
	$cache             = wc_string_to_bool( $this->attributes['cache'] ) === true;
	$transient_value   = $cache ? get_transient( $transient_name ) : false;

	if ( isset( $transient_value['value'], $transient_value['version'] ) && $transient_value['version'] === $transient_version ) {
		$results = $transient_value['value'];
	} else {
		$query = new WP_Query( $this->query_args );

		$paginated = ! $query->get( 'no_found_rows' );

		$results = (object) array(
			'ids'          => wp_parse_id_list( $query->posts ),
			'total'        => $paginated ? (int) $query->found_posts : count( $query->posts ),
			'total_pages'  => $paginated ? (int) $query->max_num_pages : 1,
			'per_page'     => (int) $query->get( 'posts_per_page' ),
			'current_page' => $paginated ? (int) max( 1, $query->get( 'paged', 1 ) ) : 1,
		);

		if ( $cache ) {
			$transient_value = array(
				'version' => $transient_version,
				'value'   => $results,
			);
			set_transient( $transient_name, $transient_value, DAY_IN_SECONDS * 30 );
		}
	}

	// Remove ordering query arguments which may have been added by get_catalog_ordering_args.
	WC()->query->remove_ordering_args();

	/**
	 * Filter shortcode products query results.
	 *
	 * @since 4.0.0
	 * @param stdClass $results Query results.
	 * @param WC_Shortcode_Products $this WC_Shortcode_Products instance.
	 */
	return apply_filters( 'woocommerce_shortcode_products_query_results', $results, $this );
}

Page Template

Product Page

// Path: wp-content\plugins\woocommerce\templates\archive-product.php

woocommerce_product_loop_start();
	if ( wc_get_loop_prop( 'total' ) ) {
		while ( have_posts() ) {
			the_post();

			/**
			 * Hook: woocommerce_shop_loop.
			 */
			do_action( 'woocommerce_shop_loop' );

			wc_get_template_part( 'content', 'product' );
		}
	}
woocommerce_product_loop_end();

// Path: wp-content\plugins\woocommerce\templates\content-product.php

global $product;

// Ensure visibility.
if ( empty( $product ) || ! $product->is_visible() ) {
	return;
}
?>
<li <?php wc_product_class( '', $product ); ?>>
	<?php
	/**
	 * Hook: woocommerce_before_shop_loop_item.
	 *
	 * @hooked woocommerce_template_loop_product_link_open - 10
	 */
	do_action( 'woocommerce_before_shop_loop_item' );

	/**
	 * Hook: woocommerce_before_shop_loop_item_title.
	 *
	 * @hooked woocommerce_show_product_loop_sale_flash - 10
	 * @hooked woocommerce_template_loop_product_thumbnail - 10
	 */
	do_action( 'woocommerce_before_shop_loop_item_title' );

	/**
	 * Hook: woocommerce_shop_loop_item_title.
	 *
	 * @hooked woocommerce_template_loop_product_title - 10
	 */
	do_action( 'woocommerce_shop_loop_item_title' );

	/**
	 * Hook: woocommerce_after_shop_loop_item_title.
	 *
	 * @hooked woocommerce_template_loop_rating - 5
	 * @hooked woocommerce_template_loop_price - 10
	 */
	do_action( 'woocommerce_after_shop_loop_item_title' );

	/**
	 * Hook: woocommerce_after_shop_loop_item.
	 *
	 * @hooked woocommerce_template_loop_product_link_close - 5
	 * @hooked woocommerce_template_loop_add_to_cart - 10
	 */
	do_action( 'woocommerce_after_shop_loop_item' );
	?>
</li>

// Path: wp-content\plugins\woocommerce\includes\wc-template-functions.php

/**
 * When the_post is called, put product data into a global.
 *
 * @param mixed $post Post Object.
 * @return WC_Product
 */
function wc_setup_product_data( $post ) {
	unset( $GLOBALS['product'] );

	if ( is_int( $post ) ) {
		$post = get_post( $post );
	}

	if ( empty( $post->post_type ) || ! in_array( $post->post_type, array( 'product', 'product_variation' ), true ) ) {
		return;
	}

	$GLOBALS['product'] = wc_get_product( $post );

	return $GLOBALS['product'];
}
add_action( 'the_post', 'wc_setup_product_data' );

// Path: wp-content\plugins\woocommerce\includes\wc-product-functions.php

/**
 * Main function for returning products, uses the WC_Product_Factory class.
 *
 * This function should only be called after 'init' action is finished, as there might be taxonomies that are getting
 * registered during the init action.
 *
 * @since 2.2.0
 *
 * @param mixed $the_product Post object or post ID of the product.
 * @param array $deprecated Previously used to pass arguments to the factory, e.g. to force a type.
 * @return WC_Product|null|false
 */
function wc_get_product( $the_product = false, $deprecated = array() ) {
	if ( ! did_action( 'woocommerce_init' ) || ! did_action( 'woocommerce_after_register_taxonomy' ) || ! did_action( 'woocommerce_after_register_post_type' ) ) {
		/* translators: 1: wc_get_product 2: woocommerce_init 3: woocommerce_after_register_taxonomy 4: woocommerce_after_register_post_type */
		wc_doing_it_wrong( __FUNCTION__, sprintf( __( '%1$s should not be called before the %2$s, %3$s and %4$s actions have finished.', 'woocommerce' ), 'wc_get_product', 'woocommerce_init', 'woocommerce_after_register_taxonomy', 'woocommerce_after_register_post_type' ), '3.9' );
		return false;
	}
	if ( ! empty( $deprecated ) ) {
		wc_deprecated_argument( 'args', '3.0', 'Passing args to wc_get_product is deprecated. If you need to force a type, construct the product class directly.' );
	}
    
    // new WC_Product_Factory()
	return WC()->product_factory->get_product( $the_product, $deprecated );
}

// Path: wp-content\plugins\woocommerce\includes\class-wc-product-factory.php

/**
 * Product Factory
 *
 * The WooCommerce product factory creating the right product object.
 *
 * @package WooCommerce/Classes
 * @version 3.0.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * Product factory class.
 */
class WC_Product_Factory {

	/**
	 * Get a product.
	 *
	 * @param mixed $product_id WC_Product|WP_Post|int|bool $product Product instance, post instance, numeric or false to use global $post.
	 * @param array $deprecated Previously used to pass arguments to the factory, e.g. to force a type.
	 * @return WC_Product|bool Product object or false if the product cannot be loaded.
	 */
	public function get_product( $product_id = false, $deprecated = array() ) {
		$product_id = $this->get_product_id( $product_id );

		if ( ! $product_id ) {
			return false;
		}

		$product_type = $this->get_product_type( $product_id );

		// Backwards compatibility.
		if ( ! empty( $deprecated ) ) {
			wc_deprecated_argument( 'args', '3.0', 'Passing args to the product factory is deprecated. If you need to force a type, construct the product class directly.' );

			if ( isset( $deprecated['product_type'] ) ) {
				$product_type = $this->get_classname_from_product_type( $deprecated['product_type'] );
			}
		}

		$classname = $this->get_product_classname( $product_id, $product_type );

		try {
             // new WC_Product_Simple()
			return new $classname( $product_id, $deprecated );
		} catch ( Exception $e ) {
			return false;
		}
	}
}


// Path: wp-content\plugins\woocommerce\includes\class-wc-product-simple.php

/**
 * Simple Product Class.
 *
 * The default product type kinda product.
 *
 * @package WooCommerce/Classes/Products
 */

defined( 'ABSPATH' ) || exit;

/**
 * Simple product class.
 */
class WC_Product_Simple extends WC_Product {

	/**
	 * Initialize simple product.
	 *
	 * @param WC_Product|int $product Product instance or ID.
	 */
	public function __construct( $product = 0 ) {
		$this->supports[] = 'ajax_add_to_cart';
		parent::__construct( $product );
	}
}


// Path: wp-content\plugins\woocommerce\includes\abstracts\abstract-wc-product.php

/**
 * WooCommerce product base class.
 *
 * @package WooCommerce/Abstracts
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Legacy product contains all deprecated methods for this class and can be
 * removed in the future.
 */
require_once WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-product.php';

/**
 * Abstract Product Class
 *
 * The WooCommerce product class handles individual product data.
 *
 * @version 3.0.0
 * @package WooCommerce/Abstracts
 */
class WC_Product extends WC_Abstract_Legacy_Product {

	/**
	 * This is the name of this object type.
	 *
	 * @var string
	 */
	protected $object_type = 'product';

	/**
	 * Post type.
	 *
	 * @var string
	 */
	protected $post_type = 'product';

	/**
	 * Cache group.
	 *
	 * @var string
	 */
	protected $cache_group = 'products';

	/**
	 * Stores product data.
	 *
	 * @var array
	 */
	protected $data = array(
		'name'               => '',
		'slug'               => '',
		'date_created'       => null,
		'date_modified'      => null,
		'status'             => false,
		'featured'           => false,
		'catalog_visibility' => 'visible',
		'description'        => '',
		'short_description'  => '',
		'sku'                => '',
		'price'              => '',
		'regular_price'      => '',
		'sale_price'         => '',
		'date_on_sale_from'  => null,
		'date_on_sale_to'    => null,
		'total_sales'        => '0',
		'tax_status'         => 'taxable',
		'tax_class'          => '',
		'manage_stock'       => false,
		'stock_quantity'     => null,
		'stock_status'       => 'instock',
		'backorders'         => 'no',
		'low_stock_amount'   => '',
		'sold_individually'  => false,
		'weight'             => '',
		'length'             => '',
		'width'              => '',
		'height'             => '',
		'upsell_ids'         => array(),
		'cross_sell_ids'     => array(),
		'parent_id'          => 0,
		'reviews_allowed'    => true,
		'purchase_note'      => '',
		'attributes'         => array(),
		'default_attributes' => array(),
		'menu_order'         => 0,
		'post_password'      => '',
		'virtual'            => false,
		'downloadable'       => false,
		'category_ids'       => array(),
		'tag_ids'            => array(),
		'shipping_class_id'  => 0,
		'downloads'          => array(),
		'image_id'           => '',
		'gallery_image_ids'  => array(),
		'download_limit'     => -1,
		'download_expiry'    => -1,
		'rating_counts'      => array(),
		'average_rating'     => 0,
		'review_count'       => 0,
	);

	/**
	 * Supported features such as 'ajax_add_to_cart'.
	 *
	 * @var array
	 */
	protected $supports = array();

	/**
	 * Get the product if ID is passed, otherwise the product is new and empty.
	 * This class should NOT be instantiated, but the wc_get_product() function
	 * should be used. It is possible, but the wc_get_product() is preferred.
	 *
	 * @param int|WC_Product|object $product Product to init.
	 */
	public function __construct( $product = 0 ) {
		parent::__construct( $product );
		if ( is_numeric( $product ) && $product > 0 ) {
			$this->set_id( $product );
		} elseif ( $product instanceof self ) {
			$this->set_id( absint( $product->get_id() ) );
		} elseif ( ! empty( $product->ID ) ) {
			$this->set_id( absint( $product->ID ) );
		} else {
			$this->set_object_read( true );
		}

		$this->data_store = WC_Data_Store::load( 'product-' . $this->get_type() );
		if ( $this->get_id() > 0 ) {
			$this->data_store->read( $this );
		}
	}
}

// Path: wp-content\plugins\woocommerce\includes\class-wc-data-store.php

/**
 * WC Data Store.
 *
 * @package WooCommerce\Classes
 * @since   3.0.0
 * @version 3.0.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * Data store class.
 */
class WC_Data_Store {
    /**
	 * Contains an instance of the data store class that we are working with.
	 *
	 * @var WC_Data_Store
	 */
	private $instance = null;

	/**
	 * Contains an array of default WC supported data stores.
	 * Format of object name => class name.
	 * Example: 'product' => 'WC_Product_Data_Store_CPT'
	 * You can also pass something like product_<type> for product stores and
	 * that type will be used first when available, if a store is requested like
	 * this and doesn't exist, then the store would fall back to 'product'.
	 * Ran through `woocommerce_data_stores`.
	 *
	 * @var array
	 */
	private $stores = array(
		'coupon'                => 'WC_Coupon_Data_Store_CPT',
		'customer'              => 'WC_Customer_Data_Store',
		'customer-download'     => 'WC_Customer_Download_Data_Store',
		'customer-download-log' => 'WC_Customer_Download_Log_Data_Store',
		'customer-session'      => 'WC_Customer_Data_Store_Session',
		'order'                 => 'WC_Order_Data_Store_CPT',
		'order-refund'          => 'WC_Order_Refund_Data_Store_CPT',
		'order-item'            => 'WC_Order_Item_Data_Store',
		'order-item-coupon'     => 'WC_Order_Item_Coupon_Data_Store',
		'order-item-fee'        => 'WC_Order_Item_Fee_Data_Store',
		'order-item-product'    => 'WC_Order_Item_Product_Data_Store',
		'order-item-shipping'   => 'WC_Order_Item_Shipping_Data_Store',
		'order-item-tax'        => 'WC_Order_Item_Tax_Data_Store',
		'payment-token'         => 'WC_Payment_Token_Data_Store',
		'product'               => 'WC_Product_Data_Store_CPT',
		'product-grouped'       => 'WC_Product_Grouped_Data_Store_CPT',
		'product-variable'      => 'WC_Product_Variable_Data_Store_CPT',
		'product-variation'     => 'WC_Product_Variation_Data_Store_CPT',
		'shipping-zone'         => 'WC_Shipping_Zone_Data_Store',
		'webhook'               => 'WC_Webhook_Data_Store',
	);

	/**
	 * Contains the name of the current data store's class name.
	 *
	 * @var string
	 */
	private $current_class_name = '';

	/**
	 * The object type this store works with.
	 *
	 * @var string
	 */
	private $object_type = '';


	/**
	 * Tells WC_Data_Store which object (coupon, product, order, etc)
	 * store we want to work with.
	 *
	 * @throws Exception When validation fails.
	 * @param string $object_type Name of object.
	 */
	public function __construct( $object_type ) {
		$this->object_type = $object_type;
		$this->stores      = apply_filters( 'woocommerce_data_stores', $this->stores );

		// If this object type can't be found, check to see if we can load one
		// level up (so if product-type isn't found, we try product).
		if ( ! array_key_exists( $object_type, $this->stores ) ) {
			$pieces      = explode( '-', $object_type );
			$object_type = $pieces[0];
		}

		if ( array_key_exists( $object_type, $this->stores ) ) {
			$store = apply_filters( 'woocommerce_' . $object_type . '_data_store', $this->stores[ $object_type ] );
			if ( is_object( $store ) ) {
				if ( ! $store instanceof WC_Object_Data_Store_Interface ) {
					throw new Exception( __( 'Invalid data store.', 'woocommerce' ) );
				}
				$this->current_class_name = get_class( $store );
				$this->instance           = $store;
			} else {
				if ( ! class_exists( $store ) ) {
					throw new Exception( __( 'Invalid data store.', 'woocommerce' ) );
				}
				$this->current_class_name = $store;
				$this->instance           = new $store();
			}
		} else {
			throw new Exception( __( 'Invalid data store.', 'woocommerce' ) );
		}
	}
    
    
    /**
	 * Reads an object from the data store.
	 *
	 * @since 3.0.0
	 * @param WC_Data $data WooCommerce data instance.
	 */
	public function read( &$data ) {
		$this->instance->read( $data );
	}
}

// Path: wp-content\plugins\woocommerce\includes\data-stores\class-wc-product-data-store-cpt.php

/**
 * WC_Product_Data_Store_CPT class file.
 *
 * @package WooCommerce/Classes
 */

use Automattic\Jetpack\Constants;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * WC Product Data Store: Stored in CPT.
 *
 * @version  3.0.0
 */
class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface, WC_Product_Data_Store_Interface {

	/**
	 * Data stored in meta keys, but not considered "meta".
	 *
	 * @since 3.0.0
	 * @var array
	 */
	protected $internal_meta_keys = array(
		'_visibility',
		'_sku',
		'_price',
		'_regular_price',
		'_sale_price',
		'_sale_price_dates_from',
		'_sale_price_dates_to',
		'total_sales',
		'_tax_status',
		'_tax_class',
		'_manage_stock',
		'_stock',
		'_stock_status',
		'_backorders',
		'_low_stock_amount',
		'_sold_individually',
		'_weight',
		'_length',
		'_width',
		'_height',
		'_upsell_ids',
		'_crosssell_ids',
		'_purchase_note',
		'_default_attributes',
		'_product_attributes',
		'_virtual',
		'_downloadable',
		'_download_limit',
		'_download_expiry',
		'_featured',
		'_downloadable_files',
		'_wc_rating_count',
		'_wc_average_rating',
		'_wc_review_count',
		'_variation_description',
		'_thumbnail_id',
		'_file_paths',
		'_product_image_gallery',
		'_product_version',
		'_wp_old_slug',
		'_edit_last',
		'_edit_lock',
	);

	/**
	 * Meta data which should exist in the DB, even if empty.
	 *
	 * @since 3.6.0
	 *
	 * @var array
	 */
	protected $must_exist_meta_keys = array(
		'_tax_class',
	);

	/**
	 * If we have already saved our extra data, don't do automatic / default handling.
	 *
	 * @var bool
	 */
	protected $extra_data_saved = false;

	/**
	 * Stores updated props.
	 *
	 * @var array
	 */
	protected $updated_props = array();

	/*
	|--------------------------------------------------------------------------
	| CRUD Methods
	|--------------------------------------------------------------------------
	*/
    
    /**
	 * Method to read a product from the database.
	 *
	 * @param WC_Product $product Product object.
	 * @throws Exception If invalid product.
	 */
	public function read( &$product ) {
		$product->set_defaults();
		$post_object = get_post( $product->get_id() );

		if ( ! $product->get_id() || ! $post_object || 'product' !== $post_object->post_type ) {
			throw new Exception( __( 'Invalid product.', 'woocommerce' ) );
		}

		$product->set_props(
			array(
				'name'              => $post_object->post_title,
				'slug'              => $post_object->post_name,
				'date_created'      => 0 < $post_object->post_date_gmt ? wc_string_to_timestamp( $post_object->post_date_gmt ) : null,
				'date_modified'     => 0 < $post_object->post_modified_gmt ? wc_string_to_timestamp( $post_object->post_modified_gmt ) : null,
				'status'            => $post_object->post_status,
				'description'       => $post_object->post_content,
				'short_description' => $post_object->post_excerpt,
				'parent_id'         => $post_object->post_parent,
				'menu_order'        => $post_object->menu_order,
				'post_password'     => $post_object->post_password,
				'reviews_allowed'   => 'open' === $post_object->comment_status,
			)
		);

		$this->read_attributes( $product );
		$this->read_downloads( $product );
		$this->read_visibility( $product );
		$this->read_product_data( $product );
		$this->read_extra_data( $product );
		$product->set_object_read( true );

		do_action( 'woocommerce_product_read', $product->get_id() );
	}
}

// Path: wp-content\plugins\woocommerce\includes\data-stores\class-wc-data-store-wp.php

/**
 * Shared logic for WP based data.
 * Contains functions like meta handling for all default data stores.
 * Your own data store doesn't need to use WC_Data_Store_WP -- you can write
 * your own meta handling functions.
 *
 * @version 3.0.0
 * @package WooCommerce/Classes
 */

defined( 'ABSPATH' ) || exit;

/**
 * WC_Data_Store_WP class.
 */
class WC_Data_Store_WP {

	/**
	 * 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 = 'post';

	/**
	 * 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 = '';

	/**
	 * Data stored in meta keys, but not considered "meta" for an object.
	 *
	 * @since 3.0.0
	 *
	 * @var array
	 */
	protected $internal_meta_keys = array();

	/**
	 * Meta data which should exist in the DB, even if empty.
	 *
	 * @since 3.6.0
	 *
	 * @var array
	 */
	protected $must_exist_meta_keys = array();	
}

// Path: wp-content\plugins\woocommerce\includes\abstracts\abstract-wc-data.php

/**
 * Abstract Data.
 *
 * Handles generic data interaction which is implemented by
 * the different data store classes.
 *
 * @class       WC_Data
 * @version     3.0.0
 * @package     WooCommerce/Classes
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Abstract WC Data Class
 *
 * Implemented by classes using the same CRUD(s) pattern.
 *
 * @version  2.6.0
 * @package  WooCommerce/Abstracts
 */
abstract class WC_Data {

	/**
	 * ID for this object.
	 *
	 * @since 3.0.0
	 * @var int
	 */
	protected $id = 0;

	/**
	 * Core data for this object. Name value pairs (name + default value).
	 *
	 * @since 3.0.0
	 * @var array
	 */
	protected $data = array();

	/**
	 * Core data changes for this object.
	 *
	 * @since 3.0.0
	 * @var array
	 */
	protected $changes = array();

	/**
	 * This is false until the object is read from the DB.
	 *
	 * @since 3.0.0
	 * @var bool
	 */
	protected $object_read = false;

	/**
	 * This is the name of this object type.
	 *
	 * @since 3.0.0
	 * @var string
	 */
	protected $object_type = 'data';

	/**
	 * Extra data for this object. Name value pairs (name + default value).
	 * Used as a standard way for sub classes (like product types) to add
	 * additional information to an inherited class.
	 *
	 * @since 3.0.0
	 * @var array
	 */
	protected $extra_data = array();

	/**
	 * Set to _data on construct so we can track and reset data if needed.
	 *
	 * @since 3.0.0
	 * @var array
	 */
	protected $default_data = array();

	/**
	 * Contains a reference to the data store for this class.
	 *
	 * @since 3.0.0
	 * @var object
	 */
	protected $data_store;

	/**
	 * Stores meta in cache for future reads.
	 * A group must be set to to enable caching.
	 *
	 * @since 3.0.0
	 * @var string
	 */
	protected $cache_group = '';

	/**
	 * Stores additional meta data.
	 *
	 * @since 3.0.0
	 * @var array
	 */
	protected $meta_data = null;

	/**
	 * Default constructor.
	 *
	 * @param int|object|array $read ID to load from the DB (optional) or already queried data.
	 */
	public function __construct( $read = 0 ) {
		$this->data         = array_merge( $this->data, $this->extra_data );
		$this->default_data = $this->data;
	}
    
    /**
	 * Set object read property.
	 *
	 * @since 3.0.0
	 * @param boolean $read Should read?.
	 */
	public function set_object_read( $read = true ) {
		$this->object_read = (bool) $read;
	}
}