Skip to content

Refactor Events Template Architecture#53

Open
Ubayed-Bin-Sufian wants to merge 16 commits intofossasia:mainfrom
Ubayed-Bin-Sufian:refactor/events-template-arch
Open

Refactor Events Template Architecture#53
Ubayed-Bin-Sufian wants to merge 16 commits intofossasia:mainfrom
Ubayed-Bin-Sufian:refactor/events-template-arch

Conversation

@Ubayed-Bin-Sufian
Copy link
Collaborator

@Ubayed-Bin-Sufian Ubayed-Bin-Sufian commented Feb 9, 2026

Description

This PR refactors a hardcoded file of events template referenced below maintaining OOP and SRP principles.


@Ubayed-Bin-Sufian Ubayed-Bin-Sufian self-assigned this Feb 9, 2026
@Ubayed-Bin-Sufian Ubayed-Bin-Sufian added the enhancement New feature or request label Feb 9, 2026
@sourcery-ai
Copy link

sourcery-ai bot commented Feb 9, 2026

Reviewer's Guide

Refactors the events page template into a richer Events Hub with role-aware queries, reusable partials, and JS-driven admin CRUD, while adding footer editing and a sidebar news feed, plus corresponding styles, meta fields, and AJAX handlers.

Sequence diagram for admin event CRUD via Events Hub

sequenceDiagram
    actor Admin
    participant Browser as Browser_WPFA_Events_JS
    participant WP as WordPress_admin_ajax_php
    participant Handler as Wpfaevent_Event_Handler
    participant DB as WP_Database

    Admin->>Browser: Click Create/Edit/Delete event
    Browser->>Browser: Collect form data
    Browser->>WP: POST action=wpfa_add_event/wpfa_update_event/wpfa_delete_event
    WP->>Handler: Route to ajax_add_event/ajax_update_event/ajax_delete_event

    Handler->>Handler: check_ajax_referer wpfa_events_ajax
    Handler->>Handler: current_user_can manage_options
    alt add_event
        Handler->>DB: wp_insert_post post_type=wpfa_event
        Handler->>DB: update_post_meta wpfa_event_start_date, wpfa_event_end_date, ...
        opt featured_image uploaded
            Handler->>WP: media_handle_upload featured_image
            WP->>DB: Store attachment and thumbnail
            Handler->>DB: set_post_thumbnail
        end
        Handler-->>WP: wp_send_json_success event_id
    else update_event
        Handler->>DB: get_post event_id
        Handler->>DB: wp_update_post title, content, excerpt
        Handler->>DB: update_post_meta wpfa_event_start_date, wpfa_event_time, ...
        opt featured_image uploaded/removed
            Handler->>WP: media_handle_upload or delete_post_thumbnail
        end
        Handler-->>WP: wp_send_json_success
    else delete_event
        Handler->>DB: get_post event_id
        Handler->>DB: wp_delete_post force=true
        Handler-->>WP: wp_send_json_success
    end

    WP-->>Browser: JSON { success, data }
    alt success
        Browser->>Browser: alert success message
        Browser->>Browser: window.location.reload
    else error
        Browser->>Browser: alert error message
    end
Loading

Sequence diagram for admin footer text update

sequenceDiagram
    actor Admin
    participant Browser as Browser_WPFA_Footer_JS
    participant WP as WordPress_admin_ajax_php
    participant FooterH as Wpfaevent_Footer_Handler
    participant DB as WP_Options_Table

    Admin->>Browser: Click Edit Footer
    Browser->>Browser: Open edit-footer-modal and prefill textarea
    Admin->>Browser: Submit footer form

    Browser->>WP: POST action=wpfa_update_footer_text
    WP->>FooterH: ajax_update_footer_text

    FooterH->>FooterH: check_ajax_referer wpfa_events_ajax
    FooterH->>FooterH: current_user_can manage_options
    FooterH->>FooterH: sanitize_text_field footer_text
    FooterH->>DB: update_option wpfa_footer_text
    FooterH-->>WP: wp_send_json_success message

    WP-->>Browser: JSON { success, message }
    Browser->>Browser: Update #footer-text-display
    Browser->>Browser: Close modal and alert success
Loading

Entity relationship diagram for wpfa_event post meta

