👻 Ghost Stories - Kiroween Hackathon Entry
"Stories that haunt your WordPress site... then vanish into the night"
Inspiration
Every Halloween (and Thanksgiving, Christmas, etc), stories are told around campfires—ephemeral tales that captivate, then fade into memory. We wanted to bring that same magic to the web.
Instagram Stories revolutionized how we share moments, but WordPress—powering 43% of the web—has been left in the dark ages.
Before becoming a Python backend developer I started my career developing WP websites in Ecuador, 8 years ago. A relative of mine contacted me a few months ago wanting stories in his site, I searched for a plugin and I found only abandoned, unmaintained, bloated and expensive plugins. I found one that was somewhat functional, and using Kiro I resurrected it :)
The "ghost" theme runs deep:
- Stories appear on your site, captivate visitors, then vanish after their expiration time
- Zero external dependencies—the plugin leaves no trace on third-party servers
- Built to be invisible to performance metrics—conditional loading means zero impact on pages without stories
Kiro became my supernatural companion in this journey, helping me completely resurrect the old plugin I found, delete all dependencies and make a lean plugin that does 1 thing very well.
What it does
Ghost Stories is a WordPress plugin that brings Instagram-style ephemeral stories to any WordPress website.
Core Features:
🔮 Story Creation - Upload images and videos through the familiar WordPress admin. Drag-and-drop to reorder. Set expiration times from 1 hour to 7 days.
⏰ Auto-Expiration System - Stories automatically "ghost" themselves after their time is up, moving to draft status. The cleanup runs via WordPress cron—no external services needed.
📱 Mobile-First Modal Viewer - Full-screen, immersive story experience with:
- Touch gestures (swipe horizontal for media, vertical for stories)
- Tap navigation zones
- Keyboard support (arrow keys, Escape)
- Progress bars synchronized with media duration
- Video controls with persistent mute state
🧱 Gutenberg Block - Drop stories anywhere using the native block editor. Select which stories to display, set alignment, done.
🔌 REST API - Full API for headless WordPress setups:
GET /wp-stories/v1/stories- Fetch active storiesGET /wp-stories/v1/stories/{id}- Get specific story with mediaPOST /wp-stories/v1/stories/{id}/view- Track views (CSRF protected)
⚡ Performance Optimized:
- Conditional asset loading (no stories = no scripts loaded)
- Transient caching for expiration checks
- Lazy loading for images
- Cache headers on API responses
🔒 Security First:
- Nonce verification on all forms
- Capability checks for admin operations
- Input sanitization and output escaping
- No external API calls or tracking
How we built it
This is where Kiro truly shined. We used nearly every Kiro feature available:
Specs for Structure
We started by creating a full specification in .kiro/specs/plugin-modernization/:
requirements.md- 12 requirement categories with acceptance criteriadesign.md- Architecture diagrams, component interfaces, data modelstasks.md- Implementation plan broken into 9 phases, 50+ subtasks
Kiro helped us think through edge cases we would have missed—like what happens when a story expires mid-viewing, or how to handle video progress synchronization.
Steering for Consistency
We set up steering rules in .kiro/steering/:
product.md- Product overview and target audiencestructure.md- File organization and naming conventionstech.md- Technical stack and common commands
This meant every time we asked Kiro for help, it understood our WordPress context, our class naming patterns (Story_* prefix), and our testing approach (PHPUnit + Brain Monkey).
Chat for Rapid Development
The conversational flow was incredible for:
- Debugging the modal viewer's touch gesture conflicts
- Implementing the video progress bar synchronization
- Refactoring the entire codebase from "Mega Stories" to "Ghost Stories" (Kiro updated 15+ files in one session!)
Tech Stack
- PHP 7.4+ - OOP architecture with singleton pattern for main plugin class
- Vanilla JavaScript - No build process, ES5-compatible for maximum WordPress compatibility
- WordPress APIs - Custom Post Types, REST API, Settings API, Block API
- PHPUnit 9.6 - Unit tests with Brain Monkey for WordPress mocking
Challenges we ran into
The Modal Visibility Nightmare
Our modal would open but remain invisible. After hours of debugging, we discovered a CSS specificity war between our styles and the theme. Kiro helped us implement !important overrides strategically and add inline style fallbacks.
Video Progress Synchronization
Getting the progress bar to smoothly sync with video playback was tricky. The timeupdate event fires inconsistently across browsers. We ended up using requestAnimationFrame for smooth 60fps updates, with Kiro helping us implement proper cleanup to prevent memory leaks.
Touch Gesture Conflicts
Horizontal swipes for media navigation kept conflicting with vertical swipes for story navigation. Kiro helped us implement angle-based detection—calculating the swipe angle and only triggering the appropriate action when the angle clearly indicates horizontal (< 45°) or vertical (> 45°) intent.
The Great Renaming
Midway through, we decided to rename from "Mega Stories" to "Ghost Stories" for the hackathon theme. This meant updating:
- Constants (
MEGA_STORIES_*→GHOST_STORIES_*) - Functions (
mega_stories_*→ghost_stories_*) - Options, text domains, console logs, API headers...
Kiro handled this massive refactor across 15+ files in a single session, catching references we would have missed manually.
Accomplishments that we're proud of
I don't know PHP anymore, I really vibe coded this plugin with the few concepts I remember from WordPress. I also don't know that much Frontend, specially vanilla JavaScript but was still able to deliver a functional plugin/
✨ Zero Dependencies - No Composer packages required for production. No external APIs. No tracking. Just WordPress.
✨ Full Spec-Driven Development - We have comprehensive requirements, design docs, and task lists. This isn't a hackathon hack—it's a maintainable, extensible plugin.
✨ Native WordPress Integration - Uses Custom Post Types, REST API, Block API, Settings API, Transients API. Feels like it belongs in WordPress core.
✨ Mobile-First UX - The modal viewer rivals native mobile apps with smooth gestures, progress indicators, and video controls.
✨ Performance Conscious - Conditional loading means zero performance impact on pages without stories. Caching throughout.
What we learned
Kiro Specs Are Game-Changing
Writing requirements and design docs before coding felt slow at first, but paid massive dividends. When we hit implementation, we knew exactly what to build. Edge cases were already considered. The architecture was solid.
Steering Rules Save Context
Instead of re-explaining our tech stack every conversation, steering rules kept Kiro informed. It knew we were building a WordPress plugin, using PHPUnit, following specific naming conventions.
AI Pair Programming Works
Kiro wasn't just autocomplete—it was a thinking partner. It caught bugs we missed, suggested better approaches, and handled tedious refactoring that would have taken hours manually.
WordPress Is Still Relevant
Building for WordPress in 2024 might seem old-school, but 43% of the web runs on it. There's massive value in bringing modern UX patterns (like Stories) to this platform.
What's next for Ghost stories
Immediate Roadmap
- [ ] WordPress.org submission for the plugin directory
- [ ] User-facing settings page (currently uses sensible defaults)
- [ ] Story analytics dashboard
- [ ] Shortcode support for non-Gutenberg users
Future Haunts
- [ ] Story highlights (permanent collections)
- [ ] User-submitted stories (frontend submission)
- [ ] Story reactions and polls

Log in or sign up for Devpost to join the conversation.