Tribe__Tickets__Metabox

Class in charge of registering and displaying the tickets metabox in the event edit screen.

Contents

Metabox will only be added if there’s a Tickets Pro provider (child of TribeTickets) available.


Source

File: src/Tribe/Metabox.php

class Tribe__Tickets__Metabox {

	/**
	 * Configure all action and filters user by this Class
	 *
	 * @return void
	 */
	public function hook() {
		add_action( 'add_meta_boxes', array( $this, 'configure' ) );

		add_action( 'tribe_events_tickets_bottom_right', array( $this, 'get_ticket_controls' ), 10, 2 );

		add_action( 'wp_ajax_tribe-ticket-panels', array( $this, 'ajax_panels' ) );

		add_action( 'wp_ajax_tribe-ticket-add', array( $this, 'ajax_ticket_add' ) );
		add_action( 'wp_ajax_tribe-ticket-edit', array( $this, 'ajax_ticket_edit' ) );
		add_action( 'wp_ajax_tribe-ticket-delete', array( $this, 'ajax_ticket_delete' ) );

		add_action( 'wp_ajax_tribe-ticket-checkin', array( $this, 'ajax_attendee_checkin' ) );
		add_action( 'wp_ajax_tribe-ticket-uncheckin', array( $this, 'ajax_attendee_uncheckin' ) );
	}

	/**
	 * Configures the Tickets Editor into a Post Type
	 *
	 * @since  4.6.2
	 *
	 * @param  string $post_type Which post type we are trying to configure
	 *
	 * @return void
	 */
	public function configure( $post_type = null ) {
		$modules = Tribe__Tickets__Tickets::modules();
		if ( empty( $modules ) ) {
			return;
		}

		if ( ! in_array( $post_type, Tribe__Tickets__Main::instance()->post_types() ) ) {
			return;
		}

		add_meta_box(
			'tribetickets',
			esc_html__( 'Tickets', 'event-tickets' ),
			array( $this, 'render' ),
			$post_type,
			'normal',
			'high',
			array(
				'__back_compat_meta_box' => true,
			)
		);

		// If we get here means that we will need Thickbox
		add_thickbox();
	}

	/**
	 * Render the actual Metabox
	 *
	 * @since  4.6.2
	 *
	 * @param  int   $post_id  Which post we are dealing with
	 *
	 * @return string|bool
	 */
	public function render( $post_id ) {
		$modules = Tribe__Tickets__Tickets::modules();
		if ( empty( $modules ) ) {
			return false;
		}

		$post = get_post( $post_id );

		// Prepare all the variables required
		$start_date = date( 'Y-m-d H:00:00' );
		$end_date   = date( 'Y-m-d H:00:00' );
		$start_time = Tribe__Date_Utils::time_only( $start_date, false );
		$end_time   = Tribe__Date_Utils::time_only( $start_date, false );

		$show_global_stock = Tribe__Tickets__Tickets::global_stock_available();
		$tickets           = Tribe__Tickets__Tickets::get_event_tickets( $post->ID );
		$global_stock      = new Tribe__Tickets__Global_Stock( $post->ID );

		return tribe( 'tickets.admin.views' )->template( array( 'editor', 'metabox' ), get_defined_vars() );
	}

	/**
	 * Refreshes panels after ajax calls that change data
	 *
	 * @since  4.6.2
	 *
	 * @return string html content of the panels
	 */
	public function ajax_panels() {
		$post_id = absint( tribe_get_request_var( 'post_id', 0 ) );

		// Didn't get a post id to work with - bail
		if ( ! $post_id ) {
			wp_send_json_error( esc_html__( 'Invalid Post ID', 'event-tickets' ) );
		}

		// Overwrites for a few templates that use get_the_ID() and get_post()
		global $post;

		$post = get_post( $post_id );
		$data = wp_parse_args( tribe_get_request_var( array( 'data' ), array() ), array() );
		$notice = tribe_get_request_var( 'tribe-notice', false );

		$data = Tribe__Utils__Array::get( $data, array( 'tribe-tickets' ), null );

		// Save if the info was passed
		if ( ! empty( $data ) ) {
			tribe( 'tickets.handler' )->save_order( $post->ID, isset( $data['list'] ) ? $data['list'] : null );
			tribe( 'tickets.handler' )->save_form_settings( $post->ID, isset( $data['settings'] ) ? $data['settings'] : null );
		}

		$return = $this->get_panels( $post );
		$return['notice'] = $this->notice( $notice );

		/**
		 * Allows filtering the data by other plugins/ecommerce solutions©
		 *
		 * @since 4.6
		 *
		 * @param array the return data
		 * @param int the post/event id
		 */
		$return = apply_filters( 'tribe_tickets_ajax_refresh_tables', $return, $post->ID );

		wp_send_json_success( $return );
	}

