// NoFestival – Create a custom metabox function nofestival_add_event_date_metabox() { add_meta_box( ‘nofestival_event_date_metabox’, ‘Event Date’, ‘nofestival_display_event_date_metabox’, ‘post’, // You can specify other post types if needed ‘normal’, ‘high’ ); } // NoFestival – Display the custom field in the metabox function nofestival_display_event_date_metabox($post) { $event_date = get_post_meta($post->ID, ‘_event_date’, true); echo ‘<label for=”event_date”>Event Date:</label>’; echo ‘<input type=”date” id=”event_date” name=”event_date” value=”‘ . esc_attr($event_date) . ‘” />’; } // NoFestival – Save the custom field data when the post is saved function nofestival_save_event_date($post_id) { if (defined(‘DOING_AUTOSAVE’) && DOING_AUTOSAVE) return; if (!current_user_can(‘edit_post’, $post_id)) return; $event_date = sanitize_text_field($_POST[‘event_date’]); update_post_meta($post_id, ‘_event_date’, $event_date); } add_action(‘add_meta_boxes’, ‘nofestival_add_event_date_metabox’); add_action(‘save_post’, ‘nofestival_save_event_date’);

add custom.js

document.addEventListener("DOMContentLoaded", function () {
const menuToggle = document.querySelector(".menu-toggle");
const mainNavigation = document.querySelector(".main-navigation");

const menuIcon = document.querySelector(".menu-toggle i");

menuToggle.addEventListener("click", function () {
mainNavigation.classList.toggle("mobile-menu-open");

if (mainNavigation.classList.contains("mobile-menu-open")) {
menuIcon.classList.add("rotate-icon");
} else {
menuIcon.classList.remove("rotate-icon");
}
});
const menuItems = document.querySelectorAll(".menu-item");

menuItems.forEach(function (item) {
item.addEventListener("click", function (event) {
mainNavigation.classList.remove("mobile-menu-open");
menuIcon.classList.remove("rotate-icon");
});
});
});

Add to functions.php

class [your-theme-name]_Walker_Nav_Menu extends Walker_Nav_Menu {
  function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {
    // Add "has-submenu" class to top-level items with submenus
    if ( in_array( 'menu-item-has-children', $item->classes ) && $depth === 0 ) {
      $item->classes[] = 'has-submenu';
    }
    // Continue with the default start_el() method
    parent::start_el( $output, $item, $depth, $args );
  }
}
function [your-theme-name]_enqueue_scripts() {
    wp_enqueue_script('[your-theme-name]-custom', get_template_directory_uri() . '/js/custom.js', array('jquery'), '1.0', true);
}

add_action('wp_enqueue_scripts', '[your-theme-name]_enqueue_scripts');

Add to Header.php

<nav id="site-navigation" class="main-navigation">
  <?php
  wp_nav_menu(
    array(
      'theme_location' => 'primary',
      'menu_id'        => 'primary-menu',
      'walker'         => new [your-theme-name]_Walker_Nav_Menu(),
    )
  );
  ?>
</nav><!-- #site-navigation -->

Add to style.css


/* Navigation */
.main-navigation {
  width: 300px;
}

.main-navigation ul,
.sub-menu {
  list-style: none;
  padding: 0;
  margin: 0;
}

.main-navigation a {
  display: block;
  text-decoration: none;
  padding: 10px;
  color: #FFF;
  transition: background-color 0.3s, color 0.3s;
}

.main-navigation a:hover {
  background-color: #FF4F00;
  color: #fff;
}

.main-navigation.mobile-menu-open .sub-menu {
  display: block;
  max-height: 400px; /* Adjust max-height as needed */
  overflow: visible;
}

.main-navigation ul.sub-menu a {
  color: #fff;
}

.main-navigation ul.sub-menu a:hover {
  background-color: #FF4F00;
}

.main-navigation.mobile-menu-open ul.sub-menu {
  max-height: 400px; /* Adjust max-height as needed */
  overflow: visible;
}

.menu-toggle {
  background: none;
  border: none;
  font-size: 24px;
  cursor: pointer;
  transition: transform 0.3s ease;
}

.menu-toggle.rotate {
  transform: rotate(360deg);
}

.menu-toggle p {
  margin: 0;
  padding-left: 0.2em;
}

.menu-toggle i {
   transition: transform 1s ease;
}

/* Rotate the icon when the "rotate-icon" class is applied */
.menu-toggle i.rotate-icon {
  transform: rotate(180deg);
}

.main-navigation ul,
.main-navigation ul.sub-menu {
  display: none;
}

.main-navigation.mobile-menu-open ul,
.main-navigation.mobile-menu-open ul.sub-menu {
  display: block;
  max-height: 400px; /* Adjust max-height as needed */
  overflow: visible;
  transition: max-height 1s ease-out;
}


