Members-only forms
The Access panel in the form editor decides who may fill a form in, as opposed to Registration limits, which decides when and how many.
Who can fill it in
The panel offers three choices, from open to narrow:
| Choice | Who gets in |
|---|---|
| Anyone with the link | No sign-in needed. How every form works unless you change it. |
| Anyone signed in to this site | Any account, whatever its role. |
| Only these roles | Only the roles you tick. |
Picking Only these roles reveals a list of every role on the site. Administrator is not in it, because administrators can always fill in any form
- see Previewing below.
Ticking no roles behaves like "anyone signed in" rather than like "nobody". An empty list means a form somebody has not finished configuring, and reading it as "everyone" would be the one interpretation that quietly opens a form up.
What people are shown
Someone who cannot fill the form in sees its title, a message, and - only if they are not signed in - a Sign in button that brings them back to the page they came from. Someone signed in with the wrong role gets no button, because it would only send them round a loop they are already at the end of.
Write your own Message for people who cannot fill it in to say what to do about it ("Ask your coordinator to be added"), which beats the default wording for anyone who is not already an insider.
The form's description and its event card are held back along with the questions. Only the title is shown, so a restricted form does not publish what it is about to everyone with the link.
It is enforced, not hidden
The check is the same one the closing dates and the capacity cap go through, so
it applies wherever the form appears - its own page, the [localform]
shortcode and the LocalForm block alike - and a submission from someone who may
not fill it in is refused by the server. A stale browser tab, or a page served
from a cache, cannot get past it. A restricted form is also marked uncacheable,
so a full-page cache does not serve the signed-out version to someone who is
signed in, or the other way round.
Signing in is WordPress's own login screen. LocalForm does not add a registration flow, so this is for forms answered by people who already have an account - staff, members, students - rather than a way to gate a public form behind a sign-up.
Previewing
Anyone who can manage forms is let through any restriction, so you can open a members-only form and see it working without keeping a test account.
Because being quietly let through is its own trap - you would see the form working and have no way to tell that everybody else is being turned away - LocalForm says so, in a notice above the form that only you can see:
Only these roles can fill this form in: Editor. You can see it because you manage forms.
Your own submission is a real response, so use a draft form rather than a live one if you want to test the whole flow.
A form limited to a role that no longer exists - a role from a plugin that has been turned off, say - would match nobody and quietly stop collecting. The editor warns you instead, and the role is kept rather than dropped, so turning that plugin back on restores the setting.
The forms list marks restricted forms too, as Signed in only or Restricted, so you can tell at a glance which ones are not open to everyone.
Who submitted
Whenever somebody is signed in, the response records which account left it - on a gated form and on a public one alike.
A Submitted by column then appears:
- in the responses list under LocalForm → Responses,
- in the Excel and CSV exports,
- and on the printout of a single response.
The column shows up only once a form actually has a response from a signed-in
visitor, so a public form never grows an empty column - and relaxing a form's
access later does not hide the names already collected. If the account has since
been deleted, the response still reads Deleted user (#12) rather than losing
the attribution silently.
This is what makes a quiz usable as a training record: the score, the questions answered and the person who answered them, on one printable page.
The recorded account is a name to read, and nothing more. No permission anywhere is decided by it, and it does not let the person who submitted come back and edit their response.
Elsewhere
- Webhooks. The payload carries
user_id, ornullwhen nobody was signed in. Turning that ID into a name or an address is deliberately left tolocalform_webhook_payload- it is a choice about what leaves your site. - Privacy tools. Tools → Export Personal Data and Tools → Erase Personal Data match responses by the account as well as by an address written into an answer, which is the only way to reach a response to a form that never asked for an address.
- Backups. A backup keeps the account ID with each response and restores it. Restored onto a different site the ID may name a different account or none at all, since account IDs are per-site.
- MCP. An AI assistant can read and set all three settings, as
access(public/members/roles),access_rolesandaccess_message.
Developers
The gate runs inside Form::is_accepting(), ahead of not_open, closed and
full - a visitor who may not see the form is not told whether it is also
fully booked. It reports one of two reasons, because the remedy differs:
| Reason | Who gets it | What they are offered |
|---|---|---|
login_required | not signed in | message + Sign in button |
role_required | signed in, wrong role | message only |
For a rule roles cannot express - a membership tier, a group, a course
enrolment - use localform_user_may_submit. It runs only on a restricted form,
after the role check, and never on a public one:
add_filter( 'localform_user_may_submit', function ( $may, $form, $user ) {
if ( 'staff-incident-report' !== $form->slug ) {
return $may;
}
return $may && my_plugin_user_is_on_ward( $user->ID, 'b' );
}, 10, 3 );
localform_is_accepting still has the final say over everything, including the
access check, so it can close a form LocalForm left open - or reopen one it
closed. Check the reason before overriding.
Useful methods on Form, all taking the form record:
access_mode()-public,membersorrolesis_restricted()- anything butpublicaccess_roles()/access_role_names()/missing_access_roles()user_may_submit( $form, $user_id = null )- the honest answer, with no manage-forms allowanceaccess_bypassed()- true when the current user is only getting in because they manage forms