	/**
	 * Get the Panels for a given
	 *
	 * @since  4.6.2
	 *
	 * @param int|WP_Post $post
	 * @param int         $ticket_id
	 *
	 * @return array
	 */
	public function get_panels( $post, $ticket_id = null ) {
		if ( ! $post instanceof WP_Post ) {
			$post = get_post( $post );
		}

		// Bail on Invalid post
		if ( ! $post instanceof WP_Post ) {
			return array();
		}

		// Overwrites for a few templates that use get_the_ID() and get_post()
		$GLOBALS['post'] = $post;

		// Let's create tickets list markup to return
		$tickets = Tribe__Tickets__Tickets::get_event_tickets( $post->ID );

		$panels = array(
			'list' => tribe( 'tickets.admin.views' )->template( 'editor/panel/list', array( 'post_id' => $post->ID, 'tickets' => $tickets ), false ),
			'settings' => tribe( 'tickets.admin.views' )->template( 'editor/panel/settings', array( 'post_id' => $post->ID ), false ),
			'ticket' => tribe( 'tickets.admin.views' )->template( 'editor/panel/ticket', array( 'post_id' => $post->ID, 'ticket_id' => $ticket_id ), false ),
		);

		return $panels;
	}

	/**
	 * Sanitizes the data for the new/edit ticket ajax call,
	 * and calls the child save_ticket function.
	 *
	 * @since  4.6.2
	 */
	public function ajax_ticket_add() {
		$post_id = absint( tribe_get_request_var( 'post_id', 0 ) );

		if ( ! $post_id ) {
			wp_send_json_error( esc_html__( 'Invalid parent Post', 'event-tickets' ) );
		}

		/**
		 * This is needed because a provider can implement a dynamic set of fields.
		 * Each provider is responsible for sanitizing these values.
		 */
		$data = wp_parse_args( tribe_get_request_var( array( 'data' ), array() ), array() );

		if ( ! $this->has_permission( $post_id, $_POST, 'add_ticket_nonce' ) ) {
			wp_send_json_error( esc_html__( 'Failed to Add the Ticket, Refresh the Page to try again.', 'event-tickets' ) );
		}

		if ( ! isset( $data['ticket_provider'] ) || ! $this->module_is_valid( $data['ticket_provider'] ) ) {
			wp_send_json_error( esc_html__( 'Commerce Provider invalid', 'event-tickets' ) );
		}

		// Get the Provider
		$module = call_user_func( array( $data['ticket_provider'], 'get_instance' ) );

		// Do the actual adding
		$ticket_id = $module->ticket_add( $post_id, $data );

		// Successful?
		if ( $ticket_id ) {
			/**
			 * Fire action when a ticket has been added
			 *
			 * @param int $post_id ID of parent "event" post
			 */
			do_action( 'tribe_tickets_ticket_added', $post_id );
		} else {
			wp_send_json_error( esc_html__( 'Failed to Add the Ticket', 'event-tickets' ) );
		}

		$return = $this->get_panels( $post_id );
		$return['notice'] = $this->notice( 'ticket-add' );

		/**
		 * Filters the return data for ticket add
		 *
		 * @param array $return Array of data to return to the ajax call
		 * @param int $post_id ID of parent "event" post
		 */
		$return = apply_filters( 'event_tickets_ajax_ticket_add_data', $return, $post_id );

		wp_send_json_success( $return );
	}

