Lubinik Learning started because I needed to prepare for WordPress job interviews.
I had not forgotten everything, but too much of my knowledge had become passive. I could recognise a hook, a custom post type, or a child-theme function when I saw one, yet I was no longer sure I could explain it clearly under pressure. The more code I delegated to AI, the easier it became to let details slip out of immediate memory.
I did not want another folder of notes that I would read once and then ignore. I wanted something that would ask me questions, make me choose an answer, show me exactly where I was wrong, and bring the difficult material back later.
So the first idea was very small: build a local WordPress site with a lot of multiple-choice exams.
The site had to ask back
The initial curriculum was deliberately broad. It began with the things that can feel embarrassingly basic when they are rusty: PHP syntax, HTTP, databases, WordPress post types, taxonomies, metadata, hooks, themes, child themes, security, debugging, and WP-CLI.
Then I added Lubinik itself. If I was going to keep building sites with this framework, I also needed to remember why its core, addons, child themes, configuration, templates, and scaffolder were separated the way they were.
That immediately made the project more useful than a generic quiz plugin. The questions could be based on the code I actually use. An explanation could point back to the relevant concept. An incorrect answer could become the beginning of a study session instead of the end of a score screen.
The first addon was not really a Lubinik addon
There was an architectural mistake early on.
I asked for the Learning addon to be created with the Lubinik scaffolder. The first implementation produced working learning code, but it had been assembled too directly. It was missing much of the generated structure that makes an addon belong to Lubinik: the expected registration layers, mappings, templates, admin integration, shortcode declarations, configuration points, and documentation.
It looked like an addon from the outside, but it did not carry the architecture.
That mattered. The scaffolder is not decoration, and it is not merely a quick way to create folders. It records the common shape of a Lubinik addon so that every new domain does not invent its own loader, naming rules, or integration strategy.
The Learning addon had to be rebuilt from the generated foundation. The custom post types, taxonomies, fields, shortcodes, templates, and learning services could then move into the correct places instead of forming a parallel system.
It was annoying to redo, but it became one of the most valuable parts of the project. Learning did not just use the scaffolder. It exposed what the scaffolder still needed to learn.
An exam is more than a page of radio buttons
Once I started taking the exams for real, the small idea expanded quickly.
An exam needs questions with stable choices, not answers that depend on their visual position. Scoring belongs on the server. A completed attempt needs its own private snapshot so that an old result remains understandable even if the original question changes later. A timed exam must keep its real deadline when it is reopened. An interrupted exam should resume without pretending it was already completed.
The result page also had to do more than display a percentage. I needed to review every answer, see the correct choice, make a wrong choice visually obvious, save a question for later, add a personal note, and retry the exam without losing the history of the first attempt.
Those details only became obvious because I was using the site, not merely checking whether the shortcode rendered.
A score was not enough
The first dashboards counted attempts, average scores, best scores, and pass rates. Useful, but incomplete.
If I completed three exams with good scores, that still did not tell me how much of the curriculum I had covered. It did not tell me whether I understood hooks but kept missing child-theme functions. It did not distinguish between seeing one question in a topic and repeatedly answering the topic correctly.
So Learning gained topic-level analytics, curriculum coverage, recent form, exam mastery states, and targeted practice links. The dashboard can show where I have started, where I am consolidating knowledge, and where I still have no evidence at all.
That distinction is important. A green score can feel reassuring. Coverage is more honest.
Flashcards changed the rhythm
Exams are good for testing a group of concepts, but they are not always the best way to remember one precise function, definition, or architectural rule.
Flashcards became the second learning mode. They can be organised by subject, marked as favourites, connected to questions, and graded Again, Hard, Good, or Easy. Those grades feed a private review schedule so that a difficult card returns sooner and an easy one can wait.
When an exam answer is wrong, the correction can recommend related flashcards. Saved questions can become a focused custom exam. The daily study queue can mix due cards, missed questions, saved material, weak topics, and a little new content without making me decide what to open first.
The daily queue also taught another useful lesson: completion is not the same as mastery. Marking an item as studied belongs in a study journal. It must not silently create an exam attempt or pretend that a flashcard received a review grade. Different actions need different meanings, even when they appear on the same dashboard.
The engine had to forget WordPress
The current site teaches WordPress and Lubinik, but the addon must not.
This became a strict boundary. The addon owns the reusable learning machinery: exams, questions, attempts, scoring, flashcards, review schedules, notes, saved items, daily sessions, analytics, privacy, and import or export rules. The child theme owns the vocabulary, page references, thresholds, menu labels, visual integration, and curriculum configuration.
The WordPress and Lubinik material belongs to the Learning site, not to the engine. A different child configuration and content pack should be able to use the same addon for tarot meanings, beer styles, a language course, or something I have not imagined yet.
That is why the content-pack format includes classifications, questions, ordered choices, explanations, references, flashcards, exams, and their relationships, while excluding attempts, favourites, notes, schedules, and other personal learner data.
Content should travel. A learner’s history should remain private.
Learning became a pressure test for Lubinik
Lubinik Learning is a study tool, but it is also one of the most demanding tests the framework has had.
It needed several related content types, multiple taxonomies, private user state, server-side scoring, frontend account pages, generated shortcodes, responsive interfaces, personal-data export and reset controls, content audits, portable JSON packs, and a child theme with substantial site-specific configuration.
Every time one of those features felt awkward, it asked a useful architectural question. Was the responsibility in the addon or the child? Was a URL being hard-coded instead of configured? Was a shortcode properly declared to Lubinik? Did a new component exist in the scaffolder, or only in the generated plugin? Would the same code still make sense if the subject were not programming?
The answers improved both the Learning addon and the machinery used to build future addons.
The lesson
I began this project because I was worried that I could no longer explain the technical things I had once known comfortably.
The solution was not to avoid AI or pretend I should remember every function name forever. It was to build a system that makes understanding visible. The code can help create the questions, organise the content, and calculate the progress, but I still have to choose an answer. I still have to notice why it was wrong. I still have to return to it later.
That is what Lubinik Learning became: a local place where the framework helps me study the framework, and where forgetting something is not a failure. It is simply the next item in the queue.