QR Scannar App for EventON QR Code Addon

If you want to sell event tickets based on a predefined seat plan, the EventON plugin is the best solution.  To validate attendees a QR code is generated with each ticket. By default, EventON does not provide any QR code Scanner app. However, you can scan the QR codes using your phone camera or any app available in Google Playstore or Apple App Store. But the process is a bit slow when you have to scan thousands of ticket QR codes. So I have developed one APP to make ticket scanning quicker and easier.

Instead of using the plugin’s default ticket-checking system, I use WordPress REST API to validate the tickets.  To use the APP, please follow the steps given below:

Step 1: To enable WordPress Rest Api for ticket QR scanning, write down the following codes in your function.php file of your WordPress theme.

//////////////////////////////////////////////////
// Get list of active events and ticket statistics
//////////////////////////////////////////////////
function register_get_active_events()
{
    register_rest_route('event/v1', 'active/(?P<key>[a-zA-Z0-9-]+)', [
        'methods'  => WP_REST_SERVER::READABLE,
        'callback' => 'get_active_events'
    ]);
}

function get_active_events($data){
    if($data['key'] == 'YOUR_SECRET_KEY'){
        $events = get_posts(array(
            'posts_per_page' => -1,
            'post_type' => 'ajde_events',
            'event_type' => 'Checkin', //ticket category = checkin, only check the events which's ticket selling is stopped.
        ));
        
        $event_list = [];
        
        for ($c = 0; $c < count($events); $c++){
            
            $post_ID = $events[$c]->ID;
            
            $ticket_checked = get_posts(array(
                'posts_per_page'    => -1,
                'post_type'     => 'evo-tix',
                 'meta_query' => array(
                     'relation' => 'AND',
                     array(
                         array(
                         'key' => 'status',
                         'value' => array('checked'),
                         'compare' => '='
                         ),
                         array(
                         'key' => '_eventid',
                         'value' => $post_ID,
                         'compare' => '='
                         ),
                     ),
                 ),
            ));
            
            $ticket_unchecked = get_posts(array(
                'posts_per_page'    => -1,
                'post_type'     => 'evo-tix',
                 'meta_query' => array(
                     'relation' => 'AND',
                     array(
                         array(
                         'key' => 'status',
                         'value' => array('check-in'),
                         'compare' => '='
                         ),
                         array(
                         'key' => '_eventid',
                         'value' => $post_ID,
                         'compare' => '='
                         ),
                     ),
                 ),
            ));
            
            if( (count($ticket_unchecked)>0) || (count($ticket_checked)>0) ){
                
                $event_list[] = array(
                    'event_thumbnail' => get_the_post_thumbnail_url($post_ID),
                    'event_title' => html_entity_decode(get_the_title($post_ID), ENT_QUOTES, 'UTF-8'),
                    'unchecked' => count($ticket_unchecked),
                    'checked' => count($ticket_checked),
                    'total_tickets_sold' => (count($ticket_unchecked) + count($ticket_checked)),
                    'event_id' => $post_ID,
                );
            }
        }
        
        return $event_list;
    }else{
         echo('Wrong secret key!');
    }
}

add_action('rest_api_init', 'register_get_active_events');




///////////////////////////////////////
// Scan QR code to update ticket status
///////////////////////////////////////

function register_get_checkin_checked_route()
{
    register_rest_route('event', 'checkin/(?P<id>[a-zA-Z0-9-]+)', [
        'methods'  => WP_REST_SERVER::READABLE,
        'callback' => 'checkin_ticket_number_c'
    ]);
}


 function checkin_ticket_number_c($data){
     
    $ticket_id = EVOQR()->checkin->decrypt_ticket_number($data['id']);
     
	$ET = new evotx_tix();
	$evotx_id = $ET->evo_tix_id = $ET->get_evotix_id_by_ticketnumber( $ticket_id );

	$TIX = new EVO_Evo_Tix_CPT( $evotx_id );
    $current_status = $TIX->get_status();
    
    if ($current_status == 'checked'){
        $ticket_status_ = "Already Checked!";
    }else{
        $ticket_status_ = 'Checked Successfully';
    }
    
    if($current_status == 'check-in'){
        $TIX->set_status('checked');
        // $status = 'Checked';
    }
    
    $TIX = new EVO_Evo_Tix_CPT( $ticket_id );
    $ticket_data = $TIX->get_props();
    
    // $xx = EVOQR()->api->checkin_ticket_number('11339-11338-11209T0');

    $EVENT = new EVO_Event($ticket_data['_eventid'][0]);
	// event time
	$output['event-time'] = $EVENT->get_formatted_smart_time();


    $ticket_data_filtered[] = array(
        'event_title' => "Event: ".html_entity_decode(get_the_title($ticket_data['_eventid'][0]), ENT_QUOTES, 'UTF-8'),
        'event_datetime' => "Date & time: ".html_entity_decode($output['event-time']),
        'ticket_holder_information' => maybe_unserialize($ticket_data['_ticket_holder_data'][0]),
        'ticket_id' => "Ticket ID: ".$ticket_id,
        'ticket_status' => $ticket_status_,
        'seat_number' => "Seat Number: ".$ticket_data['_seat_number'][0],
    );
    
    
	return $ticket_data_filtered;
}

