Page Access for Buyers
How to sell access to pages, such as a members area, a course or a private changelog: access rules, the template gate, path protection, the access link and the editor’s Store panel. A buyer of the right product (or plan) sees the page; everyone else sees a notice with buy links.
Turn on the Page Access module (page_access toggle). It needs Licensing. A license that came with a bundle unlocks pages for its own product, the same as one bought on its own. In 0.2.0 the content editor’s Store panel can also limit an entry to buyers (see The Admin, the Sidebar and Product Pages).
EmDash has no content gating API, so Vendwick gates pages in two ways, and you’ll usually use one or both:
- In templates:
<AccessGate>andhasAccess()around content. See Components, Blocks and Styling. - By path: the companion middleware guards whole paths before the page renders.
Verified: the gate has run on a local
workerdwith D1 (for 0.1.0), as well as in the Node test suite. It hasn’t run on a deployed Worker yet.
Rules
You manage rules on the Page access admin page. A rule has:
- A target: a content entry (a collection and an entry, picked from your content), or a path pattern.
/membersmatches that path exactly;/members/*matches it and everything under it. - Grants: the products that unlock it, each for any plan or one plan, and optionally "requires a live subscription" instead of just an unexpired license.
- A teaser: text shown to visitors without access.
- noindex: on by default.
- A mode: follow the store default, always show the notice (
teaser), or always redirect (redirect). - Status: active or disabled.
Paths that can never be protected: /, /_emdash, /_vendwick, /_astro, /_image, /_server-islands, and the checkout, account and product paths.
Who gets in
- A licensed product counts while its license is active, not past its expiry (no expiry means lifetime), and its order was paid and not refunded. If the license has a subscription, it must be live (
active,trialingorpast_due) or canceled with paid time left. - A product without a license (a service or event) counts while its order item is paid and not refunded.
- A disabled license or a refunded order ends access at once. A partially refunded order still counts as paid.
- With
access_after_endset to "Keep access after the first payment", a license from a paid order keeps counting after it expires or its subscription ends. - Signed-in EmDash editors and admins always get in.
Visitors without access
| Setting | Options (default first) |
|---|---|
access_guest_action: visitors not signed in | see the notice, or go to the access page |
access_denied_action: signed-in customers without the product | see the notice, or go to the product |
access_after_end | access ends, or keep access after the first payment |
access_locked_title, access_guest_text, access_denied_text | notice wording; {products} becomes the products that unlock the page |
access_show_in_account, access_account_label | show "My pages" in the customer account (on, "My pages") |
access_cookie_days | access cookie lifetime, 1 to 365 days (30) |
A rule’s mode overrides the first two settings for that rule.
Path protection
The middleware checks a request when its path falls under an active path rule, or under a pattern you declare in the site options:
vendwickSite({ accessPaths: ["/members/*", "/course"] })
- A declared path with no admin rule stays closed to everyone except staff. Admin rules say who gets in.
- Visitors with access get the page with
Cache-Control: private, no-store. Others get a 303 to/_vendwick/access?return=<path>(or the first buy link, when the rule or store says so). Non-GET requests get 403. - Active path patterns are cached in each worker isolate for 30 seconds, so a new or changed rule can take up to 30 seconds to apply.
- When storage or the plugin can’t be reached, declared paths and paths this isolate already knew were protected fail closed with 503. Every other path renders normally.
- At most 100 active path rules are read.
The access link
On the gate or the access page, a buyer types their email under "Already bought?".
- The answer is the same whether or not the email is known, so it can’t be used to find customers.
- A known email (a customer, or licenses or orders for it) gets an emailed link, at most once every five minutes per email. Each IP may ask ten times a minute.
- The email is the
page_access_linktemplate, so its wording is the page-access wording, not the account-link wording. It’s branded and editable when the emails module is on. - The link is good for 30 days and is signed with a page-only key: it never opens the customer account.
- Opening it (
/_vendwick/access?cf_page_access_token=…&return=<path>) creates a session and sets thecf_page_accesscookie (HttpOnly, Secure, SameSite=Lax, path/) foraccess_cookie_days, then redirects to the page so the token doesn’t stay in the address bar. Return paths must be on the same site; anything else goes to/. - A customer who signs in to the account also gets the
cf_page_accesscookie, mirrored from their portal session.
noindex and search
On gated pages, Vendwick’s page:metadata contribution sets robots: noindex and a generic description, so the entry’s excerpt doesn’t reach the description tag. The same metadata goes to every visitor, buyers included. Gated responses also send X-Robots-Tag: noindex when the rule has noindex on.
What a plugin can’t do on EmDash:
- Sitemaps: plugins can’t remove entries. Keep gated entries out with an excluded collection or the entry’s SEO "no index" setting, or protect a section the sitemap doesn’t list.
- Site search: plugins can’t filter results. Mark the gated collection’s body fields as not searchable, or filter results in your search template with
hasAccess(). - Prerendered or edge-cached pages can’t be gated; their HTML is built once for everyone.
- Media files aren’t protected. A page can be gated, but an image or file URL it links to from the public media library is still public. Sell files as releases or digital products instead.
"My pages"
<MyPages /> and the account’s "My pages" tab list the gated pages a customer has unlocked, with links where EmDash can resolve a public URL. Up to 500 active content rules are read for this list.