“Members only” means at least four different things, and most membership plugins pick one, hide the others behind a paywall, and never tell you which one you are buying. Getting this wrong is why so many membership sites end up either leaking content or locking out the people who paid.
So before any plugin: what are you actually restricting, and from whom?
Four levels, and they are not interchangeable
Every restriction decision on a WordPress site is one of these. Naming them properly makes the plugin choice almost automatic.
- Public. Anyone, including search engines. The default, and the right answer for more of your content than you think — a members area with nothing public has no way to attract members.
- Logged in. Any registered account. Useful for community features and almost never the right fence for paid content, because registration is free.
- Member. A registered account you have flagged as a member. This is the distinction most sites actually need, and the one WordPress has no native concept of.
- A specific tier. Gold sees this, silver does not. Only worth reaching for once you genuinely sell more than one thing.
The common mistake is conflating the middle two. If “members only” is implemented as “logged in”, then anyone who registers — free, in ten seconds — reads everything. Sites ship this and do not notice for months, because it looks correct while you are testing as an administrator.
Why WordPress roles are the wrong tool
The instinct is to use roles: make a Member role, restrict by capability, done. It works, and it becomes a problem about six months later.
Roles in WordPress describe what someone can do in the admin — edit posts, moderate comments, install plugins. Membership describes what someone can read on the front end, and that is a different axis. The moment you have a member who is also a contributor, you need someone to be two things at once, and a role-based scheme forces you to invent combinations: member-contributor, expired-member-contributor. It multiplies badly.
Keeping membership as a flag on the user, separate from their role, means a contributor can be a member, an administrator can have an expired membership for testing, and none of it interferes with what anyone can do in wp-admin.
Expiry is what turns a sale into a business
This is the part people leave until last and should design first. A membership that never expires is a one-off sale. A membership that expires is recurring revenue — and the difference is a single date field.
Two details decide whether that field behaves sanely.
Renewing early must add to the remaining time, not replace it. If someone with forty days left renews for a year, they should have four hundred and five days, not three hundred and sixty-five. Systems that overwrite the expiry date punish exactly the customers who pay early, and they generate support tickets that are painful to answer because the customer is right.
Expiry has to be evaluated on read, not on a schedule. If you rely on a nightly job to sweep expired members, then access is wrong for up to a day every time, and it is wrong in the direction that gives away content. Checking “is this person's expiry in the future?” at the moment they request the page is both simpler and always correct.
function user_is_member( $user_id ) {
if ( ! get_user_meta( $user_id, '_is_member', true ) ) {
return false;
}
$expires = (int) get_user_meta( $user_id, '_member_expires', true );
// 0 means lifetime — deliberately not "expired in 1970"
return 0 === $expires || $expires > time();
}
Note the zero case. Representing lifetime access as an empty or zero timestamp is fine, but only if you handle it explicitly — otherwise every lifetime member silently expires on the first of January 1970.
What should happen when a membership lapses
This is the design question that separates plugins that feel considered from plugins that feel hostile, and almost nobody asks it before launching.
When someone's membership runs out, their content should become unavailable — that is the point. What should not happen is anything destructive. Do not delete their account, strip their role, remove their comments, or discard the profile they filled in. They are not gone; they are lapsed, and a lapsed member is the single easiest person to sell to.
The same restraint applies to your own licence checks. If the paid component that manages expiry is disabled or its licence lapses, the sane behaviour is for existing members to keep their access rather than for the whole site to lock out everyone who paid you. Fail towards letting people in, and let the failure be visible to you in the admin rather than to them on the front end.
Do not restrict everything
A practical note that is worth more than any implementation detail: a members area where nothing is public cannot grow. Search engines index nothing, nobody can evaluate whether it is worth paying for, and your only acquisition channel is people who already trust you.
The pattern that works is a genuinely useful public layer — enough that someone can judge the quality — with the depth behind the fence. Restricted content should also degrade into a real page with a real explanation and a join link, not a redirect to a login screen. A redirect tells a visitor they did something wrong. A message tells them what exists and how to get it.
A plugin that keeps the essentials free
Membership & Content Restriction does the four levels above from a box in the post editor, with front-end registration, login and a members directory, and no cap on free members. Membership Pro adds paid plans through your own WooCommerce, expiry that behaves the way described here — early renewal adds time — and tiers. The download includes both.
The order to build it in
If you are starting now: get the public and member split right first, with no payment involved at all. Invite a handful of people, flag them as members by hand, and check that the fence holds when you view the site logged out and logged in as a plain subscriber.
Only then add money. Payment is the easy part — it is a WooCommerce product and a hook — and adding it to a restriction model you have already proven is far less painful than debugging both at once. Tiers come last, if ever. Plenty of profitable membership sites sell exactly one thing.
Building a members area and want the architecture sane from the start? Get in touch.