erDiagram
    wp_posts {
        bigint ID PK
        varchar post_type
        varchar post_title
        text post_content
        text post_excerpt
        varchar post_status
    }

    wp_postmeta {
        bigint meta_id PK
        bigint post_id FK
        varchar meta_key
        longtext meta_value
    }

    wp_users {
        bigint ID PK
        varchar user_login
    }

    wpfa_event_speakers {
        bigint post_id FK
        bigint speaker_user_id FK
    }

    wp_posts ||--o{ wp_postmeta : has_meta
    wp_posts ||--o{ wpfa_event_speakers : has_speakers
    wp_users ||--o{ wpfa_event_speakers : is_speaker

    %% Important meta keys for wpfa_event
    wp_postmeta }o--|| wp_posts : belongs_to_post

    %% Conceptual attributes (meta_key values) for wpfa_event
    wpfa_event_meta {
        string wpfa_event_start_date
        string wpfa_event_end_date
        string wpfa_event_time
        string wpfa_event_location
        string wpfa_event_lead_text
        string wpfa_event_url
        string wpfa_event_registration_link
        string wpfa_event_cfs_link
        array  wpfa_event_speakers
    }

    wp_posts ||--|| wpfa_event_meta : uses_keys_for_wpfa_event
Loading

Class diagram for new and updated WPFA event architecture classes

classDiagram
    class Wpfaevent_Public {
        -string plugin_name
        -string version
        +__construct(plugin_name, version)
        +enqueue_styles()
        +enqueue_scripts()
        +is_paginated_template() bool
    }

    class Wpfaevent_Admin {
        -string plugin_name
        -string version
        +render_event_meta_box(post)
        +save_event_meta(post_id)
    }

    class Wpfaevent_Meta_Event {
        <<static>>
        -string post_type
        +register()
    }

    class Wpfaevent_Event_Handler {
        -string plugin_name
        -string version
        +__construct(plugin_name, version)
        +ajax_get_event()
        +ajax_add_event()
        +ajax_update_event()
        +ajax_delete_event()
    }

    class Wpfaevent_Footer_Handler {
        -string plugin_name
        -string version
        +__construct(plugin_name, version)
        +ajax_update_footer_text()
    }

    class Wpfaevent_Plugin_Core {
        -Wpfaevent_Public plugin_public
        -Wpfaevent_Admin plugin_admin
        +load_dependencies()
        +define_admin_hooks()
    }

    class wpfaeventEventsConfig {
        +string ajaxUrl
        +string adminNonce
        +bool isAdmin
        +object i18n
    }

    class WPFA_Events {
        -object config
        -object elements
        +init(options)
        +openCreateEventModal()
        +openEditEventModal(card)
        +closeCreateEventModal()
        +closeEditEventModal()
        +filterEvents()
    }

    class WPFA_Footer {
        -object config
        -object elements
        +init(options)
        +openFooterModal()
        +closeFooterModal()
    }

    class WP_Core_WP_Query {
        +WP_Query(args)
    }

    %% Relationships
    Wpfaevent_Plugin_Core --> Wpfaevent_Public : creates
    Wpfaevent_Plugin_Core --> Wpfaevent_Admin : creates
    Wpfaevent_Plugin_Core --> Wpfaevent_Event_Handler : registers_ajax_actions
    Wpfaevent_Plugin_Core --> Wpfaevent_Footer_Handler : registers_ajax_actions

    Wpfaevent_Admin --> Wpfaevent_Meta_Event : uses_register_post_meta

    Wpfaevent_Public --> WP_Core_WP_Query : queries_events

    wpfaeventEventsConfig <.. Wpfaevent_Public : localized_script_data
    WPFA_Events ..> wpfaeventEventsConfig : reads_config
    WPFA_Footer ..> wpfaeventEventsConfig : reads_config

    WPFA_Events ..> Wpfaevent_Event_Handler : AJAX_calls
    WPFA_Footer ..> Wpfaevent_Footer_Handler : AJAX_calls
Loading

File-Level Changes

Change Details Files
Rebuilt the events page template into a full Events Hub with upcoming/past queries, reusable partials, sidebar, and admin-only modals.
  • Replaced the basic loop/pagination template with a complete HTML document structure that manually includes header and shared footer partials.
  • Split event card rendering into a reusable partial that reads event meta, formats dates, and exposes data-* attributes for client-side admin actions and search.
  • Introduced separate WP_Query configurations for upcoming and limited past events, with meta queries that differ for admins vs public users, and removed pagination in favor of showing all upcoming events.
  • Added layout sections for hero, search, upcoming events grid, past events grid, calendar/archive link, and a sidebar that renders latest news or an admin-only warning if the news helper is missing.
  • Conditionally loads admin-only event modals for create/edit/delete operations and wires in IDs/classes expected by the new JS module.
public/templates/page-events.php
public/partials/events/event-card.php
public/partials/events/event-modal.php
Added client-side JS for event search and admin CRUD (create, edit, delete) using AJAX endpoints and modals.
  • Implemented a modular WPFA_Events JavaScript object that initializes on DOMContentLoaded with localized config, performing DOM caching, wiring event listeners, and handling role-aware behaviors.
  • Implemented client-side text search across both upcoming and past events by matching against name, place, and description, updating a results counter and toggling card visibility.
  • Added modal handling logic for create and edit flows, including pre-filling edit fields from card data attributes, character counters, and HTML form validation.
  • Implemented AJAX calls for adding, updating, and deleting events using wpfa_add_event, wpfa_update_event, and wpfa_delete_event actions with nonce and capability checks surfaced via i18n messages.
  • Exported the module globally (window.WPFA_Events) and guarded initialization behind the presence of the localized wpfaeventEventsConfig object.
public/js/wpfaevent-events.js
Extended admin and meta infrastructure for events to support richer fields and REST exposure.
  • Augmented the event meta box to include time, lead text, registration URL, and call-for-speakers URL fields, plus corresponding inputs and placeholders.
  • Refactored event meta saving to iterate over a single list of meta keys, handling general text vs URL sanitization and preserving speakers as an array of IDs.
  • Registered new post meta keys (lead text, registration link, CFS link) for the wpfa_event post type with proper types, REST exposure, and sanitize callbacks so data is available to the frontend and API clients.
admin/class-wpfaevent-admin.php
includes/meta/class-wpfaevent-meta-event.php
Introduced dedicated AJAX handler classes for events and footer updates and wired them into the plugin bootstrap.
  • Created Wpfaevent_Event_Handler with AJAX methods to fetch a single event, add a new event, update an existing event, and delete an event, each validating nonces, capabilities, required fields, and handling featured image upload/validation.
  • Created Wpfaevent_Footer_Handler with an AJAX method to update a stored footer text option, with nonce and capability checks and JSON responses.
  • Instantiated the new handler classes in the main plugin loader and registered wp_ajax_* hooks for all new actions.
admin/partials/ajax-handlers/class-wpfaevent-event-handler.php
admin/partials/ajax-handlers/class-wpfaevent-footer-handler.php
includes/class-wpfaevent.php
Added a configurable, editable footer shared across templates, with JS wiring and styles.
  • Introduced a shared footer partial that renders configurable footer text (from wpfa_footer_text or a default), social links, and an admin-only "Edit Footer" button plus a modal with a form to update the text.
  • Added a WPFA_Footer JavaScript module that opens/closes the footer modal, syncs the displayed text with the textarea, and posts updates via AJAX using the same events nonce/config object.
  • Enqueued a dedicated footer script in the public asset loader and localized a wpfaeventFooterConfig object with AJAX URL, nonce, admin flag, and i18n messages.
  • Added global footer and modal styling to the main public stylesheet and template-specific events CSS, including responsive behavior and button styles.
public/partials/footer.php
public/js/wpfaevet-footer.js
public/class-wpfaevent-public.php
public/css/wpfaevent-public.css
public/css/templates/events.css
Added a sidebar news feed helper that consumes the FOSSASIA blog RSS and exposes a template-level API.
  • Added a helper class with functions to ensure feed support, render latest news from the FOSSASIA blog RSS with caching, and provide a styled fallback list if the feed is unavailable.
  • Exposed a wpfa_render_latest_news() function used by the events template sidebar, plus utilities to clear cache and test feed health.
  • Required the new helper from the main plugin bootstrap so the function is available when the events template loads.
includes/helpers/class-wpfaevent-news-functions.php
wpfaevent.php
Extended public-facing asset loading to support the new events and past events templates and to reuse config across modules.
  • Hooked template checks into enqueue_styles to load dedicated CSS for events and past events templates, along with navigation and pagination dependencies where needed.
  • Enqueued the events JS only on the events template and localized a config object containing AJAX URL, nonce, admin flag, and a comprehensive i18n bundle for all CRUD flows.
  • Enqueued the footer JS globally with its own localized config, leveraging the same nonce and admin capability checks used by events.
public/class-wpfaevent-public.php

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The footer JS is enqueued as wpfaevent-footer.js in Wpfaevent_Public::enqueue_styles(), but the file added is wpfaevet-footer.js, so the script will 404; either rename the file or fix the enqueue handle/path.
  • The footer module initialization in wpfaevet-footer.js currently checks for wpfaeventEventsConfig and passes that into WPFA_Footer.init, but the localized object for the footer is wpfaeventFooterConfig; align the check and the object name so the footer config is actually used.
  • In the footer JS you localize wpfaeventFooterConfig but in the DOMContentLoaded handler you gate initialization on document.getElementById('edit-footer-btn') and the presence of wpfaeventEventsConfig; this makes the footer script dependent on the events-page config and button, so consider decoupling it to work wherever the footer is rendered (e.g., check for wpfaeventFooterConfig only).
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The footer JS is enqueued as `wpfaevent-footer.js` in `Wpfaevent_Public::enqueue_styles()`, but the file added is `wpfaevet-footer.js`, so the script will 404; either rename the file or fix the enqueue handle/path.
- The footer module initialization in `wpfaevet-footer.js` currently checks for `wpfaeventEventsConfig` and passes that into `WPFA_Footer.init`, but the localized object for the footer is `wpfaeventFooterConfig`; align the check and the object name so the footer config is actually used.
- In the footer JS you localize `wpfaeventFooterConfig` but in the DOMContentLoaded handler you gate initialization on `document.getElementById('edit-footer-btn')` and the presence of `wpfaeventEventsConfig`; this makes the footer script dependent on the events-page config and button, so consider decoupling it to work wherever the footer is rendered (e.g., check for `wpfaeventFooterConfig` only).

## Individual Comments

### Comment 1
<location> `public/js/wpfaevet-footer.js:170-171` </location>
<code_context>
+if (typeof document !== 'undefined') {
+    document.addEventListener('DOMContentLoaded', function() {
+        // Check if config exists (footer exists on all template pages)
+        const footerElement = document.getElementById('edit-footer-btn');
+        if (footerElement && typeof wpfaeventEventsConfig !== 'undefined') {
+            WPFA_Footer.init(wpfaeventEventsConfig);
+        }
</code_context>

<issue_to_address>
**issue (bug_risk):** Footer module is initialized with the wrong localized config object.

Here the footer is initialized with `wpfaeventEventsConfig`, but the PHP localization exposes `wpfaeventFooterConfig`. As a result, the footer will break on pages where only the footer config is present and will miss footer-specific i18n strings. This should instead check `typeof wpfaeventFooterConfig !== 'undefined'` and pass that object into `WPFA_Footer.init`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@mariobehling mariobehling requested a review from Copilot February 10, 2026 14:37
@mariobehling mariobehling changed the title Refactor Events Template Architechture Refactor Events Template Architecture Feb 10, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Events page template into a richer “Events Hub” experience with modular partials, adds front-end admin CRUD via AJAX modals, and introduces a shared footer + “Latest News” sidebar integration.

Changes:

  • Reworked page-events.php to render upcoming + past events, include reusable event-card/modal partials, and add client-side filtering + admin controls.
  • Added AJAX handlers + public JS modules for event CRUD and footer text editing, plus new event meta fields.
  • Added RSS-based “Latest News” helper and a shared footer partial (with admin edit modal).

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
wpfaevent.php Loads the new news helper functions.
public/templates/page-events.php Major rewrite: Events Hub layout, upcoming/past queries, search UI, sidebar, footer + modals.
public/partials/footer.php New shared footer partial with admin-only edit UI.
public/partials/events/event-modal.php New create/edit event modal markup for admin front-end CRUD.
public/partials/events/event-card.php New reusable event card partial with admin action buttons and data attributes.
public/partials/events-listing-page.php Removes an old proxy partial.
public/js/wpfaevent-footer.js New JS module to update footer text via AJAX.
public/js/wpfaevent-events.js New JS module for search + admin CRUD (create/edit/delete) via AJAX.
public/css/wpfaevent-public.css Adds shared footer/modal/button styles and character counter styling.
public/css/templates/events.css Adds MVP-styled layout and components for the Events page.
public/class-wpfaevent-public.php Enqueues new template styles/scripts and localizes config for events/footer modules.
includes/meta/class-wpfaevent-meta-event.php Registers new event meta: lead text, registration link, CFS link.
includes/helpers/class-wpfaevent-news-functions.php New RSS news fetching/caching + fallback helpers.
includes/class-wpfaevent.php Loads/registers new AJAX handler classes and hooks AJAX actions.
admin/partials/ajax-handlers/class-wpfaevent-footer-handler.php New authenticated AJAX endpoint to update footer text option.
admin/partials/ajax-handlers/class-wpfaevent-event-handler.php New authenticated AJAX endpoints for event CRUD + image upload.
admin/class-wpfaevent-admin.php Extends the event meta box to include new fields (time, lead text, links).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Events Template Implementation (MVP-Parity)

2 participants