Building a member area on Core dna: who a member is in the data, the sign-in flows and their templates, single sign-on and passkeys, the my-account routing convention, members-only content, sessions and the page cache, and the security checks to run before launch.
L2
Unit 04 · The my-account area and its routing convention
Adding a custom member page
The my-account area and its routing conventionPage 24 of 36Updated
A members-only page needs a template and a deploy, nothing else: no page record, no route and no admin setting. The procedure, the file it takes, how to put it in the account menu, and what it does and does not protect.
Who this is for. The theme developer asked for "a page only members can see". Afterwards you can add one in a few minutes and say exactly what it protects.
Three steps
Create templates/my-account/downloads.html in the site's repository.
Deploy it to the environment you are working on.
Open /my-account/downloads while signed in.
That is all. No page record, no route and no setting: the member area's catch-all maps the URL onto the file (The catch-all). Signed out, the same URL sends you to /login and back to the page after you sign in.
The template
Extend your copy of the account menu, so the page sits among the built-in screens and shares their navigation (The account menu). The page receives user, the signed-in user's record, and needs no sign-in check of its own.
Template codetemplates/my-account/downloads.html
{extends 'users/frontend/includes/account.html'}
{block 'accountContent'}
{$person = $user->getPerson()}
<h1>Downloads for {$person->getFirstName()|escape}</h1>
<p>Member since {$user->getCreated()|format:'date'}</p>
{/block}
{% extends 'users/frontend/includes/account.html' %}
{% block accountContent %}
{% set person = user.getPerson() %}
<h1>Downloads for {{ person.getFirstName()|e }}</h1>
<p>Member since {{ user.getCreated()|date('j F Y') }}</p>
{% endblock %}
In Smarty, |format:'date' is the platform's date modifier, using the site's date format setting. Twig has no equivalent for dates: its own format filter is sprintf, so use Twig's date filter. A Twig site extends its own Twig copy of the account menu, since the framework's is Smarty.
Putting it in the account menu
Add the link to your copy of users/frontend/includes/account.html. Build it from the module's path, so it follows the prefix if the platform team ever changes it, and mark it current with a plain comparison of the request path:
{% set downloadsPath = _url.getModulePath('MyAccount') ~ '/downloads' %}
<a href="{{ downloadsPath }}"{% if _url.isCurrentPath(downloadsPath) %} aria-current="page"{% endif %}>Downloads</a>
What it protects
The page is closed to signed-out visitors and open to everyone who is signed in. Every member can open it, and so can any backend user signed in on the site. Three consequences:
If only some members may see it, the template has to decide, from a group or an entitlement record (Entitlements: access per record). That check protects this page only.
A file linked from it is public by design. Anyone with the file's URL can download it, signed in or not (Members-only files).
Anything it lists is only as private as its records. A record shown here can still be read wherever else it appears, unless the record itself is restricted (Two gates: published and permitted).
Checking it
Signed out, the URL answers a redirect to the sign-in page; a misspelt URL or a file that did not deploy answers 404 once you are signed in:
Then sign in in a browser as a test member and open the page. A page that shows another screen instead has collided with a built-in route (A named route always wins). A page that has to accept a form, carry an id in its path or follow other access rules needs more than the catch-all (When the catch-all is not enough).