PageRenderTime 61ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php

https://bitbucket.org/ngallois/lcsailing
PHP | 388 lines | 215 code | 43 blank | 130 comment | 23 complexity | ece782ad519f2bffc17fbd873ea7d2da MD5 | raw file
Possible License(s): MIT, GPL-3.0, Apache-2.0
  1. <?php
  2. /**
  3. * Abstract_WC_Order_Data_Store_CPT class file.
  4. *
  5. * @package WooCommerce/Classes
  6. */
  7. if ( ! defined( 'ABSPATH' ) ) {
  8. exit;
  9. }
  10. /**
  11. * Abstract Order Data Store: Stored in CPT.
  12. *
  13. * @version 3.0.0
  14. */
  15. abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface, WC_Abstract_Order_Data_Store_Interface {
  16. /**
  17. * Internal meta type used to store order data.
  18. *
  19. * @var string
  20. */
  21. protected $meta_type = 'post';
  22. /**
  23. * Data stored in meta keys, but not considered "meta" for an order.
  24. *
  25. * @since 3.0.0
  26. * @var array
  27. */
  28. protected $internal_meta_keys = array(
  29. '_order_currency',
  30. '_cart_discount',
  31. '_cart_discount_tax',
  32. '_order_shipping',
  33. '_order_shipping_tax',
  34. '_order_tax',
  35. '_order_total',
  36. '_order_version',
  37. '_prices_include_tax',
  38. '_payment_tokens',
  39. );
  40. /*
  41. |--------------------------------------------------------------------------
  42. | CRUD Methods
  43. |--------------------------------------------------------------------------
  44. */
  45. /**
  46. * Method to create a new order in the database.
  47. *
  48. * @param WC_Order $order Order object.
  49. */
  50. public function create( &$order ) {
  51. $order->set_version( WC_VERSION );
  52. $order->set_date_created( current_time( 'timestamp', true ) );
  53. $order->set_currency( $order->get_currency() ? $order->get_currency() : get_woocommerce_currency() );
  54. $id = wp_insert_post(
  55. apply_filters(
  56. 'woocommerce_new_order_data',
  57. array(
  58. 'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
  59. 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
  60. 'post_type' => $order->get_type( 'edit' ),
  61. 'post_status' => 'wc-' . ( $order->get_status( 'edit' ) ? $order->get_status( 'edit' ) : apply_filters( 'woocommerce_default_order_status', 'pending' ) ),
  62. 'ping_status' => 'closed',
  63. 'post_author' => 1,
  64. 'post_title' => $this->get_post_title(),
  65. 'post_password' => uniqid( 'order_' ),
  66. 'post_parent' => $order->get_parent_id( 'edit' ),
  67. 'post_excerpt' => $this->get_post_excerpt( $order ),
  68. )
  69. ), true
  70. );
  71. if ( $id && ! is_wp_error( $id ) ) {
  72. $order->set_id( $id );
  73. $this->update_post_meta( $order );
  74. $order->save_meta_data();
  75. $order->apply_changes();
  76. $this->clear_caches( $order );
  77. }
  78. }
  79. /**
  80. * Method to read an order from the database.
  81. *
  82. * @param WC_Data $order Order object.
  83. *
  84. * @throws Exception If passed order is invalid.
  85. */
  86. public function read( &$order ) {
  87. $order->set_defaults();
  88. $post_object = get_post( $order->get_id() );
  89. if ( ! $order->get_id() || ! $post_object || ! in_array( $post_object->post_type, wc_get_order_types(), true ) ) {
  90. throw new Exception( __( 'Invalid order.', 'woocommerce' ) );
  91. }
  92. $order->set_props(
  93. array(
  94. 'parent_id' => $post_object->post_parent,
  95. 'date_created' => 0 < $post_object->post_date_gmt ? wc_string_to_timestamp( $post_object->post_date_gmt ) : null,
  96. 'date_modified' => 0 < $post_object->post_modified_gmt ? wc_string_to_timestamp( $post_object->post_modified_gmt ) : null,
  97. 'status' => $post_object->post_status,
  98. )
  99. );
  100. $this->read_order_data( $order, $post_object );
  101. $order->read_meta_data();
  102. $order->set_object_read( true );
  103. /**
  104. * In older versions, discounts may have been stored differently.
  105. * Update them now so if the object is saved, the correct values are
  106. * stored. @todo When meta is flattened, handle this during migration.
  107. */
  108. if ( version_compare( $order->get_version( 'edit' ), '2.3.7', '<' ) && $order->get_prices_include_tax( 'edit' ) ) {
  109. $order->set_discount_total( (double) get_post_meta( $order->get_id(), '_cart_discount', true ) - (double) get_post_meta( $order->get_id(), '_cart_discount_tax', true ) );
  110. }
  111. }
  112. /**
  113. * Method to update an order in the database.
  114. *
  115. * @param WC_Order $order Order object.
  116. */
  117. public function update( &$order ) {
  118. $order->save_meta_data();
  119. $order->set_version( WC_VERSION );
  120. if ( null === $order->get_date_created( 'edit' ) ) {
  121. $order->set_date_created( current_time( 'timestamp', true ) );
  122. }
  123. $changes = $order->get_changes();
  124. // Only update the post when the post data changes.
  125. if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'post_excerpt' ), array_keys( $changes ) ) ) {
  126. $post_data = array(
  127. 'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
  128. 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
  129. 'post_status' => 'wc-' . ( $order->get_status( 'edit' ) ? $order->get_status( 'edit' ) : apply_filters( 'woocommerce_default_order_status', 'pending' ) ),
  130. 'post_parent' => $order->get_parent_id(),
  131. 'post_excerpt' => $this->get_post_excerpt( $order ),
  132. 'post_modified' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getOffsetTimestamp() ) : current_time( 'mysql' ),
  133. 'post_modified_gmt' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getTimestamp() ) : current_time( 'mysql', 1 ),
  134. );
  135. /**
  136. * When updating this object, to prevent infinite loops, use $wpdb
  137. * to update data, since wp_update_post spawns more calls to the
  138. * save_post action.
  139. *
  140. * This ensures hooks are fired by either WP itself (admin screen save),
  141. * or an update purely from CRUD.
  142. */
  143. if ( doing_action( 'save_post' ) ) {
  144. $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $order->get_id() ) );
  145. clean_post_cache( $order->get_id() );
  146. } else {
  147. wp_update_post( array_merge( array( 'ID' => $order->get_id() ), $post_data ) );
  148. }
  149. $order->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
  150. }
  151. $this->update_post_meta( $order );
  152. $order->apply_changes();
  153. $this->clear_caches( $order );
  154. }
  155. /**
  156. * Method to delete an order from the database.
  157. *
  158. * @param WC_Order $order Order object.
  159. * @param array $args Array of args to pass to the delete method.
  160. *
  161. * @return void
  162. */
  163. public function delete( &$order, $args = array() ) {
  164. $id = $order->get_id();
  165. $args = wp_parse_args(
  166. $args,
  167. array(
  168. 'force_delete' => false,
  169. )
  170. );
  171. if ( ! $id ) {
  172. return;
  173. }
  174. if ( $args['force_delete'] ) {
  175. wp_delete_post( $id );
  176. $order->set_id( 0 );
  177. do_action( 'woocommerce_delete_order', $id );
  178. } else {
  179. wp_trash_post( $id );
  180. $order->set_status( 'trash' );
  181. do_action( 'woocommerce_trash_order', $id );
  182. }
  183. }
  184. /*
  185. |--------------------------------------------------------------------------
  186. | Additional Methods
  187. |--------------------------------------------------------------------------
  188. */
  189. /**
  190. * Excerpt for post.
  191. *
  192. * @param WC_order $order Order object.
  193. * @return string
  194. */
  195. protected function get_post_excerpt( $order ) {
  196. return '';
  197. }
  198. /**
  199. * Get a title for the new post type.
  200. *
  201. * @return string
  202. */
  203. protected function get_post_title() {
  204. // @codingStandardsIgnoreStart
  205. /* translators: %s: Order date */
  206. return sprintf( __( 'Order &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) );
  207. // @codingStandardsIgnoreEnd
  208. }
  209. /**
  210. * Read order data. Can be overridden by child classes to load other props.
  211. *
  212. * @param WC_Order $order Order object.
  213. * @param object $post_object Post object.
  214. * @since 3.0.0
  215. */
  216. protected function read_order_data( &$order, $post_object ) {
  217. $id = $order->get_id();
  218. $order->set_props(
  219. array(
  220. 'currency' => get_post_meta( $id, '_order_currency', true ),
  221. 'discount_total' => get_post_meta( $id, '_cart_discount', true ),
  222. 'discount_tax' => get_post_meta( $id, '_cart_discount_tax', true ),
  223. 'shipping_total' => get_post_meta( $id, '_order_shipping', true ),
  224. 'shipping_tax' => get_post_meta( $id, '_order_shipping_tax', true ),
  225. 'cart_tax' => get_post_meta( $id, '_order_tax', true ),
  226. 'total' => get_post_meta( $id, '_order_total', true ),
  227. 'version' => get_post_meta( $id, '_order_version', true ),
  228. 'prices_include_tax' => metadata_exists( 'post', $id, '_prices_include_tax' ) ? 'yes' === get_post_meta( $id, '_prices_include_tax', true ) : 'yes' === get_option( 'woocommerce_prices_include_tax' ),
  229. )
  230. );
  231. // Gets extra data associated with the order if needed.
  232. foreach ( $order->get_extra_data_keys() as $key ) {
  233. $function = 'set_' . $key;
  234. if ( is_callable( array( $order, $function ) ) ) {
  235. $order->{$function}( get_post_meta( $order->get_id(), '_' . $key, true ) );
  236. }
  237. }
  238. }
  239. /**
  240. * Helper method that updates all the post meta for an order based on it's settings in the WC_Order class.
  241. *
  242. * @param WC_Order $order Order object.
  243. * @since 3.0.0
  244. */
  245. protected function update_post_meta( &$order ) {
  246. $updated_props = array();
  247. $meta_key_to_props = array(
  248. '_order_currency' => 'currency',
  249. '_cart_discount' => 'discount_total',
  250. '_cart_discount_tax' => 'discount_tax',
  251. '_order_shipping' => 'shipping_total',
  252. '_order_shipping_tax' => 'shipping_tax',
  253. '_order_tax' => 'cart_tax',
  254. '_order_total' => 'total',
  255. '_order_version' => 'version',
  256. '_prices_include_tax' => 'prices_include_tax',
  257. );
  258. $props_to_update = $this->get_props_to_update( $order, $meta_key_to_props );
  259. foreach ( $props_to_update as $meta_key => $prop ) {
  260. $value = $order->{"get_$prop"}( 'edit' );
  261. if ( 'prices_include_tax' === $prop ) {
  262. $value = $value ? 'yes' : 'no';
  263. }
  264. if ( update_post_meta( $order->get_id(), $meta_key, $value ) ) {
  265. $updated_props[] = $prop;
  266. }
  267. }
  268. do_action( 'woocommerce_order_object_updated_props', $order, $updated_props );
  269. }
  270. /**
  271. * Clear any caches.
  272. *
  273. * @param WC_Order $order Order object.
  274. * @since 3.0.0
  275. */
  276. protected function clear_caches( &$order ) {
  277. clean_post_cache( $order->get_id() );
  278. wc_delete_shop_order_transients( $order );
  279. wp_cache_delete( 'order-items-' . $order->get_id(), 'orders' );
  280. }
  281. /**
  282. * Read order items of a specific type from the database for this order.
  283. *
  284. * @param WC_Order $order Order object.
  285. * @param string $type Order item type.
  286. * @return array
  287. */
  288. public function read_items( $order, $type ) {
  289. global $wpdb;
  290. // Get from cache if available.
  291. $items = wp_cache_get( 'order-items-' . $order->get_id(), 'orders' );
  292. if ( false === $items ) {
  293. $items = $wpdb->get_results(
  294. $wpdb->prepare( "SELECT order_item_type, order_item_id, order_id, order_item_name FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d ORDER BY order_item_id;", $order->get_id() )
  295. );
  296. foreach ( $items as $item ) {
  297. wp_cache_set( 'item-' . $item->order_item_id, $item, 'order-items' );
  298. }
  299. wp_cache_set( 'order-items-' . $order->get_id(), $items, 'orders' );
  300. }
  301. $items = wp_list_filter( $items, array( 'order_item_type' => $type ) );
  302. if ( ! empty( $items ) ) {
  303. $items = array_map( array( 'WC_Order_Factory', 'get_order_item' ), array_combine( wp_list_pluck( $items, 'order_item_id' ), $items ) );
  304. } else {
  305. $items = array();
  306. }
  307. return $items;
  308. }
  309. /**
  310. * Remove all line items (products, coupons, shipping, taxes) from the order.
  311. *
  312. * @param WC_Order $order Order object.
  313. * @param string $type Order item type. Default null.
  314. */
  315. public function delete_items( $order, $type = null ) {
  316. global $wpdb;
  317. if ( ! empty( $type ) ) {
  318. $wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id AND items.order_id = %d AND items.order_item_type = %s", $order->get_id(), $type ) );
  319. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $order->get_id(), $type ) );
  320. } else {
  321. $wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id and items.order_id = %d", $order->get_id() ) );
  322. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $order->get_id() ) );
  323. }
  324. $this->clear_caches( $order );
  325. }
  326. /**
  327. * Get token ids for an order.
  328. *
  329. * @param WC_Order $order Order object.
  330. * @return array
  331. */
  332. public function get_payment_token_ids( $order ) {
  333. $token_ids = array_filter( (array) get_post_meta( $order->get_id(), '_payment_tokens', true ) );
  334. return $token_ids;
  335. }
  336. /**
  337. * Update token ids for an order.
  338. *
  339. * @param WC_Order $order Order object.
  340. * @param array $token_ids Payment token ids.
  341. */
  342. public function update_payment_token_ids( $order, $token_ids ) {
  343. update_post_meta( $order->get_id(), '_payment_tokens', $token_ids );
  344. }
  345. }