'attendee', 'plural' => 'attendees', 'ajax' => true, 'screen' => get_current_screen(), ) ); // Fetch the event Object if ( ! empty( $_GET['event_id'] ) ) { $this->event = get_post( $_GET['event_id'] ); } add_filter( 'event_tickets_attendees_table_row_actions', array( $this, 'add_default_row_actions' ), 10, 2 ); parent::__construct( apply_filters( 'tribe_events_tickets_attendees_table_args', $args ) ); } /** * Get a list of columns. The format is: * 'internal-name' => 'Title' * * @return array */ public static function get_table_columns() { $columns = array( 'cb' => '', 'ticket' => esc_html_x( 'Ticket', 'attendee table', 'event-tickets' ), 'primary_info' => esc_html_x( 'Primary Information', 'attendee table', 'event-tickets' ), 'security' => esc_html_x( 'Security Code', 'attendee table', 'event-tickets' ), 'status' => esc_html_x( 'Status', 'attendee table', 'event-tickets' ), 'check_in' => esc_html_x( 'Check in', 'attendee table', 'event-tickets' ), ); /** * Controls the columns rendered within the attendee screen. * * @param array $columns */ return apply_filters( 'tribe_tickets_attendee_table_columns', $columns ); } /** * Display the search box. * We don't want Core's search box, because we implemented our own jQuery based filter, * so this function overrides the parent's one and returns empty. * * @param string $text The search button text * @param string $input_id The search input id */ public function search_box( $text, $input_id ) { return; } /** * Display the pagination. * We are not paginating the attendee list, so it returns empty. */ public function pagination( $which ) { return ''; } /** * Checks the current user's permissions */ public function ajax_user_can() { return current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_posts ); } /** * Get a list of columns. The format is: * 'internal-name' => 'Title' * * @return array */ public function get_columns() { return self::get_table_columns(); } /** * Handler for the columns that don't have a specific column_{name} handler function. * * @param $item * @param $column * * @return string */ public function column_default( $item, $column ) { $value = empty( $item[ $column ] ) ? '' : $item[ $column ]; return apply_filters( 'tribe_events_tickets_attendees_table_column', $value, $item, $column ); } /** * Handler for the checkbox column * * @param $item * * @return string */ public function column_cb( $item ) { return sprintf( '', esc_attr( $this->_args['singular'] ), esc_attr( $item['attendee_id'] . '|' . $item['provider'] ) ); } /** * Populates the purchaser column. * * @param array $item * * @return string */ public function column_primary_info( array $item ) { $purchaser_name = empty( $item[ 'purchaser_name' ] ) ? '' : esc_html( $item[ 'purchaser_name' ] ); $purchaser_email = empty( $item[ 'purchaser_email' ] ) ? '' : esc_html( $item[ 'purchaser_email' ] ); return "
{$purchaser_name}
{$purchaser_email}
"; } /** * Populates the status column. * * @param array $item * * @return string */ public function column_status( array $item ) { $icon = ''; $warning = false; // Check if the order_warning flag has been set (to indicate the order has been cancelled, refunded etc) if ( isset( $item['order_warning'] ) && $item['order_warning'] ) { $warning = true; } // If the warning flag is set, add the appropriate icon if ( $warning ) { $icon = sprintf( " ", esc_url( Tribe__Tickets__Main::instance()->plugin_url . 'src/resources/images/warning.png' ) ); } // Look for an order_status_label, fall back on the actual order_status string @todo remove fallback in 3.4.3 if ( empty( $item['order_status'] ) ) { $item['order_status'] = ''; } $label = isset( $item['order_status_label'] ) ? $item['order_status_label'] : ucwords( $item['order_status'] ); $order_id_url = $this->get_order_id_url( $item ); if ( ! empty( $order_id_url ) && ! empty( $item[ 'order_id' ] ) ) { $label = '#' . esc_html( $item[ 'order_id' ] ) . ' – ' . $label . ''; } elseif ( ! empty( $item[ 'order_id' ] ) ) { $label = '#' . esc_html( $item[ 'order_id' ] ) . ' – ' . $label; } /** * Provides an opportunity to modify the order status text within * the attendees table. * * @param string $order_status_html * @param array $item */ return apply_filters( 'tribe_tickets_attendees_table_order_status', $icon . $label, $item ); } /** * Retrieves the order id for the specified table row item. * * In some cases, such as when the current item belongs to the RSVP provider, an * empty string may be returned as there is no order screen that can be linekd to. * * @param array $item * * @return string */ public function get_order_id_url( array $item ) { // Backwards compatibility if ( empty( $item['order_id_url'] ) ) { $item['order_id_url'] = get_edit_post_link( $item['order_id'], true ); } return $item['order_id_url']; } /** * Handler for the ticket column * * @since 4.1 * * @param array $item Item whose ticket data should be output * * @return string */ public function column_ticket( $item ) { ob_start(); $attendee_id = trim( esc_html( $this->get_attendee_id( $item ) ) ); if ( ! empty( $attendee_id ) ) { $attendee_id .= ' – '; } ?>
get_row_actions( $item ); ?> ' . $row_actions . ''; } /** * Adds a set of default row actions to each item in the attendee list table. * * @param array $row_actions * @param array $item * * @return array */ public function add_default_row_actions( array $row_actions, array $item ) { $attendee = esc_attr( $item['attendee_id'] . '|' . $item['provider'] ); $nonce = wp_create_nonce( 'do_item_action_' . $attendee ); $check_in_out_url = esc_url( add_query_arg( array( 'action' => $item[ 'check_in' ] ? 'uncheck_in' : 'check_in', 'nonce' => $nonce, 'attendee' => $attendee, ) ) ); $check_in_out_text = $item[ 'check_in' ] ? esc_html_x( 'Undo Check In', 'row action', 'event-tickets' ) : esc_html_x( 'Check In', 'row action', 'event-tickets' ); $delete_url = esc_url( add_query_arg( array( 'action' => 'delete_attendee', 'nonce' => $nonce, 'attendee' => $attendee, ) ) ); $default_actions = array( ' ' . $check_in_out_text . ' ', ); if ( is_admin() ) { $default_actions[] = ' ' . esc_html_x( 'Move', 'row action', 'event-tickets' ) . ' '; } $default_actions[] = '' . esc_html_x( 'Delete', 'row action', 'event-tickets' ) . ''; return array_merge( $row_actions, $default_actions ); } /** * Returns the attendee ID (or "unique ID" if set). * * @param array $item * * @return int|string */ public function get_attendee_id( $item ) { $attendee_id = empty( $item['attendee_id'] ) ? '' : $item['attendee_id']; if ( $attendee_id === '' ) { return ''; } $unique_id = get_post_meta( $attendee_id, '_unique_id', true ); if ( $unique_id === '' ) { $unique_id = $attendee_id; } /** * Filters the ticket number; defaults to the ticket unique ID. * * @param string $unique_id A unique string identifier for the ticket. * @param array $item The item entry. */ return apply_filters( 'tribe_events_tickets_attendees_table_attendee_id_column', $unique_id, $item ); } /** * Handler for the check in column * * @param $item * * @return string */ public function column_check_in( $item ) { $default_checkin_stati = array(); $provider = $item['provider_slug']; $order_id = $item['order_id']; /** * Filters the order stati that will allow for a ticket to be checked in for all commerce providers. * * @since 4.1 * * @param array $default_checkin_stati An array of default order stati that will make a ticket eligible for check-in. * @param string $provider The ticket provider slug. * @param int $order_id The order post ID. */ $check_in_stati = apply_filters( 'event_tickets_attendees_checkin_stati', $default_checkin_stati, $provider, $order_id ); /** * Filters the order stati that will allow for a ticket to be checked in for a specific commerce provider. * * @since 4.1 * * @param array $default_checkin_stati An array of default order stati that will make a ticket eligible for check-in. * @param int $order_id The order post ID. */ $check_in_stati = apply_filters( "event_tickets_attendees_{$provider}_checkin_stati", $check_in_stati, $order_id ); if ( ! empty( $item['order_status'] ) && ! empty( $item['order_id_link_src'] ) && is_array( $check_in_stati ) && ! in_array( $item['order_status'], $check_in_stati ) ) { $button_template = '%s'; return sprintf( $button_template, $item['order_id_link_src'], __( 'View order', 'event-tickets' ) ); } $button_classes = ! empty( $item['order_status'] ) && in_array( $item['order_status'], $check_in_stati ) ? 'button-primary' : 'button-primary button-disabled'; if ( empty( $this->event ) ) { $checkin = sprintf( '%s', esc_attr( $item['attendee_id'] ), esc_attr( $item['provider'] ), esc_attr( $button_classes ), esc_html__( 'Check In', 'event-tickets' ) ); $uncheckin = sprintf( '%s', esc_attr( $item['attendee_id'] ), esc_attr( $item['provider'] ), sprintf( '
%1$s
%2$s
', esc_html__( 'Undo', 'event-tickets' ), esc_html__( 'Check In', 'event-tickets' ) ) ); } else { // add the additional `data-event-id` attribute if this is an event $checkin = sprintf( '%s', esc_attr( $item['attendee_id'] ), esc_attr( $this->event->ID ), esc_attr( $item['provider'] ), esc_attr( $button_classes ), esc_html__( 'Check In', 'event-tickets' ) ); $uncheckin = sprintf( '%s', esc_attr( $item['attendee_id'] ), esc_attr( $this->event->ID ), esc_attr( $item['provider'] ), sprintf( '
%1$s
%2$s
', esc_html__( 'Undo', 'event-tickets' ), esc_html__( 'Check In', 'event-tickets' ) ) ); } return $checkin . $uncheckin; } /** * Generates content for a single row of the table * * @param object $item The current item */ public function single_row( $item ) { $checked = ''; if ( intval( $item['check_in'] ) === 1 ) { $checked = ' tickets_checked '; } echo ''; $this->single_row_columns( $item ); echo ''; /** * Hook to allow for the insertion of data after an attendee table row * * @var $item Attendee data */ do_action( 'event_tickets_attendees_table_after_row', $item ); } /** * Extra controls to be displayed between bulk actions and pagination. * * Used for the Print, Email and Export buttons, and for the jQuery based search. * * @param string $which (top|bottom) * @see WP_List_Table::display() */ public function extra_tablenav( $which ) { $export_url = add_query_arg( array( 'attendees_csv' => true, 'attendees_csv_nonce' => wp_create_nonce( 'attendees_csv_nonce' ), ) ); /** * Include TB_iframe JS */ add_thickbox(); $email_link = Tribe__Settings::instance()->get_url( array( 'page' => 'tickets-attendees', 'action' => 'email', 'event_id' => $this->event->ID, 'TB_iframe' => true, 'width' => 410, 'height' => 300, 'parent' => 'admin.php', ) ); $nav = array( 'left' => array( 'print' => sprintf( '', esc_attr__( 'Print', 'event-tickets' ) ), 'email' => '' . esc_attr__( 'Email', 'event-tickets' ) . '', 'export' => sprintf( '%s', esc_url( $export_url ), esc_html__( 'Export', 'event-tickets' ) ), ), 'right' => array(), ); if ( 'top' == $which ) { $nav['right']['filter_box'] = sprintf( '%s: ', esc_html__( 'Filter by purchaser name, ticket #, order # or security code', 'event-tickets' ) ); } $nav = apply_filters( 'tribe_events_tickets_attendees_table_nav', $nav, $which ); ?>
option_title ) with the list * of bulk actions available on this table. * * @return array */ public function get_bulk_actions() { $actions = array( 'check_in' => esc_attr__( 'Check in', 'event-tickets' ), 'uncheck_in' => esc_attr__( 'Undo Check in', 'event-tickets' ), 'delete_attendee' => esc_attr__( 'Delete', 'event-tickets' ), ); return (array) apply_filters( 'tribe_events_tickets_attendees_table_bulk_actions', $actions ); } /** * @deprecated use process_actions() */ public function process_bulk_actions() { _deprecated_function( __FUNCTION__, '4.3', __CLASS__ . '::process_actions()' ); $this->process_actions(); } /** * Handler for the different bulk actions */ public function process_actions() { if ( ! $this->validate_action_nonce() ) { return; } switch ( $this->current_action() ) { case 'check_in': $this->do_check_in(); break; case 'uncheck_in': $this->do_uncheck_in(); break; case 'delete_attendee': $this->do_delete(); break; default: do_action( 'tribe_events_tickets_attendees_table_process_bulk_action', $this->current_action() ); break; } } /** * Indicates if a valid nonce was set for the currently requested bulk or * individual action. * * @return bool */ protected function validate_action_nonce() { // If a bulk action request was posted if ( @$_POST[ 'attendee' ] && wp_verify_nonce( $_POST[ '_wpnonce' ], 'bulk-attendees' ) ) { return true; } // If an individual action was requested if ( @$_GET[ 'attendee' ] && wp_verify_nonce( $_GET[ 'nonce' ], 'do_item_action_' . $_GET[ 'attendee' ] ) ) { return true; } return false; } /** * Returns the list of attendee/tickets for the current bulk or individual * action. * * The format is an array where the elements represent the ticket ID and * provider in the following format: * * [ * '123|Ticket_Provider', * '4567|Ticket_Provider', * ] * * @return array */ protected function get_action_ids() { $action_ids = array(); if ( isset( $_POST[ 'attendee' ] ) ) { $action_ids = (array) $_POST[ 'attendee' ]; } else if ( isset( $_GET[ 'attendee' ] ) ) { $action_ids = (array) $_GET[ 'attendee' ]; } return $action_ids; } protected function do_check_in() { $attendee_ids = $this->get_action_ids(); if ( ! $attendee_ids ) { return; } foreach ( $attendee_ids as $attendee ) { list( $id, $addon ) = $this->attendee_reference( $attendee ); if ( false === $id ) { continue; } $addon->checkin( $id ); } } protected function do_uncheck_in() { $attendee_ids = $this->get_action_ids(); if ( ! $attendee_ids ) { return; } foreach ( $attendee_ids as $attendee ) { list( $id, $addon ) = $this->attendee_reference( $attendee ); if ( false === $id ) { continue; } $addon->uncheckin( $id ); } } protected function do_delete() { $attendee_ids = $this->get_action_ids(); if ( ! $attendee_ids ) { return; } foreach ( $attendee_ids as $attendee ) { list( $id, $addon ) = $this->attendee_reference( $attendee ); if ( false === $id ) { continue; } $addon->delete_ticket( null, $id ); } } /** * Returns the attendee ID and instance of the specific ticketing solution or "addon" used * to handle it. * * This is used in the context of bulk actions where each attendee table entry is identified * by a string of the pattern {id}|{ticket_class} - where possible this method turns that into * an array consisting of the attendee object ID and the relevant ticketing object. * * If this cannot be determined, both array elements will be set to false. * * @param $reference * * @return array */ protected function attendee_reference( $reference ) { $failed = array( false, false ); if ( false === strpos( $reference, '|' ) ) { return $failed; } $parts = explode( '|', $reference ); if ( count( $parts ) < 2 ) { return $failed; } $id = absint( $parts[0] ); if ( $id <= 0 ) { return $failed; } $addon = call_user_func( array( $parts[1], 'get_instance' ) ); if ( ! is_subclass_of( $addon, 'Tribe__Tickets__Tickets' ) ) { return $failed; } return array( $id, $addon ); } /** * Prepares the list of items for displaying. */ public function prepare_items() { $this->process_actions(); $event_id = isset( $_GET['event_id'] ) ? $_GET['event_id'] : 0; $items = Tribe__Tickets__Tickets::get_event_attendees( $event_id ); $this->items = $items; $total_items = count( $this->items ); $per_page = $total_items; $this->set_pagination_args( array( 'total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => 1, ) ); } }