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
196
includes/class-eb4tec-frontend.php
Normal file
196
includes/class-eb4tec-frontend.php
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
final class EB4TEC_Frontend {
|
||||
|
||||
public function __construct( private readonly EB4TEC_Ticket_Manager $ticket_manager ) {
|
||||
add_action( 'tribe_events_single_event_after_the_meta', [ $this, 'after_event_meta' ] );
|
||||
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ] );
|
||||
}
|
||||
|
||||
public function after_event_meta(): void {
|
||||
$post_id = get_the_ID();
|
||||
if ( ! $post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$eb_event_id = (string) get_post_meta( $post_id, '_eb4tec_event_id', true );
|
||||
$product_id = (int) get_post_meta( $post_id, '_eb4tec_wp_product_id', true );
|
||||
$eb_url = (string) get_post_meta( $post_id, '_eb4tec_eb_url', true );
|
||||
|
||||
// Don't render if there's no Eventbrite link and no WC product.
|
||||
if ( ! $eb_event_id && ! $product_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if event has ended.
|
||||
$end_date = (string) get_post_meta( $post_id, '_EventEndDate', true );
|
||||
$timezone = (string) get_post_meta( $post_id, '_EventTimezone', true ) ?: wp_timezone_string();
|
||||
$has_ended = false;
|
||||
if ( $end_date ) {
|
||||
try {
|
||||
$tz_obj = new DateTimeZone( $timezone );
|
||||
$end_dt = new DateTime( $end_date, $tz_obj );
|
||||
$now = new DateTime( 'now', $tz_obj );
|
||||
$has_ended = $now > $end_dt;
|
||||
} catch ( \Exception ) {
|
||||
// Keep $has_ended = false.
|
||||
}
|
||||
}
|
||||
|
||||
echo '<div class="eb4tec-ticket-section">';
|
||||
|
||||
if ( $product_id && ! $has_ended ) {
|
||||
$this->render_capacity_bar( $post_id );
|
||||
$this->render_buy_button( $post_id, $product_id );
|
||||
} elseif ( $has_ended ) {
|
||||
echo '<p class="eb4tec-event-ended">' . esc_html__( 'This event has ended.', 'eb4tec' ) . '</p>';
|
||||
}
|
||||
|
||||
if ( $eb_url ) {
|
||||
echo '<p class="eb4tec-eb-link"><a href="' . esc_url( $eb_url ) . '" target="_blank" rel="noopener">' .
|
||||
esc_html__( 'View on Eventbrite', 'eb4tec' ) . ' ↗</a></p>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
private function render_capacity_bar( int $post_id ): void {
|
||||
$total = (int) get_post_meta( $post_id, '_eb4tec_capacity', true );
|
||||
$available = $this->ticket_manager->get_available_capacity( $post_id );
|
||||
|
||||
if ( $total <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sold = max( 0, $total - $available );
|
||||
$percent = (int) round( ( $sold / $total ) * 100 );
|
||||
|
||||
echo '<div class="eb4tec-capacity-wrap">';
|
||||
printf(
|
||||
'<div class="eb4tec-capacity-bar" role="progressbar" aria-valuenow="%d" aria-valuemin="0" aria-valuemax="%d"><div class="eb4tec-capacity-bar__fill" style="width:%d%%"></div></div>',
|
||||
$sold,
|
||||
$total,
|
||||
$percent
|
||||
);
|
||||
|
||||
if ( $available > 0 ) {
|
||||
echo '<p class="eb4tec-capacity-label">' . esc_html( sprintf(
|
||||
/* translators: 1: available spots, 2: total */
|
||||
_n( '%1$d of %2$d spot remaining', '%1$d of %2$d spots remaining', $available, 'eb4tec' ),
|
||||
$available,
|
||||
$total
|
||||
) ) . '</p>';
|
||||
} else {
|
||||
echo '<p class="eb4tec-capacity-label eb4tec-capacity-label--sold-out">' . esc_html__( 'Sold out', 'eb4tec' ) . '</p>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
private function render_buy_button( int $post_id, int $product_id ): void {
|
||||
$available = $this->ticket_manager->get_available_capacity( $post_id );
|
||||
$button_html = '';
|
||||
|
||||
if ( $available > 0 ) {
|
||||
$product_url = get_permalink( $product_id );
|
||||
$button_html = sprintf(
|
||||
'<a href="%s" class="button eb4tec-buy-button">%s</a>',
|
||||
esc_url( $product_url ),
|
||||
esc_html__( 'Buy Tickets', 'eb4tec' )
|
||||
);
|
||||
} else {
|
||||
$button_html = '<span class="eb4tec-sold-out-badge">' . esc_html__( 'Sold Out', 'eb4tec' ) . '</span>';
|
||||
}
|
||||
|
||||
echo apply_filters( 'eb4tec_ticket_button_html', $button_html, $post_id );
|
||||
}
|
||||
|
||||
public function enqueue_styles(): void {
|
||||
if ( ! is_singular( 'tribe_events' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_register_style( 'eb4tec-frontend', false );
|
||||
wp_enqueue_style( 'eb4tec-frontend' );
|
||||
wp_add_inline_style( 'eb4tec-frontend', $this->get_inline_css() );
|
||||
}
|
||||
|
||||
private function get_inline_css(): string {
|
||||
return '
|
||||
.eb4tec-ticket-section {
|
||||
margin: 20px 0;
|
||||
padding: 16px 0;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
.eb4tec-capacity-wrap {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.eb4tec-capacity-bar {
|
||||
background: #e5e5e5;
|
||||
border-radius: 4px;
|
||||
height: 8px;
|
||||
overflow: hidden;
|
||||
max-width: 300px;
|
||||
}
|
||||
.eb4tec-capacity-bar__fill {
|
||||
background: #2271b1;
|
||||
height: 100%;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
.eb4tec-capacity-label {
|
||||
font-size: 0.875em;
|
||||
color: #555;
|
||||
margin: 4px 0 0;
|
||||
}
|
||||
.eb4tec-capacity-label--sold-out {
|
||||
color: #d63638;
|
||||
font-weight: 600;
|
||||
}
|
||||
.eb4tec-buy-button {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #2271b1;
|
||||
color: #fff !important;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.eb4tec-buy-button:hover {
|
||||
background: #135e96;
|
||||
}
|
||||
.eb4tec-sold-out-badge {
|
||||
display: inline-block;
|
||||
padding: 8px 16px;
|
||||
background: #d63638;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.eb4tec-event-ended {
|
||||
color: #555;
|
||||
font-style: italic;
|
||||
}
|
||||
.eb4tec-eb-link {
|
||||
margin-top: 8px;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
.eb4tec-ticket-classes {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
.eb4tec-ticket-class {
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.eb4tec-ticket-sold-out {
|
||||
color: #d63638;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
';
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue