diff --git a/adminpages/orders.php b/adminpages/orders.php index e24227f55b..59da933fed 100644 --- a/adminpages/orders.php +++ b/adminpages/orders.php @@ -9,151 +9,6 @@ $now = current_time( 'timestamp' ); -if ( isset( $_REQUEST['s'] ) ) { - $s = trim( sanitize_text_field( $_REQUEST['s'] ) ); -} else { - $s = ''; -} - -if ( isset( $_REQUEST['l'] ) ) { - $l = intval( $_REQUEST['l'] ); -} else { - $l = false; -} - -if ( isset( $_REQUEST['discount-code'] ) ) { - $discount_code = intval( $_REQUEST['discount-code'] ); -} else { - $discount_code = false; -} - -if ( isset( $_REQUEST['start-month'] ) ) { - $start_month = intval( $_REQUEST['start-month'] ); -} else { - $start_month = '1'; -} - -if ( isset( $_REQUEST['start-day'] ) ) { - $start_day = intval( $_REQUEST['start-day'] ); -} else { - $start_day = '1'; -} - -if ( isset( $_REQUEST['start-year'] ) ) { - $start_year = intval( $_REQUEST['start-year'] ); -} else { - $start_year = date( 'Y', $now ); -} - -if ( isset( $_REQUEST['end-month'] ) ) { - $end_month = intval( $_REQUEST['end-month'] ); -} else { - $end_month = date( 'n', $now ); -} - -if ( isset( $_REQUEST['end-day'] ) ) { - $end_day = intval( $_REQUEST['end-day'] ); -} else { - $end_day = date( 'j', $now ); -} - -if ( isset( $_REQUEST['end-year'] ) ) { - $end_year = intval( $_REQUEST['end-year'] ); -} else { - $end_year = date( 'Y', $now ); -} - -if ( isset( $_REQUEST['predefined-date'] ) ) { - $predefined_date = sanitize_text_field( $_REQUEST['predefined-date'] ); -} else { - $predefined_date = 'This Month'; -} - -if ( isset( $_REQUEST['status'] ) ) { - $status = sanitize_text_field( $_REQUEST['status'] ); -} else { - $status = ''; -} - -if ( isset( $_REQUEST['filter'] ) ) { - $filter = sanitize_text_field( $_REQUEST['filter'] ); -} else { - $filter = 'all'; -} - -// some vars for the search -if ( isset( $_REQUEST['pn'] ) ) { - $pn = intval( $_REQUEST['pn'] ); -} else { - $pn = 1; -} - -if ( isset( $_REQUEST['limit'] ) ) { - $limit = intval( $_REQUEST['limit'] ); -} else { - /** - * Filter to set the default number of items to show per page - * on the Orders page in the admin. - * - * @since 1.8.4.5 - * - * @param int $limit The number of items to show per page. - */ - $limit = apply_filters( 'pmpro_orders_per_page', 15 ); -} - -$end = $pn * $limit; -$start = $end - $limit; - -// filters -if ( empty( $filter ) || $filter === 'all' ) { - $condition = '1=1'; - $filter = 'all'; -} elseif ( $filter == 'within-a-date-range' ) { - $start_date = $start_year . '-' . $start_month . '-' . $start_day; - $end_date = $end_year . '-' . $end_month . '-' . $end_day; - - // add times to dates and localize - $start_date = get_gmt_from_date( $start_date . ' 00:00:00' ); - $end_date = get_gmt_from_date( $end_date . ' 23:59:59' ); - - $condition = "o.timestamp BETWEEN '" . esc_sql( $start_date ) . "' AND '" . esc_sql( $end_date ) . "'"; -} elseif ( $filter == 'predefined-date-range' ) { - if ( $predefined_date == 'Last Month' ) { - $start_date = date( 'Y-m-d', strtotime( 'first day of last month', $now ) ); - $end_date = date( 'Y-m-d', strtotime( 'last day of last month', $now ) ); - } elseif ( $predefined_date == 'This Month' ) { - $start_date = date( 'Y-m-d', strtotime( 'first day of this month', $now ) ); - $end_date = date( 'Y-m-d', strtotime( 'last day of this month', $now ) ); - } elseif ( $predefined_date == 'This Year' ) { - $year = date( 'Y', $now ); - $start_date = date( 'Y-m-d', strtotime( "first day of January $year", $now ) ); - $end_date = date( 'Y-m-d', strtotime( "last day of December $year", $now ) ); - } elseif ( $predefined_date == 'Last Year' ) { - $year = date( 'Y', $now ) - 1; - $start_date = date( 'Y-m-d', strtotime( "first day of January $year", $now ) ); - $end_date = date( 'Y-m-d', strtotime( "last day of December $year", $now ) ); - } - - // add times to dates and localize - $start_date = get_gmt_from_date( $start_date . ' 00:00:00' ); - $end_date = get_gmt_from_date( $end_date . ' 23:59:59' ); - - $condition = "o.timestamp BETWEEN '" . esc_sql( $start_date ) . "' AND '" . esc_sql( $end_date ) . "'"; -} elseif ( $filter == 'within-a-level' ) { - $condition = 'o.membership_id = ' . (int) $l ; -} elseif ( $filter == 'with-discount-code' ) { - $condition = 'dc.code_id = ' . (int) $discount_code; -} elseif ( $filter == 'within-a-status' ) { - $condition = "o.status = '" . esc_sql( $status ) . "' "; -} elseif ( $filter == 'only-paid' ) { - $condition = "o.total > 0"; -} elseif( $filter == 'only-free' ) { - $condition = "o.total = 0"; -} - -$condition = apply_filters( 'pmpro_admin_orders_query_condition', $condition, $filter ); - // deleting? if ( ! empty( $_REQUEST['delete'] ) ) { // Check nonce for deleting. @@ -210,7 +65,8 @@ ); // if this is a new order or copy of one, let's make all fields editable -if ( ! empty( $_REQUEST['order'] ) && $_REQUEST['order'] < 0 ) { +// Checking orderby as order could be the order ID or whether the List Table should be sorted ascending or descending. +if ( ( ! empty( $_REQUEST['order'] ) && $_REQUEST['order'] < 0 ) && ! isset( $_REQUEST['orderby'] ) ) { $read_only_fields = array(); } @@ -352,7 +208,8 @@ } } else { // order passed? - if ( ! empty( $_REQUEST['order'] ) ) { + // Checking orderby as order could be the order ID or whether the List Table should be sorted ascending or descending. + if ( ! empty( $_REQUEST['order'] ) && ! isset( $_REQUEST['orderby'] ) ) { $order_id = intval( $_REQUEST['order'] ); if ( $order_id > 0 ) { $order = new MemberOrder( $order_id ); @@ -1060,18 +917,18 @@ // build the export URL $export_url = admin_url( 'admin-ajax.php?action=orders_csv' ); $url_params = array( - 'filter' => $filter, - 's' => $s, - 'l' => $l, - 'start-month' => $start_month, - 'start-day' => $start_day, - 'start-year' => $start_year, - 'end-month' => $end_month, - 'end-day' => $end_day, - 'end-year' => $end_year, - 'predefined-date' => $predefined_date, - 'discount-code' => $discount_code, - 'status' => $status, + 'filter' => isset( $_REQUEST['filter'] ) ? trim( sanitize_text_field( $_REQUEST['filter'] ) ) : 'all', + 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '', + 'l' => isset( $_REQUEST['l'] ) ? sanitize_text_field( $_REQUEST['l'] ) : false, + 'start-month' => isset( $_REQUEST['start-month'] ) ? intval( $_REQUEST['start-month'] ) : '1', + 'start-day' => isset( $_REQUEST['start-day'] ) ? intval( $_REQUEST['start-day'] ) : '1', + 'start-year' => isset( $_REQUEST['start-year'] ) ? intval( $_REQUEST['start-year'] ) : date( 'Y', $now ), + 'end-month' => isset( $_REQUEST['end-month'] ) ? intval( $_REQUEST['end-month'] ) : date( 'n', $now ), + 'end-day' => isset( $_REQUEST['end-day'] ) ? intval( $_REQUEST['end-day'] ) : date( 'j', $now ), + 'end-year' => isset( $_REQUEST['end-year'] ) ? intval( $_REQUEST['end-year'] ) : date( 'Y', $now ), + 'predefined-date' => isset( $_REQUEST['predefined-date'] ) ? sanitize_text_field( $_REQUEST['predefined-date'] ) : 'This Month', + 'discount-code' => isset( $_REQUEST['discount-code'] ) ? intval( $_REQUEST['discount-code'] ) : false, + 'status' => isset( $_REQUEST['status'] ) ? sanitize_text_field( $_REQUEST['status'] ) : '', ); $export_url = add_query_arg( $url_params, $export_url ); ?> @@ -1087,677 +944,14 @@ } ?> ">

- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - pmpro_discount_codes "; - $sqlQuery .= "ORDER BY id DESC "; - $codes = $wpdb->get_results($sqlQuery, OBJECT); - if ( ! empty( $codes ) ) { ?> - - - - - - - - - - - pmpro_membership_orders o LEFT JOIN $wpdb->users u ON o.user_id = u.ID LEFT JOIN $wpdb->pmpro_membership_levels l ON o.membership_id = l.id "; - - $join_with_usermeta = apply_filters( 'pmpro_orders_search_usermeta', false ); - if ( $join_with_usermeta ) { - $sqlQuery .= "LEFT JOIN $wpdb->usermeta um ON o.user_id = um.user_id "; - } - - if ( $filter === 'with-discount-code' ) { - $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id "; - } - - $sqlQuery .= 'WHERE (1=2 '; + prepare_items(); + $orders_list_table->search_box( __( 'Search Orders', 'paid-memberships-pro' ), 'paid-memberships-pro' ); + $orders_list_table->display(); - $fields = array( - 'o.id', - 'o.code', - 'o.billing_name', - 'o.billing_street', - 'o.billing_city', - 'o.billing_state', - 'o.billing_zip', - 'o.billing_phone', - 'o.payment_type', - 'o.cardtype', - 'o.accountnumber', - 'o.status', - 'o.gateway', - 'o.gateway_environment', - 'o.payment_transaction_id', - 'o.subscription_transaction_id', - 'u.user_login', - 'u.user_email', - 'u.display_name', - 'l.name', - ); - - if ( $join_with_usermeta ) { - $fields[] = 'um.meta_value'; - } - - $fields = apply_filters( 'pmpro_orders_search_fields', $fields ); - - foreach ( $fields as $field ) { - $sqlQuery .= ' OR ' . esc_sql( $field ) . " LIKE '%" . esc_sql( $s ) . "%' "; - } - $sqlQuery .= ') '; - - //Not escaping here because we escape the values in the condition statement - $sqlQuery .= 'AND ' . $condition . ' '; - - $sqlQuery .= 'GROUP BY o.id ORDER BY o.id DESC, o.timestamp DESC '; - } else { - $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS o.id FROM $wpdb->pmpro_membership_orders o "; - - if ( $filter === 'with-discount-code' ) { - $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id "; - } - //Not escaping here because we escape the values in the condition statement - $sqlQuery .= "WHERE " . $condition . ' ORDER BY o.id DESC, o.timestamp DESC '; - } - - $sqlQuery .= "LIMIT " . (int) $start . "," . (int) $limit; - - $order_ids = $wpdb->get_col( $sqlQuery ); - - $totalrows = $wpdb->get_var( 'SELECT FOUND_ROWS() as found_rows' ); - - if ( $order_ids ) { - ?> -
- -
- get_var( "SELECT id FROM $wpdb->pmpro_discount_codes LIMIT 1" ) ) { - $pmpro_discount_codes = true; - } else { - $pmpro_discount_codes = false; - } ?> -
-
- - - - - - - - - - - - - - - - - - - - - nogateway = true; - $order->getMemberOrderByID( $order_id ); - $order->getUser(); - ?> - - - - - - - - - - - - - - - - - - - - - -
- code ); ?> -
- code ) - ) - ); - - $delete_nonce_url = wp_nonce_url( - add_query_arg( - [ - 'page' => 'pmpro-orders', - 'action' => 'delete_order', - 'delete' => $order->id, - ], - admin_url( 'admin.php' ) - ), - 'delete_order', - 'pmpro_orders_nonce' - ); - - $refund_text = esc_html( - sprintf( - // translators: %s is the Order Code. - __( 'Refund order %s at the payment gateway. This action is permanent. The user and admin will receive an email confirmation after the refund is processed. Are you sure you want to refund this order?', 'paid-memberships-pro' ), - str_replace( "'", '', $order->code ) - ) - ); - - $refund_nonce_url = wp_nonce_url( - add_query_arg( - [ - 'page' => 'pmpro-orders', - 'action' => 'refund_order', - 'refund' => $order->id, - ], - admin_url( 'admin.php' ) - ), - 'refund_order', - 'pmpro_orders_nonce' - ); - - $actions = [ - 'id' => sprintf( - // translators: %s is the Order ID. - __( 'ID: %s', 'paid-memberships-pro' ), - esc_attr( $order->id ) - ), - 'edit' => sprintf( - '%3$s', - esc_attr__( 'Edit', 'paid-memberships-pro' ), - esc_url( - add_query_arg( - [ - 'page' => 'pmpro-orders', - 'order' => $order->id, - ], - admin_url( 'admin.php' ) - ) - ), - esc_html__( 'Edit', 'paid-memberships-pro' ) - ), - 'copy' => sprintf( - '%3$s', - esc_attr__( 'Copy', 'paid-memberships-pro' ), - esc_url( - add_query_arg( - [ - 'page' => 'pmpro-orders', - 'order' => - 1, - 'copy' => $order->id, - ], - admin_url( 'admin.php' ) - ) - ), - esc_html__( 'Copy', 'paid-memberships-pro' ) - ), - 'delete' => sprintf( - '%3$s', - esc_attr__( 'Delete', 'paid-memberships-pro' ), - 'javascript:pmpro_askfirst(\'' . esc_js( $delete_text ) . '\', \'' . esc_js( $delete_nonce_url ) . '\'); void(0);', - esc_html__( 'Delete', 'paid-memberships-pro' ) - ), - 'print' => sprintf( - '%3$s', - esc_attr__( 'Print', 'paid-memberships-pro' ), - esc_url( - add_query_arg( - [ - 'action' => 'pmpro_orders_print_view', - 'order' => $order->id, - ], - admin_url( 'admin-ajax.php' ) - ) - ), - esc_html__( 'Print', 'paid-memberships-pro' ) - ), - 'email' => sprintf( - '', - esc_attr__( 'Email', 'paid-memberships-pro' ), - '#TB_inline?width=600&height=200&inlineId=email_invoice', - esc_attr( $order->id ), - esc_html__( 'Email', 'paid-memberships-pro' ) - ), - ]; - - if( pmpro_allowed_refunds( $order ) ) { - $actions['refund'] = sprintf( - '%3$s', - esc_attr__( 'Refund', 'paid-memberships-pro' ), - esc_js( 'javascript:pmpro_askfirst(' . wp_json_encode( $refund_text ) . ', ' . wp_json_encode( $refund_nonce_url ) . '); void(0);' ), - esc_html__( 'Refund', 'paid-memberships-pro' ) - ); - } - - /** - * Filter the extra actions for this user on this order. - * - * @param array $actions The list of actions. - * @param object $user The user data. - * @param MemberOrder $order The current order. - */ - $actions = apply_filters( 'pmpro_orders_user_row_actions', $actions, $order->user, $order ); - - $actions_html = []; - - foreach ( $actions as $action => $link ) { - $actions_html[] = sprintf( - '%2$s', - esc_attr( $action ), - $link - ); - } - - if ( ! empty( $actions_html ) ) { - echo implode( ' | ', $actions_html ); - } - ?> -
-
- getUser(); ?> - user ) ) { ?> - user->user_login ); ?>
- user->user_email ); ?> - user_id > 0 ) { ?> - [] - - [] - -
- membership_id ); - if ( ! empty( $level ) ) { - echo esc_html( $level->name ); - } elseif ( $order->membership_id > 0 ) { ?> - [] - - total ) ); ?> - payment_type ) ) { - if ( in_array( $order->payment_type, array( 'PayPal Standard', 'PayPal Express' ) ) ) { - $r .= esc_html__( 'PayPal', 'paid-memberships-pro' ); - } else { - $r .= esc_html( ucwords( $order->payment_type ) ); - } - $r .= '
'; - } - - if ( ! empty( $order->accountnumber ) ) { - $r .= esc_html( $order->cardtype ) . ': x' . esc_html( last4( $order->accountnumber ) ) . '
'; - } - - if ( ! empty( $order->billing->name ) ) { - $r .= esc_html( $order->billing->name ) . '
'; - } - - if ( ! empty( $order->billing->street ) ) { - $r .= esc_html( $order->billing->street ) . '
'; - } - - if ( $order->billing->city && $order->billing->state ) { - $r .= esc_html( $order->billing->city ) . ', '; - $r .= esc_html( $order->billing->state ) . ' '; - $r .= esc_html( $order->billing->zip ) . ' '; - if ( ! empty( $order->billing->country ) ) { - $r .= esc_html( $order->billing->country ); - } - } - - if ( ! empty( $order->billing->phone ) ) { - $r .= '
' . esc_html( formatPhone( $order->billing->phone ) ); - } - - // If this column is completely empty, set $r to a dash. - if ( empty( $r ) ) { - $r .= esc_html__( '—', 'paid-memberships-pro' ); - } - - // Echo the data for this column. - echo $r; - ?> -
- gateway ) ) { - if ( ! empty( $pmpro_gateways[$order->gateway] ) ) { - echo $pmpro_gateways[$order->gateway]; - } else { - esc_html_e( ucwords( $order->gateway ) ); - } - if ( $order->gateway_environment == 'sandbox' ) { - echo ' (test)'; - } - } else { - esc_html_e( '—', 'paid-memberships-pro' ); - } - ?> - - : - payment_transaction_id ) ) { - echo esc_html( $order->payment_transaction_id ); - } else { - esc_html_e( 'N/A', 'paid-memberships-pro' ); - } - ?> -
- : - subscription_transaction_id ) ) { - echo esc_html( $order->subscription_transaction_id ); - } else { - esc_html_e( 'N/A', 'paid-memberships-pro' ); - } - ?> -
- - status, array( 'success', 'cancelled' ) ) ) { - esc_html_e( 'Paid', 'paid-memberships-pro' ); - } else { - esc_html_e( ucwords( $order->status ) ); - } ?> - - is_renewal() ) { ?> - - - - getTimestamp() ) ), - esc_html( date_i18n( get_option( 'time_format' ), $order->getTimestamp() ) ) - ) ); ?> - - getDiscountCode() ) { ?> - - discount_code->code ); ?> - - -

