Bidirectional sync between Eventbrite and The Events Calendar, with WooCommerce ticket purchasing that bypasses Eventbrite's processing fees by registering buyers as free attendees via API. Includes venue/ organizer sync, QR code ticket generation, attendee management with CSV export, scheduled sync via WP-Cron, and real-time Eventbrite webhooks.
162 lines
4.6 KiB
PHP
162 lines
4.6 KiB
PHP
<?php
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
final class EB4TEC_Shortcodes {
|
|
|
|
public function __construct(
|
|
private readonly EB4TEC_API_Client $api,
|
|
private readonly EB4TEC_Ticket_Manager $ticket_manager,
|
|
) {
|
|
add_action( 'init', [ $this, 'register_shortcodes' ] );
|
|
}
|
|
|
|
public function register_shortcodes(): void {
|
|
add_shortcode( 'eb4tec_capacity', [ $this, 'capacity_shortcode' ] );
|
|
add_shortcode( 'eb4tec_tickets', [ $this, 'tickets_shortcode' ] );
|
|
}
|
|
|
|
/**
|
|
* [eb4tec_capacity event_id="123" post_id="456"]
|
|
* Renders remaining ticket capacity for an event.
|
|
*/
|
|
public function capacity_shortcode( array $atts ): string {
|
|
$post_id = $this->resolve_post_id( $atts );
|
|
if ( ! $post_id ) {
|
|
return '';
|
|
}
|
|
|
|
$total = (int) get_post_meta( $post_id, '_eb4tec_capacity', true );
|
|
$available = $this->ticket_manager->get_available_capacity( $post_id );
|
|
|
|
if ( $total <= 0 ) {
|
|
return '';
|
|
}
|
|
|
|
if ( $available <= 0 ) {
|
|
return '<span class="eb4tec-capacity eb4tec-capacity--sold-out">' .
|
|
esc_html__( 'Sold out', 'eb4tec' ) .
|
|
'</span>';
|
|
}
|
|
|
|
return sprintf(
|
|
'<span class="eb4tec-capacity">%s</span>',
|
|
esc_html( sprintf(
|
|
/* translators: 1: available spots, 2: total capacity */
|
|
_n( '%1$d of %2$d spot remaining', '%1$d of %2$d spots remaining', $available, 'eb4tec' ),
|
|
$available,
|
|
$total
|
|
) )
|
|
);
|
|
}
|
|
|
|
/**
|
|
* [eb4tec_tickets event_id="123" post_id="456"]
|
|
* Renders a list of public Eventbrite ticket classes with a Buy button.
|
|
*/
|
|
public function tickets_shortcode( array $atts ): string {
|
|
$post_id = $this->resolve_post_id( $atts );
|
|
if ( ! $post_id ) {
|
|
return '';
|
|
}
|
|
|
|
$eb_event_id = (string) get_post_meta( $post_id, '_eb4tec_event_id', true );
|
|
if ( ! $eb_event_id ) {
|
|
return '';
|
|
}
|
|
|
|
$result = $this->api->get_ticket_classes( $eb_event_id );
|
|
if ( is_wp_error( $result ) ) {
|
|
return '';
|
|
}
|
|
|
|
$ticket_classes = $result['ticket_classes'] ?? [];
|
|
$wp_label = strtolower( (string) get_option( 'eb4tec_wp_ticket_label', 'WordPress Purchase' ) );
|
|
$product_id = (int) get_post_meta( $post_id, '_eb4tec_wp_product_id', true );
|
|
$buy_url = $product_id ? get_permalink( $product_id ) : '';
|
|
|
|
// Filter out the hidden WordPress Purchase class.
|
|
$public_classes = array_filter( $ticket_classes, function( array $tc ) use ( $wp_label ): bool {
|
|
return strtolower( $tc['name'] ?? '' ) !== $wp_label;
|
|
} );
|
|
|
|
if ( empty( $public_classes ) ) {
|
|
return '';
|
|
}
|
|
|
|
$output = '<ul class="eb4tec-ticket-classes">';
|
|
|
|
foreach ( $public_classes as $tc ) {
|
|
$name = esc_html( $tc['name'] ?? '' );
|
|
$description = esc_html( $tc['description'] ?? '' );
|
|
$free = ! empty( $tc['free'] );
|
|
$price = $free ? esc_html__( 'Free', 'eb4tec' ) : esc_html( $tc['cost']['display'] ?? '' );
|
|
$sold_out = ! empty( $tc['sold_out'] );
|
|
$hidden = ! empty( $tc['hidden'] );
|
|
|
|
if ( $hidden ) {
|
|
continue;
|
|
}
|
|
|
|
$output .= '<li class="eb4tec-ticket-class">';
|
|
$output .= '<strong class="eb4tec-ticket-name">' . $name . '</strong>';
|
|
if ( $description ) {
|
|
$output .= ' <span class="eb4tec-ticket-description">' . $description . '</span>';
|
|
}
|
|
$output .= ' <span class="eb4tec-ticket-price">' . $price . '</span>';
|
|
|
|
if ( $sold_out ) {
|
|
$output .= ' <span class="eb4tec-ticket-sold-out">' . esc_html__( 'Sold out', 'eb4tec' ) . '</span>';
|
|
}
|
|
$output .= '</li>';
|
|
}
|
|
|
|
$output .= '</ul>';
|
|
|
|
// Add Buy Tickets button if a WC product exists.
|
|
if ( $buy_url ) {
|
|
$available = $this->ticket_manager->get_available_capacity( $post_id );
|
|
if ( $available > 0 ) {
|
|
$output .= sprintf(
|
|
'<a href="%s" class="button eb4tec-buy-button">%s</a>',
|
|
esc_url( $buy_url ),
|
|
esc_html__( 'Buy Tickets', 'eb4tec' )
|
|
);
|
|
} else {
|
|
$output .= '<span class="eb4tec-sold-out-badge">' . esc_html__( 'Sold Out', 'eb4tec' ) . '</span>';
|
|
}
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
private function resolve_post_id( array $atts ): int {
|
|
$atts = shortcode_atts( [
|
|
'post_id' => 0,
|
|
'event_id' => '',
|
|
], $atts );
|
|
|
|
if ( ! empty( $atts['post_id'] ) ) {
|
|
return (int) $atts['post_id'];
|
|
}
|
|
|
|
if ( ! empty( $atts['event_id'] ) ) {
|
|
// Look up TEC post by Eventbrite event ID.
|
|
$query = new WP_Query( [
|
|
'post_type' => 'tribe_events',
|
|
'post_status' => [ 'publish', 'draft' ],
|
|
'posts_per_page' => 1,
|
|
'fields' => 'ids',
|
|
'meta_query' => [ [
|
|
'key' => '_eb4tec_event_id',
|
|
'value' => sanitize_text_field( $atts['event_id'] ),
|
|
] ],
|
|
] );
|
|
return $query->posts[0] ?? 0;
|
|
}
|
|
|
|
// Default to the current event in the loop.
|
|
return get_the_ID() ?: 0;
|
|
}
|
|
}
|