	/**
	 * Returns the data from a single ticket to populate
	 * the edit form.
	 *
	 * @since  4.6.2
	 *
	 * @return array $return array of ticket data
	 */
	public function ajax_ticket_edit() {
		$post_id = absint( tribe_get_request_var( 'post_id', 0 ) );

		if ( ! $post_id ) {
			wp_send_json_error( esc_html__( 'Invalid parent Post', 'event-tickets' ) );
		}

		$ticket_id = absint( tribe_get_request_var( 'ticket_id', 0 ) );

		if ( ! $ticket_id ) {
			wp_send_json_error( esc_html__( 'Invalid Ticket', 'event-tickets' ) );
		}

		/**
		 * This is needed because a provider can implement a dynamic set of fields.
		 * Each provider is responsible for sanitizing these values.
		 */
		$data = wp_parse_args( tribe_get_request_var( array( 'data' ), array() ), array() );

		if ( ! $this->has_permission( $post_id, $_POST, 'edit_ticket_nonce' ) ) {
			wp_send_json_error( esc_html__( 'Failed to Edit the Ticket, Refresh the Page to try again.', 'event-tickets' ) );
		}

		$provider = tribe_tickets_get_ticket_provider( $ticket_id );

		if ( ! $provider ) {
			wp_send_json_error( esc_html__( 'Commerce Module invalid', 'event-tickets' ) );
		}

		// Get the Ticket Object
		$ticket = $provider->get_ticket( $post_id, $ticket_id );
		$return = $this->get_panels( $post_id, $ticket_id );

		/**
		 * Provides an opportunity for final adjustments to the data used to populate
		 * the edit-ticket form.
		 *
		 * @param array $return     Data for the JSON response
		 * @param int   $post_id    Post ID
		 * @param int   $ticket_id  Ticket ID
		 */
		$return = (array) apply_filters( 'tribe_events_tickets_ajax_ticket_edit', $return, $post_id, $ticket_id );

		wp_send_json_success( $return );
	}

	/**
	 * Sanitizes the data for the delete ticket ajax call, and calls the child delete_ticket
	 * function.
	 *
	 * @since  4.6.2
	 */
	public function ajax_ticket_delete() {
		$post_id = absint( tribe_get_request_var( 'post_id', 0 ) );

		if ( ! $post_id ) {
			wp_send_json_error( esc_html__( 'Invalid parent Post', 'event-tickets' ) );
		}

		$ticket_id = absint( tribe_get_request_var( 'ticket_id', 0 ) );

		if ( ! $ticket_id ) {
			wp_send_json_error( esc_html__( 'Invalid Ticket', 'event-tickets' ) );
		}

		if ( ! $this->has_permission( $post_id, $_POST, 'remove_ticket_nonce' ) ) {
			wp_send_json_error( esc_html__( 'Failed to Delete the Ticket, Refresh the Page to try again.', 'event-tickets' ) );
		}

		$provider = tribe_tickets_get_ticket_provider( $ticket_id );

		if ( ! $provider ) {
			wp_send_json_error( esc_html__( 'Commerce Module invalid', 'event-tickets' ) );
		}

		// Pass the control to the child object
		$return = $provider->delete_ticket( $post_id, $ticket_id );

		// Successfully deleted?
		if ( $return ) {
			$return = $this->get_panels( $post_id );
			$return['notice'] = $this->notice( 'ticket-delete' );

			/**
			 * Fire action when a ticket has been deleted
			 *
			 * @param int $post_id ID of parent "event" post
			 */
			do_action( 'tribe_tickets_ticket_deleted', $post_id );
		}

		wp_send_json_success( $return );
	}

	/**
	 * Handles the check-in ajax call, and calls the checkin method.
	 *
	 * @since  4.6.2
	 */
	public function ajax_attendee_checkin() {
		$event_id    = Tribe__Utils__Array::get( $_POST, 'event_ID', false );
		$attendee_id = Tribe__Utils__Array::get( $_POST, 'attendee_id', false );

		if ( empty( $attendee_id ) ) {
			wp_send_json_error( __( 'The attendee ID is missing from the request parameters.', 'event-tickets' ) );
		}

		$provider = Tribe__Utils__Array::get( $_POST, 'provider', false );

		if ( empty( $provider ) || ! $this->module_is_valid( $provider ) ) {
			wp_send_json_error( esc_html__( 'Commerce Module invalid', 'event-tickets' ) );
		}

		$provider = call_user_func( array( $provider, 'get_instance' ) );

		if (
			empty( $_POST['nonce'] )
			|| ! wp_verify_nonce( $_POST['nonce'], 'checkin' )
			|| ! $this->user_can( 'edit_posts', $attendee_id )
		) {
			wp_send_json_error( "Cheatin' huh?" );
		}

		// Pass the control to the child object
		$did_checkin = $provider->checkin( $attendee_id );

		$provider->clear_attendees_cache( $event_id );

		wp_send_json_success( $did_checkin );
	}

