Static Interactivity
This plugin adds interactivity to static WordPress sites
by DarkMatter-999 · github.com/darkmatter-999/wp-static-interactivity · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/darkmatter-999/wp-static-interactivity/archive/refs/heads/master.zipReadme
Static Interactivity
Static Interactivity offloads dynamic WordPress features to Supabase, a PostgreSQL-based BaaS. When your WordPress site is exported to static HTML (e.g. with Simply Static), visitors still get full-text search and threaded comments powered by direct client-side calls to Supabase.
The plugin replaces the WordPress native search and comment blocks with custom web components (<dmsi-search> and <dmsi-comments>) that query Supabase directly from the browser. No page reloads needed.
Features
- Supabase Full-Text Search — PostgreSQL
tsvectorwith weighted title/excerpt, prefix matching, pagination. - Search Suggestions — Show recent posts when no results are found.
- Custom Search Slug — Configurable URL (default
/search/) backed by a real WordPress page. - Live Comments — Visitors read and submit comments directly via Supabase REST API.
- Comment Template — Uses the active theme's comment block HTML, extracted at render time.
- Bidirectional Comment Sync — Daily cron + manual sync keeps WordPress and Supabase in sync.
- Status Sync — Approve, hold, spam, or trash from WordPress admin; status updates propagate to Supabase.
- Post Sync — Published posts are pushed to the search index on save (async, non-blocking).
- Static Site Ready — All dynamic operations happen client-side; no PHP required after export.
- No Framework Runtime — Vanilla web components, zero JavaScript framework overhead.
Requirements
- WordPress 6.9+
- PHP 8.1+
- A Supabase project (free tier works)
Installation
- Upload the
wp-static-interactivityfolder to/wp-content/plugins/. - Activate the plugin via Plugins.
- Go to Settings > Static Interactivity.
- Enter your Supabase project URL, anon (publishable) key, and service_role (secret) key.
- Create the required tables in Supabase SQL Editor (schema is displayed on the settings page).
- Create a WordPress page with the slug matching your configured search slug (default:
search).
Setup Guide
1. Supabase Tables
Run these statements in the Supabase SQL Editor.
Search index table:
CREATE TABLE public.search_index (
post_id BIGINT PRIMARY KEY,
title TEXT,
excerpt TEXT,
featured_image_url TEXT,
permalink TEXT,
search_vector tsvector GENERATED ALWAYS AS (
setweight(to_tsvector('simple', coalesce(title, '')), 'A') ||
setweight(to_tsvector('simple', coalesce(excerpt, '')), 'B')
) STORED
);
CREATE INDEX search_index_search_vector_idx ON public.search_index USING GIN (search_vector);
ALTER TABLE public.search_index ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Allow public read-only access to search_index" ON public.search_index FOR SELECT USING (true);
Comments table:
CREATE TABLE public.comments (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
post_id BIGINT NOT NULL,
author_name TEXT,
author_email TEXT,
content TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
status TEXT DEFAULT 'pending'::text
);
ALTER TABLE public.comments ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can read approved comments" ON public.comments
FOR SELECT TO anon USING (status = 'approved');
CREATE POLICY "Anyone can insert comments" ON public.comments
FOR INSERT TO anon WITH CHECK (true);
GRANT USAGE ON SCHEMA public TO anon;
GRANT SELECT, INSERT ON public.comments TO anon;
2. Supabase Keys
- Publishable Key — The anon/public key from your Supabase project (Settings > API). Sent to the browser.
- Secret Key — The
service_rolekey. Kept server-side. Used for sync operations that bypass RLS.
3. Search Page
Create a standard WordPress page with the slug you configure (default: search). The page can be empty. The plugin overrides its template to search.php and replaces the main query block with the search web component.
Configuration
Navigate to Settings > Static Interactivity.
| Setting | Description |
|---|---|
| Supabase URL | Your Supabase project URL (e.g. https://xxxxx.supabase.co) |
| Supabase Publishable Key | Anon key sent to the frontend for client-side Supabase queries |
| Supabase Secret Key | Service role key used server-side for write operations |
| Search Slug | URL slug for the search page (must match an existing WordPress page) |
| Search Suggestions | Show recent posts when a search yields no results |
Admin Tools
- Replace All Search Data — Clears and rebuilds the entire search index.
- Test Connection — Verifies Supabase connectivity and table existence.
- Check Health — Compares WordPress post count vs Supabase row count.
- Sync Comments Now — Two-phase sync: push WP comments to Supabase, pull new Supabase comments into WP.
Frontend Web Components
<dmsi-search>
Rendered on the search results page. Features:
- Full-text search with PostgreSQL
ftsquery - Pagination with Previous/Next buttons
- Featured images, titles, excerpts rendered using the theme's post template HTML
- Search suggestions on no results (optional)
- Auto-populates the search input from query parameters
<dmsi-comments>
Rendered on singular posts where comments are open. Features:
- Loads approved comments from Supabase ordered by date
- Renders comments using the theme's comment block HTML (extracted at render time)
- Avatar images via Gravatar (SHA-256 hashed email)
- Load More pagination
- Inline comment submission (status: pending)
- No page reload for any operation
Development
Build
npm install
npm run build
Dev server (hot reload)
npm start
Linting
npm run lint:js # ESLint
npm run lint:css # Stylelint
npm run lint:php # PHPCS
Type checking
npm run type-check # PHPStan
Tests
npm run test:js # Vitest
npm run test:php # Pest PHP
Project structure
assets/
├── src/
│ ├── js/
│ │ ├── main.ts # Search redirect logic
│ │ ├── search.ts # <dmsi-search> web component
│ │ ├── comments.ts # <dmsi-comments> web component
│ │ └── admin-sync.ts # Admin sync AJAX interactions
│ └── css/
│ └── main.scss
include/
├── helpers/
│ └── autoloader.php # PSR-4-like autoloader
├── traits/
│ └── trait-singleton.php # Singleton pattern
└── classes/
├── class-plugin.php # Plugin bootstrap
├── class-assets.php # Script/style enqueuing
├── class-options.php # Centralized option accessor
├── class-settings.php # Admin settings page + AJAX handlers
├── class-search.php # Search sync + frontend logic
├── class-comments.php # Comments sync + frontend logic
└── class-supabase-api.php # Supabase REST client
How It Works
Search
- When a post is saved, an async cron event pushes it to Supabase
search_index. - On the search page, the
core/queryblock is replaced with<dmsi-search>. - The JS component executes a full-text search via Supabase REST API using
ftson thesearch_vectorcolumn. - Results are rendered by cloning the theme's post template HTML from a `