PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/opentickets-community-edition/inc/ticket/product.class.php

https://gitlab.com/leobelizquierdo/cabotsubmitter-wordpress
PHP | 273 lines | 162 code | 52 blank | 59 comment | 28 complexity | 2481f673e3b2d78ac47a993a46c80513 MD5 | raw file
  1. <?php if ( __FILE__ == $_SERVER['SCRIPT_FILENAME'] ) die( header( 'Location: /') );
  2. // controls the core functionality of the evet area post type
  3. class QSOT_Ticket_Product {
  4. // container for the singleton instance
  5. protected static $instance = null;
  6. // get the singleton instance
  7. public static function instance() {
  8. // if the instance already exists, use it
  9. if ( isset( self::$instance ) && self::$instance instanceof QSOT_Ticket_Product )
  10. return self::$instance;
  11. // otherwise, start a new instance
  12. return self::$instance = new QSOT_Ticket_Product();
  13. }
  14. // constructor. handles instance setup, and multi instance prevention
  15. public function __construct() {
  16. // if there is already an instance of this object, then bail now
  17. if ( isset( self::$instance ) && self::$instance instanceof QSOT_Ticket_Product )
  18. throw new Exception( sprintf( __( 'There can only be one instance of the %s object at a time.', 'opentickets-community-edition' ), __CLASS__ ), 12000 );
  19. // otherwise, set this as the known instance
  20. self::$instance = $this;
  21. // and call the intialization function
  22. $this->initialize();
  23. }
  24. // destructor. handles instance destruction
  25. public function __destruct() {
  26. $this->deinitialize();
  27. }
  28. // initialize the object. maybe add actions and filters
  29. public function initialize() {
  30. // register the assets that may be used by this class
  31. add_action( 'init', array( &$this, 'register_assets' ), 100 );
  32. // add our filters that modify the cart and order item metas for the basic ticket information
  33. add_filter( 'qsot-ticket-item-meta-keys', array( &$this, 'meta_keys_maintained' ), 10, 1 );
  34. add_filter( 'qsot-ticket-item-hidden-meta-keys', array( &$this, 'meta_keys_hidden' ), 10, 1 );
  35. // fetch a complete list of all products that are tickets
  36. add_filter( 'qsot-get-all-ticket-products', array( &$this, 'get_all_ticket_products' ), 100, 2 );
  37. // run
  38. add_filter( 'qsot-price-formatted', array( &$this, 'formatted_price' ), 10, 1 );
  39. // add the 'ticket' production option (next to 'virtual' and 'downloadable'), and handle the saving of that value
  40. add_filter( 'product_type_options', array( &$this, 'add_ticket_product_type_option' ), 999 );
  41. add_action( 'woocommerce_process_product_meta', array( &$this, 'save_product_meta' ), 999, 2 );
  42. add_filter( 'qsot-item-is-ticket', array( &$this, 'item_is_ticket' ), 10, 2 );
  43. // ticket products do not need processing, so they can skip straight to completed
  44. add_action( 'woocommerce_order_item_needs_processing', array( &$this, 'tickets_dont_need_processing' ), 10, 3 );
  45. // add the admin ajax handler
  46. $aj = QSOT_Ajax::instance();
  47. $aj->register( 'update-order-items', array( &$this, 'admin_ajax_update_order_items' ), array( 'edit_shop_orders' ), null, 'qsot-admin-ajax' );
  48. }
  49. // deinitialize the object. remove actions and filter
  50. public function deinitialize() {
  51. remove_filter( 'qsot-ticket-item-meta-keys', array( &$this, 'meta_keys_maintained' ), 10 );
  52. remove_filter( 'qsot-ticket-item-hidden-meta-keys', array( &$this, 'meta_keys_hidden' ), 10 );
  53. remove_filter( 'qsot-get-all-ticket-products', array( &$this, 'get_all_ticket_products' ), 100 );
  54. remove_filter( 'qsot-price-formatted', array( &$this, 'formatted_price' ), 10 );
  55. remove_filter( 'product_type_options', array( &$this, 'remove_ticket_product_type_option' ), 999 );
  56. remove_action( 'woocommerce_process_product_meta', array( &$this, 'save_product_meta' ), 999 );
  57. remove_filter( 'qsot-item-is-ticket', array( &$this, 'item_is_ticket' ), 10 );
  58. remove_action( 'woocommerce_order_item_needs_processing', array( &$this, 'tickets_dont_need_processing' ), 10 );
  59. }
  60. // register the assets we might use
  61. public function register_assets() {
  62. // initialize the reusabel data
  63. $url = QSOT::plugin_url();
  64. $version = QSOT::version();
  65. }
  66. // add meta keys that should be maintained in the cart and saved into order items
  67. public function meta_keys_maintained( $list ) {
  68. $list[] = 'event_id';
  69. return $list;
  70. }
  71. // add meta keys that should be hidden on order item display
  72. public function meta_keys_hidden( $list ) {
  73. $list[] = '_event_id';
  74. return $list;
  75. }
  76. // fetch a list of all ticket products, and add their various pricing metas to the result
  77. public static function get_all_ticket_products( $list, $format='objects' ) {
  78. // args used in the get_post() method to find all ticket products
  79. $args = array(
  80. 'post_type' => 'product',
  81. 'post_status' => array( 'publish' ),
  82. 'perm' => 'readable',
  83. 'posts_per_page' => -1,
  84. 'orderby' => 'title',
  85. 'order' => 'asc',
  86. 'fields' => 'ids',
  87. 'meta_query' => array(
  88. array(
  89. 'key' => '_ticket',
  90. 'value' => 'yes',
  91. 'compare' => '=',
  92. ),
  93. ),
  94. );
  95. // if the current user can read private posts, then add private post_status
  96. if ( current_user_can( 'read_private_posts' ) )
  97. $args['post_status'][] = 'private';
  98. // get the ids of all the ticket products
  99. $ids = get_posts( $args );
  100. // if we were asked for the ids only, then return them now
  101. if ( 'ids' == $format )
  102. return $ids;
  103. $tickets = array();
  104. // otherwise load all the ticket products, and meta, into an array we will return
  105. foreach ( $ids as $id ) {
  106. // load the product
  107. $ticket = wc_get_product( $id );
  108. // if the product is not loaded, or is an error, then bail
  109. if ( ! is_object( $ticket ) || is_wp_error( $ticket ) )
  110. continue;
  111. // add some of the basic meta for pricing
  112. $ticket->post->meta = array();
  113. $ticket->post->meta['price_raw'] = $ticket->price;
  114. $ticket->post->meta['price_html'] = wc_price($ticket->post->meta['price_raw']);
  115. $ticket->post->meta['price'] = apply_filters('qsot-price-formatted', $ticket->post->meta['price_raw']);
  116. // shorthand the propername of the ticket, so we dont have to keep doing it
  117. $ticket->post->proper_name = apply_filters( 'the_title', $ticket->get_title(), $ticket->id );
  118. // add the ticket to the indexed return list
  119. $tickets[ '' . $ticket->post->ID ] = $ticket;
  120. }
  121. return $tickets;
  122. }
  123. // non-html-element version of the formatted price. will still contain entities
  124. public static function formatted_price($price) {
  125. return strip_tags( wc_price( $price ) );
  126. }
  127. // add the product option that allows the admin to define a product as a ticket
  128. public static function add_ticket_product_type_option( $list ) {
  129. $list['ticket'] = array(
  130. 'id' => '_ticket',
  131. 'wrapper_class' => 'show_if_simple',
  132. 'label' => __( 'Ticket', 'opentickets-community-edition' ),
  133. 'description' => __( 'Allows this product to be assigned as a ticket, when configuring pricing for an event.', 'opentickets-community-edition' ),
  134. );
  135. return $list;
  136. }
  137. // save the meta that designates a product as a ticket
  138. public static function save_product_meta( $post_id, $post ) {
  139. // figure out the appropriate value to save
  140. $is_ticket = isset( $_POST['_ticket'] ) ? 'yes' : 'no';
  141. // update the value in the database
  142. update_post_meta( $post_id, '_ticket', $is_ticket );
  143. // all ticket products should be hidden from the frontend shop. they should only be purchaseable via the ticket selection UI, because otherwise no event will be associated with it
  144. if ( $is_ticket == 'yes' )
  145. update_post_meta( $post_id, '_visibility', 'hidden' );
  146. }
  147. // determine if the item is a ticket product or not
  148. public static function item_is_ticket( $is, $item ) {
  149. // determine if the needed data is set or not
  150. if ( ! isset( $item['product_id'] ) || ( ! isset( $item['qty'] ) && ! isset( $item['quantity'] ) ) )
  151. return false;
  152. // determine if the product is a ticket or not
  153. $ticket = get_post_meta( $item['product_id'], '_ticket', true );
  154. return $ticket == 'yes';
  155. }
  156. // when tickets are purchased, they do not need to be 'processing'. thus, if the order is for only tickets, the order should go straight to completed after payment is received
  157. public static function tickets_dont_need_processing( $needs, $product, $order_id ) {
  158. if ( get_post_meta( $product->id, '_ticket', true ) == 'yes' )
  159. $needs = false;
  160. return $needs;
  161. }
  162. // handle the admin ajax request to refresh the order items list
  163. public static function admin_ajax_update_order_items( $resp, $event ) {
  164. // load the order
  165. $order = wc_get_order( isset( $_POST['order_id'] ) ? (int) $_POST['order_id'] : 0 );
  166. // if there is no order, then bail
  167. if ( ! is_object( $order ) || is_wp_error( $order ) ) {
  168. $resp['s'] = false;
  169. $resp['e'][] = __( 'Invalid order number.', 'opentickets-community-edition' );
  170. return $resp;
  171. }
  172. // setup our response
  173. $resp['s'] = true;
  174. $resp['i'] = array();
  175. // start capturing the output for this item
  176. ob_start();
  177. // cycle through the items that should be displayed, and display them
  178. foreach ( $order->get_items( array( 'line_item', 'fee', 'shipping', 'tax' ) ) as $item_id => $item ) {
  179. // determine the classes to add to the line item tr element
  180. $class = apply_filters( 'woocommerce_admin_order_items_class', 'new_row', $item, $order );
  181. // do something different for each item type
  182. switch ($item['type']) {
  183. // products
  184. case 'line_item' :
  185. $_product = $order->get_product_from_item($item);
  186. $template = QSOT_Templates::locate_woo_template( 'meta-boxes/views/html-order-item.php', 'admin' );
  187. if ( $template )
  188. include( $template );
  189. break;
  190. // fees
  191. case 'fee' :
  192. $template = QSOT_Templates::locate_woo_template( 'meta-boxes/views/html-order-fee.php', 'admin' );
  193. if ( $template )
  194. include( $template );
  195. break;
  196. // shipping charges
  197. case 'shipping' :
  198. $template = QSOT_Templates::locate_woo_template( 'meta-boxes/views/html-order-shipping.php', 'admin' );
  199. if ( $template )
  200. include( $template );
  201. break;
  202. // taxes
  203. case 'tax' :
  204. $template = QSOT_Templates::locate_woo_template( 'meta-boxes/views/html-order-tax.php', 'admin' );
  205. if ( $template )
  206. include( $template );
  207. break;
  208. }
  209. // add the filter that the core WC plugin would normally add after rendering this item
  210. do_action( 'woocommerce_order_item_' . $item['type'] . '_html');
  211. // grab the output of this item and store it in our response
  212. $resp['i'][] = ob_get_contents();
  213. ob_clean();
  214. }
  215. // end capturing
  216. ob_end_clean();
  217. return $resp;
  218. }
  219. }
  220. if ( defined( 'ABSPATH' ) && function_exists( 'add_action' ) )
  221. QSOT_Ticket_Product::instance();