/* CSS for submenus on larger screens */
@media screen and (min-width: 48.6em) {

	.main-navigation a {
  display: block;
  text-decoration: none;
  padding: 10px;
  color: #FFF; /* Text color */
}
	
/* Add hover behavior for all links */
.main-navigation a:hover {
  background-color: FF4F00; /* Hover background color */
  color: #fff;
}

/* Display submenus on hover */
.main-navigation li:hover > ul.sub-menu {
  display: block;
}

/* Style submenu links */
.main-navigation ul.sub-menu a {
  color: #fff;
}

/* Hover behavior for links inside submenus */
.main-navigation ul.sub-menu a:hover {
  background-color: #FF4F00; /* Hover background color */
}
}

a bit of text here….


// NoFestival - Create a custom metabox
function nofestival_add_event_details_metabox() {
    add_meta_box(
        'nofestival_event_details_metabox',
        'Event Details', // Updated title to include details
        'nofestival_display_event_details_metabox',
        'post', // You can specify other post types if needed
        'normal',
        'high'
    );
}
// Set the default timezone to Europe/Paris
date_default_timezone_set('Europe/Paris');

// NoFestival - Display the custom fields in the metabox
function nofestival_display_event_details_metabox($post) {
    $event_date = get_post_meta($post->ID, '_event_date', true);
    $event_start_time = get_post_meta($post->ID, '_event_start_time', true); // Added start time field
    $event_end_time = get_post_meta($post->ID, '_event_end_time', true); // Added end time field
    $event_location = get_post_meta($post->ID, '_event_location', true);
	$event_end_date = get_post_meta($post->ID, '_event_end_date', true); // Added end date field

    echo '<label for="event_date">Event Date:</label>';
    echo '<input type="date" id="event_date" name="event_date" value="' . esc_attr($event_date) . '" />';
    
    echo '<br><br>'; // Add some spacing between the fields

    echo '<label for="event_start_time">Start Time:</label>';
    echo '<input type="time" id="event_start_time" name="event_start_time" value="' . esc_attr($event_start_time) . '" />';

    echo '<br><br>'; // Add some spacing between the fields
	
	echo '<label for="event_end_date">Event End Date:</label>';
    echo '<input type="date" id="event_end_date" name="event_end_date" value="' . esc_attr($event_end_date) . '" />';
	
	echo '<br><br>'; // Add some spacing between the fields

    echo '<label for="event_end_time">End Time:</label>';
    echo '<input type="time" id="event_end_time" name="event_end_time" value="' . esc_attr($event_end_time) . '" />';

    echo '<br><br>'; // Add some spacing between the fields

    echo '<label for="event_location">Event Location:</label>';
    echo '<input type="text" id="event_location" name="event_location" value="' . esc_attr($event_location) . '" />';
}




// NoFestival - Save the custom field data when the post is saved
function nofestival_save_event_details($post_id) {
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_post', $post_id)) return;

    $event_date = sanitize_text_field($_POST['event_date']);
    $event_start_time = sanitize_text_field($_POST['event_start_time']); // Added start time field
	$event_end_date = sanitize_text_field($_POST['event_end_date']); // Added end date field
    $event_end_time = sanitize_text_field($_POST['event_end_time']); // Added end time field
    $event_location = sanitize_text_field($_POST['event_location']);

    update_post_meta($post_id, '_event_date', $event_date);
    update_post_meta($post_id, '_event_start_time', $event_start_time); // Added start time field
	update_post_meta($post_id, '_event_end_date', $event_end_date); // Added end date field
    update_post_meta($post_id, '_event_end_time', $event_end_time); // Added end time field
    update_post_meta($post_id, '_event_location', $event_location);
}

add_action('add_meta_boxes', 'nofestival_add_event_details_metabox');
add_action('save_post', 'nofestival_save_event_details');

// Set the default timezone to Europe/Paris
date_default_timezone_set('Europe/Paris');

