Visibility and Access Matrix
Jetonomy 1.4.1 introduced the Public / Private community toggle documented in Access Control Settings. On the code side that toggle is enforced through two pieces:
- A small helper class -
Jetonomy\Visibility- that every front-end template and REST permission callback can call to decide "is this caller allowed to see community content right now?" - A shell script -
bin/access-matrix-check.sh- that walks every public REST route as every role in both modes and asserts the responses match the documented contract.
This page covers both.
Namespace: Jetonomy\
**Source:** includes/class-visibility.php, bin/access-matrix-check.sh
Why the helper exists
Before 1.4.1 the public/private check was sprinkled across templates, the template loader, and individual REST controllers. Each call site had its own "is the community private and the user a guest?" expression, and any new endpoint had to remember to repeat the pattern. The fastest way to ship a leak was to forget the check.
Jetonomy\Visibility consolidates that into one read of jetonomy_settings.guest_read. The front-end template loader and every public-read REST endpoint route through the same helper, so they answer the same question with the same logic. New endpoints opt into the gate with a single line.
The helper deliberately does not look at per-resource visibility (private spaces, blocked users, restricted posts). Those remain the responsibility of individual controllers - Visibility only answers the global "can this caller see ANY community content right now?" question.
API Reference
Visibility::can_view_community()
Returns true if the current request should be allowed to see community content, false otherwise. In public mode this is always true. In private mode it requires the caller to be authenticated.
Returns: bool
Example - gating a custom template fragment:
add_action( 'jetonomy_sidebar_before', function () {
if ( ! \Jetonomy\Visibility::can_view_community() ) {
return;
}
echo do_shortcode( '[my_member_only_widget]' );
} );
The check is global, not per-resource - you do not need to pass a user ID or a post ID. Per-resource visibility (private spaces, restricted access rules) is enforced separately inside the relevant controllers.
Visibility::get_mode()
Returns the active visibility mode as a string. Useful when you want to render a different UI in private mode (e.g. a "Members only" badge in the site header) without duplicating the option read.
Returns: string - 'public' or 'private'
Example - tagging the body class:
add_filter( 'body_class', function ( array $classes ): array {
$classes[] = 'jt-mode-' . \Jetonomy\Visibility::get_mode();
return $classes;
} );
The function defaults to 'public' on a fresh install - an unset, null, or true value of guest_read all resolve to public. Only an explicit false flips the community to private.
Visibility::rest_check()
Designed to be used as a REST permission_callback. Returns true when the caller may proceed, or a 401 WP_Error with code community_private when the community is in private mode and the caller is not logged in.
Returns: true|\WP_Error
Example - protecting your own REST route:
register_rest_route( 'my-plugin/v1', '/community-events', [
'methods' => 'GET',
'callback' => 'my_plugin_list_events',
'permission_callback' => [ '\Jetonomy\Visibility', 'rest_check' ],
] );
Example - chaining with an existing capability check:
'permission_callback' => static function ( $request ) {
$vis = \Jetonomy\Visibility::rest_check( $request );
if ( is_wp_error( $vis ) ) {
return $vis;
}
return current_user_can( 'read' );
},
Anonymous calls in private mode return:
{
"code": "community_private",
"message": "This community is private. Please log in to view content.",
"data": { "status": 401 }
}
Authenticated calls fall through to your route's own permission logic.
Note:
/auth/*and/admin/*endpoints intentionally do not route through this helper. Locking/auth/*would lock users out forever, and admin endpoints have their own capability gates. ApplyVisibility::rest_checkto public-read endpoints only.
The Access Matrix Runner
bin/access-matrix-check.sh is the regression safety net that proves the helper actually works. It walks a representative subset of every Jetonomy REST route as every role, makes the real HTTP call, and asserts the response code matches the documented expectation.
What it covers
- 78 checks across the public REST surface
- 6 roles - anonymous, subscriber, author, editor (space-admin), moderator, administrator
- Both modes - the runner can flip
jetonomy_settings.guest_readto private for the duration of the run and restore it on exit (even if a check fails midway)
In public mode the runner asserts that anonymous reads return 200. In private mode it asserts the same anonymous reads return 401 from the central Visibility::rest_check gate. Logged-in calls are mode-independent and stay unchanged in either mode.
Running it locally
# From the plugin root:
bin/access-matrix-check.sh # public mode (default)
bin/access-matrix-check.sh --mode=private # private community gate
bin/access-matrix-check.sh --quiet # only show failures
Sample output:
PASS GET /spaces [anon] expected=200 got=200
PASS GET /spaces [subscriber] expected=200 got=200
PASS POST /posts/123/vote [anon] expected=401 got=401
FAIL GET /posts/recent [anon] expected=401 got=200 <- regression
Summary: 77 passed, 1 failed (78 total)
A regression is any row where the actual response code does not match the documented expectation. Exit code is 0 on a clean run, 1 if any row fails.
Release gating
bin/build-release.sh invokes the access matrix runner before producing the release zip. If any row regresses, the build aborts and no zip is produced - the gate exists so we never ship a release that quietly opens up a previously-locked endpoint or quietly locks a previously-open one.
Run the matrix locally before every commit that touches permission_callback wiring, the Visibility helper, or REST route registration.
What's Next?
- Hooks Reference - All
jetonomy_*actions and filters - REST API Reference - Full endpoint listing with permission contracts
- Modal Toolkit - Front-end
jetonomyConfirm/jetonomyAlert/jetonomyPromptAPI