eventbrite-for-the-events-c.../includes/class-eb4tec-frontend.php
Laurence Horrocks-Barlow f3bc795d9a 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.
2026-05-17 08:48:04 +01:00

196 lines
5 KiB
PHP

<?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;
}
';
}
}