Initial release of Eventbrite for The Events Calendar (v1.0.0)
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.
This commit is contained in:
commit
f3bc795d9a
15 changed files with 3132 additions and 0 deletions
162
includes/class-eb4tec-shortcodes.php
Normal file
162
includes/class-eb4tec-shortcodes.php
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue