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/garethcitcom/mwm-core/archive/refs/heads/main.zipCompanion plugin for the Maths with Melissa block theme. It owns the data model, the REST API the theme uses, the YouTube playlist sync and the front-end Studio at /studio/.
Requires Advanced Custom Fields Pro (field groups are registered in PHP, nothing is click-configured).
Data model
| Post type | Slug | What it is |
|---|---|---|
mwm_lesson |
/lesson/{slug}/ |
A video. format taxonomy says whether it is a lesson, a short (Quick Maths) or a gaming video. A lesson can have more than one level (e.g. GCSE Foundation and Higher) and is listed under each. |
mwm_worksheet |
/worksheets/{slug}/, listed at /worksheets/ |
Worksheet PDF (pdf), optional worked answers (answers), the lesson it goes with (lesson), level and topic. Lessons point back via worksheet_post. |
mwm_quiz |
/quiz/{slug}/ |
Quiz JSON attached to a lesson (lesson field). |
mwm_past_paper |
listed on /revision/past-papers/ |
Board, tier, series, paper number, question paper + mark scheme PDFs, matching worksheets. |
mwm_predicted_paper |
listed on /revision/predicted-papers/ |
Melissa's own paper for a coming exam: board, level (GCSE Foundation / Higher / A-level), exam year, paper name, calculator flag, question paper + worked solutions PDFs, matching worksheets. No series or paper number; retired after the exam, never becomes a past paper. |
mwm_exam_date |
(no page) | Board, level, paper label, date, session, verified flag. Feeds exam panels and the calendar. |
mwm_pathway |
(no page) | Level (+ optional boards), topic groups → rows (lesson, note, coming soon), suggested revision plan. |
Taxonomies: mwm_level (GCSE Foundation / GCSE Higher / A-level; lessons and their worksheets can carry several, read them with mwm_post_levels() and label them with mwm_levels_label(), set them with mwm_set_lesson_levels()), mwm_topic (hierarchical: topic → subtopic; term meta holds chip icon, levels, order, browse intro, sync keywords), mwm_format, mwm_theme (Roblox / Minecraft / Story), mwm_board (Edexcel / AQA / OCR).
Lesson fields: youtube_url, youtube_id, duration_seconds, thumbnail_url, worksheet (PDF), answers (PDF), source_id/source_url (old site), playlist_id (set by the sync).
Quiz JSON schema
{"questions":[
{"type":"choice","q":"…","options":["A","B","C","D"],"correct":0,"explain":"…"},
{"type":"choice-image","q":"…","image":"description","imageUrl":"https://…","imageAlt":"…","options":["…"],"correct":1,"explain":"…"},
{"type":"order","q":"…","options":["…"],"correctOrder":[1,3,0,2],"explain":"…"}
]}
3–5 options per question, at most 10 questions. MWM_Quiz::validate() returns the cleaned questions or a plain-English error; the same validator runs in the Studio, the REST API and on save in wp-admin.
Pages
Activation creates the pages the theme navigates to and stores their IDs in the mwm_pages option: Home, Learn Maths (/learn-maths/), Revision (/revision/), Exam calendar, Past papers, Predicted papers, Quick Maths, Gaming & Story Maths, My Learning, Privacy. Each page holds one ACF block from the theme. Pages added in later plugin versions are created on the first request after the update (MWM_Activator::maybe_upgrade, keyed on the plugin version), so no reactivation is needed. Pretty URLs: /learn-maths/{level}/{topic}/, /revision/{level}/{board}/, /studio/{view}/.
REST API (/wp-json/mwm/v1/)
Public: lessons, topics, pathway, exam-dates, quiz/{id}. Signed-in: me/progress (GET/POST). Studio (capability mwm_manage_studio, granted to administrators and editors): studio/video, studio/lessons, studio/lessons/{id}, studio/upload, studio/quiz/validate, studio/past-papers, studio/predicted-papers, studio/exam-dates, studio/content, studio/content/{id} (DELETE = bin), studio/content/{id}/restore, studio/sync, studio/dashboard, studio/stats.
Site stats (Studio → Site stats)
Visitors, page views, time on site, top pages, where visitors come from, devices and Google search terms, over the last 7, 28 or 90 days. The numbers come from Google Site Kit; the Studio has no Google credentials of its own.
Setup: connect Site Kit (Analytics and Search Console) as an administrator, then in Site Kit → Dashboard → Share give the Editor role view access to both. MWM_Stats calls Site Kit's own data endpoints internally as the signed-in user, and Site Kit answers view-only users with the owner's connection. Reports are cached for an hour per range (the Refresh link skips the cache). The menu item only appears while Site Kit is active; if a service isn't connected or shared, that section says so in plain English and the rest still loads. Visits to /studio/ and wp-admin are left out of the top pages.
Everything Site Kit-specific is in includes/class-stats.php. Shared requests only accept Site Kit's allowlisted metrics and dimensions (googlesitekit_shareable_analytics_4_metrics / _dimensions filters), so check those before adding new ones.
Settings → Maths with Melissa
- Coming soon mode — on by default. While ticked, visitors who aren't logged in get a branded holding page (503 + noindex, logo and fonts from the theme when present) and the whole REST API rejects logged-out requests, so nothing leaks around the gate.
wp-login.phpstays open; anyone logged in sees the full site and admins get a toolbar reminder. Untick and save to launch. - YouTube Data API key — used by the daily sync and to fetch video length/date in the Studio. Without a key the Studio falls back to oEmbed (title + thumbnail) and a best-effort read of the watch page.
- Playlist IDs — Quick Maths (Shorts), Roblox, Minecraft, Story. The sync runs daily at 3 am (WP-Cron hook
mwm_daily_playlist_sync) and upserts videos asmwm_lessonposts keyed onyoutube_id. Videos removed from a playlist go back to draft. Level/topic are guessed from the topic terms' keyword meta and never overwrite manual edits. - Redirects — the 301 map from old URLs (filled by the import).
WP-CLI
wp mwm seed-demo [--remove] # prototype sample content
wp mwm import-lessons --source=https://old-site [--post-type=lesson] [--dry-run] [--update] [--no-media] [--limit=N]
wp mwm import-lessons --file=export.xml|lessons.json
wp mwm import-worksheets [--source=…] [--dry-run] # old worksheet pages → titles, slugs, standalone worksheets, redirects
wp mwm migrate-worksheets [--dry-run] # one-off: PDFs stored on lessons → worksheet posts
wp mwm redirect-map [--format=option|nginx|apache|csv|json]
wp mwm sync
The importer reads the old site's REST API (or a WXR export / JSON list), creates mwm_lesson posts with source_id + source_url, extracts the YouTube ID from meta or embedded iframes, maps level/topic from the old taxonomies or title keywords, sideloads worksheet/answer PDFs, and saves the 301 map. Unknown old /lesson/{id}/ URLs are also resolved on the fly from source_id.