Build your own member experiences
Read a reader's membership status from your theme or plugin, with PHP, CSS classes or JavaScript, to build your own gates, member-only sections and member styling.
On this page
Choosing a method
Allspice handles sign-in, billing and deciding who is a member. Everything on this page lets your own code read that decision and act on it. Allspice's own gates keep working alongside anything you build.
| Method | Use it for | Safe for paid content? | Updates without a reload? |
|---|---|---|---|
| PHP functions | Hiding or showing content | Yes. Non-members never receive the content. | No. It applies on the next page load. |
| CSS classes | Styling and simple show/hide | No. The content is still in the page. | Yes |
| JavaScript | Interactive gates and widgets | No. It runs in the browser. | Yes |
Protect anything people pay for in PHP. Use CSS and JavaScript for presentation, such as teasers, badges, or switching a "Join" button to "Welcome back".
The CSS classes, the gate design filter and the WordPress actions need Allspice plugin 1.6.01.8 or later, and allspice_membership_ui_visible() needs 1.6.01.6 or later. Everything else on this page works on any 1.6.01 version.
Benefit IDs
A member's access is described as a list of benefits. You pass these IDs to every check on this page:
| ID | Meaning |
|---|---|
adFree | Ad-free browsing |
recipes | Members-only recipes |
articles | Exclusive articles |
pages | Member resources and pages |
mealPlans | Meal plans |
| Custom benefits | Each custom benefit you add to your membership has its own ID, for example benefit_1729543210. Contact us for the ID of any custom benefit you want to check. |
IDs are case-sensitive: mealPlans, not mealplans. A member only has the benefits included in your membership; see Site memberships.
PHP functions
These functions are available to themes and plugins whenever the Allspice plugin is active. Check that they exist before calling them, so your site keeps working if the plugin is ever deactivated.
// Does the current visitor have this benefit?
allspice_member_has_benefit('articles'); // true or false
// Full access details, or null for a non-member
allspice_get_member_access();
// [
// 'products' => ['<your membership id>'],
// 'benefits' => ['articles', 'adFree', ...],
// 'expires_at' => 1761264000, // when the current session stamp expires (Unix time)
// ]
// Shortcut for ad-free members
allspice_member_is_ad_free();
// Does the member have a specific membership product?
allspice_member_has_product('<product id>');
allspice_member_has_any_product(['<product id>', '<another product id>']);
Prefer benefit checks where you can. They keep working when you change or add membership plans, while product checks name one plan. The product IDs a member holds are listed in allspice_get_member_access().
Show your own membership buttons only after launch
Join buttons, a Members menu item or a header promo that you add to your theme should stay hidden until your membership is live. allspice_membership_ui_visible() answers that for you:
- Membership published in the Allspice portal: visible to everyone.
- Not yet published, with Membership testing turned on in the Allspice plugin settings: visible to site administrators only, so you can check your work on the real site.
- Otherwise: hidden from everyone.
<?php if (function_exists('allspice_membership_ui_visible') && allspice_membership_ui_visible()) : ?>
<a href="#allspice-membership" class="my-join-button">Become a member</a>
<?php endif; ?>
Where PHP isn’t practical, such as a page builder or a menu item, add the class allspice-membership-ui to the element instead. It stays hidden until the same switch turns on. The page’s <body> gets allspice-membership-ui-on while the switch is on, plus allspice-membership-ui-preview while only administrators can see it.
Example: a member-only section in a template
<?php if (function_exists('allspice_member_has_benefit') && allspice_member_has_benefit('articles')) : ?>
<section class="members-only">
<?php the_field('members_section'); ?>
</section>
<?php else : ?>
<aside class="my-gate">
<h3>This part is for members</h3>
<a href="#allspice-membership">Join</a>
<a href="#allspice-login">Already a member? Log in</a>
</aside>
<?php endif; ?>
Example: members-only blocks in the block editor
Allspice gates a recipe card or a whole post. To make part of a post members-only, your theme can check membership as WordPress renders each block. This works for any block, including blocks from other plugins:
- In the editor, put the members-only blocks inside a Group block.
- In the Group’s Advanced settings, add
members-onlyunder Additional CSS class(es). - Add this to your theme or a small plugin:
add_filter('render_block', function ($html, $block) {
$classes = preg_split('/\s+/', (string) ($block['attrs']['className'] ?? ''));
if (!in_array('members-only', $classes, true)) {
return $html;
}
if (function_exists('allspice_member_has_benefit') && allspice_member_has_benefit('articles')) {
return $html;
}
return '<div class="my-gate">This section is for members. '
. '<a href="#allspice-membership">Join</a> or <a href="#allspice-login">log in</a>.</div>';
}, 10, 2);
- Non-members receive the teaser in place of the whole group, so the content never reaches their browser. That also covers RSS feeds and the WordPress REST API.
- The rest of the post stays public, and search engines index what non-members see, so nothing extra is needed for SEO.
- If the Allspice plugin is ever deactivated, the check fails closed and the section stays hidden.
- To gate different sections by different benefits, use more class names, for example
members-only-forumchecked against your custom benefit’s ID.
Example: a shortcode for the classic editor
On sites using the classic editor, a shortcode lets editors wrap any part of a post.
add_shortcode('members_only', function ($atts, $content = '') {
$atts = shortcode_atts(['benefit' => 'articles'], $atts);
if (function_exists('allspice_member_has_benefit') && allspice_member_has_benefit($atts['benefit'])) {
return do_shortcode($content);
}
return '<div class="my-gate">This section is for members. '
. '<a href="#allspice-membership">Join</a> or <a href="#allspice-login">log in</a>.</div>';
});
// In a post:
// [members_only benefit="articles"] ...exclusive content... [/members_only]
Member pages are never served from a shared page cache, so a member never sees a cached non-member page and the reverse never happens either, as long as your caching is set up. See Caching.
CSS classes
Every page shown to an active member carries these classes on <body>:
allspice-memberfor any active memberallspice-benefit-{id}for each of their benefits, for exampleallspice-benefit-articlesorallspice-benefit-mealPlans
/* Teaser for everyone, full panel for members */
.member-panel { display: none; }
body.allspice-member .member-panel { display: block; }
body.allspice-member .join-teaser { display: none; }
/* Only for members with the meal plans benefit */
body:not(.allspice-benefit-mealPlans) .meal-plan-tools { display: none; }
The classes stay current without a reload: they're added the moment a reader signs in or joins, removed when they sign out, and applied even when a page is served from an edge cache.
CSS only hides content; it's still in the page source. Don't rely on it alone for anything people pay for.
You may also see allspice-paid-member and allspice-ad-free-member. Those mark ad-free members only (see Ad-free members). Use allspice-member when you mean "is a member".
JavaScript
Read the current status
const res = await fetch('/wp-json/allspice/v1/member-session', { credentials: 'same-origin' });
const status = await res.json();
// Member: { active: true, products: [...], benefits: ['articles', ...], expires_at: 1761264000, config_version: '...' }
// Non-member: { active: false, config_version: '...' }
The response is specific to the visitor and is never cached.
React to sign-in, joining and sign-out
function showGate(isMember) {
document.querySelectorAll('.my-gate').forEach((el) => { el.hidden = isMember; });
}
function refreshMyGate() {
fetch('/wp-json/allspice/v1/member-session', { credentials: 'same-origin' })
.then((r) => r.json())
.then((s) => showGate(s.active === true));
}
// After a sign-in or join has been verified and the member session is in place
// (event.detail = { active: true | false, reason })
window.addEventListener('allspice:member-session-synced', refreshMyGate);
// When the reader signs out: treat them as a non-member straight away
window.addEventListener('allspice:logout', () => showGate(false));
refreshMyGate();
Listen for allspice:member-session-synced, not allspice:login. The login event fires as the reader signs in, before their membership is confirmed, so checking status at that moment can still read "not a member". On sign-out, the member session is cleared at the same moment the event fires, so don't check status then; treat the reader as signed out.
Join, sign-in and sign-out links
Use these as the href on any link or button in your own gate or menus. The plugin handles them in place, with no script needed on your side.
| Link | Opens |
|---|---|
#allspice-membership | Signup and pricing |
#allspice-login | Sign-in for an existing member |
#allspice-account | The member's own account and billing screen |
#allspice-logout | Signs the reader out (nothing opens). Use it for a Sign out item in your own account menu. |
<a href="#allspice-membership" class="my-join-button">Become a member</a>
The full list of links is in Blocks & shortcodes.
Use your own gate design
To keep using Allspice gating (which posts and recipes are gated is still set in your membership settings) but show your own design, replace the gate box with the allspice_gate_html filter. Allspice keeps deciding when to gate, keeps the search-engine markup, and still unlocks the page the moment a reader signs in.
add_filter('allspice_gate_html', function ($html, $gate) {
// $gate['gate_type'] is 'recipe_card', 'content_preview' or 'content_immediate'
$join = $gate['signups_open']
? '<a class="my-gate__join" href="' . esc_attr($gate['join_href']) . '">' . esc_html($gate['join_label']) . '</a>'
: '';
return '<div class="my-gate">'
. '<h3>' . esc_html($gate['title']) . '</h3>'
. '<p>' . esc_html($gate['copy']) . '</p>'
. $join
. '<a class="my-gate__login" href="' . esc_attr($gate['login_href']) . '">' . esc_html($gate['login_label']) . '</a>'
. '</div>';
}, 10, 2);
Your function receives the default markup and details about the gate:
| Key | Value |
|---|---|
gate_type | recipe_card, content_preview or content_immediate |
post_id, recipe_id | The gated post, and the recipe for recipe-card gates |
title, copy, join_label, login_label | The gate wording from your membership settings |
signups_open | false when new signups are paused; leave out the Join button then |
benefits | Your membership’s benefits, each with id, title and description |
join_href, login_href | The links that open signup and sign-in |
- Return
$htmlunchanged to keep the standard design, for example for one gate type only. - Your markup sits inside an Allspice wrapper that draws no styling of its own when you replace the box, so your CSS is in full control.
- Allspice adds a small status line after your markup (for “Checking your membership” and a retry link) unless your markup already includes an element with
data-allspice-gate-status.
Adjust Allspice’s gates
These filters change how Allspice’s own gates behave, without replacing them:
| Filter | Default | What it changes |
|---|---|---|
allspice_content_gate_excluded | false | Return true to leave a post out of Allspice gating entirely, for example pages you gate with your own code. Receives $excluded, $post_id and $url_key. |
allspice_content_gate_mode | overlay | remove leaves gated content out of the page entirely instead of covering it. See Gating & SEO for when to use each. |
allspice_content_preview_word_limit | 55 | How many words a preview gate shows before the gate. Receives $limit and the post. |
allspice_content_members_only_text | “This content is for members.” | The text that replaces gated content in RSS feeds, excerpts and the WordPress REST API. |
allspice_gate_benefits_limit | 5 | How many benefits a gate lists. 0 lists them all. |
allspice_membership_closed_signups_message | Your membership settings | The message shown while new signups are paused. |
allspice_gate_fallback_policy | open | What happens when a recipe-card gate can’t be placed, for example with an unsupported recipe plugin. open leaves the recipe visible; closed gates the whole post instead. |
For example, to keep Allspice from gating forum pages that your forum plugin protects itself:
add_filter('allspice_content_gate_excluded', function ($excluded, $post_id) {
return $excluded || in_array(get_post_type($post_id), ['forum', 'topic', 'reply'], true);
}, 10, 2);
A post you exclude is no longer covered by Allspice’s search-engine handling, so follow Search engines and paywalls for anything you gate yourself.
Lock badges
When lock badges are turned on in your membership settings, Allspice adds a small “Members” badge to the featured image of every post gated in full (not recipe-card gates) wherever your theme lists it, such as archives, search results and related posts. Members still see it, so premium posts stay recognizable. The badge is added through WordPress’s standard featured-image functions, so a theme that builds its card images another way won’t show it. The label and color come from your membership settings, and these filters adjust the rest:
add_filter('allspice_lock_badge_enabled', '__return_false'); // turn the badge off
add_filter('allspice_lock_badge_label', fn() => 'Members only'); // change the wording
add_filter('allspice_lock_badge_position', fn() => 'bottom-right'); // or 'top-right' (default)
add_filter('allspice_lock_badge_class', fn() => 'my-lock-badge'); // add your own class for styling
WordPress actions
Run your own PHP when a member session starts, renews or ends:
add_action('allspice_member_session_set', function ($access, $is_new) {
// $access: ['products' => [...], 'benefits' => [...], 'expires_at' => 1761264000]
if ($is_new) {
// A member just signed in or joined in this browser
}
}, 10, 2);
add_action('allspice_member_session_cleared', function ($reason) {
// $reason: 'signed_out', or 'not_a_member' (their membership has ended)
});
- These run during the background request the page makes after a sign-in, join, renewal or sign-out, not while a page is being rendered, so don’t print output from them.
$is_newisfalsefor the automatic renewal that keeps an active member signed in (about once a day).- No personal details are included:
$accessdescribes the membership, not the reader.
WordPress accounts for members
Some WordPress plugins, such as forums, need members to be logged-in WordPress users. For those sites, Allspice can give every member a WordPress user account and log them into it. It’s off by default and not recommended unless you need it: your site then stores those accounts and their email addresses.
Turn it on per site in the Allspice portal under Memberships → Domains → WordPress accounts for members. It needs Allspice plugin 1.6.01.9 or later.
What each member gets
- A WordPress user with their email address, their name as the display name, and the Member (Allspice) role (
allspice_member). The username is a randommember-handle, so nothing from their email address appears in forum profile links. A member who already has a WordPress account with the same, verified email address is linked to it instead. - Their Allspice user ID, stored in the user meta
allspice_uid. - A WordPress login whenever they sign in through Allspice on your site. Logins last two days and renew automatically while the member stays signed in to Allspice.
// Is the logged-in WordPress user a current Allspice member?
$user = wp_get_current_user();
$is_member = in_array('allspice_member', (array) $user->roles, true);
// Their Allspice user ID
$allspice_uid = get_user_meta($user->ID, 'allspice_uid', true);
// Runs when Allspice logs a member into WordPress
add_action('allspice_wp_member_logged_in', function ($user_id, $is_new_user) {
// $is_new_user is true the first time the account is created
}, 10, 2);
In your forum plugin’s settings, give the Member (Allspice) role access to the members-only areas.
How it stays in step
- Membership ends: the member loses the
allspice_memberrole and is logged out of WordPress on every device the next time Allspice checks their membership on your site, which happens at least once a day while they browse. - Signing out of Allspice also logs them out of WordPress. The role is kept.
- Email changes in Allspice are copied to WordPress when the new address is verified and no other WordPress user has it.
- It’s one-way. Allspice handles sign-in and billing, and a WordPress login never signs anyone into Allspice.
Safeguards
- Allspice never logs anyone into an account that can create or manage content, users, plugins, your theme or a shop, including custom roles with any of those abilities, and never links a member to one, even if the email addresses match.
- If the browser is already logged into WordPress as someone else, such as you testing the site, Allspice leaves that login alone.
- Accounts Allspice creates can only sign in through Allspice: WordPress password logins, “Lost your password?” resets and application passwords are turned off for them, so a lapsed member can’t keep access by setting a password. Accounts that existed before and were linked keep their own password.
- Allspice sends no WordPress emails for these accounts. Other plugins that act on new users, such as welcome emails or CRM syncs, will still see them.
- Turning the setting off stops new accounts and logins. Accounts already created stay in WordPress, and members whose membership ends still lose the role.
Search engines and paywalls
Search engines need to understand gated content, or a page that shows them more than it shows readers can be treated as cloaking.
- Gated with Allspice, including with your own design through
allspice_gate_html: handled for you. - Your own PHP gate that leaves member content out of the page for non-members: nothing extra is needed. Search engines index what non-members see.
- Member content that is in the page but hidden with CSS or JavaScript: mark it as paywalled so search engines know why readers can’t see it.
<div class="my-members-only">
...member content...
</div>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"isAccessibleForFree": false,
"hasPart": {
"@type": "WebPageElement",
"isAccessibleForFree": false,
"cssSelector": ".my-members-only"
}
}
</script>
If an SEO plugin already outputs Article structured data for the page, add isAccessibleForFree and hasPart to that instead of adding a second block. See Gating & SEO for how Allspice’s own gates handle search engines.
Caching
Member status travels in a cookie named allspice_member_session. Every caching layer on your site must skip the cache when a request carries it. Otherwise members can be shown the cached public version of a page, and your PHP checks never run for them.
- WP Rocket is configured for you by the plugin.
- Other cache plugins, CDNs such as Cloudflare, and managed hosts need the cookie added to their bypass list.
Step-by-step settings for each are in Memberships & Page Caching. CSS classes and JavaScript still update correctly on a cached page; PHP-gated content won't until the cache is bypassed.
Sessions
- A member stays signed in to Allspice until they sign out.
- The WordPress-side session stamp (the
allspice_member_sessioncookie) lasts up to 24 hours and renews automatically while the reader browses, so an active member isn't shown as signed out. - Signing out of Allspice clears it immediately.
The function names, CSS classes, REST endpoint, events and links on this page are a supported interface. We won't rename or remove them without notice.