Memberz for Craft CMS

Free · Craft CMS 5

An account area your members can't talk their way around

Registration, profile fields, member photos and member directories, built in the control panel and rendered on the front end. No custom controller, no template surgery. Memberz reads only what a form asks for, decides privacy in exactly one place, and keeps every member's email address on your server.

Memberz

Features

A form a stranger can submit has to be safe by construction rather than by a list of things to block. Everything else follows from that.

The form is the allow-list

A submission is saved by walking the rows of the form it names and reading the one parameter each row asks for. The POST body is never iterated, and Craft's setFieldValuesFromRequest() is never called. So admin, groups, permissions and suspended do nothing: they aren't rows, so nothing reads them.

  • No list of forbidden keys to keep in step with Craft
  • Group assignment comes from the form's settings, not the submission

One privacy verdict

Each field has a ceiling the site sets and a preference the member picks, and whichever is stricter applies. A hostile form post can only tighten a setting. When several profile forms name the same field, the strictest of them wins, so adding a looser form can't widen what a directory already publishes.

  • The profile page, directory cards and Twig all ask the same function
  • A private profile is a 404, not a 403, so its URL can't confirm the account exists

Directories that answer only what they offer

Searchable, filterable, sortable member listings. A URL can send any ?sort= or ?f[…]= it likes, but Memberz only answers names that appear in the directory's own lists. ?sort=password never becomes an ORDER BY.

  • Members can unlist themselves, filtered in SQL so every page is full
  • Works as a plain GET form, with an optional script to filter in place

Photos checked by what they are

Front-end uploads are checked for size, then extension, then what the bytes actually are, so an SVG renamed to .png is refused. Accepted files are re-encoded and scaled, which strips EXIF and anything riding along. With no photo, initials are drawn on your server, coloured from the member's UID.

  • No Gravatar, so no member's email address leaves your server
  • Stored in the volume Craft's own user settings name

Craft stays in charge

Public registration, email verification and activation are Craft's settings, and Memberz reads them rather than replacing them. If the site owner has switched registration off, a registration form is refused and the refusal is logged. Changing an email or password asks for the current password first.

  • New accounts are saved pending and activated the way Craft's own registration does it
  • Works alongside Verbb Auth for social sign-in and Headcount for paid membership

Plain HTML on the front end

Craft's own user fields are drawn as plain front-end inputs, with no control-panel JavaScript on your site. There are fifteen supported field types. Anything else, Matrix included, is reported in the form builder rather than approximated as a text box that loses what the member typed.

  • No build step and no runtime dependencies
  • The optional script is only included when a template asks for it

Build it in the control panel, place it with one line

Forms and directories live in project config, so they deploy with the fields they render. Memberz routes /account and /members/<slug> for you, and a route your site already declares always wins. Everything on craft.memberz reads. Nothing in a template can save anything.

twig
{# Registration only runs when Craft itself allows it #}
{% if craft.memberz.registrationIsOpen() %}
    {{ craft.memberz.form('register') }}
{% else %}
    <p>Registration is closed at the moment.</p>
{% endif %}

{# A member directory: search, filters and sort from its own lists #}
{{ craft.memberz.directory('members') }}
{{ craft.memberz.js() }}

{# The account area and a public profile, routed for you #}
<a href="{{ craft.memberz.accountUrl() }}">Your account</a>
<a href="{{ craft.memberz.profileUrl(user) }}">
    {{ craft.memberz.avatar(user, 48) }} {{ user.fullName }}
</a>

Privacy you can't forget to check

value(), canSee() and fields() go through the same verdict as the profile page and the directory card. Craft's own accessor does not, because it knows nothing about a member's settings. Draw your own cards and the query tells you which members to list, while canSee() tells you which of their fields you may print.

twig
{# Respects the member's settings. Returns null if this visitor may not see it. #}
{{ craft.memberz.value(member, 'jobTitle') }}

{# Publishes it regardless of who is looking. #}
{{ member.jobTitle }}

{# Your own directory cards #}
{% set query = craft.memberz.members('members') %}
{% if query %}
    {% paginate query.limit(24) as pageInfo, members %}
    {% for member in members %}
        <article>
            {{ craft.memberz.avatar(member, 64) }}
            <h3>{{ member.fullName }}</h3>
            {% if craft.memberz.canSee(member, 'jobTitle') %}
                <p>{{ craft.memberz.value(member, 'jobTitle') }}</p>
            {% endif %}
        </article>
    {% endfor %}
{% endif %}

Frequently Asked Questions

Where Memberz stops, and what picks up.

A registration form, a profile form, and you're done

Free, single edition, no licence key. Build a registration form and a profile form in the control panel, visit /account, and you have a working account area. Everything after that is shaping it.