A simple event calendar application built with Flask and FullCalendar.
This calendar application solves a critical performance problem that plagues WordPress Events Calendar Pro:
- WordPress Events Calendar Pro starts to slow down around 1,000 events
- At 5,000 events, most queries take 2+ seconds per request
- This design provides nearly instantaneous speed even with a million events
- Most requests complete in under 0.02 seconds 😊 (for non-cached requests)
The performance difference is achieved through an innovative clustered index database design that optimizes for calendar-specific queries, combined with a comprehensive caching layer that serves most requests nearly instantly.
The application implements a multi-level caching system that dramatically improves real-world performance:
-
Day-Based Caching: Complete day events (both non-recurring and expanded recurring events) are cached for 1 hour. Key format:
"2025-01-15"→ complete list of events for that day. -
Calendar Range Caching: Calendar widget requests (week/month views) cache the entire date range results. Key format:
"calendar_2025-01-01_2025-01-31"→ events for the entire range. -
Cache Invalidation: Cache is automatically cleared when events are created, modified, or deleted, ensuring data consistency.
-
Memory Efficiency: Uses TTL (Time To Live) of 1 hour with maximum size limits (1,000 day entries, 100 calendar entries) to prevent memory bloat.
Real-world Performance Impact: In typical usage patterns, 90% of requests are served from cache, making them nearly instantaneous. The 0.02 seconds performance metric represents the worst-case scenario for non-cached requests, while cached requests typically complete in under 0.001 seconds.
- Monthly, weekly, and daily calendar views
- Create, edit, and delete events
- Recurring events support using iCalendar RRULE format
- Venue management
- Custom event colors
- Virtual and hybrid events support
- Full-text search functionality
- WordPress integration via widgets
- Advanced caching system with management interface
- Create a virtual environment (recommended):
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate- Install dependencies:
pip install -r requirements.txt- Run the application:
python app.py- Open your browser and navigate to
http://localhost:5000
config.yaml file!
The application requires a config.yaml file in the root directory with the following settings:
# Flask Events Calendar Configuration
# Database Settings
database:
path: "events.db"
# Timezone Settings
timezone:
local: "America/New_York"
# CORS Settings for WordPress Integration
cors:
enabled: true
origins:
- "https://your-wordpress-domain.com"
- "http://localhost:3000" # For local development
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allow_headers: ["Content-Type", "Authorization"]- CORS Origins: Must include your WordPress domain for integration to work
- Timezone: Set to your local timezone (e.g., "America/New_York", "America/Chicago")
- Database Path: Default is "events.db" in the application root
Without proper CORS configuration, the WordPress integration will fail! The application will exit with an error if the config.yaml file is missing or malformed.
The application uses 7 HTML templates that work together to create a complete event management system. All templates extend base.html and provide specific functionality for different parts of the application.
base.html (foundation)
├── widget_test.html (main interface - home & day views)
├── month.html (monthly calendar view)
├── event_form.html (event creation/editing)
├── venue_form.html (venue creation/editing)
├── venues.html (venue management list)
└── cache_management.html (cache administration)
Purpose: The main layout template that all other templates extend. It provides the common structure, navigation, and styling for the entire application.
Key Features:
- Bootstrap 5.3.6 CSS and JavaScript for responsive design
- FullCalendar 6.1.17 library for calendar functionality
- Navigation bar with links to:
- Home page (
/) - New Event (
/event/new) - Venues (
/venues) - Cache Management (
/cache-management)
- Home page (
- Flash message system for displaying success/error messages
- Responsive container layout with proper spacing
- Template blocks for custom CSS and JavaScript
Usage: Every other template extends this base template using {% extends "base.html" %}
Purpose: The primary user interface that serves as both the home page and day view. This is the most feature-rich template in your application.
Key Features:
- Two-panel layout:
- Left panel (8 columns): Events list widget with search functionality
- Right panel (4 columns): Calendar widget for date selection
- Advanced search functionality with real-time filtering
- Day navigation with Previous/Next buttons
- Event display with:
- Time, title, description, venue
- Virtual/Hybrid event badges
- Direct links to event URLs
- Interactive calendar that highlights selected dates
- Responsive design that works on all devices
Routes that use this template:
/(home route) - displays today's events/day/<date>(day view) - displays events for a specific date/widget-test(test route) - same as home page
Code Usage:
# In app.py
@app.route('/')
def home():
return render_template('widget_test.html', date=today_str)
@app.route('/day/<date>')
def day_view(date):
return render_template('widget_test.html',
year=date_obj.year,
month=date_obj.month,
day=date_obj.day,
date=date,
events=day_events)
@app.route('/widget-test')
def widget_test():
return render_template('widget_test.html')Purpose: Provides a dedicated monthly calendar view with compact styling optimized for performance.
Key Features:
- Compact monthly calendar with forced small styling
- Custom CSS that overrides FullCalendar defaults for smaller display
- Debug styling with colored borders to verify CSS application
- Responsive design with aspect ratio control
- Navigation between months
- Date clicking to navigate to day view
Routes that use this template:
/month/<int:year>/<int:month>- displays a specific month
Code Usage:
# In app.py
@app.route('/month/<int:year>/<int:month>')
def month_view(year, month):
return render_template('month.html', year=year, month=month)Special Features:
- Uses aggressive CSS overrides to force small calendar display
- Includes debug styling (red/blue/green borders) to verify CSS application
- Optimized for sidebar or compact display scenarios
Purpose: Comprehensive form for creating new events and editing existing ones.
Key Features:
- Quick date selector with buttons for Today, Tomorrow, +2 days, +3 days, Next Week
- Complete event fields:
- Title, description, start/end times
- Venue selection with "Add Venue" link
- Color customization (text and background)
- Virtual/Hybrid event options
- URL field for event links
- Recurring event support with RRULE format
- Advanced form validation with visual feedback
- Recurring event options that appear when RRULE is entered
- Virtual event options that show/hide URL field
- Auto-population of recurring end date (2 years from start)
Routes that use this template:
/event/new(GET) - displays empty form for new event/event/new(POST) - displays form with validation errors/event/<int:id>/edit(GET) - displays form with existing event data/event/<int:id>/edit(POST) - displays form with validation errors
Code Usage:
# In events.py
@app.route('/event/new', methods=['GET', 'POST'])
def add_event():
if request.method == 'POST':
# Process form data
return render_template('event_form.html', venues=venues, ...)
return render_template('event_form.html', venues=venues)
@app.route('/event/<int:id>/edit', methods=['GET', 'POST'])
def edit_event(id):
# Similar pattern for editingPurpose: Form for creating new venues and editing existing ones.
Key Features:
- Simple form with venue name (required) and address (optional)
- Form validation with visual feedback
- Help text explaining venue usage
- Delete functionality for existing venues
- Responsive design with card layout
Routes that use this template:
/venue/new(GET) - displays empty form/venue/new(POST) - displays form with validation errors/venue/<int:id>/edit(GET) - displays form with existing venue data/venue/<int:id>/edit(POST) - displays form with validation errors
Code Usage:
# In venue.py
@app.route('/venue/new', methods=['GET', 'POST'])
def add_venue():
if request.method == 'POST':
# Process form data
return render_template('venue_form.html', name=name, address=address)
return render_template('venue_form.html')
@app.route('/venue/<int:id>/edit', methods=['GET', 'POST'])
def edit_venue(id):
# Similar pattern for editingPurpose: Displays a list of all venues with management options.
Key Features:
- Table layout showing all venues
- Venue information:
- Name, address, event count
- Edit and delete buttons
- Empty state when no venues exist
- Responsive table design
- Action buttons for each venue
Routes that use this template:
/venues(GET) - displays list of all venues
Code Usage:
# In venue.py
@app.route('/venues')
def list_venues():
venues = session.query(Venue).all()
return render_template('venues.html', venues=venues)Purpose: Advanced interface for monitoring and managing the application's caching system.
Key Features:
- Cache statistics display:
- Day events cache stats (size, TTL, usage percentage)
- Calendar events cache stats
- Real-time updates
- Cache testing functionality:
- Test cache operations
- Set custom cache values
- Lookup cache entries
- Cache management:
- Clear all caches
- View recent cache keys
- Monitor cache performance
- Interactive JavaScript for real-time cache operations
Routes that use this template:
/cache-management(GET) - displays cache management interface
Code Usage:
# In cache.py
@app.route('/cache-management')
def cache_management():
return render_template('cache_management.html')API Endpoints (used by the template's JavaScript):
/api/cache/stats- get cache statistics/api/cache/clear- clear all caches/api/cache/test- test cache functionality/api/cache/get/<key>- lookup specific cache entry/api/cache/set- set cache value
- Template Inheritance: All templates extend
base.htmlfor consistent styling and navigation - Block System: Uses Jinja2 blocks (
{% block content %},{% block extra_css %},{% block extra_js %}) for customization - Responsive Design: Bootstrap-based responsive layouts that work on all devices
- JavaScript Integration: Each template includes custom JavaScript for interactive functionality
- Form Validation: Client-side and server-side validation with visual feedback
- Flash Messages: Consistent error/success message display across all templates
- widget_test.html is the most complex template, handling both home and day views
- month.html uses aggressive CSS optimization for compact display
- cache_management.html provides real-time monitoring of the caching system
- All templates use Bootstrap for consistent, responsive design
- JavaScript is loaded at the end of the page for optimal loading performance
- Click on any date to view the daily view
- Click the "New Event" button to create an event
- Click on an existing event to edit it
- Use the navigation buttons to move between months
- Switch between month, week, and day views using the view buttons
- Use the search functionality to find specific events
- Manage venues through the Venues section
- Monitor and manage cache performance through Cache Management
The application supports recurring events using the iCalendar RRULE format. Examples:
- Weekly on Monday, Wednesday, Friday:
FREQ=WEEKLY;BYDAY=MO,WE,FR - Daily:
FREQ=DAILY - Monthly on the 15th:
FREQ=MONTHLY;BYMONTHDAY=15 - Every other week:
FREQ=WEEKLY;INTERVAL=2 - First Monday of every month:
FREQ=MONTHLY;BYDAY=1MO
This application supports recurring events using the iCalendar RRULE format. Here's how recurring events are handled:
- Storage: Each recurring event is stored as a single row in the database, with its recurrence rule (RRULE) saved in the
rrulecolumn. The event also hasis_recurringandrecurring_untilfields to indicate recurrence and the end of the series. - Expansion: When the calendar or a day view is requested, the backend dynamically expands recurring events into their individual instances for the requested date range. This is done using the
dateutil.rrulelibrary, which parses the RRULE and generates all occurrences within the range. - Query Logic: For each request, the backend:
- Fetches all non-recurring events in the date range directly (using the clustered index for speed).
- Fetches all recurring events that could possibly have instances in the date range (using an index on
is_recurringandrecurring_until). - Expands only those recurring events that are relevant to the requested range, minimizing unnecessary computation.
- Editing: The event form allows users to specify or edit the recurrence rule and the end date for the series. The backend updates the relevant fields and ensures the event is treated as recurring or non-recurring as appropriate.
To ensure the application remains fast even with a large number of events and recurring series, several optimizations are used:
-
Clustered Indexing: The database uses a composite primary key
(start_date, id)so that events for the same date are stored together on disk. This makes range and day queries extremely efficient for non-recurring events. -
Targeted Recurring Queries: Instead of expanding all recurring events, the backend only considers those whose recurrence could affect the requested date range. This is achieved by filtering on
start_date,is_recurring, andrecurring_untilwith proper indexes. -
On-the-fly Expansion: Recurring events are expanded in memory only for the relevant date range, avoiding the need to store every instance in the database and keeping storage requirements low.
-
Efficient Algorithms: The use of the
dateutil.rrulelibrary allows for fast, reliable expansion of recurrence rules without custom logic.The
dateutil.rrulelibrary is a robust, well-tested implementation of the iCalendar recurrence rule (RRULE) standard. Instead of writing and maintaining custom code to interpret and expand recurrence rules—which is error-prone and can be very complex for edge cases like leap years, daylight saving time, or complex BYDAY/BYMONTH rules—dateutil.rrulehandles all of this efficiently. It is written in C and Python, optimized for performance, and used in many production systems. By leveraging this library, the application can quickly generate all event instances for any recurrence pattern, ensuring both correctness and speed, and freeing developers from having to debug or optimize custom recurrence logic. -
Indexing: An additional index on
(is_recurring, recurring_until)ensures that queries for recurring events are fast, even as the number of events grows.
These strategies ensure that the calendar remains highly performant, even with thousands of events and complex recurrence patterns.
To further optimize performance, the application implements a sophisticated caching layer that eliminates the need to re-query and re-expand events for frequently accessed dates:
-
Day-Based Caching: When a user views a specific day, the complete day events (both non-recurring and expanded recurring events) for that date are cached for 1 hour. Subsequent requests for the same date return the cached results instantly, avoiding the computational overhead of database queries and recurrence rule expansion.
-
Calendar Range Caching: For calendar widget requests (typically week or month views), the complete events for the entire date range are cached. This is particularly effective since users often navigate between adjacent weeks/months.
-
Cache Invalidation: The cache is automatically cleared when events are created, modified, or deleted, ensuring data consistency while maintaining performance benefits.
-
Memory Efficiency: The cache uses a TTL (Time To Live) of 1 hour and a maximum size of 1,000 entries, preventing memory bloat while covering the most commonly accessed date ranges.
Real-world Impact: In typical usage patterns, 80-90% of all event requests are served from cache, reducing the computational load by an order of magnitude. This means that the complex database queries and recurrence expansion work described above is only performed for the first request to a date, with subsequent requests being nearly instantaneous.
For information about planned features and enhancements, see the ROADMAP.md file. This document outlines:
- Upcoming Features: Planned enhancements ranked by importance
- Implementation Details: Technical specifications and code examples
- Feature Priorities: What's most important to implement next
- Development Guidance: Step-by-step implementation instructions
The roadmap includes features like:
- Enhanced venue and organizer management
- Custom event fields
- Advanced filtering and search
- Map view for event locations
- Event duplication functionality
- API improvements for embedding
- Video conferencing integrations
This Flask Events Calendar can be seamlessly integrated with WordPress using the included WordPress plugin. This allows you to display your high-performance events calendar on any WordPress site while maintaining the speed and functionality of the Flask backend.
-
Copy the WordPress Plugin Files
# Copy the wp-events-calendar directory to your WordPress plugins folder cp -r wp-events-calendar/ /path/to/wordpress/wp-content/plugins/ -
Activate the Plugin
- Log into your WordPress admin dashboard
- Go to Plugins → Installed Plugins
- Find "Events Calendar" and click Activate
-
Configure the Flask App URL
- Edit
wp-events-calendar/wp-events-calendar.php - Update the
FLASK_EVENTS_URLconstant to point to your Flask application:
define('FLASK_EVENTS_URL', 'http://your-flask-app-domain.com');
- Edit
For a typical setup with Flask backend on a subdomain (e.g., flaskevents.thedetroitilove.com) and WordPress on the main domain (e.g., thedetroitilove.com):
-
Copy WordPress Plugin Files
- Copy the
wp-events-calendar/directory to your WordPress plugins folder - Location:
/path/to/wordpress/wp-content/plugins/wp-events-calendar/
- Copy the
-
Activate the Plugin
- Go to WordPress admin → Plugins → Installed Plugins
- Find "Events Calendar" and click Activate
-
Configure Flask App URL
- Edit
wp-events-calendar/wp-events-calendar.php - Update the
FLASK_EVENTS_URLconstant:
define('FLASK_EVENTS_URL', 'https://flaskevents.thedetroitilove.com');
- Edit
-
Add CORS Support to Flask App
- Install Flask-CORS:
pip install flask-cors - Add to your Flask app:
from flask_cors import CORS CORS(app, origins=['https://thedetroitilove.com'])
- Install Flask-CORS:
-
Add Widgets to WordPress
- Go to Appearance → Widgets
- Add "Events Calendar" widget to your sidebar
- Add "Events List" widget to your sidebar
- Set custom titles if desired
Key Points:
- SSL Required: Both sites need HTTPS for CORS to work properly
- CORS Configuration: Flask app must allow requests from your WordPress domain
- Two Widgets Available: Calendar widget (monthly view) and Events List widget (daily events)
- No Database Changes: WordPress and Flask remain completely separate
The plugin provides two widgets that can be added to any WordPress sidebar or widget area:
- Purpose: Displays a monthly calendar for event navigation
- Features:
- Compact monthly view
- Click on any date to view events for that day
- Navigation between months
- Responsive design optimized for sidebars
- Purpose: Displays events for the selected day
- Features:
- Shows all events for the current day
- Navigation buttons to move between days
- Displays event time, title, description, and venue
- Virtual/hybrid event badges
- Direct links to event URLs
-
Access Widget Management
- Go to Appearance → Widgets in your WordPress admin
- Or go to Appearance → Customize → Widgets
-
Add the Events Calendar Widget
- Find "Events Calendar" in the available widgets
- Drag it to your desired widget area (sidebar, footer, etc.)
- Set a custom title (optional)
- Click Save
-
Add the Events List Widget
- Find "Events List" in the available widgets
- Drag it to your desired widget area
- Set a custom title (optional)
- Click Save
The WordPress integration uses a client-side approach that maintains the performance benefits of the Flask backend:
WordPress Site Flask Events Calendar
┌─────────────────┐ ┌─────────────────────┐
│ │ │ │
│ WordPress │ │ Flask App │
│ Frontend │ │ (Python) │
│ │ │ │
│ ┌─────────────┐│ │ ┌─────────────────┐│
│ │ Widget ││ │ │ Database ││
│ │ (HTML) ││ │ │ (SQLite) ││
│ └─────────────┘│ │ └─────────────────┘│
│ │ │ │
│ ┌─────────────┐│ │ ┌─────────────────┐│
│ │ JavaScript ││◄─────────────┤ │ API Endpoints ││
│ │ (Widget) ││ │ │ (/events, ││
│ └─────────────┘│ │ │ /search) ││
│ │ │ └─────────────────┘│
└─────────────────┘ └─────────────────────┘
- URL: Set the Flask app URL in the WordPress plugin
- CORS: Ensure your Flask app allows requests from your WordPress domain
- SSL: Use HTTPS for production deployments
The widgets can be customized by modifying the CSS files:
wp-events-calendar/css/events-calendar.css- Main widget styles- Widget colors, sizes, and layout can be adjusted
- Responsive breakpoints can be modified
-
CORS Configuration Add CORS headers to your Flask app to allow WordPress requests:
from flask_cors import CORS app = Flask(__name__) CORS(app, origins=['https://your-wordpress-site.com'])
-
API Rate Limiting Consider implementing rate limiting for the
/eventsand/searchendpoints:from flask_limiter import Limiter from flask_limiter.util import get_remote_address limiter = Limiter( app, key_func=get_remote_address, default_limits=["200 per day", "50 per hour"] )
-
Input Validation The Flask app already includes input validation, but ensure your WordPress site validates any user inputs before sending to the Flask API.
When integrated with WordPress, this solution provides several advantages:
- Decoupled Architecture: WordPress handles content management while Flask handles event data
- Scalability: Event data doesn't impact WordPress performance
- Caching: Flask's caching layer works independently of WordPress caching
- Database Efficiency: SQLite with clustered indexing vs WordPress's MySQL queries
- Resource Isolation: Event processing doesn't compete with WordPress resources
-
Widgets Not Loading
- Check that the Flask app URL is correct in the plugin configuration
- Verify the Flask app is running and accessible
- Check browser console for JavaScript errors
-
CORS Errors
- Ensure Flask app has CORS properly configured
- Check that the WordPress domain is in the allowed origins
-
Events Not Displaying
- Verify the
/eventsendpoint is working in the Flask app - Check that events exist in the database
- Review browser network tab for API request failures
- Verify the
-
Styling Issues
- WordPress theme CSS may conflict with widget styles
- Add
!importantdeclarations to widget CSS if needed - Test with a default WordPress theme
Enable debug mode in the WordPress plugin by adding:
define('FLASK_EVENTS_DEBUG', true);This will output additional information to help troubleshoot integration issues.
You can create custom shortcodes to embed the calendar anywhere in your WordPress content:
// Add to wp-events-calendar.php
add_shortcode('flask_events_calendar', 'flask_events_calendar_shortcode');
function flask_events_calendar_shortcode($atts) {
$atts = shortcode_atts(array(
'view' => 'month',
'height' => '400px'
), $atts);
return '<div id="flask-events-calendar" style="height: ' . $atts['height'] . ';"></div>';
}Usage: [flask_events_calendar view="month" height="500px"]
For more advanced integrations, you can use WordPress's REST API to proxy requests to the Flask app:
add_action('rest_api_init', function () {
register_rest_route('flask-events/v1', '/events', array(
'methods' => 'GET',
'callback' => 'proxy_flask_events',
'permission_callback' => '__return_true'
));
});
function proxy_flask_events($request) {
$flask_url = FLASK_EVENTS_URL . '/events';
$response = wp_remote_get($flask_url);
if (is_wp_error($response)) {
return new WP_Error('flask_error', 'Failed to fetch events');
}
return json_decode(wp_remote_retrieve_body($response));
}This approach provides better integration with WordPress's authentication and caching systems.
The WordPress plugin is organized as follows:
wp-events-calendar/
├── wp-events-calendar.php # Main plugin file
├── includes/
│ ├── class-events-calendar-widget.php # Calendar widget class
│ └── class-events-list-widget.php # Events list widget class
├── css/
│ └── events-calendar.css # Widget styles
└── js/
└── events-calendar.js # Widget JavaScript
-
Main Plugin File (
wp-events-calendar.php)- Plugin header and metadata
- Widget registration
- Script and style enqueuing
- Configuration constants
-
Widget Classes (
includes/)Events_Calendar_Widget: Monthly calendar navigationEvents_List_Widget: Daily events display- Both extend WordPress's
WP_Widgetclass - Include form handling for widget configuration
-
Frontend Assets (
css/andjs/)events-calendar.css: Responsive widget stylingevents-calendar.js: Client-side functionality- Uses FullCalendar library for calendar display
- Handles API communication with Flask backend
To create custom widgets or modify existing ones:
-
Extend the Base Widget Class
class Custom_Events_Widget extends WP_Widget { public function __construct() { parent::__construct( 'custom_events_widget', 'Custom Events Widget', array('description' => 'Custom events display') ); } public function widget($args, $instance) { // Widget display logic } public function form($instance) { // Widget configuration form } public function update($new_instance, $old_instance) { // Widget settings update } }
-
Register Custom Widgets
add_action('widgets_init', function() { register_widget('Custom_Events_Widget'); });
-
Add Custom JavaScript
// Add to events-calendar.js or create new file document.addEventListener('DOMContentLoaded', function() { // Custom widget functionality });
The plugin supports several configuration options:
// In wp-events-calendar.php
define('FLASK_EVENTS_URL', 'http://localhost:5000');
define('FLASK_EVENTS_DEBUG', false);
define('FLASK_EVENTS_CACHE_TTL', 3600);
define('FLASK_EVENTS_MAX_EVENTS', 100);The plugin provides hooks for customization:
// Filter the Flask app URL
add_filter('flask_events_url', function($url) {
return 'https://custom-flask-app.com';
});
// Filter widget CSS classes
add_filter('flask_events_widget_classes', function($classes) {
$classes[] = 'custom-widget-class';
return $classes;
});
// Action when events are loaded
add_action('flask_events_loaded', function($events) {
// Custom processing of events
});-
Flask App Deployment
- Use a production WSGI server (Gunicorn, uWSGI)
- Set up reverse proxy (Nginx, Apache)
- Configure SSL certificates
- Set up process management (systemd, supervisor)
-
WordPress Integration
- Ensure HTTPS for both WordPress and Flask
- Configure CORS properly for production domains
- Set up monitoring and logging
- Consider CDN for static assets
-
Database Considerations
- SQLite works well for moderate loads
- For high traffic, consider PostgreSQL or MySQL
- Implement database backups
- Monitor database performance
-
Flask App
- Enable response compression
- Configure proper caching headers
- Use database connection pooling
- Implement request rate limiting
-
WordPress Plugin
- Minimize JavaScript and CSS
- Use WordPress transients for caching
- Implement lazy loading for widgets
- Optimize API request frequency
-
API Security
- Implement API authentication if needed
- Validate all input parameters
- Use HTTPS for all communications
- Implement proper error handling
-
WordPress Security
- Keep WordPress and plugins updated
- Use strong authentication
- Implement security headers
- Monitor for suspicious activity
Create endpoints to monitor the Flask app:
@app.route('/health')
def health_check():
return jsonify({
'status': 'healthy',
'database': check_database_connection(),
'cache': check_cache_status(),
'timestamp': datetime.now().isoformat()
})Implement comprehensive logging:
import logging
from logging.handlers import RotatingFileHandler
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s: %(message)s',
handlers=[
RotatingFileHandler('flask_events.log', maxBytes=10240000, backupCount=10),
logging.StreamHandler()
]
)Add monitoring to the WordPress plugin:
// Add to wp-events-calendar.php
add_action('wp_ajax_flask_events_health_check', 'flask_events_health_check');
function flask_events_health_check() {
$flask_url = FLASK_EVENTS_URL . '/health';
$response = wp_remote_get($flask_url);
if (is_wp_error($response)) {
wp_send_json_error('Flask app unavailable');
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
wp_send_json_success($data);
}This comprehensive WordPress integration documentation provides everything needed to successfully deploy and maintain the Flask Events Calendar with WordPress, ensuring optimal performance and user experience.
This application uses a clustered index design for event storage, which has been proven to be more efficient than conventional indexing for calendar-based queries. The key design decisions are:
-
Composite Primary Key (start_date, id)
- Events are physically stored in order by date, then by ID
- This clustering means events for the same date are stored together on disk
- Reduces disk I/O when querying events for a specific date or date range
-
Performance Benefits
- Single day queries: ~32% faster than conventional indexing
- 3-day range queries: ~32% faster than conventional indexing
- 7-day range queries: ~12% faster than conventional indexing
- More consistent performance (lower standard deviation in query times)
-
Why This Matters
- Calendar applications typically query events by date ranges
- Most queries are for single days or small ranges (1-7 days)
- The clustered design optimizes for these common use cases
- Reduces disk seeks and improves cache efficiency
The performance tests compare two approaches:
-
Conventional Approach
- Simple auto-incrementing primary key
- Separate index on start_date
- Events stored in insertion order
- Requires additional index lookups
-
Clustered Approach
- Composite primary key (start_date, id)
- Events physically ordered by date
- No additional index lookups needed
- Better cache utilization
The test suite creates 100,000 events and runs 200 queries for each test type:
Single Day Queries:
- Clustered: 0.000645s mean, 0.000000s median
- Conventional: 0.000951s mean, 0.000000s median
- 32.12% faster with clustered index
3-Day Range Queries:
- Clustered: 0.001014s mean, 0.000000s median
- Conventional: 0.001497s mean, 0.001510s median
- 32.27% faster with clustered index
7-Day Range Queries:
- Clustered: 0.002587s mean, 0.002003s median
- Conventional: 0.002959s mean, 0.002488s median
- 12.56% faster with clustered index
-
Event Model
class Event(Base): __tablename__ = 'event' start_date = Column(Date, nullable=False) id = Column(Integer, nullable=True) # Nullable to allow ID generation after object creation __table_args__ = ( PrimaryKeyConstraint('start_date', 'id'), )
-
ID Generation and Nullability
- The
idcolumn is nullable to support a two-step object creation process:- Create event object (initially with null ID)
- Generate and assign ID based on the date
- This is safe because:
start_dateis always present (NOT NULL)idis only null during object creation- Final database state never has null values in the composite key
- SQLite treats NULL values as distinct in composite keys
- Clustering still works effectively because:
- Primary clustering is by
start_date(always present) - Secondary clustering by
idwithin each date - Temporary nullability doesn't affect query performance
- Primary clustering is by
- The
-
Query Optimization
- Queries use the clustered index naturally
- No need for additional index hints
- Efficient for both exact date and range queries
-
Disk I/O Efficiency
- Related events are stored together
- Reduces disk seeks
- Better cache utilization
-
Query Performance
- Faster for common calendar queries
- More consistent response times
- Better scalability with large datasets
-
Maintenance
- No need for additional indexes
- Simpler query plans
- Less index maintenance overhead
-
Real-world Benefits
- Faster calendar loading
- Better user experience
- More efficient resource usage