Gallery Sync
Self-hostable WordPress gallery-sync plugin with a Cloudflare Worker license server (Stripe + Supabase).
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/uplinksync/gallery-sync/archive/refs/heads/main.zipReadme
Gallery Sync
Open-source WordPress plugin that syncs photos and videos from external libraries into your WordPress media library, with a Cloudflare Worker license server, Supabase Postgres persistence, and Stripe billing.
What it does
- Syncs media from external sources into WordPress (Dropbox, Google Drive, Google Photos, Flickr, Immich, Nextcloud, OneDrive, ownCloud, and more).
- Gates premium features against a license validated by a Cloudflare Worker API.
- Handles checkout and subscription/lifetime licensing through Stripe.
Architecture
- WordPress plugin (PHP): an untrusted client. Stores a per-site
gallery_sync_instance_id(UUID v4) and an encrypted license key, calls the Worker over HTTPS for/validate-licenseand/create-checkout-session, and caches the last valid response to reduce API calls. No paid business logic lives in the plugin — forking it never unlocks premium features. - Cloudflare Worker (
worker/, TypeScript): the source of truth for licenses and activations. Verifies Stripe webhook signatures and enforces(instance_id + normalized_domain)againstmax_activations. Supportslifetimeandsubscriptionlicense types. - Supabase Postgres: stores products, plans, licenses, activations, webhook
events, and audit logs. License keys are never stored in plaintext — only
license_lookup_digest+license_verifier_hash.
Worker routes
GET /healthPOST /stripe/webhookPOST /validate-licensePOST /create-checkout-session
Screenshots
Quickstart for forks
- Create Cloudflare resources — an API token with Workers deploy
permissions and your
CLOUDFLARE_ACCOUNT_ID. - Create a Supabase project — save the Postgres connection string as
SUPABASE_DB_URL(orDATABASE_URL) in GitHub Actions secrets. - Create Stripe products/prices — update
supabase/seeds/001_products_plans.sqlwith your realstripe_price_ids. - Add GitHub Actions secrets:
CLOUDFLARE_API_TOKEN,CLOUDFLARE_ACCOUNT_ID,SUPABASE_DB_URL. Optional for the webhook-setup workflow:STRIPE_SECRET_KEY,WORKER_PUBLIC_URL. - Set Cloudflare Worker runtime secrets:
DATABASE_URL,STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,LICENSE_HMAC_SECRET. - Set your KV namespace ids in
workers/wrangler.toml(placeholders are provided — create them withwrangler kv:namespace create ...). - Run the workflows from the Actions tab:
DB Migrate, thenDeploy Worker. Optionally runStripe Webhook Setup. - Configure the Stripe webhook at
https://<your-worker-domain>/stripe/webhookforcheckout.session.completedand thecustomer.subscription.*events. - Configure the WordPress plugin — set the Worker API base URL, enter a license key, and click Validate Now.
Local development
Worker:
cd worker
npm install
npm run typecheck
npm run dev
npm run deploy
Database migrations:
psql "$DATABASE_URL" -f supabase/migrations/0001_init.sql
psql "$DATABASE_URL" -f supabase/seeds/001_products_plans.sql
An optional scripts/bootstrap.sh uses the gh CLI to set the common GitHub
Actions secrets in your fork.
Tech stack
WordPress / PHP · Cloudflare Workers (TypeScript, Wrangler) · Supabase Postgres · Stripe
Contributing
Branch from main, open a pull request, and let CI run. Never commit literal
secrets — use GitHub Actions secrets and Cloudflare Worker runtime secrets.
License
See LICENSE.