// NoFestival - Shortcode to display upcoming, happening, and past events
function nofestival_event_timeline_shortcode($atts) {
    // ...

    $args = array(
        'post_type'      => 'post',
        'meta_query'     => array(
            'relation' => 'AND',
            array(
                'key'     => '_event_date',
                'compare' => 'EXISTS', // Check if the meta key exists
            ),
            array(
                'key'     => '_event_end_date',
                'compare' => 'EXISTS', // Check if the end date meta key exists
            ),
        ),
        'orderby'        => 'meta_value',
        'order'          => 'DESC',
        'posts_per_page' => -1,
    );

    $query = new WP_Query($args);

    if ($query->have_posts()) :
        echo '<div class="event-timeline">';

        // Use current date and time based on Europe/Paris timezone
        $current_date = date('Y-m-d');
        $current_time = date('H:i');

        while ($query->have_posts()) : $query->the_post();

            $event_date = get_post_meta(get_the_ID(), '_event_date', true);
			$event_end_date = get_post_meta(get_the_ID(), '_event_end_date', true);

          // Check if event_date is empty or invalid
            if (empty($event_date) || strtotime($event_date) === false) {
                continue;
            }

            $event_start_time = get_post_meta(get_the_ID(), '_event_start_time', true);
            $event_end_time = get_post_meta(get_the_ID(), '_event_end_time', true);

            // Use _event_date as the end date if _event_end_date is empty
            $event_end_date = empty($event_end_date) ? $event_date : $event_end_date;

            // Calculate the full event start and end date/time
            $event_start_datetime = strtotime($event_date . ' ' . $event_start_time);
            $event_end_datetime = strtotime($event_end_date . ' ' . $event_end_time);

            // Check if the current time is within the event's start and end time
            if (
    $current_date >= $event_date && $current_date <= $event_end_date &&
    $current_time >= $event_start_time && $current_time <= $event_end_time
) {
    // Happening event
    $happening_events[] = get_event_markup($event_date, $event_start_time, $event_end_time);
} elseif ($current_date <= $event_end_date && $current_date >= $event_date) {
    // Event spans multiple days, consider it happening
    $happening_events[] = get_event_markup($event_date, $event_start_time, $event_end_time);
} elseif ($current_date <= $event_end_date && ($current_date < $event_date || ($current_date == $event_date && $current_time < $event_start_time))) {
    // Upcoming event
    $upcoming_events[] = get_event_markup($event_date, $event_start_time, $event_end_time);
} else {
    // Past event
    $past_events[] = get_event_markup($event_date, $event_start_time, $event_end_time);
}

        endwhile;

        // Display happening events
        if (!empty($happening_events)) {
            echo '<div class="happening-section">';
            echo '<h2>HAPPENING!!</h2>';
            echo implode('', $happening_events);
            echo '</div>';
        }

        // Display upcoming events
        if (!empty($upcoming_events)) {
			echo '<div class="upcoming-section">';
            echo '<h2 sytle="border-bottom: solid 1px darkmagenta;">UPCOMING EVENTS</h2>';
            echo implode('', $upcoming_events);
        }

        // Display past events
        if (!empty($past_events)) {
            echo '<div class="past-events">';
            echo '<h2>PAST EVENTS</h2>';
            echo implode('', $past_events);
            echo '</div>';
        }

        echo '</div>';
        wp_reset_postdata();
    else :
        echo 'No events found.';
    endif;

    return ob_get_clean();
}

add_shortcode('event_timeline', 'nofestival_event_timeline_shortcode');


function custom_limit_excerpt_length($excerpt, $length = 100) {
    if (mb_strlen($excerpt, 'UTF-8') > $length) {
        $excerpt = mb_substr($excerpt, 0, $length - 3, 'UTF-8') . '...';
    }
    return $excerpt;
}

// Function to get event markup
function get_event_markup($event_date) {
    $event_start_time = get_post_meta(get_the_ID(), '_event_start_time', true);
    $event_end_time = get_post_meta(get_the_ID(), '_event_end_time', true);
    $event_location = get_post_meta(get_the_ID(), '_event_location', true);
    $event_end_date = get_post_meta(get_the_ID(), '_event_end_date', true);

    $markup = '<div class="event-item">';

    $markup .= '<h2 class="event-title"><i class="fa-solid fa-hand-pointer fa-rotate-90" style="color: #FF4F00"></i>  <a href="' . esc_url(get_permalink()) . '">' . get_the_title() . '</a></h2>';

    // Format the start date
    $formatted_start_date = date('D j M', strtotime($event_date));

    // Format the end date if available
    $formatted_end_date = !empty($event_end_date) ? ' <i class="fa-solid fa-angles-right"></i> ' . date('D j M', strtotime($event_end_date)) : '';

    $markup .= '<p class="event-date">' . $formatted_start_date . ' : ' . $event_start_time . ' - ' . $event_end_time . $formatted_end_date . '</p>';
    $markup .= '<p class="event-location">' . $event_location . '</p>';
    
    // Include other event details as needed
    // ...

    $excerpt = get_the_excerpt();
    $limited_excerpt = custom_limit_excerpt_length($excerpt, 100);
    $markup .= '<p class="event-excerpt">' . $limited_excerpt . '</p>';

    $markup .= '</div>';

    return $markup;
}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut a sapien. Aliquam aliquet purus molestie dolor. Integer quis eros ut erat posuere dictum. Curabitur dignissim. Integer orci. Fusce vulputate lacus at ipsum. Quisque in libero nec mi laoreet volutpat. Aliquam eros pede, scelerisque quis, tristique cursus, placerat convallis, velit. Nam condimentum. Nulla ut mauris. Curabitur adipiscing, mauris non dictum aliquam, arcu risus dapibus diam, nec sollicitudin quam erat quis ligula. Aenean massa nulla, volutpat eu, accumsan et, fringilla eget, odio. Nulla placerat porta justo. Nulla vitae turpis. Praesent lacus.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut a sapien. Aliquam aliquet purus molestie dolor. Integer quis eros ut erat posuere dictum. Curabitur dignissim. Integer orci. Fusce vulputate lacus at ipsum. Quisque in libero nec mi laoreet volutpat. Aliquam eros pede, scelerisque quis, tristique cursus, placerat convallis, velit. Nam condimentum. Nulla ut mauris. Curabitur adipiscing, mauris non dictum aliquam, arcu risus dapibus diam, nec sollicitudin quam erat quis ligula. Aenean massa nulla, volutpat eu, accumsan et, fringilla eget, odio. Nulla placerat porta justo. Nulla vitae turpis. Praesent lacus.