class-wc-product-factory.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. /**
  3. * Product Factory
  4. *
  5. * The WooCommerce product factory creating the right product object.
  6. *
  7. * @package WooCommerce/Classes
  8. * @version 3.0.0
  9. */
  10. defined( 'ABSPATH' ) || exit;
  11. /**
  12. * Product factory class.
  13. */
  14. class WC_Product_Factory {
  15. /**
  16. * Get a product.
  17. *
  18. * @param mixed $product_id WC_Product|WP_Post|int|bool $product Product instance, post instance, numeric or false to use global $post.
  19. * @param array $deprecated Previously used to pass arguments to the factory, e.g. to force a type.
  20. * @return WC_Product|bool Product object or null if the product cannot be loaded.
  21. */
  22. public function get_product( $product_id = false, $deprecated = array() ) {
  23. $product_id = $this->get_product_id( $product_id );
  24. if ( ! $product_id ) {
  25. return false;
  26. }
  27. $product_type = $this->get_product_type( $product_id );
  28. // Backwards compatibility.
  29. if ( ! empty( $deprecated ) ) {
  30. 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.' );
  31. if ( isset( $deprecated['product_type'] ) ) {
  32. $product_type = $this->get_classname_from_product_type( $deprecated['product_type'] );
  33. }
  34. }
  35. $classname = $this->get_product_classname( $product_id, $product_type );
  36. try {
  37. return new $classname( $product_id, $deprecated );
  38. } catch ( Exception $e ) {
  39. return false;
  40. }
  41. }
  42. /**
  43. * Gets a product classname and allows filtering. Returns WC_Product_Simple if the class does not exist.
  44. *
  45. * @since 3.0.0
  46. * @param int $product_id Product ID.
  47. * @param string $product_type Product type.
  48. * @return string
  49. */
  50. public static function get_product_classname( $product_id, $product_type ) {
  51. $classname = apply_filters( 'woocommerce_product_class', self::get_classname_from_product_type( $product_type ), $product_type, 'variation' === $product_type ? 'product_variation' : 'product', $product_id );
  52. if ( ! $classname || ! class_exists( $classname ) ) {
  53. $classname = 'WC_Product_Simple';
  54. }
  55. return $classname;
  56. }
  57. /**
  58. * Get the product type for a product.
  59. *
  60. * @since 3.0.0
  61. * @param int $product_id Product ID.
  62. * @return string|false
  63. */
  64. public static function get_product_type( $product_id ) {
  65. // Allow the overriding of the lookup in this function. Return the product type here.
  66. $override = apply_filters( 'woocommerce_product_type_query', false, $product_id );
  67. if ( ! $override ) {
  68. return WC_Data_Store::load( 'product' )->get_product_type( $product_id );
  69. } else {
  70. return $override;
  71. }
  72. }
  73. /**
  74. * Create a WC coding standards compliant class name e.g. WC_Product_Type_Class instead of WC_Product_type-class.
  75. *
  76. * @param string $product_type Product type.
  77. * @return string|false
  78. */
  79. public static function get_classname_from_product_type( $product_type ) {
  80. return $product_type ? 'WC_Product_' . implode( '_', array_map( 'ucfirst', explode( '-', $product_type ) ) ) : false;
  81. }
  82. /**
  83. * Get the product ID depending on what was passed.
  84. *
  85. * @since 3.0.0
  86. * @param WC_Product|WP_Post|int|bool $product Product instance, post instance, numeric or false to use global $post.
  87. * @return int|bool false on failure
  88. */
  89. private function get_product_id( $product ) {
  90. global $post;
  91. if ( false === $product && isset( $post, $post->ID ) && 'product' === get_post_type( $post->ID ) ) {
  92. return absint( $post->ID );
  93. } elseif ( is_numeric( $product ) ) {
  94. return $product;
  95. } elseif ( $product instanceof WC_Product ) {
  96. return $product->get_id();
  97. } elseif ( ! empty( $product->ID ) ) {
  98. return $product->ID;
  99. } else {
  100. return false;
  101. }
  102. }
  103. }