WP Manifestindependent plugin directory
manifest / integrations / wp-static-interactivity

Static Interactivity

This plugin adds interactivity to static WordPress sites

★ 0stars

Install

Download source zip No release zip yet

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.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

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 tsvector with 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

  1. Upload the wp-static-interactivity folder to /wp-content/plugins/.
  2. Activate the plugin via Plugins.
  3. Go to Settings > Static Interactivity.
  4. Enter your Supabase project URL, anon (publishable) key, and service_role (secret) key.
  5. Create the required tables in Supabase SQL Editor (schema is displayed on the settings page).
  6. 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_role key. 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 fts query
  • 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

  1. When a post is saved, an async cron event pushes it to Supabase search_index.
  2. On the search page, the core/query block is replaced with <dmsi-search>.
  3. The JS component executes a full-text search via Supabase REST API using fts on the search_vector column.
  4. Results are rendered by cloning the theme's post template HTML from a `