	/**
	 * Handles the check-in ajax call, and calls the uncheckin method.
	 *
	 * @since  4.6.2
	 */
	public function ajax_attendee_uncheckin() {
		$event_id    = Tribe__Utils__Array::get( $_POST, 'event_ID', false );
		$attendee_id = Tribe__Utils__Array::get( $_POST, 'attendee_id', false );

		if ( empty( $attendee_id ) ) {
			wp_send_json_error( __( 'The attendee ID is missing from the request parameters.', 'event-tickets' ) );
		}

		$provider = Tribe__Utils__Array::get( $_POST, 'provider', false );

		if ( empty( $provider ) || ! $this->module_is_valid( $provider ) ) {
			wp_send_json_error( esc_html__( 'Commerce Module invalid', 'event-tickets' ) );
		}

		$provider = call_user_func( array( $provider, 'get_instance' ) );

		if (
			empty( $_POST['nonce'] )
			|| ! wp_verify_nonce( $_POST['nonce'], 'uncheckin' )
			|| ! $this->user_can( 'edit_posts', $attendee_id )
		) {
			wp_send_json_error( "Cheatin' huh?" );
		}

		// Pass the control to the child object
		$did_uncheckin = $provider->uncheckin( $attendee_id );

		$provider->clear_attendees_cache( $event_id );

		wp_send_json_success( $did_uncheckin );
	}

	/**
	 * Get the controls (move, delete) as a string
	 *
	 * @since  4.6.2
	 *
	 * @param  array   $post_id
	 * @param  array   $ticket_id
	 * @param  boolean $echo
	 *
	 * @return string
	 */
	public function get_ticket_controls( $post_id, $ticket_id = null, $echo = true ) {
		$provider = tribe_tickets_get_ticket_provider( $ticket_id );

		if ( ! $provider ) {
			return false;
		}

		if ( ! $ticket_id ) {
			return false;
		}

		$ticket = $provider->get_ticket( $post_id, $ticket_id );

		if ( empty( $ticket ) ) {
			return false;
		}

		$controls = array();

		if ( tribe_is_truthy( tribe_get_request_var( 'is_admin', true ) ) ) {
			$controls[] = $provider->get_ticket_move_link( $post_id, $ticket );
		}
		$controls[] = $provider->get_ticket_delete_link( $ticket );

		$html = join( ' | ', $controls );

		if ( $echo )  {
			echo $html;
		}

		return $html;
	}

	/**
	 * test if the nonce is correct and the current user has the correct permissions
	 *
	 * @since  4.6.2
	 *
	 * @param  WP_Post  $post
	 * @param  array   $data
	 * @param  string  $nonce_action
	 *
	 * @return boolean
	 */
	public function has_permission( $post, $data, $nonce_action ) {

		if ( ! $post instanceof WP_Post ) {
			if ( ! is_numeric( $post ) ) {
				return false;
			}

			$post = get_post( $post );
		}

		if ( empty( $data['nonce'] ) || ! wp_verify_nonce( $data['nonce'], $nonce_action ) ) {
			return false;
		}

		return current_user_can( 'edit_event_tickets' ) || current_user_can( get_post_type_object( $post->post_type )->cap->edit_posts );
	}

	/**
	 * Tests if the user has the specified capability in relation to whatever post type
	 * the attendee object relates to.
	 *
	 * For example, if the attendee was generated for a ticket set up in relation to a
	 * post of the `banana` type, the generic capability "edit_posts" will be mapped to
	 * "edit_bananas" or whatever is appropriate.
	 *
	 * @internal for internal plugin use only (in spite of having public visibility)
	 *
	 * @since  4.6.2
	 *
	 * @see    tribe( 'tickets.attendees' )->user_can
	 *
	 * @param  string $generic_cap
	 * @param  int    $attendee_id
	 *
	 * @return boolean
	 */
	public function user_can( $generic_cap, $attendee_id ) {
		$connections = tribe( 'tickets.handler' )->get_object_connections( $attendee_id );

		if ( ! $connections->event ) {
			return false;
		}

		return tribe( 'tickets.attendees' )->user_can( $generic_cap, $connections->event );
	}