add_action('rest_api_init', 'register_get_checkin_checked_route');



///////////////////////////////////////
// Uncheck ticket status
///////////////////////////////////////

function register_get_checkin_uncheck_route()
{
    register_rest_route('event', 'uncheck/(?P<id>[a-zA-Z0-9-]+)', [
        'methods'  => WP_REST_SERVER::READABLE,
        'callback' => 'checkin_ticket_number_uc'
    ]);
}


 function checkin_ticket_number_uc($data){
     
    $ticket_id = EVOQR()->checkin->decrypt_ticket_number($data['id']);
     
	$ET = new evotx_tix();
	$evotx_id = $ET->evo_tix_id = $ET->get_evotix_id_by_ticketnumber( $ticket_id );


    $TIX = new EVO_Evo_Tix_CPT( $evotx_id );
    $current_status = $TIX->get_status();
    
    if ($current_status == 'check-in'){
        $ticket_status_ = "Not checked yet!";
    }else{
        $ticket_status_ = 'Unchecked Successfully';
    }
    
    if($current_status == 'checked'){
         $TIX->set_status( 'check-in');
        //  $status = 'Check-in';
    }
    
    $TIX = new EVO_Evo_Tix_CPT( $ticket_id );
    $ticket_data = $TIX->get_props();

    $EVENT = new EVO_Event($ticket_data['_eventid'][0]);
	// event time
	$output['event-time'] = $EVENT->get_formatted_smart_time();


    $ticket_data_filtered[] = array(
        'event_title' => "Event: ".html_entity_decode(get_the_title($ticket_data['_eventid'][0]), ENT_QUOTES, 'UTF-8'),
        'event_datetime' => "Date & time: ".html_entity_decode($output['event-time']),
        'ticket_holder_information' => maybe_unserialize($ticket_data['_ticket_holder_data'][0]),
        'ticket_id' => "Ticket ID: ".$ticket_id,
        'ticket_status' => $ticket_status_,
        'seat_number' => "Seat Number: ".$ticket_data['_seat_number'][0],
    );
    
    
	return $ticket_data_filtered;
}

add_action('rest_api_init', 'register_get_checkin_uncheck_route');



///////////////////////////////////////
// Get list of attendees
///////////////////////////////////////

function register_get_list_of_attendees_route()
{
    register_rest_route('event/v1', 'list_of_attendees/(?P<id>[a-zA-Z0-9-]+)/(?P<key>[a-zA-Z0-9-]+)', [
        'methods'  => WP_REST_SERVER::READABLE,
        'callback' => 'list_of_attendees'
    ]);
}


function list_of_attendees($data){
    if($data['key'] == 'YOUR_SECRET_KEY'){
    	$EA = new EVOTX_Attendees();
    	$TH = $EA->get_tickets_for_event($data['id']);
    
    	$tickets = array_keys($TH);
    	
    	$data = [];
    	
    	foreach ($tickets as $ticket){
    	    
    	    $data[] = [
    	   	    'name' => $TH[$ticket]['name'],
    	        'email' => $TH[$ticket]['email'],
    	        'phone' => $TH[$ticket]['phone'],
    	        'seat_number' => $TH[$ticket]['oD']['seat_number'],     
    	        'event_name' => html_entity_decode($TH[$ticket]['oD']['event_title'], ENT_QUOTES, 'UTF-8'),     
    	        'ticket_status' => html_entity_decode($TH[$ticket]['s'], ENT_QUOTES, 'UTF-8'),     
    	        'ticket_number' => $ticket,     
    	   ];
    	}
        
        return $data;  
    }else{
        echo('Wrong secret key!');
    }
}
 
add_action('rest_api_init', 'register_get_list_of_attendees_route');



///////////////////////////////////////
// Verify API Credentials
///////////////////////////////////////

function register_verify_api_credentials_route()
{
    register_rest_route('event/v1', 'verify/(?P<key>[a-zA-Z0-9-]+)', [
        'methods'  => WP_REST_SERVER::READABLE,
        'callback' => 'verify_api_credentials'
    ]);
}


function verify_api_credentials($data){
    
    $key = $data['key'];
    
    if($key == 'YOUR_SECRET_KEY'){
        echo('ok'); 
    }else{
        echo('Wrong secret key!');
    }
}
 
add_action('rest_api_init', 'register_verify_api_credentials_route');

Step 2: Please update YOUR_SECRET_KEY on the code above, consider this as a password or security key of the API.

Step 3: Create an event type (category) named “Checkin” (it does not need to be exaclty “Checkin”, it could be anything you want.). You can customize the category name according to your own choice, check line 17 of the above code. In the event list window of the APP, events with the ‘Checkin’ category will appear only. You can comment on line 17 if you want to list all the events on the event window on the APP.

Step 4: Download the APP, go to the settings window and set up your website URL and Secret Key (the same key you set in Step 2). Make sure your app URL do not contain a slash “/” after the URL (e.g. http://yourwebsite.com not http://yourwebsite.com/)

Note: Since the app is not published on Google Play Store, you will have to allow the ‘Install Unsafe App’ option.

You are done! Please contact me if you find any problems using the app. I am happy to resolve any issue or add new features.