diff --git a/README.md b/README.md
index 6781975..b9312fd 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+<<<<<<< Updated upstream
# WordPress FOSSASIA Event Plugin (WPFAevent)
The **FOSSASIA Event Plugin** provides WordPress integrations for [Eventyay](https://eventyay.com)-based events.
@@ -183,3 +184,45 @@ Before submitting:
Licensed under the **Apache License, Version 2.0**
Copyright © 2025 [FOSSASIA](https://fossasia.org)
+=======
+# FOSSASIA Event WordPress Plugin
+
+A plugin to create and manage event landing pages, speakers, schedules, and sponsors within WordPress using Custom Post Types.
+
+## Features
+- Creates `Event` and `Speaker` Custom Post Types (CPTs).
+- Provides a clean, database-driven way to manage event data.
+- (For Developers) A WP-CLI command to seed test data for development and testing.
+
+## Getting Started
+
+1. **Install and Activate** the plugin.
+2. You will see new "Events" and "Speakers" menu items in your WordPress admin sidebar.
+3. You can now create and manage events and speakers just like standard WordPress posts.
+4. To display your content, you will use shortcodes (e.g., `[wpfa_speakers]`) or custom templates that query these new post types.
+
+
+## For Developers: Seeding Data with WP-CLI
+
+The plugin includes a WP-CLI command for developers to quickly seed test data. This is useful for setting up a development environment, especially when working with the Custom Post Type architecture.
+
+**Prerequisites:**
+- WP-CLI must be installed.
+- The plugin must be activated.
+
+**Commands:**
+
+1. **Seed Minimal Data:**
+ This command creates 2 placeholder speakers and 1 event in the database.
+ ```bash
+ wp wpfa seed --minimal
+ ```
+
+2. **Seed from JSON file:**
+ This command populates CPT data from a specified JSON file. A sample fixture is included in the plugin.
+ ```bash
+ wp wpfa seed --from-json=wp-content/plugins/wpfa-event/assets/demo/minimal.json
+ ```
+
+The seeder command is **idempotent**, meaning it is safe to re-run. It will update existing posts based on their slugs instead of creating duplicates.
+>>>>>>> Stashed changes
diff --git a/fossasia-landing.php b/fossasia-landing.php
new file mode 100644
index 0000000..7c250e5
--- /dev/null
+++ b/fossasia-landing.php
@@ -0,0 +1,89 @@
+setup_constants();
+ self::$instance->includes();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * Setup plugin constants.
+ */
+ private function setup_constants() {
+ // Plugin version.
+ define( 'WPFA_EVENT_VERSION', '1.0.0' );
+ }
+
+ /**
+ * Include required files.
+ */
+ private function includes() {
+ require_once WPFA_EVENT_PLUGIN_DIR . 'includes/class-wpfa-cpt.php';
+ require_once WPFA_EVENT_PLUGIN_DIR . 'public/class-wpfa-public.php';
+
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
+ require_once WPFA_EVENT_PLUGIN_DIR . 'includes/class-wpfa-cli.php';
+ }
+ }
+
+ /**
+ * Run the plugin.
+ */
+ public function run() {
+ $cpt_handler = new WPFA_CPT();
+ $public_handler = new WPFA_Public( 'wpfa-event', WPFA_EVENT_VERSION );
+
+ add_action( 'init', array( $cpt_handler, 'register_cpts' ) );
+ add_action( 'init', array( $cpt_handler, 'register_meta' ) );
+
+ add_action( 'wp_enqueue_scripts', array( $public_handler, 'enqueue_styles' ) );
+ add_action( 'init', array( $public_handler, 'register_shortcodes' ) );
+ }
+}
+
+/**
+ * Begins execution of the plugin.
+ */
+function run_wpfa_event() {
+ $plugin = WPFA_Event::instance();
+ $plugin->run();
+}
+
+add_action( 'plugins_loaded', 'run_wpfa_event' );
+
+// Register WP-CLI command if in CLI context.
+if ( defined( 'WP_CLI' ) && WP_CLI ) {
+ WP_CLI::add_command( 'wpfa', 'WPFA_CLI' );
+}
diff --git a/includes/class-fossasia-uninstaller.php b/includes/class-fossasia-uninstaller.php
new file mode 100644
index 0000000..4e04e01
--- /dev/null
+++ b/includes/class-fossasia-uninstaller.php
@@ -0,0 +1,73 @@
+ $post_type,
+ 'posts_per_page' => -1,
+ 'fields' => 'ids',
+ ] );
+
+ if ( $query->have_posts() ) {
+ foreach ( $query->posts as $post_id ) {
+ wp_delete_post( $post_id, true );
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes the plugin's data directory using the WP_Filesystem API.
+ */
+ private static function delete_data_directory() {
+ global $wp_filesystem;
+
+ // Ensure the filesystem is initialized.
+ if ( empty( $wp_filesystem ) ) {
+ require_once ABSPATH . '/wp-admin/includes/file.php';
+ WP_Filesystem();
+ }
+
+ $upload_dir = wp_upload_dir();
+ $data_dir = $upload_dir['basedir'] . '/fossasia-data';
+
+ if ( $wp_filesystem->is_dir( $data_dir ) ) {
+ $wp_filesystem->rmdir( $data_dir, true );
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/class-wpfa-cli.php b/includes/class-wpfa-cli.php
new file mode 100644
index 0000000..5666df4
--- /dev/null
+++ b/includes/class-wpfa-cli.php
@@ -0,0 +1,236 @@
+]
+ * : Path to a JSON file with seed data.
+ *
+ * ## EXAMPLES
+ * wp wpfa seed --minimal
+ * wp wpfa seed --from-json=wp-content/plugins/wpfa-event/assets/demo/minimal.json
+ *
+ * @when after_wp_load
+ *
+ * @param array $args
+ * @param array $assoc_args
+ */
+ public static function seed( $args, $assoc_args ) {
+ if ( isset( $assoc_args['from-json'] ) ) {
+ self::seed_from_json( $assoc_args['from-json'] );
+ return;
+ }
+
+ if ( isset( $assoc_args['minimal'] ) ) {
+ self::seed_minimal();
+ return;
+ }
+
+ WP_CLI::error( 'No option provided. Use --minimal or --from-json=.' );
+ }
+
+ /**
+ * Minimal hardcoded seed (2 speakers, 1 event).
+ */
+ private static function seed_minimal() {
+ $placeholder = 'https://via.placeholder.com/150';
+
+ $speakers = [
+ [
+ 'post_title' => 'Alex Example',
+ 'post_content' => 'Open source contributor and community speaker.',
+ 'meta' => [
+ 'wpfa_speaker_org' => 'FOSSASIA',
+ 'wpfa_speaker_position' => 'Developer Advocate',
+ 'wpfa_speaker_photo_url' => $placeholder,
+ ],
+ 'slug' => 'alex-example',
+ ],
+ [
+ 'post_title' => 'Bao Nguyen',
+ 'post_content' => 'Engineer focusing on event platforms and accessibility.',
+ 'meta' => [
+ 'wpfa_speaker_org' => 'Eventyay',
+ 'wpfa_speaker_position' => 'Software Engineer',
+ 'wpfa_speaker_photo_url' => $placeholder,
+ ],
+ 'slug' => 'bao-nguyen',
+ ],
+ ];
+
+ $event = [
+ 'post_title' => 'FOSSASIA Community Meetup',
+ 'post_content' => 'A casual meetup to discuss the roadmap and OSS collaboration.',
+ 'meta' => [
+ 'wpfa_event_start_date' => date( 'Y-m-d', strtotime( '+30 days' ) ),
+ 'wpfa_event_end_date' => date( 'Y-m-d', strtotime( '+31 days' ) ),
+ 'wpfa_event_location' => 'Online',
+ 'wpfa_event_url' => 'https://eventyay.com/',
+ ],
+ 'slug' => 'fossasia-community-meetup',
+ ];
+
+ // Insert speakers (idempotent by slug).
+ $speaker_ids = [];
+ foreach ( $speakers as $s ) {
+ $speaker_ids[] = self::upsert_post_by_slug(
+ 'wpfa_speaker',
+ sanitize_title( $s['slug'] ),
+ [
+ 'post_title' => $s['post_title'],
+ 'post_content' => $s['post_content'],
+ 'post_status' => 'publish',
+ 'post_type' => 'wpfa_speaker', // Ensure this matches your CPT slug
+ ],
+ $s['meta']
+ );
+ }
+
+ // Insert event (idempotent by slug).
+ $event_id = self::upsert_post_by_slug(
+ 'wpfa_event',
+ sanitize_title( $event['slug'] ),
+ [
+ 'post_title' => $event['post_title'],
+ 'post_content' => $event['post_content'],
+ 'post_status' => 'publish',
+ 'post_type' => 'wpfa_event', // Ensure this matches your CPT slug
+ ],
+ $event['meta']
+ );
+
+ // Relate event ↔ speakers (store both sides; skip if already there).
+ self::sync_relationships( $event_id, $speaker_ids );
+
+ WP_CLI::success( 'Seeded minimal data: 2 speakers, 1 event.' );
+ }
+
+ /**
+ * Seed from JSON file.
+ *
+ * @param string $path
+ */
+ private static function seed_from_json( $path ) {
+ if ( ! file_exists( $path ) ) {
+ WP_CLI::error( "JSON file not found: {$path}" );
+ }
+ $json = file_get_contents( $path );
+ if ( false === $json ) {
+ WP_CLI::error( "Unable to read JSON file: {$path}" );
+ }
+
+ $data = json_decode( $json, true );
+ if ( ! is_array( $data ) ) {
+ WP_CLI::error( 'Invalid JSON structure.' );
+ }
+
+ // Insert speakers first.
+ $slug_to_id = [];
+ if ( ! empty( $data['speakers'] ) && is_array( $data['speakers'] ) ) {
+ foreach ( $data['speakers'] as $s ) {
+ $slug = sanitize_title( $s['slug'] ?? $s['title'] ?? wp_generate_uuid4() );
+ $title = sanitize_text_field( $s['title'] ?? 'Speaker' );
+ $content = wp_kses_post( $s['content'] ?? '' );
+
+ $meta = [
+ 'wpfa_speaker_org' => isset( $s['org'] ) ? sanitize_text_field( $s['org'] ) : '',
+ 'wpfa_speaker_position' => isset( $s['position'] ) ? sanitize_text_field( $s['position'] ) : '',
+ 'wpfa_speaker_photo_url' => isset( $s['photo'] ) ? esc_url_raw( $s['photo'] ) : 'https://via.placeholder.com/150',
+ ];
+
+ $id = self::upsert_post_by_slug( 'wpfa_speaker', $slug, [ 'post_title' => $title, 'post_content' => $content, 'post_status' => 'publish', 'post_type' => 'wpfa_speaker', ], $meta );
+ $slug_to_id[ $slug ] = $id;
+ }
+ }
+
+ // Insert events and relate to speakers from slugs.
+ if ( ! empty( $data['events'] ) && is_array( $data['events'] ) ) {
+ foreach ( $data['events'] as $e ) {
+ $slug = sanitize_title( $e['slug'] ?? $e['title'] ?? wp_generate_uuid4() );
+ $title = sanitize_text_field( $e['title'] ?? 'Event' );
+ $content = wp_kses_post( $e['content'] ?? '' );
+
+ $meta = [
+ 'wpfa_event_start_date' => isset( $e['start_date'] ) ? sanitize_text_field( $e['start_date'] ) : '',
+ 'wpfa_event_end_date' => isset( $e['end_date'] ) ? sanitize_text_field( $e['end_date'] ) : '',
+ 'wpfa_event_location' => isset( $e['location'] ) ? sanitize_text_field( $e['location'] ) : '',
+ 'wpfa_event_url' => isset( $e['url'] ) ? esc_url_raw( $e['url'] ) : '',
+ ];
+
+ $event_id = self::upsert_post_by_slug( 'wpfa_event', $slug, [ 'post_title' => $title, 'post_content' => $content, 'post_status' => 'publish', 'post_type' => 'wpfa_event', ], $meta );
+
+ $event_speaker_slugs = ! empty( $e['speakers'] ) && is_array( $e['speakers'] ) ? $e['speakers'] : [];
+ $speaker_ids = array_values( array_intersect_key( $slug_to_id, array_flip( $event_speaker_slugs ) ) );
+
+ self::sync_relationships( $event_id, $speaker_ids );
+ }
+ }
+
+ WP_CLI::success( 'Seeded data from JSON.' );
+ }
+
+ /**
+ * Upsert by slug: create the post if not found; otherwise update meta.
+ */
+ private static function upsert_post_by_slug( $post_type, $slug, $postarr, $meta ) {
+ $existing = get_page_by_path( $slug, OBJECT, $post_type );
+ if ( $existing ) {
+ $post_id = $existing->ID;
+ $postarr['ID'] = $post_id;
+ wp_update_post( $postarr );
+ } else {
+ $postarr['post_name'] = $slug;
+ $post_id = wp_insert_post( $postarr );
+ }
+
+ if ( is_wp_error( $post_id ) || ! $post_id ) {
+ WP_CLI::warning( "Failed to upsert {$post_type} : {$slug}" );
+ return 0;
+ }
+
+ update_post_meta( $post_id, '_wpfa_seeded', 1 );
+ if ( is_array( $meta ) ) {
+ foreach ( $meta as $k => $v ) {
+ update_post_meta( $post_id, $k, $v );
+ }
+ }
+ return $post_id;
+ }
+
+ /**
+ * Sync event <-> speakers relationships.
+ */
+ private static function sync_relationships( $event_id, $speaker_ids ) {
+ $event_id = absint( $event_id );
+ $speaker_ids = array_values( array_unique( array_map( 'absint', $speaker_ids ) ) );
+
+ if ( ! $event_id || empty( $speaker_ids ) ) {
+ return;
+ }
+
+ $current = (array) get_post_meta( $event_id, 'wpfa_event_speakers', true );
+ $new = array_values( array_unique( array_merge( $current, $speaker_ids ) ) );
+ update_post_meta( $event_id, 'wpfa_event_speakers', $new );
+
+ foreach ( $speaker_ids as $sid ) {
+ $cur = (array) get_post_meta( $sid, 'wpfa_speaker_events', true );
+ if ( ! in_array( $event_id, $cur, true ) ) {
+ $cur[] = $event_id;
+ }
+ update_post_meta( $sid, 'wpfa_speaker_events', array_values( array_unique( $cur ) ) );
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/class-wpfa-cpt.php b/includes/class-wpfa-cpt.php
new file mode 100644
index 0000000..cbe1170
--- /dev/null
+++ b/includes/class-wpfa-cpt.php
@@ -0,0 +1,59 @@
+ array(
+ 'name' => __( 'Events', 'wpfa-event' ),
+ 'singular_name' => __( 'Event', 'wpfa-event' ),
+ ),
+ 'public' => true,
+ 'has_archive' => true,
+ 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
+ 'show_in_rest' => true,
+ )
+ );
+
+ // Speakers CPT.
+ register_post_type(
+ 'wpfa_speaker',
+ array(
+ 'labels' => array(
+ 'name' => __( 'Speakers', 'wpfa-event' ),
+ 'singular_name' => __( 'Speaker', 'wpfa-event' ),
+ ),
+ 'public' => true,
+ 'has_archive' => true,
+ 'supports' => array( 'title', 'editor', 'thumbnail' ),
+ 'show_in_rest' => true,
+ )
+ );
+ }
+
+ /**
+ * Register meta fields for CPTs.
+ */
+ public function register_meta() {
+ register_post_meta( 'wpfa_speaker', 'wpfa_speaker_org', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field' ) );
+ register_post_meta( 'wpfa_speaker', 'wpfa_speaker_position', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field' ) );
+ register_post_meta( 'wpfa_speaker', 'wpfa_speaker_photo_url', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'esc_url_raw' ) );
+
+ register_post_meta( 'wpfa_event', 'wpfa_event_start_date', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field' ) );
+ register_post_meta( 'wpfa_event', 'wpfa_event_end_date', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field' ) );
+ register_post_meta( 'wpfa_event', 'wpfa_event_location', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field' ) );
+ register_post_meta( 'wpfa_event', 'wpfa_event_url', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'esc_url_raw' ) );
+ }
+}
\ No newline at end of file
diff --git a/public/class-wpfa-public.php b/public/class-wpfa-public.php
new file mode 100644
index 0000000..cff307b
--- /dev/null
+++ b/public/class-wpfa-public.php
@@ -0,0 +1,96 @@
+plugin_name = $plugin_name;
+ $this->version = $version;
+ }
+
+ /**
+ * Register the stylesheets for the public-facing side of the site.
+ */
+ public function enqueue_styles() {
+ wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpfa-public.css', array(), $this->version, 'all' );
+ }
+
+ /**
+ * Register the shortcodes for the plugin.
+ */
+ public function register_shortcodes() {
+ add_shortcode( 'wpfa_speakers', array( $this, 'render_speakers_shortcode' ) );
+ }
+
+ /**
+ * Renders the [wpfa_speakers] shortcode.
+ *
+ * @param array $atts Shortcode attributes.
+ * @return string HTML output.
+ */
+ public function render_speakers_shortcode( $atts ) {
+ $atts = shortcode_atts(
+ array(
+ 'limit' => -1,
+ ),
+ $atts,
+ 'wpfa_speakers'
+ );
+
+ $query = new WP_Query(
+ array(
+ 'post_type' => 'wpfa_speaker',
+ 'posts_per_page' => intval( $atts['limit'] ),
+ 'post_status' => 'publish',
+ )
+ );
+
+ if ( ! $query->have_posts() ) {
+ return '' . esc_html__( 'No speakers found.', 'wpfa-event' ) . '
';
+ }
+
+ ob_start();
+ echo '';
+ while ( $query->have_posts() ) {
+ $query->the_post();
+ $org = get_post_meta( get_the_ID(), 'wpfa_speaker_org', true );
+ $position = get_post_meta( get_the_ID(), 'wpfa_speaker_position', true );
+ $photo_url = get_the_post_thumbnail_url( get_the_ID(), 'medium' ) ?: 'https://via.placeholder.com/150';
+
+ echo '
';
+ echo '
';
+ echo '
' . esc_html( get_the_title() ) . ' ';
+ echo '
' . esc_html( $position ) . ', ' . esc_html( $org ) . '
';
+ echo '
';
+ }
+ echo '
';
+ wp_reset_postdata();
+ return ob_get_clean();
+ }
+
+}
\ No newline at end of file
diff --git a/public/uninstall.php b/public/uninstall.php
new file mode 100644
index 0000000..e69de29
diff --git a/public/wpfa-public.css b/public/wpfa-public.css
new file mode 100644
index 0000000..2f13c23
--- /dev/null
+++ b/public/wpfa-public.css
@@ -0,0 +1,23 @@
+/**
+ * All of the CSS for your public-facing functionality should be
+ * included in this file.
+ */
+
+.wpfa-speakers-archive {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ gap: 20px;
+}
+
+.wpfa-speaker-card {
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ padding: 15px;
+ text-align: center;
+}
+
+.wpfa-speaker-card img {
+ max-width: 150px;
+ border-radius: 50%;
+ margin: 0 auto 10px;
+}
\ No newline at end of file
diff --git a/templates/admin-dashboard.php b/templates/admin-dashboard.php
new file mode 100644
index 0000000..5b30bd0
--- /dev/null
+++ b/templates/admin-dashboard.php
@@ -0,0 +1,2266 @@
+ 403 ] );
+}
+
+$event_id = isset($_GET['event_id']) ? absint($_GET['event_id']) : 0;
+$event_title = $event_id ? get_the_title($event_id) : '';
+
+$upload_dir = wp_upload_dir();
+$data_dir = $upload_dir['basedir'] . '/fossasia-data';
+
+// Define file paths based on event ID
+$sponsors_file = $event_id ? $data_dir . '/sponsors-' . $event_id . '.json' : '';
+$settings_file = $event_id ? $data_dir . '/site-settings-' . $event_id . '.json' : '';
+$speakers_file = $event_id ? $data_dir . '/speakers-' . $event_id . '.json' : '';
+$schedule_file = $event_id ? $data_dir . '/schedule-' . $event_id . '.json' : '';
+$theme_settings_file = $event_id ? $data_dir . '/theme-settings-' . $event_id . '.json' : '';
+
+// Global files that are not event-specific
+$global_settings_file = $data_dir . '/site-settings.json';
+if ($event_id) {
+ $sections_file = $data_dir . '/custom-sections-' . $event_id . '.json';
+} else {
+ $sections_file = $data_dir . '/custom-sections.json'; // This remains the "global" file for the Events Listing page.
+}
+$navigation_file = $data_dir . '/navigation.json'; // Assuming navigation is global
+$coc_content_file = $data_dir . '/coc-content.json';
+
+// Ensure files exist
+if ($event_id) {
+ if (!file_exists($sponsors_file)) { file_put_contents($sponsors_file, '[]'); }
+ if (!file_exists($settings_file)) { file_put_contents($settings_file, '{"about_section_content": "", "section_visibility": {"about": true, "speakers": true, "schedule": true, "sponsors": true}}'); }
+ if (!file_exists($speakers_file)) { file_put_contents($speakers_file, '[]'); }
+ if (!file_exists($schedule_file)) { file_put_contents($schedule_file, '{}'); }
+ if (!file_exists($theme_settings_file)) { file_put_contents($theme_settings_file, '{"brand_color": "#D51007", "background_color": "#f8f9fa", "text_color": "#0b0b0b"}'); }
+}
+if (!file_exists($sections_file)) { file_put_contents($sections_file, '[]'); } // This now correctly handles both global and event-specific files.
+if (!file_exists($navigation_file)) { file_put_contents($navigation_file, '[]'); }
+if (!file_exists($global_settings_file)) { file_put_contents($global_settings_file, '{"hero_image_url": "", "footer_text": ""}'); }
+if (!file_exists($coc_content_file)) { file_put_contents($coc_content_file, '{"content": "Placeholder CoC content.
"}'); }
+
+// Speaker data is needed for the new "Manage Speakers" tab
+$speakers_data = $event_id && file_exists($speakers_file) ? json_decode(file_get_contents($speakers_file), true) : [];
+$sponsors_data = $event_id && file_exists($sponsors_file) ? json_decode(file_get_contents($sponsors_file), true) : [];
+$site_settings_data = $event_id && file_exists($settings_file) ? json_decode(file_get_contents($settings_file), true) : [];
+$custom_sections_data = json_decode(file_get_contents($sections_file), true);
+$schedule_data = $event_id && file_exists($schedule_file) ? json_decode(file_get_contents($schedule_file), true) : [];
+$navigation_data = json_decode(file_get_contents($navigation_file), true);
+$theme_settings_data = $event_id && file_exists($theme_settings_file) ? json_decode(file_get_contents($theme_settings_file), true) : [];
+$coc_content_data = json_decode(file_get_contents($coc_content_file), true);
+
+// Determine the correct "View Site" URL.
+$view_site_url = esc_url( home_url( '/fossasia-summit/' ) ); // Default URL.
+
+if ( isset( $_GET['return_to'] ) ) {
+ // Priority 1: Use the 'return_to' query parameter if it exists.
+ $view_site_url = esc_url( urldecode( $_GET['return_to'] ) ); // This is now the event-specific page
+} else {
+ // Priority 2 (Fallback): Use the HTTP referer if it's a valid internal URL.
+ $referer_url = wp_get_referer();
+ if ( $referer_url && strpos( $referer_url, home_url() ) === 0 && strpos( $referer_url, 'admin-dashboard' ) === false ) {
+ $view_site_url = esc_url( $referer_url );
+ }
+}
+?>
+
+>
+
+
+
+
+
+
+>
+
+
+
+
+
+
+
+ No Event Selected
+ Please go to the Events page and click "Edit Content" on an event card to manage its specific content.
+ You can still manage global site settings below.
+
+
+
+
+
+
+
Data Sync
+
Manage Speakers
+
Manage Schedule
+
About Section
+
Section Visibility
+
Manage Sponsors
+
Site Settings
+
Theme
+
+
+
Custom Sections
+
Manage Navigation
+
+
Code of Conduct
+
+
+
+
+
+
+
+
Import Sample Data
+
Click this button to populate the current event with sample speakers, sponsors, and settings. This will overwrite existing data for this event.
+
Import Sample Data
+
+
+
+
+
Manage Speakers
+
+
+
+
+
+
+
Manage Schedule Table
+
Create or edit the single schedule table for the "Full Schedule" page. Only one table can exist at a time.
+
+
+
+
+
+
+
+
Edit "About" Section Content
+
Use the editor below to change the content of the "About" section on the main summit page. You can use formatting like bold, italics, lists, and links.
+
+
+
+
+
Manage Section Visibility
+
Use these toggles to show or hide the default sections on the event page.
+
+
+
+
Save Visibility Settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Edit Code of Conduct
+
Use the editor below to change the content of the Code of Conduct page. This content is global and applies to all events.
+
+ 'coc_content',
+ 'media_buttons' => false,
+ 'textarea_rows' => 20,
+ 'tinymce' => [
+ 'height' => 450,
+ ],
+ ] ); ?>
+ Save Code of Conduct
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
×
+
+ Add New Schedule Table
+
+
+
+ Table Settings
+ Table Name (e.g., "Day 1 - Main Track"):
+
+
+
+
+ Table Content
+
+ Save Table
+
+
+
+
+
+
+
+
+
+
+
+
+
+
×
+
+ Add New Section
+
+
+
+ General Settings
+ Section Title (e.g., "Venue & Travel"):
+
+ Section Subtitle (small text next to the title):
+
+ Position on Page:
+
+ Display Order (lower numbers appear first):
+
+ Active
+
+
+
+ Layout & Content
+ Layout Style:
+
+ Two Column - Media Left
+ Two Column - Media Right
+ Full Width Text
+
+
+
+ Content Title (optional H3 heading):
+
+ Content Body:
+ 'sectionContentBody',
+ 'media_buttons' => true, // Enable the "Add Media" button
+ 'textarea_rows' => 15,
+ 'tinymce' => [
+ 'height' => 350,
+ ],
+ ] ); ?>
+ Button Text (optional):
+
+ Button Link (optional):
+
+
+
+
+
+ Media Column
+ Media Title (optional H3 heading):
+
+ Media Type:
+ Photo
+ Map
+
+ Photo (URL or Upload):
+
+
Map Embed URL (the 'src' from an iframe):
+
From Google Maps, click "Share", then "Embed a map", and copy the URL from the `src="..."` attribute in the iframe code. Pasting the full iframe code also works.
+
+ Video Embed URL (YouTube, Vimeo, etc.):
+
+
+
+ Save Section
+
+
+
+
Save Section
+
+
+
+
+
+
+
+
+
+
+
Confirmation
+
Are you sure?
+
+ Cancel
+ OK
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/c_Users_Nishil_Downloads_test38(1)_templates_events-listing-page.php b/templates/c_Users_Nishil_Downloads_test38(1)_templates_events-listing-page.php
new file mode 100644
index 0000000..5c97138
--- /dev/null
+++ b/templates/c_Users_Nishil_Downloads_test38(1)_templates_events-listing-page.php
@@ -0,0 +1,1356 @@
+ ($b['order'] ?? 10);
+ });
+
+ foreach ($sections_to_render as $section) {
+ $section_id = esc_attr($section['id']);
+ $layout = $section['layout'] ?? 'full_width';
+ $section_type = $section['type'] ?? 'content';
+ ?>
+
+
+
+
';
+ } elseif ($section['mediaType'] === 'video' && !empty($section['video_embed_src'])) {
+ $embed_url = get_video_embed_url_for_events($section['video_embed_src']);
+ echo '
';
+ } elseif ($section['mediaType'] === 'carousel' && !empty($section['carousel_images']) && is_array($section['carousel_images'])) {
+ $carousel_id = 'carousel-' . esc_attr($section['id']);
+ $timer = !empty($section['carousel_timer']) ? absint($section['carousel_timer']) * 1000 : 5000;
+ ?>
+
+
+
+
+
';
+ } elseif ($section['mediaType'] === 'map' && !empty($section['map_embed_src'])) {
+ $media_col_html = '
';
+ }
+
+ $content_col_html = '';
+ ?>
+
+
+
+
+
+
+ 'page',
+ 'posts_per_page' => -1,
+ 'meta_key' => '_event_date',
+ 'orderby' => 'meta_value',
+ 'order' => 'ASC',
+ 'meta_query' => [
+ 'relation' => 'AND',
+ [
+ 'key' => '_wp_page_template',
+ 'value' => 'fossasia-landing-template.php'
+ ],
+ [
+ // This logic finds events where the end date is today or in the future,
+ // OR if there is no end date, where the start date is today or in the future.
+ 'relation' => 'OR',
+ [
+ 'relation' => 'AND',
+ [
+ 'key' => '_event_end_date',
+ 'compare' => 'EXISTS'
+ ],
+ [
+ 'key' => '_event_end_date',
+ 'value' => $today,
+ 'compare' => '>=',
+ 'type' => 'DATE'
+ ]
+ ],
+ [
+ 'key' => '_event_date',
+ 'value' => $today,
+ 'compare' => '>=',
+ 'type' => 'DATE'
+ ]
+ ]
+ ]
+]);
+$calendar_events = [];
+if ($all_events_query->have_posts()) {
+ while ($all_events_query->have_posts()) {
+ $all_events_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);
+ $event_place = get_post_meta(get_the_ID(), '_event_place', true);
+ $event_time = get_post_meta(get_the_ID(), '_event_time', true);
+ $event_description = get_the_excerpt();
+ $featured_img_url = get_the_post_thumbnail_url(get_the_ID(), 'large') ?: '';
+
+ $calendar_events[] = [
+ 'id' => get_the_ID(),
+ 'name' => get_the_title(),
+ 'date' => $event_date,
+ 'endDate' => $event_end_date,
+ 'place' => $event_place,
+ 'time' => $event_time,
+ 'description' => $event_description,
+ 'permalink' => get_the_permalink(),
+ 'image_url' => $featured_img_url,
+ 'year' => !empty($event_date) ? date('Y', strtotime($event_date)) : null
+ ];
+ }
+}
+
+/**
+ * Fetches and renders latest blog posts from FOSSASIA blog.
+ */
+function render_latest_news() {
+ include_once( ABSPATH . WPINC . '/feed.php' );
+
+ // Get a SimplePie feed object from the specified feed source.
+ $rss = fetch_feed( 'https://blog.fossasia.org/rss/' );
+
+ if ( is_wp_error( $rss ) ) {
+ echo 'Could not fetch news. Please try again later.
';
+ return;
+ }
+
+ // Figure out how many total items there are, but limit it to 5.
+ $maxitems = $rss->get_item_quantity( 5 );
+
+ // Build an array of all the items, starting with element 0 (first element).
+ $rss_items = $rss->get_items( 0, $maxitems );
+
+ if ( $maxitems == 0 ) {
+ echo 'No news items found.
';
+ } else {
+ // Loop through each feed item and display each item as a hyperlink.
+ echo '';
+ foreach ( $rss_items as $item ) : ?>
+
+ get_date('j F Y | g:i a'); ?>' target="_blank" rel="noopener">
+ get_title() ); ?>
+
+ get_date('F j, Y'); ?>
+
+ ';
+ echo '';
+ }
+}
+?>
+
+>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+>
+
+
+
+
+
+
+
+
+ FOSSASIA Events
+ Discover upcoming community events, local meetups, and partner conferences from the FOSSASIA network.
+
+
+
+
+
+
+
+
+
Events
+
+
+
+
+
+
+
+
+
+ Showing 0 matching events.
+
+
+
+ have_posts() ) :
+ while ( $all_events_query->have_posts() ) : $all_events_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 );
+ $event_place = get_post_meta( get_the_ID(), '_event_place', true );
+ $event_description = get_the_excerpt();
+ $featured_img_url = get_the_post_thumbnail_url( get_the_ID(), 'large' ) ?: '';
+
+ $formatted_date = 'Date not set';
+ if (!empty($event_date)) {
+ $start = date_create($event_date);
+ if (!empty($event_end_date) && $event_end_date !== $event_date) {
+ $end = date_create($event_end_date);
+ $formatted_date = date_format($start, 'M j') . ' - ' . date_format($end, 'M j, Y');
+ } else {
+ $formatted_date = date_format($start, 'F j, Y');
+ }
+ }
+ ?>
+
+ No events created yet. Click "Create Event" to add one!';
+ endif;
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This is a preview of the global Code of Conduct. To make changes, please go to the main Admin Dashboard .
+ ''];
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/c_Users_Nishil_Downloads_test38(1)_templates_past-events-page.php b/templates/c_Users_Nishil_Downloads_test38(1)_templates_past-events-page.php
new file mode 100644
index 0000000..b5d9ea5
--- /dev/null
+++ b/templates/c_Users_Nishil_Downloads_test38(1)_templates_past-events-page.php
@@ -0,0 +1,184 @@
+ 'page',
+ 'posts_per_page' => -1,
+ 'meta_key' => '_event_date',
+ 'orderby' => 'meta_value',
+ 'order' => 'DESC', // Show most recent past events first
+ 'meta_query' => [
+ 'relation' => 'AND',
+ [
+ 'key' => '_wp_page_template',
+ 'value' => 'fossasia-landing-template.php',
+ 'compare' => '=',
+ ],
+ [
+ // This logic finds events where the end date is in the past.
+ // If no end date, it checks if the start date is in the past.
+ 'relation' => 'OR',
+ [
+ 'key' => '_event_end_date',
+ 'value' => $today,
+ 'compare' => '<',
+ 'type' => 'DATE'
+ ],
+ [
+ 'relation' => 'AND',
+ [
+ 'key' => '_event_end_date',
+ 'compare' => 'NOT EXISTS'
+ ],
+ [
+ 'key' => '_event_date',
+ 'value' => $today,
+ 'compare' => '<',
+ 'type' => 'DATE'
+ ]
+ ]
+ ]
+ ],
+]);
+?>
+
+>
+
+
+
+
+
+
+
+>
+
+
+
+
+
+
+
+ Past FOSSASIA Events
+ A look back at our community events, meetups, and conferences.
+
+
+
+
+
+
+
Event Archive
+
+
+
+ have_posts() ) :
+ while ( $past_events_query->have_posts() ) : $past_events_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 );
+ $event_place = get_post_meta( get_the_ID(), '_event_place', true );
+ $featured_img_url = get_the_post_thumbnail_url( get_the_ID(), 'large' ) ?: plugins_url('../images/hero-image.jpg', __FILE__);
+
+ $formatted_date = 'Date not set';
+ if (!empty($event_date)) {
+ $start = date_create($event_date);
+ if (!empty($event_end_date) && $event_end_date !== $event_date) {
+ $end = date_create($event_end_date);
+ $formatted_date = date_format($start, 'M j') . ' - ' . date_format($end, 'M j, Y');
+ } else {
+ $formatted_date = date_format($start, 'F j, Y');
+ }
+ }
+ ?>
+
+ No past events found in the archive.';
+ endif;
+ ?>
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/code-of-conduct-page.php b/templates/code-of-conduct-page.php
new file mode 100644
index 0000000..43ab654
--- /dev/null
+++ b/templates/code-of-conduct-page.php
@@ -0,0 +1,91 @@
+Placeholder CoC content.
"}'); }
+
+$theme_settings_data = json_decode(file_get_contents($global_theme_settings_file), true);
+$coc_content_data = json_decode(file_get_contents($coc_content_file), true);
+$coc_content = $coc_content_data['content'] ?? 'The Code of Conduct has not been set. Please add it in the admin dashboard.
';
+?>
+
+>
+
+
+
+
+
+
+
+>
+
+
+
+
+
+
+
+ Code of Conduct
+ Our commitment to a safe, respectful, and harassment-free event experience for everyone.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/events-listing-page.php b/templates/events-listing-page.php
new file mode 100644
index 0000000..bafec67
--- /dev/null
+++ b/templates/events-listing-page.php
@@ -0,0 +1,1354 @@
+ ($b['order'] ?? 10);
+ });
+
+ foreach ($sections_to_render as $section) {
+ $section_id = esc_attr($section['id']);
+ $layout = $section['layout'] ?? 'full_width';
+ $section_type = $section['type'] ?? 'content';
+ ?>
+
+
+
+
';
+ } elseif ($section['mediaType'] === 'video' && !empty($section['video_embed_src'])) {
+ $embed_url = get_video_embed_url_for_events($section['video_embed_src']);
+ echo '
';
+ } elseif ($section['mediaType'] === 'carousel' && !empty($section['carousel_images']) && is_array($section['carousel_images'])) {
+ $carousel_id = 'carousel-' . esc_attr($section['id']);
+ $timer = !empty($section['carousel_timer']) ? absint($section['carousel_timer']) * 1000 : 5000;
+ ?>
+
+
+
+
+
';
+ } elseif ($section['mediaType'] === 'map' && !empty($section['map_embed_src'])) {
+ $media_col_html = '
';
+ }
+
+ $content_col_html = '';
+ ?>
+
+
+
+
+
+
+ 'page',
+ 'posts_per_page' => -1,
+ 'meta_key' => '_event_date',
+ 'orderby' => 'meta_value',
+ 'order' => 'ASC',
+ 'meta_query' => [
+ 'relation' => 'AND',
+ [
+ 'key' => '_wp_page_template',
+ 'value' => 'fossasia-landing-template.php'
+ ],
+ [
+ // This logic finds events where the end date is today or in the future,
+ // OR if there is no end date, where the start date is today or in the future.
+ 'relation' => 'OR',
+ [
+ 'relation' => 'AND',
+ [
+ 'key' => '_event_end_date',
+ 'compare' => 'EXISTS'
+ ],
+ [
+ 'key' => '_event_end_date',
+ 'value' => $today,
+ 'compare' => '>=',
+ 'type' => 'DATE'
+ ]
+ ],
+ [
+ 'key' => '_event_date',
+ 'value' => $today,
+ 'compare' => '>=',
+ 'type' => 'DATE'
+ ]
+ ]
+ ]
+]);
+$calendar_events = [];
+if ($all_events_query->have_posts()) {
+ while ($all_events_query->have_posts()) {
+ $all_events_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);
+ $event_place = get_post_meta(get_the_ID(), '_event_place', true);
+ $event_time = get_post_meta(get_the_ID(), '_event_time', true);
+ $event_description = get_the_excerpt();
+ $featured_img_url = get_the_post_thumbnail_url(get_the_ID(), 'large') ?: '';
+
+ $calendar_events[] = [
+ 'id' => get_the_ID(),
+ 'name' => get_the_title(),
+ 'date' => $event_date,
+ 'endDate' => $event_end_date,
+ 'place' => $event_place,
+ 'time' => $event_time,
+ 'description' => $event_description,
+ 'permalink' => get_the_permalink(),
+ 'image_url' => $featured_img_url,
+ 'year' => !empty($event_date) ? date('Y', strtotime($event_date)) : null
+ ];
+ }
+}
+
+/**
+ * Fetches and renders latest blog posts from FOSSASIA blog.
+ */
+function render_latest_news() {
+ include_once( ABSPATH . WPINC . '/feed.php' );
+
+ // Get a SimplePie feed object from the specified feed source.
+ $rss = fetch_feed( 'https://blog.fossasia.org/rss/' );
+
+ if ( is_wp_error( $rss ) ) {
+ echo 'Could not fetch news. Please try again later.
';
+ return;
+ }
+
+ // Figure out how many total items there are, but limit it to 5.
+ $maxitems = $rss->get_item_quantity( 5 );
+
+ // Build an array of all the items, starting with element 0 (first element).
+ $rss_items = $rss->get_items( 0, $maxitems );
+
+ if ( $maxitems == 0 ) {
+ echo 'No news items found.
';
+ } else {
+ // Loop through each feed item and display each item as a hyperlink.
+ echo '';
+ foreach ( $rss_items as $item ) : ?>
+
+ get_date('j F Y | g:i a'); ?>' target="_blank" rel="noopener">
+ get_title() ); ?>
+
+ get_date('F j, Y'); ?>
+
+ ';
+ echo '';
+ }
+}
+?>
+
+>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+>
+
+
+
+
+
+
+
+
+ FOSSASIA Events
+ Discover upcoming community events, local meetups, and partner conferences from the FOSSASIA network.
+
+
+
+
+
+
+
+
+
Events
+
+
+
+
+
+
+
+
+
+ Showing 0 matching events.
+
+
+
+ have_posts() ) :
+ while ( $all_events_query->have_posts() ) : $all_events_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 );
+ $event_place = get_post_meta( get_the_ID(), '_event_place', true );
+ $event_description = get_the_excerpt();
+ $featured_img_url = get_the_post_thumbnail_url( get_the_ID(), 'large' ) ?: '';
+
+ $formatted_date = 'Date not set';
+ if (!empty($event_date)) {
+ $start = date_create($event_date);
+ if (!empty($event_end_date) && $event_end_date !== $event_date) {
+ $end = date_create($event_end_date);
+ $formatted_date = date_format($start, 'M j') . ' - ' . date_format($end, 'M j, Y');
+ } else {
+ $formatted_date = date_format($start, 'F j, Y');
+ }
+ }
+ ?>
+
+ No events created yet. Click "Create Event" to add one!';
+ endif;
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This is a preview of the global Code of Conduct. To make changes, please go to the main Admin Dashboard .
+ ''];
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/fossasia-landing-content.php b/templates/fossasia-landing-content.php
new file mode 100644
index 0000000..e69de29
diff --git a/templates/fossasia-landing-template.php b/templates/fossasia-landing-template.php
new file mode 100644
index 0000000..6ed5f59
--- /dev/null
+++ b/templates/fossasia-landing-template.php
@@ -0,0 +1,1421 @@
+ ($b['order'] ?? 10);
+ });
+
+ foreach ($sections_to_render as $section) {
+ $section_id = esc_attr($section['id']);
+ $layout = $section['layout'] ?? 'full_width';
+ $section_type = $section['type'] ?? 'content';
+ ?>
+
+
+
+
+
';
+ } elseif ($section['mediaType'] === 'video' && !empty($section['video_embed_src'])) {
+ $embed_url = get_video_embed_url($section['video_embed_src']);
+ echo '
';
+ } elseif ($section['mediaType'] === 'carousel' && !empty($section['carousel_images']) && is_array($section['carousel_images'])) {
+ $carousel_id = 'carousel-' . esc_attr($section['id']);
+ $timer = !empty($section['carousel_timer']) ? absint($section['carousel_timer']) * 1000 : 5000;
+ ?>
+
+
+
+
+
';
+ } elseif ($section['mediaType'] === 'map' && !empty($section['map_embed_src'])) {
+ $media_col_html = '
';
+ }
+
+ $content_col_html = '';
+
+ ?>
+
+
+
+
+
+
+ 'About', 'href' => '#about', 'order' => 20];
+}
+if ($section_visibility['speakers'] ?? true) {
+ $dynamic_nav_items['speakers'] = ['text' => 'Speakers', 'href' => '#speakers', 'order' => 30];
+}
+if ($section_visibility['schedule'] ?? true) {
+ $dynamic_nav_items['schedule-overview'] = ['text' => 'Schedule', 'href' => '#schedule-overview', 'order' => 40];
+}
+if ($section_visibility['sponsors'] ?? true) {
+ $dynamic_nav_items['sponsors'] = ['text' => 'Sponsors', 'href' => '#sponsors', 'order' => 50];
+}
+
+// Add active custom sections that have a title
+if (!empty($custom_sections_data) && is_array($custom_sections_data)) {
+ $active_custom_sections = array_filter($custom_sections_data, function($section) {
+ return !empty($section['is_active']) && !empty($section['title']);
+ });
+
+ foreach ($active_custom_sections as $section) {
+ $nav_item = [
+ 'text' => $section['title'],
+ 'href' => '#custom-section-' . $section['id'],
+ 'order' => $section['order'] ?? 100 // Use the section's order for sorting
+ ];
+ $dynamic_nav_items['custom-' . $section['id']] = $nav_item;
+ }
+}
+
+// Sort all navigation items by their order
+uasort($dynamic_nav_items, fn($a, $b) => ($a['order'] ?? 100) <=> ($b['order'] ?? 100));
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+ // Use the new dynamically generated navigation items
+ if (!empty($dynamic_nav_items)) {
+ foreach ($dynamic_nav_items as $nav_item) {
+ $href = esc_attr($nav_item['href']);
+ $text = esc_html($nav_item['text']);
+ echo "{$text} ";
+ }
+ }
+ echo ' ';
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ About content has not been set for this event.'); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Featured Speakers
+
+
+
Curated invited & selected speakers
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Schedule Overview
+
+
+
Event timeline and sessions
+
+
+
+
+
+ '; // Wrapper to match theme style
+ echo '
' . esc_html($table['name']) . ' ';
+ echo '
';
+ echo '
';
+
+ $is_first_row = true;
+ foreach ($table['data'] as $row_data) {
+ echo '';
+ foreach ($row_data as $cell_content) {
+ $cell_html = preg_replace('/\*\*(.*?)\*\*/', '$1 ', esc_html($cell_content));
+ $cell_html = preg_replace('/\*(.*?)\*/', '$1 ', $cell_html);
+ $cell_html = nl2br($cell_html);
+ $tag = $is_first_row ? 'th' : 'td';
+ echo "<{$tag}>" . wp_kses_post($cell_html) . "{$tag}>";
+ }
+ echo ' ';
+ $is_first_row = false;
+ }
+ echo '
';
+ }
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/speakers-page-content.php b/templates/speakers-page-content.php
new file mode 100644
index 0000000..e69de29
diff --git a/templates/speakers-page.php b/templates/speakers-page.php
new file mode 100644
index 0000000..85be397
--- /dev/null
+++ b/templates/speakers-page.php
@@ -0,0 +1,1066 @@
+
+ "#D51007", "background_color" => "#f8f9fa", "text_color" => "#0b0b0b"]; }
+$navigation_data = json_decode(file_get_contents($navigation_file), true);
+$custom_sections_data = file_exists($sections_file) ? json_decode(file_get_contents($sections_file), true) : [];
+
+// --- Dynamically build navigation based on visible sections ---
+$dynamic_nav_items = [];
+$settings_file = $event_id ? $data_dir . '/site-settings-' . $event_id . '.json' : '';
+$site_settings_data = $event_id && file_exists($settings_file) ? json_decode(file_get_contents($settings_file), true) : [];
+$section_visibility = $site_settings_data['section_visibility'] ?? [];
+
+// Add default sections if they are visible
+if ($section_visibility['about'] ?? true) {
+ $dynamic_nav_items['about'] = ['text' => 'About', 'href' => get_permalink($event_id) . '#about', 'order' => 20];
+}
+if ($section_visibility['speakers'] ?? true) {
+ $dynamic_nav_items['speakers'] = ['text' => 'Speakers', 'href' => get_permalink($event_id) . '#speakers', 'order' => 30];
+}
+if ($section_visibility['schedule'] ?? true) {
+ $dynamic_nav_items['schedule-overview'] = ['text' => 'Schedule', 'href' => get_permalink($event_id) . '#schedule-overview', 'order' => 40];
+}
+if ($section_visibility['sponsors'] ?? true) {
+ $dynamic_nav_items['sponsors'] = ['text' => 'Sponsors', 'href' => get_permalink($event_id) . '#sponsors', 'order' => 50];
+}
+
+// Add active custom sections that have a title
+if (!empty($custom_sections_data) && is_array($custom_sections_data)) {
+ foreach ($custom_sections_data as $section) {
+ if (!empty($section['is_active']) && !empty($section['title'])) {
+ $dynamic_nav_items['custom-' . $section['id']] = ['text' => $section['title'], 'href' => get_permalink($event_id) . '#custom-section-' . $section['id'], 'order' => $section['order'] ?? 100];
+ }
+ }
+}
+
+// Sort all navigation items by their order
+uasort($dynamic_nav_items, fn($a, $b) => ($a['order'] ?? 100) <=> ($b['order'] ?? 100));
+?>
+
+>
+
+
+
+
+
+
+
+
+>
+
+
+
+
+
+
+
+
+
+
+ ';
+ // Use the new dynamically generated navigation items
+ if (!empty($dynamic_nav_items)) {
+ foreach ($dynamic_nav_items as $nav_item) {
+ $href = esc_url($nav_item['href']);
+ $text = esc_html($nav_item['text']);
+ echo "{$text} ";
+ }
+ }
+ echo ' ';
+ ?>
+
+
+
+
+
+
+
+
+
FOSSASIA Summit Speakers
+
Discover all the amazing speakers joining us at FOSSASIA Summit 2025
+
+
+
+ 🔍
+
+
+
+
+
+
+
+ Sort by:
+
+ Name (A-Z)
+ Name (Z-A)
+ Category (A-Z)
+
+
+
+
+
+
+ Showing 0 speakers
+
+
+
+
No speakers found
+
Try adjusting your search or filters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uninstall.php b/uninstall.php
index 18392b5..12e0fd1 100644
--- a/uninstall.php
+++ b/uninstall.php
@@ -1,31 +1,27 @@
-1,
+ 'post_type' => $cpt_slug,
+ 'post_status' => 'any',
+ )
+ );
+ // Delete each post.
+ foreach ( $posts as $post ) {
+ wp_delete_post( $post->ID, true );
+ }
+}
+// Note: This simple uninstaller does not remove the `fossasia-data` directory
+// from wp-content/uploads, as that was part of the old implementation.
+// A more robust uninstaller could be added here if needed.