	/**
	 * Returns whether a class name is a valid active module/provider.
	 *
	 * @since  4.6.2
	 *
	 * @param  string  $module  class name of module
	 *
	 * @return bool
	 */
	public function module_is_valid( $module ) {
		return array_key_exists( $module, Tribe__Tickets__Tickets::modules() );
	}

	/**
	 * Returns the markup for a notice in the admin
	 *
	 * @since  4.6.2
	 *
	 * @param  string $msg Text for the notice
	 *
	 * @return string Notice with markup
	 */
	protected function notice( $msg ) {
		return sprintf( '<div class="wrap"><div class="updated"><p>%s</p></div></div>', $msg );
	}

	/**
	 * Decimal Character Asset Localization (used on Community Tickets)
	 *
	 * @todo   We need to deprecate this
	 *
	 * @return void
	 */
	public static function localize_decimal_character() {
		$locale  = localeconv();
		$decimal = isset( $locale['decimal_point'] ) ? $locale['decimal_point'] : '.';

		/**
		 * Filter the decimal point character used in the price
		 */
		$decimal = apply_filters( 'tribe_event_ticket_decimal_point', $decimal );

		wp_localize_script( 'event-tickets-js', 'price_format', array(
			'decimal' => $decimal,
			'decimal_error' => __( 'Please enter in without thousand separators and currency symbols.', 'event-tickets' ),
		) );
	}


	/************************
	 *                      *
	 *  Deprecated Methods  *
	 *                      *
	 ************************/
	// @codingStandardsIgnoreStart

	/**
	 * Refreshes panel settings after canceling saving
	 *
	 * @deprecated 4.6.2
	 * @since 4.6
	 *
	 * @return string html content of the panel settings
	 */
	public function ajax_refresh_settings() {

	}

	/**
	 * @deprecated 4.6.2
	 *
	 * @return void
	 */
	public function ajax_handler_save_settings() {

	}

	/**
	 * Registers the tickets metabox if there's at least
	 * one Tribe Tickets module (provider) enabled
	 *
	 * @deprecated 4.6.2
	 *
	 * @param $post_type
	 */
	public static function maybe_add_meta_box( $post_type ) {
		tribe( 'tickets.metabox' )->configure( $post_type );
	}

	/**
	 * Loads the content of the tickets metabox if there's at
	 * least one Tribe Tickets module (provider) enabled
	 *
	 * @deprecated 4.6.2
	 *
	 * @param $post_id
	 */
	public static function do_modules_metaboxes( $post_id ) {
		tribe( 'tickets.metabox' )->render( $post_id );
	}

	/**
	 * Enqueue the tickets metabox JS and CSS
	 *
	 * @deprecated 4.6
	 *
	 * @param $unused_hook
	 */
	public static function add_admin_scripts( $unused_hook ) {
		_deprecated_function( __METHOD__, '4.6', 'Tribe__Tickets__Assets::admin_enqueue_scripts' );
	}

	// @codingStandardsIgnoreEnd
}

Top ↑

Methods

  • ajax_attendee_checkin — Handles the check-in ajax call, and calls the checkin method.
  • ajax_attendee_uncheckin — Handles the check-in ajax call, and calls the uncheckin method.
  • ajax_panels — Refreshes panels after ajax calls that change data
  • ajax_ticket_add — Sanitizes the data for the new/edit ticket ajax call, and calls the child save_ticket function.
  • ajax_ticket_delete — Sanitizes the data for the delete ticket ajax call, and calls the child delete_ticket function.
  • ajax_ticket_duplicate — Sanitizes the data for the duplicate ticket ajax call, then duplicates the ticket and meta.
  • ajax_ticket_edit — Returns the data from a single ticket to populate the edit form.
  • configure — Configures the Tickets Editor into a Post Type
  • get_panels — Get the Panels for a given post.
  • get_ticket_controls — Get the controls (move, delete) as a string.
  • has_permission — test if the nonce is correct and the current user has the correct permissions
  • hook — Configure all action and filters user by this Class
  • localize_decimal_character — Decimal Character Asset Localization (used on Community Tickets)
  • module_is_valid — Returns whether a class name is a valid active module/provider.
  • render — Render the actual Metabox
  • user_can — Tests if the user has the specified capability in relation to whatever post type the attendee object relates to.