Skip to content
Learnomy

Pricing and Access Models

Every Learnomy course carries two linked settings: an access type (the coarse "how is this course reached" value) and a pricing model (the richer "how a student pays" value). Together they decide whether a course shows a price, a Buy button, a membership path, or nothing at all.

What you can do

  • Offer a course for free, so any signed-in student can enrol with one click and no payment.
  • Sell a course for a one-time price, with an optional timed sale price.
  • Sell time-limited access, where a purchase grants entry for a fixed number of days and then expires.
  • Sell a course as a recurring subscription, billed per month or per year.
  • Gate a course behind a membership plan, so only members whose plan includes it can enrol.
  • Offer both paths at once: let students either buy the course outright or reach it through their membership.
  • Run a closed course that is never sold on your site, granting access from an outside system instead. See Closed Course Pricing.

Pricing and Access Models first view

How to use it

Step 1 -- open the Pricing & Access section

Edit the course and open the Pricing & Access section of the course editor. You will see the Pricing model control and the price fields.

Step 2 -- pick a pricing model

Learnomy supports seven pricing models. Each maps to one of five access types under the hood, so the catalog, checkout, and membership surfaces all agree:

Pricing model What the student does Access type stored
Free Enrols for free, no payment free
One-time Buys once, keeps lifetime access paid
Fixed-term Buys once, access expires after a set number of days paid
Recurring Subscribes per month or per year to keep access paid
Members only Enrols only if their membership plan includes the course membership
One-time or members Buys the course outright OR reaches it through membership paid_or_membership
Closed Cannot buy here; you grant access externally closed

Step 3 -- set the price fields

The visible price fields depend on the model you chose:

  • One-time and fixed-term courses use the regular Price, with an optional Sale price inside a Sale starts / Sale ends window.
  • Fixed-term courses also read an access-duration value (in days); when set, each enrollment is stamped with an expiry date that many days out.
  • Recurring courses use a recurring amount plus an interval of month or year.
  • Free, members only, and closed courses show no price -- switching a course to free also zeroes any lingering price and clears the sale price automatically.

Step 4 -- save

On save, Learnomy reconciles the two columns so they never drift: the model you picked sets the matching access type, and a free course can never keep a stale price.

Settings and options

  • Sales. A sale price only counts as active when it is positive, below the regular price, and the current time falls inside the sale window. Every surface (single course page, catalog card, price facet) reads the same rule, so they cannot show different prices.
  • Fixed-term expiry. Access expiry is computed from the course's access-duration days at enrollment time. Only fixed-term courses expire; every other model grants lifetime access by default.
  • Pricing lock after purchase. Once at least one student holds a non-pending paid or subscription enrollment, the course form refuses to rewrite the pricing model. Existing paying customers must not be moved into a half-state; clone the course to relaunch it with new pricing. Free enrollments do not lock the model.
  • Access-type filter. The catalog can be filtered by access type, so students can narrow to free or paid courses.

For developers

Model (Learnomy\Models\Course) is the single source of truth for the pricing vocabulary -- never hardcode the maps:

  • Course::ACCESS_TYPES / Course::PRICING_MODELS -- the two canonical option lists.
  • Course::MODEL_ACCESS_MAP / Course::ACCESS_PRIMARY_MODEL -- the maps between the two dimensions.
  • Course::model_for_access( $access_type ) / Course::access_for_model( $model ) -- convert between them.
  • Course::pricing_model( $course ) -- the resolved model for a course row, guarding against a stale pricing_model='free' column.
  • Course::is_free() / is_one_time() / is_fixed_term() / is_recurring() / is_members_only() / has_member_path() / requires_purchase() / is_closed() -- predicate helpers that take a stdClass course row.
  • Course::is_on_sale( $course ) / Course::effective_price( $course ) -- sale state and the price the buyer actually pays.
  • Course::compute_access_expiry( $course, $from = null ) -- the expiry DateTimeImmutable for a fixed-term course (null for every other model).
  • Course::recurring_amount( $course ) / Course::recurring_interval( $course ) -- per-period price and month / year interval for recurring courses.
  • Course::lock_pricing_model_if_purchased( $course_id ) -- true when a paid/subscription enrollment locks the model.

REST: the courses controller accepts access_type (enum including paid_or_membership) and the pricing fields on create/update.

Related