PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/theme WP a cương/test_wp/wp-content/plugins/woocommerce/classes/class-wc-product-variation.php

https://gitlab.com/hop23typhu/list-theme
PHP | 456 lines | 228 code | 98 blank | 130 comment | 73 complexity | 2852e8c20e0d32b99e7ae4e285a37220 MD5 | raw file
  1. <?php
  2. if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
  3. /**
  4. * Product Variation Class
  5. *
  6. * The WooCommerce product variation class handles product variation data.
  7. *
  8. * @class WC_Product_Variation
  9. * @version 2.0.0
  10. * @package WooCommerce/Classes
  11. * @category Class
  12. * @author WooThemes
  13. */
  14. class WC_Product_Variation extends WC_Product {
  15. /** @public int ID of the variable product. */
  16. public $variation_id;
  17. /** @public object Parent Variable product object. */
  18. public $parent;
  19. /** @public array Stores variation data (attributes) for the current variation. */
  20. public $variation_data = array();
  21. /** @public bool True if the variation has a length. */
  22. public $variation_has_length = false;
  23. /** @public bool True if the variation has a width. */
  24. public $variation_has_width = false;
  25. /** @public bool True if the variation has a height. */
  26. public $variation_has_height = false;
  27. /** @public bool True if the variation has a weight. */
  28. public $variation_has_weight = false;
  29. /** @public bool True if the variation has stock and is managing stock. */
  30. public $variation_has_stock = false;
  31. /** @public bool True if the variation has a sku. */
  32. public $variation_has_sku = false;
  33. /** @public string Stores the shipping class of the variation. */
  34. public $variation_shipping_class = false;
  35. /** @public int Stores the shipping class ID of the variation. */
  36. public $variation_shipping_class_id = false;
  37. /** @public bool True if the variation has a tax class. */
  38. public $variation_has_tax_class = false;
  39. /**
  40. * Loads all product data from custom fields
  41. *
  42. * @access public
  43. * @param int $variation_id ID of the variation to load
  44. * @param array $args Array of the arguments containing parent product data
  45. * @return void
  46. */
  47. public function __construct( $variation, $args = array() ) {
  48. $this->product_type = 'variation';
  49. if ( is_object( $variation ) ) {
  50. $this->variation_id = absint( $variation->ID );
  51. } else {
  52. $this->variation_id = absint( $variation );
  53. }
  54. /* Get main product data from parent (args) */
  55. $this->id = ! empty( $args['parent_id'] ) ? intval( $args['parent_id'] ) : wp_get_post_parent_id( $this->variation_id );
  56. // The post doesn't have a parent id, therefore its invalid.
  57. if ( empty( $this->id ) )
  58. return false;
  59. // Get post data
  60. $this->parent = ! empty( $args['parent'] ) ? $args['parent'] : get_product( $this->id );
  61. $this->post = ! empty( $this->parent->post ) ? $this->parent->post : array();
  62. $this->product_custom_fields = get_post_meta( $this->variation_id );
  63. // Get the variation attributes from meta
  64. foreach ( $this->product_custom_fields as $name => $value ) {
  65. if ( ! strstr( $name, 'attribute_' ) )
  66. continue;
  67. $this->variation_data[ $name ] = sanitize_title( $value[0] );
  68. }
  69. // Now get variation meta to override the parent variable product
  70. if ( ! empty( $this->product_custom_fields['_sku'][0] ) ) {
  71. $this->variation_has_sku = true;
  72. $this->sku = $this->product_custom_fields['_sku'][0];
  73. }
  74. if ( isset( $this->product_custom_fields['_stock'][0] ) && $this->product_custom_fields['_stock'][0] !== '' ) {
  75. $this->variation_has_stock = true;
  76. $this->manage_stock = 'yes';
  77. $this->stock = $this->product_custom_fields['_stock'][0];
  78. }
  79. if ( isset( $this->product_custom_fields['_weight'][0] ) && $this->product_custom_fields['_weight'][0] !== '' ) {
  80. $this->variation_has_weight = true;
  81. $this->weight = $this->product_custom_fields['_weight'][0];
  82. }
  83. if ( isset( $this->product_custom_fields['_length'][0] ) && $this->product_custom_fields['_length'][0] !== '' ) {
  84. $this->variation_has_length = true;
  85. $this->length = $this->product_custom_fields['_length'][0];
  86. }
  87. if ( isset( $this->product_custom_fields['_width'][0] ) && $this->product_custom_fields['_width'][0] !== '' ) {
  88. $this->variation_has_width = true;
  89. $this->width = $this->product_custom_fields['_width'][0];
  90. }
  91. if ( isset( $this->product_custom_fields['_height'][0] ) && $this->product_custom_fields['_height'][0] !== '' ) {
  92. $this->variation_has_height = true;
  93. $this->height = $this->product_custom_fields['_height'][0];
  94. }
  95. if ( isset( $this->product_custom_fields['_downloadable'][0] ) && $this->product_custom_fields['_downloadable'][0] == 'yes' ) {
  96. $this->downloadable = 'yes';
  97. } else {
  98. $this->downloadable = 'no';
  99. }
  100. if ( isset( $this->product_custom_fields['_virtual'][0] ) && $this->product_custom_fields['_virtual'][0] == 'yes' ) {
  101. $this->virtual = 'yes';
  102. } else {
  103. $this->virtual = 'no';
  104. }
  105. if ( isset( $this->product_custom_fields['_tax_class'][0] ) ) {
  106. $this->variation_has_tax_class = true;
  107. $this->tax_class = $this->product_custom_fields['_tax_class'][0];
  108. }
  109. if ( isset( $this->product_custom_fields['_sale_price_dates_from'][0] ) )
  110. $this->sale_price_dates_from = $this->product_custom_fields['_sale_price_dates_from'][0];
  111. if ( isset( $this->product_custom_fields['_sale_price_dates_to'][0] ) )
  112. $this->sale_price_dates_from = $this->product_custom_fields['_sale_price_dates_to'][0];
  113. // Prices
  114. $this->price = isset( $this->product_custom_fields['_price'][0] ) ? $this->product_custom_fields['_price'][0] : '';
  115. $this->regular_price = isset( $this->product_custom_fields['_regular_price'][0] ) ? $this->product_custom_fields['_regular_price'][0] : '';
  116. $this->sale_price = isset( $this->product_custom_fields['_sale_price'][0] ) ? $this->product_custom_fields['_sale_price'][0] : '';
  117. // Backwards compat for prices
  118. if ( $this->price !== '' && $this->regular_price == '' ) {
  119. update_post_meta( $this->variation_id, '_regular_price', $this->price );
  120. $this->regular_price = $this->price;
  121. if ( $this->sale_price !== '' && $this->sale_price < $this->regular_price ) {
  122. update_post_meta( $this->variation_id, '_price', $this->sale_price );
  123. $this->price = $this->sale_price;
  124. }
  125. }
  126. $this->total_stock = $this->stock;
  127. }
  128. /**
  129. * Returns whether or not the product post exists.
  130. *
  131. * @access public
  132. * @return bool
  133. */
  134. function exists() {
  135. return empty( $this->id ) ? false : true;
  136. }
  137. /**
  138. * Returns whether or not the variation is visible.
  139. *
  140. * @access public
  141. * @return bool
  142. */
  143. public function is_visible() {
  144. $visible = true;
  145. // Out of stock visibility
  146. if ( get_option('woocommerce_hide_out_of_stock_items') == 'yes' && ! $this->is_in_stock() )
  147. $visible = false;
  148. // Price not set
  149. elseif ( $this->price == "" )
  150. $visible = false;
  151. return apply_filters( 'woocommerce_product_is_visible', $visible, $this->id );
  152. }
  153. /**
  154. * Returns whether or not the variations parent is visible.
  155. *
  156. * @access public
  157. * @return bool
  158. */
  159. public function parent_is_visible() {
  160. return parent::is_visible();
  161. }
  162. /**
  163. * Get variation ID
  164. *
  165. * @return int
  166. */
  167. public function get_variation_id() {
  168. return absint( $this->variation_id );
  169. }
  170. /**
  171. * Get variation attribute values
  172. *
  173. * @return array of attributes and their values for this variation
  174. */
  175. public function get_variation_attributes() {
  176. return $this->variation_data;
  177. }
  178. /**
  179. * Get variation price HTML. Prices are not inherited from parents.
  180. *
  181. * @param string $price (default: '')
  182. * @return string containing the formatted price
  183. */
  184. public function get_price_html( $price = '' ) {
  185. if ( $this->price !== '' ) {
  186. if ( $this->price == $this->sale_price && $this->sale_price < $this->regular_price ) {
  187. $price = '<del>' . woocommerce_price( $this->regular_price ) . '</del> <ins>' . woocommerce_price( $this->sale_price ) . '</ins>';
  188. $price = apply_filters( 'woocommerce_variation_sale_price_html', $price, $this );
  189. } elseif ( $this->price > 0 ) {
  190. $price = woocommerce_price( $this->price );
  191. $price = apply_filters( 'woocommerce_variation_price_html', $price, $this );
  192. } else {
  193. $price = __( 'Free!', 'woocommerce' );
  194. $price = apply_filters( 'woocommerce_variation_free_price_html', $price, $this );
  195. }
  196. } else {
  197. $price = apply_filters( 'woocommerce_variation_empty_price_html', '', $this );
  198. }
  199. return $price;
  200. }
  201. /**
  202. * Gets the main product image.
  203. *
  204. * @access public
  205. * @param string $size (default: 'shop_thumbnail')
  206. * @return string
  207. */
  208. public function get_image( $size = 'shop_thumbnail', $attr = array() ) {
  209. global $woocommerce;
  210. $image = '';
  211. if ( $this->variation_id && has_post_thumbnail( $this->variation_id ) ) {
  212. $image = get_the_post_thumbnail( $this->variation_id, $size, $attr );
  213. } elseif ( has_post_thumbnail( $this->id ) ) {
  214. $image = get_the_post_thumbnail( $this->id, $size, $attr );
  215. } elseif ( ( $parent_id = wp_get_post_parent_id( $this->id ) ) && has_post_thumbnail( $parent_id ) ) {
  216. $image = get_the_post_thumbnail( $parent_id, $size, $attr);
  217. } else {
  218. $image = woocommerce_placeholder_img( $size );
  219. }
  220. return $image;
  221. }
  222. /**
  223. * Set stock level of the product.
  224. *
  225. * @access public
  226. * @param mixed $amount (default: null)
  227. * @return int Stock
  228. */
  229. function set_stock( $amount = null ) {
  230. global $woocommerce;
  231. if ( $this->variation_has_stock ) {
  232. if ( $this->managing_stock() && ! is_null( $amount ) ) {
  233. $this->stock = intval( $amount );
  234. $this->total_stock = intval( $amount );
  235. update_post_meta( $this->variation_id, '_stock', $this->stock );
  236. $woocommerce->clear_product_transients( $this->id ); // Clear transient
  237. // Check parents out of stock attribute
  238. if ( ! $this->is_in_stock() ) {
  239. // Check parent
  240. $parent_product = get_product( $this->id );
  241. // Only continue if the parent has backorders off
  242. if ( ! $parent_product->backorders_allowed() && $parent_product->get_total_stock() <= 0 )
  243. $this->set_stock_status( 'outofstock' );
  244. } elseif ( $this->is_in_stock() ) {
  245. $this->set_stock_status( 'instock' );
  246. }
  247. return apply_filters( 'woocommerce_stock_amount', $this->stock );
  248. }
  249. } else {
  250. return parent::set_stock( $amount );
  251. }
  252. }
  253. /**
  254. * Reduce stock level of the product.
  255. *
  256. * @access public
  257. * @param int $by (default: 1) Amount to reduce by
  258. * @return int stock level
  259. */
  260. public function reduce_stock( $by = 1 ) {
  261. global $woocommerce;
  262. if ( $this->variation_has_stock ) {
  263. if ( $this->managing_stock() ) {
  264. $this->stock = $this->stock - $by;
  265. $this->total_stock = $this->total_stock - $by;
  266. update_post_meta( $this->variation_id, '_stock', $this->stock );
  267. $woocommerce->clear_product_transients( $this->id ); // Clear transient
  268. // Check parents out of stock attribute
  269. if ( ! $this->is_in_stock() ) {
  270. // Check parent
  271. $parent_product = get_product( $this->id );
  272. // Only continue if the parent has backorders off
  273. if ( ! $parent_product->backorders_allowed() && $parent_product->get_total_stock() <= 0 )
  274. $this->set_stock_status( 'outofstock' );
  275. }
  276. return apply_filters( 'woocommerce_stock_amount', $this->stock );
  277. }
  278. } else {
  279. return parent::reduce_stock( $by );
  280. }
  281. }
  282. /**
  283. * Increase stock level of the product.
  284. *
  285. * @access public
  286. * @param int $by (default: 1) Amount to increase by
  287. * @return int stock level
  288. */
  289. public function increase_stock( $by = 1 ) {
  290. global $woocommerce;
  291. if ($this->variation_has_stock) :
  292. if ($this->managing_stock()) :
  293. $this->stock = $this->stock + $by;
  294. $this->total_stock = $this->total_stock + $by;
  295. update_post_meta( $this->variation_id, '_stock', $this->stock );
  296. $woocommerce->clear_product_transients( $this->id ); // Clear transient
  297. // Parents out of stock attribute
  298. if ( $this->is_in_stock() )
  299. $this->set_stock_status( 'instock' );
  300. return apply_filters( 'woocommerce_stock_amount', $this->stock );
  301. endif;
  302. else :
  303. return parent::increase_stock( $by );
  304. endif;
  305. }
  306. /**
  307. * Get the shipping class, and if not set, get the shipping class of the parent.
  308. *
  309. * @access public
  310. * @return string
  311. */
  312. public function get_shipping_class() {
  313. if ( ! $this->variation_shipping_class ) {
  314. $classes = get_the_terms( $this->variation_id, 'product_shipping_class' );
  315. if ( $classes && ! is_wp_error( $classes ) ) {
  316. $this->variation_shipping_class = esc_attr( current( $classes )->slug );
  317. } else {
  318. $this->variation_shipping_class = parent::get_shipping_class();
  319. }
  320. }
  321. return $this->variation_shipping_class;
  322. }
  323. /**
  324. * Returns the product shipping class ID.
  325. *
  326. * @access public
  327. * @return int
  328. */
  329. public function get_shipping_class_id() {
  330. if ( ! $this->variation_shipping_class_id ) {
  331. $classes = get_the_terms( $this->variation_id, 'product_shipping_class' );
  332. if ( $classes && ! is_wp_error( $classes ) )
  333. $this->variation_shipping_class_id = current( $classes )->term_id;
  334. else
  335. $this->variation_shipping_class_id = parent::get_shipping_class_id();
  336. }
  337. return absint( $this->variation_shipping_class_id );
  338. }
  339. /**
  340. * Get file download path identified by $download_id
  341. *
  342. * @access public
  343. * @param string $download_id file identifier
  344. * @return array
  345. */
  346. public function get_file_download_path( $download_id ) {
  347. $file_path = '';
  348. $file_paths = (array) apply_filters( 'woocommerce_file_download_paths', get_post_meta( $this->variation_id, '_file_paths', true ), $this->variation_id, null, null );
  349. if ( ! $download_id && count( $file_paths ) == 1 ) {
  350. // backwards compatibility for old-style download URLs and template files
  351. $file_path = array_shift( $file_paths );
  352. } elseif ( isset( $file_paths[ $download_id ] ) ) {
  353. $file_path = $file_paths[ $download_id ];
  354. }
  355. // allow overriding based on the particular file being requested
  356. return apply_filters( 'woocommerce_file_download_path', $file_path, $this->variation_id, $download_id );
  357. }
  358. }