File: /var/www/test.kaunokolegija.lt/kk_wp_content/plugins/events/kauno-events-plugin.php
<?php
/**
* Plugin Name: Kauno Events Manager
* Description: Complete events management system for Kauno Kolegija multisite with multilingual support and image galleries
* Version: 1.2.0
* Author: Kauno kolegija team
* Text Domain: kauno-events
* Network: true
*/
// Prevent direct access
if (!defined("ABSPATH")) {
exit();
}
// Define plugin constants
define("KAUNO_EVENTS_PLUGIN_URL", plugin_dir_url(__FILE__));
define("KAUNO_EVENTS_PLUGIN_PATH", plugin_dir_path(__FILE__));
define("KAUNO_EVENTS_VERSION", "1.2.0");
// Main plugin class
class KaunoEventsPlugin
{
public function __construct()
{
add_action("init", [$this, "init"]);
add_action("admin_menu", [$this, "add_admin_menu"]);
add_action("wp_enqueue_scripts", [$this, "enqueue_scripts"]);
add_action("admin_enqueue_scripts", [$this, "enqueue_admin_scripts"]);
// Shortcodes
add_shortcode("event_home", [$this, "event_home_shortcode"]);
add_shortcode("event_list", [$this, "event_list_shortcode"]);
add_shortcode("event_detail", [$this, "event_detail_shortcode"]);
// Removed old custom_rewrite_rules action - using add_rewrite_rules instead
add_filter("query_vars", [$this, "add_query_vars"]);
// AJAX handlers
add_action("wp_ajax_submit_event_form", [
$this,
"handle_event_form_submission",
]);
add_action("wp_ajax_nopriv_submit_event_form", [
$this,
"handle_event_form_submission",
]);
add_action("wp_ajax_load_more_events", [$this, "load_more_events"]);
add_action("wp_ajax_nopriv_load_more_events", [ $this,"load_more_events",]);
add_action("wp_ajax_upload_event_images", [
$this,
"handle_image_upload",
]);
add_action("wp_ajax_delete_event_image", [
$this,
"handle_image_delete",
]);
// URL rewriting for event details
add_action("init", [$this, "add_rewrite_rules"]);
add_filter("query_vars", [$this, "add_query_vars"]);
add_action("template_redirect", [$this, "handle_event_detail_page"]);
// Multisite hooks
add_action(
"wpmu_new_blog",
[$this, "create_tables_for_new_site"],
10,
6
);
add_action(
"wp_initialize_site",
[$this, "create_tables_for_new_site_wp5"],
10,
2
);
// Plugin activation/deactivation hooks
register_activation_hook(__FILE__, [$this, "plugin_activation"]);
register_deactivation_hook(__FILE__, [$this, "plugin_deactivation"]);
// Check and create tables on admin init (fallback)
add_action("admin_init", [$this, "check_and_create_tables"]);
}
public function init()
{
load_plugin_textdomain(
"kauno-events",
false,
dirname(plugin_basename(__FILE__)) . "/languages"
);
}
/**
* Plugin activation handler
* Creates tables for all existing sites in multisite
*/
public function plugin_activation()
{
if (is_multisite()) {
$this->create_tables_for_all_sites();
} else {
$this->create_tables();
}
// Flush rewrite rules
flush_rewrite_rules();
// Set plugin version
update_option("kauno_events_version", KAUNO_EVENTS_VERSION);
// Log activation
error_log(
"Kauno Events Plugin activated for " .
(is_multisite() ? "multisite" : "single site")
);
}
/**
* Plugin deactivation handler
*/
public function plugin_deactivation()
{
// Flush rewrite rules
flush_rewrite_rules();
// Log deactivation
error_log("Kauno Events Plugin deactivated");
}
/**
* Check and create tables if they don't exist (fallback safety check)
*/
public function check_and_create_tables()
{
// Only run this check once per admin session
if (get_transient("kauno_events_tables_checked")) {
return;
}
global $wpdb;
if (is_multisite()) {
$events_table = $wpdb->base_prefix . "kauno_events";
$submissions_table = $wpdb->base_prefix . "kauno_event_submissions";
} else {
$events_table = $wpdb->prefix . "kauno_events";
$submissions_table = $wpdb->prefix . "kauno_event_submissions";
}
// Check if tables exist
$events_exists =
$wpdb->get_var("SHOW TABLES LIKE '$events_table'") == $events_table;
$submissions_exists =
$wpdb->get_var("SHOW TABLES LIKE '$submissions_table'") ==
$submissions_table;
if (!$events_exists || !$submissions_exists) {
if (is_multisite()) {
$this->create_tables_for_all_sites();
} else {
$this->create_tables();
}
// Show admin notice
add_action("admin_notices", [$this, "tables_created_notice"]);
}
// Set transient to avoid repeated checks
set_transient("kauno_events_tables_checked", true, HOUR_IN_SECONDS);
}
/**
* Admin notice for table creation
*/
public function tables_created_notice()
{
echo '<div class="notice notice-success is-dismissible">';
echo "<p><strong>Kauno Events:</strong> Database tables have been created/updated successfully.</p>";
echo "</div>";
}
/**
* Create tables for all sites in multisite network
*/
public function create_tables_for_all_sites()
{
global $wpdb;
if (!is_multisite()) {
$this->create_tables();
return;
}
// Get all sites in the network
$sites = get_sites([
"number" => 0, // Get all sites
"deleted" => 0,
]);
error_log(
"Kauno Events: Creating tables for " . count($sites) . " sites"
);
// Create shared tables using base_prefix (for multisite)
$this->create_shared_tables();
// Log site information
foreach ($sites as $site) {
error_log(
"Kauno Events: Site ID {$site->blog_id} - {$site->domain}{$site->path}"
);
}
error_log("Kauno Events: All tables created successfully");
}
/**
* Create shared tables for multisite (using base_prefix)
*/
public function create_shared_tables()
{
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// Use base_prefix for multisite - creates tables once for all sites
$events_table = $wpdb->base_prefix . "kauno_events";
$submissions_table = $wpdb->base_prefix . "kauno_event_submissions";
// Events table
$events_sql = "CREATE TABLE $events_table (
id int(11) NOT NULL AUTO_INCREMENT,
site_id int(11) NOT NULL,
title varchar(255) NOT NULL,
description text,
event_slug varchar(255) NOT NULL,
event_date datetime NOT NULL,
end_date datetime,
location varchar(255),
address text,
featured_image varchar(255),
gallery_images text,
language varchar(2) NOT NULL DEFAULT 'lt',
status varchar(20) NOT NULL DEFAULT 'active',
registration_required tinyint(1) DEFAULT 0,
max_participants int(11),
contact_email varchar(255),
contact_phone varchar(50),
price decimal(10,2) DEFAULT 0.00,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY site_id (site_id),
KEY event_date (event_date),
KEY language (language),
KEY status (status)
) $charset_collate;";
// Submissions table
$submissions_sql = "CREATE TABLE $submissions_table (
id int(11) NOT NULL AUTO_INCREMENT,
event_id int(11) NOT NULL,
site_id int(11) NOT NULL,
name varchar(255) NOT NULL,
email varchar(255) NOT NULL,
phone varchar(50),
message text,
participants int(11) DEFAULT 1,
submitted_at datetime DEFAULT CURRENT_TIMESTAMP,
status varchar(20) NOT NULL DEFAULT 'new',
PRIMARY KEY (id),
KEY event_id (event_id),
KEY site_id (site_id),
KEY status (status)
) $charset_collate;";
require_once ABSPATH . "wp-admin/includes/upgrade.php";
$result1 = dbDelta($events_sql);
$result2 = dbDelta($submissions_sql);
// Log results
error_log(
"Kauno Events - Events table creation: " . print_r($result1, true)
);
error_log(
"Kauno Events - Submissions table creation: " .
print_r($result2, true)
);
// Verify tables were created
$events_exists =
$wpdb->get_var("SHOW TABLES LIKE '$events_table'") == $events_table;
$submissions_exists =
$wpdb->get_var("SHOW TABLES LIKE '$submissions_table'") ==
$submissions_table;
if ($events_exists && $submissions_exists) {
error_log(
"Kauno Events: ✅ All shared tables created successfully"
);
update_option("kauno_events_tables_created", time());
} else {
error_log("Kauno Events: ❌ Error creating tables");
error_log(
"Events table exists: " . ($events_exists ? "YES" : "NO")
);
error_log(
"Submissions table exists: " .
($submissions_exists ? "YES" : "NO")
);
}
}
/**
* Handle new site creation (WordPress < 5.1)
*/
public function create_tables_for_new_site(
$blog_id,
$user_id,
$domain,
$path,
$site_id,
$meta
) {
// Tables are shared in multisite, so we don't need to create new ones
// Just log the new site
error_log(
"Kauno Events: New site created - ID: $blog_id, Domain: $domain$path"
);
}
/**
* Handle new site creation (WordPress 5.1+)
*/
public function create_tables_for_new_site_wp5($site, $args)
{
// Tables are shared in multisite, so we don't need to create new ones
// Just log the new site
error_log(
"Kauno Events: New site created - ID: {$site->blog_id}, Domain: {$site->domain}{$site->path}"
);
}
/**
* Create tables for single site or fallback
*/
public function create_tables()
{
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// For single site, use regular prefix
$events_table = $wpdb->prefix . "kauno_events";
$submissions_table = $wpdb->prefix . "kauno_event_submissions";
// Events table
$events_sql = "CREATE TABLE $events_table (
id int(11) NOT NULL AUTO_INCREMENT,
site_id int(11) NOT NULL DEFAULT 1,
event_slug varchar(255) NOT NULL,
title varchar(255) NOT NULL,
description text,
event_date datetime NOT NULL,
end_date datetime,
location varchar(255),
address text,
featured_image varchar(255),
gallery_images text,
language varchar(2) NOT NULL DEFAULT 'lt',
status varchar(20) NOT NULL DEFAULT 'active',
registration_required tinyint(1) DEFAULT 0,
max_participants int(11),
contact_email varchar(255),
contact_phone varchar(50),
price decimal(10,2) DEFAULT 0.00,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY site_id (site_id),
KEY event_date (event_date),
KEY language (language),
KEY status (status)
) $charset_collate;";
// Submissions table
$submissions_sql = "CREATE TABLE $submissions_table (
id int(11) NOT NULL AUTO_INCREMENT,
event_id int(11) NOT NULL,
site_id int(11) NOT NULL DEFAULT 1,
name varchar(255) NOT NULL,
email varchar(255) NOT NULL,
phone varchar(50),
message text,
participants int(11) DEFAULT 1,
submitted_at datetime DEFAULT CURRENT_TIMESTAMP,
status varchar(20) NOT NULL DEFAULT 'new',
PRIMARY KEY (id),
KEY event_id (event_id),
KEY site_id (site_id),
KEY status (status)
) $charset_collate;";
require_once ABSPATH . "wp-admin/includes/upgrade.php";
dbDelta($events_sql);
dbDelta($submissions_sql);
}
/**
* Get the correct table name based on multisite setup
*/
private function get_events_table()
{
global $wpdb;
return is_multisite()
? $wpdb->base_prefix . "kauno_events"
: $wpdb->prefix . "kauno_events";
}
/**
* Get the correct submissions table name based on multisite setup
*/
private function get_submissions_table()
{
global $wpdb;
return is_multisite()
? $wpdb->base_prefix . "kauno_event_submissions"
: $wpdb->prefix . "kauno_event_submissions";
}
// Add admin menu
public function add_admin_menu()
{
// Main menu
add_menu_page(
__("Kauno Events", "kauno-events"),
__("Events", "kauno-events"),
"manage_options",
"kauno-events",
[$this, "admin_events_list"],
"dashicons-calendar-alt",
30
);
// Submenu pages
add_submenu_page(
"kauno-events",
__("All Events", "kauno-events"),
__("All Events", "kauno-events"),
"manage_options",
"kauno-events",
[$this, "admin_events_list"]
);
add_submenu_page(
"kauno-events",
__("Add New Event", "kauno-events"),
__("Add New", "kauno-events"),
"manage_options",
"kauno-events-add",
[$this, "admin_add_event"]
);
add_submenu_page(
"kauno-events",
__("Event Submissions", "kauno-events"),
__("Submissions", "kauno-events"),
"manage_options",
"kauno-events-submissions",
[$this, "admin_submissions"]
);
add_submenu_page(
"kauno-events",
__("Settings", "kauno-events"),
__("Settings", "kauno-events"),
"manage_options",
"kauno-events-settings",
[$this, "admin_settings"]
);
// Add debug info submenu for admins
if (current_user_can("manage_network") || WP_DEBUG) {
add_submenu_page(
"kauno-events",
__("Debug Info", "kauno-events"),
__("Debug Info", "kauno-events"),
"manage_options",
"kauno-events-debug",
[$this, "admin_debug_info"]
);
}
}
/**
* Debug info page
*/
public function admin_debug_info()
{
global $wpdb;
echo '<div class="wrap">';
echo "<h1>Kauno Events - Debug Information</h1>";
// Database info
echo '<div class="card" style="max-width: none;">';
echo "<h2>Database Information</h2>";
echo '<table class="widefat">';
echo "<tr><td><strong>Is Multisite:</strong></td><td>" .
(is_multisite() ? "YES" : "NO") .
"</td></tr>";
echo "<tr><td><strong>Current Site ID:</strong></td><td>" .
get_current_blog_id() .
"</td></tr>";
echo "<tr><td><strong>Database Name:</strong></td><td>" .
DB_NAME .
"</td></tr>";
echo "<tr><td><strong>Table Prefix:</strong></td><td>" .
$wpdb->prefix .
"</td></tr>";
echo "<tr><td><strong>Base Prefix:</strong></td><td>" .
$wpdb->base_prefix .
"</td></tr>";
echo "<tr><td><strong>Events Table:</strong></td><td>" .
$this->get_events_table() .
"</td></tr>";
echo "<tr><td><strong>Submissions Table:</strong></td><td>" .
$this->get_submissions_table() .
"</td></tr>";
echo "</table>";
echo "</div>";
// Table status
echo '<div class="card" style="max-width: none; margin-top: 20px;">';
echo "<h2>Table Status</h2>";
$events_table = $this->get_events_table();
$submissions_table = $this->get_submissions_table();
$events_exists =
$wpdb->get_var("SHOW TABLES LIKE '$events_table'") == $events_table;
$submissions_exists =
$wpdb->get_var("SHOW TABLES LIKE '$submissions_table'") ==
$submissions_table;
echo '<table class="widefat">';
echo "<tr><td><strong>Events Table Exists:</strong></td><td>" .
($events_exists ? "✅ YES" : "❌ NO") .
"</td></tr>";
echo "<tr><td><strong>Submissions Table Exists:</strong></td><td>" .
($submissions_exists ? "✅ YES" : "❌ NO") .
"</td></tr>";
echo "</table>";
if ($events_exists) {
$event_count = $wpdb->get_var(
"SELECT COUNT(*) FROM $events_table WHERE site_id = " .
get_current_blog_id()
);
echo "<p><strong>Events in current site:</strong> " .
$event_count .
"</p>";
}
if ($submissions_exists) {
$submission_count = $wpdb->get_var(
"SELECT COUNT(*) FROM $submissions_table WHERE site_id = " .
get_current_blog_id()
);
echo "<p><strong>Submissions in current site:</strong> " .
$submission_count .
"</p>";
}
echo "</div>";
// Multisite info
if (is_multisite()) {
echo '<div class="card" style="max-width: none; margin-top: 20px;">';
echo "<h2>Multisite Information</h2>";
$sites = get_sites(["number" => 0]);
echo '<table class="widefat">';
echo "<thead><tr><th>Site ID</th><th>Domain</th><th>Path</th><th>Events Count</th></tr></thead>";
echo "<tbody>";
foreach ($sites as $site) {
$event_count = 0;
if ($events_exists) {
$event_count = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM $events_table WHERE site_id = %d",
$site->blog_id
)
);
}
echo "<tr>";
echo "<td>" . $site->blog_id . "</td>";
echo "<td>" . $site->domain . "</td>";
echo "<td>" . $site->path . "</td>";
echo "<td>" . $event_count . "</td>";
echo "</tr>";
}
echo "</tbody></table>";
echo "</div>";
}
// Actions
echo '<div class="card" style="max-width: none; margin-top: 20px;">';
echo "<h2>Actions</h2>";
echo "<p>";
echo '<a href="?page=kauno-events-debug&action=recreate_tables" class="button button-secondary" onclick="return confirm(\'Are you sure you want to recreate all tables? This will not delete existing data.\')">Recreate Tables</a> ';
echo '<a href="?page=kauno-events-debug&action=clear_cache" class="button button-secondary">Clear Cache</a>';
echo "</p>";
echo "</div>";
// Handle actions
if (isset($_GET["action"])) {
switch ($_GET["action"]) {
case "recreate_tables":
if (is_multisite()) {
$this->create_tables_for_all_sites();
} else {
$this->create_tables();
}
echo '<div class="notice notice-success"><p>Tables recreated successfully!</p></div>';
break;
case "clear_cache":
delete_transient("kauno_events_tables_checked");
echo '<div class="notice notice-success"><p>Cache cleared successfully!</p></div>';
break;
}
}
echo "</div>";
}
// Enqueue frontend scripts and styles
public function enqueue_scripts()
{
// Only enqueue on pages that need it
if (is_page() || is_single() || get_query_var("event_slug")) {
// CSS
wp_enqueue_style(
"kauno-events-style",
KAUNO_EVENTS_PLUGIN_URL . "assets/style.css",
[],
KAUNO_EVENTS_VERSION
);
wp_enqueue_style(
"kauno-events-detail-style",
KAUNO_EVENTS_PLUGIN_URL . "assets/event-detail-styles.css",
[],
KAUNO_EVENTS_VERSION
);
// JavaScript
wp_enqueue_script(
"kauno-events-script",
KAUNO_EVENTS_PLUGIN_URL . "assets/script.js",
["jquery"],
KAUNO_EVENTS_VERSION,
true
);
wp_enqueue_script(
"kauno-events-detail-script",
KAUNO_EVENTS_PLUGIN_URL . "assets/event-detail-script.js",
["jquery"],
KAUNO_EVENTS_VERSION,
true
);
// Localize script for AJAX
wp_localize_script("kauno-events-script", "kaunoEvents", [
"ajaxurl" => admin_url("admin-ajax.php"),
"nonce" => wp_create_nonce("kauno_events_nonce"),
"strings" => [
"loading" => __("Loading...", "kauno-events"),
"error" => __(
"Error occurred. Please try again.",
"kauno-events"
),
"success" => __("Success!", "kauno-events"),
"confirm_delete" => __(
"Are you sure you want to delete this item?",
"kauno-events"
),
],
]);
}
}
// Enqueue admin scripts and styles
public function enqueue_admin_scripts($hook)
{
// Only load on our plugin pages
if (strpos($hook, "kauno-events") === false) {
return;
}
// WordPress media uploader
wp_enqueue_media();
// Admin CSS
wp_enqueue_style(
"kauno-events-admin-style",
KAUNO_EVENTS_PLUGIN_URL . "assets/admin-style.css",
[],
KAUNO_EVENTS_VERSION
);
// Admin JavaScript
wp_enqueue_script(
"kauno-events-admin-script",
KAUNO_EVENTS_PLUGIN_URL . "assets/admin-script.js",
["jquery", "wp-color-picker"],
KAUNO_EVENTS_VERSION,
true
);
// Color picker
wp_enqueue_style("wp-color-picker");
// Localize admin script
wp_localize_script("kauno-events-admin-script", "kaunoEventsAdmin", [
"ajaxurl" => admin_url("admin-ajax.php"),
"nonce" => wp_create_nonce("kauno_events_nonce"),
"strings" => [
"confirm_delete" => __(
"Are you sure you want to delete this event? This action cannot be undone.",
"kauno-events"
),
"uploading" => __("Uploading...", "kauno-events"),
"upload_error" => __(
"Upload failed. Please try again.",
"kauno-events"
),
"select_image" => __("Select Image", "kauno-events"),
"use_image" => __("Use This Image", "kauno-events"),
"remove_image" => __("Remove Image", "kauno-events"),
],
]);
}
// Admin page: Events list
public function admin_events_list()
{
include KAUNO_EVENTS_PLUGIN_PATH . "admin/events-list.php";
}
// Admin page: Add/Edit event
public function admin_add_event()
{
include KAUNO_EVENTS_PLUGIN_PATH . "admin/add-event.php";
}
// Admin page: Submissions
public function admin_submissions()
{
include KAUNO_EVENTS_PLUGIN_PATH . "admin/submissions.php";
}
// Admin page: Settings
public function admin_settings()
{
include KAUNO_EVENTS_PLUGIN_PATH . "admin/settings.php";
}
public function add_rewrite_rules()
{
add_rewrite_rule(
'^event/([^/]+)/?$',
'index.php?event_slug=$matches[1]',
"top"
);
}
public function add_query_vars($vars)
{
$vars[] = "event_slug";
return $vars;
}
public function handle_event_detail_page()
{
$event_slug = get_query_var("event_slug");
if ($event_slug) {
// Start output
echo '<!DOCTYPE html>';
echo '<html ';
language_attributes();
echo '>';
echo '<head>';
echo '<meta charset="' . get_bloginfo('charset') . '">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
wp_head(); // Still calls any enqueued styles/scripts
echo '</head>';
echo '<body>';
// Your event content
$this->display_event_detail_page($event_slug);
wp_footer(); // Optional but good for plugins/scripts
echo '</body></html>';
exit;
}
}
// Get events
private function get_events($limit = 10, $offset = 0, $language = null, $exclude_ids = [], $date = null)
{
global $wpdb;
$events_table = $this->get_events_table();
$current_site = get_current_blog_id();
$where = "site_id = %d AND status = 'active'";
$params = [$current_site];
// Add date condition only if provided
if (!empty($date)) {
$where .= " AND end_date >= %s";
$params[] = $date; // Example: '2025-08-20'
}
// Exclude loaded IDs if any
if (!empty($exclude_ids)) {
$placeholders = implode(',', array_fill(0, count($exclude_ids), '%d'));
$where .= " AND id NOT IN ($placeholders)";
$params = array_merge($params, $exclude_ids);
}
// Add LIMIT and OFFSET at the end
$params[] = (int) $limit;
$params[] = (int) $offset;
$sql = $wpdb->prepare(
"SELECT * FROM {$events_table} WHERE {$where} ORDER BY event_date DESC LIMIT %d OFFSET %d",
$params
);
return $wpdb->get_results($sql);
}
// Get single event
private function get_event($event_slug)
{
global $wpdb;
$events_table = $this->get_events_table();
return $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $events_table WHERE event_slug = %s AND status = 'active'",
$event_slug
)
);
}
// Event detail page display
public function display_event_detail_page($event_slug)
{
$event = $this->get_event($event_slug);
if (!$event) {
wp_die("Event not found", "Event Not Found", ["response" => 404]);
}
// Get header
get_header();
// Display event detail
echo $this->render_event_detail($event);
// Get footer
get_footer();
}
// Render event detail
private function render_event_detail($event)
{
$gallery_images = $event->gallery_images
? json_decode($event->gallery_images, true)
: [];
$is_lithuanian = $event->language === "lt";
ob_start();
?>
<div class="kauno-event-detail">
<!-- Hero Section -->
<div class="event-hero">
<?php if (get_option('kauno_events_show_breadcrumb', 1)): ?>
<div class="event-hero-content">
<div class="container">
<div class="hero-breadcrumb">
<a href="<?php echo home_url(); ?>"><?php echo $is_lithuanian ? "Pradžia" : "Home"; ?></a>
<span class="separator">›</span>
<a href="<?php echo $this->get_all_events_url(); ?>"><?php echo $is_lithuanian ? "Įvykiai" : "Events"; ?></a>
<span class="separator">›</span>
<span class="current"><?php echo esc_html(
$event->title
); ?></span>
</div>
</div>
</div>
</div>
<?php endif; ?>
<!-- Main Content -->
<div class="event-content">
<div class="container">
<div class="content-grid">
<!-- Left Column - Main Content -->
<div class="main-content">
<div class="information">
<h1 class="event-title"><?php echo esc_html(
$event->title
); ?></h1>
<div class="event-meta">
<div class="meta-item">
<svg class="meta-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"/>
</svg>
<span><?php echo $this->format_event_date_detailed(
$event->event_date,
$event->end_date,
$event->language
); ?></span>
</div>
<?php if ($event->location): ?>
<div class="meta-item">
<svg class="meta-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
</svg>
<span><?php echo esc_html(
$event->location
); ?></span>
</div>
<?php endif; ?>
<?php if ($event->price > 0): ?>
<div class="meta-item">
<svg class="meta-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M11.8 10.9c-2.27-.59-3-1.2-3-2.15 0-1.09 1.01-1.85 2.7-1.85 1.78 0 2.44.85 2.5 2.1h2.21c-.07-1.72-1.12-3.3-3.21-3.81V3h-3v2.16c-1.94.42-3.5 1.68-3.5 3.61 0 2.31 1.91 3.46 4.7 4.13 2.5.6 3 1.48 3 2.41 0 .69-.49 1.79-2.7 1.79-2.06 0-2.87-.92-2.98-2.1h-2.2c.12 2.19 1.76 3.42 3.68 3.83V21h3v-2.15c1.95-.37 3.5-1.5 3.5-3.55 0-2.84-2.43-3.81-4.7-4.4z"/>
</svg>
<span><?php echo number_format(
$event->price,
2
); ?> €</span>
</div>
<?php endif; ?>
</div>
</div>
<?php if ($event->description): ?>
<div class="content-section">
<h2><?php echo $is_lithuanian
? "Aprašymas"
: "Description"; ?></h2>
<div class="event-description">
<?php echo wp_kses_post($event->description); ?>
</div>
</div>
<?php endif; ?>
<!-- Image Gallery -->
<?php if (!empty($gallery_images)): ?>
<div class="content-section">
<?php if ($event->featured_image): ?>
<h2><?php echo $is_lithuanian
? "Paveikslėlis"
: "Main Image"; ?></h2>
<div class="event-gallery-container-featured">
<div class="event-gallery-featured">
<img src="<?php echo esc_url(
$event->featured_image
); ?>" alt="<?php echo esc_attr($event->title); ?>">
</div>
</div>
<?php endif; ?>
<h2><?php echo $is_lithuanian
? "Galerija"
: "Gallery"; ?></h2>
<!-- Gallery Carousel Container -->
<div class="gallery-carousel-container">
<!-- Navigation Arrows -->
<button class="gallery-nav gallery-prev" id="galleryPrev">
<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
</svg>
</button>
<button class="gallery-nav gallery-next" id="galleryNext">
<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
</svg>
</button>
<!-- Gallery Track -->
<div class="event-gallery" id="galleryTrack">
<?php foreach (
$gallery_images
as $index => $image
): ?>
<div class="gallery-item" data-index="<?php echo $index; ?>">
<img src="<?php echo esc_url(
$image
); ?>" alt="Event gallery image <?php echo $index +
1; ?>">
<div class="gallery-overlay">
<button class="gallery-zoom" data-image="<?php echo esc_url(
$image
); ?>">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L23.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
</svg>
</button>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<!-- Right Column - Sidebar -->
<div class="event-sidebar">
<!-- Registration Form -->
<?php if ($event->registration_required): ?>
<div class="sidebar-section registration-section">
<h3><?php echo $is_lithuanian
? "Registracija"
: "Registration"; ?></h3>
<form class="event-registration-form" data-event-id="<?php echo $event->id; ?>">
<input type="hidden" name="event_id" value="<?php echo $event->id; ?>">
<input type="hidden" name="event_slug" value="<?php echo $event->event_slug; ?>">
<div class="form-group">
<label for="reg-name"><?php echo $is_lithuanian
? "Vardas, pavardė"
: "Full Name"; ?> *</label>
<input type="text" id="reg-name" name="name" required>
</div>
<div class="form-group">
<label for="reg-email"><?php echo $is_lithuanian
? "El. paštas"
: "Email"; ?> *</label>
<input type="email" id="reg-email" name="email" required>
</div>
<div class="form-group">
<label for="reg-phone"><?php echo $is_lithuanian
? "Telefonas"
: "Phone"; ?></label>
<input type="tel" id="reg-phone" name="phone">
</div>
<?php if ($event->max_participants): ?>
<div class="form-group">
<label for="reg-participants"><?php echo $is_lithuanian
? "Dalyvių skaičius"
: "Number of Participants"; ?></label>
<select id="reg-participants" name="participants">
<?php for (
$i = 1;
$i <=
min(
10,
$event->max_participants
);
$i++
): ?>
<option value="<?php echo $i; ?>"><?php echo $i; ?></option>
<?php endfor; ?>
</select>
</div>
<?php endif; ?>
<div class="form-group">
<label for="reg-message"><?php echo $is_lithuanian
? "Papildoma informacija"
: "Additional Information"; ?></label>
<textarea id="reg-message" name="message" rows="4"></textarea>
</div>
<button type="submit" class="btn-register">
<?php echo $is_lithuanian
? "Registruotis"
: "Register"; ?>
</button>
</form>
</div>
<?php endif; ?>
<!-- Event Details -->
<div class="sidebar-section event-details">
<h3><?php echo $is_lithuanian
? "Informacija"
: "Event Details"; ?></h3>
<div class="detail-item">
<strong><?php echo $is_lithuanian
? "Data ir laikas:"
: "Date & Time:"; ?></strong>
<span><?php echo $this->format_event_date_detailed(
$event->event_date,
$event->end_date,
$event->language
); ?></span>
</div>
<?php if ($event->location): ?>
<div class="detail-item">
<strong><?php echo $is_lithuanian
? "Vieta:"
: "Location:"; ?></strong>
<span><?php echo esc_html(
$event->location
); ?></span>
</div>
<?php endif; ?>
<?php if ($event->address): ?>
<div class="detail-item">
<strong><?php echo $is_lithuanian
? "Adresas:"
: "Address:"; ?></strong>
<span><?php echo esc_html(
$event->address
); ?></span>
</div>
<?php endif; ?>
<?php if ($event->price > 0): ?>
<div class="detail-item">
<strong><?php echo $is_lithuanian
? "Kaina:"
: "Price:"; ?></strong>
<span><?php echo number_format(
$event->price,
2
); ?> €</span>
</div>
<?php endif; ?>
<?php if ($event->max_participants): ?>
<div class="detail-item">
<strong><?php echo $is_lithuanian
? "Maksimalus dalyvių skaičius:"
: "Max Participants:"; ?></strong>
<span><?php echo $event->max_participants; ?></span>
</div>
<?php endif; ?>
</div>
<!-- Contact Information -->
<?php if (
$event->contact_email ||
$event->contact_phone
): ?>
<div class="sidebar-section contact-info">
<h3><?php echo $is_lithuanian
? "Kontaktai"
: "Contact"; ?></h3>
<?php if ($event->contact_email): ?>
<div class="contact-item">
<svg class="contact-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>
</svg>
<a href="mailto:<?php echo esc_attr(
$event->contact_email
); ?>">
<?php echo esc_html(
$event->contact_email
); ?>
</a>
</div>
<?php endif; ?>
<?php if ($event->contact_phone): ?>
<div class="contact-item">
<svg class="contact-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/>
</svg>
<a href="tel:<?php echo esc_attr(
$event->contact_phone
); ?>">
<?php echo esc_html(
$event->contact_phone
); ?>
</a>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Share Section -->
<div class="sidebar-section share-section">
<h3><?php echo $is_lithuanian
? "Dalintis"
: "Share"; ?></h3>
<div class="share-buttons">
<a href="https://www.facebook.com/sharer/sharer.php?u=<?php echo urlencode(
$this->get_current_url()
); ?>"
target="_blank" class="share-btn facebook" title="Facebook">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
</svg>
</a>
<a href="https://www.linkedin.com/sharing/share-offsite/?url=<?php echo urlencode(
$this->get_current_url()
); ?>"
target="_blank" class="share-btn linkedin" title="LinkedIn">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
</svg>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Image Lightbox -->
<div id="image-lightbox" class="lightbox" style="display: none;">
<div class="lightbox-content">
<span class="lightbox-close">×</span>
<img class="lightbox-image" src="/placeholder.svg" alt="">
<div class="lightbox-nav">
<button class="lightbox-prev">‹</button>
<button class="lightbox-next">›</button>
</div>
</div>
</div>
<style>
/* Gallery Carousel Styles */
.gallery-carousel-container {
position: relative;
width: 100%;
overflow: hidden;
border-radius: 8px;
margin: 20px 0;
}
.gallery-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: rgba(255, 255, 255, 0.9) !important;
border: none;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
color: #333;
}
.gallery-nav:hover {
background: rgba(255, 255, 255, 1);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
transform: translateY(-50%) scale(1.05);
}
.gallery-nav:active {
transform: translateY(-50%) scale(0.95);
}
.gallery-prev {
left: 15px;
}
.gallery-next {
right: 15px;
}
.event-gallery {
display: flex;
transition: transform 0.5s ease;
gap: 15px;
padding: 0 15px;
}
.gallery-item {
flex: 0 0 calc(33.333% - 10px);
position: relative;
border-radius: 8px;
overflow: hidden;
aspect-ratio: 4/3;
cursor: pointer;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.gallery-item:hover img {
transform: scale(1.05);
}
.gallery-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
opacity: 0;
transition: opacity 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.gallery-item:hover .gallery-overlay {
opacity: 1;
}
.gallery-zoom {
background: rgba(255, 255, 255, 0.9) !important;
border: none;
border-radius: 50%;
cursor: pointer;
display: flex
;
align-items: center;
justify-content: center;
color: #333;
}
.gallery-zoom:hover {
background: white;
transform: scale(1.1);
}
.event-gallery-featured img {
border-radius: 8px;
}
/* Gallery Dots */
.gallery-dots {
display: flex;
justify-content: center;
gap: 8px;
margin-top: 20px;
padding: 0 20px;
}
.gallery-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: none;
background: #ddd;
cursor: pointer;
transition: all 0.3s ease;
}
.gallery-dot.active,
.gallery-dot:hover {
background: #4ecdc4;
transform: scale(1.2);
}
/* Mobile Responsive Styles */
@media (max-width: 768px) {
.gallery-item {
flex: 0 0 calc(50% - 7.5px);
}
.gallery-nav {
width: 50px;
height: 50px;
}
.gallery-prev {
left: 10px;
}
.gallery-next {
right: 10px;
}
.event-gallery {
gap: 10px;
padding: 0 10px;
}
.gallery-dots {
padding: 0 15px;
}
}
@media (max-width: 480px) {
.gallery-item {
flex: 0 0 calc(100% - 10px);
}
.gallery-nav {
width: 50px;
height: 50px;
}
.event-gallery {
gap: 5px;
padding: 0 5px;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const galleryTrack = document.getElementById('galleryTrack');
const galleryPrev = document.getElementById('galleryPrev');
const galleryNext = document.getElementById('galleryNext');
const galleryDots = document.querySelectorAll('.gallery-dot');
if (!galleryTrack) return;
const galleryItems = galleryTrack.querySelectorAll('.gallery-item');
const totalItems = galleryItems.length;
if (totalItems === 0) return;
let currentIndex = 0;
let itemsToShow = 3; // Default for desktop
// Determine items to show based on screen size
function updateItemsToShow() {
if (window.innerWidth <= 480) {
itemsToShow = 1;
} else if (window.innerWidth <= 768) {
itemsToShow = 2;
} else {
itemsToShow = 3;
}
}
// Update gallery position
function updateGalleryPosition() {
const itemWidth = 100 / itemsToShow;
const translateX = -currentIndex * itemWidth;
galleryTrack.style.transform = `translateX(${translateX}%)`;
// Update dots
galleryDots.forEach((dot, index) => {
dot.classList.toggle('active', index === currentIndex);
});
// Update navigation buttons
if (galleryPrev) galleryPrev.style.display = currentIndex === 0 ? 'none' : 'flex';
if (galleryNext) galleryNext.style.display = currentIndex >= totalItems - itemsToShow ? 'none' : 'flex';
}
// Go to next slide
function nextSlide() {
if (currentIndex < totalItems - itemsToShow) {
currentIndex++;
updateGalleryPosition();
}
}
// Go to previous slide
function prevSlide() {
if (currentIndex > 0) {
currentIndex--;
updateGalleryPosition();
}
}
// Go to specific slide
function goToSlide(index) {
currentIndex = Math.min(index, totalItems - itemsToShow);
updateGalleryPosition();
}
// Event listeners
if (galleryNext) {
galleryNext.addEventListener('click', nextSlide);
}
if (galleryPrev) {
galleryPrev.addEventListener('click', prevSlide);
}
galleryDots.forEach((dot, index) => {
dot.addEventListener('click', () => goToSlide(index));
});
// Handle window resize
window.addEventListener('resize', function() {
updateItemsToShow();
currentIndex = Math.min(currentIndex, totalItems - itemsToShow);
updateGalleryPosition();
});
// Touch/Swipe support for mobile
let startX = 0;
let startY = 0;
let isDown = false;
galleryTrack.addEventListener('touchstart', function(e) {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
isDown = true;
});
galleryTrack.addEventListener('touchmove', function(e) {
if (!isDown) return;
e.preventDefault();
});
galleryTrack.addEventListener('touchend', function(e) {
if (!isDown) return;
isDown = false;
const endX = e.changedTouches[0].clientX;
const endY = e.changedTouches[0].clientY;
const diffX = startX - endX;
const diffY = startY - endY;
// Only handle horizontal swipes
if (Math.abs(diffX) > Math.abs(diffY) && Math.abs(diffX) > 50) {
if (diffX > 0) {
nextSlide(); // Swipe left - go to next
} else {
prevSlide(); // Swipe right - go to previous
}
}
});
// Initialize
updateItemsToShow();
updateGalleryPosition();
// Lightbox functionality for zoom
const lightbox = document.getElementById('image-lightbox');
const lightboxImage = lightbox?.querySelector('.lightbox-image');
const lightboxClose = lightbox?.querySelector('.lightbox-close');
const zoomButtons = document.querySelectorAll('.gallery-zoom');
zoomButtons.forEach(button => {
button.addEventListener('click', function(e) {
e.stopPropagation();
const imageUrl = this.getAttribute('data-image');
if (lightbox && lightboxImage && imageUrl) {
lightboxImage.src = imageUrl;
lightbox.style.display = 'flex';
document.body.style.overflow = 'hidden';
}
});
});
if (lightboxClose) {
lightboxClose.addEventListener('click', function() {
lightbox.style.display = 'none';
document.body.style.overflow = '';
});
}
if (lightbox) {
lightbox.addEventListener('click', function(e) {
if (e.target === lightbox) {
lightbox.style.display = 'none';
document.body.style.overflow = '';
}
});
}
// Keyboard navigation
document.addEventListener('keydown', function(e) {
if (lightbox && lightbox.style.display === 'flex') {
if (e.key === 'Escape') {
lightbox.style.display = 'none';
document.body.style.overflow = '';
}
} else {
if (e.key === 'ArrowLeft') {
prevSlide();
} else if (e.key === 'ArrowRight') {
nextSlide();
}
}
});
});
</script>
<?php return ob_get_clean();
}
// Helper function for detailed date formatting
private function format_event_date_detailed(
$start_date,
$end_date = null,
$language = "lt"
) {
$start_timestamp = strtotime($start_date);
$end_timestamp = $end_date ? strtotime($end_date) : null;
if ($language === "en") {
$formatted = date('F j, Y \a\t H:i', $start_timestamp);
if (
$end_timestamp &&
date("Y-m-d", $start_timestamp) ===
date("Y-m-d", $end_timestamp)
) {
$formatted .= " - " . date("H:i", $end_timestamp);
} elseif ($end_timestamp) {
$formatted .= " - " . date('F j, Y \a\t H:i', $end_timestamp);
}
} else {
$months_lt = [
1 => "Sausio",
2 => "Vasario",
3 => "Kovo",
4 => "Balandžio",
5 => "Gegužės",
6 => "Birželio",
7 => "Liepos",
8 => "Rugpjūčio",
9 => "Rugsėjo",
10 => "Spalio",
11 => "Lapkričio",
12 => "Gruodžio",
];
$month = $months_lt[date("n", $start_timestamp)];
$formatted = $month . " " . date("j, Y H:i", $start_timestamp);
if (
$end_timestamp &&
date("Y-m-d", $start_timestamp) ===
date("Y-m-d", $end_timestamp)
) {
$formatted .= " - " . date("H:i", $end_timestamp);
} elseif ($end_timestamp) {
$end_month = $months_lt[date("n", $end_timestamp)];
$formatted .=
" - " . $end_month . " " . date("j, Y H:i", $end_timestamp);
}
}
return $formatted;
}
// Format event date for listings
private function format_event_date($date, $language = "lt")
{
$timestamp = strtotime($date);
if ($language === "en") {
return date("M j, Y", $timestamp);
} else {
$months_lt = [
1 => "Sau",
2 => "Vas",
3 => "Kov",
4 => "Bal",
5 => "Geg",
6 => "Bir",
7 => "Lie",
8 => "Rug",
9 => "Rug",
10 => "Spa",
11 => "Lap",
12 => "Gru",
];
$month = $months_lt[date("n", $timestamp)];
return $month . " " . date("j, Y", $timestamp);
}
}
// Event home shortcode
public function event_home_shortcode($atts)
{
$atts = shortcode_atts(
[
"limit" => 4,
"language" => null,
],
$atts
);
$events = $this->get_events(
$atts["limit"],
0,
$atts["language"],
[],
date("Y-m-d") // formatted date
);
ob_start();
if (empty($events)) {
?>
<div class="kauno-events-empty">Šiuo metu nėra artėjančių įvykių.</div>
<div class="events-footer"> <a href="<?php echo $this->get_all_events_url(); ?>" class="btn-all-events">Visi įvykiai</a></div>
<?php
} else {
?>
<div class="kauno-events-home">
<h2 class="events-title" >Artėjantys įvykiai</h2>
<div class="events-carousel">
<div class="events-slider">
<?php foreach ($events as $event): ?>
<div class="event-card">
<div class="event-content" style="background: transparent !important;">
<h3 class="event-title" style="margin: 10px 0px 18px 0;font-size: 10px !important;">
<a href="<?php echo $this->get_event_url(
$event->id
); ?>">
<?php echo esc_html($event->title); ?>
</a>
</h3>
<div class="event-date">
<?php echo $this->format_event_date(
$event->event_date,
$event->language
); ?>
</div>
<?php if ($event->location): ?>
<div class="event-location">
<?php echo esc_html($event->location); ?>
</div>
<?php endif; ?>
</div>
<div class="event-arrow" style="cursor: pointer;" onclick="window.location.href='<?php echo home_url(); ?>/event/<?php echo $event->event_slug; ?>'">
<svg width="70" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
<polyline points="9,18 15,12 9,6"></polyline>
</svg>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="events-footer"> <a href="<?php echo $this->get_all_events_url(); ?>" class="btn-all-events">Visi įvykiai</a></div>
</div>
<?php
}
return ob_get_clean();
}
public function event_list_shortcode($atts)
{
$atts = shortcode_atts(
[
"limit" => 2,
"language" => null,
"show_filters" => true,
],
$atts
);
$events = $this->get_events($atts["limit"], 0, $atts["language"]);
ob_start();
?>
<style>
.kauno-events-list {
max-width: 95%;
margin: 0 auto;
padding: 15px 0px 50px 0px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.events-filters {
display: flex;
justify-content: flex-end;
margin-bottom: 30px;
}
.event-sort-select {
background: #4ecdc4;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: right 8px center;
background-repeat: no-repeat;
background-size: 16px;
padding-right: 32px;
min-width: 200px;
}
.event-sort-select:hover {
background-color: #45b7aa;
}
.events-table {
background: white;
margin-bottom: 30px;
}
.event-row {
display: grid;
grid-template-columns: 200px 1fr 300px;
gap: 30px;
padding: 20px 0;
border-bottom: 1px solid #f0f0f0;
align-items: start;
}
.event-row:last-child {
border-bottom: none;
}
.event-date-col {
color: #333;
font-size: 14px;
font-weight: 400;
line-height: 1.4;
}
.event-info-col {
display: flex;
flex-direction: column;
gap: 8px;
}
.event-link {
margin: 0;
font-size: 16px;
font-weight: 500;
line-height: 1.3;
}
.event-link a {
color: #4ecdc4;
text-decoration: none;
transition: color 0.2s ease;
}
.event-link a:hover {
color: #45b7aa;
text-decoration: underline;
}
.event-location-col {
color: #666;
font-size: 14px;
font-weight: 400;
text-align: right;
line-height: 1.4;
}
.events-load-more {
display: flex;
justify-content: center;
margin-top: 40px;
}
.btn-load-more {
background: #4ecdc4;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s ease;
appearance: none;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: right 12px center;
background-repeat: no-repeat;
background-size: 16px;
padding-right: 40px;
}
.btn-load-more:hover {
background-color: #45b7aa;
}
.no-events {
text-align: center;
padding: 60px 20px;
color: #666;
font-size: 16px;
}
/* Responsive Design */
@media (max-width: 768px) {
.kauno-events-list {
padding: 15px;
}
.event-hero-content {
padding: 80px 0 60px 22px;
}
.container {
padding: 0 4px;
}
.event-row {
grid-template-columns: 1fr;
gap: 10px;
padding: 15px 0;
}
.event-location-col {
text-align: left;
margin-top: 5px;
}
.events-filters {
justify-content: center;
margin-bottom: 20px;
}
.event-sort-select {
min-width: 250px;
}
}
@media (max-width: 480px) {
.event-sort-select {
min-width: 100%;
max-width: 300px;
}
}
</style>
<div class="kauno-events-list">
<?php if ($atts["show_filters"]): ?>
<div class="sorting">
<div>
</div>
<div class="custom-dropdown-container ">
<select class="custom-dropdown-select event-sort-select" id="eventSortSelect" name="sortOrder">
<option value="date_desc">Data (naujausi pirma)</option>
<option value="date_asc">Data (seniausi pirma)</option>
<option value="title_asc">Pavadinimas (A-Z)</option>
<option value="title_desc">Pavadinimas (Z-A)</option>
</select>
<div class="custom-dropdown-lines">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
<?php endif; ?>
<div class="events-table" id="eventsContainer">
<?php if (empty($events)): ?>
<div class="no-events">
Šiuo metu nėra artėjančių įvykių.
</div>
<?php else: ?>
<?php foreach ($events as $event): ?>
<div class="event-row" data-date="<?php echo strtotime($event->event_date); ?>" data-title="<?php echo esc_attr($event->title); ?>">
<!-- Title -->
<div class="event-info-col">
<h3 class="event-link">
<a href="<?php echo esc_url($this->get_event_url($event->event_slug)); ?>">
<?php echo esc_html($event->title); ?>
</a>
</h3>
</div>
<!-- Date -->
<div class="abcf">
<div class="event-date-col">
<?php echo $this->format_event_date_detailed(
$event->event_date,
null,
$event->language
); ?>
</div>
<!-- Location -->
<div class="event-location-col">
<?php if ($event->address): ?>
<?php echo esc_html($event->address); ?>
<?php endif; ?>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php if (count($events) >= $atts["limit"]): ?>
<div class="events-load-more">
<button class="btn-load-more" data-total="<?php echo count($events); ?>" data-offset="<?php echo $atts[
"limit"
]; ?>" id="loadMoreButton">
Daugiau įvykių
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
</div>
<?php endif; ?>
</div>
<?php return ob_get_clean();
}
// Event detail shortcode (for embedding in pages)
public function event_detail_shortcode($atts)
{
$atts = shortcode_atts(
[
"id" => 0,
],
$atts
);
if (!$atts["id"]) {
return "<p>Event ID is required.</p>";
}
$event = $this->get_event($atts["event_slug"]);
if (!$event) {
return "<p>Event not found.</p>";
}
return $this->render_event_detail($event);
}
// Removed old custom_rewrite_rules function - using add_rewrite_rules instead
// AJAX: Handle event form submission
public function handle_event_form_submission()
{
check_ajax_referer("kauno_events_nonce", "nonce");
$event_id = intval($_POST["event_id"]);
$name = sanitize_text_field($_POST["name"]);
$email = sanitize_email($_POST["email"]);
$phone = sanitize_text_field($_POST["phone"]);
$message = sanitize_textarea_field($_POST["message"]);
$participants = intval($_POST["participants"]) ?: 1;
if (!$event_id || !$name || !$email) {
wp_send_json_error("Required fields are missing.");
}
global $wpdb;
$submissions_table = $this->get_submissions_table();
$result = $wpdb->insert($submissions_table, [
"event_id" => $event_id,
"site_id" => get_current_blog_id(),
"name" => $name,
"email" => $email,
"phone" => $phone,
"message" => $message,
"participants" => $participants,
"status" => "new",
]);
if ($result) {
// Send confirmation email (optional)
$this->send_registration_confirmation($email, $name, $event_id);
wp_send_json_success(
"Registration successful! You will receive a confirmation email shortly."
);
} else {
wp_send_json_error("Registration failed. Please try again.");
}
}
// AJAX: Load more events
public function load_more_events()
{
// $this->check_ajax_nonce(); // Uncomment if you're using nonce validation
$offset = intval($_POST["offset"]);
// Sanitize exclude_ids
$exclude_ids = [];
if (!empty($_POST['exclude_ids']) && is_array($_POST['exclude_ids'])) {
$exclude_ids = array_map('intval', $_POST['exclude_ids']);
}
// Fetch events
$events = $this->get_events(10, $offset, "", $exclude_ids);
if (empty($events)) {
wp_send_json_error("No more events found.");
}
$html = '';
foreach ($events as $event) {
$html .= '<div class="event-row" data-date="' . strtotime($event->event_date) . '" data-title="' . esc_attr($event->title) . '" data-id="' . intval($event->id) . '">';
// Title
$html .= '<div class="event-info-col">';
$html .= '<h3 class="event-link">';
$html .= '<a href="' . esc_url($this->get_event_url($event->event_slug)) . '">';
$html .= esc_html($event->title);
$html .= '</a>';
$html .= '</h3>';
$html .= '</div>';
// Date + Location wrapped in abcf
$html .= '<div class="abcf">';
// Date
$html .= '<div class="event-date-col">';
$html .= $this->format_event_date_detailed($event->event_date, null, $event->language);
$html .= '</div>';
// Location
$html .= '<div class="event-location-col">';
if (!empty($event->address)) {
$html .= esc_html($event->address);
}
$html .= '</div>';
$html .= '</div>'; // close abcf
$html .= '</div>'; // close event-row
}
$has_more = count($events) === 10;
wp_send_json_success([
'html' => $html,
'has_more' => $has_more,
'count' => count($events),
]);
}
// Image upload handler
public function handle_image_upload()
{
check_ajax_referer("kauno_events_nonce", "nonce");
if (!current_user_can("manage_options")) {
wp_send_json_error("Insufficient permissions");
}
if (!function_exists("wp_handle_upload")) {
require_once ABSPATH . "wp-admin/includes/file.php";
}
$uploaded_files = [];
if (!empty($_FILES["images"])) {
$files = $_FILES["images"];
for ($i = 0; $i < count($files["name"]); $i++) {
if ($files["error"][$i] === UPLOAD_ERR_OK) {
$file = [
"name" => $files["name"][$i],
"type" => $files["type"][$i],
"tmp_name" => $files["tmp_name"][$i],
"error" => $files["error"][$i],
"size" => $files["size"][$i],
];
$upload = wp_handle_upload($file, ["test_form" => false]);
if (!isset($upload["error"])) {
$uploaded_files[] = $upload["url"];
}
}
}
}
wp_send_json_success($uploaded_files);
}
// Image delete handler
public function handle_image_delete()
{
check_ajax_referer("kauno_events_nonce", "nonce");
if (!current_user_can("manage_options")) {
wp_send_json_error("Insufficient permissions");
}
$image_url = sanitize_url($_POST["image_url"]);
// Get the file path from URL
$upload_dir = wp_upload_dir();
$file_path = str_replace(
$upload_dir["baseurl"],
$upload_dir["basedir"],
$image_url
);
if (file_exists($file_path)) {
unlink($file_path);
wp_send_json_success("Image deleted");
} else {
wp_send_json_error("Image not found");
}
}
// Helper functions
private function get_event_url($event_slug)
{
return home_url("/event/" . $event_slug . "/");
}
private function get_all_events_url()
{
return home_url("/events/");
}
private function get_current_url()
{
return (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] === "on"
? "https"
: "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
}
// Send registration confirmation email
private function send_registration_confirmation($email, $name, $event_id)
{
// Get event by ID for internal operations
global $wpdb;
$events_table = $this->get_events_table();
$event = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM $events_table WHERE id = %d AND status = 'active'",
$event_id
)
);
if (!$event) {
return;
}
$subject = "Event Registration Confirmation - " . $event->title;
$message = "Dear $name,\n\n";
$message .= "Thank you for registering for the event: {$event->title}\n\n";
$message .= "Event Details:\n";
$message .=
"Date: " .
$this->format_event_date_detailed(
$event->event_date,
$event->end_date,
"en"
) .
"\n";
if ($event->location) {
$message .= "Location: {$event->location}\n";
}
$message .= "\nWe look forward to seeing you at the event!\n\n";
$message .= "Best regards,\nKauno Events Team";
wp_mail($email, $subject, $message);
}
}
// Initialize plugin
new KaunoEventsPlugin();
function scriptmine()
{
?>
<script>
document.addEventListener('DOMContentLoaded', function () {
const sortSelect = document.getElementById('eventSortSelect');
const eventsContainer = document.getElementById('eventsContainer');
if (sortSelect && eventsContainer) {
sortSelect.addEventListener('change', function () {
const sortValue = this.value;
const eventRows = Array.from(eventsContainer.querySelectorAll('.event-row'));
eventRows.sort(function (a, b) {
if (sortValue === 'date_asc') {
return parseInt(a.dataset.date, 10) - parseInt(b.dataset.date, 10);
} else if (sortValue === 'date_desc') {
return parseInt(b.dataset.date, 10) - parseInt(a.dataset.date, 10);
} else if (sortValue === 'title_asc') {
return a.dataset.title.localeCompare(b.dataset.title);
} else if (sortValue === 'title_desc') {
return b.dataset.title.localeCompare(a.dataset.title);
}
return 0;
});
// Re-render sorted items
eventsContainer.innerHTML = '';
eventRows.forEach(function (row) {
eventsContainer.appendChild(row);
});
});
}
});
// Load more functionality
// Store IDs of already loaded events globally
const loadedEventIds = new Set();
function loadMoreEvents(button) {
const offset = parseInt(button.dataset.offset, 10);
const originalText = button.textContent;
button.textContent = 'Kraunama...';
button.disabled = true;
const formData = new FormData();
formData.append('action', 'load_more_events');
formData.append('offset', offset);
formData.append('nonce', '<?php echo wp_create_nonce("kauno_events_nonce"); ?>');
// Include existing IDs to backend for exclusion
loadedEventIds.forEach(id => formData.append('exclude_ids[]', id));
fetch('<?php echo admin_url("admin-ajax.php"); ?>', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => {
if (!data.success) {
button.textContent = 'Klaida';
button.disabled = false;
return;
}
const { html, count, has_more } = data.data;
if (count > 0) {
const tempDiv = document.createElement('div');
tempDiv.innerHTML = html;
console.log(data)
tempDiv.querySelectorAll('.event-row[data-id]').forEach(el => {
const id = el.getAttribute('data-id');
if (!loadedEventIds.has(id)) {
loadedEventIds.add(id);
document.getElementById('eventsContainer').appendChild(el);
}
});
button.dataset.offset = offset + count;
}
if (!has_more || count === 0) {
button.style.display = 'none';
} else {
button.textContent = originalText;
button.disabled = false;
}
})
.catch(err => {
console.error('Load more error:', err);
button.textContent = originalText;
button.disabled = false;
});
}
document.addEventListener('DOMContentLoaded', () => {
const loadMoreButton = document.getElementById('loadMoreButton');
if (loadMoreButton && !loadMoreButton.dataset.listenerAttached) {
loadMoreButton.dataset.listenerAttached = 'true'; // ✅ Mark as attached
loadMoreButton.addEventListener('click', function (event) {
event.preventDefault();
loadMoreEvents(this);
});
}
});
</script>
<?php
}
add_action("wp_head", "scriptmine");
?>