Session log — WhatsApp isiXhosa course, plus the login fix that let everyone see it
Session log — WhatsApp isiXhosa course, plus the login fix that let everyone see it
What happened, in order
1. The brief
WAxhosa. Call the course WhatsApp isiXhosa.The shape of the work was the same as the SARS isiXhosa course on 30 April: lessons already exist on Vimeo in isiXhosa, with isiXhosa titles and descriptions. The job was to give them a home on s2l.online so an isiXhosa speaker can find them, take them in order, and have the whole course feel like one course rather than a playlist.
What was different this time was scale: ten lessons instead of six, and almost eighty minutes of content instead of twenty. Not a long form course by any stretch, but enough that putting the wrong order in front of a learner would be obvious.
2. A WhatsApp course in isiXhosa, ten lessons
Searching Vimeo for the WAxhosa tag returned ten videos, all isiXhosa, all titled with an Isifundo number from 01 to 10. The numbering told us the order, the durations told us the runtime, and the descriptions provided ready-made isiXhosa copy under each lesson title. No translation work, no re-recording, just stitching.
The lesson list, in order:
| # | Lesson | Length |
|---|---|---|
| 1 | Isifundo 01 Intshayelelo kunye noCwangciso | 4 min |
| 2 | Isifundo 02 Ukuphonononga iThebhu yeSetingi | 9 min |
| 3 | Isifundo 03 Ukuphonononga iThebhu yeeNgxoxo | 6 min |
| 4 | Isifundo 04 Sebenzisa Ikhamera ye-WhatsApp Kalula | 6 min |
| 5 | Isifundo 05 Ukuhlola iThebhu yeeFowuni | 4 min |
| 6 | Isifundo 06 Ubuchule Beengxoxo Inxalenye 1 | 12 min |
| 7 | Isifundo 07 Ubuchule Beencoko Inxalenye 2 | 16 min |
| 8 | Isifundo 08 Ukusetyenziswa koLuhlu lokuSasaza kwi-WhatsApp | 7 min |
| 9 | Isifundo 09 Ubumfihlo | 10 min |
| 10 | Isifundo 10 Khusela i-WhatsApp yakho | 5 min |
Total runtime is roughly 79 minutes. The course is free, level set to free, and surfaces automatically on the isiXhosa courses page next to the existing SARS series, because that listing is built from a language tag rather than a hand-curated list.
3. The login bug we found along the way
Once the course was up, Hasmukh tried it as a learner: register, browse, click through to a lesson. He noticed the top-right button still said Start Learning Free even after he had logged in. That should not happen. Once you are signed in, the site is meant to swap that button for an account link.
The first try was the obvious one: replace the static link in the navigation with the [member-nav mode=cta] shortcode that the membership plugin already provides. That shortcode reads “am I signed in?” and chooses the right label. The change went in cleanly, but the result did not change. The button still said Start Learning Free.
Digging into why the membership plugin thought every visitor was a guest revealed a real bug in the login flow. PageMotor's auth cookie has a specific format: it is signed, with the username, a timestamp, and an HMAC, joined by pipes. The login flow in the membership plugin was writing the cookie in a much simpler form: just the username on its own. The browser kept that cookie quite happily, but every subsequent page load checked the cookie, found it didn't match the expected format, and treated the visitor as a guest. Hasmukh felt logged in (he had clicked Log In and seen a redirect) while the site quietly disagreed.
The fix was to make the membership login sign the cookie the same way the rest of the site does. Same expiry, same domain, same flags, but the value now carries the username, the issued-at timestamp, and the HMAC, in the format every other part of the site already expects. After Hasmukh logged out and back in, the navigation finally swapped to My account.
4. Easier log out
With the login state now visible to the rest of the site, the next obvious gap was logging out. Until today, signing out meant finding the small link at the bottom of the profile page. Hasmukh wanted it visible from the top of the page, on every page.
Three options were on the table: a click-to-open dropdown under My account, a single account button with a separate logout link in the profile page, or just two buttons side by side. The decision was the simplest one: two buttons in the top right.
The membership plugin's nav shortcode now returns two list items when a learner is signed in. The first is the existing red My account button, kept exactly as it was. The second is a softly outlined Log out button. The same pair appears in the mobile drawer, so a learner on a small screen can sign out without leaving the page they are on.
The visual balance between the two matters. A red button next to a second red button shouts; a red button next to a plain text link mumbles. The middle ground is a thin grey outline around Log out, transparent fill, dark text. It says “I am clickable” without competing with the primary action.
5. The mystery “kennjordan” under every page
While testing the course as a learner, Hasmukh spotted a small italicised line under the page title on the watch page: kennjordan. It was on every page, not just the watch page, sitting between the heading and the body copy. It served no purpose to a learner. It was the page author from PageMotor's underlying schema, leaking through the theme.
The two ways to stop it are to remove the element from the page template, or to hide it with a CSS rule. Hasmukh's preference was clear: hide rather than remove, in case it is wanted back later for a different theme or a future change. A single CSS rule was added to the active theme's custom stylesheet, the stylesheet was recompiled, and the line is now invisible everywhere on the site.
6. A course-add playbook, so the next course is faster
One observation Hasmukh made afterwards was that adding a new course tends to be slow at the start of a session: the Vimeo token has to be tracked down, the right database tables remembered, the bug from a previous session (the one where lessons saved cleanly but had no video player because the wrong column was filled) re-learned and worked around. None of that is the interesting work; it is friction.
The fix is a written playbook, stored in Claude's memory, that loads into every new session automatically. It captures, in plain English: where the Vimeo token lives, how to search Vimeo by tag, the exact field shape for the two database tables a course needs, the field gotcha where a lesson must carry both the video URL and the Vimeo id, the row that creates the course's landing page, the fact that the language listing picks up the course on its own, the URLs to verify, and a rollback recipe if anything is wrong.
The other half of the agreement was about session shape. From the next course onwards, each one happens in its own fresh session. That keeps each session log focused, gives a clean git checkpoint to roll back to, and means the playbook only has to be re-read once per course, not per topic. A typical prompt to start a course-add session now looks like:
Build a new course on s2l.online.
Title: WhatsApp isiZulu
Slug: whatsapp-isizulu
Language: zulu
Vimeo tag: WAzulu
Description: A short course in isiZulu on getting started with WhatsApp on your Android phone.
That is enough for the playbook to take over: pull the videos, present the lesson list and total runtime for sign-off, then build the course and verify it on the live site, all in one transaction.
7. Going forward
Three things remain. The first is short: write a polished isiXhosa course summary for /whatsapp-isixhosa/ in place of the generic one. The second is to repeat the WhatsApp course in the other South African languages once those translated recordings are uploaded to Vimeo with the matching language tag (WAzulu, WAafrikaans, and so on). The third is the upstream nudge to the EP Membership maintainers: the local cookie patch can become a one-line plugin update once they accept it back into the suite.
Out of all of today's work, the biggest unlock is invisible: logged-in learners are now recognised as logged-in across the whole site. Every future feature that depends on login state, paid courses, progress tracking, certificates, comment posting, can be built on top without a buried surprise underneath.