{"id":397837,"date":"2026-11-12T16:06:22","date_gmt":"2026-11-12T16:06:22","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/caje-course-builder\/"},"modified":"2026-11-13T04:53:48","modified_gmt":"2026-11-13T04:53:48","slug":"caje-course-builder","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/caje-course-builder\/","author":23598099,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.3","stable_tag":"1.0.3","tested":"7.1.4","requires":"6.6","requires_php":"8.1","requires_plugins":null,"header_name":"CAJE Course Builder","header_author":"CAJE Creations","header_description":"Sell video courses that unlock weekly and expire on schedule, with reminder emails and protected video.","last_updated":"2026-11-13 04:53:48","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":95,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.2":{"tag":"1.0.2","author":"cajebuilder","date":"2026-11-12 16:06:01","revision":3798739},"1.0.3":{"tag":"1.0.3","author":"cajebuilder","date":"2026-11-13 04:53:48","revision":3799680}},"upgrade_notice":[],"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":{"cajecb\/my-courses":{"$schema":"https:\/\/schemas.wp.org\/trunk\/block.json","apiVersion":3,"name":"cajecb\/my-courses","version":"1.0.2","title":"My Courses","category":"widgets","icon":"welcome-learn-more","description":"The logged-in student's courses: unlocked weeks, the next unlock and days of access left.","keywords":["courses","dashboard","student","enrollments"],"textdomain":"caje-course-builder","attributes":{"showEnded":{"type":"boolean","default":true}},"supports":{"html":false,"align":["wide","full"],"spacing":{"margin":true,"padding":true}},"editorScript":"file:.\/index.js","style":"cajecb-frontend"}},"tagged_versions":["1.0.2","1.0.3"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3798738,"resolution":"1","location":"assets","locale":"","width":1280,"height":1180},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3798738,"resolution":"2","location":"assets","locale":"","width":1280,"height":1000},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3799680,"resolution":"3","location":"assets","locale":"","width":1386,"height":1240},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3799680,"resolution":"4","location":"assets","locale":"","width":1386,"height":1036},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3798738,"resolution":"5","location":"assets","locale":"","width":1280,"height":860}},"screenshots":{"1":"The curriculum screen: drag lessons between weeks.","2":"Course settings with the live schedule summary.","3":"A course page for an enrolled student, with locked weeks and their unlock dates.","4":"The My Courses dashboard.","5":"Courses \u2192 Setup, from install to a test purchase."}},"plugin_section":[],"plugin_tags":[7114,260730,2195,2193,5349],"plugin_category":[45],"plugin_contributors":[292325],"plugin_business_model":[],"class_list":["post-397837","plugin","type-plugin","status-publish","hentry","plugin_tags-courses","plugin_tags-drip-content","plugin_tags-lms","plugin_tags-online-course","plugin_tags-stripe","plugin_category-ecommerce","plugin_contributors-cajebuilder","plugin_committers-cajebuilder"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/caje-course-builder.svg","icon_2x":false,"generated":true},"screenshots":[{"src":"https:\/\/ps.w.org\/caje-course-builder\/assets\/screenshot-1.png?rev=3798738","caption":"The curriculum screen: drag lessons between weeks."},{"src":"https:\/\/ps.w.org\/caje-course-builder\/assets\/screenshot-2.png?rev=3798738","caption":"Course settings with the live schedule summary."},{"src":"https:\/\/ps.w.org\/caje-course-builder\/assets\/screenshot-3.png?rev=3799680","caption":"A course page for an enrolled student, with locked weeks and their unlock dates."},{"src":"https:\/\/ps.w.org\/caje-course-builder\/assets\/screenshot-4.png?rev=3799680","caption":"The My Courses dashboard."},{"src":"https:\/\/ps.w.org\/caje-course-builder\/assets\/screenshot-5.png?rev=3798738","caption":"Courses \u2192 Setup, from install to a test purchase."}],"raw_content":"<!--section=description-->\n<p>CAJE Course Builder is for creators who release a video course or series a little at a time. Each student's schedule starts when they buy: the first lessons open right away, the next ones unlock after the interval you choose (every day, every 3 days, every week, or any number of days), and access ends a set number of days after the last unlock. It feels like a cohort, without running one.<\/p>\n\n<p><strong>Unlocks on your schedule, for each student<\/strong><\/p>\n\n<ul>\n<li>Build the curriculum by dragging lessons into weeks.<\/li>\n<li>Unlocks happen at a time of day you choose, in your site's timezone, and stay correct across daylight saving changes.<\/li>\n<li>A live summary shows exactly when the last week unlocks and when access ends, e.g. \"Week 6 unlocks on day 35. Access ends on day 125.\"<\/li>\n<li>Locked lessons show their title and unlock date, never their content. Videos are only sent to the page once a student is allowed to watch.<\/li>\n<\/ul>\n\n<p><strong>Selling with Stripe<\/strong><\/p>\n\n<ul>\n<li>New students create an account right on the course page (name, email, password) and go straight to checkout. No confirmation email to dig out first.<\/li>\n<li>Stripe's hosted Checkout: card details never touch your site.<\/li>\n<li>Stripe Tax support for sales tax and VAT.<\/li>\n<li>The webhook is set up for you when you save your key.<\/li>\n<li>Refund from WordPress; access ends when Stripe confirms the refund.<\/li>\n<li>Missed webhooks are caught by an hourly check with Stripe.<\/li>\n<li>Free courses get an \"Enroll for free\" button.<\/li>\n<\/ul>\n\n<p><strong>Emails students actually need<\/strong><\/p>\n\n<ul>\n<li>A welcome email, one each time a week unlocks, reminders before access ends (30, 7 and 1 days by default) and one when it ends.<\/li>\n<li>Each email goes out once, even if scheduled tasks run late or twice.<\/li>\n<li>Sent through <code>wp_mail()<\/code>, so your SMTP plugin applies. Templates can be overridden in your theme.<\/li>\n<\/ul>\n\n<p><strong>Student dashboard<\/strong><\/p>\n\n<ul>\n<li>A My Courses block and <code>[cajecb_my_courses]<\/code> shortcode: unlocked weeks, when the next one unlocks, and days of access left.<\/li>\n<li>Students land there after logging in.<\/li>\n<\/ul>\n\n<p><strong>Set up in minutes<\/strong><\/p>\n\n<p>Courses \u2192 Setup walks you from a fresh install to a test purchase: basics, Stripe, student accounts, emails and your first course, then a checklist of anything still missing.<\/p>\n\n<p><strong>Video<\/strong><\/p>\n\n<p>Embed YouTube or Vimeo videos per lesson. For protected video that can't be shared, the separate Pro add-on adds Bunny Stream uploads from the lesson editor with signed, expiring player links.<\/p>\n\n<p><strong>For developers<\/strong><\/p>\n\n<ul>\n<li>WP-CLI: <code>wp cajecb enroll --student=\u2026<\/code>, <code>wp cajecb status --student=\u2026 --now=\u2026<\/code> to see any student's access on any date, and <code>wp cajecb sweep --now=\u2026<\/code> to walk a schedule without waiting. <code>--student<\/code> is the student; WP-CLI already uses <code>--user<\/code> for the account that runs the command.<\/li>\n<li>Hooks for gateways, video providers, features, merge tags and email content.<\/li>\n<li>Theme-overridable templates in <code>caje-course-builder\/<\/code>.<\/li>\n<li>The screens in <code>build\/<\/code> are compiled. The readable source is included in <code>src\/<\/code>.<\/li>\n<\/ul>\n\n<h3>Privacy and external services<\/h3>\n\n<p>This plugin stores, in your WordPress database: enrollments (user, course, dates and status), orders (user, course, amount, tax, currency, status and the Stripe Checkout Session and payment IDs) and a log of which course emails each student was sent. It adds suggested text to your privacy policy, supports WordPress's personal data export and erasure tools, and removes a user's enrollments when the user is deleted. Orders are kept as sales records.<\/p>\n\n<p>It connects to these services:<\/p>\n\n<p><strong>Stripe<\/strong> (payments), only after you add a Stripe secret key:<\/p>\n\n<ul>\n<li>When a logged-in buyer clicks Buy, the plugin creates a Checkout Session at <code>api.stripe.com<\/code>, sending the course name, price, currency, the buyer's email address and WordPress user ID, and your site's address. The buyer then pays on <code>checkout.stripe.com<\/code>.<\/li>\n<li>When you save your key, or check the connection, it creates or checks the webhook endpoint for your site and reads your Stripe Tax status.<\/li>\n<li>Hourly, it asks Stripe for Checkout Sessions from the last 72 hours to catch any payment whose webhook didn't arrive.<\/li>\n<li>When you click Refund, it creates a refund for that payment.<\/li>\n<li>Stripe's <a href=\"https:\/\/stripe.com\/legal\/ssa\">Services Agreement<\/a> and <a href=\"https:\/\/stripe.com\/privacy\">Privacy Policy<\/a>.<\/li>\n<\/ul>\n\n<p><strong>YouTube and Vimeo<\/strong> (video embeds), only on lessons you've given a YouTube or Vimeo link, and only for students allowed to watch them: the student's browser loads the player from <code>www.youtube-nocookie.com<\/code> or <code>player.vimeo.com<\/code> (with Vimeo's \"do not track\" option). YouTube's <a href=\"https:\/\/www.youtube.com\/t\/terms\">Terms<\/a> and Google's <a href=\"https:\/\/policies.google.com\/privacy\">Privacy Policy<\/a>; Vimeo's <a href=\"https:\/\/vimeo.com\/terms\">Terms<\/a> and <a href=\"https:\/\/vimeo.com\/privacy\">Privacy Policy<\/a>.<\/p>\n\n<p>The plugin makes no other external requests, and sends no usage data.<\/p>\n\n<h3>Credits<\/h3>\n\n<p>The curriculum screen's drag and drop uses <a href=\"https:\/\/dndkit.com\/\">dnd kit<\/a> (MIT license).<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin.<\/li>\n<li>Go to <strong>Courses \u2192 Setup<\/strong> and follow the steps.<\/li>\n<li>In <strong>Settings \u2192 General<\/strong>, set your timezone to a city (not a UTC offset) so unlock times follow daylight saving.<\/li>\n<li>For dependable email timing on quiet sites, have your host run WordPress cron from the server. <strong>Courses \u2192 Settings \u2192 Emails<\/strong> shows how.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"when%20do%20new%20lessons%20unlock%3F\"><h3>When do new lessons unlock?<\/h3><\/dt>\n<dd><p>At the unlock time you choose (8:00 am by default) in your site's timezone, on the day it's due. You set the interval per course in days: with 7, week 2 unlocks 7 days after purchase and week 3 after 14; with 3, every 3 days. You can also give a single lesson its own unlock day.<\/p><\/dd>\n<dt id=\"can%20i%20test%20a%20schedule%20without%20waiting%20weeks%3F\"><h3>Can I test a schedule without waiting weeks?<\/h3><\/dt>\n<dd><p>Yes. <code>wp cajecb status --student=\u2026 --now=\"2026-12-01 09:00\"<\/code> shows what a student can see at any moment, and <code>wp cajecb sweep --now=\u2026<\/code> sends the emails that would be due then. Enroll and revoke take the same <code>--student<\/code> (an ID, email or login) and <code>--course<\/code>. On non-production sites you can also set the plugin's clock with the <code>CAJECB_NOW<\/code> constant in wp-config.php.<\/p><\/dd>\n<dt id=\"can%20i%20test%20payments%20on%20my%20own%20computer%3F\"><h3>Can I test payments on my own computer?<\/h3><\/dt>\n<dd><p>Yes. Use Stripe test mode and run <code>stripe listen --forward-to<\/code> with the webhook URL shown in Courses \u2192 Settings \u2192 Payments, then paste the signing secret it prints.<\/p><\/dd>\n<dt id=\"are%20embedded%20youtube%20or%20vimeo%20videos%20protected%3F\"><h3>Are embedded YouTube or Vimeo videos protected?<\/h3><\/dt>\n<dd><p>No. The plugin only puts the player on the page for students who are allowed to watch, but anyone who has the video's link can watch it on YouTube or Vimeo. Use unlisted or private videos with domain restrictions, or the Pro add-on's Bunny Stream integration for protected video.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20i%20delete%20the%20plugin%3F\"><h3>What happens when I delete the plugin?<\/h3><\/dt>\n<dd><p>Scheduled tasks are removed. Your courses, enrollments, orders and settings are kept unless you turn on \"Delete all \u2026 when the plugin is deleted\" in Courses \u2192 Settings \u2192 General. The webhook in your Stripe account isn't removed; delete it in Stripe \u2192 Developers \u2192 Webhooks.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>A new look for course pages, lessons, the locked-lesson message, My Courses and the sign-up form: calm panels, a week timeline and clear open and locked states, on your theme's own font.<\/li>\n<li>New Accent color setting in Courses \u2192 Settings \u2192 General. Button text switches between white and dark to stay readable.<\/li>\n<li>Templates add state classes such as <code>is-open<\/code> and <code>is-locked<\/code>. Templates copied to your theme keep working.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Signup limits from one connection stay in force when several requests arrive together.<\/li>\n<li>A sweep handles a fixed number of emails per run, including ones it only records as skipped, and later runs finish the rest without sending anything twice.<\/li>\n<li>After you log in or register to buy, checkout continues only with a nonce issued for that login, plus the one-time token from your browser.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Setup screen styles are loaded with <code>wp_enqueue_style<\/code> instead of a style tag in the page.<\/li>\n<li>Actions that change enrollments, settings, or setup check a nonce and a capability. Request values are unslashed and sanitized.<\/li>\n<li>Course pages, locked lessons, and My Courses escape the HTML they add to the page, including video players.<\/li>\n<li>The setup reminder on the Courses screen is dismissible and stays dismissed for that user.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First public release: weekly drip schedules with expiry, Stripe Checkout with Stripe Tax and refunds, student emails, the My Courses dashboard, the setup wizard and WP-CLI commands.<\/li>\n<li>Lessons a visitor can't watch stay out of search, including the REST search endpoints.<\/li>\n<li><code>wp cajecb enroll<\/code>, <code>status<\/code> and <code>revoke<\/code> take <code>--student<\/code> (WP-CLI reserves <code>--user<\/code>).<\/li>\n<li>A payment that doesn't match the course price tells the buyer and emails the site owner.<\/li>\n<li>Returning from login continues to checkout only with a short-lived token from this site.<\/li>\n<li>Days of access left follow calendar dates in the site timezone, including across daylight saving.<\/li>\n<\/ul>","raw_excerpt":"Video courses and series that unlock on your schedule, for each student, with Stripe Checkout, reminder emails and a student dashboard.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/397837","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=397837"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/cajebuilder"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=397837"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=397837"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=397837"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=397837"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=397837"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=397837"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}