monorepo/native/wordpress/ticket-tailor-wp-max/includes/class-blocks.php

547 lines
24 KiB
PHP

<?php
/**
* Ticket Tailor Blocks
* Enhanced with full-width support and responsive columns
* FIXED: Removed spacers that were making cards too tall
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
class Ticket_Tailor_Blocks {
/**
* Event Manager
*/
private $events;
/**
* Constructor
*/
public function __construct($events) {
$this->events = $events;
add_action('init', array($this, 'register_blocks'));
add_action('enqueue_block_editor_assets', array($this, 'enqueue_editor_assets'));
}
/**
* Register blocks
*/
public function register_blocks() {
// Event Widget Block (Original)
register_block_type('ticket-tailor/event-widget', array(
'render_callback' => array($this, 'render_event_widget_block'),
'attributes' => array(
'url' => array('type' => 'string', 'default' => ''),
'minimal' => array('type' => 'boolean', 'default' => false),
'bgFill' => array('type' => 'boolean', 'default' => true),
'showLogo' => array('type' => 'boolean', 'default' => true),
'ref' => array('type' => 'string', 'default' => 'website_widget'),
'align' => array('type' => 'string', 'default' => ''),
),
));
// Event Listing Block - ENHANCED
register_block_type('ticket-tailor/event-listing', array(
'render_callback' => array($this, 'render_event_listing_block'),
'attributes' => array(
'limit' => array('type' => 'number', 'default' => 10),
'layout' => array('type' => 'string', 'default' => 'grid'),
'columns' => array('type' => 'number', 'default' => 3),
'columnsMode' => array('type' => 'string', 'default' => 'fixed'),
'showPast' => array('type' => 'boolean', 'default' => false),
'showImage' => array('type' => 'boolean', 'default' => true),
'imageType' => array('type' => 'string', 'default' => 'thumbnail'),
'fullWidth' => array('type' => 'boolean', 'default' => true),
'maxCardWidth' => array('type' => 'string', 'default' => 'none'),
'align' => array('type' => 'string', 'default' => ''),
'className' => array('type' => 'string', 'default' => ''),
),
));
// Single Event Block - ENHANCED
register_block_type('ticket-tailor/single-event', array(
'render_callback' => array($this, 'render_single_event_block'),
'attributes' => array(
'eventId' => array('type' => 'string', 'default' => ''),
'showDescription' => array('type' => 'boolean', 'default' => true),
'showTickets' => array('type' => 'boolean', 'default' => true),
'showImage' => array('type' => 'boolean', 'default' => true),
'imageType' => array('type' => 'string', 'default' => 'header'),
'fullWidth' => array('type' => 'boolean', 'default' => false),
'maxWidth' => array('type' => 'string', 'default' => '800px'),
'align' => array('type' => 'string', 'default' => ''),
),
));
// Category Events Block - ENHANCED
register_block_type('ticket-tailor/category-events', array(
'render_callback' => array($this, 'render_category_events_block'),
'attributes' => array(
'category' => array('type' => 'string', 'default' => ''),
'limit' => array('type' => 'number', 'default' => 10),
'layout' => array('type' => 'string', 'default' => 'grid'),
'columns' => array('type' => 'number', 'default' => 3),
'columnsMode' => array('type' => 'string', 'default' => 'fixed'),
'showImage' => array('type' => 'boolean', 'default' => true),
'imageType' => array('type' => 'string', 'default' => 'thumbnail'),
'fullWidth' => array('type' => 'boolean', 'default' => true),
'align' => array('type' => 'string', 'default' => ''),
),
));
}
/**
* Enqueue editor assets
*/
public function enqueue_editor_assets() {
wp_enqueue_script(
'ticket-tailor-blocks',
TICKET_TAILOR_PLUGIN_URL . 'assets/js/blocks.js',
array('wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-data'),
TICKET_TAILOR_VERSION,
true
);
// Pass events data to editor
$events = $this->events->get_events();
if (!is_wp_error($events)) {
$event_options = array();
foreach ($events as $event) {
$event_options[] = array(
'value' => $event['id'],
'label' => $event['name'],
);
}
wp_localize_script('ticket-tailor-blocks', 'ticketTailorData', array(
'events' => $event_options,
));
}
wp_enqueue_style(
'ticket-tailor-blocks-editor',
TICKET_TAILOR_PLUGIN_URL . 'assets/css/blocks-editor.css',
array('wp-edit-blocks'),
TICKET_TAILOR_VERSION
);
}
/**
* Render event widget block
*/
public function render_event_widget_block($attributes) {
$url = $attributes['url'] ?? '';
$align = $attributes['align'] ?? '';
if (empty($url)) {
return '<div class="tt-block-placeholder">' . esc_html__('Please enter an event URL', 'ticket-tailor') . '</div>';
}
$minimal = $attributes['minimal'] ?? false;
$bg_fill = $attributes['bgFill'] ?? true;
$show_logo = $attributes['showLogo'] ?? true;
$ref = $attributes['ref'] ?? 'website_widget';
// Add alignment class
$wrapper_class = 'tt-widget-block';
if (!empty($align)) {
$wrapper_class .= ' align' . esc_attr($align);
}
// Use shortcode renderer
$shortcode = new Ticket_Tailor_Shortcodes($this->events, null);
$widget_html = $shortcode->event_widget_shortcode(array(
'url' => $url,
'minimal' => $minimal ? 'true' : 'false',
'bg_fill' => $bg_fill ? 'true' : 'false',
'show_logo' => $show_logo ? 'true' : 'false',
'ref' => $ref,
));
return '<div class="' . esc_attr($wrapper_class) . '">' . $widget_html . '</div>';
}
/**
* Render event listing block - ENHANCED
*/
public function render_event_listing_block($attributes) {
$limit = $attributes['limit'] ?? 10;
$layout = $attributes['layout'] ?? 'grid';
$columns = $attributes['columns'] ?? 3;
$columns_mode = $attributes['columnsMode'] ?? 'fixed';
$show_past = $attributes['showPast'] ?? false;
$show_image = $attributes['showImage'] ?? true;
$image_type = $attributes['imageType'] ?? 'thumbnail';
$full_width = $attributes['fullWidth'] ?? true;
$max_card_width = $attributes['maxCardWidth'] ?? 'none';
$align = $attributes['align'] ?? '';
$className = $attributes['className'] ?? '';
// Sanitize image type
if (!in_array($image_type, array('thumbnail', 'header'))) {
$image_type = 'thumbnail';
}
$events = $show_past ? $this->events->get_past_events($limit) : $this->events->get_upcoming_events($limit);
if (is_wp_error($events)) {
return '<div class="tt-error">' . esc_html($events->get_error_message()) . '</div>';
}
if (empty($events)) {
return '<div class="tt-no-events">' . esc_html__('No events found', 'ticket-tailor') . '</div>';
}
ob_start();
// Build wrapper classes
$wrapper_classes = array('tt-event-listing-wrapper');
if ($full_width) {
$wrapper_classes[] = 'tt-full-width';
}
if (!empty($align)) {
$wrapper_classes[] = 'align' . esc_attr($align);
}
if (!empty($className)) {
$wrapper_classes[] = esc_attr($className);
}
// Build listing classes
$class = 'tt-event-listing tt-layout-' . esc_attr($layout);
if ($layout === 'grid') {
if ($columns_mode === 'responsive') {
$class .= ' tt-columns-responsive tt-max-columns-' . esc_attr($columns);
} else {
$class .= ' tt-columns-' . esc_attr($columns);
}
}
// Add inline styles ONLY for responsive mode, not for fixed mode
$style = '';
if ($layout === 'grid' && $columns_mode === 'responsive') {
$min_width = $max_card_width === 'small' ? '280px' :
($max_card_width === 'medium' ? '350px' :
($max_card_width === 'large' ? '450px' : '320px'));
$style = 'style="grid-template-columns: repeat(auto-fit, minmax(' . esc_attr($min_width) . ', 1fr));"';
}
// No inline styles for fixed mode - let CSS classes handle it
?>
<div class="<?php echo esc_attr(implode(' ', $wrapper_classes)); ?>">
<div class="<?php echo esc_attr($class); ?>" <?php echo $style; ?>>
<?php foreach ($events as $event) : ?>
<div class="tt-event-card">
<?php if ($show_image && !empty($event['images'][$image_type])) : ?>
<div class="tt-event-image tt-image-<?php echo esc_attr($image_type); ?>">
<img src="<?php echo esc_url($event['images'][$image_type]); ?>"
alt="<?php echo esc_attr($event['name']); ?>"
loading="lazy">
</div>
<?php endif; ?>
<div class="tt-event-content">
<h3 class="tt-event-title"><?php echo esc_html($event['name']); ?></h3>
<?php if (!empty($event['start']['iso'])) : ?>
<div class="tt-event-date">
<span class="dashicons dashicons-calendar-alt"></span>
<?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($event['start']['iso']))); ?>
</div>
<?php endif; ?>
<?php if (!empty($event['venue']['name'])) : ?>
<div class="tt-event-venue">
<span class="dashicons dashicons-location"></span>
<?php echo esc_html($event['venue']['name']); ?>
</div>
<?php endif; ?>
<?php if ($layout === 'list' && !empty($event['description'])) : ?>
<div class="tt-event-excerpt">
<?php echo esc_html(wp_trim_words($event['description'], 20)); ?>
</div>
<?php endif; ?>
<?php /* REMOVED SPACER - was making cards too tall
<!-- Spacer pushes button to bottom -->
<div class="tt-event-spacer"></div>
*/ ?>
<!-- Button container -->
<?php if (!empty($event['url'])) : ?>
<div class="tt-event-button-container">
<a href="<?php echo esc_url($event['url']); ?>"
class="tt-event-button"
target="_blank"
rel="noopener noreferrer">
<?php esc_html_e('Get Tickets', 'ticket-tailor'); ?>
</a>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php
return ob_get_clean();
}
/**
* Render single event block - ENHANCED
*/
public function render_single_event_block($attributes) {
$event_id = $attributes['eventId'] ?? '';
$show_description = $attributes['showDescription'] ?? true;
$show_tickets = $attributes['showTickets'] ?? true;
$show_image = $attributes['showImage'] ?? true;
$image_type = $attributes['imageType'] ?? 'header';
$full_width = $attributes['fullWidth'] ?? false;
$max_width = $attributes['maxWidth'] ?? '800px';
$align = $attributes['align'] ?? '';
if (empty($event_id)) {
return '<div class="tt-block-placeholder">' . esc_html__('Please select an event', 'ticket-tailor') . '</div>';
}
// Sanitize image type
if (!in_array($image_type, array('thumbnail', 'header'))) {
$image_type = 'thumbnail';
}
$event = $this->events->get_event($event_id);
if (is_wp_error($event)) {
return '<div class="tt-error">' . esc_html($event->get_error_message()) . '</div>';
}
ob_start();
// Build wrapper classes
$wrapper_classes = array('tt-single-event-wrapper');
if (!empty($align)) {
$wrapper_classes[] = 'align' . esc_attr($align);
}
// Build inline styles
$style = '';
if (!$full_width && !empty($max_width)) {
$style = 'style="max-width: ' . esc_attr($max_width) . ';"';
}
?>
<div class="<?php echo esc_attr(implode(' ', $wrapper_classes)); ?>">
<div class="tt-single-event" <?php echo $style; ?>>
<?php if ($show_image && !empty($event['images'][$image_type])) : ?>
<div class="tt-event-header-image">
<img src="<?php echo esc_url($event['images'][$image_type]); ?>"
alt="<?php echo esc_attr($event['name']); ?>"
loading="lazy">
</div>
<?php endif; ?>
<div class="tt-event-details">
<h2 class="tt-event-title"><?php echo esc_html($event['name']); ?></h2>
<div class="tt-event-meta">
<?php if (!empty($event['start']['iso'])) : ?>
<div class="tt-meta-item">
<span class="dashicons dashicons-calendar-alt"></span>
<strong><?php esc_html_e('Date:', 'ticket-tailor'); ?></strong>
<?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($event['start']['iso']))); ?>
</div>
<?php endif; ?>
<?php if (!empty($event['venue']['name'])) : ?>
<div class="tt-meta-item">
<span class="dashicons dashicons-location"></span>
<strong><?php esc_html_e('Venue:', 'ticket-tailor'); ?></strong>
<?php echo esc_html($event['venue']['name']); ?>
<?php if (!empty($event['venue']['address'])) : ?>
<br><small style="margin-left: 28px;"><?php echo esc_html($event['venue']['address']); ?></small>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (!empty($event['status'])) : ?>
<div class="tt-meta-item">
<span class="dashicons dashicons-info"></span>
<strong><?php esc_html_e('Status:', 'ticket-tailor'); ?></strong>
<span class="tt-status tt-status-<?php echo esc_attr($event['status']); ?>">
<?php echo esc_html($event['status']); ?>
</span>
</div>
<?php endif; ?>
</div>
<?php if ($show_description && !empty($event['description'])) : ?>
<div class="tt-event-description">
<?php echo wp_kses_post(wpautop($event['description'])); ?>
</div>
<?php endif; ?>
<?php if ($show_tickets && !empty($event['url'])) : ?>
<div class="tt-event-cta">
<a href="<?php echo esc_url($event['url']); ?>"
class="tt-button tt-button-primary"
target="_blank"
rel="noopener noreferrer">
<?php esc_html_e('Buy Tickets', 'ticket-tailor'); ?>
</a>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php
return ob_get_clean();
}
/**
* Render category events block - ENHANCED
*/
public function render_category_events_block($attributes) {
$category = $attributes['category'] ?? '';
$limit = $attributes['limit'] ?? 10;
$layout = $attributes['layout'] ?? 'grid';
$columns = $attributes['columns'] ?? 3;
$columns_mode = $attributes['columnsMode'] ?? 'fixed';
$show_image = $attributes['showImage'] ?? true;
$image_type = $attributes['imageType'] ?? 'thumbnail';
$full_width = $attributes['fullWidth'] ?? true;
$align = $attributes['align'] ?? '';
if (empty($category)) {
return '<div class="tt-block-placeholder">' . esc_html__('Please select a category', 'ticket-tailor') . '</div>';
}
// Sanitize image type
if (!in_array($image_type, array('thumbnail', 'header'))) {
$image_type = 'thumbnail';
}
// Get events by category
$events = $this->events->get_events_by_category($category);
if (is_wp_error($events)) {
return '<div class="tt-error">' . esc_html($events->get_error_message()) . '</div>';
}
// Limit results
$events = array_slice($events, 0, $limit);
if (empty($events)) {
return '<div class="tt-no-events">' .
sprintf(
/* translators: %s: category name */
esc_html__('No events found in category: %s', 'ticket-tailor'),
esc_html($category)
) .
'</div>';
}
ob_start();
// Build wrapper classes
$wrapper_classes = array('tt-category-events-wrapper');
if ($full_width) {
$wrapper_classes[] = 'tt-full-width';
}
if (!empty($align)) {
$wrapper_classes[] = 'align' . esc_attr($align);
}
// Build listing classes
$class = 'tt-event-listing tt-category-listing tt-layout-' . esc_attr($layout);
if ($layout === 'grid') {
if ($columns_mode === 'responsive') {
$class .= ' tt-columns-responsive tt-max-columns-' . esc_attr($columns);
} else {
$class .= ' tt-columns-' . esc_attr($columns);
}
}
// Add inline styles ONLY for responsive mode, not for fixed mode
$style = '';
if ($layout === 'grid' && $columns_mode === 'responsive') {
$style = 'style="grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));"';
}
// No inline styles for fixed mode - let CSS classes handle it
?>
<div class="<?php echo esc_attr(implode(' ', $wrapper_classes)); ?>" data-category="<?php echo esc_attr($category); ?>">
<div class="tt-category-header">
<h2 class="tt-category-title">
<?php
printf(
/* translators: %s: category name */
esc_html__('%s Events', 'ticket-tailor'),
esc_html(ucfirst($category))
);
?>
</h2>
</div>
<div class="<?php echo esc_attr($class); ?>" <?php echo $style; ?>>
<?php foreach ($events as $event) : ?>
<div class="tt-event-card">
<?php if ($show_image && !empty($event['images'][$image_type])) : ?>
<div class="tt-event-image tt-image-<?php echo esc_attr($image_type); ?>">
<img src="<?php echo esc_url($event['images'][$image_type]); ?>"
alt="<?php echo esc_attr($event['name']); ?>"
loading="lazy">
</div>
<?php endif; ?>
<div class="tt-event-content">
<h3 class="tt-event-title"><?php echo esc_html($event['name']); ?></h3>
<?php if (!empty($event['start']['iso'])) : ?>
<div class="tt-event-date">
<span class="dashicons dashicons-calendar-alt"></span>
<?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($event['start']['iso']))); ?>
</div>
<?php endif; ?>
<?php if (!empty($event['venue']['name'])) : ?>
<div class="tt-event-venue">
<span class="dashicons dashicons-location"></span>
<?php echo esc_html($event['venue']['name']); ?>
</div>
<?php endif; ?>
<?php if ($layout === 'list' && !empty($event['description'])) : ?>
<div class="tt-event-excerpt">
<?php echo esc_html(wp_trim_words($event['description'], 20)); ?>
</div>
<?php endif; ?>
<?php /* REMOVED SPACER - was making cards too tall
<!-- Spacer pushes button to bottom -->
<div class="tt-event-spacer"></div>
*/ ?>
<!-- Button container -->
<?php if (!empty($event['url'])) : ?>
<div class="tt-event-button-container">
<a href="<?php echo esc_url($event['url']); ?>"
class="tt-event-button"
target="_blank"
rel="noopener noreferrer">
<?php esc_html_e('Get Tickets', 'ticket-tailor'); ?>
</a>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php
return ob_get_clean();
}
}