Imported from woocommerce/sensei-certificates (
AGENTS.md). Install upstream withnpx skills add woocommerce/sensei-certificates. Copyright stays with the author.
Sensei LMS Certificates is a WordPress plugin that awards students a downloadable PDF certificate when they complete a Sensei LMS course. It extends Sensei LMS (the sibling sensei plugin) and does not function without it — see the dependency section below.
Read before writing code
This repo has no conventions docs of its own; it follows Sensei LMS's, canonical in the sensei repo.
- Writing or changing a test? Read Sensei LMS's unit-test conventions first.
- Writing a class, hook, meta key, block, or stylesheet? Read Sensei LMS's naming conventions first.
Apply them to code you add. Do not rewrite surrounding code to match. Where they conflict with this repo's established patterns (legacy prefixes, existing learner identifiers), the local pattern wins — see Conventions.
Repository layout
woothemes-sensei-certificates.php— plugin entry point. Defines constants, runs the dependency checker, then bootsWooThemes_Sensei_Certificates. Also the source of truth forRequires PHPandRequires at least(minimum WordPress).classes/— main plugin PHP source. Key files:class-woothemes-sensei-certificates.php— main class (certificate generation, settings, download, hooks into Sensei).class-woothemes-sensei-certificate-templates.php— thecertificate/certificate_templatecustom post types and the design system.class-woothemes-sensei-pdf-certificate.php+class-woothemes-sensei-certificates-tfpdf.php/class-vip-tfpdf.php— PDF rendering on top of the bundled tFPDF library.class-woothemes-sensei-certificates-dependency-checker.php— gates activation on PHP version and the Sensei LMS dependency.blocks/,background-jobs/,tools/— the "View Certificate" block, bulk certificate generation jobs, and Sensei LMS Tools integrations.
admin/— admin post-type UI and write panels for the certificate template designer.assets/— JS/SCSS source and blocks; built artifacts land inassets/dist/(git-ignored, produced by the build).templates/— front-end certificate templates (overridable by themes).lib/tfpdf/— vendored tFPDF PDF library. Treat as read-only third-party code; excluded from linting.lang/— translations and the.potfile.sensei-certificates-functions.php— global template/helper functions.changelog/— per-PR changelog entries (created vianpm run changelog; see Conventions)..github/— PR and issue templates plus CI definitions.
Sensei LMS dependency
Sensei LMS Certificates is a runtime extension of Sensei LMS — there is no build-time coupling to the sensei source, but at runtime the sensei plugin must be installed and active, or this plugin deactivates itself.
- The gate lives in
Woothemes_Sensei_Certificates_Dependency_Checker: it requires theSensei_Mainclass and thesensei-versionoption to be at least theMINIMUM_SENSEI_VERSIONconstant declared there (source of truth for the minimum Sensei LMS version). - Code here consumes Sensei LMS APIs directly: the
Sensei()global,Sensei_Assets,Sensei_Settings, and course/lesson data. When you touch these, check the siblingsenseicheckout (usually../sensei) for the current signatures rather than guessing. - Do not vendor or duplicate Sensei LMS code here. If a shared concern needs fixing, fix it in the
senseirepo. Treat thesenseisource as read-only from this repo. - To exercise this plugin locally you need both plugins active in the same WordPress install with a course a student can complete.
Development environment
- Match your Node version to
.nvmrc(nvm usereads it) before anynpmcommand, so the committedpackage-lock.jsonisn't rewritten. - Install JS deps with
npm ciand PHP dev tooling (PHPCS) withcomposer install. - This repo has no wp-env / Docker sandbox of its own. Develop against a WordPress install that already has an active, compatible Sensei LMS — e.g. the local site this checkout lives under.
Building
npm run build— full release build:build:assetsthenarchive(producessensei-certificates.zipviacomposer archive).npm run build:assets— compile JS/CSS fromassets/intoassets/dist/(wp-scripts build). Run this after changing anything underassets/; the built files are what the browser loads.npm run start— webpack watch mode for iterative asset work.npm run i18n:build— regeneratelang/sensei-certificates.pot(needswp-cli).
Testing
- Test-driven development: Write tests for non-trivial new behavior and bug fixes — a failing test first, then implement until it passes. Skip tests only for trivial changes such as copy/string tweaks, config, mechanical renames, one-line passthroughs, and styling. If unsure whether a change needs a test, ask rather than skip by default.
- No harness is wired up yet (no PHPUnit, Jest, or Playwright config in this repo). Standing up the appropriate runner is part of doing a change properly — add PHPUnit (the WordPress-plugin standard, as the
senseirepo uses) for PHP behavior, or coordinate with the maintainer. Do not treat the missing harness as license to skip tests, and do not fabricatemake test/npm testcommands that don't exist. - Ad-hoc UI verification: For UI or behavior changes, use the
ui-verificationskill (.claude/skills/ui-verification/SKILL.md), which scopes from the diff and drives the running site via Chrome DevTools MCP. Requires a WordPress install with Sensei LMS active and a course a student can complete.
Linting
- PHPCS: Run
npm run lint:php. Auto-fix withnpm run format:php. - JS / CSS / package.json:
npm run lint:js(ESLint onassets/js),npm run lint:css(stylelint onassets/css),npm run lint:pkg-json(package.json). - Before pushing: CI runs PHPCS on every PR. Always run
npm run lint:phpon modified files before pushing to avoid CI failures.
Conventions
- Changelogs: Every user-facing change MUST have a changelog entry. Add one with
npm run changelog(fill Significance/Type/Message; writes thechangelog/file). For purely internal changes (refactors, test-only), apply theNo Changeloglabel instead. - PR milestones: Every PR should have a milestone. The
pull-requestskill assigns the next shipping milestone when it opens a PR. - Coding standards: Follow the WordPress coding standards for the language you touch — PHP, JavaScript, CSS. Use long-form
array( ... )in new PHP. - Naming — local exceptions to Sensei's conventions: Follow Sensei LMS's naming conventions (linked under "Read before writing code") for new code, except where this repo's established patterns win: classes are prefixed
WooThemes_Sensei_/Woothemes_Sensei_, and globals (functions, hooks) use thesensei/woothemesprefixes enforced byphpcs.xml.dist. Existinglearner-based identifiers and DB keys (e.g. thelearner_idpost meta) can't be renamed — leave them. Do not rewrite surrounding code to match a new style. - Documenting hooks and functions: Document new or updated actions/filters and public functions with docblocks (params, return,
@since). For@since, use the next version being released. When a change adds or updates a hook, describe it and apply theHookslabel; when it deprecates code, name the replacement and apply theDeprecationlabel. - Minimum supported versions: The
woothemes-sensei-certificates.phpplugin header is the source of truth —Requires PHP(minimum PHP) andRequires at least(minimum WordPress). Keep it,readme.txt, andSENSEI_CERTIFICATES_VERSIONin sync on a version bump. Don't use PHP features newer than the minimum.
Common pitfalls
- Editing the
senseisource orlib/tfpdf/from this repo. Both are effectively read-only here — fix Sensei LMS concerns upstream insensei; treat tFPDF as vendored third-party code. - Stale built assets: changes under
assets/don't appear in the browser untilnpm run build:assets(ornpm run start) regeneratesassets/dist/. Hard-reload after building. - Assuming Sensei LMS APIs: signatures for
Sensei(),Sensei_Assets,Sensei_Settings, etc. live in thesenseirepo — verify there instead of guessing. - Forgetting the version-file sync on a release (plugin header,
SENSEI_CERTIFICATES_VERSION,package.json,readme.txt). - Using the wrong Node: run
nvm usefirst sopackage-lock.jsonisn't rewritten by a newer npm.