-
-
- - - - -
-
- -plugin_text_domain = 'paid-memberships-pro'; + + parent::__construct( + array( + 'plural' => 'orders', + // Plural value used for labels and the objects being listed. + 'singular' => 'order', + // Singular label for an object being listed, e.g. 'post'. + 'ajax' => false, + // If true, the parent class will call the _js_vars() method in the footer + ) + ); + } + + /** + * Prepares the list of items for displaying. + * + * Query, filter data, handle sorting, and pagination, and any other data-manipulation required prior to rendering + * + * @since TBD + */ + public function prepare_items() { + + $columns = $this->get_columns(); + $hidden = $this->get_hidden_columns(); + $sortable = $this->get_sortable_columns(); + + $this->_column_headers = array($columns, $hidden, $sortable); + + $items_per_page = $this->get_items_per_page( 'orders_per_page' ); + /** + * Filter to set the default number of items to show per page + * on the Orders page in the admin. + * + * @since 1.8.4.5 + * + * @param int $limit The number of items to show per page. + */ + $items_per_page = apply_filters( 'pmpro_orders_per_page', $items_per_page ); + + $this->items = $this->sql_table_data( false ); + $total_items = $this->sql_table_data( true ); + + $this->set_pagination_args( + array( + 'total_items' => $total_items, + 'per_page' => $items_per_page, + 'total_pages' => ceil( $total_items / $items_per_page ), + ) + ); + + } + + /** + * Get a list of columns. + * + * The format is: 'internal-name' => 'Title' + * + * @since TBD + * + * @return array + */ + public function get_columns() { + + $columns = array( + 'order_id' => __( 'ID', 'paid-memberships-pro' ), + //We cant use 'code' as is because it formats the column as code + 'order_code' => __( 'Code', 'paid-memberships-pro' ), + 'user' => __( 'User', 'paid-memberships-pro' ), + 'level' => __( 'Level', 'paid-memberships-pro' ), + 'total' => __( 'Total', 'paid-memberships-pro' ), + 'billing' => __( 'Billing', 'paid-memberships-pro' ), + 'gateway' => __( 'Gateway', 'paid-memberships-pro' ), + 'transaction_ids' => __( 'Transaction IDs', 'paid-memberships-pro' ), + 'order_status' => __( 'Status', 'paid-memberships-pro' ), + 'date' => __( 'Date', 'paid-memberships-pro' ), + 'discount_code' => __( 'Discount Code', 'paid-memberships-pro' ), + ); + + // Re-implementing old hook, will be deprecated. + ob_start(); + do_action( 'pmpro_orders_extra_cols_header' ); + $extra_cols = ob_get_clean(); + preg_match_all( '/(.*?)<\/th>/s', $extra_cols, $matches ); + $custom_field_num = 0; + foreach ( $matches[1] as $match ) { + $columns[ 'custom_field_' . $custom_field_num ] = $match; + $custom_field_num++; + } + + // Shortcut for editing columns in default discount code list location. + $current_screen = get_current_screen(); + if ( ! empty( $current_screen ) && strpos( $current_screen->id, "pmpro-orders" ) !== false ) { + $columns = apply_filters( 'pmpro_manage_orderslist_columns', $columns ); + } + + + return $columns; + } + + /** + * Define which columns are hidden + * + * @return Array + */ + public function get_hidden_columns() { + + return array(); + + } + + /** + * Get a list of sortable columns. The format is: + * 'internal-name' => 'orderby' + * or + * 'internal-name' => array( 'orderby', true ) + * + * The second format will make the initial sorting order be descending + * + * @since TBD + * + * @return array + */ + protected function get_sortable_columns() { + /** + * actual sorting still needs to be done by prepare_items. + * specify which columns should have the sort icon. + * + * key => value + * column name_in_list_table => columnname in the db + */ + $sortable_columns = array( + 'order_id' => array( 'id', true ), + 'level' => array( 'name', false ), + 'total' => array( 'total', false ), + 'order_status' => array( 'status_label', false ), + 'date' => array( 'timestamp', false ), + ); + return $sortable_columns; + } + + /** + * Text displayed when no user data is available + * + * @since TBD + * + * @return void + */ + public function no_items() { + + esc_html_e( 'No orders found.', 'paid-memberships-pro' ); + + } + + /** + * Get the table data + * + * @return Array|integer if $count parameter = true + */ + private function sql_table_data( $count = false, $limit = 15 ) { + + global $wpdb; + $now = current_time( 'timestamp' ); + + $s = isset( $_REQUEST['s'] ) ? trim( sanitize_text_field( $_REQUEST['s'] ) ) : ''; + $l = isset( $_REQUEST['l'] ) ? intval( $_REQUEST['l'] ) : false; + $discount_code = isset( $_REQUEST['discount-code'] ) ? intval( $_REQUEST['discount-code'] ) : false; + $start_month = isset( $_REQUEST['start-month'] ) ? intval( $_REQUEST['start-month'] ) : '1'; + $start_day = isset( $_REQUEST['start-day'] ) ? intval( $_REQUEST['start-day'] ) : '1'; + $start_year = isset( $_REQUEST['start-year'] ) ? intval( $_REQUEST['start-year'] ) : date( 'Y', $now ); + $end_month = isset( $_REQUEST['end-month'] ) ? intval( $_REQUEST['end-month'] ) : date( 'n', $now ); + $end_day = isset( $_REQUEST['end-day'] ) ? intval( $_REQUEST['end-day'] ) : date( 'j', $now ); + $end_year = isset( $_REQUEST['end-year'] ) ? intval( $_REQUEST['end-year'] ) : date( 'Y', $now ); + $predefined_date = isset( $_REQUEST['predefined-date'] ) ? sanitize_text_field( $_REQUEST['predefined-date'] ) : 'This Month'; + $status = isset( $_REQUEST['status'] ) ? sanitize_text_field( $_REQUEST['status'] ) : ''; + $filter = isset( $_REQUEST['filter'] ) ? sanitize_text_field( $_REQUEST['filter'] ) : 'all'; + $pn = isset( $_REQUEST['paged'] ) ? intval( $_REQUEST['paged'] ) : 1; + + $items_per_page = $this->get_items_per_page( 'orders_per_page' ); + /** + * Filter to set the default number of items to show per page + * on the Orders page in the admin. + * + * @since 1.8.4.5 + * + * @param int $limit The number of items to show per page. + */ + $limit = apply_filters( 'pmpro_orders_per_page', $items_per_page ); + + $end = $pn * $limit; + $start = $end - $limit; + + // filters + if ( empty( $filter ) || $filter === 'all' ) { + $condition = '1=1'; + $filter = 'all'; + } elseif ( $filter == 'within-a-date-range' ) { + $start_date = $start_year . '-' . $start_month . '-' . $start_day; + $end_date = $end_year . '-' . $end_month . '-' . $end_day; + + // add times to dates and localize + $start_date = get_gmt_from_date( $start_date . ' 00:00:00' ); + $end_date = get_gmt_from_date( $end_date . ' 23:59:59' ); + + $condition = "o.timestamp BETWEEN '" . esc_sql( $start_date ) . "' AND '" . esc_sql( $end_date ) . "'"; + } elseif ( $filter == 'predefined-date-range' ) { + if ( $predefined_date == 'Last Month' ) { + $start_date = date( 'Y-m-d', strtotime( 'first day of last month', $now ) ); + $end_date = date( 'Y-m-d', strtotime( 'last day of last month', $now ) ); + } elseif ( $predefined_date == 'This Month' ) { + $start_date = date( 'Y-m-d', strtotime( 'first day of this month', $now ) ); + $end_date = date( 'Y-m-d', strtotime( 'last day of this month', $now ) ); + } elseif ( $predefined_date == 'This Year' ) { + $year = date( 'Y', $now ); + $start_date = date( 'Y-m-d', strtotime( "first day of January $year", $now ) ); + $end_date = date( 'Y-m-d', strtotime( "last day of December $year", $now ) ); + } elseif ( $predefined_date == 'Last Year' ) { + $year = date( 'Y', $now ) - 1; + $start_date = date( 'Y-m-d', strtotime( "first day of January $year", $now ) ); + $end_date = date( 'Y-m-d', strtotime( "last day of December $year", $now ) ); + } + + // add times to dates and localize + $start_date = get_gmt_from_date( $start_date . ' 00:00:00' ); + $end_date = get_gmt_from_date( $end_date . ' 23:59:59' ); + + $condition = "o.timestamp BETWEEN '" . esc_sql( $start_date ) . "' AND '" . esc_sql( $end_date ) . "'"; + } elseif ( $filter == 'within-a-level' ) { + $condition = 'o.membership_id = ' . esc_sql( $l ); + } elseif ( $filter == 'with-discount-code' ) { + $condition = 'dc.code_id = ' . esc_sql( $discount_code ); + } elseif ( $filter == 'within-a-status' ) { + $condition = "o.status = '" . esc_sql( $status ) . "' "; + } elseif ( $filter == 'only-paid' ) { + $condition = "o.total > 0"; + } elseif( $filter == 'only-free' ) { + $condition = "o.total = 0"; + } else { + $condition = ""; + } + + $condition = apply_filters( 'pmpro_admin_orders_query_condition', $condition, $filter ); + + $orderby = ''; + + if( ! empty( $_REQUEST['order'] ) && ! empty( $_REQUEST['orderby'] ) && ! $count ) { + + $order = strtoupper( esc_sql( $_REQUEST['order'] ) ); + $orderby = ( $_REQUEST['orderby'] ); + + if( $orderby == 'total' ) { + $orderby = 'total + 0'; //This pads the number and allows it to sort correctly + } + + $order_query = "ORDER BY $orderby $order"; + } else { + $order_query = 'ORDER BY id DESC'; + } + + $paid_string = __( 'Paid', 'paid-memberships-pro' ); + $cancelled_string = __( 'Cancelled', 'paid-memberships-pro' ); + $refunded_string = __( 'Refunded', 'paid-memberships-pro' ); + $token_string = __( 'Token', 'paid-memberships-pro' ); + $review_string = __( 'Review', 'paid-memberships-pro' ); + $pending_string = __( 'Pending', 'paid-memberships-pro' ); + $error_string = __( 'Error', 'paid-memberships-pro' ); + + if( $count ) { + $calculation_function = 'COUNT(*), '; + } else { + $calculation_function = 'SQL_CALC_FOUND_ROWS'; + } + + $sqlQuery = "SELECT $calculation_function o.id, CASE WHEN o.status = 'success' THEN 'Paid' WHEN o.status = 'cancelled' THEN '$paid_string' WHEN o.status = 'refunded' THEN '$refunded_string' WHEN o.status = 'token' THEN '$token_string' WHEN o.status = 'review' THEN '$review_string' WHEN o.status = 'pending' THEN '$pending_string' WHEN o.status = 'error' THEN '$error_string' ELSE '$cancelled_string' END as `status_label` FROM $wpdb->pmpro_membership_orders o LEFT JOIN $wpdb->pmpro_membership_levels ml ON o.membership_id = ml.id LEFT JOIN $wpdb->users u ON o.user_id = u.ID "; + + if ( $s ) { + + $join_with_usermeta = apply_filters( 'pmpro_orders_search_usermeta', false ); + + if ( $join_with_usermeta ) { + $sqlQuery .= "LEFT JOIN $wpdb->usermeta um ON o.user_id = um.user_id "; + } + + if ( $filter === 'with-discount-code' ) { + $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id "; + } + + $sqlQuery .= 'WHERE (1=2 '; + + $fields = array( + 'o.id', + 'o.code', + 'o.billing_name', + 'o.billing_street', + 'o.billing_city', + 'o.billing_state', + 'o.billing_zip', + 'o.billing_phone', + 'o.payment_type', + 'o.cardtype', + 'o.accountnumber', + 'o.status', + 'o.gateway', + 'o.gateway_environment', + 'o.payment_transaction_id', + 'o.subscription_transaction_id', + 'u.user_login', + 'u.user_email', + 'u.display_name', + 'ml.name', + ); + + if ( $join_with_usermeta ) { + $fields[] = 'um.meta_value'; + } + + $fields = apply_filters( 'pmpro_orders_search_fields', $fields ); + + foreach ( $fields as $field ) { + $sqlQuery .= ' OR ' . esc_sql( $field ) . " LIKE '%" . esc_sql( $s ) . "%' "; + } + $sqlQuery .= ') '; + + //Not escaping here because we escape the values in the condition statement + $sqlQuery .= 'AND ' . $condition . ' '; + $sqlQuery .= 'GROUP BY o.id ORDER BY o.id DESC, o.timestamp DESC '; + } else { + + if ( $filter === 'with-discount-code' ) { + $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON o.id = dc.order_id "; + } + //Not escaping here because we escape the values in the condition statement + $sqlQuery .= "WHERE " . $condition . ' ' . $order_query . ' '; + + } + + if( $count ) { + return $wpdb->get_var( $sqlQuery ); + } else { + $sqlQuery .= "LIMIT " . esc_sql( $start ) . "," . esc_sql( $limit ); + $order_ids = $wpdb->get_col( $sqlQuery ); + $order_data = array(); + foreach ( $order_ids as $order_id ) { + $order = new MemberOrder(); + $order->nogateway = true; + $order->getMemberOrderByID( $order_id ); + $order->getUser(); + + $order_data[] = $order; + } + return $order_data; + } + } + + /** + * Add extra markup in the toolbars before or after the list + * + * @param string $which, helps you decide if you add the markup after (bottom) or before (top) the list array( '' => 'Select a Level' ) + */ + function extra_tablenav( $which ) { + + if ( $which == 'top' ) { + + global $wpdb; + + $now = current_time( 'timestamp' ); + + if ( isset( $_REQUEST['l'] ) ) { + $l = intval( $_REQUEST['l'] ); + } else { + $l = false; + } + + if ( isset( $_REQUEST['discount-code'] ) ) { + $discount_code = intval( $_REQUEST['discount-code'] ); + } else { + $discount_code = false; + } + + if ( isset( $_REQUEST['start-month'] ) ) { + $start_month = intval( $_REQUEST['start-month'] ); + } else { + $start_month = '1'; + } + + if ( isset( $_REQUEST['start-day'] ) ) { + $start_day = intval( $_REQUEST['start-day'] ); + } else { + $start_day = '1'; + } + + if ( isset( $_REQUEST['start-year'] ) ) { + $start_year = intval( $_REQUEST['start-year'] ); + } else { + $start_year = date( 'Y', $now ); + } + + if ( isset( $_REQUEST['end-month'] ) ) { + $end_month = intval( $_REQUEST['end-month'] ); + } else { + $end_month = date( 'n', $now ); + } + + if ( isset( $_REQUEST['end-day'] ) ) { + $end_day = intval( $_REQUEST['end-day'] ); + } else { + $end_day = date( 'j', $now ); + } + + if ( isset( $_REQUEST['end-year'] ) ) { + $end_year = intval( $_REQUEST['end-year'] ); + } else { + $end_year = date( 'Y', $now ); + } + + if ( isset( $_REQUEST['predefined-date'] ) ) { + $predefined_date = sanitize_text_field( $_REQUEST['predefined-date'] ); + } else { + $predefined_date = 'This Month'; + } + + if ( isset( $_REQUEST['status'] ) ) { + $status = sanitize_text_field( $_REQUEST['status'] ); + } else { + $status = ''; + } + + if ( isset( $_REQUEST['filter'] ) ) { + $filter = sanitize_text_field( $_REQUEST['filter'] ); + } else { + $filter = 'all'; + } + + // filters + if ( empty( $filter ) || $filter === 'all' ) { + $filter = 'all'; + } + + // The code that goes before the table is here + if ( ! empty( $pmpro_msg ) ) { ?> +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + pmpro_discount_codes "; + $sqlQuery .= "ORDER BY id DESC "; + $codes = $wpdb->get_results($sqlQuery, OBJECT); + if ( ! empty( $codes ) ) { ?> + + + + + + + + + + 'id', + 'level' => 'name', + 'total' => 'total', + 'status' => 'status_label', + 'date' => 'timestamp', + ); + + if ( ! empty( $allowed_orderbys[$orderby] ) ) { + $orderby = $allowed_orderbys[$orderby]; + } else { + $orderby = false; + } + + return $allowed_orderbys; + } + + /** + * Render a column when no column specific method exists. + * + * @param array $item + * @param string $column_name + * + * @return mixed + */ + public function column_default( $item, $column_name ) { + + $column_item = (array) apply_filters( 'pmpro_order_list_item', $item ); + + if ( isset( $column_item[ $column_name ] ) ) { + // If the user is adding content via the "pmpro_order_list_item" filter. + echo( esc_html( $column_item[ $column_name ] ) ); + } elseif ( 0 === strpos( $column_name, 'custom_field_' ) ) { + // If the user is adding content via the "pmpro_orders_extra_cols_body" hook. + // Re-implementing old hook, will be deprecated. + ob_start(); + do_action( 'pmpro_orders_extra_cols_body', $item ); + $extra_cols = ob_get_clean(); + preg_match_all( '/(.*?)<\/td>/s', $extra_cols, $matches ); + + $custom_field_num_arr = explode( 'custom_field_', $column_name ); + $custom_field_num = $custom_field_num_arr[1]; + if ( is_numeric( $custom_field_num ) && isset( $matches[1][ intval( $custom_field_num ) ] ) ) { + // If the escaping here breaks your old column body, use the new filters. + echo( wp_kses_post( $matches[1][ intval( $custom_field_num ) ] ) ); + } + } else { + // The preferred ways of doing things. + do_action( 'pmpro_manage_orderlist_custom_column', $column_name, $item->id ); + } + + } + + /** + * Renders the columns order ID value + * + * @param object $item + * + * @return string + */ + public function column_order_id( $item ) { + + return $item->id; + + } + + /** + * Renders the columns order code value + * + * @param object $item + * + * @return string + */ + public function column_order_code( $item ) { + ?> + code ); ?> +
+ code ) + ) + ); + + $delete_nonce_url = wp_nonce_url( + add_query_arg( + [ + 'page' => 'pmpro-orders', + 'action' => 'delete_order', + 'delete' => $item->id, + 'order' => isset( $_REQUEST['order'] ) ? intval( $_REQUEST['order'] ) : null, + 'orderby' => isset( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : null, + 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : null, + 'filter' => isset( $_REQUEST['filter'] ) ? sanitize_text_field( $_REQUEST['filter'] ) : null, + 'start-month' => isset( $_REQUEST['start-month'] ) ? intval( $_REQUEST['start-month'] ) : null, + 'start-day' => isset( $_REQUEST['start-day'] ) ? intval( $_REQUEST['start-day'] ) : null, + 'start-year' => isset( $_REQUEST['start-year'] ) ? intval( $_REQUEST['start-year'] ) : null, + 'end-month' => isset( $_REQUEST['end-month'] ) ? intval( $_REQUEST['end-month'] ) : null, + 'end-day' => isset( $_REQUEST['end-day'] ) ? intval( $_REQUEST['end-day'] ) : null, + 'end-year' => isset( $_REQUEST['end-year'] ) ? intval( $_REQUEST['end-year'] ) : null, + 'predefined-date' => isset( $_REQUEST['predefined-date'] ) ? sanitize_text_field( $_REQUEST['predefined-date'] ) : null, + 'l' => isset( $_REQUEST['l'] ) ? sanitize_text_field( $_REQUEST['l'] ) : null, + 'status' => isset( $_REQUEST['status'] ) ? sanitize_text_field( $_REQUEST['status'] ) : null, + 'discount-code' => isset( $_REQUEST['discount-code'] ) ? sanitize_text_field( $_REQUEST['discount-code'] ) : null, + ], + admin_url( 'admin.php' ) + ), + 'delete_order', + 'pmpro_orders_nonce' + ); + + $refund_text = esc_html( + sprintf( + // translators: %s is the Order Code. + __( 'Refund order %s at the payment gateway. This action is permanent. The user and admin will receive an email confirmation after the refund is processed. Are you sure you want to refund this order?', 'paid-memberships-pro' ), + str_replace( "'", '', $item->code ) + ) + ); + + $refund_nonce_url = wp_nonce_url( + add_query_arg( + [ + 'page' => 'pmpro-orders', + 'action' => 'refund_order', + 'refund' => $item->id, + ], + admin_url( 'admin.php' ) + ), + 'refund_order', + 'pmpro_orders_nonce' + ); + + $actions = [ + 'id' => sprintf( + // translators: %s is the Order ID. + __( 'ID: %s', 'paid-memberships-pro' ), + esc_attr( $item->id ) + ), + 'edit' => sprintf( + '%3$s', + esc_attr__( 'Edit', 'paid-memberships-pro' ), + esc_url( + add_query_arg( + [ + 'page' => 'pmpro-orders', + 'order' => $item->id, + ], + admin_url( 'admin.php' ) + ) + ), + esc_html__( 'Edit', 'paid-memberships-pro' ) + ), + 'copy' => sprintf( + '%3$s', + esc_attr__( 'Copy', 'paid-memberships-pro' ), + esc_url( + add_query_arg( + [ + 'page' => 'pmpro-orders', + 'order' => - 1, + 'copy' => $item->id, + ], + admin_url( 'admin.php' ) + ) + ), + esc_html__( 'Copy', 'paid-memberships-pro' ) + ), + 'delete' => sprintf( + '%3$s', + esc_attr__( 'Delete', 'paid-memberships-pro' ), + 'javascript:pmpro_askfirst(\'' . esc_js( $delete_text ) . '\', \'' . esc_js( $delete_nonce_url ) . '\'); void(0);', + esc_html__( 'Delete', 'paid-memberships-pro' ) + ), + 'print' => sprintf( + '%3$s', + esc_attr__( 'Print', 'paid-memberships-pro' ), + esc_url( + add_query_arg( + [ + 'action' => 'pmpro_orders_print_view', + 'order' => $item->id, + ], + admin_url( 'admin-ajax.php' ) + ) + ), + esc_html__( 'Print', 'paid-memberships-pro' ) + ), + 'email' => sprintf( + '', + esc_attr__( 'Email', 'paid-memberships-pro' ), + '#TB_inline?width=600&height=200&inlineId=email_invoice', + esc_attr( $item->id ), + esc_html__( 'Email', 'paid-memberships-pro' ) + ), + ]; + + if( pmpro_allowed_refunds( $item ) ) { + $actions['refund'] = sprintf( + '%3$s', + esc_attr__( 'Refund', 'paid-memberships-pro' ), + esc_js( 'javascript:pmpro_askfirst(' . wp_json_encode( $refund_text ) . ', ' . wp_json_encode( $refund_nonce_url ) . '); void(0);' ), + esc_html__( 'Refund', 'paid-memberships-pro' ) + ); + } + + /** + * Filter the extra actions for this user on this order. + * + * @param array $actions The list of actions. + * @param object $user The user data. + * @param MemberOrder $order The current order. + */ + $actions = apply_filters( 'pmpro_orders_user_row_actions', $actions, $item->user, $item ); + + $actions_html = []; + + foreach ( $actions as $action => $link ) { + $actions_html[] = sprintf( + '%2$s', + esc_attr( $action ), + $link + ); + } + + if ( ! empty( $actions_html ) ) { + echo implode( ' | ', $actions_html ); + } + ?> +
+ user ) ) { + echo ''.esc_html( $item->user->user_login ).'
'; + echo esc_html( $item->user->user_email ); + } elseif ( $item->user_id > 0 ) { + echo '['. esc_html__( 'deleted', 'paid-memberships-pro' ) . ']'; + } else { + echo '['. esc_html__( 'none', 'paid-memberships-pro' ) . ']'; + } + } + + /** + * Renders the columns level + * + * @param object $item + * + * @return string + */ + public function column_level( $item ) { + + $level = pmpro_getLevel( $item->membership_id ); + if ( ! empty( $level ) ) { + echo esc_html( $level->name ); + } elseif ( $item->membership_id > 0 ) { + echo '['. esc_html( 'deleted', 'paid-memberships-pro' ).']'; + } else { + esc_html_e( '—', 'paid-memberships-pro' ); + } + + } + + /** + * Renders the columns order total + * + * @param object $item + * + * @return string + */ + public function column_total( $item ) { + + echo pmpro_escape_price( pmpro_formatPrice( $item->total ) ); + + } + + /** + * Renders the columns order billing information + * + * @param object $item + * + * @return string + */ + public function column_billing( $item ) { + + // Build our return variable. + $r = ''; + + if ( ! empty( $item->payment_type ) ) { + if ( in_array( $item->payment_type, array( 'PayPal Standard', 'PayPal Express' ) ) ) { + $r .= esc_html__( 'PayPal', 'paid-memberships-pro' ); + } else { + $r .= esc_html( ucwords( $item->payment_type ) ); + } + $r .= '
'; + } + + if ( ! empty( $item->accountnumber ) ) { + $r .= esc_html( $item->cardtype ) . ': x' . esc_html( last4( $item->accountnumber ) ) . '
'; + } + + if ( ! empty( $item->billing->name ) ) { + $r .= esc_html( $item->billing->name ) . '
'; + } + + if ( ! empty( $item->billing->street ) ) { + $r .= esc_html( $item->billing->street ) . '
'; + } + + if ( $item->billing->city && $item->billing->state ) { + $r .= esc_html( $item->billing->city ) . ', '; + $r .= esc_html( $item->billing->state ) . ' '; + $r .= esc_html( $item->billing->zip ) . ' '; + if ( ! empty( $item->billing->country ) ) { + $r .= esc_html( $item->billing->country ); + } + } + + if ( ! empty( $item->billing->phone ) ) { + $r .= '
' . esc_html( formatPhone( $item->billing->phone ) ); + } + + // If this column is completely empty, set $r to a dash. + if ( empty( $r ) ) { + $r .= esc_html__( '—', 'paid-memberships-pro' ); + } + + // Echo the data for this column. + echo $r; + + } + + /** + * Renders the columns order gateway value + * + * @param object $item + * + * @return string + */ + public function column_gateway( $item ) { + + global $pmpro_gateways; + + if ( ! empty( $item->gateway ) ) { + if ( ! empty( $pmpro_gateways[$item->gateway] ) ) { + echo $pmpro_gateways[$item->gateway]; + } else { + esc_html_e( ucwords( $item->gateway ) ); + } + if ( $item->gateway_environment == 'sandbox' ) { + echo ' (test)'; + } + } else { + esc_html_e( '—', 'paid-memberships-pro' ); + } + + } + + /** + * Renders the columns order transaction IDs + * + * @param object $item + * + * @return string + */ + public function column_transaction_ids( $item ) { + + esc_html_e( 'Payment', 'paid-memberships-pro' ); ?>: + payment_transaction_id ) ) { + echo esc_html( $item->payment_transaction_id ); + } else { + esc_html_e( 'N/A', 'paid-memberships-pro' ); + } + ?> +
+ : + subscription_transaction_id ) ) { + echo esc_html( $item->subscription_transaction_id ); + } else { + esc_html_e( 'N/A', 'paid-memberships-pro' ); + } + + + } + + /** + * Renders the columns order status + * + * @param object $item + * + * @return string + */ + public function column_order_status( $item ) { + + ?> + + status, array( 'success', 'cancelled' ) ) ) { + esc_html_e( 'Paid', 'paid-memberships-pro' ); + } else { + esc_html_e( ucwords( $item->status ) ); + } ?> + + is_renewal() ) { ?> + + getTimestamp() ) ), + esc_html( date_i18n( get_option( 'time_format' ), $item->getTimestamp() ) ) + ) ); + } + + /** + * Renders the columns order discount value + * + * @param object $item + * + * @return string + */ + public function column_discount_code( $item ) { + if ( $item->getDiscountCode() ) { ?> + + discount_code->code ); ?> + + =' ) ) {