PluginProbe
Tutor LMS – eLearning and online course solution / 3.4.2
Tutor LMS – eLearning and online course solution v3.4.2
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 All 191 releases
← All changes | classes/WooCommerce.php +34 -411 trunk3.4.2 View file →
@@ -9,14 +9,12 @@
9 9 */
10 10
11 11 namespace TUTOR;
12 12
13 -defined( 'ABSPATH' ) || exit;
13 +if ( ! defined( 'ABSPATH' ) ) {
14 + exit;
15 +}
14 16
15 -use Tutor\Helpers\QueryHelper;
16 -use Tutor\Helpers\UrlHelper;
17 -use Tutor\Models\EnrollmentModel;
18 -
19 17 /**
20 18 * Handle woocommerce hooks
21 19 *
22 20 * @since 1.0.0
@@ -22,13 +20,11 @@
22 20 * @since 1.0.0
23 21 */
24 22 class WooCommerce extends Tutor_Base {
25 23
26 - const MONETIZE_BY = 'wc';
27 24
28 - const TUTOR_WC_GUEST_CUSTOMER_ID = '_tutor_wc_guest_customer_id';
29 - const WC_STORE_API_DRAFT_ORDER = 'store_api_draft_order';
30 - const TUTOR_COURSE_PRODUCT_ID_META = '_tutor_course_product_id';
25 + const TUTOR_WC_GUEST_CUSTOMER_ID = '_tutor_wc_guest_customer_id';
26 + const WC_STORE_API_DRAFT_ORDER = 'store_api_draft_order';
31 27
32 28 /**
33 29 * Register hooks
34 30 *
@@ -65,9 +61,8 @@
65 61 * After place new order
66 62 */
67 63 add_action( 'woocommerce_new_order', array( $this, 'course_placing_order_from_admin' ), 10, 3 );
68 64 add_action( 'woocommerce_new_order_item', array( $this, 'course_placing_order_from_customer' ), 10, 3 );
69 - add_action( 'woocommerce_order_status_changed', array( $this, 'handle_customer_order_by_block_checkout' ), 9, 3 );
70 65
71 66 /**
72 67 * Order Status Hook
73 68 *
@@ -95,11 +90,10 @@
95 90 * Manage WooCommerce plugin dependency
96 91 *
97 92 * @since 1.7.8
98 93 */
99 - $woocommerce_path = WP_PLUGIN_DIR . '/woocommerce/woocommerce.php';
94 + $woocommerce_path = dirname( dirname( __DIR__ ) ) . DIRECTORY_SEPARATOR . 'woocommerce' . DIRECTORY_SEPARATOR . 'woocommerce.php';
100 95 register_deactivation_hook( $woocommerce_path, array( $this, 'woocommerce_deactivation_handler' ) );
101 -
102 96 /**
103 97 * Redirect student on enrolled courses after course
104 98 * Enrollment complete
105 99 *
@@ -124,77 +118,11 @@
124 118
125 119 add_action( 'woocommerce_order_after_calculate_totals', array( $this, 'add_coupon_to_order' ), 10, 2 );
126 120
127 121 add_action( 'woocommerce_guest_session_to_user_id', array( $this, 'enroll_guest_user' ), 10, 2 );
128 -
129 - add_filter( 'woocommerce_shortcode_products_query_results', array( $this, 'filter_products_query_results' ), 10, 2 );
130 -
131 - add_filter( 'woocommerce_shortcode_products_query', array( $this, 'filter_tutor_course_products' ) );
132 -
133 - // @since 4.0.0
134 - add_filter( 'tutor_order_history_card_template', fn( $template ) => tutor_get_template( 'dashboard.account.billing.wc-order-history-card' ) );
135 - add_filter( 'tutor_order_history_status_options', array( $this, 'filter_order_history_status_options' ), 10, 2 );
136 - add_filter( 'tutor_get_orders_by_user_id', array( $this, 'filter_tutor_get_orders_by_user_id' ), 10, 3 );
137 122 }
138 123
139 124 /**
140 - * Filter tutor courses from shortcode shop page if enabled.
141 - *
142 - * @since 3.6.2
143 - *
144 - * @param array $query_args the query args.
145 - *
146 - * @return array
147 - */
148 - public function filter_tutor_course_products( $query_args ) {
149 - $hide_course_from_shop_page = (bool) get_tutor_option( 'hide_course_from_shop_page' );
150 -
151 - if ( ! $hide_course_from_shop_page ) {
152 - return $query_args;
153 - }
154 -
155 - $course_ids = ( new Course() )->get_connected_wc_product_ids();
156 -
157 - $query_args['post__not_in'] = $course_ids;
158 -
159 - return $query_args;
160 - }
161 -
162 - /**
163 - * Filter woocommerce shop query result to remove scheduled posts.
164 - *
165 - * @since 3.6.2
166 - *
167 - * @param \WP_Query $results the query result object.
168 - * @param object $wc_shortcode_products_obj the shortcode product class object.
169 - *
170 - * @return array
171 - */
172 - public function filter_products_query_results( $results, $wc_shortcode_products_obj ) {
173 - $ids = $results->ids ?? array();
174 -
175 - if ( $ids ) {
176 - $filtered_ids = array_filter(
177 - $ids,
178 - function ( $val ) {
179 - $course_id = (int) $this->get_post_id_by_meta_key_and_value( self::TUTOR_COURSE_PRODUCT_ID_META, $val );
180 - if ( ! $course_id ) {
181 - return true;
182 - }
183 -
184 - if ( $course_id && 'future' !== get_post_status( $course_id ) ) {
185 - return true;
186 - }
187 - }
188 - );
189 -
190 - $results->ids = $filtered_ids;
191 - }
192 -
193 - return $results;
194 - }
195 -
196 - /**
197 125 * Enroll students to course after guest checkout.
198 126 *
199 127 * @since 3.2.0
200 128 *
@@ -215,15 +143,10 @@
215 143
216 144 $order_id = WC()->session->get( self::WC_STORE_API_DRAFT_ORDER, 0 );
217 145
218 146 if ( $course_ids && $order_id ) {
219 - $wc_order = wc_get_order( $order_id );
220 - if ( ! $wc_order ) {
221 - return;
222 - }
223 -
224 147 foreach ( $course_ids as $course_id ) {
225 - EnrollmentModel::do_enroll( $course_id, $order_id, $customer_id );
148 + tutor_utils()->do_enroll( $course_id, $order_id, $customer_id );
226 149 }
227 150 }
228 151 }
229 152
@@ -568,13 +491,9 @@
568 491 // Invoke enrolled hook.
569 492 if ( 'completed' === $status_to ) {
570 493 $user_id = get_post_field( 'post_author', $enrolled_id );
571 494 $course_id = get_post_field( 'post_parent', $enrolled_id );
572 -
573 - $should_fire_hook = apply_filters( 'tutor_should_fire_after_enrolled_for_wc_order', true, $order_id, $enrolled_id );
574 - if ( $should_fire_hook ) {
575 - do_action( 'tutor_after_enrolled', $course_id, $user_id, $enrolled_id );
576 - }
495 + do_action( 'tutor_after_enrolled', $course_id, $user_id, $enrolled_id );
577 496 }
578 497 }
579 498 }
580 499 }
@@ -591,9 +510,9 @@
591 510 */
592 511 public function tutor_monetization_options( $arr ) {
593 512 $has_wc = tutor_utils()->has_wc();
594 513 if ( $has_wc ) {
595 - $arr[ self::MONETIZE_BY ] = __( 'WooCommerce', 'tutor' );
514 + $arr['wc'] = __( 'WooCommerce', 'tutor' );
596 515 }
597 516 return $arr;
598 517 }
599 518
@@ -614,34 +533,13 @@
614 533
615 534 global $wpdb;
616 535 $item = new \WC_Order_Item_Product( $item );
617 536
618 - $product_id = $item->get_product_id();
619 - $order = wc_get_order( $order_id );
620 - if ( ! $order ) {
621 - return;
622 - }
623 -
624 - /**
625 - * Prevent adding earning data when order is created with WC block checkout page.
626 - *
627 - * @since 3.9.14
628 - *
629 - * @since 4.0.5 Check session before using $order->has_status
630 - */
631 - if ( WC()->session && $order->has_status( 'checkout-draft' ) ) {
632 - return;
633 - }
634 -
635 - $order_type = $order->get_type();
636 -
637 - if ( 'shop_subscription' === $order_type ) {
638 - return;
639 - }
640 -
537 + $product_id = $item->get_product_id();
641 538 $if_has_course = tutor_utils()->product_belongs_with_course( $product_id );
642 539
643 - if ( $if_has_course && is_object( $order ) ) {
540 + if ( $if_has_course ) {
541 + $order = wc_get_order( $order_id );
644 542 $course_id = $if_has_course->post_id;
645 543 $user_id = get_post_field( 'post_author', $course_id );
646 544 $order_status = "wc-{$order->get_status()}";
647 545
@@ -733,136 +631,53 @@
733 631 $if_has_course = tutor_utils()->product_belongs_with_course( $product_id );
734 632 if ( $if_has_course ) {
735 633 $course_id = $if_has_course->post_id;
736 634 $customer_id = $order->get_customer_id();
737 - EnrollmentModel::do_enroll( $course_id, $order_id, $customer_id );
635 + tutor_utils()->do_enroll( $course_id, $order_id, $customer_id );
738 636 }
739 637 }
740 638 }
741 639
742 640 /**
743 - * Handle checkout order item.
641 + * Course placing order from customer
744 642 *
745 - * @since 3.9.14
643 + * @since 1.6.7
746 644 *
747 - * @param object $order the order object.
748 - * @param object $item the order item object.
749 - * @param string $context the context of checkout page.
645 + * @param int $item_id item id.
646 + * @param mixed $item order item.
647 + * @param int $order_id wc order id.
750 648 *
751 649 * @return void
752 650 */
753 - private function handle_checkout_order_item( $order, $item, $context = 'classic_checkout' ) {
754 - if ( ! $order instanceof \WC_Order || ! $item instanceof \WC_Order_Item_Product ) {
651 + public function course_placing_order_from_customer( $item_id, $item, $order_id ) {
652 + if ( is_admin() ) {
755 653 return;
756 654 }
757 655
758 - $order_id = $order->get_id();
759 - $is_gift_item = apply_filters( 'tutor_is_gift_item', false, $item );
760 - if ( $is_gift_item ) {
761 - return;
762 - }
763 -
656 + $item = new \WC_Order_Item_Product( $item );
764 657 $product_id = $item->get_product_id();
765 658 $if_has_course = tutor_utils()->product_belongs_with_course( $product_id );
766 659
767 660 if ( $if_has_course ) {
768 - $should_process = apply_filters( 'tutor_wc_should_process_checkout_order_item', true, $item, $order );
769 - if ( ! $should_process ) {
770 - return;
771 - }
661 + $order = wc_get_order( $order_id );
772 662
663 + /**
664 + * Get customer ID from from order
665 + *
666 + * @since 2.1.7
667 + */
668 + $customer_id = $order->get_customer_id();
773 669 $course_id = $if_has_course->post_id;
774 - $customer_id = $order->get_customer_id();
775 -
776 - // Handle course enrollment.
777 - if ( ! $customer_id && WC()->session && WC()->session->has_session() ) {
670 + if ( ! $customer_id && WC()->session->has_session() ) {
778 671 $guest_customer_id = WC()->session->get_customer_unique_id();
779 672 update_post_meta( $course_id, self::TUTOR_WC_GUEST_CUSTOMER_ID, $guest_customer_id );
780 - } else {
781 - $has_enrollment = tutor_utils()->is_enrolled( $course_id, $customer_id, true );
782 - if ( ! $has_enrollment ) {
783 - tutor_utils()->do_enroll( $course_id, $order_id, $customer_id );
784 - }
673 + return;
785 674 }
786 -
787 - if ( 'block_checkout' === $context ) {
788 - $this->add_earning_data( $item->get_id(), $item, $order_id );
789 - }
675 + tutor_utils()->do_enroll( $course_id, $order_id, $customer_id );
790 676 }
791 677 }
792 678
793 -
794 679 /**
795 - * Course placing order from customer
796 - *
797 - * @since 1.6.7
798 - * @since 3.8.0 Filter hook: tutor_is_gift_item added
799 - * @since 4.0.0 Filter hook: tutor_wc_should_process_checkout_order_item added
800 - * Prevent duplicate enrollment on checkout.
801 - *
802 - * @param int $item_id item id.
803 - * @param mixed $item order item.
804 - * @param int $order_id wc order id.
805 - *
806 - * @return void
807 - */
808 - public function course_placing_order_from_customer( $item_id, $item, $order_id ) {
809 -
810 - if ( is_admin() ) {
811 - return;
812 - }
813 -
814 - $order = wc_get_order( $order_id );
815 - if ( ! $order ) {
816 - return;
817 - }
818 -
819 - /**
820 - * Prevent when order is created with WC block checkout page.
821 - *
822 - * @since 3.9.14
823 - *
824 - * @since 4.0.5 Check session before using $order->has_status
825 - */
826 - if ( WC()->session && $order->has_status( 'checkout-draft' ) ) {
827 - return;
828 - }
829 -
830 - $this->handle_checkout_order_item( $order, $item, 'classic_checkout' );
831 - }
832 -
833 - /**
834 - * Handle order status change by block checkout page.
835 - *
836 - * @since 3.9.14
837 - *
838 - * @param int $order_id WooCommerce order ID.
839 - * @param string $status_from Previous order status.
840 - * @param string $status_to New order status.
841 - *
842 - * @return void
843 - */
844 - public function handle_customer_order_by_block_checkout( $order_id, $status_from, $status_to ) {
845 - if ( 'checkout-draft' !== $status_from ) {
846 - return;
847 - }
848 -
849 - // If transitioning to another draft or invalid status, do nothing.
850 - if ( in_array( $status_to, array( 'checkout-draft', 'draft' ), true ) ) {
851 - return;
852 - }
853 -
854 - $order = wc_get_order( $order_id );
855 - if ( ! $order ) {
856 - return;
857 - }
858 -
859 - foreach ( $order->get_items() as $item ) {
860 - $this->handle_checkout_order_item( $order, $item, 'block_checkout' );
861 - }
862 - }
863 -
864 - /**
865 680 * Handle disabling WooCommerce monetization on WooCommerce plugin deactivation
866 681 *
867 682 * @since 1.7.8
868 683 *
@@ -876,9 +691,9 @@
876 691 * monetize courses after re-activating WooCommerce:
877 692 *
878 693 * Possible follow-up fix: Only show a notice when
879 694 * WooCommerce was re-activated after this forced
880 - * disabling of WooCommerce monetization took place:
695 + * disabling of WooCommerce monetisation took place:
881 696 */
882 697 update_option( 'tutor_show_woocommerce_notice', true );
883 698 }
884 699 }
@@ -901,9 +716,9 @@
901 716
902 717 // get woo order details.
903 718 $order = wc_get_order( $order_id );
904 719 $tutor_product = false;
905 - $url = tutor_utils()->tutor_dashboard_url() . 'courses/';
720 + $url = tutor_utils()->tutor_dashboard_url() . 'enrolled-courses/';
906 721
907 722 /**
908 723 * Loop though each WC order item.
909 724 *
@@ -1025,198 +840,6 @@
1025 840 }
1026 841
1027 842 return $auto_complete;
1028 843 }
844 +}
1029 845
1030 - /**
1031 - * Count orders for a user.
1032 - *
1033 - * @since 4.0.0
1034 - *
1035 - * @param array $args array of arguments.
1036 - *
1037 - * @return int return count of orders.
1038 - */
1039 - public static function get_count( $args = array() ): int {
1040 - $query = wc_get_orders(
1041 - array(
1042 - 'customer' => $args['user_id'] ?? 0,
1043 - 'status' => $args['status'] ?? 'all',
1044 - 'date_created' => $args['date_created'] ?? null,
1045 - 'meta_query' => array(
1046 - array(
1047 - 'key' => '_is_tutor_order_for_course',
1048 - 'compare' => 'EXISTS',
1049 - ),
1050 - ),
1051 - // Limit 1 for query performance.
1052 - 'limit' => 1,
1053 - 'paginate' => true,
1054 - )
1055 - );
1056 -
1057 - return $query->total;
1058 - }
1059 -
1060 - /**
1061 - * Filter order history status options.
1062 - *
1063 - * @since 4.0.0
1064 - *
1065 - * @param array $options the status options.
1066 - * @param string $seleted the selected status.
1067 - *
1068 - * @return array<array{label: string, value: string, count: int, url: string, active: bool}>
1069 - */
1070 - public function filter_order_history_status_options( $options, $seleted ) {
1071 - $url = get_pagenum_link();
1072 - $user_id = get_current_user_id();
1073 -
1074 - $statuses = array_merge( array( 'all' => 'All' ), wc_get_order_statuses() );
1075 - if ( isset( $statuses['wc-checkout-draft'] ) ) {
1076 - unset( $statuses['wc-checkout-draft'] );
1077 - }
1078 -
1079 - $start_date = Input::get( 'start_date' );
1080 - $end_date = Input::get( 'end_date' );
1081 -
1082 - $options = array();
1083 -
1084 - foreach ( $statuses as $key => $status ) {
1085 - $params = array(
1086 - 'user_id' => $user_id,
1087 - 'status' => $key,
1088 - );
1089 -
1090 - if ( ! empty( $start_date ) && ! empty( $end_date ) ) {
1091 - $params['date_created'] = $start_date . '...' . $end_date;
1092 - }
1093 -
1094 - $options[] = array(
1095 - 'label' => $status,
1096 - 'value' => $key,
1097 - 'count' => self::get_count( $params ),
1098 - 'url' => UrlHelper::add_query_params( $url, array( 'data' => $key ) ),
1099 - 'active' => $key === $seleted || ( empty( $key ) && 'all' === $seleted ),
1100 - );
1101 - }
1102 -
1103 - return $options;
1104 - }
1105 -
1106 - /**
1107 - * Filter tutor get orders by user id.
1108 - *
1109 - * @since 4.0.0
1110 - *
1111 - * @param object $data data.
1112 - * @param int $user_id user id.
1113 - * @param array $args array of arguments.
1114 - *
1115 - * @return object {results: array, total_count: int}
1116 - */
1117 - public function filter_tutor_get_orders_by_user_id( $data, $user_id, $args ) {
1118 - if ( ! $user_id ) {
1119 - return $data;
1120 - }
1121 -
1122 - global $wpdb;
1123 -
1124 - $period = Input::sanitize( $args['period'] ?? '' );
1125 - $status = Input::sanitize( $args['status'] ?? 'all' );
1126 - $start_date = Input::sanitize( $args['start_date'] ?? '' );
1127 - $end_date = Input::sanitize( $args['end_date'] ?? '' );
1128 - $order = QueryHelper::get_valid_sort_order( $args['order'] ?? 'DESC' );
1129 - $limit = intval( $args['limit'] ?? 0 );
1130 - $offset = intval( $args['offset'] ?? 0 );
1131 -
1132 - $post_type = 'shop_order';
1133 - $user_meta = '_customer_user';
1134 - $wc_hpos = self::hpos_enabled();
1135 - $dt_column = $wc_hpos ? 'date_created_gmt' : 'post_date';
1136 -
1137 - $period_query = '';
1138 - if ( ! empty( $period ) ) {
1139 - if ( 'today' === $period ) {
1140 - $period_query = ' AND DATE(' . $dt_column . ') = CURDATE() ';
1141 - } elseif ( 'monthly' === $period ) {
1142 - $period_query = ' AND MONTH(' . $dt_column . ') = MONTH(CURDATE()) ';
1143 - } else {
1144 - $period_query = ' AND YEAR(' . $dt_column . ') = YEAR(CURDATE()) ';
1145 - }
1146 - }
1147 -
1148 - if ( ! empty( $start_date ) && ! empty( $end_date ) ) {
1149 - $period_query = $wpdb->prepare(
1150 - //phpcs:ignore -- $dt_column is static value
1151 - " AND DATE($dt_column) BETWEEN CAST(%s AS DATE) AND CAST(%s AS DATE) ",
1152 - $start_date,
1153 - $end_date
1154 - );
1155 - }
1156 -
1157 - $offset_limit_query = '';
1158 - if ( $offset && $limit ) {
1159 - $offset_limit_query = "LIMIT {$offset}, {$limit}";
1160 - }
1161 -
1162 - $status_query = '';
1163 - if ( 'all' !== $status ) {
1164 - $status_query = $wc_hpos
1165 - ? $wpdb->prepare( 'AND status = %s', $status )
1166 - : $wpdb->prepare( 'AND post_status = %s', $status );
1167 - }
1168 -
1169 - if ( $wc_hpos ) {
1170 - //phpcs:disable
1171 - $results = $wpdb->get_results(
1172 - $wpdb->prepare(
1173 - "SELECT SQL_CALC_FOUND_ROWS orders.id AS ID, orders.status AS post_status, orders.date_created_gmt AS post_date, orders.*
1174 - FROM {$wpdb->prefix}wc_orders orders
1175 - INNER JOIN {$wpdb->prefix}wc_orders_meta order_meta
1176 - ON orders.id = order_meta.order_id
1177 - AND order_meta.meta_key = '_is_tutor_order_for_course'
1178 - WHERE orders.type = %s
1179 - AND orders.customer_id = %d
1180 - {$status_query}
1181 - {$period_query}
1182 - ORDER BY orders.id {$order}
1183 - {$offset_limit_query}",
1184 - $post_type,
1185 - $user_id
1186 - )
1187 - );
1188 - //phpcs:enable
1189 - } else {
1190 - //phpcs:disable
1191 - $results = $wpdb->get_results(
1192 - $wpdb->prepare(
1193 - "SELECT SQL_CALC_FOUND_ROWS {$wpdb->posts}.*
1194 - FROM {$wpdb->posts}
1195 - INNER JOIN {$wpdb->postmeta} customer
1196 - ON id = customer.post_id
1197 - AND customer.meta_key = '{$user_meta}'
1198 - INNER JOIN {$wpdb->postmeta} tutor_order
1199 - ON id = tutor_order.post_id
1200 - AND tutor_order.meta_key = '_is_tutor_order_for_course'
1201 - WHERE post_type = %s
1202 - AND customer.meta_value = %d
1203 - {$status_query}
1204 - {$period_query}
1205 - ORDER BY {$wpdb->posts}.id {$order}
1206 - {$offset_limit_query}
1207 - ",
1208 - $post_type,
1209 - $user_id
1210 - )
1211 - );
1212 - //phpcs:enable
1213 - }
1214 -
1215 - $total_count = (int) $wpdb->get_var( 'SELECT FOUND_ROWS()' );
1216 -
1217 - $data->results = $results;
1218 - $data->total_count = $total_count;
1219 -
1220 - return $data;
1221 - }
1222 -}