Tribe__Tickets__Admin__Move_Ticket_Types
Handles moving ticket types from a post to another.
Source
File: src/Tribe/Admin/Move_Ticket_Types.php
class Tribe__Tickets__Admin__Move_Ticket_Types extends Tribe__Tickets__Admin__Move_Tickets {
protected $dialog_name = 'move_ticket_types';
public function setup() {
add_action( 'admin_init', array( $this, 'dialog' ) );
add_action( 'wp_ajax_move_ticket_types_post_list', array( $this, 'update_post_choices' ) );
add_action( 'wp_ajax_move_ticket_type', array( $this, 'move_ticket_type_requests' ) );
add_action( 'tribe_tickets_ticket_type_moved', array( $this, 'notify_event_attendees' ), 100, 3 );
add_action( 'tribe_events_tickets_metabox_edit_ajax_advanced', array( $this, 'expose_ticket_history' ), 100 );
add_filter( 'tribe_tickets_move_tickets_template_vars', array( $this, 'move_tickets_dialog_vars' ) );
add_filter( 'tribe_tickets_move_tickets_script_data', array( $this, 'move_tickets_dialog_data' ) );
}
public function move_tickets_dialog_vars( array $vars ) {
if ( ! $this->is_move_tickets_dialog() ) {
return $vars;
}
return array_merge( $vars, array(
'title' => __( 'Move Ticket Types', 'event-tickets' ),
'mode' => 'ticket_type_only',
) );
}
public function move_tickets_dialog_data( array $data ) {
if ( ! $this->is_move_tickets_dialog() ) {
return $data;
}
return array_merge( $data, array(
'ticket_type_id' => absint( $_GET[ 'ticket_type_id' ] ),
'src_post_id' => absint( $_GET[ 'post' ] ),
'mode' => 'ticket_type_only',
) );
}
/**
* Returns an updated list of post choices.
*/
public function update_post_choices() {
if ( ! wp_verify_nonce( $_POST['check' ], 'move_ticket_type' ) ) {
wp_send_json_error();
}
$args = wp_parse_args( $_POST, array(
'post_type' => '',
'search_terms' => '',
'ignore' => '',
) );
wp_send_json_success( array( 'posts' => $this->get_possible_matches( $args ) ) );
}
/**
* Returns a list of post types for which tickets are currently enabled.
*
* The list is expressed as an array in the following format:
*
* [ 'slug' => 'name', ... ]
*
* @return array
*/
protected function get_post_types_list() {
$types_list = array( 'all' => __( 'All supported types', 'tribe-tickets' ) );
foreach ( Tribe__Tickets__Main::instance()->post_types() as $type ) {
$pto = get_post_type_object( $type );
$types_list[ $type ] = $pto->label;
}
return $types_list;
}
/**
* Listens out for ajax requests to move a ticket type to a new post.
*/
public function move_ticket_type_requests() {
$args = wp_parse_args( $_POST, array(
'check' => '',
'ticket_type_id' => 0,
'target_post_id' => 0,
'src_post_id' => 0,
) );
if ( ! wp_verify_nonce( $args['check' ], 'move_tickets' ) ) {
wp_send_json_error();
}
$ticket_type_id = absint( $args['ticket_type_id'] );
$destination_id = absint( $args['target_post_id'] );
$src_post_id = absint( $args['src_post_id'] );
if ( ! $ticket_type_id || ! $destination_id ) {
wp_send_json_error( array(
'message' => __( 'Ticket type could not be moved: the ticket type or destination post was invalid.', 'event-tickets' )
) );
}
if ( ! $this->move_ticket_type( $ticket_type_id, $destination_id ) ) {
wp_send_json_error( array(
'message' => __( 'Ticket type could not be moved: unexpected failure during reassignment.', 'event-tickets' )
) );
}
wp_send_json_success( array(
'message' => sprintf(
'<p>' . __( 'Ticket type %1$s for %2$s was successfully moved to %3$s. All previously sold tickets of this type have been transferred to %3$s. Please adjust capacity and stock manually as needed. %1$s ticket holders have received an email notifying them of the change. You may now close this window!', 'event-tickets' ) . '</p>',
'<a href="' . esc_url( get_admin_url( null, '/post.php?post=' . $ticket_type_id . '&action=edit' ) ) . '" target="_blank">' . get_the_title( $ticket_type_id ) . '</a>',
'<a href="' . esc_url( get_admin_url( null, '/post.php?post=' . $src_post_id . '&action=edit' ) ) . '" target="_blank">' . get_the_title( $src_post_id ) . '</a>',
'<a href="' . esc_url( get_admin_url( null, '/post.php?post=' . $destination_id . '&action=edit' ) ) . '" target="_blank">' . get_the_title( $destination_id ) . '</a>'
),
'remove_ticket_type' => $ticket_type_id,
) );
}
/**
* Moves a ticket type to a new post.
*
* For example, a VIP ticket type may be attached to an event called "Tuesday Race Day",
* however if this event is rained out it may be desirable to move the VIP ticket type
* to a new "Thursday Race Day" event instead.
*
* Moving the ticket type, rather than recreating it, can be useful when ticket orders
* have already been placed.
*
* @param int $ticket_type_id
* @param int $destination_post_id
* @param int $instigator_id (optional) the user who initiated or requested the change
*
* @return bool
*/
public function move_ticket_type( $ticket_type_id, $destination_post_id, $instigator_id = null ) {
if ( null === $instigator_id ) {
$instigator_id = get_current_user_id();
}
$ticket_type = Tribe__Tickets__Tickets::load_ticket_object( $ticket_type_id );
if ( null === $ticket_type ) {
return false;
}
$provider = $ticket_type->get_provider();
$event_key = $provider->get_event_key();
/**
* Fires immediately before a ticket type is moved.
*
* @param int $ticket_type_id
* @param int $destination_post_id
* @param int $instigator_id
*/
do_action( 'tribe_tickets_ticket_type_before_move', $ticket_type_id, $destination_post_id, $instigator_id );
$src_post_id = get_post_meta( $ticket_type_id, $event_key, true );
$success = update_post_meta( $ticket_type_id, $event_key, $destination_post_id );
if ( ! $success ) {
return false;
}
$src_event_cap = new Tribe__Tickets__Global_Stock( $src_post_id );
$tgt_event_cap = new Tribe__Tickets__Global_Stock( $destination_post_id );
$src_mode = get_post_meta( $ticket_type_id, Tribe__Tickets__Global_Stock::TICKET_STOCK_MODE, true );
// When the Mode is not `own` we have to check and modify some stuff
if ( Tribe__Tickets__Global_Stock::OWN_STOCK_MODE !== $src_mode ) {
// If we have Source cap and not on Target, we set it up
if ( ! $tgt_event_cap->is_enabled() ) {
$src_event_capacity = tribe_tickets_get_capacity( $src_post_id );
// Activate Shared Capacity on the Ticket
$tgt_event_cap->enable();
// Setup the Stock level to match Source capacity
$tgt_event_cap->set_stock_level( $src_event_capacity );
// Update the Target event with the Capacity from the Source
update_post_meta( $destination_post_id, tribe( 'tickets.handler' )->key_capacity, $src_event_capacity );
} elseif ( Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE === $src_mode ) {
// Check if we have capped to avoid ticket cap over event cap
$src_ticket_capacity = tribe_tickets_get_capacity( $ticket_type_id );
$tgt_event_capacity = tribe_tickets_get_capacity( $destination_post_id );
// Don't allow ticket capacity to be bigger than Target Event Cap
if ( $src_ticket_capacity > $tgt_event_capacity ) {
update_post_meta( $ticket_type_id, tribe( 'tickets.handler' )->key_capacity, $tgt_event_capacity );
}
}
}
$provider->clear_attendees_cache( $src_post_id );
$provider->clear_attendees_cache( $destination_post_id );
$history_message = sprintf(
__( 'Ticket type was moved to <a href="%1$s" target="_blank">%2$s</a> from <a href="%3$s" target="_blank">%4$s</a>', 'event-tickets' ),
get_permalink( $destination_post_id ),
get_the_title( $destination_post_id ),
get_permalink( $src_post_id ),
get_the_title( $src_post_id )
);
$history_data = array(
'src_event_id' => $src_post_id,
'tgt_event_id' => $destination_post_id,
);
Tribe__Post_History::load( $ticket_type_id )->add_entry( $history_message, $history_data );
/**
* Fires when a ticket type is relocated from one post to another.
*
* @param int $ticket_type_id the ticket type which has been moved
* @param int $destination_post_id the post to which the ticket type has been moved
* @param int $src_post_id the post which previously hosted the ticket type
* @param int $instigator_id the user who initiated the change
*/
do_action( 'tribe_tickets_ticket_type_moved', $ticket_type_id, $destination_post_id, $src_post_id, $instigator_id );
return true;
}
/**
* Notify attendees who purchased tickets of this type that it has been
* reassigned to a different post/event.
*
* @param int $ticket_type_id
* @param int $new_post_id
* @param int $original_post_id
*/
public function notify_event_attendees( $ticket_type_id, $new_post_id, $original_post_id ) {
$to_notify = [];
$args = [
'by' => [
'ticket' => $ticket_type_id,
],
];
$attendee_data = Tribe__Tickets__Tickets::get_event_attendees_by_args( $new_post_id, $args );
// Build a list of email addresses we want to send notifications of the change to
foreach ( $attendee_data['attendees'] as $attendee ) {
// Skip if an email address isn't available
if ( ! isset( $attendee['purchaser_email'] ) ) {
continue;
}
if ( ! isset( $to_notify[ $attendee['purchaser_email'] ] ) ) {
$to_notify[ $attendee['purchaser_email'] ] = 1;
} else {
$to_notify[ $attendee['purchaser_email'] ] ++;
}
}
// Dispatch the emails
foreach ( $to_notify as $email_addr => $num_tickets ) {
/**
* Sets the moved ticket type email address.
*
* @param string $email_addr
*/
$to = apply_filters( 'tribe_tickets_ticket_type_moved_email_recipient', $email_addr );
/**
* Sets any attachments for the moved ticket type email address.
*
* @param array $attachments
*/
$attachments = apply_filters( 'tribe_tickets_ticket_type_moved_email_attachments', array() );
/**
* Sets the HTML for the moved ticket type email.
*
* @param string $html
*/
$content = apply_filters( 'tribe_tickets_ticket_type_moved_email_content',
$this->generate_email_content( $ticket_type_id, $original_post_id, $new_post_id, $num_tickets )
);
/**
* Sets any headers for the moved ticket type email.
*
* @param array $headers
*/
$headers = apply_filters( 'tribe_tickets_ticket_type_moved_email_headers',
array( 'Content-type: text/html' )
);
/**
* Sets the subject line for the moved ticket type email.
*
* @param string $subject
*/
$subject = apply_filters( 'tribe_tickets_ticket_type_moved_email_subject',
sprintf( __( 'Changes to your tickets from %s', 'event-tickets' ), get_bloginfo( 'name' ) )
);
wp_mail( $to, $subject, $content, $headers, $attachments );
}
}
/**
* @param int $tgt_ticket_type_id
* @param int $src_event_id
* @param int $tgt_event_id
* @param int $num_tickets
*
* @return string
*/
protected function generate_email_content( $tgt_ticket_type_id, $src_event_id, $tgt_event_id, $num_tickets ) {
$vars = array(
'original_event_id' => $src_event_id,
'original_event_name' => get_the_title( $src_event_id ),
'new_event_id' => $tgt_event_id,
'new_event_name' => get_the_title( $tgt_event_id ),
'ticket_type_id' => $tgt_ticket_type_id,
'ticket_type_name' => get_the_title( $tgt_ticket_type_id ),
'num_tickets' => $num_tickets
);
return tribe_tickets_get_template_part( 'tickets/email-ticket-type-moved', null, $vars, false );
}
/**
* Prints out the audit trail/post history for the current ticket, if
* available.
*/
public function expose_ticket_history() {
// This will only be available during edit requests for existing tickets
if ( ! isset( $_POST[ 'ticket_id' ] ) ) {
return;
}
$ticket_id = absint( $_POST[ 'ticket_id' ] );
$ticket_object = Tribe__Tickets__Tickets::load_ticket_object( $ticket_id );
if ( ! $ticket_object || ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
return;
}
/**
* Allows the display of a ticket type's post history ("audit trail")
* within the ticket editor to be turned on or off.
*
* @param bool $show_history
*/
if ( ! apply_filters( 'tribe_tickets_show_ticket_type_history_in_ticket_editor', true ) ) {
return;
}
// $provider is needed to form the correct table row classes (otherwise the
// history section will not show/hide appropriately)
$provider = $ticket_object->provider_class;
$history = Tribe__Post_History::load( $ticket_id );
if ( ! $history->has_entries() ) {
return;
}
include EVENT_TICKETS_DIR . '/src/admin-views/ticket-type-history.php';
}
}
Methods
- expose_ticket_history — Prints out the audit trail/post history for the current ticket, if available.
- move_ticket_type — Moves a ticket type to a new post.
- move_ticket_type_requests — Listens out for ajax requests to move a ticket type to a new post.
- move_tickets_dialog_data
- move_tickets_dialog_vars
- notify_event_attendees — Notify attendees who purchased tickets of this type that it has been reassigned to a different post/event.
- setup
- update_post_choices — Returns an updated list of post choices.