Static Interactivity
This plugin adds interactivity to static WordPress sites
Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/darkmatter-999/wp-static-interactivity/archive/refs/heads/master.zipStatic 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 `