Wbcom Designs Jetonomy Docs
Back to product Buy Now

Getting Started

Install, configure, and launch your community in minutes.

Feature Overview

Everything Jetonomy does, on one page. This is the fastest way to see whether Jetonomy fits your community - it groups every feature by what it actually does for you, links straight to the deep-dive guide for each area, and marks which features are free and which are Jetonomy Pro.

The Jetonomy community home page showing categories, spaces, and recent activity

How to Use This Page

Each section below is a job your community needs done - publishing discussions, organizing them, keeping them clean, recognizing contributors, and so on. Read the benefit, scan what is included, then follow the links to the full guide for anything you want to set up.

Features marked Pro require Jetonomy Pro. Everything else ships in the free plugin.

Content & Discussions

This is the heart of Jetonomy: a fast, modern composer and a reply system built for threads with hundreds of contributions. Members write clear topics, the best answers float to the top, and nobody loses a half-finished post.

What is included:

  • Topics - the primary unit of discussion, with a Markdown composer, inline image upload, tags, similar-topic detection, and topic prefixes. See Creating Topics.
  • Replies and threading - threaded conversations, multiple sort orders, and efficient loading for long threads. See Replies & Threading.
  • Voting - upvote and downvote on posts and replies so the most useful content rises naturally. See Voting.
  • Accepted answers - mark the reply that solved a question in Q&A spaces. See Replies & Threading.
  • Drafts and scheduling - save work in progress and publish now or at a future date. See Drafts & Scheduling.

Pro adds:

  • Polls - attach a single or multi-select poll to any topic for decisions and feedback. See Polls.
  • Reactions - emoji reactions on posts and replies so members can respond without writing a full reply. See Reactions.

Spaces & Organization

Spaces are how you keep a large community navigable. Group them into categories, pick the right space type for each purpose, and control exactly who can join. The right structure makes your community feel purpose-built instead of generic.

What is included:

  • Categories and spaces - top-level categories that group focused discussion spaces. See Creating Spaces.
  • Four space types - Forum, Q&A, Ideas, and Feed, each changing how posts and replies behave. See Space Types.
  • Membership and join policies - public, private, or hidden visibility paired with open, approval-required, or invite-only join rules. See Membership & Join Policies.
  • Invites - invite-link landing pages so the right people get in without manual setup. See Membership & Join Policies.

Pro adds:

  • Custom Fields - structured fields on posts, member profiles, and spaces so you collect exactly the information your community needs. See Custom Fields.

Moderation & Trust

Jetonomy keeps quality high without a moderator watching every post. Trust grows automatically with good participation, members flag problems, and one queue handles everything that needs human review.

What is included:

  • Trust levels 0 to 5 - members earn higher trust and unlock capabilities automatically as they contribute. See Trust Levels.
  • Flagging and reporting - any logged-in member can report content that breaks your rules. See Flagging & Reporting.
  • Moderation queue - a single dashboard for posts awaiting approval, flagged content, and spam-caught items. See Moderation Queue.
  • Anti-spam - multiple silent layers of spam protection that real members never notice. See Anti-Spam.
  • Banning - remove and block disruptive members from your community. See Trust Levels.
  • Pinning and announcements - keep important topics at the top of a space. See Topic Management.

Pro adds:

  • Advanced Moderation - rules that catch bad content automatically before it ever appears. See Advanced Moderation.
  • Site Announcements - feature one post at the top of every space across the whole community. See Site Announcements.

Members & Gamification

Recognition keeps people coming back. Every member gets a public profile, reputation built from real contributions, and a place on the leaderboard worth competing for.

What is included:

  • Member profiles - a public page showing who a member is and what they have contributed. See User Profiles.
  • Reputation - a contribution score that powers trust levels and rankings. See User Profiles.
  • Leaderboard - public recognition for your top contributors. See Leaderboard.

Pro adds:

  • Custom Badges - design your own badges and the conditions members earn them by. See Custom Badges.

Search & Discovery

Members can only engage with content they can find. Full-text search and cross-space tags make every discussion discoverable the moment it is published.

What is included:

  • Full-text search - fast search across topics and replies with filters. See Search & Filters.
  • Tags - connect related discussions across every space from a single tag page. See Tags.

Pro adds:

  • SEO Pro - per-space meta titles, Open Graph images, Twitter Cards, schema markup, and sitemap rules. See SEO Pro.

Notifications & Messaging

Jetonomy brings members back when something relevant happens. Every event has an in-app notification and an email, and Pro adds direct messaging plus the channels members actually check.

What is included:

  • In-app notifications - real-time alerts for replies, mentions, votes, and more. See Notifications.
  • Email notifications - an email for every event type, with per-member control over what is delivered. See Email Settings.

Pro adds:

  • Private Messaging - one-on-one and small-group direct messages without leaving your community. See Private Messaging.
  • Email Digest - a curated daily or weekly summary of community activity. See Email Digest.
  • Web Push - browser push notifications that reach members even after they close your site. See Web Push.
  • Reply by Email - members reply to discussions straight from their email client. See Reply by Email.

Admin & Branding

Run the whole community from a clean WordPress admin. Every setting has a home, every action is logged, and Pro lets you present the community as entirely your own.

What is included:

  • Settings - configure general behavior, permissions, email, appearance, SEO, anti-spam, and access control. See General Settings.
  • Admin pages - manage spaces, categories, content, and users from the dashboard. See General Settings.
  • Activity log - a read-only, filterable audit trail of every important event. See Activity Log.

Pro adds:

  • White Label - remove all Jetonomy branding and present the community as your own product. See White Label.

Analytics & Integrations

See what your community is doing and connect it to the tools you already run. Jetonomy integrates with the major membership, commerce, learning, and community plugins so access follows enrollment automatically.

Pro adds:

  • Analytics - a single dashboard for growth, engagement, and your most active members. See Analytics.
  • Webhooks - send community events to Slack, Zapier, your CRM, or any custom pipeline. See Webhooks.

Integrations included:

  • MemberPress - gate spaces by membership level. See MemberPress.
  • Paid Memberships Pro - gate spaces by PMPro level. See Paid Memberships Pro.
  • WooCommerce - unlock spaces on product purchase or active subscription. See WooCommerce.
  • LearnDash - pair course and group enrollment with discussion spaces. See LearnDash.
  • Tutor LMS - pair course enrollment with discussion spaces. See Tutor LMS.
  • BuddyPress - make groups and forum spaces feel like one membership. See BuddyPress.
  • FluentCommunity - run the social feed and the forum as one product. See FluentCommunity.

Developer Platform

Jetonomy is built to be extended. Everything members can do is reachable through a documented REST API, hooks, WP-CLI, blocks, and shortcodes - so you can automate, embed, and customize without touching core.

What is included:

  • REST API - 48+ free endpoints under jetonomy/v1, 90+ with Pro active. See REST API.
  • Hooks - 58 free hooks plus 9 in Pro for actions and filters. See Hooks Reference.
  • WP-CLI - 14 free command roots and 15 in Pro for headless automation. See WP-CLI.
  • Blocks and shortcodes - eight Gutenberg blocks, four classic widgets, and eight shortcodes to embed community content anywhere. The four widgets are Recent Posts, Leaderboard, Active Spaces, and User Stats (Active Spaces and User Stats are reachable only through the [jetonomy_widget] shortcode). Most surfaces are available as both a block and a shortcode, with three exceptions each way: Navigation, Login, and User Panel are block-only, while [jetonomy_user_profile], [jetonomy_space_members], and [jetonomy_widget] are shortcode-only. See Shortcodes, Widgets & Blocks.

Pro adds:

  • AI - bring large language models into spam detection, auto-moderation, reply suggestions, and thread summaries, with self-hosted options. See AI.

What's Next?

Ready to set it up? Start with installation, then run the setup wizard to go live.

Installation

Get Jetonomy running on your WordPress site in under five minutes. This guide covers system requirements, how to install, and what happens the moment you activate.

Jetonomy setup wizard guiding you through initial configuration

What You Will Learn

  • Whether your server meets the requirements
  • Three ways to install Jetonomy
  • What Jetonomy sets up automatically on first activation

See it running first - community.wbcomdesigns.com is Wbcom's own support community, running Jetonomy in production. Browse the spaces, read the threads, and see how topics, replies, voting, trust levels, and moderation feel on a live site before you install. Public registration is open, so you can sign up and ask a question there if you have one.

Requirements

Jetonomy requires a modern WordPress stack. Check these before installing.

Requirement Minimum
WordPress 6.7 or higher
PHP 8.1 or higher
MySQL 5.7 or higher (or MariaDB 10.4+)
Browser Any modern browser (Chrome, Firefox, Safari, Edge)

Jetonomy works with any WordPress theme. For the best visual result with zero extra configuration, use BuddyX.

Note: Jetonomy does not use WordPress custom post types. It stores all community data in its own optimized database tables (wp_jt_*). This is intentional - it gives your community the query performance and scalability that CPT-based plugins cannot match.

Installation

  1. Go to Plugins → Add New Plugin in your WordPress admin.
  2. Search for Jetonomy.
  3. Click Install Now, then Activate.

Method 2: Upload a ZIP File

  1. Download the Jetonomy ZIP from jetonomy.com or wordpress.org.
  2. Go to Plugins → Add New Plugin → Upload Plugin.
  3. Choose the ZIP file and click Install Now, then Activate.

Method 3: WP-CLI

wp plugin install jetonomy --activate

What Happens on Activation

Jetonomy sets everything up automatically the first time you activate it. You do not need to run any SQL or configure anything manually.

Database tables created:

Jetonomy creates its own set of custom tables under the wp_jt_ prefix - one for each data entity: categories, spaces, posts, replies, votes, user profiles, notifications, subscriptions, tags, moderation flags, revisions, invite links, bookmarks, and more. It does not use WordPress custom post types.

WordPress capabilities registered:

Jetonomy registers its own custom capabilities (jetonomy_read, jetonomy_create_posts, jetonomy_moderate, and others) and maps them to your existing WordPress roles automatically.

Permalink rules flushed:

Your community URLs (e.g. yoursite.com/community/) are registered and rewrite rules are flushed immediately. No manual permalink reset needed.

URL Note: Throughout this documentation, /community/ is used as the default base URL. You can change this to any slug (e.g. /forum/, /discuss/, /hub/) in Jetonomy → Settings → General → Community Base URL. All community URLs automatically update when you change the base slug.

Cron jobs scheduled:

Six background jobs are scheduled via WP-Cron:

  • Trust level evaluation - promotes members who have earned higher trust levels.
  • Expired restriction cleanup - lifts temporary restrictions once they expire.
  • Activity log pruning - trims old activity-log rows to keep the table lean.
  • Notification cleanup - removes stale read notifications.
  • Scheduled post publishing - publishes posts queued for a future date.
  • Verification reminders - nudges members who have not completed verification.

After activation, you will see a blue notice at the top of your dashboard:

Your community is almost ready. Run the setup wizard to get started.

Click that notice to launch the setup wizard and go live.

Tip: If you are migrating from bbPress, wpForo, or Asgaros Forum, activate Jetonomy first to complete setup, then use the importer at Jetonomy → Import. Your existing data is never touched until you explicitly start an import.

WordPress Multisite

Jetonomy is multisite-compatible. When you network-activate the plugin from Network Admin → Plugins, Jetonomy automatically creates all required wp_jt_* database tables on every existing subsite in the network.

New subsites created after network activation are also provisioned automatically. The moment WordPress adds a new subsite to the network, Jetonomy detects it and creates the required tables before any community activity can occur.

Note: Each subsite has its own independent set of wp_{blog_id}_jt_* tables and its own community data. Spaces, posts, and members are not shared across subsites.

If you prefer per-site activation rather than network activation, install and activate Jetonomy on each subsite individually. Both approaches work correctly.

Uninstalling

If you deactivate Jetonomy, your data is preserved. Only a full uninstall (delete) removes the wp_jt_* tables, all plugin options, and all registered capabilities, giving you a clean removal with no database debris. Jetonomy Pro behaves the same way: uninstalling it removes every wp_jt_pro_* table, its options and user meta, and its scheduled tasks (fully covered as of 1.5.0).

What's Next?

Run the three-step setup wizard to choose your community URL, create your first space, and go live.

Run the Setup Wizard →

Setup Wizard

After you activate Jetonomy, a three-step wizard walks you through the only decisions you need to make before your community goes live. The whole process takes about two minutes.

Jetonomy setup wizard with step-by-step configuration

What You Will Learn

  • How to set your community URL slug
  • How to choose between creating your first space manually or loading demo data
  • What the wizard does, and what you can always change later

Opening the Wizard

Click the blue notice at the top of your WordPress dashboard, or go to Jetonomy → Dashboard and click Launch Setup Wizard.

The wizard runs in a full-screen overlay. You can close it at any time. Your progress is saved, and you can return to finish it later.

Step 1: Community URL

Setup wizard Step 1: the community URL slug field with a default-space-type selector below it

Choose the slug where your community will live on your site.

The default is community, which gives you yoursite.com/community/. You can change this to anything that fits your site: forum, hub, members, discuss, or your brand name.

Example slug Resulting URL
community yoursite.com/community/
forum yoursite.com/forum/
hub yoursite.com/hub/

Default space type: Also on this screen, choose the default type for new spaces you create. Your options are:

  • Forum - open-ended threaded discussion
  • Q&A - questions with votable answers; the best answer can be marked accepted
  • Ideas - feature requests and votes with a status-lane roadmap
  • Feed - short-form cards for status updates, introductions, and sharing work

You can create spaces of any type regardless of what you choose here. This setting just controls the default when you click "Add Space" later.

Tip: You can change your community URL slug later in Jetonomy → Settings → General. Jetonomy automatically flushes permalink rules when you save.

Make the community your homepage: Under Jetonomy → Settings → General → Community Setup, enable Show the community home on the site front page to serve the community home at your site root. This takes precedence over the WordPress "Your homepage displays" setting, and all other community URLs, posts, and feeds keep working unchanged.

Step 2: First Space

Setup wizard Step 2: the choice between Path A (create your first space) and Path B (load sample data)

This step gets real content into your community so it is ready to share the moment you finish. Choose the path that fits where you are right now.

Path A: Create Your First Space

Choose this if you are setting up a production site and want to start with your own content.

  1. Enter a name for your first space (e.g., "General Discussion").
  2. The space uses the default type you picked in Step 1 (Forum, Q&A, Ideas, or Feed). You can change a space's type any time under Jetonomy → Spaces → Edit.
  3. Click Create Space.

Your space is created and visible immediately after you finish the wizard.

Path B: Load Sample Data

Choose this if you want to explore Jetonomy's features before committing to a structure.

Jetonomy seeds your site with a complete, realistic community:

  • Four categories - Start Here, Product & Engineering, Community, and Help & Support
  • A full set of spaces across all four types - Forum, Q&A, Ideas, and Feed - so you can see how each type behaves (for example, "Feature Requests" is an Ideas space with a roadmap, "Bug Reports" is a Q&A space with accepted answers, and "Announcements" is a Feed space)
  • Demo users with realistic avatars, trust level badges, and posting history
  • Sample posts and replies - enough content to see voting, accepted answers, tags, and notifications working in context

This lets you experience the full community interface as a regular member would see it, without writing any content yourself.

When you are ready to go live, click Remove Demo Data on the Jetonomy dashboard. Every demo post, reply, space, category, and user record is deleted in a single operation. Any real content you added alongside the demo data is preserved.

Note: Demo data is tracked internally via a jetonomy_demo_data record. Removal is precise and does not affect any content you created yourself.

Step 3: Done

The final screen confirms your community is live and gives you two quick links:

  • Visit your community - opens yoursite.com/community/ in a new tab so you can see the frontend immediately.
  • Go to admin dashboard - takes you to Jetonomy → Dashboard where you can manage spaces, moderate content, and configure settings.

Everything you configured in the wizard can be changed later:

Setting Where to change it
Community URL slug Jetonomy → Settings → General
Default space type Jetonomy → Settings → General (Community Setup)
Space name, type, join policy Jetonomy → Spaces → Edit
Email notifications Jetonomy → Settings → Email (Notification Defaults)

What's Next?

Your community is live. Now learn what to do in the first hour: create categories, set up your real spaces, and invite your first members.

Your First Community →

Your First Community

Your community is installed and the wizard is complete. This guide walks you through what to do next, from organizing your spaces to inviting your first members, so your community is genuinely ready for people on day one.

Community home page showing spaces organized by category

What You Will Learn

  • How to organize spaces with categories
  • How to create your first real space and choose the right type
  • How to invite members with a shareable link
  • How to customize the look and feel
  • How to import from bbPress or wpForo if you are migrating
  • What the community frontend looks like for your members

Create Categories to Organize Your Spaces

Categories are the top-level groupings in your community. Every space belongs to a category. Before you create more spaces, take a moment to plan your category structure - it is much easier to do now than to reorganize later.

To create a category:

  1. Go to Jetonomy → Categories.
  2. Enter a name and optional description in the form on the left.
  3. Click Add Category.

Your category appears in the table on the right. Drag rows to reorder them. The order here is the order your members see on the community home page.

Jetonomy Categories admin: the add-category form on the left and the drag-to-reorder category table on the right

Tip: Start with two to four broad categories. You can always add more later. Common patterns: "Support / General / Announcements" for a product community, or "Ideas / Questions / Showcase" for a creator community.

Create Your First Real Space

A space is where discussions happen. Each space has a type that shapes how members interact with content.

Choosing a Space Type

Type Best for Key feature
Forum General discussion, announcements, support Threaded replies, newest/popular sort
Q&A Technical help, knowledge bases Votable answers, accepted answer highlight
Ideas Feature requests, roadmaps Status lanes (Planned, In Progress, Shipped, Declined) with roadmap view
Feed Status updates, introductions, sharing work Card feed with optional title and votes

To create a space, you can use either the wp-admin form or the front-end Create Space page. Both produce the same result.

From wp-admin:

  1. Go to Jetonomy → Spaces → Add Space.
  2. Enter a name and optional description.
  3. Pick an icon from the visual Lucide picker (16 defaults plus a search field).
  4. Choose the space type.
  5. Set visibility: Public (anyone can see it), Private (members only see content), or Hidden (not listed, invite only).
  6. Set the join policy: Open, Request to join, or Invite only.
  7. Click Save Space.

The Add Space form showing the Lucide icon picker and the visibility and join-policy selectors

From the front end (so non-admin owners can create spaces too): visit /community/new-space/ while signed in. The form is identical and is available to any role you've enabled under Jetonomy → Settings → General, in the Front-end space creation field.

Your space is immediately available on the community frontend under its category.

Invite Members

You do not need to wait for members to discover your community organically. Jetonomy gives you a direct invite link you can share anywhere.

  1. Go to Jetonomy → Spaces and click on your space.
  2. Click Members in the space navigation.
  3. Click Generate Invite Link.
  4. Set an expiry date, or leave it open with no expiry.
  5. Copy the link and share it via email, Slack, social media, or anywhere else.

The Generate Invite Link panel showing the expiry option and the copyable invite URL

When someone visits the link, they are added to the space immediately after logging in or creating a WordPress account.

Note: Invite links work for any WordPress user registration flow you have configured. If you allow open registration, new members can sign up and join in one step.

Existing WordPress Users

Anyone who already has an account on your WordPress site can visit yoursite.com/community/ and join public spaces by clicking Join Space. Their existing avatar, display name, and email are used automatically.

Customize the Appearance

Jetonomy inherits your theme's fonts, colors, and border radius automatically via WordPress theme tokens. If you are using BuddyX, this integration is immediate. Jetonomy reads BuddyX's design tokens and matches your brand without any manual work.

To adjust further:

  • Go to Jetonomy → Settings and explore the General and Advanced tabs.
  • To override specific templates, create a jetonomy/ folder inside your active theme directory and drop in any template file from wp-content/plugins/jetonomy/templates/. Jetonomy always checks your theme folder first.

Tip: You do not need to copy all templates. Only override the ones you want to change. Unmodified templates are served directly from the plugin.

Importing from bbPress, wpForo, or Asgaros

If you are migrating an existing community, Jetonomy includes a built-in importer for three sources.

The Jetonomy Import screen with the source selector and a detected-data summary such as "Found: 12 forums, 3,847 topics, 28,419 replies"

  1. Go to Jetonomy → Import.
  2. Select your source plugin: bbPress, wpForo, or Asgaros Forum.
  3. Jetonomy auto-detects your existing data and shows a summary, for example: "Found: 12 forums, 3,847 topics, 28,419 replies."
  4. Run a Dry Run first to check for any mapping issues.
  5. Click Start Import when you are ready.

Imports run in background batches. You can close your browser and come back. The import continues via WP-Cron and resumes from where it left off if interrupted.

What gets migrated:

Source Jetonomy
Forums Categories + Spaces
Topics Posts
Replies Replies
Users WordPress users + Jetonomy profiles

The Community Frontend: A Quick Tour

Once you have content, here is what your members will see.

Community Home (/community/)

The home page lists all categories with their spaces. Each space card shows the post count, member count, and a recent activity indicator. Members can sort by activity or browse by category.

Space Listing (/community/s/space-slug/)

Inside a space, members see a topic list with vote scores, reply counts, author avatars, tags, and time. They can filter by Latest, Popular, or Unanswered. A New Post button appears in the top right for members who have permission to post.

Single Topic (/community/s/space-slug/t/topic-slug/)

The topic view shows the full post, vote buttons, and all replies. Replies are threaded up to three levels deep. For busy topics with many replies, Jetonomy loads the first 10 and last 10 replies by default, with a gap-loader button in between to fetch more. This keeps page load fast regardless of reply count.

In Q&A spaces, the accepted answer is pinned to the top and highlighted with a green checkmark.

The community sidebar (where the theme layout places it) shows active members, trending tags, and recent activity. The exact sidebar layout depends on your theme.

Note: All community pages are server-side rendered. There are no JavaScript-only pages, so every URL is indexable by search engines out of the box.

What's Next?

Now that your community is live and populated, learn how to organize it further with spaces and categories, including visibility rules and per-space permissions.

Spaces and Categories →

In-Page Authentication

Jetonomy can handle Login, Register, and Forgot Password right inside your community pages, with forms that match your theme instead of bouncing members to the generic WordPress login screen. It does this through its own /auth/* REST endpoints, so signing in to upvote a post or reply to a thread happens in place, without a jarring redirect to wp-login.php and back. This is an optional enhancement you can set up at any time after launch.

What You Will Learn

  • Where the in-page auth forms appear and how they behave
  • Why the Login block improves member experience over a bare login screen
  • How captcha protection now covers signup, not just posting
  • How signed-out interactions and Private community mode route visitors
  • How to customize the auth surface with theme tokens

Where the Forms Appear

The Jetonomy Login block rendered inline on a page, showing the Login, Register, and Lost Password tabs

In-page auth is delivered by the Login block (wp:jetonomy/login). Place the block on any page or template, and it renders Login, Register, and Lost Password tabs inline, styled to match your community. The forms submit to Jetonomy's own /auth/* REST endpoints, so a visitor signs in or registers without ever leaving the page the block is on.

Use it wherever a sign-in surface makes sense:

  • A dedicated member-login page you build with the block
  • A sidebar or footer widget area
  • A landing page that gates content behind membership

Signed-Out Interactions

When a signed-out visitor tries to do something that requires an account - upvoting a post, starting a reply, following a space, subscribing to a tag, or bookmarking - Jetonomy sends them to the WordPress login screen (wp_login_url) with a redirect_to parameter back to the page they were on. After they sign in, they land back where they started.

For a fully in-page experience, point those visitors at a page that hosts the Login block instead of relying on the default wp-login.php redirect.

Why This Matters

The old wp-login.php flow worked, but it had three real problems:

  1. Visual jarring. The WordPress login screen does not look like your community. Visitors went from your themed pages to a generic blue-and-white form and back. The break in visual continuity made the community feel less polished.
  2. Lost context. Visitors who clicked "Reply" had to sign in, then find their way back to the thread. WordPress's redirect handling did not always land them on the right page, especially with theme-specific URLs.
  3. Slow perceived load. Two full page navigations for what should be a quick "sign me in and let me reply" step.

The Login block fixes all three. The forms render inline on the page you place the block on, look like the rest of the community, and submit through the /auth/* endpoints without a full page navigation.

Captcha Now Protects Signup

Site owners can configure reCAPTCHA or Cloudflare Turnstile keys under Jetonomy → Settings → Anti-spam. Before 1.4.0, those keys only protected post and reply submission. Bots could still register accounts freely.

From 1.4.0, the same captcha keys also protect:

  • New account registration
  • Password reset requests
  • Login attempts after repeated failures from the same IP

Nothing needs to change in your settings. If you already had captcha configured, it now extends to signup automatically. If you don't have captcha configured, the auth forms still work; they just have less spam protection.

Captcha Providers Supported

Provider Where to get keys
Google reCAPTCHA v3 https://www.google.com/recaptcha/admin
Cloudflare Turnstile https://dash.cloudflare.com/?to=/:account/turnstile

Choose whichever fits your stack. Turnstile is recommended if you're privacy-conscious or already on Cloudflare; it runs without challenging visitors in most cases.

Who Still Uses wp-login.php

The Login block gives members an in-page sign-in surface. The standard WordPress site-wide login is unchanged.

Administrators (anyone with the manage_options capability) sign in at wp-login.php and reach wp-admin/. That's intentional. Site owners need a reliable way to get into the admin area even if community pages have an issue, and security plugins, two-factor plugins, and SSO integrations all hook into wp-login.php.

In practice:

  • Members can use a page hosting the Login block, or fall back to wp-login.php
  • Signed-out interactions that require an account redirect to wp-login.php unless you route them to a Login-block page
  • Any plugin you have that customises wp-login.php (login restrictions, two-factor, branding) still works for admin login

Private Community Mode

If you've set your community to Private (the Public / Private access control under Jetonomy → Settings → General → Access Control), signed-out visitors cannot read any community content.

Every community URL redirects an anonymous visitor to the WordPress login screen (wp_login_url) with a redirect_to parameter back to the page they were trying to reach, so they land there as soon as they sign in. If you've built a page with the Login block, point your members at it for an in-page sign-in instead.

Registration can be disabled separately if you only want to allow invited members. In that case the Login block hides its Register tab.

Customization

The auth surface uses the same --jt-* design tokens as the rest of Jetonomy. That means your theme's brand color, fonts, border radius, and spacing are picked up automatically. No custom CSS required for a polished match.

Light Auth Surface in Dark Mode

The Login block staying light while the surrounding community page is in dark mode

There's one intentional exception: the Login block stays in light mode even when the rest of your community is in dark mode. This is a deliberate UX choice. Sign-in forms in dark mode are statistically harder to read and easier to mistype, especially on mobile. Keeping the auth surface light maintains form readability where it matters most: at the point of conversion.

If you want to override this and run a dark auth surface (for a fully dark community theme), you can do it via CSS:

.jt-login-block {
  --jt-bg: #1a1a1a;
  --jt-text: #f5f5f5;
}

Customising Form Labels

All auth form labels are translatable through the standard WordPress translation pipeline. They use the jetonomy text domain. If you're running a translated site, the forms pick up your translations on the next load.

What's Next?

With onboarding complete, fine-tune your community in the settings screens, starting with General settings for your community URL and access controls.

General Settings →

Admin Dashboard

The Jetonomy admin dashboard is your first stop after logging in to wp-admin. It shows a live snapshot of community health and gives you one-click access to the most common management tasks.

The Jetonomy admin dashboard: six stat cards across the top, the Recent Activity feed on the left, and the Quick Actions, Demo Data, and System Info panels in the right sidebar

What You Will Learn

  • What each stat card measures
  • How to use the Quick Actions panel
  • What the Recent Activity feed shows
  • Where to find System Info

Go to Jetonomy → Dashboard to access this screen. It is also the landing page when you click Jetonomy in the wp-admin sidebar.

Setup Wizard Notice

On a fresh install where the setup wizard has not been completed, a blue notice appears at the top of the dashboard asking you to run the wizard. The wizard creates your first space and seeds optional demo content. Once you complete it, the notice disappears and does not return.

Stat Cards

Six cards show current counts for the most important community metrics. Counts update in real time - refreshing the page fetches the latest values.

Card What It Counts
Total Posts All published posts across every space
Total Replies All published replies across every post
Active Spaces Spaces with status "active"
Registered Users Total WordPress users with at least one Jetonomy profile row
Pending Flags Flags in the moderation queue that have not been resolved
Posts Today Posts created in the current calendar day (UTC)

The Pending Flags card turns orange when the count is greater than zero - a visual signal to visit the moderation queue.

Recent Activity Feed

The Recent Activity table on the left side of the dashboard shows the most recent member actions logged in the activity system. Columns:

Column Description
User Display name of the member who took the action
Action What they did (colored dot indicates category: green = create, blue = vote, orange = moderation)
Object The post, reply, space, or user the action involved, with a link to the relevant admin page
When Relative time (e.g. "3 minutes ago")

If no activity has been logged yet, a placeholder message appears. The feed is read-only - use it for monitoring, not for taking action on specific items.

Quick Actions Panel

The right sidebar has a Quick Actions card with three buttons:

Button What It Does
Create Space Opens the new-space form at Jetonomy → Spaces → Add New
View Community Opens the community home in a new browser tab
Flush Rules Triggers flush_rewrite_rules() to rebuild WordPress permalink rules

Use Flush Rules any time your community URLs return 404s after changing the base slug, activating a new plugin, or running a migration.

Demo Data Notice

If you used the setup wizard's demo-data option, a yellow card labeled Demo Data Active appears below Quick Actions. Click Remove All Demo Data to delete all demo posts, replies, spaces, and the related setup option.

This card only appears while jetonomy_demo_data option is set. It disappears permanently once you click Remove.

System Info

A small table at the bottom of the sidebar shows:

Row Value
Plugin Version Current Jetonomy version constant
DB Version The database schema version currently applied
PHP Version Server PHP version
WordPress Version WordPress core version
Base URL The configured community base slug (e.g. /community/)

Use this table when filing a support request or diagnosing compatibility issues. Copy the values rather than describing them from memory.

Pro Analytics Widget (Jetonomy Pro)

When Jetonomy Pro is active and the Analytics extension is enabled, Pro adds an analytics mini-widget to the sidebar showing recent engagement trends. A full analytics dashboard is available at Jetonomy → Analytics.

When Pro is not active, a small card in the sidebar describes what the Analytics extension adds and links to the Jetonomy Pro store page.

What's Next?

Give members a sign-in experience that matches your community by adding in-page login and registration.

In-Page Authentication →

Spaces & Categories

Organize your community into discussion spaces.

Categories are the top-level groupings members see on your community home page - think of them as the tabs or sections that organize your spaces. Every space belongs to a category, so it makes sense to set up your categories first, then create spaces inside them.

Jetonomy Categories admin screen with the Add New Category form on the left and the category table on the right

What You Will Learn

  • How categories relate to spaces (and why you set them up first)
  • How to create, edit, delete, and reorder categories
  • How category visibility works
  • How icons and colors appear in navigation

Categories vs Spaces

  • A category is a label that groups related spaces together (for example "Support", "Community", or "Product").
  • A space is the actual discussion area where members post topics and replies.

A space must be assigned to a category to appear in the community navigation. So the normal setup order is: create a category, then create one or more spaces inside it. See Creating Spaces once your categories are ready.

Where to Find It

Go to Jetonomy → Categories in your WordPress admin.

This screen is administrator-only by default - it requires the jetonomy_manage_settings capability, which is granted only to administrators. Editors and other roles do not see this page.

Page Layout

The Categories screen is split into two panels side by side:

  • Left - Add New Category form for creating a new category
  • Right - Categories table listing existing categories and their children

Creating a Category

Fill in the Add New Category form and click Add Category.

Field Required What it does
Name Yes Shown in navigation and on the category page
Slug No Auto-generated from the name if left blank. Used in the URL.
Description No Optional text shown on the category listing page
Parent Category No Nest this category under an existing one. Two levels maximum.
Visibility No Controls who can see this category (see below)
Icon No Choose from the built-in Lucide icon picker
Color No A color swatch shown next to the category name in navigation

Visibility Options

Option Who can see the category
Public All visitors, including logged-out visitors, when guest access is on
Private Logged-in members only
Hidden Not shown in navigation or listings; the direct URL still works

A category's visibility does not override the visibility of the individual spaces inside it. A public category can still contain private spaces - each space keeps its own visibility setting.

Editing a Category

Click Edit in the row actions under any category name. An Edit Category dialog opens with the same fields as the creation form. Make your changes and click Update Category.

Deleting a Category

Click Delete in the row actions. A confirmation prompt appears before the delete runs.

Warning: Deleting a category does not delete the spaces inside it. Those spaces lose their category assignment and become "uncategorized," which means they drop out of the community navigation until you reassign them. There is no undo - reassign the spaces first if you want to keep them visible.

Reordering Categories

Drag the handle icon at the far left of any row to reorder categories. The new order saves automatically when you drop the row. Child categories follow their parent when the parent moves.

Child Categories

Set Parent Category when creating or editing a category to nest it under an existing top-level category. The table shows children indented below their parent. Two nesting levels are supported.

Use the search box in the table toolbar to filter categories by name. Clear the search to see all categories again. Searching does not affect the Add New Category form.

Rows Per Page

The dropdown in the table toolbar controls how many categories appear per page (20, 50, or 100). The list refreshes as soon as you change the selection - useful once you have a large number of categories.

What's Next?

Now that your categories are set up, create the spaces members will actually post in.

Creating Spaces →

Spaces are the discussion areas inside your community - each one has its own topic listing, member list, and settings. This guide shows you how to create, configure, and manage them.

Admin space editor with name, description, and settings fields

What You Will Learn

  • What spaces are and how they relate to categories
  • Every field on the space creation form
  • How the space header looks on the frontend
  • How to edit and archive an existing space

What Is a Space?

A space is a focused discussion area organized around a single topic or purpose. Examples: a "General Discussion" space, a "Product Feedback" space, a "Help & Support" space.

Every space belongs to a category. Categories are the top-level groupings (like tabs or sections) that members see on the community home page. A space without a category will not appear in the community navigation, so set your categories up first. See Categories for how to create and organize them.

Tip: Plan your space structure before creating anything. Too many spaces fragment your community early. Start with three to five and add more as demand grows.

Creating a Space

You have two ways to create a space, depending on who needs to do it:

  • wp-admin path (admins): Go to Jetonomy → Spaces in your WordPress dashboard and click Add New Space.
  • Front-end path (anyone you choose): Visit /community/new-space/ while signed in. This page is available to any user role you've allowed under Settings → Front-end space creation, so you can let space owners or moderators create spaces without giving them wp-admin access. See Creating Spaces From the Front End for the full walkthrough.

Both paths show the same fields and produce the same result. The rest of this section describes each field.

Basic Information

Title - The name members see in listings, the space header, and breadcrumbs. Keep it short and descriptive.

Slug - The URL-safe identifier for this space. Jetonomy auto-generates a slug from the title. The final URL will be /community/s/your-slug/. You can change the slug, but doing so after posts exist will break any existing links.

Description - A short sentence or two explaining what this space is for. This appears in the space header below the title and in category listing cards. It also populates the meta description for search engines.

Icon - The space icon is selected from Jetonomy's built-in Lucide icon picker (16 default icons plus 8 extras revealed by the "Show more" button, plus a search field to find any other Lucide name). The chosen icon appears in the space header and on category listing cards alongside the title. Icons render as crisp SVGs at every size, so they read clearly on mobile.

Category - Select which category this space belongs to. A space must be assigned to a category to appear on the community home page.

Space Configuration

Type - Choose Forum, Q&A, or Ideas. This controls how posts and replies behave. See Space Types for a full explanation of each.

Visibility - Controls who can see the space and its content. Options: Public, Private, or Hidden. See Membership & Join Policies for details.

Join Policy - Controls how members gain access. Options: Open, Approval Required, or Invite Only.

Defaults: if you leave Visibility and Join Policy untouched, a new space is Public + Open - anyone can find, read, and join it. Change them for private or invite-only spaces. Note that Hidden visibility always forces Invite Only; see Membership & Join Policies.

Click Save Space to publish it immediately.

The Space Header (Frontend)

Every space has a header at the top of /community/s/your-slug/ showing:

  • The Lucide icon at large size
  • The space title and description
  • A stat bar with total post count, member count, and last activity time
  • A Follow button for logged-in users (subscribes them to new post notifications)
  • A Join button when the space requires membership

Members who have already joined see the Join button replaced with their role badge (Member, Moderator, or Admin).

Editing a Space

Two paths, same fields:

  • wp-admin: Go to Jetonomy → Spaces, find the space in the list, and click Edit.
  • Front end: Visit the space at /community/s/your-slug/ while signed in as a space owner / moderator and click the Edit space button in the space header. See Editing Spaces From the Front End for screenshots.

All fields are editable from either path, including the type and visibility settings.

Note: Changing the space type after content exists does not reformat old posts. Existing posts keep their original structure. Only new posts use the new type's behavior.

Archiving a Space

To archive a space, open it for editing and set its Status to Archived. An archived space becomes read-only - members can read existing posts and replies, but cannot create new ones. The space remains visible in listings with a clear "Archived" label.

Archived spaces do not count toward activity stats on the community home page.

To permanently remove a space, click Delete in the space list. This action also deletes all posts, replies, votes, and member records inside that space. It cannot be undone.

What's Next?

Learn how each space type changes the way posts and replies behave.

Space Types →

The space type you choose determines how posts are structured, how replies work, and what extra features appear. Pick the right type and your community will feel purpose-built - pick the wrong one and members will feel like they are fighting the interface.

Q&A space showing questions with accepted answers and vote counts

What You Will Learn

  • What each space type is designed for
  • How posts and replies behave differently per type
  • The unique features each type unlocks
  • How to change a space type after creation

The Four Space Types

Forum

Forum is the default type. It is the right choice for general discussion, support, announcements, or any conversation without a single "correct" answer.

How it works:

  • Members post a topic with a title and rich content.
  • Replies thread up to three levels deep (reply to a reply to a reply).
  • Votes on replies surface the best contributions via the Best sort, but no reply is formally "accepted."
  • Topics can be sorted by Newest, Oldest, or Best on the space listing page.

Use Forum for: support channels, general discussion, community announcements, staff Q&A sessions.

Q&A

Q&A is built for questions that have a definitive best answer. It follows the model made popular by Stack Overflow. The person who asked the question marks one reply as the accepted answer.

How it works:

  • Every post is a question. The title should be phrased as a question.
  • Replies are answers. Each answer is voted on independently.
  • The post author sees an Accept button on every reply. Clicking it marks that reply as the accepted answer and pins it to the top of the reply list, regardless of sort order.
  • The accepted answer author earns a reputation bonus (+15 points).
  • The post listing shows an "Answered" badge on topics with an accepted answer. This badge also appears on the space list so members can see at a glance which Q&A spaces have resolved questions.

Use Q&A for: help & support, how-to guides, technical documentation requests, troubleshooting.

Tip: The Unanswered filter on the space listing page shows only topics with no accepted answer. This is a powerful tool for community moderators and support teams tracking open questions.

Ideas

Ideas is built for feature requests, product feedback, and roadmap voting. Each idea has a status that you control, and members vote to indicate demand.

How it works:

  • Members submit ideas with a title and description.
  • Other members upvote (or downvote) to signal interest. Vote score drives the default sort order.
  • Each idea has an Idea Status that the space moderator or admin updates manually:
Status Meaning
Planned On the roadmap
In Progress Being built right now
Shipped Completed and available
Declined Will not be implemented
  • Status updates appear in the reply thread as a system activity entry, so members can see when an idea's status changed.
  • The space listing page has a filter bar showing counts per status, making it easy to browse the roadmap.

Use Ideas for: product feedback boards, feature request trackers, community roadmaps, vote-to-prioritize workflows.

For a full guide to the Ideas roadmap view, see Ideas Roadmap.

Tip: Pick the lightbulb icon from the Lucide icon picker and name the space something like "Ideas & Feedback" to set the right expectation before members click through.

Feed

Feed is designed for short-form status updates - brief posts without a required title. Posts render as feed cards rather than the row list used by Forum and Q&A, so it behaves more like an activity stream than a traditional forum.

How it works:

  • The post title field is optional. Members can post a standalone message, image, or link.
  • Posts appear in a card-style feed sorted chronologically by default.
  • Replies work the same as Forum type, threaded up to three levels deep.
  • Voting is available, but the feed sort does not default to Best - it defaults to Latest.

Use Feed for: member introductions, community announcements, daily check-ins, showcasing work, open-ended community updates.

Changing the Space Type

You can change the type of an existing space at any time. Either open it in Jetonomy → Spaces in wp-admin, or use the Edit space button on the space header itself (front-end edit), and update the Type field.

The change takes effect immediately for all new posts. Existing posts keep their original structure. A Q&A post does not lose its accepted answer, and an Ideas post does not lose its status history.

If you change a Q&A space to Forum, the Accept button disappears from the UI but existing accepted answers remain stored in the database.

What's Next?

Learn how to control who can see your spaces and how members join them.

Membership & Join Policies →

Every space has two controls: who can see it (visibility) and how members get in (join policy). Combining them gives you precise control over every access scenario - from fully public forums to invite-only private communities. The two controls are independent in every combination except one: a Hidden space is always Invite Only (see the note under Hidden below).

Per-space access controls on the space edit screen: the Visibility selector (Public/Private/Hidden), the Join Policy selector (Open/Approval/Invite), and the Who Can Post / Who Can Reply dropdowns

What You Will Learn

  • The three visibility levels and when to use each
  • The three join policies and how they differ
  • Per-space posting restrictions
  • Space member roles and what each can do
  • How to combine visibility and join policy for common use cases

What you get if you leave the defaults alone: a new space is Public visibility with an Open join policy unless you change it (or unless you have changed the community-wide default under Jetonomy → Settings). That means anyone can find, read, and join the space with no approval - the most open setting. Tighten it from there for private or invite-only communities.

Visibility Levels

Visibility controls whether the space appears in listings and whether non-members can read its content.

Public

The space appears on the community home page, in search results, and in category listings. Any visitor - including users who are not logged in - can read all posts and replies.

Members still need to join (or be approved) before they can post or reply, depending on your join policy.

Use Public when you want maximum reach and SEO value. Most community spaces should start here.

Private

The space appears in listings and search results, so members can discover it. However, only approved members can read the content. Non-members see the space name and description, then a "Request to Join" prompt.

Use Private for paid membership communities, internal team discussions, or beta program spaces where content should be gated but the space itself should be findable.

Hidden

The space does not appear in any listing, search result, or category navigation. Only members who have already joined - and admins - can see it.

Members can only reach a hidden space via a direct link or an invite link you share with them.

Use Hidden for admin-only spaces, private moderator discussion boards, or early access groups where you control every invitation.

Hidden spaces are always Invite Only. Because a Hidden space has no public Join button, its join policy is locked to Invite Only - members can only enter through an invite link you share. If you pick Hidden in wp-admin, the join policy is switched to Invite Only for you automatically (and if you set a Hidden space back to Open or Approval Required, the visibility drops to Private). From the front-end create/edit form or the REST API, the same combination is rejected on save with the message "Hidden spaces must use the invite-only join policy" - so always pair Hidden with Invite Only.

Note: WP Admins and space admins can always see hidden spaces in the admin panel, regardless of their membership status.

Join Policies

Join policy controls how members gain access to the space. It works in combination with visibility.

Open

Any logged-in user can join instantly by clicking the Join button on the space header. There is no approval step.

Members who join an Open space can post and reply immediately (subject to your per-space posting restrictions).

Use Open for general discussion spaces, community-wide help channels, and any space where you want minimal friction.

Approval Required

When a user clicks Join, they submit a join request. The request goes to the space moderators and admins for review.

Moderators see pending requests in Jetonomy → Moderation → Join Requests. They can approve or decline each request. The user gets a notification when their request is reviewed.

Approved members can then post and reply immediately.

Use Approval Required when you want to vet members before they can participate - for example, a verified customer support channel or a professional community with admission criteria.

Invite Only

No join button is shown to non-members. Members can only enter via an invite link generated by a space moderator or admin.

To create an invite link, open the space in the admin panel (Jetonomy → Spaces → [space] → Edit) and go to the Invite Links section. Each link has a configurable usage limit and optional expiry date. You can see how many times each link has been used.

Invite links are created in wp-admin. Invite-link management lives on the wp-admin space edit screen, not on the front-end editor. A front-end space owner who does not have wp-admin access can still run an Invite Only space, but a site administrator (or someone with wp-admin access) generates and shares the links for them. The front-end Edit Space page can set the join policy to Invite Only but does not create the links themselves.

Anyone who visits a valid invite link is automatically added as a member - no approval step required.

Use Invite Only for private groups, course cohorts, or closed communities where every member should be explicitly invited.

Per-Space Posting Restrictions

Beyond join policy, each space has two additional settings that control what members can do once inside:

Who Can Post - Controls who can create new topics in this space.

Setting Effect
(Use Global Default) Falls back to the community-wide Who Can Post setting
Members Only All members of the space can post
Moderators & Admins Only space moderators and admins can post
Admins Only Only space admins (and site admins) can post

Who Can Reply - Controls who can reply to existing topics.

Setting Effect
(Use Global Default) Falls back to the community-wide Who Can Reply setting
Members Only All members of the space can reply
Moderators & Admins Only space moderators and admins can reply

These settings let you create announcement-only spaces (post set to Moderators & Admins, reply set to Moderators & Admins), or read-heavy Q&A spaces where only trusted members can contribute.

Space Member Roles

Every member of a space has one of three roles:

Member - Can read, post, and reply within the space's configured restrictions. Can vote, follow, and bookmark topics.

Moderator - All member abilities plus: approve pending posts, pin topics, close topics, move topics, delete posts and replies, manage join requests, create invite links, and review flagged content within the space.

Admin - All moderator abilities plus: change space settings, assign moderator and admin roles to other members, manage access rules, and archive or delete the space.

Note: WordPress site admins can perform all admin-level actions on any space, regardless of their space role.

Promoting members from the front-end (1.3.8+)

Space admins (and site admins) can change a member's space role directly from the front-end members page at /community/s/:slug/members/. Each member row carries a role dropdown; picking a new role saves the change live with inline success or error feedback. There is no wp-admin round-trip to add a moderator and no separate settings screen to open.

The dropdown is hidden for members who cannot manage roles, and a member cannot demote themselves below the level needed to keep at least one space admin. Members visible in the list still have to be members of the space to be assigned a role; the same per-space role rules listed above apply.

Common Visibility + Join Policy Combinations

Goal Visibility Join Policy
Public community forum Public Open
Paid membership forum Private Approval Required
Team-only internal channel Hidden Invite Only
Verified customer support Public Approval Required
Early access beta group Hidden Invite Only
Course community Private Open (link-gated via Invite Only)

What's Next?

See every per-space setting in one place, including how they override global defaults.

Space Settings →

Each space can override the global Jetonomy defaults with its own settings. This page is a complete reference for every per-space option, how it interacts with global settings, and how invite links work.

Admin space editor showing per-space configuration options

What You Will Learn

  • Every per-space setting and what it controls
  • How per-space settings override global defaults
  • How to require moderator approval before posts go live
  • How to create, share, and track invite links

Accessing Space Settings

Go to Jetonomy → Spaces in your WordPress admin, find the space, and click Edit. The settings panel is on the right side of the edit screen.

Per-Space Settings Reference

Posts Per Page

Default: Inherits from global setting (default: 20)

Overrides how many topics appear per page on this space's listing. Set a lower number for low-traffic spaces with long post titles. Set a higher number for high-activity spaces where members scan quickly.

Valid range: 5 to 100.

Require Post Approval

Default: Off

When enabled, every new post submitted by a non-moderator is held in a pending state and does not appear publicly until a moderator approves it.

Moderators and space admins can see pending posts immediately in the space listing with a "Pending" label. They can approve, reject, or mark the post as spam from the topic view or from Jetonomy → Moderation.

The post author receives a notification when their post is approved or rejected.

Tip: Enable this for your early community days when you want to review every submission, then turn it off once you trust your membership base.

Allow Voting

Default: On (inherits from global)

Controls whether upvote and downvote buttons appear on posts and replies in this space. Disabling voting also removes vote scores from the space's topic listing.

In Q&A spaces, voting is always available on replies regardless of this setting - otherwise the Best sort and accepted-answer workflow cannot function correctly.

In Ideas spaces, voting cannot be disabled because it is the core mechanism for prioritizing ideas.

Who Can Post

Default: Anyone (members)

See Membership & Join Policies for the full option set. The per-space value overrides the global default for this space only.

Who Can Reply

Default: Anyone (members)

Controls who can add replies to topics in this space. Overrides the global default for this space only.

Post Prefixes

Default: Off

Prefixes are short, colored labels members can attach to the front of a topic title - for example "Bug", "Idea", "Solved", or "Announcement" - so the listing is easier to scan.

Turn on the Enable prefixes toggle to reveal the prefix list, then add one row per prefix. Each row has a label (up to 50 characters) and a color swatch. Add as many as the space needs, and remove any with the × button.

Once prefixes are enabled:

  • When a member starts a new topic in the space, an optional Prefix dropdown appears on the compose form. They pick one (or leave it blank).
  • The chosen prefix shows as a colored label in front of the topic title on the space listing and the single-topic view, using the color you set.

Prefixes are configured per space, so a "Support" space can offer "Bug / Question / Solved" while an "Announcements" space offers none. You can manage prefixes from either the wp-admin space editor or the front-end Edit Space page.

How Per-Space Settings Override Global Settings

Jetonomy uses a two-layer settings system:

  1. Global settings - Set at Jetonomy → Settings → Community. These are the defaults that apply to every space.
  2. Per-space settings - Set on individual spaces. When a per-space value is configured, it takes precedence over the global value for that space only.

If you leave a per-space setting at "Inherit from global," any future changes to the global setting will automatically apply to that space. If you explicitly set a per-space value, global changes do not affect it.

This means you can configure a sensible default globally and only override the spaces that need different behavior - instead of configuring every space individually.

Access Rules for Membership-Gated Spaces

For Private and Hidden spaces, you can restrict access based on external membership status - not just whether someone has joined the space.

Go to the Access Rules tab on the space edit screen to add rules.

Each rule has three parts:

Rule Type - What to check:

Type What it checks
Everyone Matches every visitor, including logged-out users
Logged In User is authenticated
WordPress Role User has a specific WP role (e.g. Editor)
Capability User has a specific WP capability
Trust Level User's Jetonomy trust level (0-5)
Membership User has an active membership. The specific provider - MemberPress or Paid Memberships Pro in free, plus WooCommerce Memberships, Restrict Content Pro, and LearnDash in Pro - is chosen within the rule via the matching membership adapter

Access Grant - What to allow:

Grant Effect
Read Can view posts and replies, cannot participate
Participate Can read, post, and reply
Full All participate abilities plus moderator actions

Auto-Assign Role - Optionally assign the member a space role (Member, Moderator, Admin) automatically when the access rule is satisfied. This is useful when you want MemberPress Gold members to automatically become space moderators.

Multiple rules can be stacked. Jetonomy grants the highest matching permission level.

Note: MemberPress and Paid Memberships Pro adapters are available in Jetonomy free. WooCommerce Memberships, Restrict Content Pro, and LearnDash adapters require Jetonomy Pro.

Invite links let you bring specific people into a space without opening up general membership.

Where to manage invite links: invite links are created and tracked from the wp-admin space edit screen (Jetonomy → Spaces → [space] → Edit → Invite Links), not from the front-end Edit Space page. A space owner without wp-admin access can run an Invite Only space, but a site administrator generates and shares the links on their behalf.

  1. Open the space for editing in wp-admin and go to the Invite Links section.
  2. Click Create Invite Link.
  3. Set an optional Usage Limit (how many people can use this link before it expires).
  4. Set an optional Expiry Date.
  5. Click Generate.

Jetonomy generates a unique URL: /community/invite/abc123def/

Copy the link from the Invite Links table and share it however you prefer - email, Slack, a membership welcome email, etc.

When someone visits the link, they are prompted to log in if they are not already. After logging in, they are automatically added to the space as a Member.

Tracking Usage

The Invite Links table shows each link's current usage count against its limit. Links that have reached their usage limit are automatically deactivated but remain in the table for your records.

You can manually deactivate or delete any invite link at any time.

Space RSS Feeds

New in 1.5.0. Every public space publishes an RSS 2.0 feed of its latest 20 topics at:

https://your-site.com/community/s/{space-slug}/feed/

Feed readers and browsers discover it automatically from the space page. Members and visitors can follow a single space from any RSS reader without creating an account - useful for announcement spaces, changelogs, and "follow this team" workflows.

Privacy is preserved: the feed serves only what a logged-out visitor could already read. Private and hidden spaces return 404 from their feed URL, and switching the whole community to private mode disables all feeds. Developers can adjust feed contents with the jetonomy_space_feed_posts filter.

What's Next?

Learn how to create topics and posts inside your spaces.

Creating Topics →

  • Custom Fields - add structured fields to posts and profiles, configurable per space.

Every Ideas space includes a built-in roadmap view. Instead of scrolling through a flat list of feature requests, visitors can see all ideas organized by status - what is planned, what is being built, what has shipped, and what will not be pursued. This page explains the roadmap, the status lanes, and how status changes are communicated to your community.

What You Will Learn

  • Where to find the roadmap view
  • What the four status lanes mean
  • How admins update an idea's status
  • How status changes surface in notifications and the activity log
  • What the roadmap looks like for community members

What the Roadmap Shows

Ideas roadmap view with four status lanes - Planned, In Progress, Shipped, and Declined - each holding idea cards sorted by vote score

The roadmap is a dedicated view of an Ideas space that groups all ideas by their current status. Access it at:

/community/s/<space-slug>/roadmap/

A link to the roadmap appears in the Ideas space navigation alongside the main topic list. Members do not need to navigate manually - they can switch between the idea list and the roadmap from within the space.

Each status lane shows all ideas in that state, sorted by vote score within the lane (highest votes first). This gives members a clear view of what the community wants most and where each request stands.

Status Lanes

The roadmap has four lanes:

Status What it means
Planned The idea has been accepted and is on the roadmap. Work has not started yet.
In Progress The team is actively building or implementing this idea.
Shipped The idea has been completed and is now available.
Declined The team has decided not to pursue this idea. A reply with context is recommended.

New ideas submitted by members have no status by default. They appear in the main idea list but not in any roadmap lane until a moderator or admin assigns a status.

Tip: When you decline an idea, add a reply explaining why. Members who took the time to submit and vote on an idea deserve a clear answer. Declined ideas with a closing comment are far less likely to be re-submitted repeatedly.

How Admins Update a Status

Any space moderator or admin can change an idea's status:

  1. Open the idea (the single post view).
  2. Find the Status control in the post meta area below the title.
  3. Select a new status from the dropdown: Planned, In Progress, Shipped, or Declined.
  4. Click Update Status.

The status change saves immediately. A system entry appears in the reply thread showing what the status changed from and to, with a timestamp. This gives the idea's full history in one place.

You can also update status from the space admin panel at Jetonomy → Spaces → [Space Name] → Posts. The status column is editable inline from that view, which is useful for processing a batch of ideas at once.

How Status Changes Surface in Notifications

When an idea's status changes, Jetonomy sends notifications across three channels:

Activity log - A system activity entry is created in the idea's reply thread, visible to anyone who opens that idea.

Email digest - If a member follows the Ideas space and has email digest enabled, the status change is included in their next digest email (daily or weekly depending on their preference).

In-app inbox - The idea author receives an in-app notification immediately. All followers of the Ideas space also receive an in-app notification.

Members who do not follow the space will not receive notifications about that specific status change. Encourage members to follow the space after submitting an idea so they stay informed.

Customer-Visible Behaviors

What members see at each stage:

  • New idea with no status assigned - Appears in the idea list. Not shown in any roadmap lane until an admin or moderator picks a status. Vote buttons are active so members can build up signal even before the team triages.
  • Planned - Appears in the Planned lane on the roadmap. A "Planned" badge shows on the idea card.
  • In Progress - Moves to the In Progress lane. Badge updates. Members can see work has started.
  • Shipped - Moves to the Shipped lane. Badge shows "Shipped." Upvote button remains available so members can react positively to the delivery.
  • Declined - Moves to the Declined lane. Badge shows "Declined." Vote controls remain visible.

Ideas can be moved between statuses at any time. Moving a shipped idea back to In Progress (for a revision, for example) is valid and will notify followers again.

What's Next?

The roadmap is a deep-dive on the Ideas space type. To set up a space without leaving the front end, see the front-end create flow.

Create a Space from the Front-End →

Since Jetonomy 1.4.0, members with the right role can create a new space without ever opening wp-admin. The front-end Create Space page lives at /community/new-space/ and gives community owners a way to delegate space creation to trusted regulars, team leads, or paying members without handing out WordPress admin access.

Front-end Create Space form at /community/new-space/ showing the Title, Description, Type, Visibility, Join policy, Category, and Icon fields

What You Will Learn

  • Where the Create Space page lives and who can reach it
  • Which roles are allowed to create spaces, and how to change that
  • Every field available on the form, including the visual icon picker
  • What happens the moment the form is submitted
  • When to use this page versus the wp-admin equivalent

Where The Page Lives

The page is always available at /community/new-space/. It is part of the standard /community/ rewrite group, so it inherits the same theme, header, and footer as the rest of your community pages.

There is no separate menu item by default. Most communities expose the page in two places:

  • A "Create space" button on /community/ for signed-in users with permission
  • A "Start a space" link in the header avatar menu

Both links are conditional. Members who do not have permission never see the link and never see the page either, even if they type the URL directly.

Who Can Create Spaces

Open Jetonomy → Settings → Front-end space creation. The setting is a list of WordPress roles. Tick the roles you want to allow.

The default is Administrator only, which matches the pre-1.4.0 behaviour. Most communities widen this to Editor, Author, or a custom role such as "Community Builder" after they have run for a few weeks and identified trusted members.

A few important notes:

  • The permission is role-based, not per-user. If you want to grant one specific member the ability to create spaces, add them to a role that has it.
  • Granting the right to create a space is not the same as granting the right to moderate every other space. A member who can create one space only moderates the spaces they created, not the whole community.
  • Network admins on multisite have the permission everywhere by default.

The Form Fields

The front-end form covers the fields a member needs to launch a space. The slug is generated automatically from the title, and posts-per-page is set later on the Edit Space page rather than at creation time.

Field What it controls
Title The display name shown in listings and the space header. Required.
Description One or two sentences shown on the space card and the space header.
Type Forum, Q&A, Ideas, or Feed. Cannot be changed after creation.
Visibility Public, Private, or Hidden.
Join policy Open, Approval Required, or Invite Only.
Category Which top-level community category the space belongs to. Optional but recommended for navigation.
Icon A visual icon shown next to the title everywhere the space appears.

The form does its own validation in the browser before submission, then again on the server. Submitting with an empty title returns an inline error rather than a generic failure. The slug is derived from the title automatically and made unique by the server.

The Visual Icon Picker

The icon field is not a free-text field. Jetonomy ships with a Lucide icon picker so every space gets a consistent, professionally-drawn icon.

Lucide icon picker open, showing the 16 default icons, the Show more button, and the search field at the top

The picker shows 16 default icons up front, covering the most common community space themes: users, hand, megaphone, message-circle, help-circle, lightbulb, star, rocket, book-open, award, shield, pin, bookmark, home, hash, and folder.

Click "Show more" to reveal another 8 icons for less common topics. If none of those fit, the search field at the top filters the entire Lucide catalogue by name, so typing "music" surfaces the music note icon, "camera" surfaces the camera icon, and so on.

The picker stores only the icon name, not an SVG, so the icon stays crisp at any size and automatically picks up the active theme's color tokens.

What Happens On Submit

Submitting the form does five things in one transaction:

  1. Creates the space row in wp_jt_spaces
  2. Adds the submitting user as the space admin (role = admin)
  3. Adds the space to the chosen category, if any
  4. Flushes the relevant rewrite caches so the space URL resolves immediately
  5. Redirects the user to the new space at /community/s/<slug>/

There is no approval queue. The space is live the moment the form is submitted. Who may reach the form at all is gated by the jetonomy_create_spaces capability plus the Front-end space creation roles setting, so you control space creation by role rather than by an after-the-fact approval step.

Validation Hints

  • Title is required and cannot be a duplicate of an existing space title within the same category.
  • The slug is generated automatically from the title and made unique by the server. There is no slug field on the create form; you can edit the slug later from the Edit Space page.
  • Description is optional but space cards look better with one.
  • Category, Type, Visibility, and Join policy default to the community-wide defaults set in Jetonomy → Settings.

Permission Gotchas

A few rules that surprise people on first use:

  • Creating is not moderating. A role granted "create spaces" is automatically space admin only for the spaces it creates. It cannot moderate other spaces it did not create.
  • Visibility is per-space, not per-role. A role allowed to create spaces can create a space of any visibility, including Hidden. There is no built-in per-visibility gate; restrict who can create spaces at all via the Front-end space creation roles setting if that matters for your community. One rule does apply to the combination, though: a Hidden space must use the Invite Only join policy. Picking Hidden with Open or Approval Required on the front-end form is rejected on save with "Hidden spaces must use the invite-only join policy" - set the join policy to Invite Only when you choose Hidden. See Membership & Join Policies for the full explanation.
  • Deactivating a member who created a space does not delete the space. The space remains; ownership transfers to the next admin in the space, or to the site administrator if there is no other admin.
  • Slug collisions are checked across the whole site. A member trying to create a space with a slug another space already uses will see an inline error, even if they cannot see the other space.

Front-End Form vs wp-admin

Both paths produce identical spaces. Pick whichever is faster for the situation.

Situation Use front-end Use wp-admin
You're a regular member with permission Yes Not available
You're an admin and already in the community Yes, faster Either
You're an admin setting up the community for the first time Either Either, bulk import easier
You want to create 10+ spaces in one session Either wp-admin has bulk tools
You want to seed a space with demo content wp-admin wp-admin only
You want to change advanced options (access rules, custom roles) wp-admin wp-admin only

The front-end form covers everything a member or space owner needs. The wp-admin editor adds bulk tools and a few advanced toggles that only site administrators ever touch.

Developer Hooks

The two controls that come up most often when customising this page:

  • jetonomy_create_spaces (capability) - granted to roles via the Front-end space creation roles setting. A user without this capability never sees the Create Space link or page. This is the primary gate.
  • jetonomy_use_frontend_space_edit (filter) - returns true to route both the Create and Edit space flows through the front-end UI. Default true. Return false to send these flows to wp-admin instead.

See the Developer Reference for the full signatures and examples.

What's Next?

Once a member has created a space, they often want to tweak it. The Edit Space page lets them adjust the icon, description, join policy, and more without leaving the front-end.

Edit a Space from the Front-End →

Since Jetonomy 1.4.0, space owners and moderators can edit their space directly from the front-end. They click an Edit space button in the space header and adjust the title, description, cover image, icon, type, visibility, join policy, category, posts-per-page, and prefixes without ever loading wp-admin.

Front-end Edit Space page at /community/s/<slug>/edit/ with the Edit space button visible in the space header and the editable fields below

What You Will Learn

  • Where the Edit space button appears and who sees it
  • Every field you can change from the front-end
  • How the cover image upload works without wp-admin permissions
  • The safety rules that prevent a space from being orphaned by accident
  • The difference between archiving and deleting a space
  • When to use the front-end editor versus the wp-admin one

Where The Edit Button Appears

The Edit space button lives in the top right of every space header, just above the post listing. It is conditional: only members with the right role inside that space see it.

The roles that see the button:

  • Space admin - the member who created the space, plus anyone they promote to admin
  • Space moderator - members promoted by a space admin
  • Site administrator - sees the button in every space

Regular members and guests never see the button. If a member loses their moderator role mid-session, the button disappears on the next page load.

The button leads to a dedicated page at /community/s/<slug>/edit/. The URL is permission-checked on every request, so typing it directly without the right role returns a 403.

What You Can Edit

Every space setting that is editable in wp-admin is editable from the front-end. The two editors are kept in lockstep release after release.

Field What it controls
Title The display name shown everywhere the space appears
Slug The URL segment under /community/s/. Changing it sets up a redirect from the old slug
Description The one-line summary shown on the space card and header
Cover image A wide banner image shown above the space header
Icon The Lucide icon shown next to the title
Category Which community category the space belongs to
Type Forum, Q&A, Ideas, or Feed
Visibility Public, Private, or Hidden
Join policy Open, Approval Required, or Invite Only
Posts per page A number from 1 to 100; leave blank to use the site default
Post prefixes Optional tags shown in front of post titles (e.g. "Bug", "Idea")

Changing the type after creation is supported but rarely a good idea. Switching a Q&A space to a Forum keeps every existing post but stops showing the "Mark as answer" affordance. The editor warns you before saving a type change.

The Visual Icon Picker

The icon picker is the same one used on the Create Space page. 16 default Lucide icons up front, 8 more behind a "Show more" button, and a search field that filters the full Lucide catalogue by name.

Changing the icon takes effect immediately on save. Cached pages and listings pick up the new icon on the next refresh. There is no manual cache flush needed.

Cover Image Upload

The cover image field accepts a standard image file. Recommended dimensions are around 1600 x 400 pixels - that is guidance for how the banner is cropped, not an enforced limit.

Uploads go into the standard WordPress media library at /wp-content/uploads/YYYY/MM/, the same place every other site image lives. The space stores only the resulting image URL, so the upload is reusable like any other attachment. The upload endpoint is gated by the logged-in member's edit permission in the space rather than by WordPress's upload_files capability, so a space owner can set a cover without site-wide media upload rights.

There is a Remove cover link below the upload field that clears the image reference from the space. Removing a cover only clears the reference; it does not delete the underlying attachment from the media library.

Role-Protection Rules

The front-end editor is intentionally cautious about anything that could leave a space without an owner.

  • No self-demote. A space admin cannot demote themselves if they are the only admin. The role dropdown skips the "moderator" and "member" options in that case and shows a tooltip explaining why.
  • No last-admin-out. A space admin cannot delete or archive the space if they have set themselves to leave it. The flow forces a transfer-to-another-admin step first.
  • No silent ownership transfer. Promoting another member to admin happens on the Members tab, not on the Edit space page. The editor never moves ownership in the background.

These rules exist because the most common community support ticket pre-1.4.0 was "I accidentally demoted myself and now nobody can edit the space." The front-end editor blocks that path entirely.

Archive vs Delete

The bottom of the Edit space page has two destructive actions, kept visually separate from the save button.

Archive space marks the space read-only. Existing posts and replies stay visible to anyone who could see them before. New posts and replies are disabled. The space disappears from category listings but is still reachable at its original URL. Archive is reversible: re-opening the editor and clicking Unarchive restores everything.

Use archive when:

  • A space has run its course but the content is still worth keeping
  • A seasonal event ends and you want the archive of last year's discussion to remain
  • A topic moves to a different space and you want the old discussions preserved

Delete space removes the space and every post, reply, vote, flag, and subscription in it. It cannot be undone from the UI. The button asks for explicit confirmation (typing the space title) before it fires.

Use delete when:

  • The space was created by mistake and has no real content
  • The content needs to be removed for legal or moderation reasons
  • You are cleaning up after a spam attack

If you are unsure, archive instead of delete. Archiving is reversible; deletion is not.

Front-End Edit vs wp-admin Edit

Both editors produce identical results. They share the same model, the same validation, and the same hooks.

Situation Use front-end Use wp-admin
You're a space owner without admin access Yes Not available
You're a site admin already in the community Yes, faster Either
You want to change advanced access rules Not supported wp-admin only
You want to bulk-edit multiple spaces Not supported wp-admin only
You want to change Pro extensions config Not supported wp-admin only
You want to fix a typo in the description Yes, fastest Either

The front-end editor covers the day-to-day fields a space owner touches. The wp-admin editor adds bulk tools and a handful of advanced settings that only site administrators ever need to change.

What's Next?

If you give space-creation permission to a wider group, expect those members to want a single place to see every space they run or belong to. The My Spaces page does exactly that.

My Spaces →

Discussions & Topics

Create topics, reply, vote, and manage conversations.

A topic is the primary unit of discussion in Jetonomy - every conversation, question, idea, or update starts here. This guide walks through everything that happens from the moment a member clicks "New Post" to when their topic goes live.

New post form with title, content editor, tags, and publish options

What You Will Learn

  • How to open the new post form in a space
  • Every field in the post composer and what it does
  • How Markdown formatting works in the content editor
  • How content moderation and rate limiting affect new members
  • Whether posts publish immediately or wait for approval

Opening the New Post Form

Members can start a new topic in three ways:

  1. Navigate to a space and click the New Post button in the space header.
  2. Visit the direct URL: /community/s/your-space-slug/new/
  3. Click + New from any page in the community - this opens a space picker first, then the form.

The new post form is always scoped to a specific space. If a member arrives via the generic + New button, they choose a space before the form loads. This ensures every topic lands in the right place.

The Post Composer

Title

The title field is required for Forum, Q&A, and Ideas spaces. Write a clear, specific title that tells members exactly what the topic is about before they click it.

Good: "How do I set up automatic email digests for my space?" Weak: "Help with emails"

For Q&A spaces, phrase the title as a question - it helps other members find answers when searching.

The title field is optional for Social Feed spaces, where short-form posts without titles are common.

Content

The content field supports rich text via a Markdown toolbar. You do not need to know Markdown syntax - the toolbar buttons handle formatting for you.

Toolbar options:

Button What it does
B Bold text
I Italic text
< > Inline code
Link Insert a hyperlink
Quote Block quote
Image Upload an image from your device

You can also type Markdown directly if you prefer:

  • **bold**bold
  • *italic*italic
  • `code`code
  • > quote → block quote

Images are uploaded to the WordPress media library. Each image is inserted as a standard <img> tag in the content. There is no separate file attachment field - all media goes inline.

Tags

Add up to five tags to help members find your topic through search and tag filtering. Type a tag name and press Enter. Jetonomy auto-suggests existing tags as you type - reusing existing tags is better than creating near-duplicates.

Tags are space-scoped by default. A "bug" tag in your Support space and a "bug" tag in your Dev space are the same tag in the database, but the tag page at /community/tag/bug/ will show posts from all spaces.

Similar Topics Detection

As you type the title, Jetonomy searches for existing topics with similar titles in the current space and shows up to five matches inline below the title field. This is the single best defense against duplicate topics - most duplicates happen because the author simply did not know an existing topic already covered their question.

If you see your question already answered in the list, click the match to jump to the existing topic instead of submitting a duplicate. If none of the matches fit, keep typing - the search re-runs after every few characters.

Similar Topics detection runs a lightweight, debounced search request (about 400ms after you stop typing) against the server search index, so it does not reload the page.

Prefix Selector

If the space has topic prefixes enabled, a Prefix selector appears next to the title field. Pick a prefix (for example, Bug, Suggestion, Solved) from the list and it appears as a colored label in front of your topic in the space listing.

Prefixes are configured per space by the space owner - see the Topic Prefixes guide.

Private Topic Toggle

If your space allows it, a Private toggle appears at the bottom of the composer. Enabling it restricts the topic to you and space moderators only - other space members cannot see it. Use this for sensitive support issues, personal requests, or anything that should stay between you and the moderators.

Not every space allows private topics. If you do not see the toggle, the space owner has disabled the feature.

See Private Topics and Topic Prefixes for the full guide.

Post Type Is Derived Automatically

You do not select the post type - Jetonomy determines it from the space type:

Space type Post type
Forum Discussion
Q&A Question
Ideas Idea
Social Feed Update

The composer adapts its UI accordingly. Q&A spaces show a hint to "phrase as a question." Ideas spaces show the Idea Status selector (visible to moderators). Social Feed spaces make the title optional and show a shorter, Twitter-style composer.

Content Moderation Checks

Before a post is saved, Jetonomy runs three checks:

Rate limiting - New members (Trust Level 0) can submit a maximum of 3 posts per day and 10 replies per day. If a member has hit their limit, the submit button shows an error and the post is not saved. Rate limits reset at midnight UTC. Members at Trust Level 1 and above have higher or no limits, depending on your global settings.

Require post approval - If the space has "Require Post Approval" enabled, the post is saved with a Pending status. It is not visible to other members until a moderator approves it. The submitter sees a confirmation: "Your post has been submitted and is awaiting approval."

Auto-moderation rules (Jetonomy Pro) - If Pro auto-moderation rules are configured, Jetonomy checks the content against those rules before saving. Depending on the rule configuration, the post may be flagged, held, blocked, or marked as spam automatically.

Note: WP Admins and space moderators bypass rate limiting and approval requirements. Their posts always publish immediately.

After Publishing

When a topic publishes successfully:

  • It appears at the top of the space listing under the Latest sort.
  • The author is automatically subscribed to the topic and will receive notifications for new replies.
  • The space's post count increments immediately.
  • Search indexes are updated on the next cron run (typically within a few minutes).

If the topic is pending approval, it does not appear in the listing, does not increment the post count, and the author's subscription is created but held until approval.

What's Next?

Learn how replies work, how threading is structured, and how to accept answers in Q&A spaces.

Replies & Threading →

  • Embedding the Composer - drop a "start a topic" box onto any WordPress page, post, or landing page using the Compose Topic block or the [jetonomy_compose_topic] shortcode.
  • You can also surface existing discussions on any page with the Forum Feed and Trending blocks (and their [jetonomy_recent_posts] / [jetonomy_trending_posts] shortcodes) - see Shortcodes, Widgets & Blocks.

These Pro extensions add to the discussion experience:

  • Polls - attach a single or multi-select poll to any topic.
  • Reactions - emoji reactions on posts and replies.

Replies are where conversations happen. Jetonomy's reply system supports threaded discussions, multiple sort orders, accepted answers in Q&A spaces, and efficient loading for threads with hundreds of contributions.

Single topic page with threaded replies and voting controls

What You Will Learn

  • How to add a reply to a topic
  • How threaded replies work and how deep they go
  • How to sort replies and what each sort does
  • How accepted answers work in Q&A spaces
  • How to edit your own replies
  • How Jetonomy handles large threads efficiently

The Reply Composer

The reply composer appears at the bottom of every topic page. Click into the text area to expand the full Markdown toolbar - the same formatting options available in the post composer (bold, italic, inline code, links, block quotes, image upload, code blocks).

Click Reply to submit. The reply appears immediately without a page reload.

If the space has "Require Post Approval" enabled, your reply is held for moderator review before appearing to other members. A confirmation message tells you it is pending.

Quote Replies

To reply while quoting a specific passage from an existing reply, select the text you want to quote and click the Quote button that appears. Jetonomy inserts the quoted text as a styled blockquote in your reply composer, with the author attribution linked back to the source reply.

You can also click Quote in the ... menu on any reply to quote its full body without selecting text first. This is the quickest way to address a specific point from a long reply - the quoted passage gives readers the context without forcing them to scroll back up.

Threading: Replies to Replies

You can reply to any existing reply by clicking the Reply link that appears when you hover over a reply. This creates a threaded sub-reply nested visually under the parent.

Jetonomy supports three levels of nesting:

Reply (level 1)
  └─ Reply to reply (level 2)
       └─ Reply to reply to reply (level 3)

At level 3, no further nesting is allowed. Members can still reply to a level-3 comment - that reply is added at level 3 as well, keeping the conversation readable.

Threaded replies let you have multiple parallel conversations inside the same topic without them colliding. A question inside a reply gets its own sub-thread. The main discussion continues underneath.

Sorting Replies

Use the sort controls at the top of the reply list to change the order:

Oldest first - Replies appear in chronological order, oldest at the top. Best for reading a long discussion from the beginning. This is the default for Forum spaces.

Newest first - Most recent replies appear at the top. Best for active topics where you want to see the latest contributions without scrolling.

Best - Replies are ranked by net vote score (upvotes minus downvotes), highest at the top. Best for Q&A spaces or any topic where you want the most useful contributions visible first. Within the same vote score, older replies rank first.

Sort preference is stored per-session - if you change it on one topic, it persists as you navigate between topics in the same session.

Note: "Best" is the vote-ranked sort for replies inside a topic. The space topic listing uses a similarly named vote-ranked sort called Popular (see Voting & Reputation). Both rank by net vote score - they are simply labelled differently because one orders replies and the other orders topics.

Accepted Answers in Q&A Spaces

In Q&A spaces, the person who asked the question (the topic author) decides which reply is the accepted answer. This signals to everyone else that the question has been solved and surfaces the winning reply at the top of the thread.

Q&A question with an accepted answer pinned to the top, showing the green Accepted tag and the Accepted answer callout box

Marking an Answer as Accepted

As the asker, you are the one who confirms which reply actually solved your problem:

  1. Open your own question. You must be the post author (space moderators and admins can also accept on your behalf, see below).
  2. Find the reply that best answers your question.
  3. Click the Accept button, the checkmark icon shown below the reply, on each reply in a Q&A space.
  4. The reply is immediately pinned to the top of the reply list, above all other replies and regardless of the current sort order.

What changes the moment you accept:

  • The reply gets a green Accepted tag and the whole thread is marked as resolved.
  • An "Accepted answer" callout box appears at the top of the topic, so anyone landing on the question sees the solution first without scrolling.
  • The reply's author receives a notification and a reputation bonus (a default of +15; you do not earn reputation for accepting your own reply). The bonus amount is admin-configurable under Settings → Permissions → Reputation Points.

Changing or Removing the Accepted Answer

The acceptance is never locked in. As the asker you stay in control:

  • Switch answers: Click Accept on a different reply. The previous reply automatically loses its accepted status, so there is only ever one accepted answer at a time.
  • Unaccept entirely: On the currently accepted reply, click the Unaccept button (the x-circle icon). This clears the accepted answer, returns the question to the unresolved state, removes the callout, and revokes the reputation that was awarded when it was accepted, so trust scores stay honest.

Tip: Space moderators (and admins) can also accept or unaccept answers on any Q&A topic in their space, useful for resolving questions on behalf of an asker who never came back to mark a solution.

Editing Your Own Replies

Click the ... menu on any reply you authored and select Edit. The reply text becomes an inline editor - you make changes and click Save. No page reload.

Edits are tracked as revisions internally. Moderators can view reply revision history from the moderation panel.

You can edit a reply at any time after posting. There is no edit window.

If a moderator edits your reply, the reply gets an "Edited by moderator" label.

How Jetonomy Handles Large Threads

For topics with many replies, Jetonomy uses cursor-based pagination to load replies in batches.

The first time you open a topic, you see the first batch of top-level replies (default: 20). A Load more replies button appears at the bottom if more exist. Clicking it loads the next batch without reloading the page.

For very high-traffic topics - those with hundreds of top-level replies - Jetonomy uses a smart loading strategy: it loads the first 10 replies and the last 10 replies, with a collapsed gap in the middle showing how many replies are hidden. You can click the gap to load replies from that range.

Threaded sub-replies follow the same pattern. A thread deeper than a few replies shows a "Show X more replies" link inline.

Note: New reply notifications appear as a sticky banner at the bottom of the page when other members post while you are reading. Click the banner to load the new replies without losing your scroll position.

What's Next?

Learn how upvotes and downvotes work, how they affect reputation, and how they power the Popular sort and trending sidebar.

Voting & Reputation →

Voting is the engine behind Jetonomy's quality signals. It surfaces the best content, rewards helpful members, and gives you a community where the most useful posts rise to the top naturally, without moderator intervention.

Topic page showing upvote and downvote buttons with vote scores on replies

What You Will Learn

  • How to vote on topics and replies
  • How vote scores appear in listings and on reply cards
  • How votes translate into reputation points
  • How votes power the Popular sort and trending sidebar
  • The one-vote-per-item rule and how to undo a vote

Voting on Topics and Replies

Every topic and every reply has an upvote button (thumbs up) and a downvote button (thumbs down). The net vote score (upvotes minus downvotes) is displayed between them.

To vote: Click the upvote or downvote button. The score updates instantly. No page reload.

To undo a vote: Click the same button again. The vote is removed and the score returns to its previous value.

To change your vote direction: Click the opposite button. Jetonomy removes your previous vote and applies the new one in a single action. The score adjusts correctly.

You must be logged in to vote. If you click a vote button while logged out, Jetonomy opens its in-page sign-in form (no wp-login.php bounce) and returns you to the same topic once you sign in.

Note: You cannot vote on your own posts or replies. The vote buttons are visible but disabled with a tooltip explaining why.

Note: When a space admin disables voting on a space, vote controls are removed from the interface entirely, not just greyed out. Members will not see the upvote or downvote buttons on any post or reply in that space.

Where Vote Scores Appear

Topic listing page - Each topic card shows the net vote score. This is how members quickly identify high-quality discussions without opening them.

Single topic page - The topic's vote score appears prominently alongside the title.

Reply cards - Every reply in a thread shows its vote score. In Q&A spaces, this score directly determines the Best sort order, making it easy to find the most helpful answer.

Vote scores are updated in real time as you vote. You never need to reload the page to see the current score.

How Votes Affect Reputation

When you receive votes on your content, your Jetonomy reputation score changes. Reputation is displayed on your public profile and powers your trust level progression.

Event Reputation change
Your post is upvoted +10
Your reply is upvoted +5
Your reply is accepted as an answer (Q&A) +15
Your post or reply is downvoted -2
Your post is deleted by a moderator -20

These are the defaults. Every value is admin-configurable per site under Jetonomy → Settings → Permissions → Reputation Points - positive numbers reward, negative numbers penalize, and any row you leave alone keeps its default. See Permissions Settings → Reputation Points for the full table and how to change a value.

Reputation is calculated and stored in real time. The moment someone votes on your content, your reputation score updates. There is no batch processing.

Casting a downvote does not cost you any reputation points. Downvotes are free for voters.

How Votes Power Content Discovery

Votes are not just cosmetic. They feed two core discovery features:

Popular sort - On the space listing page, the Popular sort orders topics by their net vote score. High-vote topics stay visible longer. New topics start at zero and rise based on community reaction.

Trending sidebar - The community home page and individual space pages show a trending sidebar highlighting the topics with the highest recent vote velocity, meaning they received the most votes in a short window. A post with 20 upvotes in 2 hours outranks one with 100 upvotes spread over a month.

In Ideas spaces, vote scores are the primary ranking signal on the roadmap view. Ideas with the most votes appear first, giving product teams a clear priority signal.

The One Vote Per Item Rule

Each member can cast exactly one vote per post and one vote per reply. The database enforces this with a unique constraint. There is no way to vote twice on the same item.

Toggling (undoing) and changing direction both work correctly within this constraint. At any moment, your vote on a given item is either +1, -1, or nothing.

If you vote on a topic in the listing view, then open the topic and vote again, you are interacting with the same vote record. The second click undoes the first vote.

What's Next?

Learn how to bookmark topics for quick access and how to follow spaces to get notified about new posts.

Bookmarks & Following →

Bookmarks and following are how members stay connected to the content they care about. Bookmarks are a personal reading list. Following a space is a subscription to that space's activity. Together they make sure your community members never lose track of an important discussion.

Topic page with bookmark, follow, and share action buttons

What You Will Learn

  • How to bookmark a topic and access your bookmarks later
  • How to follow a space and what that means for notifications
  • How auto-subscription works when you post or reply
  • How to manage your subscriptions and turn off notifications

Bookmarking Topics

How to Bookmark

Open any topic and click the bookmark icon in the topic action bar (next to the share and report buttons). The icon fills to indicate the bookmark is saved. Click it again to remove the bookmark.

Bookmarking is instant and does not require a page reload. There is no confirmation dialog.

Accessing Your Bookmarks

Two ways to get there, both show the same list:

  • The Bookmarks tab on your profile at /community/u/your-username/
  • A dedicated standalone page at /community/bookmarks/ (new in 1.4.1)

Both list every topic you have bookmarked, most recent first. Each item shows the topic title, the space it belongs to, the author, and when it was posted. Click any item to go directly to the topic.

Bookmarks are private - other members cannot see your bookmark list. The standalone page requires sign-in and is excluded from search engines so the URL itself never reveals what you've saved.

Tip: Use bookmarks as a reading queue - bookmark topics you want to read later, then clear them as you go. The Bookmarks tab gives you a clean list without any algorithm reordering it.

Following Spaces

How to Follow

Visit any space and click the Follow button in the space header. The button changes to Following immediately.

Following a space subscribes you to new post notifications from that space. Every time a new topic is published in a space you follow, you receive a notification in your notification bell.

Unfollowing

Click Following in the space header to toggle it off. The button returns to Follow and you stop receiving new post notifications from that space.

Following a space does not make you a member of the space. In Open spaces, you can follow without joining - you will receive notifications but you will not be listed as a member and cannot post until you join.

What You Get Notified About

When you follow a space, you receive notifications for:

  • Every new topic published in that space (including by authors you do not know)

You do not receive notifications for replies to topics in followed spaces unless you are also subscribed to those individual topics. Following is space-level; subscriptions are topic-level.

Topic Auto-Subscription

When You Create a Topic

When you publish a new topic, you are automatically subscribed to it. You will receive notifications for:

  • Every new reply to your topic (including threaded sub-replies)
  • When your topic is answered and accepted (Q&A spaces)
  • When your topic's idea status changes (Ideas spaces)

When You Reply to a Topic

When you post a reply to any topic, you are automatically subscribed to that topic. You will receive the same notifications as if you had subscribed manually.

Unsubscribing from a Topic

Open the topic and click the ... menu at the top of the page, then select Unsubscribe. You will stop receiving notifications for new replies on that topic.

You can re-subscribe at any time using the same menu.

Managing All Your Subscriptions

Go to your profile's Settings page at /community/u/your-username/edit/ and open the Notifications section.

Here you can:

  • See a list of all spaces you follow with a one-click unfollow option
  • See topics you are subscribed to (the list shows the 20 most recent)
  • Set your notification preference for email delivery (immediate, daily digest, or never)

Note: Daily and weekly email digests are a Jetonomy Pro feature. In the free plugin, email notifications are sent immediately for each event or not at all - based on your notification settings.

What's Next?

Learn how to save work-in-progress posts as drafts and schedule topics for future publication.

Drafts & Scheduled Posts →

Not every post is ready to publish the moment you start writing it. Drafts let you save work-in-progress posts and come back to them later. Scheduled posts let you write now and publish at a specific date and time automatically.

Post composer with draft and schedule publishing options

What You Will Learn

  • How to save a post as a draft
  • Where to find and manage your drafts
  • How to schedule a post for future publication
  • How the draft/schedule split-button UI works
  • How scheduled posts are published and what happens if the window is missed

Saving a Draft

When you are composing a new topic and want to save your progress without publishing:

  1. Write your title and content as usual.
  2. Click the arrow next to the main Post button to expand the split-button menu.
  3. Select Save as Draft.

Your draft is saved immediately and you are returned to the space listing. No notification is sent to other members. The topic does not appear in the space listing.

Tip: Press Ctrl+Enter (Windows/Linux) or Cmd+Enter (Mac) to trigger the composer's primary action without reaching for the mouse. This clicks the split-button's current primary button - for a new post that submits it; while editing a draft it runs whichever action the button currently shows.

Finding Your Drafts

Two ways to get there, both show the same list:

  • The Drafts tab on your profile at /community/u/your-username/
  • A dedicated standalone page at /community/drafts/ (new in 1.4.1)

Your drafts are listed in order of last-modified time, most recent first. The standalone page requires sign-in and is excluded from search engines, so unfinished work never leaks. Each draft shows:

  • The post title (or "Untitled Draft" if you have not written a title yet)
  • The space it is intended for
  • When you last saved it

Click any draft to reopen the full composer with your saved content. Make your changes, then publish or save again.

Drafts are private. Only you and site admins can see your drafts.

Drafts and Post Counts

Draft posts do not count toward any community statistics until they are published:

  • They do not increment the space's post count.
  • They do not appear in the space listing.
  • They do not appear in search results.
  • They do not appear on your public profile's Posts tab.

The moment a draft is published, either manually or via scheduled publishing, all of the above update immediately.

Scheduling a Post

You can schedule a post to publish automatically at a specific future date and time:

  1. Write your title and content.
  2. Click the arrow next to the Post button to expand the split-button menu.
  3. Select Schedule.
  4. A date and time picker appears. Choose when you want the post to go live.
  5. Click Schedule Post.

The post is saved with a Scheduled status. It does not appear publicly until the scheduled time.

Scheduled posts appear in your Drafts tab with a "Scheduled" label and the publish date/time displayed. You can click into a scheduled post to edit the content or change the publish time at any point before it goes live.

To cancel a scheduled post and convert it back to a draft, open it and click Unschedule.

How Scheduled Publishing Works

Jetonomy publishes scheduled posts through Action Scheduler - the same background queue that powers WooCommerce - which runs its own queue runner rather than relying purely on page views. The check runs every hour. (WP-Cron remains a legacy fallback for older installs.)

This means a post scheduled for 9:00 AM may publish at any point during the following hour rather than exactly on the minute.

If a post's scheduled time is missed (for example, because the queue did not run during a low-traffic period), Jetonomy will publish it on the next run. It never silently drops a scheduled post.

The Split-Button UI

Post composer publish split-button expanded, showing Save as Draft and Schedule options with the date and time picker open

The publish button in the post composer is a split button:

  • Left side: The primary action (defaults to Post Now for new posts, Update for existing drafts).
  • Right side (arrow): Opens the options menu with Save as Draft, Schedule, and any other contextual actions.

The left side updates based on context. When you are editing a draft, the left side shows Publish Now and the right side shows options to reschedule or keep as draft.

What's Next?

Learn the full set of moderation tools available to space moderators: moving, merging, splitting, pinning, closing, and deleting topics.

Topic Management →

Space moderators have a full toolkit for organizing, curating, and controlling discussions. Every action in this guide requires moderator permission on the space where the topic lives - or site-wide admin access.

Admin moderation panel with content review and bulk action controls

What You Will Learn

  • How to move a topic to a different space
  • How to merge duplicate topics
  • How to split a reply into a new topic
  • How to pin and unpin topics
  • How to close and reopen topics
  • How to delete topics

Who Can Use These Tools

All moderation actions described here require one of the following:

  • Space Moderator role in the space where the topic lives
  • Space Admin role in that space
  • WordPress Administrator (can moderate any space)

Regular members do not see moderation options in the menus, even if they are the topic author. Topic authors can edit and delete their own posts, but not pin, close, move, merge, or split them.

Moving a Topic to a Different Space

Use this when a topic was posted in the wrong space - for example, a bug report in a General Discussion space that belongs in a Support space.

  1. Open the topic.
  2. Click the ... menu at the top right of the topic.
  3. Select Move Topic.
  4. A modal appears with a searchable space picker. Type to filter spaces by name.
  5. Select the destination space.
  6. Click Move.

The topic disappears from the original space immediately and appears at the top of the destination space's listing. Its URL changes to reflect the new space slug. The old URL redirects to the new one automatically.

All replies, votes, bookmarks, and subscriptions move with the topic. Nothing is lost.

Tip: If you move a Q&A topic from a Q&A space into a Forum space, the accepted answer marking is preserved in the database, but the "Accepted" badge may not render in the Forum space depending on your display settings.

Merging Duplicate Topics

Use this when two members post the same question or idea in the same space. Merging moves all replies from the source topic into the target topic and deletes the source.

  1. Open the topic you want to remove (the duplicate).
  2. Click the ... menu and select Merge Topic.
  3. A modal appears with a search field. Search for the target topic by title.
  4. Select the target topic.
  5. Click Merge.

All replies from the duplicate are appended to the target topic's reply list in chronological order. The source topic is permanently deleted - it is not moved to trash. A moderator note is added to the target topic indicating that replies were merged from another topic.

Warning: Merging cannot be undone. Verify you have selected the correct target topic before confirming.

Splitting a Reply Into a New Topic

Use this when a reply inside a topic starts a new conversation that deserves its own thread.

  1. Find the reply you want to split.
  2. Click the ... menu on that reply.
  3. Select Split to New Topic.
  4. A modal appears asking for the new topic title.
  5. Enter the title and click Split.

Jetonomy creates a new topic in the same space with your chosen title. The selected reply becomes the first post content of the new topic. All sub-replies (direct children of that reply) move with it.

The original reply is removed from the source topic. A moderator note appears in the source topic: "A reply was split into a new topic: [title with link]."

Pinning and Unpinning Topics

Pinned topics appear at the top of the space listing, above all other topics, regardless of which sort tab is selected (Latest, Popular, or Unanswered). Use pinning for space rules, important reference threads, or a "start here" topic. Pinning here affects only this space - to feature a post across the whole community, see Community Announcements (Pro, admins only).

  1. Open the topic.
  2. Click the ... menu and select Pin.

The topic moves to the top of the listing immediately and shows a green Pinned badge - on both the listing row and the topic's own header - so members can see at a glance that it is pinned.

To unpin, open the same menu and select Unpin.

Each space allows up to 3 pinned topics by default. Once the limit is reached, pinning another topic returns "You can pin up to 3 topics in a space. Unpin one first." The cap keeps the top of the space scarce and meaningful; developers can change it with the jetonomy_max_space_pins filter.

Closing Topics

Closing a topic prevents new replies while keeping all existing content visible and readable. Use this when a question has been answered, a discussion has run its course, or a thread is becoming unproductive.

  1. Open the topic.
  2. Click the ... menu and select Close Topic.

Closed topics show a banner: "This topic is closed. No new replies can be added."

The reply composer is hidden for regular members. Moderators and admins can still reply to closed topics.

To reopen a topic, click the ... menu and select Reopen Topic.

Deleting Topics

Deleting a topic moves it to trash. It disappears from the space listing and is no longer accessible to members. The space's post count decrements.

  1. Open the topic.
  2. Click the ... menu and select Delete Topic.
  3. Confirm the deletion in the prompt.

Deleted topics can be recovered by a site admin from Jetonomy → Content in the WordPress admin - filter by status "Trash" to find them. A trashed topic can be restored or permanently deleted.

Permanent deletion removes the topic, all replies, all votes, all bookmarks, and all associated notifications from the database. It cannot be undone.

Note: When you delete a topic, the topic author's reputation is reduced (a default of 20 points) to reflect the removed content. The penalty amount is admin-configurable under Settings → Permissions → Reputation Points.

What's Next?

Return to the Spaces & Categories section to learn about managing space membership and access rules.

Membership & Join Policies →

Two features that give you finer control over individual topics - mark sensitive topics private so only you and moderators can see them, and use colored prefixes to classify topics at a glance in the space listing.

What You Will Learn

  • How to mark a topic as private and who can read it
  • How to enable topic prefixes for a space
  • How to create, edit, and color prefixes
  • How prefixes appear in the space listing and topic page
  • When to choose a private topic over a private space

Private Topics

A private topic is visible only to its author and to space moderators. Other members of the space cannot see it in the listing, cannot find it through search, and cannot open its URL directly - they receive a "not found" response instead.

Use private topics for:

  • Support requests that include account details, order numbers, or personal information
  • Reports of abuse or harassment where naming the other member in public would escalate the situation
  • Personal asks to a space owner that do not need a full private message thread
  • Sensitive billing or legal questions where a full support ticket is too formal

Enabling Private Topics on a Space

Private topics are an opt-in feature per space. The space owner turns them on from Jetonomy → Spaces → (your space) → Settings → Posting.

  1. Toggle Allow private topics on.
  2. Save.

If the setting is off, the Private toggle does not appear in the new post composer and members cannot create private topics in the space.

Creating a Private Topic

When the feature is enabled for a space, a Private toggle appears at the bottom of the new post composer. Turn it on before submitting and your topic is flagged as private.

Private topics show a Private badge next to the title on the topic page. The badge is visible only to you and to moderators (other members cannot see the topic at all).

Who Can See Private Topics

Role Can see private topics?
Topic author Yes
Space moderators Yes
Space owner Yes
WP admins Yes
Other space members No
Logged-out visitors No

A moderator can reply to a private topic, mark it resolved, or escalate it to a full support ticket using whatever workflow your community has. The topic author is notified of replies the same way they would be on a normal topic.

Note: Private topics are different from private spaces. A private space is hidden entirely - a member either has access to everything in it or nothing at all. A private topic is a one-off exception inside an otherwise public space. Pick private spaces for ongoing confidential work (staff lounges, paying customer lounges) and private topics for one-off sensitive conversations.

Topic Prefixes

Prefixes are colored labels that appear in front of topic titles in the space listing. They let members classify topics at a glance - Bug, Question, Solved, Announcement, Discussion, and so on.

Prefixes are configured per space by the space owner. Different spaces can have entirely different prefix sets - a support space might use Bug, Question, Solved, while a marketing space might use Idea, Campaign, Report.

Enabling and Creating Prefixes

Go to Jetonomy → Spaces → (your space) → Settings → Prefixes.

  1. Toggle Enable topic prefixes on.
  2. Click Add Prefix.
  3. Type a short label (up to 20 characters).
  4. Pick a color from the palette, or enter a custom hex value.
  5. Save.

Repeat for each prefix you want. Re-ordering a prefix in the admin changes its order in the composer picker. Prefixes you no longer need can be deleted - topics that used a deleted prefix revert to having no prefix.

Using a Prefix When Creating a Topic

When prefixes are enabled for a space, a Prefix dropdown appears next to the title field in the new post composer. Members pick one prefix per topic, or leave it blank.

If the space is configured with Require prefix enabled, the composer rejects the submission unless a prefix is selected.

Where Prefixes Appear

  • In the space listing next to the topic title
  • On the topic page, in the topic header above the title
  • In search results
  • In notification emails that reference the topic
  • In the admin moderation queue

Filter the space listing by prefix by clicking any prefix label - the listing re-renders to show only topics with that prefix.

Prefix Color Guidelines

  • Use high-contrast colors for critical prefixes (Bug in red, Announcement in blue)
  • Use muted colors for passive prefixes (Discussion in grey)
  • Avoid using green except for Solved or Done - green is a strong "resolved" signal
  • Avoid using red except for critical prefixes - red grabs attention

What's Next?

Return to Creating Topics for a full walkthrough of the new post composer, or continue to the next discussion guide.

The composer is the box you type in when you create a new post or reply. It works like a modern community tool, not a plain comment form. Members can @mention each other, see at a glance which threads have new replies, and find out who runs a space and who on staff is replying. This guide covers each of those features and how they behave for the member.

What You Will Learn

  • How @mention autocomplete works in posts and replies
  • What the "New" pill on the topic card means and when it clears
  • How the "Managed by" sidebar surfaces space admins and moderators
  • Where role pills appear and what they tell members
  • How link previews turn a pasted URL into a rich card
  • How members add images, and which capability gates uploads
  • How the composer's formatting toolbar and markdown shortcuts work

@mention Autocomplete

Type @ anywhere in the composer and Jetonomy opens a dropdown of matching people. Keep typing to narrow the list, then click a result or press Enter to insert the mention.

The inserted mention is a clickable link to the user's profile, and the moment your post or reply is published, Jetonomy fires a notification to the mentioned member. They see it in the bell menu and, if they have email notifications on, in their inbox.

Where It Works

Surface Mentions supported
New post composer Yes
Reply composer Yes
Edit post / edit reply Yes
Private message composer (Pro) Yes
Quick reply on a topic card Yes

Who Shows Up in the Dropdown

The dropdown is scoped to people the current user shares at least one space with. This keeps the list relevant on large communities and avoids leaking member names across private spaces. Within that scope, results are ordered by:

  1. Recent contributors in the current space (they are most likely to be relevant)
  2. Other members of the current space
  3. People you share other spaces with

If you start typing a name that does not match anyone in your shared spaces, the dropdown shows "No matches" rather than searching the whole site.

Walkthrough: Mentioning a Member in a Reply

  1. Open any topic and start a reply.
  2. Type @ followed by the first few letters of the person's name or username.
  3. The dropdown appears under your cursor with up to 10 matching members.
  4. Use the arrow keys to highlight a name, or click directly.
  5. Press Enter (or click) to insert the mention.
  6. Publish the reply. The mentioned member receives a notification within seconds.

Notes on Privacy

  • Mentions in a private space still notify the mentioned member, but the linked post is only visible to people who can read that space.
  • Mentioning a member who has muted you still inserts the link, but no notification is sent.
  • Site admins can disable mention notifications globally in Jetonomy → Settings → Notifications.

"New" Pill on Unread Threads

The space listing shows a card for each topic. When a topic has replies you have not read yet, a small "New" pill appears on the card.

The pill is intentionally subtle. It uses the --jt-accent design token, so it picks up your theme's brand color and matches dark mode automatically.

When the Pill Appears and Clears

Event Pill state
Someone replies to a thread you previously read Pill appears
You open the thread Pill clears immediately
You scroll past the thread without opening it Pill stays
The original poster edits their post (no new replies) Pill does not appear
You are not signed in Pill never appears (read state is per-user)

The pill is driven by the same read-status table that powers the unread indicator in the bell menu. There is no separate setting to toggle it. If you do not want unread tracking at all, disable read tracking in Jetonomy → Settings → Performance.

Mobile Behavior

On mobile the pill sits at the top-right of the card, sized for thumb readability without crowding the title. It uses the same touch target as the rest of the card, so tapping anywhere on the card opens the thread and clears the pill.

"Managed by" Sidebar Card

Space sidebar "Managed by" card listing the space admins and moderators with avatars and role badges

Every space page now shows a "Managed by" card in the sidebar. The card lists the space admin(s) and moderator(s) with their avatars and a small role badge next to each name.

What the Card Shows

  • Up to 5 staff members per space, sorted with admins first, then moderators
  • Each entry shows: avatar, display name, role badge
  • Hovering an entry reveals a "View profile" link
  • If the space has private messaging enabled (Pro), a "Message" link appears as well

If a space has more than 5 staff, the card shows the first 5 and a "See all staff" link that opens the full member list filtered to staff only.

Why This Helps Members

Members often want to ask a question, report a problem, or appeal a moderation action but don't know who to talk to. The "Managed by" card answers that question on every space page, without forcing members to dig through settings or member lists.

For owners, this surfaces your community staff and gives them visibility. Members are more likely to recognise and trust moderators they see consistently.

Customizing the Card

The card is rendered from templates/partials/managed-by-card.php. You can override it in your theme at theme/jetonomy/partials/managed-by-card.php to change the layout, hide certain roles, or add extra links.

Role Pills on Posts and Replies

In addition to the sidebar card, admins and moderators now have role pills next to their name on every post and reply they make. The pill is small, accessible, and uses theme tokens for color.

Role Pill label Pill style
Community Admin "Admin" Filled, accent color
Space Moderator "Mod" Outline, accent color
Member (no pill) n/a

The pills are visible to everyone, including signed-out visitors. They make it obvious when an answer comes from staff vs from another member, which matters for support spaces and Q&A spaces where members weigh staff replies more heavily.

Paste a URL on its own line in a post or reply and Jetonomy automatically fetches the page's metadata and renders a rich preview card beneath it, the same style of card you see when you share a link on LinkedIn or Twitter. Members get context (title, description, thumbnail, site name) without leaving the thread.

How It Works

When a link sits alone on its own line (not inline inside a sentence), Jetonomy calls GET /jetonomy/v1/link-preview?url=... and renders the result as a card. The card shows:

  • Thumbnail image (when the page provides one)
  • Page title
  • Short description
  • Site name and favicon

The preview endpoint pulls metadata from Open Graph and Twitter Card tags, so it covers almost any site with social tags (news outlets, blogs, GitHub, LinkedIn, Instagram, Facebook, and more). For the major sanctioned oEmbed hosts (YouTube, Vimeo, TikTok, Spotify, SoundCloud, Reddit, and the rest of the WordPress oEmbed registry) it returns a true rich embed instead of a static card.

Behavior and Limits

  • Up to 3 preview cards render per post or reply, so a message full of links does not turn into a wall of cards.
  • Results are cached on the server (roughly 12 hours for a successful fetch, a few minutes for a failed one), so a 200-reply thread does not refetch the same link 200 times.
  • Mentions (@name) and tag links never turn into preview cards, only standalone web URLs do.

Developers can customize how link previews are fetched and rendered - see Developer Notes at the end of this guide.

Media Uploads

The composer lets members add images to posts and replies in three ways:

  • Toolbar button - click the image button in the composer toolbar to open a file picker.
  • Drag and drop - drag an image straight from your desktop onto the editor.
  • Paste - paste a screenshot or copied image directly from your clipboard.

Uploads go to POST /jetonomy/v1/media, which stores the file as a standard WordPress attachment and returns its URL so the image drops into the editor inline. Every uploaded image is given alt text automatically (derived from the file name) for accessibility and SEO, and members can supply their own alt text.

Who Can Upload

In practice, most members who can post or reply can also attach images. Members who can already upload to your WordPress media library can attach images, and members earn the ability to upload automatically once they reach Trust Level 1, even if their WordPress role would not otherwise allow it. So a brand-new member may not be able to attach an image on their very first day, but gains it as soon as they reach Trust Level 1.

Developers who need the exact capability list can find it under Developer Notes.

The Formatting Toolbar

The composer is a single rich-text editor with a small formatting toolbar - there is no separate "plain text" vs "WYSIWYG" mode to choose between. The toolbar buttons are: bold, italic, inline code (</>), link, blockquote, and image upload.

Members who prefer to type can also use common markdown shortcuts (**bold**, *italic*, `code`, > quote) directly in the editor. The toolbar and the markdown shortcuts produce the same formatted result.

Paste handling, image uploads, and @mention autocomplete all work the same way regardless of whether you click a toolbar button or type the markup yourself.

For more on the content editor and its fields, see Creating Topics.

Developer Notes

These details are for developers extending the composer. Site owners and members do not need them.

The link preview pipeline is fully filterable:

Filter Purpose
jetonomy_link_preview_providers Add or reorder host-specific providers (e.g. a custom intranet URL rewriter) ahead of the defaults
jetonomy_link_preview_data Final mutation of the preview data right before it is cached and returned
jetonomy_link_preview_cache_ttl Override the cache lifetime, in seconds
jetonomy_link_preview_user_agent Override the user agent used when fetching the page (some corporate firewalls only allow specific agents)

Media upload capabilities

Uploading is gated by capability. A member can upload media if they have any one of:

  • upload_files - the standard WordPress capability (Author and above)
  • jetonomy_upload_media - the Jetonomy role-map capability, granted to the Contributor role and automatically granted at Trust Level 1
  • jetonomy_create_posts or jetonomy_create_replies - anyone who can post or reply

Uploads go to POST /jetonomy/v1/media, which stores the file as a standard WordPress attachment and returns its URL.

What's Next?

Learn how Jetonomy's in-product modal toolkit replaces native browser dialogs with accessible, themeable confirmations.

Modals and Confirmations

Jetonomy 1.4.0 introduced an in-product modal toolkit that replaces the native browser confirm, alert, and prompt dialogs across the community. Native browser dialogs look like operating system pop-ups, cannot be themed, and don't follow modern accessibility patterns. The Jetonomy modals are themed, keyboard-accessible, and localised. The 1.4.2 retag completed full translation coverage for the button labels.

What You Will Learn

  • What the modal toolkit replaces and why
  • Where you'll see Jetonomy modals in the community
  • How the modals handle accessibility and keyboard navigation
  • How button labels translate for non-English sites
  • How dark mode and theme colors are picked up automatically
  • How to override the modal styling in your theme

What the Toolkit Replaces

JavaScript has three built-in dialog functions:

  • window.confirm("Are you sure?") returns true / false
  • window.alert("Done.") shows an info message
  • window.prompt("Reason?") asks for a text input

These look like system pop-ups. They sit outside your theme, look different on every operating system and browser, can't be styled, and don't return focus to the right element when dismissed. Screen readers treat them inconsistently, and keyboard navigation is at the mercy of the browser.

Jetonomy now uses its own modal toolkit for every "Are you sure?" prompt across the plugin. The modals look like your community, behave consistently, and play nicely with screen readers and keyboards.

Themed danger confirmation modal reading "Delete this post?" with a red Delete button and a Cancel button

Where You'll See Jetonomy Modals

Anywhere the community needs to confirm an action or collect a short answer:

Action Modal type
Delete a post or reply Confirm
Remove a flag without taking action Confirm
Ban or silence a member Prompt (asks for duration / reason)
Lift a ban Confirm
Move a topic to another space Prompt (asks for target space)
Split a reply into a new topic Prompt (asks for new topic title)
Pin or unpin a topic Confirm
Mark all notifications read Confirm
Trash a category Confirm
Approve or reject pending content Confirm
Cancel an unsaved edit Confirm

The pattern is consistent: destructive actions always require a confirmation, prompts that need an answer always show a clear input field with sensible defaults.

The toolkit exposes three modal types:

  • Confirm - two buttons (Cancel / Confirm). For yes/no decisions
  • Alert - one button (OK). For one-way info or success messages
  • Prompt - text input plus two buttons (Cancel / Submit). For collecting a short answer

Each type uses the same overlay and box, so the visual style is uniform across the community.

Accessibility

The toolkit is built to WCAG 2.1 AA. Every detail that screen reader users and keyboard users rely on is wired up:

Feature Behaviour
Keyboard open Focus moves to the first focusable element in the modal
Tab cycling Focus stays trapped inside the modal until it closes
Escape key Dismisses the modal, equivalent to clicking Cancel
aria-labelledby Points to the modal title element
aria-describedby Points to the modal body text
role="dialog" Set on the modal box
aria-modal="true" Tells assistive tech the rest of the page is inert
Focus return When the modal closes, focus returns to the element that opened it
Overlay click Closes the modal (configurable, off for destructive prompts)

Screen reader users hear the modal title and body when it opens. Keyboard users can tab through the controls without escaping the dialog. Mouse users can dismiss by clicking the overlay, except on destructive prompts where overlay dismiss is intentionally disabled to prevent accidental data loss.

Reduced Motion

If the visitor's operating system has "Reduce motion" enabled, the modal skips its slide-in and fade animations. The dialog still opens and closes; it just appears and disappears instead of animating. This respects vestibular accessibility preferences without compromising functionality.

Localisation

All button labels translate through the standard WordPress translation pipeline:

English label Used in
Cancel Every modal
Confirm Confirm modals
OK Alert modals
Submit Prompt modals

Modal titles and body text are localised by the calling code (e.g. "Delete this post?" is translated by the delete action that opens the modal). The toolkit itself only contributes the four button labels above.

The 1.4.2 retag completed full translation coverage for every label. Before that retag, English fallbacks could leak into translated locales for one or two of the buttons. Sites running a translated locale (French, German, Spanish, Arabic, etc.) now see fully translated buttons everywhere.

Dark Mode

The modal box and overlay both use Jetonomy design tokens. That means:

  • Dark theme active → modal renders dark automatically
  • Light theme active → modal renders light
  • Theme brand color → primary button picks it up
  • Theme border radius → modal corners match

No per-theme configuration required. If your theme defines a custom --jt-bg or --jt-accent, the modal picks it up.

Styling Override

Site owners who want a custom look can override the modal styles in their theme stylesheet. The relevant classes are:

Class Element
.jt-modal-overlay The backdrop behind the modal
.jt-modal-box The modal container
.jt-modal-title The title heading inside the modal
.jt-modal-body The body text or prompt input wrapper
.jt-modal-actions The button row at the bottom
.jt-modal-button Both buttons (Cancel / Confirm)
.jt-modal-button--primary The primary (right-hand) button
.jt-modal-button--secondary The Cancel (left-hand) button

Example: dimming the overlay further for a more cinematic feel.

.jt-modal-overlay {
  background: rgba(0, 0, 0, 0.7);
}

Example: making the modal a bit wider on desktop.

@media (min-width: 768px) {
  .jt-modal-box {
    max-width: 560px;
  }
}

We recommend overriding tokens (e.g. --jt-bg, --jt-radius) at the modal level rather than rewriting properties directly, so dark mode and theme switching keep working.

Developer Note

The toolkit exposes three global functions for any custom JavaScript that integrates with Jetonomy. Each returns a Promise.

The message is always the first argument; an options object follows.

// Yes/no confirmation
const confirmed = await window.jetonomyConfirm( 'This cannot be undone.', {
  title: 'Delete this post?',
  confirmLabel: 'Delete',
  danger: true,
} );

// One-button info dialog
await window.jetonomyAlert( 'Your changes are live.', {
  title: 'Saved',
} );

// Text input prompt
const reason = await window.jetonomyPrompt( 'Tell our moderators what is wrong.', {
  title: 'Why are you reporting this?',
  placeholder: 'Reason',
} );

The danger: true flag styles the confirm button in red and disables overlay-click dismiss. Useful for delete confirmations and account actions.

These are pure JS globals; you don't need to import anything if jetonomy is already enqueued on the page.

What's Next?

Learn how the activity log tracks every audit-worthy event in your community.

Activity Log

Members normally start a topic from inside a space. But you can also drop a "start a topic" box onto any WordPress page, post, or landing page - so a visitor can begin a discussion without first navigating into the community. Jetonomy gives you two ways to do this, and both produce the same box: a Gutenberg block and a shortcode.

Compose Topic box embedded on a regular WordPress page, with a space picker, title field, and details field

What You Will Learn

  • Where the embedded composer is useful
  • How to add it with the Compose Topic block (Gutenberg)
  • How to add it with the [jetonomy_compose_topic] shortcode (Classic editor and page builders)
  • The difference between "picker" mode and "fixed" mode
  • What logged-out visitors see

When to Use It

The embedded composer is handy when you want members to start a discussion from outside the community pages, for example:

  • A "Ask the community" box on your homepage or a landing page
  • A support page that drops members straight into your Support space
  • A product page that invites feedback into an Ideas space

Adding It with the Block (Gutenberg)

  1. Edit any page or post in the WordPress block editor.
  2. Click the + (Add block) button.
  3. Search for Jetonomy Compose Topic and insert it.
  4. In the block sidebar, choose how the box behaves (see Picker vs Fixed Mode below).
  5. Publish or update the page.

Adding It with the Shortcode

If you use the Classic editor, a widget, or a page builder (Elementor, Divi, Bricks, WPBakery), use the shortcode instead. It produces an identical box.

[jetonomy_compose_topic mode="picker"]
[jetonomy_compose_topic mode="fixed" space_id="5"]

The block and the shortcode are interchangeable - either surface works and they render the same composer, so pick whichever fits your editor.

Picker vs Fixed Mode

The composer has two modes, set with the mode attribute (block sidebar control or shortcode attribute):

Mode What it does
Picker (default) Shows a space dropdown so the member chooses which space their topic lands in. Only spaces where the member is allowed to post appear in the list.
Fixed Locks the box to one space - no dropdown. Use this on a page that is clearly about a single topic area (e.g. a Support page that always posts into the Support space). Set the space with space_id (the Space ID to post into control in the block).

If you choose Fixed mode but the space is missing or the member cannot post in it, the box quietly falls back to Picker mode rather than showing an error.

Limiting the Post Types

The types attribute controls which kinds of topic the box can create. By default it allows topic,question,idea. Remove any you do not want to offer on that page. (The actual post type a member ends up creating still follows the space type - see Creating Topics.)

What Logged-Out Visitors See

If a visitor is not signed in, the box does not show a form. Instead it shows a "Sign in to start a new topic" prompt that returns them to the same page after they log in. There is no exposed form for signed-out visitors, so you can safely place the composer on a public page.

Search & Discovery

Find content with full-text search, tags, and filters.

Jetonomy's search finds content across your entire community in real time - topics, spaces, and tags - and lets you narrow results with powerful filters so members always land on exactly what they need.

What You Will Learn

  • How to run a full-text search from anywhere in the community
  • What the filter pills do and how to use them
  • How advanced filters refine results by date, author, tag, and sort order
  • How to show and hide the filter bar
  • How developers can extend search filters with a custom hook

The search bar sits in the community navigation, visible on every page. Type any keyword and press Enter or click the search icon. Jetonomy searches across:

  • Topic titles and content
  • Space names and descriptions
  • Tag names

Results appear on the search results page at /community/search/. Each result card shows the content type, the space it belongs to, the author, the date, and a short excerpt with your search term highlighted.

Search results page

Tip: Every word you type is required (AND), matched as a prefix - searching email digest finds posts containing both email... and digest.... Short words (under 4 characters) are ignored, so lead with the distinctive terms.

Filter Pills

At the top of the results page, four filter pills let you narrow by content type instantly:

Pill Shows
All Every matching result
Posts Topic results only
Spaces Space results only
Tags Tag results only

Click any pill to filter. The URL updates so you can share a filtered search link with your team.

Advanced Filters

Click the Filters disclosure to expand the advanced filter bar. It auto-expands whenever any filter is already active. These filters stack - you can combine them in any combination.

Search page with the Filters disclosure expanded, showing the Date from, Date to, Author, Tag, and Sort order controls

Date Range

Set a Date from and / or Date to date to restrict results to a window. Jetonomy filters by the post's original publish date, not its last reply date.

Author

Type a name or username to filter results to a specific author. Jetonomy resolves it to the matching member when you submit the search (there is no live typeahead). This is useful for reviewing a particular member's contributions or finding your own older posts.

Tag

Type a tag name to restrict results to posts that carry that tag. Combining author and tag filters is a fast way to find all posts by a specific member on a specific topic.

Sort Order

Option Orders by
Relevance Full-text match score (default)
Newest Most recently published first
Most Voted Highest net vote score first

Relevance is the default because it surfaces the best textual match. Switch to Newest when you know you are looking for a recent discussion. Switch to Most Voted when you want the community's highest-rated answer on a topic.

Collapsing the Filter Bar

Click Filters again to collapse the bar. Your active filters remain applied even while the bar is collapsed.

For Developers: Extending Search Filters

To modify the search query itself, use the jetonomy_search_query_args filter. It receives the assembled query arguments (q, space_id, date_from, date_to, author_id, tag_slug, sort) and must return the array.

add_filter( 'jetonomy_search_query_args', function( $args ) {
    // Restrict the query to a specific space.
    if ( ! empty( $_GET['space_id'] ) ) {
        $args['space_id'] = absint( $_GET['space_id'] );
    }
    return $args;
} );

To render extra controls in the filter bar, hook the jetonomy_search_filters action. It is a do_action (it returns nothing) fired just after the filter form, with three arguments: the query string $q, the active $filter pill, and an array of the current filter values.

add_action( 'jetonomy_search_filters', function( $q, $filter, $filters ) {
    // Echo your own markup for an extra filter control here.
}, 10, 3 );

See the Hooks Reference for the full parameter list.

What's Next?

Learn how tags work across spaces and how members can browse tag pages to find related content.

Tags →

  • SEO Pro - per-space meta, schema.org markup, OG/Twitter cards, and sitemaps so search engines surface your community.

Tags connect related discussions across your entire community. A member searching for help with "payments" can click the payments tag and instantly see every relevant topic - no matter which space it lives in.

Tag page listing all topics associated with a specific tag

What You Will Learn

  • How to add tags when creating a topic
  • How tag pills work on topic listings
  • How tag pages bring together content from multiple spaces
  • How the Popular Tags sidebar section helps members discover content
  • Why consistent tagging improves search and community quality

Adding Tags to a Topic

When creating or editing a topic, the Tags field appears below the content editor. Type one or more tag names separated by commas - for example python, django, architecture.

Reuse existing tag names whenever possible - reusing tags makes the tag page more useful for everyone who follows that topic, and matching an existing name (rather than a typo) keeps related posts together.

Tip: In Q&A spaces, good tags are the fastest route to an answer. A question tagged with "payments" and "stripe" will appear on both tag pages, doubling its chance of being seen by someone who can help.

Tag Pills on Topic Listings

Every topic card in a space listing shows its tags as small pills below the title. Clicking a tag pill takes you directly to that tag's page - you do not leave the flow to reach it.

Tags in listings are a fast way to browse by topic without running a search. If a space covers multiple subjects, tag pills help members navigate without scrolling through unrelated posts.

Tag Pages

Every tag has a dedicated page at /community/tag/tag-slug/. The tag page shows all published topics across all spaces that carry that tag, sorted by Latest (newest first) by default.

Members can switch the sort to Popular to find the best content on that topic - Popular orders by net vote score.

Tag pages are publicly accessible by default. If your community is private, tag pages respect the space access rules - topics in private spaces are not shown on tag pages to members who do not have access to those spaces.

The Popular Tags section in the community sidebar lists the most frequently used tags across your community (up to 15), each linking to its tag page with a post count. It appears automatically - there is nothing to configure.

Developers can hide it with the jetonomy_show_sidebar_popular_tags filter:

add_filter( 'jetonomy_show_sidebar_popular_tags', '__return_false' );

To inject custom markup (an ad, a banner, a related-tags block) directly around the Popular Tags section, hook the jetonomy_sidebar_before_popular_tags or jetonomy_sidebar_after_popular_tags actions. Each receives the current space object, or null when the sidebar renders outside a space:

add_action( 'jetonomy_sidebar_after_popular_tags', function ( $space ) {
    // Echo your own markup below the Popular Tags list here.
} );

Headless and app consumers can read the same tag list over REST: GET /jetonomy/v1/tags returns tags ordered by popularity (or alphabetically with ?sort=alphabetical), with a limit of up to 100. See the Hooks Reference for the full parameter list.

How Tags Improve Your Community

Tags work across space boundaries. A tag named "onboarding" can tie together a tutorial in your Guides space, a question in your Q&A space, and a feature idea in your Ideas space. Members following that tag see the full picture regardless of which space each post lives in.

Encouraging consistent tag use - especially in high-traffic spaces - pays dividends in search quality. Jetonomy's full-text search treats tags as a search signal, so well-tagged posts surface higher in relevant queries.

Note: Tags are shared across all spaces. There is one global tag namespace. A tag created in your Support space appears on the same tag page as the same tag used in your Ideas space.

Admin Tag Management

Members create tags on the fly as they post, but admins get a dedicated management screen for the whole global tag namespace at Jetonomy → Tags in the WordPress admin. Managing tags here requires the jetonomy_manage_settings capability.

Jetonomy Tags admin screen: a table of tags with post counts, a bulk-action dropdown, a search box, and the Add New Tag form

The page lists every tag with its post count and gives you these controls:

Action What it does
Add New Tag Create a tag directly from the admin (name, optional slug) without having to post first
Edit Rename a tag or change its slug. The change applies everywhere the tag is used
Delete Remove a single tag. You can force-delete a tag even when posts are still attached to it
Bulk Delete Tick multiple tags, choose Delete from the bulk-action dropdown, and click Apply to clear several at once

The list also has a search box and a per-page picker, and it paginates so it stays fast even on communities with thousands of tags.

Use this screen to clean up duplicate or misspelled tags (for example merging "stripe" and "Stripe" by deleting the stray one), retire tags that are no longer relevant, or pre-create the canonical tags you want members to reuse. Because the namespace is global, an edit or delete here affects every space at once.

What's Next?

Learn how trending surfaces the discussions your community is talking about right now, and how to place a trending list anywhere on your site.

Trending →

Moderation & Trust

Keep your community safe with trust levels and moderation tools.

Jetonomy's trust system automatically promotes reliable members to higher privilege levels as they earn reputation - so you spend less time manually managing who can do what, and your most active members get recognized for their contributions.

Permissions settings with trust level thresholds and promotion rules

What You Will Learn

  • What the six trust levels are and what each one unlocks
  • How members earn reputation points
  • How automatic promotion works
  • How to adjust thresholds in your admin settings
  • How trust badges appear on member avatars

The Six Trust Levels

Jetonomy has six trust levels, numbered 0 through 5. Every new member starts at Trust Level 0. Levels 1 through 3 are earned automatically when a member meets the configured requirements. Levels 4 and 5 are not earned automatically - they are granted manually by an admin.

Promotion to levels 1-3 is based on a combination of activity stats, not a single reputation number. A member must meet every requirement listed for a level to reach it.

Level Name Default Requirements
TL0 Newcomer Automatic on signup
TL1 Member 5 posts, 3 days active, 10 replies received
TL2 Regular 30 posts, 20 days active, 50 reputation
TL3 Trusted 100 posts, 60 days active, 200 reputation
TL4 Leader Manually granted by an admin
TL5 Moderator Manually granted by an admin

What Each Level Unlocks

Trust levels expand what a member can do without moderator intervention.

Capability TL0 TL1 TL2 TL3 TL4 TL5
Create topics Yes Yes Yes Yes Yes Yes
Post replies Yes Yes Yes Yes Yes Yes
Flag content Yes Yes Yes Yes Yes Yes
Upload images No Yes Yes Yes Yes Yes
Edit / delete own posts No Yes Yes Yes Yes Yes
Daily post and rate limit lifted No Yes Yes Yes Yes Yes
Skip CAPTCHA No No Yes Yes Yes Yes
Create new spaces No No Yes Yes Yes Yes
Recategorize and rename others' topics No No No Yes Yes Yes
Moderate content and manage members No No No No Yes Yes
Manage settings, categories, and analytics No No No No No Yes

Each level adds to the one below it - a Trusted member (TL3) keeps everything TL1 and TL2 unlocked and gains the recategorize/rename abilities on top. Note that the higher levels are not just lifted limits: TL2 members can start their own spaces, TL3 members can tidy up the category and titles of any topic, and TL4/TL5 members effectively act as community staff (moderation, member management, and - at TL5 - settings, categories, and analytics).

Space moderators and WordPress admins always have full capabilities regardless of trust level.

Note: "Rate limit lifted" at TL1 refers to the per-day posting caps that apply to brand-new (TL0) accounts - 3 topics, 10 replies, and 5 votes per day by default. Those caps and how to tune them are covered in Anti-Spam Protection → Rate Limiting for New Members.

How Members Earn Reputation

Reputation is updated in real time whenever a qualifying event occurs.

Event Points
Your topic is upvoted +10
Your reply is upvoted +5
Your reply is accepted as an answer (Q&A) +15
Your idea is moved to Planned/Shipped +20
A flag you submitted is confirmed +5
Your topic or reply is downvoted -2
Your post is reported -10
A moderator deletes your content -20

Every point value is editable at Jetonomy → Settings → Permissions → Reputation Points - adjust any action's score without touching code.

Reputation points accumulate on your public profile. The leaderboard ranks members by reputation score - see the Leaderboard doc for details.

Automatic Promotion

A cron job runs twice daily to evaluate all members against the current requirements for levels 1-3. Any member who meets every requirement for the next level is automatically promoted.

Promotion is silent - members are not notified by default. You can add a welcome notification using the jetonomy_trust_level_changed action hook if you want to acknowledge promotions.

Demotion works the same way. If a member's reputation falls below a threshold (for example, because posts were deleted), they are automatically moved back to the appropriate level on the next cron run.

Tip: You can set a member's trust level directly from Jetonomy → Users in the WordPress admin. Find the user and click Change Trust Level, then pick the level. This is a manual override that sets the level immediately - useful for elevating a known expert or correcting an edge case.

Jetonomy Users admin page listing community members with per-row Change Trust Level and Ban / Unban controls

The Jetonomy → Users page is the central place to manage individual members: each row shows the member's trust level, post and reputation stats, and per-row controls to Change Trust Level and to Ban / Unban (covered in Banning Members).

Configuring Thresholds

Go to Jetonomy → Settings → Permissions to adjust the promotion requirements. Each of the three earned levels (1, 2, and 3) has its own row with four inputs: posts, days active, reputation, and replies received. A member must meet every value in a row to reach that level. Changes take effect on the next cron run.

Levels 4 and 5 have no requirement inputs - they are granted manually from Jetonomy → Users and cannot be earned automatically.

Lower requirements make promotion faster and more accessible. Higher requirements make higher trust levels a meaningful achievement. There is no right answer - tune these to the pace and size of your community.

Note: Setting a requirement to 0 removes it as a gate for that level. For example, setting a level's reputation requirement to 0 means members can reach it on activity stats alone.

Trust Badges on Avatars

Each trust level has a colored badge that appears on a member's avatar across topic listings, reply cards, and their profile page. The badge uses the data-jt-tl attribute so you can restyle it in your theme using CSS if needed.

Level Badge Color
TL0 Grey
TL1 Blue
TL2 Green
TL3 Teal
TL4 Purple
TL5 Gold

Why Trust-Based Moderation Beats Manual Role Assignment

In a traditional forum, you manually decide who is a "trusted" member. That does not scale. With Jetonomy's trust system, your community self-selects. Members who contribute quality content earn their way to higher levels automatically. You only need to intervene in edge cases - banning bad actors or manually elevating a known expert to a higher level.

For Developers

Trust and moderation events fire WordPress action hooks you can listen to in a small custom plugin or your theme's functions.php - for example to send a welcome message when a member is promoted, or to log every resolved flag to an external system:

  • jetonomy_trust_level_changed - fires when a member's trust level goes up or down.
  • jetonomy_flag_resolved - fires when a moderator marks a flag valid or dismisses it.
  • jetonomy_sidebar_auth_card - lets you add content to the community sidebar.

The full signatures (parameters and when each one runs) are in the Hooks Reference in the developer guide.

What's Next?

Learn how members can flag content for review and how flagged content reaches the moderation queue.

Flagging & Reporting Content →

Flagging lets any logged-in member report content that breaks your community rules. It is the first step in the moderation pipeline - members surface problems, and your moderators review and act.

Admin moderation dashboard showing flagged content awaiting review

What You Will Learn

  • How to flag a topic or reply
  • How to report an entire member account
  • What information a flag captures
  • What the reason categories mean and where they come from
  • Who can flag content and what the restrictions are
  • What happens to flagged content before a moderator reviews it
  • How flags flow into the moderation queue

How to Flag Content

Every topic and every reply has a ... (more actions) menu. Open it and click Report. A prompt dialog appears asking why you are reporting the content. Type a brief description of the problem - for example, "This contains spam links" or "This is abusive toward another member" - and confirm.

Member reporting a post: the ... menu Report action and the "Why are you reporting this post?" reason prompt

The flag is saved immediately and you receive a confirmation message. The text you type is stored as the flag's description; the member-side report files every flag under the Other reason category, and moderators see that category alongside your description when they review it.

Tip: A good flag reason helps moderators act faster. "Spam" alone works, but "Contains a link to a commercial site unrelated to this community" gives the moderator everything they need without having to investigate.

Who Can Flag Content

Any logged-in member can flag a topic or reply, regardless of their trust level. There is one restriction: you cannot flag your own content.

The flag button is not visible to guests (logged-out visitors). If you want guests to be able to report content, you will need a custom solution - the built-in flagging system requires authentication.

There is no daily limit on flags per member. A member who finds multiple pieces of problematic content can flag all of them.

Reporting a Member

Flagging is not limited to individual posts and replies - a member can also report an entire user account. This is for cases where the problem is the person rather than one piece of content (for example, a member sending unwanted messages or repeatedly causing trouble across many topics).

To report a member, open their profile page (/community/u/their-username/) and click the Report button next to the Message button. A prompt asks why you are reporting the user; type a brief reason and confirm. As with content flags, you cannot report your own account, and the control only appears to logged-in members.

A user report creates a flag the same way a content report does - it is recorded against that member's account, captures your reason text and your name as the reporter, and surfaces in the moderation tools for a moderator to review and act on (for example, by banning the member if the report is justified).

What a Flag Captures

When a flag is submitted, Jetonomy records:

  • The content or member being flagged (a post, a reply, or a user account, with its ID)
  • The member who submitted the flag
  • The reason category and the reason text they entered
  • The timestamp

Moderators see all of this information when they review the flag in the moderation queue.

Reason Categories vs Free Text

When a moderator opens the queue, each flag shows a reason category - one of Spam, Offensive, Off-topic, Harassment, or Other. The built-in Report button that members click always files under the Other category and stores their typed description, so most member-submitted flags you see will be tagged Other with a free-text note.

The other categories (Spam, Offensive, Off-topic, Harassment) come from automated and advanced paths - the REST API, WP-CLI, and Jetonomy Pro's moderation automation - which can file a flag with a specific structured reason. So if you see category chips other than Other in your queue, those flags were raised by an integration or automation rule, not chosen by a member in the standard report dialog.

What Happens to Flagged Content

Flagging alone does not change the visibility of a post or reply. The content stays live and readable by all members until a moderator reviews it and takes action. This is intentional - hiding content automatically on a single flag would allow abuse of the flagging system.

A moderator can then mark the flag Valid (confirming the content breaks the rules, which trashes it) or Dismiss it (marking it unfounded, leaving the content live). See the Moderation Queue guide for the full review workflow.

Note: If the same piece of content receives multiple flags from different members, all flags are grouped under that content item in the moderation queue. Moderators see the total flag count and each individual reason.

Preventing Flag Abuse

Jetonomy does not currently auto-penalize members who submit flags that moderators consistently dismiss. If you have a member who is abusing the flagging system, handle it by adjusting their trust level or banning them from Jetonomy → Users in the WordPress admin.

What's Next?

See how flagged content and posts pending approval appear in the moderation queue, and learn how moderators take action.

Moderation Queue →

The moderation queue is your single dashboard for everything that needs human review - posts waiting for approval, flagged content, and items caught by spam filters. You can action everything from one page without digging through individual topics.

Admin moderation queue with pending items and per-row action controls

What You Will Learn

  • How to access the moderation queue
  • What types of content appear in the queue
  • What actions you can take on each item
  • How per-space moderation differs from global moderation
  • How Akismet-held content appears in the queue
  • Where to ban a member when content-level actions are not enough

Accessing the Moderation Queue

Go to Jetonomy → Moderation in your WordPress admin. The page is also accessible from the frontend at /community/mod/ - WordPress Administrators and users with the jetonomy_moderate capability can access both routes.

The queue shows a count badge on the admin menu item whenever there are items waiting for review.

What Appears in the Queue

The queue is split into four tabbed views, each with a count of how many items it holds:

Pending Posts

These are topics submitted in a space with Require Post Approval enabled. They are not visible to other community members until a moderator approves them.

Each pending item shows the full content, the author, the space it was submitted to, and how long it has been waiting. Items are ordered oldest first so nothing sits in the queue unnoticed.

Automated checks can also route content here. Jetonomy Pro's AI spam detection and moderation rules can place a post or reply into this held "pending" state for review rather than publishing it outright.

Pending Replies

The same as Pending Posts, but for replies awaiting approval in spaces that require it. Replies get their own tab so you can clear topics and replies independently.

Flags

These are live topics and replies that members have flagged for review. Flagged content stays visible in the community until a moderator acts. Each item shows the content, the flag reason(s), how many unique members flagged it, and the timestamp of the most recent flag.

Banned Users

A list of members who are currently banned, with the option to lift each ban. See Banning Members for the full ban workflow.

Available Actions

Actions differ between the pending tabs and the Flags tab.

On Pending Posts and Pending Replies, each item has three buttons:

Action What it does
Approve Publishes the pending post or reply so the community can see it
Spam Marks the content as spam and moves it to trash; updates Akismet's spam training if Akismet is active
Trash Moves the content to trash without marking it as spam

On the Flags tab, each flag row has two buttons:

Action What it does
Valid (Trash) Confirms the flag was justified - the content is trashed and the flag resolved
Dismiss Marks the flag unfounded - the content stays live and the flag is resolved

Tip: Use Spam rather than Trash when content is clearly commercial spam. This trains Akismet for your site, making future auto-detection more accurate.

Per-Space vs Global Moderation

The queue shows content from all spaces by default. Use the Space filter dropdown at the top of the queue to narrow to a single space. This is useful when you have dedicated space moderators - a moderator for your Support space only needs to see Support space items.

Space moderators who do not have global admin access see only their own spaces' items when they visit /community/mod/. They do not see content from spaces they do not moderate.

Frontend moderation dashboard at /community/mod/ as a space moderator sees it, scoped to their own spaces

Fixed in 1.4.1: moderators of multiple spaces now see every queue they own when they visit /community/mod/. Earlier versions could redirect a multi-space moderator away from the dashboard if access checks ran in the wrong order. If you have moderators who report "I can see one space's queue but not the others," update to 1.4.1 and the dashboard will load all of them.

Akismet Integration

If the Akismet Anti-Spam plugin is active and configured on your site, Jetonomy automatically passes new posts and replies through Akismet before saving them. If Akismet marks content as spam:

  • The post or reply is saved with a Spam status (not Pending)
  • It does not appear in the community

Spam-flagged content is set to a Spam status rather than surfaced as a dedicated tab in the moderation screen. The four moderation tabs are Pending Posts, Pending Replies, Flags, and Banned Users.

Note: Akismet integration requires the Akismet plugin to be installed, activated, and connected with a valid API key. Jetonomy does not bundle Akismet - it integrates with it automatically when present.

Banning Members

Approve, Mark as Spam, and Trash all act on individual pieces of content. When a member is repeatedly disruptive, content-level actions are not enough and you need to act on the person instead. The Banned Users tab here shows everyone who is currently banned, with an Unban control on each row.

Banning is a subsystem of its own - three ban types, durations, auto-expiry, and the Jetonomy → Users admin page - covered in full in its own guide.

Banning Members →

What's Next?

Learn about Jetonomy's built-in anti-spam tools - reCAPTCHA, Turnstile, and rate limiting - that reduce how much reaches the moderation queue in the first place.

Anti-Spam Protection →

Spam is the fastest way to kill a community's quality. Jetonomy has multiple layers of protection that work silently in the background - your real members never know they are there.

Anti-spam settings with CAPTCHA provider selection and API key fields

What You Will Learn

  • How to enable reCAPTCHA v3 or Cloudflare Turnstile
  • Where to enter your API keys in the admin settings
  • How trusted members are automatically exempted from CAPTCHA
  • How Akismet integration catches spam that passes CAPTCHA
  • How rate limiting protects against new-member spam floods

Choosing a CAPTCHA Provider

Go to Jetonomy → Settings → Anti-Spam to configure your CAPTCHA provider.

Jetonomy supports two providers:

Provider Type User friction
Google reCAPTCHA v3 Score-based, invisible None - runs in background
Cloudflare Turnstile Challenge-based, invisible None - usually auto-passes

Both are invisible to real users. reCAPTCHA v3 assigns a bot-likelihood score and blocks low-scoring submissions. Cloudflare Turnstile analyzes browser signals and shows a challenge only when it cannot verify the user automatically.

Choose Cloudflare Turnstile if your community has members who are privacy-conscious or who block Google services. Both providers have free tiers sufficient for most communities.

Setting Up reCAPTCHA v3

  1. Go to google.com/recaptcha and create a v3 site.
  2. Add your domain to the allowed domains list.
  3. Copy the Site Key and Secret Key.
  4. In Jetonomy → Settings → Anti-Spam, select reCAPTCHA v3, paste both keys, and click Save.

Setting Up Cloudflare Turnstile

  1. Log in to your Cloudflare dashboard and go to Turnstile.
  2. Add a site and set the widget mode to Invisible.
  3. Copy the Site Key and Secret Key.
  4. In Jetonomy → Settings → Anti-Spam, select Cloudflare Turnstile, paste both keys, and click Save.

Note: After saving, Jetonomy automatically loads the CAPTCHA script on the post and reply forms. You do not need to add any code to your theme.

Trusted Members Skip CAPTCHA

Members at Trust Level 2 and above never see or trigger a CAPTCHA check. Jetonomy bypasses the verification entirely for them - the API call is never made.

This means your most active, trusted members post without any friction while new accounts get verified. As members earn reputation and cross the TL2 threshold, they transition out of CAPTCHA checks automatically.

Akismet Integration

If the Akismet plugin is active on your site, Jetonomy sends every new post and reply through Akismet's spam detection API as a second layer of protection. Content that passes CAPTCHA but that Akismet marks as spam is held in the moderation queue rather than published.

See the Moderation Queue guide for how to review Akismet-held content.

Akismet and CAPTCHA work independently. You can run both at the same time for maximum protection, or use either one alone.

AI-Powered Spam Detection (Pro)

Jetonomy Pro's AI extension adds a third layer: a language model reads every new post and reply and scores it for spam probability before it is published. Posts above the configured threshold go to the moderation queue with a reason the model generated. Posts below it are published as normal.

This catches the kinds of spam that pattern matching and Akismet miss - subtly rewritten affiliate spam, contextually wrong replies designed to pad posting history, and coordinated attacks that use clean accounts.

Run the detection through any supported provider - OpenAI, Anthropic, a custom endpoint, or self-hosted Ollama (which keeps all content on your own server). See AI Integration for setup.

AI spam detection stacks on top of CAPTCHA, Akismet, and rate limits - not instead of them. Each layer catches different threats.

Rate Limiting for New Members

Trust Level 0 members (brand-new accounts) are subject to posting rate limits regardless of CAPTCHA:

Content type Default limit
Topics per day 3
Replies per day 10
Votes per day 5

Limits reset after 24 hours. Members at Trust Level 1 and above are exempt from all rate limits.

You can adjust the default thresholds at Jetonomy → Settings → Permissions. Setting a limit to 0 disables it for that trust level.

Tip: Rate limiting is your best defense against coordinated spam from many new accounts. Even if a bot farm passes CAPTCHA, each account can only post 3 topics before hitting the daily limit.

Rate Limit Settings

These rate limits live alongside the trust system. The per-day caps shown above are the Trust Level 0 defaults; every trust level above TL0 is exempt. See Trust Levels for how a member graduates out of rate limiting by earning their way to TL1, and where the "Rate limit lifted" capability fits in the wider trust ladder.

What's Next?

When spam prevention is not enough and you need to act on a specific member, the next guide covers banning.

Banning Members →

Approving, marking as spam, and trashing all act on a single piece of content. Banning acts on the person. When a member is not just posting one bad item but is repeatedly disruptive - or is a confirmed bad actor - you ban the account so they cannot keep posting. This guide covers the three ban types, how long a ban lasts, and where to manage bans.

Jetonomy Users admin page listing community members with per-row Ban / Unban and Change Trust Level controls

What You Will Learn

  • Where to ban and unban members
  • The three ban types and when to use each
  • How ban durations work, including automatic expiry
  • How to lift a ban early
  • Who is allowed to ban members

Where to Manage Bans

You ban and unban members from the Jetonomy → Users page in the WordPress admin. The page lists every community member with their trust level and stats, and gives each row a Ban / Unban control (plus a quick Silence link). Currently banned members also appear on the Banned Users tab of the Moderation Queue, where you can lift each ban.

Banning requires the jetonomy_moderate capability - the same capability that gates the moderation queue itself. WordPress administrators and Trust Level 4+ members have it by default.

The Ban Dialog

Clicking Ban on a member's row opens the Ban User dialog with three choices:

Ban Types

Jetonomy supports three levels of restriction so the response fits the situation:

Type Effect
Global Ban The member is blocked from posting anywhere in the community
Space Ban The member is blocked from a single space but can still participate elsewhere
Silence The member can still read everything but cannot post or reply anywhere

Tip: The Silence quick-link on each user row opens this same dialog pre-set to the Silence type with a 7-day duration - a fast way to cool down a heated member without a full ban.

Duration

Pick how long the ban lasts from the Duration selector:

Duration Effect
Permanent The ban stays in place until you lift it manually
1 Day Lifts automatically 1 day after it is applied
7 Days Lifts automatically 7 days after it is applied
30 Days Lifts automatically 30 days after it is applied

Time-limited bans lift themselves automatically when they expire, so you do not have to remember to unban a member after a cooling-off period.

Reason

The dialog has an optional Reason field. The reason is stored with the ban for your own records - it does not change how the ban behaves. Recording why you banned someone makes it easy for you or another moderator to understand the history later.

Lifting a Ban Early

To remove a ban before it expires, click Unban on the member's row (on the Users page or the Banned Users tab). The restriction is cleared and the member can participate again immediately.

When to Ban vs. Act on Content

Reach for a ban only when content-level actions are not enough:

  • A single bad post - use Trash or Mark as Spam from the Moderation Queue.
  • A member causing trouble in one space - use a Space Ban so they keep their access elsewhere.
  • A member you want to cool down, not remove - use Silence (they can still read).
  • A member who keeps coming back - use a Global Ban, permanent or timed, to stop the behavior at the source.

What's Next?

Learn how in-app notifications keep your members engaged and informed about replies, mentions, and votes.

Notifications →

Notifications & Email

Stay informed with in-app and email notifications.

Notifications keep your community members in the loop without requiring them to check back manually. Every relevant activity (replies, mentions, votes) surfaces instantly in the notification bell so members always know when something needs their attention.

Notifications panel showing recent activity alerts and unread count

What You Will Learn

  • How the notification bell works and where it appears
  • Every notification type and when each one fires
  • How to mark notifications as read
  • How to view, filter, and delete notifications on the full notifications page
  • How the verification reminder email nudges members who never confirmed their address
  • Where members set their personal notification preferences

The Notification Bell

The notification bell icon appears in the community navigation bar on every page. When you have unread notifications, a red badge shows the count. The count updates automatically. You do not need to refresh the page.

Click the bell to open a dropdown showing your most recent notifications. The dropdown lazy-loads its content when you click, keeping page load times fast.

Each notification in the dropdown shows:

  • The notification type (icon)
  • A summary of what happened (for example, "Sarah replied to your topic")
  • The time it occurred
  • A direct link to the relevant content

Clicking a notification in the dropdown marks it as read and navigates you to the relevant topic, reply, or profile.

Notification Types

Jetonomy fires a notification for each of the following events:

Jetonomy ships with ten notification types. The Channels column shows the default channels for each type; "In-app" means it appears in the bell, "email" means it also sends an email by default. Every type can be turned on or off per channel, both site-wide by an admin and per-member. See the Preferences section below.

Event Who receives it Channels (default)
Someone replies to your topic Topic author In-app, email
Someone replies to your reply (threaded) Reply author In-app
Someone mentions you with @username Mentioned member In-app, email
Your reply is accepted as an answer (Q&A) Reply author In-app, email
An idea's status changes (Ideas spaces) Idea author In-app, email
A new topic is posted in a space you follow All followers of that space In-app
You earn a badge (Jetonomy Pro) The member In-app
Your topic or reply receives a vote Content author In-app
A moderator reviews or acts on your content Content author In-app, email
A member requests to join a space you manage Space managers In-app, email

Note: The badge notification only fires on communities running Jetonomy Pro. Votes are reported through a single "vote on your post" notification (it covers both upvotes and downvotes).

These channels are the defaults that ship with Jetonomy. An administrator can change the site-wide default for any type under Jetonomy → Settings → Email, and each member can override their own preferences. The full default table lives in Email Notifications.

Marking Notifications as Read

Mark one as read: Click any notification in the dropdown. Navigating to it marks it read automatically.

Mark all as read: Click the Mark all as read link at the top of the dropdown. All notifications are cleared in a single action. The badge disappears immediately.

Unread notifications are highlighted with a subtle background tint in the dropdown so you can spot them at a glance.

The Full Notifications Page

The dropdown shows your most recent notifications, roughly the last 10 to 20 items depending on screen size. To see your full notification history, click See all notifications at the bottom of the dropdown or navigate directly to /community/notifications/.

The full page lists every notification you have received, loading 20 at a time with a Load More button at the bottom. A weekly background job marks unread notifications older than 30 days as read. Notifications are not auto-deleted from the database.

Full notifications page showing the All / Unread / Mentions / Replies / Votes / Badges filter tabs with count badges, and the bulk-select toolbar with Mark read and Delete buttons above selected rows

Filter Tabs

The page has a row of filter tabs across the top so members can focus on one kind of update at a time. Each tab shows a count badge of how many notifications match it, so you can see at a glance where the activity is.

Tab What it shows
All Every notification you have received
Unread Only notifications you have not opened yet
Mentions Notifications where someone @-mentioned you
Replies Replies to your posts and to your replies
Votes Upvotes and downvotes on your posts and replies
Badges Badges you have earned (only shown when Jetonomy Pro is active)

Switching tabs reloads the list filtered to that type and keeps your place. The Badges tab appears only on communities running Jetonomy Pro, since badges are a Pro feature.

Deleting Notifications

Members can clear out notifications they no longer need, not just mark them read.

  • Delete one: Open the ... actions menu on any notification row and choose Delete. The row is removed immediately.
  • Bulk delete: Tick the checkbox on one or more rows. A toolbar appears at the top of the list showing how many you have selected, with Mark read and Delete buttons that apply to every selected row at once. A Select all on page checkbox selects the whole visible page in one tick.

Deleting is permanent for that member's own inbox. It does not affect anyone else's notifications or the underlying post or reply.

Note: Per-notification delete and the bulk-delete toolbar were added in 1.4.3.

The Verification Reminder Email

When a community requires email verification at signup (Jetonomy → Settings → Email), some members register but never click the verification link in their welcome email. Jetonomy sends those members a single follow-up reminder email nudging them to finish verifying, so they do not get stuck unable to participate.

  • The reminder is sent once per member. It will never email the same person twice.
  • It goes out a configurable number of hours after registration. Set the delay in jetonomy_settings.verification_reminder_hours. Setting it to 0 disables the reminder entirely.
  • It respects each member's email opt-out, so anyone who has opted out of community email is skipped.
  • It uses the same branded email template as your other Jetonomy emails, so the subject and body can be customised under Settings → Email → Email Templates.
  • The reminder only runs while email verification is switched on. Turn verification off and there is nothing to remind about.

Per-User Notification Preferences

Each member can control which notification types they receive. Go to Profile → Edit Profile → Notifications (at /community/u/your-username/edit/).

Edit Profile Notifications tab showing the per-type Web and Email toggle grid with the Pause all email notifications switch below it

Options are:

  • In-app notifications on/off per type
  • Email notifications on/off per type (see Email Notifications for the full email guide)
  • A single Pause all email notifications toggle at the bottom of the same Notifications tab. Turning it on snoozes every email type at once while still showing web notifications in the community, so a member can step away from email without losing their per-type settings. Turning it back off restores their previous choices.

Members cannot disable notifications for direct mentions. The @mention notification is always delivered to ensure important communications reach their target.

Note: Administrators can set the default notification preferences that new members start with. Go to Jetonomy → Settings → Email to configure the defaults applied at signup.

What's Next?

Learn how to configure email notification delivery, set community-wide defaults, and understand which notification types support email.

Email Notifications →

Pro adds more ways to reach and message members:

Email notifications bring members back to your community even when they are not actively browsing. Jetonomy sends a notification email for every in-app event type, and both you and your members have control over which emails are delivered.

Admin email settings with notification toggles and sender configuration

What You Will Learn

  • Which notification types send email
  • How to configure default email settings for new members
  • How members control their own email preferences
  • How one-click unsubscribe links work
  • How Jetonomy sends email and how to use your own SMTP provider
  • What email digest options are available in Jetonomy Pro

Which Notification Types Send Email

Every notification type that appears in the in-app bell can also send an email. The email mirrors the in-app notification - it names the event, shows a short excerpt of the content, and includes a direct link back to the relevant topic or reply.

Jetonomy ships with ten notification types. Each one sends email by default, or not, as shown below:

Notification type Email sent by default
Reply to your topic Yes
Reply to your reply No
@mention Yes
Answer accepted (Q&A) Yes
Idea roadmap status changed Yes
New post in followed space No
Badge earned (Jetonomy Pro) No
Vote on your post No
Moderator action on your content Yes
Space join request Yes

The defaults above are what Jetonomy applies when a new member signs up. Administrators set these site-wide defaults in Jetonomy → Settings → Email; the full settings reference, including the matching web (in-app) defaults, lives in Email Settings. Each member can then override any type for themselves (see "How Members Control Their Preferences" below).

Tip: "New post in followed space", vote, and badge emails are off by default because they can occur frequently. A member who follows many active spaces would otherwise receive a high volume of email. Let members opt in rather than having to opt out.

Editable Email Templates (updated in 1.4.1)

Every notification email Jetonomy sends has an editable template - subject and body - at Jetonomy → Settings → Email → Templates. Change the wording to match your community's voice without writing any code.

Two improvements landed in 1.4.1 that are worth knowing about:

  • Reset to default button on every template - one click restores the shipped subject and body. No more retyping if you change your mind or want to start over.
  • Verification reminder template is now editable from the same screen. The reminder fires once per member, a configurable number of hours after sign-up (default 24), if they haven't clicked the verification link in their welcome email. Set the delay in jetonomy_settings.verification_reminder_hours, or set it to 0 to disable the reminder entirely. See the verification reminder section for the full behaviour.

Defaults now have a single source of truth so reset always restores the exact copy the plugin ships with - even if a future update changes the default wording, your reset still gets the version you'd see on a fresh install.

Template Placeholders

You can use these placeholders in any subject or body. They are replaced with the real values when the email is sent:

Placeholder Replaced with
{site} Your site name
{user} The recipient's display name
{message} The notification summary text
{type} The notification type key
{url} A direct link to the relevant content
{post_title} The title of the related topic or idea
{actor_display_name} The member who triggered the notification
{reply_excerpt} A short excerpt of the reply
{space_title} The space the activity happened in

Any placeholder with no value for a given event renders as an empty string, so it never shows up as literal {post_title} text in the email.

Configuring Default Settings

The community-wide defaults - which types email by default, the From name, the From address, email branding, and the editable templates - all live on the admin Jetonomy → Settings → Email screen. That screen is documented in full, with every setting key, default, and location, in Email Settings.

Changes to defaults apply only to new members who sign up after the change. Existing members keep their current preferences.

How Members Control Their Preferences

Each member can override the defaults from their profile settings at /community/u/their-username/edit/ under the Notifications tab. Every notification type has a separate toggle for in-app and email delivery.

Members can disable all notification emails at once with the Pause all email toggle. This is the equivalent of a temporary snooze - all preferences are preserved so they can turn email back on later.

One-Click Unsubscribe

Every notification email sent by Jetonomy includes an unsubscribe link in the footer. Clicking it immediately unsubscribes the member from that one notification type and shows a confirmation message.

No login is required to unsubscribe - the link contains a signed token that authenticates the action. This keeps unsubscribe rates low and means members who receive an email do not need to remember their password to opt out.

How Jetonomy Sends Email

Jetonomy uses WordPress's wp_mail() function to send all notification emails. This means it automatically works with any SMTP plugin you have installed - WP Mail SMTP, FluentSMTP, Postmark, Mailgun, or any other wp_mail compatible provider.

No additional configuration is needed in Jetonomy when you add an SMTP plugin - it just works.

Note: If you send high volumes of notification email, use a dedicated transactional email provider (Postmark, Mailgun, Sendgrid) rather than your hosting server's mail. Dedicated providers give you delivery tracking, bounce handling, and higher sending limits.

Email Digest (Jetonomy Pro)

PRO - This feature requires Jetonomy Pro.

The Email Digest feature bundles all notifications from a configurable time window into a single summary email. Members can choose daily or weekly digests instead of receiving individual emails for each event. This dramatically reduces email volume for active community members while keeping them informed.

What's Next?

Learn how member profiles work, what stats are displayed, and how members can edit their own information.

User Profiles →

User Profiles & Leaderboard

Member profiles, reputation, and community rankings.

Every member in your community has a public profile page that shows who they are, how much they contribute, and what they have been up to. Profiles build trust between members and give contributors the recognition they have earned.

What You Will Learn

  • What a member profile page shows
  • How online status works on profiles
  • Which tabs are available and who can see each one
  • How members edit their own profile
  • Where reputation and trust level appear

The Profile Page

Every member has a profile page at /community/u/their-username/. Anyone can visit this page - no login is required unless your community is set to private.

User profile page

Header Section

The profile header shows:

  • Avatar - pulled from WordPress Gravatar by default. Members can upload a custom photo from the Edit Profile page and crop it square before it is saved.
  • Display name - the name shown across all community activity
  • Username - the login handle used in @mentions and the profile URL
  • Bio - a short text description the member writes themselves
  • Join date - when the member's account was created
  • Online status - a green dot appears if the member was active in the last 5 minutes (see Online Status)

Stats Bar

Below the header, four stats appear at a glance:

Stat What it shows
Reputation Total reputation score earned
Posts Number of published topics
Replies Number of published replies
Trust Level Current trust level badge and name

The trust level badge uses the same color coding as it does on reply cards - grey for TL0, scaling up to gold for TL5.

Profile Tabs

Posts

Lists every topic the member has published, paginated 20 per page, sorted newest first. Each item shows the topic title, the space it belongs to, the vote score, and the reply count.

Replies

Lists every reply the member has posted across all spaces, paginated 20 per page, newest first. Each item shows the reply excerpt, the topic it belongs to, and the vote score.

Votes

Shows the content this member has voted on. The tab is visible to the member themselves and to WordPress Administrators. Other members cannot see this tab - voting is semi-private.

Bookmarks

Lists the topics this member has bookmarked, at /community/u/their-username/bookmarks/. Like Drafts, this tab appears only on the member's own profile. Bookmarks are private to the member who saved them, so no one else (including administrators viewing the public profile) sees this tab. It gives members a quick personal reading list of posts they wanted to come back to. See Bookmarks & Following for how members save and manage bookmarks.

Drafts

Shows unpublished draft topics saved by this member. This tab is visible only to the profile owner and WordPress Administrators. Drafts are never exposed publicly.

Tip: Encourage active members to complete their bio. Profiles with a bio and a recognizable avatar get more replies - other members feel more comfortable engaging when they know who they are talking to.

Editing a Profile

Members can edit their own profile at /community/u/their-username/edit/. This page is accessible from the Edit Profile button on the profile page header.

Edit Profile page with display name, bio, avatar upload, and notification preference fields

Editable fields:

  • Display name
  • Bio
  • Avatar - upload a JPG, PNG, GIF, or WebP. After choosing a non-GIF image, a crop dialog opens: drag to reposition, use the slider to zoom, then Crop and upload saves a square avatar (animated GIFs upload as-is to preserve animation). The "Remove photo" button reverts to the Gravatar.
  • Notification preferences (email and in-app toggles per type)

Avatar crop dialog open with the image preview, zoom slider, and Crop and upload button

WordPress Administrators can edit any member's profile from the standard WordPress Users admin as well.

Embedding Profiles on a Page

You do not have to send members to the full profile page to surface profile information. Two shortcodes let you drop a compact member card or a space member roster onto any WordPress page, post, or widget area. Both are shortcode-only - there is no matching Gutenberg block, so add them with a Shortcode block or directly in the editor.

Member profile card

[jetonomy_user_profile user_id="0"]

Renders a small card with the member's display name, trust level badge, a short bio excerpt, and their reputation and post count. Set user_id to a specific member's ID, or leave it as 0 (the default) to show the currently logged-in member's card - handy for a "your profile at a glance" panel on a members-only page.

Space member roster

[jetonomy_space_members space_id="5" count="20"]

Lists the members of one space, ranked by reputation. Drop it on a space landing page or an "About this community" page so visitors can see who is active.

Attribute Default What it does
space_id 0 The ID of the space whose members to list. Required - leave it unset and nothing renders.
count 10 How many members to show, highest reputation first.

Note: The roster attribute is count, not limit.

What's Next?

See how your top contributors rank against each other on the community leaderboard.

Leaderboard →

  • Custom Badges - award badges automatically or by hand to recognize members.

The leaderboard turns quality participation into something visible and worth competing for. Your top contributors are recognized publicly, which encourages every member to engage more thoughtfully.

What You Will Learn

  • How to find the leaderboard page
  • What information is displayed for each member
  • How the top 3 medal positions work
  • How to add the leaderboard sidebar widget
  • Why public recognition improves community quality

The Leaderboard Page

The community leaderboard is available at /community/leaderboard/. Any member - and guests, if your community is public - can view it. No login is required.

Leaderboard page

Members are ranked by total reputation score, highest first. The leaderboard updates in real time as reputation changes - there is no daily cache delay between earning reputation and appearing in the rankings.

How Reputation Is Earned

Reputation is what drives a member's position on the board. Members earn it through quality participation - upvotes on their topics and replies, and having an answer accepted on a question. Downvotes and moderator removals subtract from it. The exact point values are defaults you can adjust under Jetonomy → Settings, so you can tune what your community rewards. See Voting & Reputation for the full list of actions and their default point values.

Time Period Filter

The leaderboard page has a row of period pills at the top that scope which members appear:

Pill What it shows
All time Every member, ranked by reputation (the default)
This month Only members active within the last 30 days, ranked by reputation
This week Only members active within the last 7 days, ranked by reputation

The month and week filters narrow the board to recently active members - ranking is still by total reputation score within each window, not by reputation earned during that period.

What Each Row Shows

Every row on the leaderboard displays:

Column Description
Rank Position number (1, 2, 3...)
Avatar Member's initials avatar - their first two initials, not the uploaded photo, so the board stays fast (no online status dot on the leaderboard)
Name Display name, linked to their profile page
Reputation Total reputation score
Posts Total published topic count

Clicking a member's name goes directly to their profile page.

Top 3 Medal Positions

The first three positions on the leaderboard display a medal icon next to the rank number:

Position Medal
1st place Gold medal
2nd place Silver medal
3rd place Bronze medal

Medal icons draw the eye immediately when someone opens the leaderboard page. Being in the top 3 is a genuine achievement that members notice and compete for.

The Leaderboard Sidebar Widget

Add the Jetonomy: Leaderboard widget to any sidebar from Appearance → Widgets. The widget shows the top 5 members by reputation, listing each member's name and reputation score - a compact preview of the leaderboard without requiring members to visit the full page. (Its default heading text is "Top Members".)

Configuration options:

Option Default Description
Title Top Members Widget heading text
Count 5 Number of members to show (max 20)

The widget runs a single direct LIMIT query to fetch the top members by reputation.

Why the Leaderboard Improves Community Quality

Recognition is a powerful motivator. When members see their name on the leaderboard, they are more likely to write detailed answers, respond helpfully to new members, and keep coming back. Members who are close to moving up a rank are especially motivated - the leaderboard creates natural competition without requiring badges, gamification plugins, or manual awards.

Tip: Reference the leaderboard in your community welcome message or newsletter. "See who our top contributors are this month" gives members a reason to engage and something to aspire to.

What's Next?

Learn how the online status green dot works - when it shows, where it appears, and how Jetonomy tracks it efficiently.

Online Status →

The online status green dot shows which members are currently active in your community. It makes conversations feel more live and helps members know when is a good time to expect a quick reply.

User profile page showing avatar with online status indicator

What You Will Learn

  • When the green dot appears on a member's avatar
  • Where online status is displayed across the community
  • Where it is intentionally not shown and why
  • How Jetonomy tracks activity without overloading the database
  • That no setup is needed - it works automatically

When the Green Dot Appears

A green dot appears on a member's avatar when they have been active in the community within the last 5 minutes. Active means any authenticated page load or interaction - visiting a topic, posting a reply, casting a vote, or navigating between pages.

Close-up of a member avatar with the green online status dot in the lower corner

After 5 minutes of inactivity, the dot disappears automatically on the next page load that renders it.

There is no manual "appear offline" or "appear online" toggle. Online status reflects real activity.

Where Online Status Appears

The green dot is shown in these locations:

Location Shown
Reply cards (author avatar) Yes
Member profile page (header avatar) Yes
Sidebar Leaderboard widget No (the widget lists names and scores only, no avatars)
Topic listing rows (author credit) No
Search results (author credit) No

Why Not on Topic Listing Rows

Topic listing pages can show dozens of topics, each by a different author. Rendering the online status for every author on that page would require checking multiple records in a single request - potentially 20 to 50 lookups per page view on an active community.

Jetonomy deliberately omits the online dot from listing rows to keep those pages fast. The detail-level contexts (reply cards, profiles, widgets) are the right place for presence information because you are already focused on a specific member.

How Activity Tracking Works

When a logged-in member loads any community page, Jetonomy records a timestamp on their user record. To prevent a database write on every single page view, updates are rate-limited: Jetonomy writes the timestamp at most once per minute per member.

If a member loads 10 pages in 30 seconds, Jetonomy writes to the database once. This keeps the wp_jt_user_profiles table write volume proportional to the number of unique active members, not the total number of page views.

The online status check itself (reading whether a member is active) is cached for 60 seconds using the WordPress object cache. On a page with 10 reply cards by different authors, Jetonomy makes at most a small batch of cache reads rather than 10 individual queries.

No Setup Required

Online status is automatic. There is no setting to enable, no API key to configure, and no JavaScript polling. It works the moment Jetonomy is activated.

Note: Online status is only tracked for logged-in members. Guests who browse your community are not tracked and do not show an online indicator.

What's Next?

Go back to explore other sections, or return to the main community setup guide.

User Profiles → | Leaderboard →

Since Jetonomy 1.4.0, every signed-in member has a personal page at /community/my-spaces/ that lists every space they run and every space they're a member of, in one place. It is the fastest way to jump back into a space you are active in without scrolling the home page.

What You Will Learn

  • Where the My Spaces page lives and how to reach it
  • The two sections shown on the page and what they mean
  • What each row tells you at a glance
  • Quick actions available per row
  • What members see when they're brand new and have not joined any space yet
  • The privacy semantics: who can see this page

Where The Page Lives

The page is always at /community/my-spaces/. It is signed-in only. Visiting the URL while signed out redirects to the login page and returns to My Spaces after a successful sign-in.

There are two built-in ways to reach the page:

  • The My Spaces link in the header avatar menu (added automatically in Jetonomy 1.4.0+)
  • The mobile drawer menu under "Community"

If your theme overrides the header template, the link may not appear automatically. The page itself still works at the URL.

The Two Sections

My Spaces page showing the "Spaces you run" section with Admin and Mod role badges and Edit, Mod queue, and Members quick-action buttons, above the "Spaces you're in" section

The page is split into two sections, stacked top to bottom.

Spaces You Run

The first section lists every space where you are a space admin or space moderator. These are the spaces you have authority over.

For each space, the row shows:

  • The space icon and title
  • A role badge ("Admin" or "Mod")
  • The post count and member count
  • Quick action buttons: Edit (admins only), Mod queue, Members

The whole card is a link to the space home, so there is no separate "Visit" button.

If you run no spaces, this section simply does not appear (empty sections are hidden). If you also belong to no spaces, the page shows a single combined empty state - see Empty State below.

Spaces You're In

The second section lists every space where you are a regular member. These are the spaces you have joined but do not moderate.

For each space, the row shows:

  • The space icon and title
  • An optional short description
  • The post count and member count

The whole card is a link to the space home; member rows have no per-row action buttons.

If you have not joined any spaces yet, this section simply does not appear (empty sections are hidden).

What Each Row Tells You

Element What it means
Icon The Lucide icon picked by the space owner
Title The space name; the whole card links to the space home
Role badge "Admin" or "Mod" on the spaces you run; no badge for regular members
Description An optional short description excerpt, when the space has one
Post count Total published topics in the space
Member count Total members in the space

Quick Actions

Action buttons appear only on rows in the "Spaces you run" section. Member rows have no action buttons - clicking the card opens the space.

  • Edit appears only for spaces you administer. It opens the front-end Edit Space page covered in the previous article.
  • Mod queue opens the space's moderation queue.
  • Members opens the members tab where you can promote, demote, or remove members.

Empty State

Brand-new members often land on My Spaces before they have joined anything. When you neither run nor belong to any space, the page shows a single full-page empty state - "You are not in any spaces yet" with a Browse spaces button that goes to the community home.

Otherwise, empty sections are simply hidden: if you run spaces but belong to none as a regular member (or vice versa), only the section with content renders. There is no per-section "collapsed" placeholder and no "Create a space" button on this page.

Privacy

The My Spaces page is personal to the signed-in user.

  • It requires sign-in. Signed-out visitors are bounced to login.
  • It is excluded from search engine indexing via the noindex, nofollow meta tag.
  • It is not visible to anyone else. There is no public URL that shows another user's space list.
  • Membership in a Hidden space is shown on this page but is still not visible on the user's public profile.

If you want to see which spaces another user is in, you have to look at their public profile, which only shows public memberships.

Performance

The page loads all of your spaces with one indexed query per role bucket (the spaces you run, and the spaces you belong to). Space rows are hydrated once each, so there is no per-row N+1 query, and the per-card role label ("Admin" / "Mod") is served from a warmed cache.

Note: The page does not paginate. It loads every space you run and every space you belong to. For the typical member this is a handful of spaces; if you expect members to belong to hundreds of spaces, pagination here is a known gap rather than a shipped feature.

What's Next?

The My Spaces page is one entry into your community life. The full profile page covers the rest of what a member does: their posts, replies, votes, bookmarks, and drafts, alongside their reputation score and trust level. (#05-custom-badges-jtnmy) Pro extension.)

Your Profile Page →

Pro Features

Premium extensions: reactions, messaging, polls, badges, analytics, and more.

Activate your license, switch on the extensions you need, and understand which capabilities gate each Pro feature.

PRO - This section covers Jetonomy Pro.

What You Will Learn

  • How to activate your Jetonomy Pro license
  • How to enable and disable individual Pro extensions
  • Which license tier unlocks which extensions
  • Which WordPress capabilities gate each Pro feature

Activate Your License

Jetonomy Pro is a peer plugin to free Jetonomy. Install and activate free Jetonomy first, then install Jetonomy Pro - Pro shows an admin notice and stays dormant if the free plugin is not active.

  1. Go to Jetonomy → Settings → License in your WordPress admin (License is a tab inside the free plugin's Settings page, not a standalone page).
  2. Paste the license key from your purchase receipt.
  3. Click Activate. Jetonomy validates the key against the store and shows your tier and expiry.

Your license drives automatic updates and tier checks. If a license is missing or expired, extensions still boot - but features that require a higher tier than your license carries are blocked at the gate.

Note: Free and Pro always ship the same x.y.z version. Keep both updated together so the contracts between them stay in sync.

Enable Extensions

Jetonomy Pro ships fifteen extensions. None of them do anything until you switch them on.

  1. Go to Jetonomy → Extensions (the jetonomy-extensions page).
  2. Each extension shows a card with its name, description, and a toggle.
  3. Click Enable on the extensions you want. The toggle persists the choice to the jetonomy_pro_extensions option (an array of extension IDs).
  4. Enabling an extension runs any one-time setup it needs (for example, creating its database tables) and registers its hooks, REST routes, and admin screens immediately.

Disable an extension at any time from the same page. Disabling stops the feature and unregisters its hooks; it does not delete the data the extension already stored.

License Tiers

Tier Who it suits
Starter A single community getting started with Pro features
Growth A growing community that needs the full extension set across more sites
Agency Builders running Pro across many client sites
Lifetime One-time purchase with ongoing updates

All fifteen extensions are available on the paid tiers. Higher tiers raise the activation limits (number of sites) and support level rather than locking individual features behind a paywall. The exact site limits per tier are listed on your account page and on the pricing page.

Capabilities

Pro registers five capabilities that gate its features. Each maps to the WordPress roles shown below by default; you can reassign them with any role-editor plugin if your community uses custom roles.

Capability Default roles What it gates
jetonomy_manage_settings Administrator Access to the Pro settings pages (License, Extensions, integration and extension settings tabs)
jetonomy_manage_spaces Administrator Per-space Pro admin controls - SEO Pro metadata, custom-field tabs, and creating site-wide announcements
jetonomy_moderate Editor, Administrator The actions Advanced Moderation rules can take on matched content
jetonomy_vote Subscriber, Contributor, Author, Editor, Administrator Casting Reactions and voting in Polls
jetonomy_view_analytics Administrator Viewing the community Analytics dashboard

Note: Most Pro REST write routes are additionally gated by manage_options for admin operations, and by trust level for member operations (for example, Private Messaging and Poll creation require Trust Level 1 or higher). See the per-feature pages and the REST API reference for the exact permission on each route.

What's Next?

Start with the engagement extensions members notice first.

Emoji Reactions →

Add expressive emoji reactions to every post and reply - so members can respond instantly without writing a full reply.

PRO - This feature requires Jetonomy Pro.

Reaction chips below a community post

What You Will Learn

  • How to enable Reactions for your community
  • How to customize which emojis appear per space
  • How members react to and change their reaction on a post
  • How to read reaction counts from the REST API

Why Reactions Matter

A quick reaction lowers the bar for engagement. Members who would never write a reply will tap a rocket emoji or a heart. That micro-engagement adds up - you get richer signal on your best content and members feel heard without the pressure of composing a response.

How It Works

Every post and every reply in your community shows a reaction strip. Members click any emoji to react. Clicking a different emoji replaces the previous one - each member can hold exactly one reaction per piece of content at a time. Clicking the same emoji again removes the reaction entirely.

The reaction counts are displayed as chips directly below the post body. Each chip shows the emoji and the total count. Hovering a chip reveals the names of recent reactors.

The reaction strip on a post, showing the eight default emoji options a member can pick from

Enabling Reactions

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Reactions and click Enable.
  3. Reactions appear on all posts and replies immediately - no page-level configuration needed.

Tip: Enabling Reactions does not affect any existing posts. Historical content simply starts with zero reactions.

Default Emoji Set

Jetonomy ships with eight emoji reactions out of the box:

Emoji Label Use case
Like Thumbs up General agreement
Love Heart Enthusiasm, appreciation
Haha Laughing face Humor, something funny
Celebrate Party popper Wins, announcements
Thinking Thinking face Interesting, thought-provoking
Watching Eyes Following along, keeping an eye on it
Rocket Rocket Fast, shipped, love it
Dislike Thumbs down Disagreement

All eight are enabled globally by default. You can adjust which ones appear per space.

Per-Space Customization

Different spaces have different tones. A Support space might not need a Celebrate emoji, and a General Chat space might not need Dislike.

  1. Go to Jetonomy → Spaces and open the space you want to customize.
  2. Open the Reactions tab in the space settings panel.
  3. Toggle individual emojis on or off for this space.
  4. Save. The change takes effect immediately for all posts in that space.

The Reactions tab inside a space's settings panel, with a per-emoji on/off toggle for that space

REST API

The Reactions extension registers these endpoints under jetonomy/v1:

Method Endpoint Description
GET /posts/{id}/reactions Get the reactions and counts for a post
POST /posts/{id}/reactions Toggle your reaction on a post (add, replace, or remove)
GET /replies/{id}/reactions Get the reactions and counts for a reply
POST /replies/{id}/reactions Toggle your reaction on a reply

{id} is the numeric ID of the post or reply. A single POST toggles your reaction: sending a new emoji replaces your previous one, and sending your current emoji again clears it.

Example - toggle a reaction:

POST /wp-json/jetonomy/v1/posts/42/reactions
{
  "emoji": "rocket"
}

Reading reactions is open to any visitor; toggling a reaction requires the jetonomy_vote capability (logged-in members by default). See the REST API reference for full payloads.

What's Next?

Allow members to message each other privately, without leaving your community.

Private Messaging →

Let members send direct messages to each other - one-on-one or in small groups - without leaving your community.

PRO - This feature requires Jetonomy Pro.

Messages inbox showing conversation list

What You Will Learn

  • How to enable Private Messaging
  • How members start conversations and send messages
  • How unread counts and notifications work
  • How to block users from messaging you
  • How to use the REST API for conversations and messages

Why Private Messaging Matters

When members can message each other directly, your community becomes a platform - not just a forum. It reduces off-site communication, keeps relationships within your ecosystem, and gives you a richer, stickier product.

How It Works

Private Messaging adds a dedicated inbox at /community/messages/. Members can start a new conversation with any other member, or create a group conversation with up to 20 participants. Each conversation is a persistent thread - messages appear in chronological order, and new messages are loaded automatically via polling.

Single conversation thread view

Enabling Private Messaging

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Private Messaging and click Enable.
  3. A Messages link appears automatically in the community navigation bar.

No additional configuration is required to go live.

Starting a Conversation

Members start a new conversation in two ways:

  • Click New Message from the Messages inbox at /community/messages/.
  • Click the Message button on any member's profile page.

Both methods open a composer. Members type the recipient's name (autocomplete searches by display name and username), write their first message, and hit Send. The conversation thread opens immediately.

For group conversations, members add multiple recipients before sending. The group conversation shows all participants' avatars at the top of the thread.

Group Conversations

A conversation is either direct (1:1) or a group with multiple participants. Add several recipients in the composer to start a group thread, and every participant sees the same shared history.

Group threads keep a complete record. When a member leaves a group, their past messages stay in place attributed to them with a "left the conversation" note - Jetonomy does not delete the messages, so the thread always reads coherently. Creating a direct message to someone you already have a 1:1 thread with reuses that existing thread instead of starting a duplicate.

Archive, Leave, and Mute

Each of these is a per-member setting - your choice never changes the conversation for the other participants.

  • Mute - silences notifications for a conversation while keeping it in your inbox. New messages still arrive; you just are not pinged. Unmute from the same menu.
  • Archive - hides a conversation from your main inbox to keep it tidy. Archived conversations stay fully intact and reappear (or can be reopened) when there is new activity; nothing is deleted.
  • Leave - removes you from a group conversation. You stop receiving its messages, but the thread and your past messages remain for everyone still in it. Leaving applies to group conversations.

Unread Counts and Notifications

A red badge on the Messages nav icon shows the total number of unread conversations. The count updates every 30 seconds via polling. It drops to zero when a member opens and reads the conversation.

Jetonomy also sends a notification to the recipient's bell icon when a new message arrives. Members who have email notifications enabled for private messages receive an email notification as well.

Tip: Members control their messaging email notifications in Profile → Notification Settings. Admins cannot override individual user preferences.

Blocking Users

Any member can block another from sending them messages:

  1. Open a conversation with the person.
  2. Click the ··· menu in the thread header.
  3. Select Block [username].

Blocked users cannot send new messages to the member who blocked them. Existing conversation history is preserved but no new messages are delivered. The blocked user sees a generic "Unable to send message" error - they are not told they are blocked.

Admins can view and clear blocks in Jetonomy → Users → [username] → Messaging.

REST API

Private Messaging adds endpoints under jetonomy/v1:

Method Endpoint Description
GET /conversations List your conversations (paginated, filterable)
POST /conversations Start a new direct or group conversation
GET /conversations/{id} Get conversation details and participant list
PATCH /conversations/{id} Update your settings on the conversation (mute)
GET /conversations/{id}/messages List messages (cursor-based pagination)
POST /conversations/{id}/messages Send a message
GET /conversations/unread-count Your total unread conversation count (30s cache)
POST /conversations/{id}/mute Mute or unmute the conversation for you
POST /conversations/{id}/archive Archive or unarchive the conversation for you
POST /conversations/{id}/leave Leave a group conversation
POST /conversations/{id}/block Block or unblock the other participant (direct only)

All endpoints require authentication, and member operations on a conversation require you to be a participant. Starting a conversation and sending messages require Trust Level 1 or higher (admins and moderators bypass this). See the REST API reference for full payloads.

Example - start a conversation:

POST /wp-json/jetonomy/v1/conversations
{
  "recipients": [45, 67],
  "message": "Hey, wanted to follow up on your question about onboarding."
}

Example - get messages with cursor pagination:

GET /wp-json/jetonomy/v1/conversations/12/messages?after=msg_abc123&per_page=20

Site-Owner Oversight (Conversations Admin Page)

New in 1.5.0. Site administrators get a dedicated Jetonomy → Conversations page in wp-admin for messaging oversight - useful for abuse investigations, GDPR requests, and verifying that messaging is healthy on a large community.

  • Conversations list - every conversation with participants, message count, and last activity, paginated at 50 per page so it stays fast even with tens of thousands of threads.
  • Thread detail - click any conversation to read its full message history.
  • Purge - permanently delete a conversation and all of its messages and read-state rows. The button asks for confirmation; the deletion fires the jetonomy_pro_conversation_purged action so audit tooling can record it.

Purging is irreversible and bypasses the participants' own archive/leave state - reserve it for moderation and compliance situations.

What's Next?

Add polls to any topic to gather community input and drive decisions.

Polls →

Attach a poll to any topic and let your community vote - perfect for decisions, feedback, and feature prioritization.

PRO - This feature requires Jetonomy Pro.

A poll attached to a community post, showing each option as a horizontal percentage bar with its vote count

What You Will Learn

  • How to enable Polls
  • How to attach a poll when creating or editing a topic
  • How members vote, change their vote, and remove it
  • How poll results are displayed
  • How poll creators close a poll

Why Polls Matter

Asking a question in text is passive. Attaching a poll turns the same question into an action - members click an option in seconds instead of writing a response. You get quantified signal, higher engagement on that post, and a result the whole community can see at a glance.

Enabling Polls

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Polls and click Enable.
  3. A + Add Poll button appears at the bottom of the post composer.

Creating a Poll

When writing a new topic, click + Add Poll beneath the content editor.

The poll builder lets you:

  • Write up to 20 options (minimum 2 required).
  • Choose Single choice (members pick one) or Multiple choice (members pick several).
  • Optionally set a Close date - the poll stops accepting votes automatically at that date and time.

The poll builder open in the post composer, with the option list, the single/multiple choice selector, and the optional close-date field The poll is attached to the topic and saved together when you click Post. You cannot attach a poll to a reply - only to top-level topics.

Tip: You can add or remove a poll from an existing topic by editing the post. Removing a poll permanently deletes all votes cast on it.

How Members Vote

The poll appears below the post body, before any replies. Each option is displayed as a labeled button.

  • Single choice - clicking an option records your vote immediately. You see the results as percentage bars as soon as you vote.
  • Multiple choice - checkboxes appear. Select all the options you want and click Vote.

After voting, members can change their vote by clicking a different option. Clicking your current selection a second time removes your vote entirely.

Members who have not voted see the options. Members who have voted see the live results. This design keeps undecided members from being anchored by early results.

Reading Results

Results display as horizontal percentage bars with the option label, the percentage, and the raw vote count. Bars fill in proportion to the leading option.

Voted poll results with horizontal percentage bars, each option's percentage and raw vote count, and the total vote tally below The total vote count appears below the bar chart. If the poll has a close date, a countdown shows how much time remains.

Closing a Poll

The topic author and any space moderator can close a poll at any time:

  1. Open the topic.
  2. Click the ··· menu on the poll card.
  3. Select Close Poll.

Once closed, the poll shows a Closed badge and no further votes are accepted. Existing results remain visible. A closed poll can be re-opened by the same users using the same menu.

Note: If you set a close date and later want to extend it, edit the post and update the date in the poll settings.

Multi-Select Voting

A poll is either single choice or multiple choice, set when you build it:

  • Single choice records exactly one option per member. Voting for a different option moves the vote.
  • Multiple choice lets each member pick several options at once. Each option toggles independently - a member can hold any number of selections, and clicking a chosen option a second time clears just that one.

Because of this, the total vote count on a multiple-choice poll can be higher than the number of voters - one member can contribute several votes.

Polls Admin

Enabling the extension adds a Polls submenu under the Jetonomy admin menu (jetonomy-pro-polls). It lists every poll in your community with its post, type, total votes, and close state, so you can review and close polls without opening each topic.

The Polls admin list page, showing every poll with its post, type, total votes, and close state

REST API

Polls registers these endpoints under jetonomy/v1:

Method Endpoint Description
POST /posts/{post_id}/poll Create a poll on a post
GET /posts/{post_id}/poll Get a poll's options and live vote counts
POST /polls/{id}/vote Cast a vote - pass option_id for single choice or option_ids (array) for multiple choice
DELETE /polls/{id}/vote Remove your vote(s) from the poll
PATCH /polls/{id} Update a poll (for example, change the close date)

Creating a poll and voting require the member to be logged in; poll creation additionally requires the right to post in the target space. See the REST API reference for full request and response payloads.

What's Next?

Collect structured information about your members with custom profile fields.

Custom Profile Fields →

Add structured fields to member profiles - collect the information that matters to your specific community.

PRO - This feature requires Jetonomy Pro.

Custom fields displayed on a member profile page

What You Will Learn

  • How to create and manage custom profile fields
  • Which field types are available
  • How to set visibility and required status
  • How members fill in their fields
  • How to read and update field values via the REST API

Why Custom Fields Matter

A generic WordPress profile has a bio and a website URL. That is not enough for most communities. A developer community needs a GitHub handle. A healthcare community needs a specialty. A SaaS community needs a company name. Custom Fields lets you define exactly the information that makes members useful and findable in your community.

Enabling Custom Fields

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Custom Fields and click Enable.
  3. A Custom Fields item appears under the Jetonomy admin menu.

Creating a Field

  1. Go to Jetonomy → Custom Fields.
  2. Click Add Field.
  3. Fill in the field settings:
Setting Description
Label Displayed on the profile and in the edit form
Field Key Unique slug used in the REST API (auto-generated, editable)
Type See field types below
Required If on, members cannot save their profile without filling this in
Visibility Who can see the field value
Description Optional helper text shown below the input
  1. Click Save Field.

The Custom Fields admin page, listing existing fields with the Add Field form open showing the Label, Field Key, Type, Required, Visibility, and Description settings

Field Types

Type Best for
Text Short single-line answers (job title, company, username)
Textarea Longer free-form text (bio supplement, expertise description)
Number Numeric values (years of experience, team size)
Email Contact email address
URL Website, GitHub, LinkedIn, portfolio links
Select Predefined options as a dropdown, single choice (country, role, industry)
Checkbox Yes/no toggle (newsletter opt-in, open to work)
Radio Predefined options as radio buttons, single choice
Date A calendar date (joined date, availability)

For the Select and Radio types, you define the options in the field editor - one per line. Select renders a dropdown; Radio renders a set of radio buttons.

Visibility Options

Each field has one of three visibility settings:

Visibility Who sees the value
Public Anyone, including logged-out visitors
Members only Logged-in community members
Private Only the member themselves and admins

Private fields are still editable by the member but do not appear on their public profile. They are accessible to admins via the admin Users page.

How Members Fill In Fields

Members edit their custom fields at /community/u/{username}/edit/ under the Profile Details section. Required fields show a red asterisk. Saving the profile validates all required fields before updating.

Tip: Guide members to complete their profiles right after joining by linking to the edit profile page in your welcome notification or email digest.

REST API

Custom Fields adds field-aware parameters to the existing profile and post endpoints:

Method Endpoint Description
GET /users/{id} Profile response includes custom_fields object
GET /users List response includes custom_fields on each member
PATCH /users/{id} Pass custom_fields: { field_key: value } to update
GET /posts/{id} Post response includes custom_fields if any post-level fields are configured
GET /posts List response includes custom_fields on each post
GET /custom-fields List all defined fields and their settings
POST /custom-field-values Set a single field value on a target object (user or post)

Example - read a profile with custom fields:

GET /wp-json/jetonomy/v1/users/45

{
  "id": 45,
  "name": "Priya Sharma",
  "custom_fields": {
    "company": "Acme Corp",
    "github_username": "priyasharma",
    "open_to_work": true
  }
}

Example - update custom fields:

PATCH /wp-json/jetonomy/v1/users/45
{
  "custom_fields": {
    "company": "New Horizons Ltd"
  }
}

Members can only update their own fields. Admins can update any member's fields.

Setting one value at a time: if you want to set a single field on a single object rather than sending the whole custom_fields object, POST /custom-field-values with the field key, the target object type and ID, and the value. This is the lightweight path used by the edit-profile form and is handy for partial updates from custom tooling.

How fields surface in output: once a field is configured, its value is embedded automatically in the relevant REST responses - the custom_fields object on /users and /posts (and their list endpoints) - and rendered on the matching frontend surface (the member profile for profile fields, the post for post fields), subject to the field's visibility setting. You do not register a separate read endpoint per field; the value rides along with the object it belongs to.

See the REST API reference for full payloads.

Upgrading From Older Versions

If you are on Jetonomy 1.4.1 or newer, custom field values are returned automatically on the /jetonomy/v1/posts and /jetonomy/v1/users endpoints, so any tool reading the API sees every field you have configured. On older versions the values were saved to the database but did not appear in API responses - update both the free and Pro plugins together to read custom fields over the API.

What's Next?

Recognize and reward your most engaged members with custom badges.

Custom Badges →

Design your own badges, set the conditions that earn them, and watch members compete to collect them.

PRO - This feature requires Jetonomy Pro.

Badges displayed on a member profile page

What You Will Learn

  • How to create a badge with a name, icon, and tier
  • How to set auto-award conditions
  • How to award badges manually as an admin
  • How badges display on member profiles

Why Custom Badges Matter

Trust levels and reputation points are invisible to casual members. Badges are visible, collectible, and shareable - they give members a concrete goal to aim for. A "100 Posts" badge tells the community this member is active. A "Top Answerer" badge signals expertise. Badges convert passive lurkers into active contributors.

Enabling Custom Badges

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Custom Badges and click Enable.
  3. A Badges item appears under the Jetonomy admin menu.

Creating a Badge

  1. Go to Jetonomy → Badges.
  2. Click Create Badge.
  3. Fill in the badge details:
Field Description
Name Displayed on the badge and in the award notification
Description One sentence explaining how to earn it
Icon Upload a 64×64 PNG or SVG icon
Tier Bronze, Silver, or Gold - controls the border color on profile
  1. Set the award conditions (see below).
  2. Click Save Badge.

The Create Badge editor, showing the name, description, icon upload, Bronze/Silver/Gold tier selector, and auto-award criteria settings

Award Conditions

Auto-Award

Auto-awarded badges evaluate all members on a regular schedule and grant the badge automatically when the conditions are met. Choose from built-in criteria:

Criteria Example threshold
Total posts 10, 50, 100, 500 posts
Accepted answers 5, 25, 50 accepted answers
Total replies 25, 100, 250 replies
Upvotes received 10, 50, 200 upvotes on any content
Days as member 30, 180, 365 days since joining
Reputation 100, 500, 1000 reputation points
Trust level Trust level 1 through 5
Spaces joined 3, 10, 25 spaces joined

Set the threshold for each criteria you want to use. You can combine multiple criteria with all (the member must satisfy every condition) or any (one is enough) to earn the badge.

Note: Auto-evaluation runs automatically - a recurring job every 6 hours (via Action Scheduler, with a WP-Cron fallback), plus event-driven re-evaluation that fires when a member's posts, replies, votes, reputation, or trust level change. There is no manual "evaluate now" button.

Manual Award

Some badges should not be automated - "Staff Pick", "Most Helpful in July", or "Community Founder" are judgment calls. For these, leave all auto-award criteria blank and award manually:

  1. Go to Jetonomy → Users and open the member's profile.
  2. Click Award Badge.
  3. Select the badge from the list and add an optional private note.
  4. Click Award.

The member receives a notification immediately and the badge appears on their profile.

Badge Tiers

Badges have three visual tiers that appear as border colors on the badge icon:

Tier Color Suggested use
Bronze Warm bronze Entry-level milestones (first post, 7-day streak)
Silver Cool silver Mid-tier milestones (100 posts, 10 accepted answers)
Gold Bright gold Elite milestones (500 posts, Top Contributor of the year)

Tiers are visual only - they do not affect permissions or trust levels.

Badge Display

Badges appear on member profile pages in a dedicated Badges section. Members who have earned no badges see an empty state that lists a few featured badges to work toward - this passively encourages engagement.

The three most recently earned badges also appear in the member's hover card, which pops up when anyone hovers their username throughout the community.

REST API

Custom Badges registers these endpoints under jetonomy/v1:

Method Endpoint Description
GET /badges List all defined badges and their settings
POST /badges Create a badge
PATCH /badges/{id} Update a badge
DELETE /badges/{id} Delete a badge
POST /users/{id}/badges Award a badge to a member

Badges can be created, edited, and awarded entirely through REST, so you can automate awards from your own tooling or grant a badge as part of an external workflow. Listing badges is open to any logged-in member; creating, editing, deleting, and awarding require manage_options. See the REST API reference for full payloads.

What's Next?

Get a data-driven view of your community's health with the Analytics Dashboard.

Analytics Dashboard →

Understand what your community is doing, where it is growing, and who is driving it - all from a single admin dashboard.

PRO - This feature requires Jetonomy Pro.

Analytics dashboard showing charts and top contributor table

What You Will Learn

  • How to access the Analytics dashboard
  • Which metrics are tracked and what they mean
  • How to use the date range filter
  • How to export data as CSV

Why Analytics Matter

You cannot grow what you cannot measure. The Analytics dashboard turns raw community activity into actionable metrics - so you know which spaces need attention, who your power users are, and whether engagement is trending up or down before it becomes a problem.

Enabling Analytics

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Analytics and click Enable.
  3. An Analytics item appears under the Jetonomy admin menu.

Analytics begin recording from the moment you enable the extension. Historical data before activation is not backfilled.

Go to Jetonomy → Analytics. The dashboard opens on the last 30 days by default.

Date Range Filter

Use the date range picker at the top right to select any custom range. Preset shortcuts:

  • Last 7 days
  • Last 30 days
  • Last 90 days
  • This month
  • Last month

All charts and tables update instantly when you change the range.

The analytics date-range picker, showing the preset shortcuts (Last 7 days, Last 30 days, Last 90 days, This month, Last month) and the custom range option

Overview Metrics

The top row shows four headline numbers for your selected range:

Metric What it means
Total Posts New topics created in the period
Total Replies New replies created in the period
Active Members Unique members who posted, replied, or voted
Growth Rate Percentage change vs the previous equal-length period

Below the headline row, a line chart shows daily post and reply volume over the selected range. Spikes are easy to spot - hover any point to see the exact date and count.

Counting semantics (improved in 1.5.0): the daily totals count published content and stay accurate through the whole content lifecycle. A post created as pending counts on the day it was created once a moderator approves it; trashing a published post removes it from its original day's total (never producing negative days); restoring adds it back. Earlier versions counted at creation only, so moderated or trashed content slowly drifted the totals.

Top Spaces

A ranked table shows your most active spaces sorted by total posts + replies in the period. Columns include post count, reply count, unique contributors, and engagement rate (replies per post).

Use this view to find spaces that are thriving - and spaces that have gone quiet and may need a prompt or a featured topic.

Top Contributors

A ranked table of your most active members sorted by total contributions (posts + replies + accepted answers). Each row shows the member's avatar, display name, trust level, and contribution breakdown.

Tip: Use this list to identify members to invite into a moderator role, feature in a community spotlight, or send a personal thank-you.

Engagement Metrics

The engagement section shows:

Metric What it means
Avg. replies per post How much discussion each new topic generates
Vote activity Total upvotes and downvotes cast
Accepted answers Q&A spaces only - rate of questions getting resolved
New member joins Community growth over the period

Moderation Stats

The moderation section shows flagged content volume, auto-moderation rule triggers (if Advanced Moderation is enabled), and moderator response time. A high flag volume combined with slow response time signals you need more moderators.

CSV Export

Click Export CSV in the top right of any table to download a full data export for the current date range. Exports include all rows - not just the visible page.

Exported files are compatible with Excel, Google Sheets, and any BI tool. Column headers match the on-screen labels exactly.

Dual-Path Aggregator (1.4.1, observation only)

In 1.4.1 a second analytics path runs quietly alongside the existing direct-query reader. It's an event-driven aggregator that writes to a new internal table (jt_pro_analytics_aggregate) on every relevant community event, instead of querying core tables every time the dashboard loads.

The aggregator is in a 7-day observation window. Your dashboards still read from the original direct-query path in 1.4.1 - there is no public-facing behaviour change yet. The point of the observation window is to verify that the two paths agree before flipping the default.

Verify Dual-Path admin toggle

Go to Jetonomy → Analytics. The Pro Analytics page now has a Verify dual-path toggle. Turn it on and every metric on the page is shown twice - once from the direct-query reader, once from the aggregator - with a drift percentage between them. Use this if you want to spot-check the aggregator's accuracy before we promote it to default.

GET /jetonomy/v1/analytics/diff-report

For programmatic comparison, the same data is available at:

GET /wp-json/jetonomy/v1/analytics/diff-report?range=30d

{
  "range": "30d",
  "metrics": [
    { "key": "total_posts", "direct": 1284, "aggregated": 1284, "drift_pct": 0 },
    { "key": "active_members", "direct": 312, "aggregated": 311, "drift_pct": -0.32 }
  ]
}

Helpful if you want to ship a custom monitoring panel during the observation window.

What's Next?

Reduce your moderation workload by automating common moderation decisions.

Advanced Moderation Rules →

Define rules that catch bad content automatically - before it ever appears in your community.

PRO - This feature requires Jetonomy Pro.

What You Will Learn

  • How to enable Advanced Moderation Rules
  • How to create keyword, regex, link-limit, and spam-score rules
  • What actions each rule can take on matched content
  • How to scope rules to a specific space or apply them globally
  • How to read rule trigger statistics

Why Auto-Moderation Matters

Manual moderation does not scale. A single moderator reviewing every post works fine at 10 posts per day - it fails at 1,000. Auto-moderation rules handle the obvious cases automatically so your human moderators can focus on edge cases that require judgment.

Advanced Moderation complements the free trust level system. New members with Trust Level 0 are already rate-limited. Auto-moderation rules add a content layer on top of that.

Enabling Advanced Moderation

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Advanced Moderation and click Enable.
  3. A Moderation Rules tab appears under Jetonomy → Moderation.

Creating a Rule

  1. Go to Jetonomy → Moderation → Rules.
  2. Click Add Rule.
  3. Configure the rule:
Setting Description
Name Internal label - members never see this
Pattern type Keyword, Regex, Link limit, or Spam score
Pattern The word, phrase, regex, or threshold to match
Action What happens when the rule triggers
Scope Global (all spaces) or a specific space
Active Enable or disable the rule without deleting it
  1. Click Save Rule.

Pattern Types

Keyword

Matches any post or reply body that contains the exact word or phrase (case-insensitive). Use comma-separated values to match any of several words with a single rule.

Example: buy now, click here, limited offer

Regex

Full regular expression matched against the post body. Use this for patterns a keyword list cannot capture - phone number patterns, URL shortener patterns, or obfuscated spam.

Example: \b(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b

Note: Regex patterns are evaluated server-side using PHP preg_match(). Test your regex at regex101.com before adding it to a live rule.

Triggers when a post or reply contains more than a set number of links. New spammers often post content with 5-10 outbound links. A limit of 3 catches most of these while allowing legitimate "here are some resources" posts.

Spam Score

Jetonomy calculates a spam probability score (0-100) for each post based on content patterns, account age, and posting frequency. Set a threshold - any post above that score triggers the rule.

A threshold of 80 is a good starting point. Lower it only if you are seeing spam slip through.

Rule Actions

Action What happens
Flag Content publishes normally and is added to the mod queue with a flag
Hold Content is held as Pending and does not appear until a moderator approves it
Block The post is rejected and the member sees an error message
Spam Content is marked as spam and hidden immediately

Choose the least restrictive action that solves the problem. Use Flag for borderline content, Hold for likely-bad content, and Block or Spam for clearly harmful content.

Rule Scope

Global rules apply to every post and reply across all spaces. Use these for site-wide policies - prohibited words, adult content, competitor spam.

Space-scoped rules apply only within a specific space. Use these for space-specific norms - a Support space might block all links to prevent fishing attacks, while General Chat allows them freely.

Rule Statistics

The rules list shows a Triggered count for each rule - how many times it has fired since the rule was created. Click a rule to see a breakdown by action, by space, and a timeline chart.

Use this data to tune your rules. A rule that triggers 500 times in a week and sends everything to Spam probably needs a higher threshold - it is catching legitimate content.

REST API

Advanced Moderation manages rules under jetonomy/v1:

Method Endpoint Description
GET /moderation/rules List all moderation rules
POST /moderation/rules Create a rule
PATCH /moderation/rules/{id} Update a rule
DELETE /moderation/rules/{id} Delete a rule
GET /moderation/rules/{id}/stats Get a rule's trigger statistics

All routes require manage_options. See the REST API reference for full payloads.

What's Next?

Re-engage members who have not visited recently with automated email digests.

Email Digest →

Send a curated summary of community activity to members' inboxes - daily or weekly - so they never feel out of the loop.

PRO - This feature requires Jetonomy Pro.

Email digest preview showing top posts from the week

What You Will Learn

  • How to enable and configure the Email Digest
  • What content appears in each digest
  • How members control their digest frequency
  • How to send a test digest as an admin

Why Email Digest Matters

Most community members are not daily visitors. They join, participate a few times, and drift away - not because they lost interest, but because they forgot. A well-timed email digest brings them back. It shows them what they missed and gives them a reason to click.

Enabling Email Digest

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Email Digest and click Enable.
  3. Go to Jetonomy → Settings → Email Digest to configure sending times and content rules.

Configuring the Digest

Send Schedule

Set when the digests go out:

Digest type Default send time
Daily 8:00 AM (site timezone)
Weekly Monday, 8:00 AM (site timezone)

You can change both send times in the Email Digest settings. Times use the timezone set in Settings → General → Timezone in WordPress.

Digest Content

The digest compiles:

  • Top posts - the most-upvoted new topics since the last digest
  • Active discussions - posts with the most replies in the period
  • Spaces you follow - activity in spaces the member has joined or bookmarked
  • Replies to your topics - new replies on topics the member created or commented on
  • 🏆 Badges earned (new in 1.4.1) - every badge the member earned during the digest window
  • 🗳️ Polls voted on (new in 1.4.1) - every poll the member participated in during the window

You can toggle each content section on or off in the digest settings. At least one section must remain on.

How the new sections work: badges and polls are tracked in a per-user buffer that's capped at 100 events with a 30-day TTL. The buffer is cleared only after a successful send, so opted-out members never accumulate state, and a missed send doesn't lose the activity.

The Jetonomy, Settings, Email Digest panel, showing the daily and weekly send-time fields and the per-section content toggles

Tip: Keeping "Replies to your topics" on is the single most effective setting. Members always care more about activity on their own posts than about the broader community.

Member Notification Preferences

Each member controls their own digest frequency from Profile → Notification Settings → Email:

Option What it means
Instant Individual emails per event (free behavior)
Daily digest One email per day summarizing activity
Weekly digest One email per week summarizing activity
None No community emails

Members who select Daily or Weekly stop receiving per-event notification emails. The digest replaces them - they are not sent in addition to them.

New members default to Daily digest. You can change this default in the Email Digest settings.

Admin Test Send

Before going live, send yourself a test digest to check formatting and content:

  1. Go to Jetonomy → Settings → Email Digest.
  2. Scroll to the Test Send section.
  3. Enter an email address (pre-filled with your admin email).
  4. Click Send Test Digest.

The test digest uses real community data from the last 7 days. If your community is new and has little activity, the digest may look sparse - that is expected.

Digest Statistics

The Email Digest settings page shows send statistics for the last 90 days:

Stat Description
Digests sent Total number of emails delivered
Preference breakdown How many members are on daily vs weekly vs none

Open rates and click rates are available if you use a supported ESP adapter (SendGrid, Mailgun, SES, or Postmark) - basic wp_mail delivery does not provide tracking data.

REST API

Email Digest exposes endpoints under jetonomy/v1:

Method Endpoint Description
GET /users/me/digest-preferences Read the current member's digest frequency and section choices
PATCH /users/me/digest-preferences Update the current member's digest preferences
POST /admin/digest/test Send a test digest (admin)
GET /admin/digest/stats Read digest send statistics (admin)

Members manage their own preferences; the /admin/* routes require manage_options. See the REST API reference for full payloads.

What's Next?

Connect your community to external tools like Slack, CRMs, and Zapier using outbound webhooks.

Outbound Webhooks →

Automatically send community events to any external URL - connect Jetonomy to Slack, Zapier, your CRM, or any custom pipeline.

PRO - This feature requires Jetonomy Pro.

Webhook management page listing configured endpoints

What You Will Learn

  • How to create and manage webhook endpoints
  • Which community events you can subscribe to
  • How to test a webhook before going live
  • How to read the delivery log to debug failures

Why Webhooks Matter

Jetonomy lives inside WordPress - but your business does not. Your team lives in Slack. Your sales data lives in a CRM. Your analytics live in a data warehouse. Webhooks close that gap. Every time something happens in your community, Jetonomy can push that data wherever you need it - in real time, with zero polling.

Enabling Webhooks

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Outbound Webhooks and click Enable.
  3. A Webhooks item appears under the Jetonomy admin menu.

Creating a Webhook

  1. Go to Jetonomy → Webhooks.
  2. Click Add Webhook.
  3. Fill in the endpoint settings:
Setting Description
URL The HTTPS endpoint that will receive the POST request
Events Which community events trigger this webhook
Secret Optional signing secret for verifying payload authenticity
Active Toggle the webhook on or off without deleting it
  1. Click Save Webhook.

The Add Webhook form, with the URL, Events, Secret, and Active fields

Available Events

Subscribe to any combination of these events:

Event Fires when...
post.created A new topic is published
post.updated A topic is edited
post.deleted A topic is deleted or trashed
reply.created A new reply is posted
reply.updated A reply is edited
reply.deleted A reply is deleted or trashed
vote.cast A member votes on a post or reply
answer.accepted A Q&A answer is accepted
member.joined A new user joins the community
member.left A member leaves a space
member.banned A member is banned
user.registered A new user account is created
trust_level.changed A member is promoted or demoted
flag.created Content is flagged by a member
flag.resolved A flag is resolved by a moderator
moderation.action A moderator approves, spams, or trashes content

You can create multiple webhooks pointing to different URLs with different event subsets - for example, one webhook for Slack (post events only) and one for your CRM (member events only).

Payload Format

Every webhook delivers a JSON body with this structure:

{
  "event": "post.created",
  "timestamp": "2026-03-26T08:14:32Z",
  "site_url": "https://yoursite.com",
  "data": {
    "post_id": 1024,
    "title": "How do I reset my password?",
    "author_id": 45,
    "author_name": "Priya Sharma",
    "space_id": 3,
    "space_slug": "support",
    "url": "https://yoursite.com/community/s/support/t/how-do-i-reset-my-password/"
  }
}

The data object varies by event type. All events include event, timestamp, and site_url.

Verifying Payloads

If you set a secret, Jetonomy includes an X-Jetonomy-Signature header with each request. The value is an HMAC-SHA256 signature of the raw request body, signed with your secret.

Verify on your server:

$signature = hash_hmac( 'sha256', $raw_body, $your_secret );
$expected   = 'sha256=' . $signature;
$received   = $_SERVER['HTTP_X_JETONOMY_SIGNATURE'];

if ( ! hash_equals( $expected, $received ) ) {
    http_response_code( 401 );
    exit;
}

Testing a Webhook

Before you point a webhook at a production system, send a test:

  1. Open the webhook in Jetonomy → Webhooks.
  2. Click Send Test.
  3. Jetonomy sends a sample ping event to your URL and shows the HTTP response code and body inline.

Use a tool like webhook.site to inspect the full request during development.

Delivery Log

Every delivery attempt is logged. Go to Jetonomy → Webhooks → [webhook name] → Delivery Log to see:

  • Timestamp of each attempt
  • HTTP response code
  • Response body (first 500 characters)
  • Whether the delivery succeeded or failed

Failed deliveries are retried up to three times with exponential backoff (5 min, 30 min, 2 hrs). After the third failure, the delivery is marked as permanently failed and no further retries are attempted.

Tip: If you see consistent failures, check that your endpoint returns a 2xx response within 10 seconds. Jetonomy times out at 10 seconds and treats the delivery as failed.

Use Case Examples

  • Slack notifications - Post a message to a Slack channel whenever a new topic is created in your community.
  • CRM sync - Push member.joined events to HubSpot or Salesforce to trigger a welcome sequence.
  • Zapier - Connect any event to thousands of apps via a Zapier webhook trigger - no custom code needed.
  • Analytics pipeline - Stream all events to a data warehouse like BigQuery or Amplitude for long-term retention and custom analysis.

Upgrading From Older Versions

On Jetonomy 1.4.1 and newer every event in the list above fires reliably for real community activity. If you configured webhooks on an older version and saw zero deliveries despite real activity, update both the free and Pro plugins together to 1.4.1 or later - your existing webhooks start delivering without any reconfiguration.

What's Next?

Send browser push notifications to members even when they are not on your site.

Web Push Notifications →

Reach members with browser push notifications - even when they have closed your site.

PRO - This feature requires Jetonomy Pro.

What You Will Learn

  • How to generate VAPID keys and enable Web Push
  • How members subscribe to push notifications
  • Which events trigger a push notification
  • Which browsers are supported

Why Web Push Matters

Email notifications have open rates around 20-30%. Browser push notifications have open rates above 60% because they appear immediately on the member's screen - no inbox, no subject line, no waiting. For time-sensitive events like a reply to your question or a mention from a teammate, push gets the message there instantly.

Enabling Web Push

Web Push requires a VAPID key pair to authenticate your server with browsers.

  1. Go to Jetonomy → Settings → Web Push.
  2. Click Generate VAPID Keys. Jetonomy creates a public/private key pair and stores them in your WordPress options table.
  3. Toggle Enable Web Push to on.
  4. Click Save.

Important: VAPID keys are generated once. If you regenerate them, all existing push subscriptions are invalidated and members must subscribe again. Only regenerate if you believe your private key has been compromised.

Web Push settings page with VAPID key fields and enable toggle

Service Worker Registration

Jetonomy automatically registers a service worker (/community/sw.js) on every community page. You do not need to create or configure the service worker - this happens at extension activation.

The service worker handles:

  • Receiving push messages from the Jetonomy server
  • Displaying the browser notification
  • Opening the correct URL when the notification is clicked

Member Subscription

The first time a logged-in member visits any community page after you enable Web Push, a Enable push notifications prompt appears at the top of the page. Clicking Enable triggers the browser's native permission dialog.

Members who grant permission are subscribed automatically. Their subscription is stored in the Jetonomy database and associated with their account.

Members can unsubscribe at any time from Profile → Notification Settings → Push Notifications → Off.

Note: The browser permission prompt can only be triggered by a user action (a click). Jetonomy waits for the member to interact with the prompt banner before requesting permission - it never requests permission automatically on page load.

Notification Events

Push notifications are sent for the same events that trigger bell notifications, based on each member's preferences:

Event Who receives a push
New reply on your topic Topic author
New reply in a topic you follow Followers
You are mentioned Mentioned member
Your answer is accepted Answer author
New message received Message recipient (Private Messaging Pro)
Badge awarded Badge recipient

Members control which of these events trigger a push in Profile → Notification Settings.

Browser Support

Web Push works on all major modern browsers without any app installation:

Browser Desktop Mobile
Chrome Yes Yes (Android)
Edge Yes Yes (Android)
Firefox Yes Limited
Safari Yes (macOS 13+) Yes (iOS 16.4+)

Tip: Safari on iOS requires members to add your site to their Home Screen before push notifications work. This is an Apple platform limitation - not a Jetonomy limitation.

REST API

Web Push registers these endpoints under jetonomy/v1:

Method Endpoint Description
POST /push/subscribe Register the current member's browser push subscription
DELETE /push/subscribe Remove the current member's push subscription
GET /push/vapid-key Fetch the public VAPID key the browser needs to subscribe
GET /push/service-worker.js Serve the service worker script

Subscribe and unsubscribe require the member to be logged in; the VAPID key and service worker are served for the page to register push. See the REST API reference for full payloads.

What's Next?

Let members reply to community topics directly from their email client.

Reply by Email →

Let members reply to community discussions directly from their email client - no login required for that one reply.

PRO - This feature requires Jetonomy Pro.

What You Will Learn

  • How Reply by Email works end to end
  • How to configure the inbound email endpoint
  • How emails are parsed and turned into replies
  • How to test the feature and handle parsing errors

Why Reply by Email Matters

Every step between "I got a notification" and "I posted a reply" loses members. Reply by Email removes all those steps. The member reads the notification in their inbox, types a reply directly, hits Send, and the reply appears in the community - without opening a browser or logging in. Removing that friction increases reply volume noticeably.

How It Works

  1. Jetonomy sends a notification email for a new reply or mention.
  2. The email contains a Reply to this post call to action with a unique reply-to address.
  3. The member replies to that email.
  4. The inbound email is delivered to your configured endpoint.
  5. Jetonomy parses the email, strips quoted content, and creates a community reply attributed to that member.

Each reply-to address is unique to the member and the topic - it encodes an authentication token so no login is required.

Configuration

Reply by Email requires an inbound email endpoint - a URL that receives incoming emails from your email provider. Most email providers (SendGrid Inbound Parse, Mailgun Inbound Routes, Postmark Inbound, or Amazon SES with SNS) can forward inbound email as an HTTP POST to a URL.

Step 1: Get Your Inbound Endpoint URL

  1. Go to Jetonomy → Settings → Reply by Email.
  2. Copy the Inbound Endpoint URL. It looks like:
https://yoursite.com/wp-json/jetonomy/v1/email/inbound

Step 2: Configure Your Email Provider

Point your email provider's inbound parsing feature at the Jetonomy endpoint URL. The exact steps vary by provider - follow your provider's documentation for "inbound email parsing" or "inbound routing."

Set up a dedicated inbound domain or subdomain for replies. Example: reply.yoursite.com. Your provider resolves inbound mail sent to *@reply.yoursite.com and forwards the parsed payload to your Jetonomy endpoint.

Step 3: Enter Your Reply Domain

Back in Jetonomy → Settings → Reply by Email, enter the reply domain (e.g. reply.yoursite.com) and click Save.

Jetonomy now generates per-user, per-topic reply addresses using that domain.

The Jetonomy, Settings, Reply by Email screen, showing the Inbound Endpoint URL and the reply domain field

Email Parsing

Jetonomy parses the incoming email using these rules:

  1. Strip quoted content - Lines that begin with > (standard email quoting) are removed. The reply contains only the new text the member typed.
  2. Plain text preferred - If the email has a plain text part, Jetonomy uses that. If not, it strips HTML and uses the text content.
  3. Basic formatting preserved - Line breaks are preserved. Links in the plain text body are converted to Markdown links.
  4. Attachments ignored - Image and file attachments in reply emails are not processed in v1.0.

The parsed reply text goes through the same wp_kses_post sanitization as any other reply before it is saved.

Parsing Rules Configuration

You can adjust how Jetonomy handles edge cases:

Setting Default Description
Min reply length 5 characters Rejects replies shorter than this (catches accidental sends)
Max reply length 10,000 characters Truncates anything longer
Strip signatures On Removes common signature separators (-- , Sent from my iPhone, etc.)

Security

Each reply-to address contains a signed token that ties the email address to a specific WordPress user and topic. Jetonomy verifies the token before creating any reply. An attacker who intercepts or guesses a reply address cannot post as another member - the token is cryptographically bound to the user ID.

Tokens expire after 30 days. Notification emails older than 30 days cannot be replied to by email.

Testing Reply by Email

  1. Go to Jetonomy → Settings → Reply by Email.
  2. Click Send Test Email to send a sample notification to your admin email address.
  3. Reply to that email with any text.
  4. Return to the admin and click Check Last Inbound to see the parsed result.

What's Next?

Remove all Jetonomy branding and present the community as entirely your own.

White Label & Branding →

Remove all Jetonomy branding and present your community as entirely your own product.

PRO - This feature requires Jetonomy Pro.

What You Will Learn

  • How to enable White Label
  • How to remove Jetonomy branding from the frontend and admin
  • How to set a custom admin menu label and icon
  • How to rebrand transactional emails and digests

Why White Label Matters

You built your community. Your members know your brand - not the plugin powering it. White Label means your community looks like yours from every angle: the frontend pages, the admin sidebar, and the notification emails. This is especially important for agencies delivering client projects and for SaaS products embedding community features under their own brand.

Enabling White Label

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find White Label and click Enable.
  3. A Branding tab appears under Jetonomy → Settings.

Removing Frontend Branding

Go to Jetonomy → Settings → Branding.

Setting Default What it controls
"Powered by Jetonomy" footer Shown Remove the attribution link from the community footer
Jetonomy logo in community nav Shown Replace with your own logo or hide entirely
Custom CSS injection Empty Add CSS that loads on every community page

Upload your own logo (SVG or PNG, max 400×100 px) to replace the Jetonomy logo in the community navigation bar. Leave the logo field blank to show no logo at all.

White Label branding settings panel

Tip: Use the Custom CSS injection field to apply brand-specific color overrides without editing any theme files. The CSS injects after Jetonomy's own stylesheet so your values always win.

Admin Menu Customization

By default, the Jetonomy admin menu item is labeled "Jetonomy" with the Jetonomy logo icon.

In Jetonomy → Settings → Branding → Admin Menu:

  • Menu label - Change to any string (e.g. "Community", "Forum", "My Community").
  • Menu icon - Enter any Dashicons class (e.g. dashicons-groups) or leave blank to use the default.

The label change applies to the top-level menu item and the browser window title on all Jetonomy admin pages.

Email Branding

White Label also affects transactional emails and digests. In Settings → Branding → Email:

  • From name - Defaults to your site name. Change to any value.
  • Email footer - Replaces the default Jetonomy email footer with your own text or HTML.
  • Logo in emails - Upload a logo displayed at the top of notification emails.

Branding Settings Reference

White Label stores its configuration in the jetonomy_pro_white_label option. The settings worth calling out:

Setting What it does
header_logo_url The logo actually displayed in the community header. This is the image members see at the top of every community page.
logo_url The fallback / Open Graph logo. Used for social share cards (OG image) and anywhere a logo is needed but no header logo is set. Keep this set even if you customize the header separately.
accent_color A global accent colour override. Recolours Pro-rebranded surfaces - including email accents - in one place so your brand colour is consistent across the community and its emails.
custom_css Freeform CSS injected on every community page. It loads after Jetonomy's own stylesheet, so your rules always win - use it for brand colour and spacing tweaks without touching theme files.
sidebar_auth_card_html Custom HTML for the community sidebar's sign-in / call-to-action card. When set, it replaces Jetonomy's default auth card with your own markup; leave it empty to keep the default card.
footer_text Replaces the "Powered by Jetonomy" footer text.
email_logo_url Logo shown at the top of notification and digest emails.

Tip: header_logo_url and logo_url are deliberately separate. Set header_logo_url for the on-page logo and logo_url for the share-card / fallback image - they are often different sizes and aspect ratios.

REST API

White Label exposes its settings under jetonomy/v1:

Method Endpoint Description
GET /settings/white-label Read the current white-label settings
PATCH /settings/white-label Save white-label settings

Both routes require manage_options. See the REST API reference for full payloads.

Upgrading From Older Versions

On Jetonomy 1.4.1 and newer every White Label setting applies on every surface - the header logo, footer text, email accent colour, email logos, the sidebar sign-in card, and the admin footer all rebrand on each render and send. On older versions the Branding settings saved but did not always take effect; update both the free and Pro plugins together so all branding applies.

What's Next?

Bring large language models into your community for smarter spam detection, auto-moderation, reply suggestions, and thread summaries.

AI Integration →

Bring large language models into your community - for smarter spam detection, auto-moderation, reply suggestions, and thread summaries - without sending data to a third party unless you want to.

PRO - This feature requires Jetonomy Pro.

The AI Integration settings tab: provider activation (OpenAI, Anthropic, Ollama, Custom), the default-provider fallback chain, per-feature toggles for spam detection, content moderation, reply suggestions and thread summaries, the live usage dashboard, member usage limits, and the monthly spend cap

What You Will Learn

  • How the AI extension is organized (providers + features)
  • Which AI providers Jetonomy supports, including self-hosted Ollama
  • How to enable AI-powered spam detection, content moderation, reply suggestions, and thread summaries
  • Where to monitor token usage and cost
  • How to keep community content private by running models locally

Why AI Matters for Communities

Moderation is the single biggest burden on community owners. Every post and every reply is a potential spam attempt, abuse report, or duplicate question. At 50 topics a day, a human moderator can keep up. At 500, they cannot.

The Jetonomy Pro AI extension gives your community a language model that reads every new post and every new reply, flags the ones that need a human, and leaves the rest alone. It does not replace your moderators - it filters what they see so they can focus on judgment calls instead of the obvious cases.

Supported Providers

Jetonomy's AI layer is built on a pluggable adapter pattern. Four providers ship out of the box:

Provider Hosted by Best for
Ollama You - runs on your own server Privacy-sensitive communities, GDPR, full data control
OpenAI OpenAI Fastest time to value, best general quality
Anthropic Anthropic (Claude) High-quality moderation, long context windows
Custom You Self-hosted vLLM, LM Studio, or any OpenAI-compatible endpoint

You can register more than one provider and assign different features to different providers - for example, run moderation through Ollama locally while using OpenAI only for summaries of long threads.

Tip: If you already run Ollama on the same server as WordPress, the AI extension uses it over localhost - no network hop, no API key, no data leaves your machine.

Multi-Provider Fallback Chain

Every AI feature can be assigned a primary provider plus an optional fallback chain. If the primary provider errors mid-request (rate limit, timeout, 5xx), Jetonomy automatically retries the next provider in the chain before surfacing an error to the admin.

Typical setup: Ollama (primary) → OpenAI (fallback) → Anthropic (second fallback). You get privacy-first moderation with a safety net for the moments when the local model is restarting or overloaded.

The chain is configured per feature at Jetonomy → Settings → AI Integration → Advanced. Requests that succeed via the fallback chain are logged with a fallback_used flag so you can spot providers that are flapping.

Monthly Spend Caps

Every cloud provider (OpenAI, Anthropic, Custom) can be given a monthly spend cap in USD. Once usage crosses the cap in the current billing window, Jetonomy stops dispatching requests to that provider and surfaces a clear admin notice explaining what happened and when the cap resets.

Spend caps protect you from a runaway loop - a broken summary trigger, a spam wave that hits the reply-suggestion endpoint - draining your account. Self-hosted Ollama has no cap UI because it has no per-request cost.

Caps are evaluated against the usage log (wp_jt_pro_ai_usage), not the provider's invoice, so the cap reacts immediately. Expect a 2-3% variance versus your invoice at the end of the month because Jetonomy's estimate uses published token rates.

AI-Powered Features

Each feature can be toggled independently from Jetonomy → Settings → AI Integration.

Spam Detection

Replaces the free plugin's pattern-based spam detector with a model-driven classifier. Each new post or reply is scored for spam probability before it is published. Posts above the threshold go straight to the moderation queue; posts below it are published as normal.

Works alongside Akismet and trust-level rate limits - AI spam detection is the third layer, not a replacement.

Content Moderation

Flags content that breaks rules you describe in plain English. You write a few sentences - "no political attacks, no personal insults, no harassment" - and the model reads every new post against that policy.

Violations are sent to the moderation queue with a reason the model generated. Your human moderators make the final call, but they see a pre-filled explanation instead of a blank flag.

Moderation presets - Four tuned presets ship out of the box so you do not have to write a policy from scratch:

Preset Tuned for
Community Forum General discussion boards. Flags spam, harassment, obvious off-topic. Permissive on mild profanity and opinion-based disagreement.
Support Desk Product and service support. Flags abusive language toward staff, solicitation, and off-topic promotion. Permissive on frustration.
Kids Safe Under-13 communities. Aggressive filter - any profanity, sexual language, personal contact requests, or outside links flagged.
Academic University and research communities. Flags plagiarism indicators, academic dishonesty keywords, and personal attacks. Permissive on technical debate.

Pick a preset as your starting point and customize from there. The preset fills the policy text field - you edit it - and the model uses your edited copy.

Reply Suggestions

When a member is composing a reply, Jetonomy can ask the model for a draft based on the topic context. The member can accept it, edit it, or ignore it. Draft replies are never sent without human approval.

Great for knowledge-base communities where most answers follow a pattern.

Thread Summaries

On long threads (30+ replies), Jetonomy can generate a short summary pinned at the top of the topic. New visitors read the summary instead of scrolling through every back-and-forth. Summaries regenerate when new replies meaningfully change the conversation.

Cached in the wp_jt_pro_ai_cache table so each summary is generated once per content state.

Enabling AI Integration

  1. Go to Jetonomy → Extensions and enable AI.
  2. Open Jetonomy → Settings → AI Integration.
  3. Choose a provider. For Ollama, enter the base URL (usually http://localhost:11434) and the model name (for example, llama3.1:8b).
  4. (Optional) Add a fallback provider and set a monthly spend cap at AI Integration → Advanced.
  5. Turn on the individual features you want - Spam Detection, Content Moderation, Reply Suggestions, or Thread Summaries. Pick a Content Moderation preset if you enable moderation.
  6. Save.

Each feature has its own Enable switch and an optional Provider Override, so you can, for example, run moderation locally on Ollama while sending summaries to OpenAI - see the per-feature toggles in the AI Integration settings tab above.

Usage Tracking and Cost

Every AI request is logged to the wp_jt_pro_ai_usage table with the model used, token counts, latency, and estimated cost.

AI Usage dashboard widget - A dedicated widget appears on the main Jetonomy admin dashboard as soon as at least one provider is connected. It shows at a glance:

  • Requests today and this month
  • Token usage by feature
  • Estimated spend by provider (and percentage of the monthly cap consumed)
  • Average response time
  • Error rate and fallback-chain activations

The AI Usage widget on the main Jetonomy admin dashboard, showing requests today and this month, token usage by feature, estimated spend by provider with the share of the monthly cap consumed, average response time, and error rate

A detailed breakdown lives at Jetonomy → Settings → AI Integration → Usage with per-day charts, per-feature filtering, and CSV export.

If a feature starts running hot (a new spam wave, an unexpected summary loop), you see it in the dashboard and can pause that feature without disabling the whole extension. The spend cap will also pause the provider automatically if the runaway is expensive enough to cross the cap.

Privacy and Self-Hosting

For communities that cannot send member content to a third-party API - legal, health, financial, enterprise internal - run Ollama on the same server. Jetonomy talks to the model over localhost only. No external network calls, no API keys, no data leaves your machine.

The wp_jt_pro_ai_log audit table records every model decision (feature, object, confidence, action taken) so you have a permanent record of what the AI did and why - useful for compliance reviews.

REST API

The AI extension registers three endpoints under jetonomy/v1:

Method Endpoint Description
GET /ai/usage Aggregated usage metrics for a date range
GET /ai/usage/summary Rolled-up usage summary for a date range
POST /ai/suggest-reply Request a reply suggestion - pass post_id in the JSON body

The two usage endpoints require an administrator (manage_options). /ai/suggest-reply requires any logged-in member and is rate-limited.

What's Next?

Give every Pro space its own SEO controls - custom meta titles, Open Graph images, schema, and sitemap rules.

SEO Pro →

Give every space its own meta titles, Open Graph images, Twitter Cards, schema markup, and sitemap rules - without touching your site-wide SEO plugin.

PRO - This feature requires Jetonomy Pro.

The SEO tab inside a space's settings panel, showing the meta title, meta description, and Open Graph image fields

What You Will Learn

  • Why community SEO is different from page/post SEO
  • How to set per-space meta titles and descriptions
  • How to control Open Graph and Twitter Card previews per space
  • How Jetonomy outputs Schema.org structured data automatically
  • How to include or exclude spaces from your sitemap
  • How to customize robots directives and canonical URLs

Why Community SEO Is Different

Your posts and pages have one author, one publish date, and one body. A forum topic has dozens of authors, evolves over time, and the most recent reply is often the most important part. A Q&A thread is really a QAPage with an acceptedAnswer, not a blog post. A sitemap that treats every reply as a top-level URL pollutes your search index.

The free Jetonomy plugin already outputs baseline SEO - canonical URLs, Open Graph tags, Schema.org, and a sitemap provider for spaces and posts. SEO Pro is for when you need to override the defaults on a per-space basis, because different spaces have different audiences, different goals, and different search intent.

Per-Space Meta Title and Description

Every space gets a dedicated SEO tab in its settings panel. Inside that tab:

  • Meta Title - defaults to the space name. Override for search engines only (the on-site title stays unchanged).
  • Meta Description - defaults to the space description. Override with a keyword-rich summary written for search snippets.
  • Meta Keywords - legacy field, not used by Google but some vertical engines still read it. Optional.

Both meta title and description support template tokens: {space_name}, {site_name}, {space_count}, {post_count}. For example, a meta title template of {space_name} - {post_count} discussions | {site_name} produces Python Help - 2,481 discussions | MyForum automatically.

Open Graph and Twitter Cards

SEO Pro lets you upload a custom Open Graph image per space - a 1200x630 image used when the space URL is shared on Facebook, LinkedIn, and Slack. It also lets you override:

  • Open Graph title (defaults to meta title)
  • Open Graph description (defaults to meta description)
  • Twitter Card type (summary or summary_large_image)
  • Twitter Card image

If you skip these fields, Jetonomy falls back to the meta title/description and uses the default OG image from your main settings.

Schema.org Structured Data

For every space and every post, Jetonomy Pro emits JSON-LD structured data:

  • Space pages - DiscussionForumPosting with post count and date
  • Topic pages (Forum) - DiscussionForumPosting with author, date, and answer count
  • Topic pages (Q&A) - QAPage with acceptedAnswer (if marked) and suggestedAnswer entries
  • Topic pages (Ideas) - CreativeWork with about (the idea)
  • User profiles - Person with memberOf the space list
  • Breadcrumbs - BreadcrumbList on every community page

You do not need to configure any of this. Enabling SEO Pro turns it on automatically. The free plugin emits a subset of these (basic DiscussionForumPosting and BreadcrumbList) - SEO Pro adds the richer types.

Sitemap Controls

Jetonomy core registers a sitemap provider for spaces and posts. SEO Pro adds:

  • Include / exclude per space - mark a private support space as excluded from the sitemap with one click
  • Priority per space - boost your flagship space above others in the sitemap XML
  • Change frequency per space - hint at how often a space updates (always, hourly, daily, weekly, monthly)
  • Maximum URLs per sitemap - split large sitemaps into chunks that search engines can crawl without timing out

All sitemap changes take effect on the next request - no flush needed.

Robots Directives and Canonical URLs

  • Robots meta per space - set noindex, nofollow, noarchive, or any combination on a space-by-space basis. Useful for staff-only spaces that should not appear in search results.
  • Custom canonical URL - override the default canonical URL on a space or topic. Useful when you syndicate content from an external blog and want Google to credit the original.
  • robots.txt directives - add SEO Pro specific rules to your site's virtual robots.txt without touching a file.

Enabling SEO Pro

  1. Go to Jetonomy → Extensions and enable SEO Pro.
  2. Open any space in Jetonomy → Spaces.
  3. Click the SEO tab inside the space settings panel.
  4. Fill in the fields you want to override. Leave the rest blank to inherit the site defaults.
  5. Save.

No site-wide settings page - SEO Pro is intentionally per-space, so you do not accidentally change defaults that other spaces depend on.

REST API

Method Endpoint Description
GET /spaces/{id}/seo Get the current SEO settings for a space
PATCH /spaces/{id}/seo Update the SEO settings for a space

Both endpoints require the manage_jetonomy capability or space-admin role.

Compatibility With Site-Wide SEO Plugins

SEO Pro does not replace Yoast, Rank Math, or All in One SEO. It handles the community area only - URLs under /community/ - and leaves your blog, pages, and WooCommerce products entirely alone. If a site-wide SEO plugin already writes og:title for a community URL, SEO Pro's tags take precedence on community pages.

What's Next?

Feature an important post at the top of every space across your whole community.

Site Announcements →

Feature an important post at the top of every space across your whole community.

PRO - This feature requires Jetonomy Pro.

What You Will Learn

  • How to enable Site Announcements
  • What a community announcement is, and how it differs from pinning a topic in a space
  • Who is allowed to create announcements
  • How to pin a post to the community and where it appears
  • How many announcements you can have at once
  • How to remove an announcement

Enabling Site Announcements

Site Announcements is one of the Pro extensions, enabled the same way as the others:

  1. Go to Jetonomy → Extensions in your WordPress admin.
  2. Find Site Announcements and click Enable.
  3. A Pin to community button appears in the action bar of every post for administrators.

Announcements vs Space Pinning

Jetonomy has two separate "pin" tools for two different jobs:

Space pin ("Pin") Community announcement ("Pin to community")
Scope Top of one space only Top of every space across the community
Who can use it Space moderators and admins Administrators only
Badge shown green Pinned green Announcement
Where to find it The topic's ... menu A Pin to community button on the topic

Use a space pin for a "start here" thread inside one forum. Use a community announcement for something everyone should see no matter which space they are browsing - a maintenance notice, a major release, or community-wide rules. Space pinning is covered in Topic Management.

Who Can Create Announcements

Community announcements are administrator-only. The control is gated by the manage_options and jetonomy_manage_spaces capabilities, and jetonomy_manage_spaces is granted only to the Administrator role by default. Moderators who can pin topics within their own space cannot create site-wide announcements - that power stays with admins, because an announcement affects every space.

Pinning a Post to the Community

  1. Open the post you want to feature.
  2. In the action bar below the post, click Pin to community.

The post is immediately featured across the community. The button changes to Unpin from community, and an Announcement badge appears on the post.

Where Announcements Appear

A community announcement is shown in two places:

  • At the top of every space's listing - above that space's own topics, with an Announcement badge, so members see it wherever they browse.
  • On the post's own header - with the same Announcement badge.

A post can be both space-pinned and a community announcement at the same time; in that case it shows both the Pinned and Announcement badges, which is expected.

The Announcement Limit

You can have up to 5 community announcements at once. When the limit is reached, pinning another post returns "You can only pin 5 announcements at a time. Unpin one first." Keeping the set small protects the value of the slot - if everything is an announcement, nothing is.

Removing an Announcement

Open the post and click Unpin from community in the action bar. The post returns to its normal position everywhere and the Announcement badge is removed. This does not delete or unpin the post within its own space - if it was also space-pinned, that pin remains.

REST API

Site Announcements registers these endpoints under jetonomy-pro/v1:

Method Endpoint Description
GET /site-announcements List the current set of pinned posts and the pin limit
POST /site-announcements/{id} Pin a post to the community
DELETE /site-announcements/{id} Unpin a post from the community

{id} is the numeric post ID. Pinning and unpinning require the manage_options or jetonomy_manage_spaces capability (Administrator by default); the same capability is required to list the current pins. See the REST API reference for full payloads.

What's Next?

You have now seen every Pro feature. Return to the Pro getting-started guide to choose which extensions to enable for your community.

Integrations

Connect with membership plugins, themes, and third-party services.

Jetonomy connects to the membership, course, and community plugins you already run, so a member's access to a discussion space follows their subscription, course enrolment, or group membership automatically. This page is the map of every integration - what each one does, and whether it is in the free plugin or needs Jetonomy Pro.

What You Will Learn

  • Which integrations gate space access (membership and LMS) versus connect two communities (coexistence)
  • Which integrations are in the free plugin and which require Jetonomy Pro
  • Where to go next for each one

Access-gating integrations

These connect an external "who has paid / who is enrolled" system to Jetonomy's Access Rules, so members are added to (and removed from) spaces automatically. They all follow the same Access Rules flow, walked through step by step in the MemberPress guide.

Integration Free or Pro What it gates a space by
MemberPress Free MemberPress membership level
Paid Memberships Pro Free PMPro subscription level
WooCommerce Pro WooCommerce Memberships plan or Subscription product
Restrict Content Pro Pro RCP subscription level
LearnDash Pro LearnDash course or group enrolment
Tutor LMS Pro Tutor course enrolment
LifterLMS Pro LifterLMS course or membership enrolment
Sensei LMS Pro Sensei course enrolment
MasterStudy LMS Pro MasterStudy course enrolment

Tip: Access Rules from different integrations stack. You can gate one space to "MemberPress VIP or a specific WooCommerce product or a LearnDash course" - a member who matches any rule gets in.

Coexistence integrations

These do not gate access by purchase. Instead they make Jetonomy and another community plugin feel like one product - shared members, paired spaces, cross-links, and (where supported) activity broadcast. All are in the free plugin and turn on automatically when the other plugin is active.

Integration Free or Pro What it connects
BuddyNext Free Shares BuddyNext's design tokens and lets BuddyNext own the page header and navigation
BuddyPress Free Pairs BuddyPress groups with forum spaces; two-way member sync, group Forum tab, activity broadcast
FluentCommunity Free Pairs FluentCommunity spaces with Jetonomy spaces; add-only member sync, cross-profile links, activity broadcast

Theme compatibility

Integration Free or Pro What it does
Theme Compatibility Free Adapts Jetonomy to any WordPress theme via CSS custom properties, with full template overrides

Where to Start

  • Running a paid community on MemberPress or Paid Memberships Pro? Start with MemberPress - it is the canonical Access Rules walkthrough every other gating guide links back to.
  • Selling courses? Go to the lead LMS guide, LearnDash, then the matching guide for your LMS.
  • Already on BuddyPress or FluentCommunity? Open the BuddyPress or FluentCommunity guide - nothing to configure to switch the integration on.

Connect MemberPress membership levels to Jetonomy spaces - so paying members automatically land in the right discussion areas the moment their subscription activates.

Available in Jetonomy free. The MemberPress and Paid Memberships Pro adapters ship in the free plugin - you do not need Jetonomy Pro to gate spaces by these two membership plugins. (WooCommerce, Restrict Content Pro, and all LMS integrations require Jetonomy Pro.)

Jetonomy admin settings panel for configuring integrations

What You Will Learn

  • How Jetonomy detects and communicates with MemberPress
  • How to gate a space by membership level using Access Rules
  • What happens when a membership activates or expires
  • How to test the integration before going live

How Detection Works

Jetonomy checks for MemberPress automatically on every page load. No configuration needed. When MemberPress is active, the MemberPress adapter registers itself with Jetonomy's Adapter Registry and enables the Access Rules UI inside each space's settings.

Note: If you activate MemberPress after Jetonomy, navigate to Jetonomy → Settings and save once. This triggers adapter re-registration.

Setting Up an Access Rule

This is the standard Access Rules flow that every membership and LMS integration in this section follows. The other integration guides link back here for the full walkthrough.

Jetonomy Access Rules tab showing a saved membership rule with its Type, Value, Grants, and Space Role columns

  1. Go to Jetonomy → Spaces and open the space you want to gate.
  2. Click the Access Rules tab in the space settings panel.
  3. Set Rule Type to your MemberPress level (membership levels appear in the dropdown once MemberPress is active).
  4. Pick the membership level in the Value field.
  5. Choose what the rule Grants - Read, Participate, or Full (see below).
  6. Choose the Space Role members get when they match - Viewer, Member, Moderator, or Admin (see below).
  7. Click Add Rule. The rule appears in the table below the form.

Members who hold the selected level gain access to this space at the level you chose. Members without it see the space as locked (or hidden, depending on your space visibility setting).

Tip: Add more than one rule if you want to grant access for more than one membership level. Rules are evaluated top to bottom by priority, and a member passes on the first rule they match.

Grants and Space Role

Every Access Rule has two settings that decide what a matching member can do. They are the same across all integrations:

Grants - how much of the space the member can use:

Grants What the member can do
Read View topics and replies, but not post or reply
Participate Read, post topics, and reply (the usual choice for a course or paid space)
Full Participate plus the space-management abilities tied to their Space Role

Space Role - the role the member is given inside this one space:

Space Role Meaning
Viewer Read-only presence in the space
Member A regular participating member (the usual choice)
Moderator Can moderate content in this space
Admin Can manage this space's settings and members

For most gated spaces - a paid membership or a course community - set Grants: Participate and Space Role: Member. Use Moderator or Admin only when you specifically want a membership tier to run the space.

Note: There is no separate "Grant vs Revoke" switch. A rule always grants the access you choose to members who match it; members who match no rule simply do not get in. To take a level's access away, delete its rule.

Auto-Join and Auto-Leave

When a MemberPress membership activates, Jetonomy automatically adds the member to any spaces whose Access Rules grant that level. They receive a welcome notification in the community.

When a membership expires, cancels, or is paused, Jetonomy fires jetonomy_membership_deactivated and removes the member from any spaces gated exclusively to that level. Their posts and replies remain intact.

This is handled by the MemberPress_Adapter class. It hooks mepr-txn-status-complete for activation, and mepr-txn-status-refunded, mepr-txn-expired, and mepr_subscription_transition_status for deactivation.

Visibility Behavior

Space Visibility Non-member sees...
Public Space listed, content visible, locked from posting
Private Space listed with lock icon, content hidden
Hidden Space not listed at all

Developer Hook

Both membership events fire the Jetonomy standard hooks you can use in your own code:

// Fires when a MemberPress membership activates.
add_action( 'jetonomy_membership_activated', function( int $user_id, string $level_id, string $adapter ) {
    // $adapter will be 'memberpress'
    if ( 'memberpress' === $adapter ) {
        // Custom logic here.
    }
}, 10, 3 );

Troubleshooting

Access rules dropdown is empty - MemberPress may not be active. Check Plugins → Installed Plugins and confirm MemberPress is activated.

Member not joining on activation - Ensure the membership level ID in the Access Rule exactly matches the level in MemberPress. Level IDs are numeric; check the MemberPress level edit URL for the ID.

Member still has access after expiry - Check whether the member holds a second membership level that also grants access to the space.

What's Next?

Learn how to gate spaces using Paid Memberships Pro, which follows the same pattern.

Paid Memberships Pro Integration →

Gate Jetonomy spaces by Paid Memberships Pro subscription level - with automatic access granted on activation and revoked on cancellation or expiry.

Available in Jetonomy free. The Paid Memberships Pro adapter ships in the free plugin - Jetonomy Pro is not required to gate spaces by PMPro levels.

Jetonomy admin settings showing integration configuration options

What You Will Learn

  • How Jetonomy detects Paid Memberships Pro (PMPro)
  • How to set up an Access Rule tied to a PMPro level
  • What triggers the auto-join and auto-leave behavior
  • The hook names you can use for custom logic

How Detection Works

Jetonomy detects PMPro automatically when the plugin is active. The PMPro adapter registers with Jetonomy's Adapter Registry and unlocks the Access Rules tab in space settings. No manual connection step is required.

Note: If you activate PMPro after Jetonomy is already running, go to Jetonomy → Settings and save the page once to trigger adapter re-registration.

Setting Up an Access Rule

  1. Go to Jetonomy → Spaces and open the space you want to gate.
  2. Open the Access Rules tab in the space settings panel.
  3. Set Rule Type to your Paid Memberships Pro level (PMPro levels appear in the dropdown once PMPro is active).
  4. Pick the PMPro level in the Value field.
  5. Set Grants to Participate and Space Role to Member for a standard gated space.
  6. Click Add Rule. The rule appears in the table below the form.

Members who hold the selected PMPro level gain access to the space immediately. You can stack multiple rules - access is granted if the member matches any rule.

Tip: For a full explanation of the Grants (Read / Participate / Full) and Space Role (Viewer / Member / Moderator / Admin) choices, see Grants and Space Role in the MemberPress guide - they work the same for every integration.

Auto-Join and Auto-Leave

On activation - when a member's PMPro level activates, Jetonomy adds them to any spaces where that level is in an Access Rule. The hook jetonomy_membership_activated fires with $adapter = 'pmpro'.

On cancellation or expiry - when a PMPro level expires or is manually cancelled, Jetonomy removes the member from gated spaces. The hook jetonomy_membership_deactivated fires with $adapter = 'pmpro'.

The adapter hooks into PMPro's pmpro_after_change_membership_level action to detect both events.

Visibility Behavior

Space Visibility Non-member sees...
Public Space listed, content readable, posting locked
Private Space listed with lock icon, content hidden
Hidden Space not listed at all

Developer Hook

// Fires when a PMPro membership deactivates.
add_action( 'jetonomy_membership_deactivated', function( int $user_id, string $level_id, string $adapter ) {
    if ( 'pmpro' === $adapter ) {
        // Remove user from any related external system.
        my_crm_remove_access( $user_id, $level_id );
    }
}, 10, 3 );

Troubleshooting

Level dropdown is empty in Access Rules - Confirm PMPro is active and that you have at least one membership level created in Memberships → Membership Levels.

Member not removed on cancellation - PMPro has several cancellation states (expired, admin-cancelled, non-renewing). Jetonomy listens to all of them via pmpro_after_change_membership_level where the new level is 0.

Multiple levels, unexpected access - If a user holds more than one PMPro level, Jetonomy evaluates all rules. Access persists as long as any single rule still matches an active level.

What's Next?

Gate spaces using a WooCommerce product purchase or subscription - available in Jetonomy Pro.

WooCommerce Integration →

Gate Jetonomy spaces by WooCommerce Membership plan or active WooCommerce Subscription - so customers unlock discussion areas the moment their membership or subscription becomes active.

The Jetonomy admin settings screen

PRO - This feature requires Jetonomy Pro.

What You Will Learn

  • Which WooCommerce levels Jetonomy Pro supports as access gates
  • How to set up an Access Rule tied to a membership plan or subscription
  • How access activates and revokes on membership and subscription status changes
  • How to combine WooCommerce gates with membership-level gates

Supported Gate Types

The WooCommerce adapter activates only when WooCommerce is active and either WooCommerce Memberships or WooCommerce Subscriptions is also active. What you can select as a gate is a Membership plan or a Subscription product - not a plain Simple or Variable product.

Gate Type Supported Notes
WooCommerce Memberships plan Yes Access tracks the membership status (active/paused/cancelled)
WooCommerce Subscription product Yes Access active while the subscription is active; revoked on hold, cancel, or expiry
Variable-subscription product Yes Selectable like any other subscription product
Plain Simple product No Use a WooCommerce Memberships plan tied to that product instead
Plain Variable product No Use a WooCommerce Memberships plan instead
Grouped product No Gate via a Membership plan instead

Note: Either WooCommerce Memberships or WooCommerce Subscriptions (both WooCommerce.com extensions) is required. WooCommerce on its own does not enable space gating - the adapter stays inactive until one of the two is present.

Setting Up an Access Rule

  1. Install and activate Jetonomy Pro, ensure WooCommerce is active, and ensure WooCommerce Memberships or WooCommerce Subscriptions is active.
  2. Go to Jetonomy → Spaces and open the space you want to gate.
  3. Click the Access Rules tab.
  4. Set Rule Type to WooCommerce.
  5. Pick the Membership plan or Subscription product in the Value field.
  6. Set Grants to Participate and Space Role to Member for a standard gated space.
  7. Click Add Rule.

The Access Rule takes effect immediately. Members who already hold the membership or active subscription are granted access in the background within a few seconds of saving.

Tip: You can add multiple WooCommerce rules to a single space. Access is granted if the member matches any one of the listed memberships or subscriptions. For what the Grants and Space Role fields mean, see Grants and Space Role.

Auto-Activate

Jetonomy Pro listens to WooCommerce Memberships and WooCommerce Subscriptions status changes - not to raw order status transitions.

For WooCommerce Memberships, when a membership becomes active Jetonomy Pro adds the member to any spaces that grant access on that plan and sends a welcome notification.

For WooCommerce Subscriptions, access tracks the subscription status:

Subscription Status Access
Active Granted
On-hold Revoked
Cancelled Revoked
Expired Revoked

Auto-Revoke

Access is revoked through the same status hooks. A WooCommerce Membership moving out of active status, or a subscription moving to on-hold, cancelled, or expired, removes the member from any spaces gated exclusively to that level.

Note: Revocation is driven by membership and subscription status changes, not by order Refunded transitions. Refunding a one-off order does not by itself revoke access - the gating membership or subscription has to change status.

Combining with Other Rules

WooCommerce rules stack with MemberPress, PMPro, and trust-level rules in the same space. A member gains access if they satisfy any rule - regardless of which rule type it is.

Example: gate a "Premium VIP" space to either MemberPress VIP level OR a specific WooCommerce product purchase. Members who qualify through either path are both added automatically.

Troubleshooting

Rule Type dropdown does not show WooCommerce - Confirm Jetonomy Pro is active, WooCommerce is active, and WooCommerce Memberships or WooCommerce Subscriptions is active. The adapter stays inactive (and the rule type is hidden) until one of those two extensions is present.

No plans or products to select - The dropdown lists WooCommerce Memberships plans and Subscription (including variable-subscription) products only. If it is empty, create a Membership plan or a Subscription product first. Plain Simple and Variable products are not selectable.

Member not removed after a refund - Access is tied to the gating membership or subscription status, not the order. Verify the WooCommerce Membership moved out of active status, or the subscription moved to on-hold, cancelled, or expired. A refunded order alone does not revoke access.

What's Next?

Gate spaces by LearnDash course or group enrollment - so students get discussion access automatically when they enroll.

LearnDash Integration →

Connect LearnDash course and group enrollment to Jetonomy spaces - students get dedicated discussion areas automatically when they enroll, and lose access when they un-enroll.

PRO - This feature requires Jetonomy Pro.

Jetonomy Settings - Integrations tab showing the integration status table and the Auto-Create Spaces for Courses card

LearnDash is the lead LMS integration in this section. The other four LMS guides (Tutor, LifterLMS, Sensei, MasterStudy) work the same way and link back here for the screenshots and the shared Access Rules walkthrough.

What You Will Learn

  • How to gate a Jetonomy space by LearnDash course enrollment
  • How to gate a space by LearnDash group membership
  • How to auto-create spaces when new courses are published
  • How to sync existing students into a space
  • What happens when a student un-enrolls

How Detection Works

Jetonomy Pro detects LearnDash automatically when both plugins are active. A LearnDash Course option appears in the Access Rules rule type dropdown - no setup needed. Compatible with LearnDash 4.x and 5.x.

Gating a Space by Course Enrollment

The Access Rules course picker with a searchable dropdown autocompleting course names as you type

  1. Go to Jetonomy → Spaces → open the space → Access Rules tab.
  2. Select LearnDash Course from the rule type dropdown.
  3. Start typing the course name - a searchable dropdown shows all published LearnDash courses.
  4. Select the course, set Grants to Participate and Space Role to Member.
  5. Click Add Rule.

The rule appears in the table showing the course name and a Sync Members button. For what the Grants and Space Role fields mean, see Grants and Space Role.

Gating a Space by LearnDash Group

LearnDash groups also appear in the searchable dropdown. This is ideal for cohort-based learning - one group, one space.

  1. Select LearnDash Course from the rule type dropdown.
  2. Type the group name - groups show as "Group Name (LD Group)" in the results.
  3. Select the group, set Grants and Space Role, and click Add Rule.

All members of the LearnDash group - including group leaders - gain access. When a user is removed from the group, they lose space access.

Syncing Existing Students

If students are already enrolled before the rule was created, click the Sync Members button. This pulls in all currently enrolled users. A notification shows how many were synced.

New enrollments and removals are handled automatically after the rule is created.

Auto-Create Spaces for New Courses

The Auto-Create Spaces for Courses card and the integration status table both live on the Integrations tab shown in the screenshot at the top of this guide (Jetonomy → Settings → Integrations).

  1. Go to Jetonomy → Settings → Integrations.
  2. Enable the LearnDash toggle under Auto-Create Spaces for Courses.
  3. Choose the default space type (Q&A, Forum, or Feed).
  4. Click Save Settings.

When you publish a new course in LearnDash, a private discussion space is automatically created with:

  • The course title as the space name
  • A membership access rule linking the course to the space
  • The course author assigned as space admin

Enrollment and Un-enrollment Events

LearnDash Event Jetonomy Action
Student enrolls in course Added to linked spaces as Member
Student completes course Access retained
Student un-enrolls or is removed Removed from linked spaces
User added to group Added to linked spaces as Member
User removed from group Removed from linked spaces

Content (posts and replies) remains in the space - only access is revoked.

Typical Setup for a Course Community

  • One Private space per course, gated to that course's enrollment
  • One Public space for general Q&A open to all students
  • One Hidden space per group/cohort, gated to a LearnDash Group

Troubleshooting

LearnDash Course does not appear in the rule type dropdown - Confirm Jetonomy Pro and LearnDash are both active. Check Jetonomy → Settings → Integrations to see the LearnDash status.

Students still have access after un-enrolling - Confirm the un-enrollment uses LearnDash's standard course access management. Custom enrollment plugins that bypass the learndash_update_course_access hook will not trigger removal.

Sync Members shows 0 synced - The students may already be space members, or no users are enrolled in the selected course.

What's Next?

Learn how to gate spaces using Restrict Content Pro subscriptions.

Restrict Content Pro Integration →

Gate Jetonomy spaces by Restrict Content Pro subscription level - with automatic access on activation and automatic removal on expiry or cancellation.

The Jetonomy admin settings screen

PRO - This feature requires Jetonomy Pro.

What You Will Learn

  • How Jetonomy Pro detects Restrict Content Pro (RCP)
  • How to create an Access Rule tied to an RCP subscription level
  • What membership events trigger auto-join and auto-leave
  • How to handle free and paid RCP levels differently

How Detection Works

Jetonomy Pro detects Restrict Content Pro automatically when both plugins are active. The RCP adapter registers with the Adapter Registry and adds Restrict Content Pro Level as a Rule Type in the Access Rules tab for every space.

Note: Jetonomy Pro supports Restrict Content Pro version 3.x and above. If you are on an older version, update RCP first.

Setting Up an Access Rule

  1. Go to Jetonomy → Spaces and open the space you want to gate.
  2. Click the Access Rules tab.
  3. Set Rule Type to Restrict Content Pro Level.
  4. Pick the subscription level in the Value field.
  5. Set Grants to Participate and Space Role to Member for a standard gated space.
  6. Click Add Rule.

Members with an active subscription to the selected level gain access immediately. You can add multiple rules to grant access across more than one RCP level. For what the Grants and Space Role fields mean, see Grants and Space Role.

Tip: RCP supports free membership levels. You can use a free level as a gate to require a (free) registration before members can post - while still keeping the community open to anyone willing to sign up.

Auto-Join on Activation

When a member's RCP subscription status becomes active, Jetonomy Pro adds them to any spaces that grant that subscription level. The standard Jetonomy hook fires:

add_action( 'jetonomy_membership_activated', function( int $user_id, string $level_id, string $adapter ) {
    // $adapter is 'rcp' for Restrict Content Pro events.
}, 10, 3 );

Auto-Leave on Expiry or Cancellation

When an RCP subscription expires, is cancelled, or is set to pending, Jetonomy Pro removes the member from any spaces gated exclusively to that level. The hook jetonomy_membership_deactivated fires with $adapter = 'rcp'.

RCP Status Access
Active Granted
Pending Revoked
Expired Revoked
Cancelled Revoked
Disabled Revoked

Combining with Other Adapters

RCP rules stack with all other Access Rule types in Jetonomy. A member gains access to a space if they satisfy any single rule - whether it comes from RCP, MemberPress, WooCommerce, or trust level.

Troubleshooting

RCP Level not appearing in Rule Type dropdown - Confirm Jetonomy Pro is active and Restrict Content Pro is active. Check that at least one subscription level exists in Restrict Content → Subscription Levels.

Member not removed after subscription expires - RCP can be configured to change status on expiry, grace periods, or manual review. Jetonomy listens to RCP 3.x membership API actions: rcp_membership_post_activate, rcp_membership_post_cancel, and rcp_transition_membership_status (which removes access on expired, cancelled, and pending). If a custom RCP workflow bypasses these actions, auto-removal will not fire.

Access still active after cancellation - Check whether the user holds a second active RCP subscription that also grants access to the space via a separate rule.

What's Next?

Learn how Jetonomy integrates with BuddyNext for a unified community hub experience.

BuddyNext Integration →

When BuddyNext is active alongside Jetonomy, the two plugins integrate automatically - sharing design tokens and letting BuddyNext own the page header and navigation, without any configuration.

The Jetonomy admin settings screen

What You Will Learn

  • What the BuddyNext integration enables
  • How shared design tokens work
  • How Jetonomy suppresses its own header and nav when BuddyNext is active
  • What you need to do (spoiler: nothing)

Auto-Detection

Jetonomy detects BuddyNext automatically - there are no settings to configure and no toggles to enable. When BuddyNext is active, Jetonomy adopts its colors and typography and lets BuddyNext own the page header and navigation.

Note: The integration activates only when BuddyNext 1.0 or higher is active and the BuddyNext community hub feature is enabled.

Shared Design Tokens

BuddyNext's TokenService injects CSS custom properties (--brand, --bg, --text-1, --green, --amber, --red, --r-md, --font-body, --font-display) into the page. Jetonomy's CSS inherits these automatically through its --jt-* token cascade:

--jt-accent: var(--brand, var(--wp--preset--color--primary, #3B82F6));
--jt-bg:     var(--bg,    var(--wp--preset--color--base,    #ffffff));
--jt-font:   var(--font-body, var(--wp--preset--font-family--body, inherit));

This means Jetonomy matches the BuddyNext visual style without you writing a single line of CSS. Accent color, typography, border radius, and dark mode all flow through automatically.

Header and Navigation Suppression

When BuddyNext is active, Jetonomy detects it via the buddynext_loaded action and suppresses its own community header and top navigation. BuddyNext owns the page chrome, so Jetonomy renders its content inside BuddyNext's layout without duplicating the header bar or navigation.

This keeps the page from showing two competing headers. When BuddyNext is not active, Jetonomy renders its own header and navigation as normal.

Dark Mode

BuddyNext's dark mode toggle sets data-theme="dark" on the document root. Jetonomy's dark mode overrides live in .jt-dark .jt-app and respond to this same attribute - so toggling dark mode in BuddyNext also applies to Jetonomy community pages instantly.

Developer Notes

Detection is driven by the buddynext_loaded action. Jetonomy's templates check did_action( 'buddynext_loaded' ) and skip rendering their own header and navigation when BuddyNext is present (see templates/partials/header.php and templates/partials/sidebar.php). There is no separate bridge class to configure - the suppression is built into the templates and runs automatically.

Troubleshooting

Jetonomy still showing its own header alongside BuddyNext - The buddynext_loaded action must fire before Jetonomy's templates render. Confirm BuddyNext is active and loading on the page, and that no caching layer is serving a pre-BuddyNext version of the page.

Design tokens not matching - BuddyNext's TokenService may not be firing on community pages. Check the BuddyNext community page template and ensure buddynext_loaded action fires before the wp_head hook.

What's Next?

Learn how Jetonomy adapts to any WordPress theme via CSS custom properties and template overrides.

Theme Compatibility →

Jetonomy works with any WordPress theme. Its CSS inherits from your theme's design tokens automatically, so the community looks native - not bolted on.

Community home page adapting to the active WordPress theme

What You Will Learn

  • How Jetonomy adapts its visual style to your active theme
  • What zero-config means with BuddyX
  • How to override community templates from your theme
  • How to control design tokens for fine-grained customization

How Theme Adaptation Works

Jetonomy reads WordPress theme.json values through CSS custom properties. Every --jt-* token in Jetonomy's CSS resolves first to a WordPress preset token (--wp--preset--color--primary, --wp--preset--font-family--body, etc.), with a hardcoded fallback last:

--jt-accent: var(--brand, var(--wp--preset--color--primary, #3B82F6));
--jt-text:   var(--text-1, var(--wp--preset--color--contrast, #1a1a1a));
--jt-font:   var(--font-body, var(--wp--preset--font-family--body, inherit));
--jt-radius: var(--r-md, var(--wp--custom--border-radius, 8px));

If your theme defines these standard WP preset tokens, Jetonomy adopts the theme's colors, typography, and spacing without you writing any CSS.

Best With BuddyX

BuddyX is Jetonomy's reference theme. With BuddyX active, Jetonomy requires zero configuration - colors, fonts, border radius, hover states, and dark mode all match the theme perfectly out of the box.

Tip: If you are building a new community site from scratch, start with BuddyX. You can always switch themes later - Jetonomy will adapt.

BuddyX Pro, Reign, and the Theme Bridge (1.3.0+)

Starting in 1.3.0, Jetonomy ships a dedicated bridge for the three Kirki-based themes most of our customers run: BuddyX, BuddyX Pro, and Reign.

What the bridge does

  • Reads the theme's Kirki mods on every render (accent color, dark mode state, container width).
  • Injects --jt-accent directly so the community picks up the exact color the customer chose in the Customizer - not a hardcoded fallback.
  • Toggles .jt-dark on the page <body> via body_class whenever the theme is in dark mode, so the community's dark overrides activate automatically without requiring custom CSS.
  • No configuration screen. If the theme is active, the bridge runs. If you switch to a non-Kirki theme, the bridge silently bows out and the standard theme.json path takes over.

Where it lives

includes/integrations/class-theme-integration.php - guarded by class_exists( 'Kirki' ) and a per-theme check against the theme template slug.

Why this matters

On BuddyX/BuddyX Pro/Reign, flipping the theme's dark-mode toggle in the Customizer now flips the entire community sidebar, nav, post cards, and reply editor in the same render. No custom-CSS bridge required.

If you build a custom Kirki theme and want to hook into the same bridge, the integration is extensible via the jetonomy_theme_light_tokens and jetonomy_theme_dark_tokens filters. Each receives a map of --jt-* token => hex color (light mode and dark mode respectively) - return your own token maps and Jetonomy will inject them. Return an empty array to disable that mode's override.

Using Other Themes

Jetonomy works with any well-built WordPress theme. Compatibility level depends on how fully the theme uses theme.json:

Theme Type Expected Result
Modern block theme (theme.json) Excellent - tokens inherit fully
Classic theme with CSS variables Good - accent and font tokens pick up if variable names match
Classic theme without CSS variables Functional - Jetonomy falls back to its own neutral defaults

For classic themes, you can override the --jt-accent token in your theme's style.css or via Jetonomy → Settings → Appearance → Custom CSS.

Dark Mode

Jetonomy supports dark mode natively. If your theme sets data-theme="dark" or a .dark class on the <html> or <body> element, Jetonomy's dark overrides activate automatically via the .jt-dark .jt-app CSS selector.

BuddyX and BuddyNext set data-theme="dark" - so dark mode is seamless. For other themes, add a small bridge if their dark mode uses a different selector:

/* In your theme's style.css - bridge for custom dark mode selector */
.my-theme-dark .jt-app { --jt-bg: #121212; --jt-text: #f0f0f0; }

Template Overrides

Jetonomy's frontend is powered by PHP templates. Every template can be overridden in your theme without touching plugin files.

Create a jetonomy/ folder inside your theme and copy any template file from wp-content/plugins/jetonomy/templates/ into it. Jetonomy's template loader checks the theme directory first.

Override directory structure:

your-theme/
└── jetonomy/
    ├── views/
    │   ├── community-home.php
    │   ├── space.php
    │   ├── single-post.php
    │   └── user-profile.php
    └── partials/
        ├── header.php
        └── reply-card.php

Note: When you override a template, you own it. Future Jetonomy updates will not touch your override. Check the plugin's template changelog after each update to merge any changes manually.

Customizing Design Tokens Without Template Overrides

For small visual adjustments, use the Custom CSS field in Jetonomy → Settings → Appearance. You can re-define any --jt-* token at the .jt-app scope:

.jt-app {
    --jt-accent: #e11d48;
    --jt-radius: 4px;
}

This approach is update-safe and does not require template overrides.

Available --jt-* Tokens

Category Tokens
Typography --jt-font, --jt-font-heading, --jt-font-mono
Accent --jt-accent, --jt-accent-hover, --jt-accent-light, --jt-accent-muted
Text --jt-text, --jt-text-secondary, --jt-text-tertiary
Background --jt-bg, --jt-bg-subtle, --jt-bg-muted, --jt-bg-hover
Border --jt-border, --jt-border-strong
Semantic --jt-success, --jt-warn, --jt-danger and their -light variants
Radius --jt-radius, --jt-radius-sm, --jt-radius-lg, --jt-radius-full

What's Next?

Configure your community's global settings - URL slug, pagination, and access defaults.

General Settings →

Connect Tutor LMS course enrollment to Jetonomy spaces - students get a dedicated discussion area automatically when they enroll, and lose access when they cancel or are removed.

PRO - This feature requires Jetonomy Pro.

Jetonomy Settings - Integrations tab showing the integration status table and the Auto-Create Spaces for Courses card

Tutor LMS works exactly like the other LMS integrations. The course picker, the Sync Members button, and the Auto-Create card are shown in the LearnDash guide, which is the lead LMS reference for this section.

What You Will Learn

  • How to gate a Jetonomy space by Tutor LMS course enrollment
  • How to auto-create spaces when new courses are published
  • How to sync existing students into a space
  • What happens when a student un-enrolls or cancels

How Detection Works

Jetonomy Pro detects Tutor LMS automatically when both plugins are active. A Tutor Course option appears in the Access Rules rule type dropdown - no setup needed.

Linking a Course to a Space

  1. Go to Jetonomy → Spaces and open (or create) the discussion space for your course.
  2. Open the Access Rules tab.
  3. Select Tutor Course from the rule type dropdown.
  4. Start typing your course name - a searchable dropdown appears showing all published Tutor courses (see the course picker screenshot).
  5. Select the course, set Grants to Participate and Space Role to Member.
  6. Click Add Rule.

The rule appears in the table showing the course name (not an ID), with a Sync Members button and Delete button. For what the Grants and Space Role fields mean, see Grants and Space Role.

Syncing Existing Students

If students are already enrolled in the course before the rule was created, click the Sync Members button next to the rule. This pulls in all currently enrolled students and adds them to the space. A toast notification shows how many were synced.

New enrollments and cancellations are handled automatically after the rule is created - no further action needed.

Auto-Create Spaces for New Courses

Instead of manually creating a space for each course:

  1. Go to Jetonomy → Settings → Integrations.
  2. Under Auto-Create Spaces for Courses, enable the Tutor LMS toggle.
  3. Choose the default space type (Q&A, Forum, or Feed).
  4. Click Save Settings.

Now when you publish a new course in Tutor, a private discussion space is automatically created with:

  • The course title as the space name
  • A membership access rule linking the course to the space
  • The course author assigned as space admin

Enrollment and Un-enrollment Events

Tutor LMS Event Jetonomy Action
Student enrolls in course Added to linked space as Member
Student completes course Access retained
Student enrollment cancelled Removed from linked space
Student enrollment deleted Removed from linked space

Content (posts and replies) created by the student remains in the space - only access is revoked.

Typical Setup

  • One Private space per paid course, gated to enrollment
  • One Public space per free course for open discussion
  • One Public space for general Q&A open to all students

Troubleshooting

Tutor Course does not appear in the rule type dropdown - Confirm Jetonomy Pro and Tutor LMS are both active. Check Jetonomy → Settings → Integrations to see the Tutor LMS status.

Students still have access after cancellation - Confirm the cancellation uses Tutor's standard enrollment management. Set the space to Private to fully restrict access.

Sync Members shows 0 synced - The students may already be space members, or no users are enrolled in the selected course.

What's Next?

LifterLMS Integration →

Connect LifterLMS course and membership enrollment to Jetonomy spaces - students get a dedicated discussion area when they enroll, and lose access when removed.

PRO - This feature requires Jetonomy Pro.

Jetonomy Settings - Integrations tab showing the integration status table and the Auto-Create Spaces for Courses card

LifterLMS works exactly like the other LMS integrations. The course picker, the Sync Members button, and the Auto-Create card are shown in the LearnDash guide, which is the lead LMS reference for this section.

What You Will Learn

  • How to gate a space by LifterLMS course or membership enrollment
  • How to auto-create spaces when new courses are published
  • How to sync existing students into a space

How Detection Works

Jetonomy Pro detects LifterLMS automatically when both plugins are active. A LifterLMS Course option appears in the Access Rules rule type dropdown.

Linking a Course to a Space

  1. Go to Jetonomy → Spaces → open the space → Access Rules tab.
  2. Select LifterLMS Course from the rule type dropdown.
  3. Start typing the course name - a searchable dropdown shows all published courses and memberships (see the course picker screenshot).
  4. Select the course, set Grants to Participate and Space Role to Member.
  5. Click Add Rule.

LifterLMS memberships also appear in the search - select a membership to gate a space by membership level instead of individual course enrollment. For what the Grants and Space Role fields mean, see Grants and Space Role.

Syncing Existing Students

Click the Sync Members button next to any rule to pull in all currently enrolled students. New enrollments and removals sync automatically.

Auto-Create Spaces for New Courses

  1. Go to Jetonomy → Settings → Integrations.
  2. Enable the LifterLMS toggle under Auto-Create Spaces for Courses.
  3. Choose the default space type and save.

When you publish a new LifterLMS course, a private space is created with the course name, an access rule, and the course author as space admin.

Enrollment and Un-enrollment Events

LifterLMS Event Jetonomy Action
Student enrolls in course Added to linked space as Member
Student added to membership Added to linked space as Member
Student completes course Access retained
Student removed from course Removed from linked space
Student removed from membership Removed from linked space
Enrollment permanently deleted Removed from linked space

Content remains in the space - only access is revoked.

Memberships and Courses

LifterLMS memberships can auto-enroll students in multiple courses. When a student joins a membership:

  • They gain access to spaces linked to the membership itself
  • They also gain access to spaces linked to the auto-enrolled courses (via the course enrollment hooks)

Troubleshooting

LifterLMS Course does not appear in dropdown - Confirm Jetonomy Pro and LifterLMS are both active. Check Jetonomy → Settings → Integrations.

Membership students not getting access - Ensure the access rule uses the membership level ID (shows as "Membership Name (LifterLMS Membership)" in the search). Course-level rules only apply to direct course enrollment.

What's Next?

Sensei LMS Integration →

Connect Sensei LMS course enrollment to Jetonomy spaces - students get a dedicated discussion area when enrolled, and lose access when withdrawn.

PRO - This feature requires Jetonomy Pro.

Jetonomy Settings - Integrations tab showing the integration status table and the Auto-Create Spaces for Courses card

Sensei LMS works exactly like the other LMS integrations. The course picker, the Sync Members button, and the Auto-Create card are shown in the LearnDash guide, which is the lead LMS reference for this section.

What You Will Learn

  • How to gate a space by Sensei LMS course enrollment
  • How to auto-create spaces when new courses are published
  • How to sync existing students into a space

How Detection Works

Jetonomy Pro detects Sensei LMS automatically when both plugins are active. A Sensei Course option appears in the Access Rules rule type dropdown.

Linking a Course to a Space

  1. Go to Jetonomy → Spaces → open the space → Access Rules tab.
  2. Select Sensei Course from the rule type dropdown.
  3. Start typing the course name - a searchable dropdown shows all published Sensei courses (see the course picker screenshot).
  4. Select the course, set Grants to Participate and Space Role to Member.
  5. Click Add Rule.

For what the Grants and Space Role fields mean, see Grants and Space Role.

Syncing Existing Students

Click the Sync Members button next to any rule to pull in all currently enrolled learners. New enrollments and withdrawals sync automatically.

Auto-Create Spaces for New Courses

  1. Go to Jetonomy → Settings → Integrations.
  2. Enable the Sensei LMS toggle under Auto-Create Spaces for Courses.
  3. Choose the default space type and save.

When you publish a new Sensei course, a private space is created with the course name, an access rule, and the course author (teacher) as space admin.

Enrollment and Un-enrollment Events

Sensei uses a single enrollment status change event that handles both enrollment and withdrawal:

Sensei LMS Event Jetonomy Action
Learner enrolled in course Added to linked space as Member
Learner completes course Access retained
Learner withdrawn from course Removed from linked space
Learner manually enrolled by admin Added to linked space as Member
Learner manually withdrawn by admin Removed from linked space

Content remains in the space - only access is revoked.

WooCommerce Integration

Sensei LMS integrates with WooCommerce for paid courses. When a student purchases a course through WooCommerce and Sensei enrolls them, the Jetonomy space access rule triggers automatically - no additional WooCommerce adapter needed for course gating.

Troubleshooting

Sensei Course does not appear in dropdown - Confirm Jetonomy Pro and Sensei LMS are both active. Check Jetonomy → Settings → Integrations.

Students not losing access after withdrawal - Ensure the withdrawal uses Sensei's standard enrollment management. Set the space to Private to fully restrict access.

What's Next?

MasterStudy LMS Integration →

Connect MasterStudy LMS course enrollment to Jetonomy spaces - students get a dedicated discussion area when they enroll in a course.

PRO - This feature requires Jetonomy Pro.

Jetonomy Settings - Integrations tab showing the integration status table and the Auto-Create Spaces for Courses card

MasterStudy LMS works like the other LMS integrations for adding members. The course picker, the Sync Members button, and the Auto-Create card are shown in the LearnDash guide, which is the lead LMS reference for this section. (One difference: MasterStudy does not fire a removal hook - see Important Note on Removal below.)

What You Will Learn

  • How to gate a space by MasterStudy LMS course enrollment
  • How to auto-create spaces when new courses are published
  • How to sync existing students into a space

How Detection Works

Jetonomy Pro detects MasterStudy LMS automatically when both plugins are active. A MasterStudy Course option appears in the Access Rules rule type dropdown.

Linking a Course to a Space

  1. Go to Jetonomy → Spaces → open the space → Access Rules tab.
  2. Select MasterStudy Course from the rule type dropdown.
  3. Start typing the course name - a searchable dropdown shows all published MasterStudy courses (see the course picker screenshot).
  4. Select the course, set Grants to Participate and Space Role to Member.
  5. Click Add Rule.

For what the Grants and Space Role fields mean, see Grants and Space Role.

Syncing Existing Students

Click the Sync Members button next to any rule to pull in all currently enrolled students. New enrollments sync automatically.

Auto-Create Spaces for New Courses

  1. Go to Jetonomy → Settings → Integrations.
  2. Enable the MasterStudy LMS toggle under Auto-Create Spaces for Courses.
  3. Choose the default space type and save.

When you publish a new MasterStudy course, a private space is created with the course name, an access rule, and the course author as space admin.

Enrollment Events

MasterStudy LMS Event Jetonomy Action
Student enrolls in course Added to linked space as Member
Student completes course Access retained

Important Note on Removal

MasterStudy LMS does not fire a hook when students are removed from courses. This means automatic removal from linked spaces is not available. To manage access:

  • Use the Sync Members button periodically to re-sync - students no longer enrolled will not be re-added
  • Remove students manually from the space Members tab
  • For subscription-based access, consider pairing MasterStudy with WooCommerce Memberships which does fire removal hooks

Troubleshooting

MasterStudy Course does not appear in dropdown - Confirm Jetonomy Pro and MasterStudy LMS are both active. Check Jetonomy → Settings → Integrations.

Students remain in space after course access revoked - MasterStudy does not fire removal hooks. Remove students manually from the space Members tab or use the Sync Members button to verify current enrollment.

What's Next?

BuddyNext Integration →

When FluentCommunity is active alongside Jetonomy, the two plugins coexist as one product. Members navigate between the social feed and the forum without noticing two separate systems, and admins pair spaces in one click.

What You Will Learn

  • How the integration auto-detects FluentCommunity
  • How to pair FluentCommunity spaces with Jetonomy spaces
  • How member sync, activity broadcast, and the comment-to-reply bridge work
  • How the cross-profile links and unified avatars behave
  • What stays separate (private content, moderation, notifications)

Auto-Detection

Jetonomy detects FluentCommunity automatically - there is nothing to install or configure to turn the integration on. As soon as both plugins are active, the connecting surfaces (the Discussions tab, the cross-profile links, member sync, and activity broadcast) become available.

Jetonomy never writes directly to FluentCommunity's database; it only adds members and feed posts through FluentCommunity's own functions. You can deactivate FluentCommunity at any time and both plugins keep working independently, with no leftover data.

Developer note: detection runs on every page load via class_exists( 'FluentCommunity\App\App' ). All writes go through FluentCommunity's public helpers (addToSpace) and the Feed model - never raw SQL.

Pairing Spaces

Open Jetonomy Settings > FluentCommunity. You will see:

  • A status line confirming FluentCommunity is detected
  • A tab-label field (default "Discussions")
  • A pairings table where each row maps one FluentCommunity space to one Jetonomy space

Click Add pair, pick the FluentCommunity space on the left and the Jetonomy space on the right, and save. The pairing is stored in a single WordPress option (jetonomy_fc_space_pairs). Unpair a row by setting the Jetonomy column to "Not paired".

Once a pair is saved, you get five connected surfaces automatically:

  1. A Discussions tab appears on the FluentCommunity space header, linking to the paired Jetonomy space.
  2. An Also on {your community} card appears in the Jetonomy space sidebar, linking back to the FluentCommunity feed.
  3. The FluentCommunity profile gets a Discussions block showing the member's five most recent topics started plus the five topics they follow on Jetonomy.
  4. The Jetonomy profile gets a View on {your community} cross-link to the member's FluentCommunity profile.
  5. Member avatars unify across both sides: the FluentCommunity avatar is used everywhere on the site, including Jetonomy pages.

The tab, card, and button labels pick up the Site Title configured in FluentCommunity so the wording matches your community brand. The Discussions label is configurable from the settings page.

Member Sync

When a member joins a paired FluentCommunity space, they are automatically added to the paired Jetonomy space. The reverse also holds: joining the Jetonomy space enrols the member in the FluentCommunity space.

Sync is add-only by design:

  • Joins propagate in both directions.
  • Leaves do not propagate. Removing yourself from one side never yanks you out of the other.
  • Role changes do not propagate. Each plugin manages its own role structure.

Member sync is enabled by default and can be toggled off from the settings page. There is also a Sync existing members now button that performs a one-click backfill: every member already in one side of a pair is enrolled into the other side. Backfill is safe to re-run and capped at 5,000 members per space per run.

Activity Broadcast

When a new topic is created in a paired Jetonomy space, an announcement feed post appears in the paired FluentCommunity space with the topic title, excerpt, and a discreet "Shared from the forum" attribution link.

Properties:

  • One-way only. Broadcast runs from Jetonomy to FluentCommunity. FluentCommunity feed posts never silently create forum topics.
  • Private topics are never broadcast. If a topic is marked private in Jetonomy, nothing is posted to FluentCommunity. The FC feed audience can be broader than the private-topic scope, so private content stays where it was authored.
  • Paragraph breaks preserved. The excerpt keeps its formatting through the HTML-to-plain conversion.
  • No duplicated titles. The feed post uses the topic title as its heading once, with the excerpt as body and a footer link back to the Jetonomy topic.

Broadcast is enabled by default and can be toggled off from the settings page.

Comment-to-Reply Bridge

When a member comments on one of the broadcast feed posts in FluentCommunity, the comment is mirrored back as a reply on the original Jetonomy topic, preserving author attribution.

Only comments on broadcast feed posts round-trip. Native FluentCommunity feed posts (ones Jetonomy did not broadcast) are left alone. Edits and deletes on FluentCommunity do not propagate: the forum thread remains the durable record of record.

Cross-Profile Navigation

Navigation between the two profile systems works in both directions:

  • FluentCommunity profile: the Discussions block ends with a View all on forum link pointing to the Jetonomy profile.
  • Jetonomy profile: a View on {your community} button points to the FluentCommunity profile.

The FluentCommunity site title is read from the fluent_community_settings option's site_title key, so the button text always matches what your FC admin has branded the community with. If you have not set one, the button falls back to your WordPress site name, then to "Community".

Identity Keying

Everything joins on user_id, never on username. This matters when a user has different usernames on the two sides (for example WP user admin with FluentCommunity xprofile username admin2). user_id is the primary key in both wp_fcom_xprofile and wp_jt_user_profiles, so the integration stays correct no matter how usernames diverge.

Stability Guarantees

  • No core changes to FluentCommunity or Jetonomy. Everything lives in one integration file in the Jetonomy plugin.
  • No writes to FluentCommunity tables outside FC's public helpers. Remove the integration and FluentCommunity is untouched.
  • Stale pair handling. If either side's space ID does not resolve (deleted space, renamed slug), the tab and card silently disappear. No admin cleanup needed.
  • Graceful degradation. If a FluentCommunity hook is ever renamed or removed in a future FC release, only the corresponding surface stops rendering. The rest of the integration keeps working.
  • One option row. The pairing map is stored in a single WordPress option. Uninstall deletes one row.

What Is Not Integrated (Yet)

Kept out of the first release on purpose:

  • Leave sync. Destructive semantics: pulling someone off one side when they leave the other is too likely to cause surprise removals. Add-only stays the default.
  • Privacy mirroring. Paired spaces do not share visibility settings. Exposing or hiding content across two plugins silently is a product decision, not a hook decision.
  • Profile field sync. Bios, display names, and custom fields are not synced two-way.
  • Notification inbox merge. Each plugin keeps its own notification stream.
  • Unified search. FC and Jetonomy have different search surfaces; querying both simultaneously is not wired.
  • Shared moderation queue. Different content models, different flag rules.

Open a request if one of these is the feature you need. We ship what customers actually use.


Building on top of the integration? See the FluentCommunity integration reference in the Developer Guide for options, hooks, and extension points.

When BuddyPress is active alongside Jetonomy, groups and forum spaces feel like one membership. Members who join a group are enrolled in the paired forum space, new topics are announced on the group activity stream, and comments on those activities flow back to the topic as replies.

What You Will Learn

  • How the integration auto-detects BuddyPress
  • How to pair a group with a forum space (create a new one or link an existing one)
  • How member sync and role sync work across groups and spaces
  • How topics broadcast to the group activity stream and how comments round-trip back as replies
  • What surfaces appear on group pages and member profiles

Auto-Detection

Jetonomy detects BuddyPress automatically when the Groups component is active - there is nothing to install or configure to turn the integration on. The pairing options, member sync, the Forum tab, and the profile nav all become available as soon as both plugins are active.

If you have BuddyPress Groups enabled but the Activity component turned off, everything still works - Jetonomy simply skips the activity-stream broadcast and the comment bridge, which need Activity.

Developer note: detection runs on every page load via bp_is_active( 'groups' ); the broadcast and comment-bridge pieces additionally check bp_is_active( 'activity' ) at runtime.

Pairing Groups and Spaces

Group-to-space pairs are set directly inside BuddyPress's group creation wizard and the group Manage > Details screen. The Jetonomy integration adds a Discussion Forum section with three choices:

  • No forum. The group has no paired forum space. Default for new groups.
  • Create new discussion forum. Creates a matching Jetonomy space with the group's name, description, and visibility (public → public, private → private, hidden → hidden). The group creator becomes the space admin.
  • Link existing forum. Pick from a dropdown of unlinked spaces the current user already owns or moderates. Site admins see every unlinked space.

The pairing is stored as jetonomy_space_id in BuddyPress's group meta (one value per group). Unpairing a group is as simple as setting the dropdown back to "No forum".

Member Sync

Once a group is paired, membership changes propagate both ways:

  • Join a BP group → added to the paired Jetonomy space as a member.
  • Join the paired Jetonomy space → added to the BP group as a member.
  • Leave or be removed from the BP group → removed from the paired space.
  • Banned from the group → removed from the space.
  • Unbanned → re-added to the space.
  • Promoted to group admin → space admin.
  • Promoted to group moderator → space moderator.
  • Demoted → back to space member.

Unlike the FluentCommunity integration, BuddyPress member sync is bidirectional for both adds and leaves. Groups and forum spaces are treated as a single membership, which is the model most BuddyPress sites expect.

Want add-only sync? If you would rather a member who leaves a group keep their forum-space access (the way the FluentCommunity integration behaves), a developer can disable leave-sync with a few lines of code. See Disable member-leave propagation in the BuddyPress integration reference.

Forum Tab on BP Group Pages

Paired groups gain a Forum tab in their group nav. Clicking it renders a list of the most recent topics in the paired space with reply counts, author, and time-ago, plus a + New Topic button for signed-in members.

The listing is visibility-aware: private topics only appear to the author or a moderator, so activity-stream widgets and group-page readers never see content they shouldn't.

Forum Nav on BP Member Profiles

Every member profile gets a Forum primary nav item with three sub-tabs:

  • Posts: the member's most recent topics with reply counts and links.
  • Replies: the member's most recent replies with links to the original topics.
  • Bookmarks: topics the member has bookmarked. Own profile only; others don't see your bookmarks.

A stats block above each sub-tab shows the member's posts, replies, votes, reputation, and trust level at a glance. A View Full Forum Profile link takes them to the Jetonomy profile for deeper history.

Back-to-Group Banner on Jetonomy Pages

When a member clicks through from a BP group to a paired Jetonomy space (or a topic in it), a subtle back-link banner at the top of the Jetonomy page lets them return to the group with one click. Keeps the navigation continuous.

On paired Jetonomy spaces, the sidebar About card shows a small tag linking to the paired BP group. Useful for members who enter the space from the forum side and want to jump back to the group's activity feed or members list.

Activity Broadcast (New)

When a new topic is created in a paired Jetonomy space, an activity item is posted to the paired BP group's activity stream with:

  • An action line: "Someone started a new forum topic in Group Name" (rendered by BuddyPress with the standard member + group links).
  • The topic excerpt as paragraphs.
  • A discreet "Shared from the forum · View discussion" attribution line at the bottom.

Properties:

  • One-way only. Broadcast runs from Jetonomy to BuddyPress. BP activity posts never silently create forum topics.
  • Private topics are never broadcast. If a topic is marked private on the Jetonomy side, no activity item is created. The group audience can be broader than the private-topic scope on the forum side.
  • Private/hidden groups stay private. The activity is posted with hide_sitewide set, so site-wide activity feeds do not leak the item outside the group.
  • Paragraph breaks preserved. The excerpt keeps its structure because the integration whitelists <br> and <p> on bp_activity_allowed_tags for broadcast content (tags are harmless on their own, with no attributes allowed through).

Broadcast is enabled by default. To turn it off, go to Jetonomy → Settings → Integrations and clear the Broadcast topics to group activity checkbox. (This tab appears only while BuddyPress Groups is active.)

Comment-to-Reply Bridge (New)

When a member comments on one of those broadcast activity items, the comment is mirrored back to the originating Jetonomy topic as a reply, with author attribution preserved.

Only comments on broadcast activities round-trip. Comments on native BP activity posts (status updates, other plugins' activity types) are left alone. The integration identifies broadcast activities by a jetonomy_post_id activity-meta marker it sets at post time.

Add-only by design: edits and deletes on the BuddyPress side do not propagate back. The forum thread stays the durable record. Enabled by default. To turn it off, go to Jetonomy → Settings → Integrations and clear the Round-trip activity comments checkbox - it requires Broadcast topics to group activity to stay on.

Identity Keying

Everything joins on user_id, which is the same primary key for BuddyPress user profiles and Jetonomy user profiles. Usernames and display names can diverge between the two without breaking the integration.

Stability Guarantees

  • No core changes to BuddyPress. Everything lives in Jetonomy's integration class; BP tables are read via its public API.
  • Group meta is the only data footprint on the BP side (one jetonomy_space_id key per paired group). Deactivating Jetonomy leaves BuddyPress untouched.
  • Graceful degradation. If BuddyPress is removed, the BP-specific surfaces disappear (the integration class is gated on bp_is_active('groups')), and the paired Jetonomy spaces continue to work on their own.
  • Activity component optional. The broadcast and comment bridge gate themselves on bp_is_active('activity') at runtime, so sites with BP Groups but not Activity still get member sync and forum tabs.
  • Stale pair handling. If a paired space is deleted on the Jetonomy side, the forum tab on the BP group quietly disappears on next render. No admin cleanup required, no fatal.

What Is Not Integrated (Yet)

  • Cross-plugin notification merge. BuddyPress notifications and Jetonomy notifications live in separate inboxes. Members see them in two places.
  • Unified search. Each plugin has its own search UX.
  • Shared moderation queue. Group moderation and forum moderation are independent. A user banned from a group is removed from the space but not flagged for forum moderation, and vice versa.
  • Two-way edit/delete sync on comments and replies. The comment bridge creates a reply on round-trip but does not keep the reply and the activity comment in sync after that point.

Building on top of the integration? See the BuddyPress integration reference in the Developer Guide for hooks, options, and extension points.

Admin Settings

Configure every aspect of your Jetonomy community.

The General settings tab is the first place to go after installation. It controls your community URL, pagination defaults, and who can read or participate.

What You Will Learn

  • How to change your community's base URL slug
  • What the default space type setting controls
  • How to set your community's display title
  • How to configure pagination for posts and replies
  • How the Public / Private access control works

General settings

Go to Jetonomy → Settings to access these options. All changes take effect on save.

Community Base URL

Setting: base_slug Default: community Location: General tab → Community URL section

This is the URL prefix for all Jetonomy pages on your site. With the default value, your community home is at yoursite.com/community/. Spaces live at yoursite.com/community/s/space-name/, and so on.

You can change this to any URL-safe string, for example forum, hub, or discuss. Jetonomy automatically flushes rewrite rules when you change the base URL and save settings.

Warning: Changing the base URL after your community has content will break all existing links. If you must change it on a live site, set up 301 redirects from the old slug to the new one.

Community Title

Setting: community_title Default: Community Location: General tab → Community URL section

The display name of your community. It is shown as the main heading at the top of the community home page. Change it to your brand or community name (for example "Acme Support Forum" or "The Builders Hub"). This is a display label only - it does not change the base URL or any links.

Default Space Type

Setting: default_space_type Default: forum Options: Forum, Q&A, Ideas, Feed

When you create a new space in the admin, this setting pre-fills the Type dropdown. It is a convenience setting only - you can always change the type on any individual space. It does not affect existing spaces.

Choose the type that best matches the primary purpose of your community:

  • Forum - open discussion, replies sorted by date
  • Q&A - questions and answers, accepted answers float to top
  • Ideas - feature requests and votes, status workflow
  • Feed - short-form cards, optional title, chronological feed

Posts Per Page

Setting: posts_per_page Default: 20 Location: General tab → Pagination section

Controls how many posts appear per page in space listings and search results. A lower number is faster on large communities; a higher number reduces clicks for users who prefer scrolling. This value also controls how many additional posts load each time a member clicks Load More on a space listing.

Tip: For communities with 10,000+ posts per space, keep this at 20 or lower. Higher values increase page load time and database query time proportionally.

Replies Per Page

Setting: replies_per_page Default: 30 Location: General tab → Pagination section

Controls how many replies load per page inside a single post view. This value also controls how many additional replies load each time a member clicks Load More in a thread. Pagination starts at the oldest replies and works forward. Members can jump to the last page to see the most recent replies.

Guest Access (Public / Private)

Setting: guest_read Default: Public (guest reading on) Location: General tab → Access Control card

This is the single control that decides whether logged-out visitors can read your community. On the Access Control card it appears as two radio buttons - Public community and Private community - not a checkbox.

  • Public community (default) - logged-out visitors can read all public spaces, posts, and member profiles. They see a prompt to log in when they try to vote, reply, or follow a space.
  • Private community - every community page redirects guests to sign-in, and the REST API rejects unauthenticated requests. Choose this for members-only communities you do not want indexed by search engines.

Note: Even in Public mode, anonymous posting is not supported. "Public" means read-only browsing for logged-out visitors. Visitors must always log in to post, reply, or vote.

This Public/Private toggle is the same guest_read setting documented in full - including exactly which pages stay reachable in Private mode and how the REST API behaves - on the Access Control page.

Community as Homepage

Setting: front_page Default: off Location: General tab → Community Setup section

When enabled, visitors to your site root see the community home page instead of the WordPress front page. This takes precedence over the WordPress Settings → Reading → Your homepage displays setting. All community URLs, posts, pages, and feeds keep working unchanged.

Front-end Space Creation

Setting: frontend_space_creation_roles Default: empty (admin-only) Location: General tab → Community Setup section

Controls which WordPress roles may create spaces from the front end at /community/new-space/. Tick any roles you trust to create spaces. Site administrators always qualify regardless of the selection. Leave every box unticked to keep front-end space creation admin-only.

Require Email Verification

Setting: require_email_verification Default: off Location: General tab → Access section

When this is on, new members who register through Jetonomy's Login block receive a confirmation email immediately after sign-up. They cannot log in until they click the verification link in that email. Existing members are not affected - this setting applies only to accounts created after you enable it.

A follow-up reminder is sent automatically if the member has not confirmed within the configured window.

Setting: verification_reminder_hours Default: 24 Location: Stored in jetonomy_settings['verification_reminder_hours']

This controls how many hours after registration the reminder email is sent. The reminder runs on an hourly WP-Cron schedule (hook: jetonomy_verification_reminder). The email template can be customized on the Settings → Email screen under the "Verification reminder" row.

Note: If you use a third-party registration flow (WooCommerce, Restrict Content Pro, LearnDash) instead of Jetonomy's Login block, those plugins handle their own email verification. This setting only applies to registrations that go through the Jetonomy Login block.

Rebuild Counters

Location: Dashboard → Quick Actions, or via WP-CLI / REST API

Jetonomy stores denormalized counters (reply counts per post, post counts per space, member counts per space, vote scores) for performance. These counters are updated in real time on every write, but they can drift from true values after bulk database edits, server failures, or plugin imports.

Use Rebuild Counters to recalculate all denormalized values from the canonical tables.

WP-CLI:

wp --path="/path/to/wordpress" jetonomy recount
wp --path="/path/to/wordpress" jetonomy recount --type=posts   # posts only
wp --path="/path/to/wordpress" jetonomy recount --type=spaces  # spaces only
wp --path="/path/to/wordpress" jetonomy recount --type=votes   # votes only
wp --path="/path/to/wordpress" jetonomy recount --type=users   # user profile counters only

REST API (site admin only):

POST /jetonomy/v1/admin/recount
{ "type": "all" }

Valid type values: all, posts, spaces, votes, users. Omit or pass all to rebuild everything. The response reports how many rows were updated per step. On a large community (100,000+ posts), a full recount may take 10-60 seconds - run it during low-traffic hours.

Tip: After running an import from bbPress, wpForo, or Asgaros, always run a full recount. The importers insert rows directly and skip the counter-update logic.

Admin Bar Shortcut

All logged-in members see a Community menu in the WordPress admin bar. This menu links to the community home, your notification inbox, and your profile.

Members who have the jetonomy_manage_spaces or manage_options capability also see an admin sub-section with direct links to: Manage Spaces, Add New Space, Categories, Moderation Queue, Posts and Replies, and Settings.

The admin bar menu appears on both the public site and inside wp-admin, so you can jump from any page in the dashboard directly into the community and back.

Settings Save Confirmations

After you click Save Changes, a confirmation banner appears at the top of the settings page. The banner stays visible until you dismiss it - it does not disappear automatically. This ensures you always have a clear signal that your changes were saved.

What's Next?

Configure trust level thresholds and rate limits to control who can do what in your community.

Permission Settings →

  • White Label - replace Jetonomy branding with your own.
  • Analytics - community health and engagement dashboard.
  • Webhooks - send community events to external services.

The Permissions tab controls how quickly members earn trust in your community and how much they can do before you have had a chance to evaluate their behavior.

Permissions settings panel with trust level thresholds and rate limits

What You Will Learn

  • What Jetonomy's trust level system is and how it auto-promotes members
  • How to configure the thresholds for each trust level
  • What each trust level unlocks
  • How to adjust rate limits to match your community's size and risk tolerance

Go to Jetonomy → Settings → Permissions to access these settings.

The Trust Level System

Jetonomy uses six trust levels (0 through 5) to gradually extend posting privileges to members as they demonstrate good behavior. Levels 0 through 3 are earned automatically by the background cron job. Levels 4 and 5 are granted manually by moderators or admins.

Level Name Earned By
0 Newcomer Default on registration
1 Member Automatic - light activity
2 Regular Automatic - consistent participation
3 Trusted Automatic - high engagement and reputation
4 Leader Manual - granted by moderator or admin
5 Moderator Manual - granted by admin only

The cron job runs every 12 hours and re-evaluates every member against the configured thresholds. Demotion is also possible - if a member is muted or receives too many spam flags, their trust level can drop.

Trust Level Thresholds

Setting: trust_thresholds Location: Permissions tab → Trust Levels section

Each auto-promotion level (1, 2, and 3) has a configurable set of thresholds. A member must meet all thresholds for a level to be promoted to it.

Threshold Description Configurable
posts Minimum posts created Yes
days_active Minimum days since registration Yes
reputation Minimum reputation score Yes
replies_received Minimum replies received on own posts Yes

Default thresholds (Level 1):

Threshold Default Value
posts 5
days_active 3
reputation 0
replies_received 10

For small communities (under 200 members), lower the thresholds. Members can feel stuck if Level 1 requirements take weeks to meet. For larger communities, raise the thresholds to protect against spam waves.

Tip: Start with low thresholds and tighten them if you see abuse. It is easier to tighten later than to manually promote members who are stuck at Level 0.

What Each Trust Level Unlocks

Ability Level Required
Read public spaces 0 (any visitor)
Create posts 0
Reply to posts 0
Add images to posts 1
Include external links 1
Use @mentions 1
Follow spaces 0
Vote on posts and replies 0
Flag content for moderation 1
Edit own posts 0
Delete own posts 1
Access invite links 1
Create invite links 2
Skip anti-spam checks 2
Moderate content (space moderator) Assigned by admin

Note: The anti-spam exemption at Level 2 is important. Members who have earned Level 2 are trusted enough to skip reCAPTCHA and Turnstile checks entirely. This keeps the experience smooth for your most active members.

Rate Limits

Setting: rate_limits Location: Permissions tab → Rate Limits section

Rate limits cap how many actions a member can take in a given time window. They protect your community from spam bursts and accidental double-submissions.

Action Default Limit Window
Create post 3 per day
Create reply 10 per day
Vote 5 per day

Trust Level 1+ members are exempt from all rate limits.

For high-traffic communities, raise these limits. For communities experiencing spam problems, lower them. Changes take effect immediately - no cache flush needed.

Adjusting for Community Size

Small community (under 500 members):

  • Lower all trust thresholds significantly - active members should reach Level 2 within a week
  • Keep rate limits at defaults - spam volume is low
  • Consider setting days_active to 0 for Level 1 to avoid frustrating early adopters

Large community (10,000+ members):

  • Keep thresholds at defaults or raise them - organic promotion still happens, just slower
  • Raise the reputation and posts thresholds to make higher levels harder to reach
  • Lower post rate limits if you see spam bursts

Reputation Points

Setting: jetonomy_settings['reputation_points'] Location: Permissions tab → Reputation Points section

Every community action awards or deducts a fixed number of reputation points. You can override any default value on this screen. Positive numbers reward the action; negative numbers penalize it.

Action key Label Default
post_upvoted Post upvoted +10
reply_upvoted Reply upvoted +5
post_downvoted Post downvoted -2
reply_downvoted Reply downvoted -2
reply_accepted Reply accepted as answer +15
idea_planned Idea moved to Planned/Shipped +20
flag_validated Flag confirmed (reporter) +5
post_reported Post reported -10
post_removed Post removed by moderator -20

The Default column shows each value before any override is saved. You can restore a row to its default by deleting your override and saving again.

Lookup order at runtime: saved admin override in jetonomy_settings['reputation_points'] → hardcoded defaults above → 0. This means a site with no overrides still scores correctly out of the box.

Developer hook: jetonomy_reputation_points_for

add_filter( 'jetonomy_reputation_points_for', function( int $points, string $action ): int {
    // Double the reward for replies accepted as answers.
    if ( 'reply_accepted' === $action ) {
        return $points * 2;
    }
    return $points;
}, 10, 2 );

The filter runs after the admin override and hardcoded fallback resolve, so $points already reflects any per-site override. Return an int.

What's Next?

Configure which notification types are enabled by default and set your community email identity.

Email Settings →

The Email settings tab controls which notification emails Jetonomy sends, what name and address they come from, and how to test your email configuration.

Email settings with From name, From address, and notification type toggles

What You Will Learn

  • Which notification types can be toggled on or off
  • How to set your community's From name and From address
  • How to send a test email to confirm delivery
  • How to connect an SMTP plugin for reliable email delivery

Go to Jetonomy → Settings → Email to access these settings.

How Jetonomy Sends Email

Jetonomy uses WordPress's built-in wp_mail() function for all outgoing notifications. This means it is immediately compatible with any SMTP plugin you already use - WP Mail SMTP, FluentSMTP, Postman, or any other. No extra configuration in Jetonomy is needed; just configure your SMTP plugin and Jetonomy benefits automatically.

Tip: On production sites, always use an SMTP plugin with a transactional email service (Mailgun, Postmark, SendGrid, SES). The default PHP mail() delivery is unreliable and frequently lands in spam.

From Name

Setting: email_from_name Default: Your WordPress site name Location: Email tab → Sender section

This is the display name that appears in the From field of every Jetonomy notification email. Use your community or product name - something members will recognize immediately in their inbox.

From Address

Setting: email_from_email Default: WordPress admin email Location: Email tab → Sender section

This is the email address that appears in the From field. Use a dedicated address such as community@yoursite.com or noreply@yoursite.com.

Warning: The From address must be a verified sender with your email service provider. Using an unverified address causes high bounce rates and spam scoring. If you use Gmail SMTP, the From address must match your Google account.

Branding the Email

Two optional fields let you brand every notification email with your own logo and footer line. Both live on the Email tab and are empty by default - leave them blank to send plain, text-only emails.

Setting: email_logo_url Default: Empty (your site name is shown as text instead) Location: Email tab → Sender section

Paste the full URL to a logo image (for example https://yoursite.com/logo.png). The image appears at the top of every notification email. A landscape logo around 200x40px in PNG or SVG works best. If you leave this empty, Jetonomy shows your community name as plain text at the top instead.

Tip: Use an absolute https:// URL hosted on your own site or media library. Relative paths and http:// URLs are blocked by many email clients.

Setting: email_footer_text Default: Empty (placeholder text: "You received this because you are a member of the community.") Location: Email tab → Footer Text section

A short line shown at the very bottom of every branded notification email - typically a reminder of why the member is receiving it. If you leave it blank, the placeholder line above is used.

Notification Toggles

Setting: notification_defaults Location: Email tab → Notification Types section

Each notification type has an independent toggle for both web (in-app bell) and email delivery. The defaults shown here are the site-wide defaults. Individual members can override their own preferences from their notification settings page.

Notification Type Web Default Email Default
Reply to your post On On
Reply to a reply you made On Off
@mention On On
Accepted answer (Q&A) On On
Your idea roadmap status changed On On
New post in followed space On Off
Badge earned On Off
Vote on your post On Off
Moderator action on your content On On
Space join request On On

The values you set here are the starting defaults for new members. Individual members can still override any type from their own notification settings. Use these defaults to keep noisy notification types quiet out of the box without locking members out of re-enabling them.

Note: Vote and badge notifications default to web-only because they can occur frequently. Email for every vote would quickly train members to ignore your community emails entirely.

Test Email

Location: Email tab → bottom of page → Send Test Email button

Click Send Test Email to send a test message to the WordPress admin email address. The test email confirms that wp_mail() is working and that your From name and address are applying correctly.

If the test email does not arrive within a few minutes, check:

  1. Your SMTP plugin's log for send errors
  2. Your spam folder
  3. That the From address is verified with your email provider

Email and Jetonomy Pro

Jetonomy Pro adds two additional email capabilities:

  • Email Digest - daily and weekly summary emails that bundle multiple notifications into one. Members set their preference per notification type.
  • ESP Adapters - native integrations for SendGrid, Mailgun, Amazon SES, and Postmark that bypass wp_mail() for higher throughput and detailed delivery analytics.

Both are managed via Jetonomy → Extensions after installing Jetonomy Pro.

What's Next?

Control the visual appearance of your community - accent color, font inheritance, layout density, and custom CSS.

Appearance Settings →

The Appearance settings tab gives you direct control over the visual style of your community - from a single accent color override to a full custom CSS field.

Appearance settings with accent color picker, font options, and layout density controls

What You Will Learn

  • How to set a custom accent color
  • What the font and color inheritance toggles do
  • How layout density affects the community UI
  • How to use the custom CSS field safely

Go to Jetonomy → Settings → Appearance to access these settings.

How Jetonomy's Visual System Works

Jetonomy uses CSS custom properties (--jt-* tokens) throughout its stylesheet. Every color, font, radius, and spacing value references a token. By default, those tokens inherit from your active theme's theme.json values automatically.

The Appearance tab gives you a set of override controls on top of that inheritance layer. You can use them without writing any CSS.

Accent Color

Setting: accent_color Default: #0073aa shown in the picker; the live community inherits your theme's primary color while Inherit Colors from Theme is on Location: Appearance tab → Colors section

The accent color drives buttons, links, vote arrows, trust-level highlights, and other interactive elements.

When you first open the picker it shows a blue value (#0073aa). Do not be alarmed - while Inherit Colors from Theme (below) is on, that stored value is ignored and the live community pulls its accent from your theme's primary color (--wp--preset--color--primary). The picker value only takes effect once you turn Inherit Colors off, at which point it is injected as --jt-accent on the .jt-app element and overrides the theme.

To set a custom accent: turn Inherit Colors from Theme off, then pick your color here.

Tip: Use a color that has at least a 4.5:1 contrast ratio against white (WCAG AA). The community UI places accent colors on white backgrounds frequently.

Inherit Fonts from Theme

Setting: inherit_fonts Default: On Location: Appearance tab → Typography section

When on, Jetonomy uses --jt-font: inherit - the community adopts whatever font your theme sets on the body element. This is the correct setting for most sites.

Turn this off only if you want Jetonomy to use a specific font independent of your theme. In that case, define --jt-font in the Custom CSS field.

Inherit Colors from Theme

Setting: inherit_colors Default: On Location: Appearance tab → Colors section

When on, the --jt-accent token pulls from --wp--preset--color--primary in your theme.json. This means the accent color stays in sync with theme updates automatically.

Turn this off if you have set a custom accent color above and do not want theme updates to override it.

Color Palette

Location: Appearance tab → Color Palette section

Beyond the accent color, you can set the community's core surface colors directly. This is useful when your theme has no color tokens for Jetonomy to inherit. These overrides apply when Inherit Colors from Theme is off. Leave any field empty to keep the default - secondary shades (hover, muted text) derive automatically.

Each field accepts a hex color value:

  • Text (text_color) - Body copy and headings. Secondary and muted text derive from it.
  • Background (bg_color) - Cards and content surfaces.
  • Subtle Background (bg_subtle_color) - Secondary surfaces such as table headers, code, and quiet panels.
  • Border (border_color) - Card outlines, dividers, and input borders.

Layout

Jetonomy 1.4.0 added a Layout panel with three controls that decide how the community canvas sits inside your active theme. Every option defaults to Theme Default, so existing installs see no visual change after the upgrade. When you do change a value, Jetonomy emits a small block of CSS scoped to body.jt-page - the rules only apply on community routes and never leak into the rest of your site.

Container Width

Setting: container_width Default: Theme Default Options: Theme Default, Full Width, Custom (px) Location: Appearance tab → Layout section

Controls how wide the community canvas can grow before it stops expanding.

  • Theme Default - Inherits the host theme's content container width. Use this when your theme's reading width already feels right.
  • Full Width - Lets the community stretch edge-to-edge of the viewport. Best for kanban-style spaces, leaderboards, and dense feeds that benefit from horizontal room.
  • Custom (px) - Pins the canvas to a specific pixel width (e.g. 1280). Useful when you want a wider reading column than the theme provides without going fully edge-to-edge.

Theme Sidebar

Setting: sidebar_visibility Default: Theme Default Options: Theme Default, Hide on community pages Location: Appearance tab → Layout section

Decides whether the host theme's sidebar shows on community routes.

  • Theme Default - Leaves the theme's sidebar exactly where the theme renders it.
  • Hide on community pages - Suppresses the host theme's sidebar across /community/* so the forum renders at full width even when the rest of the site has a sidebar everywhere. Pair this with Full Width above when you want a true full-bleed community experience.

Page Padding

Setting: padding_preset Default: Theme Default Options: Theme Default, None, Comfortable Location: Appearance tab → Layout section

Adjusts the inline padding around the community canvas.

  • Theme Default - Uses whatever inline padding the theme provides.
  • None - Removes the inline padding so the community sits flush against the viewport edges. Good for themes that already hug the edges.
  • Comfortable - Adds a generous inline padding. Useful for themes that hug the edges too tightly and leave content butting against the screen on mobile.

Tip: If your theme has a sidebar everywhere but you want the community to feel like a standalone app, set Container Width to Full Width, Theme Sidebar to Hide on community pages, and Page Padding to Comfortable. The rest of your site keeps the original theme layout.

Layout Density

Setting: layout_density Default: comfortable Options: Compact, Comfortable, Spacious Location: Appearance tab → Layout section

Compact - Reduced padding and tighter spacing. Fits more content on screen at once. Best for high-volume spaces where members scan many posts quickly.

Comfortable - Standard spacing between post cards, reply cards, and interface elements. Best for general communities and long-form discussion.

Spacious - Extra-roomy spacing between cards and interface elements. Best for low-volume, reading-focused communities that favor breathing room over density.

When you change this setting, Jetonomy adds data-jt-density="compact" (or "comfortable") to the .jt-app wrapper element. CSS rules keyed to this attribute apply the appropriate spacing.

Custom CSS

Setting: custom_css Default: Empty Location: Appearance tab → Custom CSS section

The Custom CSS field accepts any valid CSS. Jetonomy outputs this CSS as an inline style block at the end of the <head> on all community pages, scoped after the main jetonomy.css stylesheet.

Use this field to override --jt-* tokens, adjust component styles, or add community-specific visual tweaks:

/* Override accent color and border radius */
.jt-app {
    --jt-accent: #7c3aed;
    --jt-radius: 12px;
}

/* Increase heading size in post titles */
.jt-post-title {
    font-size: 1.25rem;
}

Note: Custom CSS is output as-is - no minification, no scoping, no sandboxing. Write only CSS you control. If you enter invalid CSS here, it may break parts of the community UI.

Tip: For larger CSS customizations, consider using a child theme's style.css or a dedicated CSS plugin instead of this field. The Custom CSS field is best for quick, targeted overrides.

What's Next?

Configure how Jetonomy appears in search engines - XML sitemaps, schema markup, and meta title patterns.

SEO Settings →

The SEO settings tab controls how Jetonomy pages appear in search engines - XML sitemaps, structured data, meta title patterns, and robots directives for specific page types.

SEO settings with sitemap toggle, meta title patterns, and robots directives

What You Will Learn

  • How Jetonomy generates SEO-friendly URLs for community pages
  • How to enable or disable the XML sitemap
  • How schema markup works for forum content
  • How to configure meta title patterns
  • How to exclude certain page types from search engine indexing

Go to Jetonomy → Settings → SEO to access these settings.

How Jetonomy Generates URLs

Every Jetonomy page has a clean, human-readable URL structured around your community base slug:

Page Type URL Pattern
Community home /community/
Category /community/category/slug/
Space /community/s/slug/
Post /community/s/space-slug/t/post-slug/
User profile /community/u/username/
Tag /community/tag/slug/
Search /community/search/

Post slugs are auto-generated from the post title, truncated at 60 characters, and deduplicated with a numeric suffix if needed. All URLs use standard WordPress rewrite rules and are compatible with all SEO plugins.

XML Sitemap

Setting: seo_sitemap Default: On Location: SEO tab → Sitemap section

When enabled, Jetonomy registers a custom sitemap provider with WordPress's built-in sitemap API. Community pages appear at /wp-sitemap.xml alongside your regular WordPress content.

The sitemap includes:

  • All public spaces
  • All public posts (paginated if over 2,000)
  • User profile pages

Private, hidden, and archived spaces are excluded. Draft and scheduled posts are excluded.

Tip: Check Settings → Reading → Search engine visibility is not set to "Discourage search engines" or your sitemap will be disregarded.

Location: SEO tab → Sitemap section

Right next to the toggle is a button that surfaces the live sitemap URL for your install (typically https://example.com/wp-sitemap.xml). Copy the URL straight from the admin and submit it to:

You only need to submit the sitemap once per search engine. Google and Bing both recrawl the file automatically after the first submission, so new posts and spaces appear in the index without any further action.

Schema Markup

Setting: seo_schema Default: On Location: SEO tab → Structured Data section

When enabled, Jetonomy outputs JSON-LD structured data on community pages. This helps search engines understand your content and can improve how your pages appear in search results.

Page Type Schema Type
Community home WebSite + BreadcrumbList
Space DiscussionForumPosting (as container)
Single post DiscussionForumPosting
Post with replies DiscussionForumPosting + Comment
User profile Person

The DiscussionForumPosting type is the W3C-recognized schema for forum content. Google uses it to display rich results for Q&A content in particular.

Meta Title Patterns

Settings: seo_post_title, seo_space_title Location: SEO tab → Title Patterns section

These patterns control the <title> tag on Jetonomy pages. Use the available tokens to build the pattern you want.

Available tokens:

Token Output
{post_title} The post title
{space_name} The space name
{site_name} Your WordPress site name

Default post title pattern: {post_title} - {space_name} | {site_name}

Default space title pattern: {space_name} | {site_name}

Tip: Keep titles under 60 characters to avoid truncation in search results. The {site_name} suffix is good for brand recognition but costs characters. For long space names, consider omitting {site_name}.

Noindex Controls

Settings: seo_noindex_profiles, seo_noindex_search Default: On for both profiles and search Location: SEO tab → Robots section

Noindex user profiles - When enabled, Jetonomy adds <meta name="robots" content="noindex"> to all /community/u/*/ pages. Enable this if you prefer profiles not to appear in search results (common for privacy-sensitive communities).

Noindex search results - When enabled, the /community/search/ page is excluded from indexing. This is on by default because search results pages provide minimal SEO value and can create duplicate-content signals.

Open Graph and Twitter Card Tags

Jetonomy outputs Open Graph and Twitter Card meta tags automatically on all public community pages. No setting is needed. These tags control how your posts appear when shared on social media:

  • og:title - the post or space title
  • og:description - the post excerpt (first 160 characters of body text)
  • og:type - article for posts, website for other pages
  • og:url - the canonical URL
  • twitter:card - summary (or summary_large_image if a post has an image attachment)

Note: If you use an SEO plugin like Yoast SEO, RankMath, or The SEO Framework, its OG tags may override Jetonomy's. This is fine - SEO plugin output takes priority via standard WordPress wp_head hook priority ordering.

Twitter / X Handle

Setting: seo_twitter_handle Default: Empty Location: SEO tab → Twitter handle

Enter your community's Twitter or X handle (with or without the leading @). When set, Jetonomy emits twitter:site and twitter:creator meta tags on every community page that does not already declare a per-page override. This gives X / Twitter a verified attribution to display alongside link previews and unlocks richer card layouts.

Leave this empty if the community has no Twitter / X presence - Jetonomy simply omits the tags instead of emitting empty ones.

Default Share Image

Setting: seo_default_og_image Default: Empty Location: SEO tab → Default share image

Paste the absolute URL of an image to use as the fallback og:image whenever a specific post does not have an image of its own. This is a plain URL field, not a media-library picker. Posts that already include their own image continue to use that image - this setting only kicks in when there is nothing else to show. When left empty, Jetonomy falls back to the WordPress site logo / icon.

Recommended specs:

Property Value
Dimensions 1200 x 630 px
Format PNG or JPG
File size Under 5 MB
Aspect ratio 1.91:1

Twitter / X, Facebook, LinkedIn, and Slack all read this image when generating link previews, so picking a branded fallback (logo + community name on a clean background) keeps shared links recognizable.

Social Embeds (Instagram & Facebook)

Settings: fb_app_id, fb_app_secret Location: SEO tab → Social Embeds section

When members paste a link, Jetonomy turns it into a rich embed. YouTube, Vimeo, TikTok, Twitter/X, Spotify, SoundCloud, and TED Talks embed automatically with no setup required.

Instagram and Facebook are the exception: Meta deprecated anonymous oEmbed access in October 2020, so those two providers require a free Meta Developer App.

  • Facebook App ID (fb_app_id) - the numeric App ID from your Meta Developer dashboard.
  • Facebook App Secret (fb_app_secret) - the App Secret. It is stored in wp_options and never exposed to the frontend.

Leave both fields empty if you do not need Instagram or Facebook embeds - every other provider keeps working without them.

What's Next?

Set up anti-spam protection to keep your community clean without frustrating legitimate members.

Anti-Spam Settings →

The Anti-Spam tab lets you add invisible bot protection to post and reply submission - without disrupting the experience for legitimate members.

Anti-spam settings with provider selection, API keys, and score threshold

What You Will Learn

  • Which anti-spam providers Jetonomy supports
  • How to add your API keys and enable protection
  • How the score threshold works for reCAPTCHA v3
  • Which members are automatically exempt from checks

Go to Jetonomy → Settings → Anti-Spam to access these settings.

How It Works

Anti-spam checks run server-side before a post or reply is saved. When a submission fails the check, Jetonomy blocks the save and returns an error to the user. The check is invisible to legitimate members - no checkbox to tick, no image to identify.

Members at Trust Level 2 or above are exempt from all anti-spam checks. Admins are always exempt. This ensures your most active, trusted members never encounter friction.

Choosing a Provider

Setting: captcha_provider Default: None (none) Options: None (none), Google reCAPTCHA v3 (recaptcha_v3), Cloudflare Turnstile (turnstile)

Provider How It Works User Visibility
None No spam protection -
Google reCAPTCHA v3 Score-based, no user interaction Invisible (small badge)
Cloudflare Turnstile Smart challenge, no image puzzle Invisible (small badge)

Google reCAPTCHA v3 assigns a risk score (0.0 to 1.0) to each submission. You set a threshold - submissions below it are blocked.

Cloudflare Turnstile is GDPR-friendlier than reCAPTCHA and does not show a challenge unless it detects suspicious behavior. It is a good default for EU communities.

Tip: If you are seeing bot spam despite having anti-spam enabled, also check your Trust Level 0 rate limits in the Permissions tab. Combining low rate limits with Turnstile stops most automated spam without any user friction.

Google reCAPTCHA v3

  1. Go to google.com/recaptcha/admin and create a new site.
  2. Select reCAPTCHA v3 as the type.
  3. Add your domain to the allowed domains list.
  4. Copy the Site Key and Secret Key.
  5. Paste them into the corresponding fields in Jetonomy → Settings → Anti-Spam.
  6. Set the Score Threshold (see below).
  7. Save settings.

Site Key and Secret Key

Both supported providers (reCAPTCHA v3 and Turnstile) use the same two fields on this tab to store the credentials you copy from the provider's dashboard:

Setting: captcha_site_key Default: Empty Location: Anti-Spam tab → Site Key field

The public key that the protection widget loads in the browser. Safe to expose - it is meant to be visible in page source.

Setting: captcha_secret_key Default: Empty Location: Anti-Spam tab → Secret Key field

The private key Jetonomy uses server-side to verify each submission with the provider. Keep it confidential - it is rendered as a masked password field and is never exposed to the browser.

Score Threshold (reCAPTCHA v3 Only)

Setting: captcha_score_threshold Default: 0.5 Range: 0.1 to 0.9

Google's reCAPTCHA v3 returns a score between 0.0 (likely bot) and 1.0 (likely human). Jetonomy blocks any submission with a score below your threshold.

Threshold Effect
0.3 Block only very confident bots. May let some spam through.
0.5 Balanced default. Blocks most bots, rarely affects humans.
0.7 Strict. May occasionally block mobile users or VPN users.

Start at 0.5. If you see false positives (legitimate members getting blocked), lower to 0.4. If spam is still getting through, raise to 0.6.

Cloudflare Turnstile

  1. Go to dash.cloudflare.comTurnstile and add a new site.
  2. Select Invisible as the widget mode.
  3. Add your domain to the allowed hostnames list.
  4. Copy the Site Key and Secret Key.
  5. Paste them into Jetonomy → Settings → Anti-Spam.
  6. Save settings.

There is no score threshold for Turnstile - Cloudflare handles the risk scoring internally. A submission either passes or fails.

Note: Turnstile requires your domain to be exactly correct in the Cloudflare dashboard. www.yoursite.com and yoursite.com are treated as different hostnames.

Trust Level Exemptions

Members at Trust Level 2 or above are never shown a challenge and their submissions never go through the anti-spam check. The check is skipped entirely on the server side.

This is intentional. Trust Level 2 requires consistent participation over time - members who earn it are clearly not bots.

WordPress admins (manage_options capability) are also always exempt, regardless of trust level.

Testing Your Setup

  1. Log out of WordPress completely.
  2. Go to any space on your community.
  3. Try to create a post or reply.
  4. If protection is working, the submission should complete (legitimate human request) and no error should appear.

To test blocking, lower the reCAPTCHA threshold to 0.9 temporarily and try submitting. If the error message appears, your integration is working correctly. Reset to 0.5 afterward.

What's Next?

Migrate your existing community data from bbPress or wpForo into Jetonomy.

Importing from bbPress →

The Access Control setting decides whether your community is open to the public or hidden behind sign-in. Pick the right mode in one place and Jetonomy enforces it across every page and the REST API.

What You Will Learn

  • The difference between Public and Private community modes
  • Which pages stay reachable in Private mode (sign-in, register, lost password)
  • How REST API access changes between the two modes
  • When to switch and what to expect

Go to Jetonomy → Settings → General and find the Access Control card to choose the mode. It is one card on the General tab, not a separate sub-page - the same guest_read toggle introduced under Guest Access on the General Settings page.

Public Mode (default)

Anyone - including search engines and visitors who haven't signed in - can read posts, replies, and member profiles. Posting and voting still require sign-in.

This is the default for every community and is unchanged from prior versions. Existing communities continue working without any setting change after upgrading to 1.4.1.

Use Public mode when:

  • You want search engine traffic to find your community
  • You're running a customer support forum or open knowledge base
  • New visitors should be able to browse before signing up

Private Mode

Every community page requires sign-in. Guests visiting /community/ or any space, post, tag, or profile URL are redirected to the sign-in page. The REST API also rejects unauthenticated requests for community data.

The sign-in, register, and forgot-password pages stay reachable so guests can still create an account or recover access.

Use Private mode when:

  • The community is for paying members only
  • Discussions are confidential (internal team, private group, paid coaching)
  • You don't want search engines to index any community content

What Stays Public in Private Mode

These pages are intentionally exempt so guests can sign up and recover access:

  • The sign-in page
  • The registration page
  • The forgot-password page
  • Email verification and password-reset confirmation links

Everything else - homepage, spaces, posts, replies, tags, member profiles, leaderboard, search - is gated.

REST API Behaviour

Public mode: read endpoints return data to anyone. Write endpoints still require auth.

Private mode: every endpoint under /wp-json/jetonomy/v1/ requires an authenticated request. Anonymous calls return 401 Unauthorized. This is checked centrally - third-party clients calling the API see the same gate as the website does.

Switching Modes

Switching is instant and applies to the next page load. You can change the mode at any time:

  • Public → Private: existing public links become sign-in redirects. Search engines will eventually drop your indexed pages.
  • Private → Public: pages become reachable again. Submit your sitemap to search engines if you want re-indexing.

There's no migration step and no downtime.

The Activity Log admin page shows you every audit-worthy event in your community - who created a post, who approved a reply, who banned a member, when a role changed. Read-only and filterable.

What You Will Learn

  • What events are recorded in the Activity Log
  • How to filter the log by user, event type, or date range
  • Why some events appear and others don't
  • How to use the log for moderation reviews and account audits

Go to Jetonomy → Activity Log to access the page.

Activity Log admin page showing a filtered list of community events with user, type, and date-range filters

What Gets Logged

The log records every event that changes the state of the community in a way that's worth being able to look back on:

  • Posts created, edited, deleted, restored
  • Replies created, edited, deleted, restored
  • Flags raised and resolved (with the resolution outcome)
  • Members joining or leaving a space
  • Role changes (member → moderator, moderator → admin, demotions)
  • Trust level promotions and demotions
  • Bans and silences (issued and lifted)
  • Setting changes that affect community behaviour

What's NOT logged: votes, reads, search queries, page views - these are too high-volume to keep useful and are tracked separately by Analytics (Pro).

Filters

The page supports three independent filters that can be combined:

Filter What it does
User Show only events caused by a specific member or staff user
Type Show only one event type (e.g. "post created", "ban issued")
Date range Show events between two dates

Combine all three to answer questions like "which posts did this moderator approve last week?"

Read-Only

The Activity Log is intentionally read-only. You can't edit or delete entries from this page. The log is the audit trail - modifying it would defeat the point.

If you need to undo something a member or staff user did, do it in the relevant area (e.g. restore a deleted post from the post page, lift a ban from the member's profile). The log will then record the corrective action as a new entry.

Performance

The log is paginated server-side at 20 entries per page by default (adjustable via the per-page screen option). Filters apply at the database level, so even on a community with hundreds of thousands of entries, filtered queries return in under a second on a normal host.

There's no automatic cleanup - entries are kept indefinitely. If you want to prune the log, you can do it via WP-CLI; reach out via support if you need a recipe.

The Revisions admin page lets you browse every saved revision of every post and reply, and compare any two of them side-by-side. Use it to see what changed when a member edits, or to recover content from an earlier version.

What You Will Learn

  • When Jetonomy saves a revision (and when it doesn't)
  • How to find a specific revision by post, user, or date
  • How to read the side-by-side diff
  • The relationship between the Revisions page and the post-level edit history

Go to Jetonomy → Revisions to access the page.

When a Revision Is Saved

A revision is saved every time a post or reply is edited and the change is meaningful - that is, the content actually differs from the previous version. Pure formatting tweaks (e.g. adding a paragraph break that doesn't change the rendered output) won't always create a revision.

Revisions are NOT created when:

  • The post is first published - that's the initial version, not a revision
  • The edit is from the same user within the auto-save window (a few seconds)
  • Only metadata changes (e.g. tags or pinned-state) - those go into the Activity Log, not Revisions

Browsing Revisions

The list view shows every revision sorted by date. Use the filters to narrow:

Filter What it does
Post Show every revision of one specific post or reply
User Show every revision authored by one user (across posts)
Date range Show revisions saved between two dates

Each row shows the post title, the editor, when the change was saved, and the size delta (e.g. "+128 chars / −42 chars").

Side-by-Side Diff

Revisions diff view showing the before and after versions of a post side by side, with added text highlighted green and removed text highlighted red

Click any revision to open the diff view. Pick two revisions from the same post and you'll see:

  • The before version on the left, after on the right
  • Added text highlighted green, removed text highlighted red
  • Line numbers so you can locate changes in context

The diff is character-aware, so small typo fixes show as small highlights rather than entire-paragraph rewrites.

Read-Only

Like the Activity Log, the Revisions page is read-only. To roll back to a prior revision, edit the post and paste the older content in. There's no one-click revert button - that's a deliberate choice to keep the audit trail truthful.

Permission

Only users with the jetonomy_manage_settings capability (administrators only by default) can see this page. Members can see their own edit history on each individual post, but not the cross-post Revisions admin view.

Storage

Revisions are stored in a dedicated database table separate from WordPress core revisions. They don't bloat wp_posts, and they're not affected by the WP_POST_REVISIONS constant. Jetonomy keeps every revision indefinitely; if you need a retention policy, reach out via support.

The Users admin screen gives moderators and administrators a full view of every community member - with one-click access to ban, silence, or change trust level without leaving wp-admin.

What You Will Learn

  • How to search and filter members in the admin
  • How to ban, silence, or space-ban a member
  • How to override a member's trust level manually
  • Which capability gates access to this screen

Go to Jetonomy → Users to access this screen.

Required Capability

The Users screen and its actions are gated by:

Action Required Capability
View the Users page jetonomy_manage_settings
Ban or unban a member jetonomy_moderate
Silence a member jetonomy_moderate
Change trust level jetonomy_manage_settings
Search users (AJAX picker in other admin screens) jetonomy_manage_spaces

The Users page menu is administrator-only (jetonomy_manage_settings). Editors receive jetonomy_moderate automatically, which powers the inline ban and silence actions, but it does not open the Users page menu. See Settings → Permissions → WordPress Role Mapping for the full capability table.

Searching and Filtering

The toolbar at the top of the Users screen has two controls:

  1. Search box - searches by username or display name. Type at least two characters; results update on submit.
  2. Trust Level filter - dropdown to show only members at a specific trust level (0 = Newcomer through 5 = Moderator). Select "All Trust Levels" to show everyone.

The paginator at the bottom shows total user count and lets you move between pages.

User Table Columns

Column Description
Username Avatar, login name, and row action links
Display Name Public display name
Trust Level Badge showing current level (0-5)
Reputation Total reputation score
Posts Post count
Replies Reply count
Joined Registration date (relative)
Last Seen Most recent login (relative)

Row Actions

Hover over a row to reveal the action links under the username.

View Profile

Opens the standard WordPress user edit screen for that member. This is the right place to change their email, reset their password, or modify their WordPress role.

Change Trust Level

Opens an inline dropdown directly in the table row. Choose any level from 0 (Newcomer) to 5 (Moderator) and click Save. The change takes effect immediately and is logged in the activity log.

Trust levels 0 through 3 are normally earned automatically by the trust cron job. Use this override to:

  • Promote a long-standing member to Level 4 or 5 (manual tiers)
  • Demote a member who behaved poorly but has not yet triggered enough flags for automatic demotion
  • Grant Level 2 to a known member immediately after import

Ban

Opens the Ban User modal. Three options:

Type Effect
Global Ban Member cannot log in to Jetonomy at all
Silence Member can log in and read but cannot post, reply, or vote
Space Ban Member is banned from a single space (enter the space ID in the form)

Duration options: Permanent, 1 Day, 7 Days, 30 Days.

A Reason field is optional but recommended - the reason is stored in the wp_jt_restrictions table and visible if you query restrictions via WP-CLI or the REST API.

Silence (quick action)

The row also exposes a Silence shortcut link that applies a permanent global silence immediately without opening the modal. Use the Ban modal if you want a temporary silence or a reason.

Removing a Ban

Bans are not managed through the Users screen directly after they are created. To remove a ban:

WP-CLI:

wp --path="/path/to/wordpress" jetonomy user unban <user_id>

REST API (site admin):

DELETE /jetonomy/v1/users/<user_id>/restrictions/<restriction_id>

Temporary bans (1d, 7d, 30d) expire automatically - you do not need to remove them manually.

Trust Level Reference

Level Name How Earned
0 Newcomer Default on registration
1 Member Auto - light participation
2 Regular Auto - consistent participation
3 Trusted Auto - high engagement
4 Leader Manual only (moderator or admin)
5 Moderator Manual only (admin only)

Thresholds for levels 1-3 are configured on Settings → Permissions → Trust Level Thresholds.

What's Next?

Manage posts and replies from the content list view.

Admin Content →

The Posts and Replies admin screen lets you view, search, edit, and moderate every piece of content in your community without visiting the front end.

What You Will Learn

  • How to find and filter community posts and replies
  • How to inline-edit a post title or body
  • How to trash, approve, or mark content as spam
  • How bulk actions work

Go to Jetonomy → Posts and Replies to access this screen.

Posts and Replies admin screen showing the content list with the status filter and an inline edit panel open

Required Capability

The Posts and Replies admin page itself requires jetonomy_manage_settings, which is administrator-only by default. The separate jetonomy_moderate capability (which Editors receive automatically) governs the Moderation screen, not this page.

The Toolbar

The filter bar at the top of the screen has four controls that can be combined freely:

Control What it filters
Space filter Show only posts from a specific space
Status filter All, Published, Pending, Spam, or Trash
Search box Searches post titles
Clear button Appears when any filter is active; resets all to defaults

The counter in the toolbar shows which range of results you are viewing and the total matching count.

Post Table Columns

Column Description
(checkbox) Select row for bulk actions
Title Post title, status badge, reply count link, row actions
Space The space the post belongs to
Author Display name of the author
Status Published, Pending, Spam, or Trash
Replies Reply count, linking to a filtered view of replies for that post
Views View count
Date Time elapsed since creation

Row Actions

Hover a row to reveal its action links.

Edit (inline)

Click Edit to expand an inline edit panel directly in the table row. You can change:

  • Post title (up to 255 characters)
  • Post body (full HTML content)

Click Save to apply the change. Click Cancel to collapse the panel without saving.

Trash

Moves the post to Trash status. Trashed posts are hidden from the front end but remain in the database. Use the Status filter to view trashed posts and restore them with the Restore action that appears in their row.

Spam

Marks the post as spam. Spam posts are hidden from the front end. The author's reputation is not automatically adjusted by this action.

View

Opens the post on the front end in a new tab. Only appears when the post has a valid space and slug.

Bulk Actions

To apply an action to multiple posts at once:

  1. Check the boxes next to the posts you want to affect. Check the header checkbox to select all visible rows.
  2. Choose Approve, Move to Trash, or Mark as Spam from the bulk action dropdown.
  3. Click Apply.

A confirmation prompt appears before the action runs. The spinner in the toolbar indicates the request is in flight.

Tip: If a bulk action partially fails (some rows succeed, some do not), the page will report the count that succeeded. Refresh and re-apply to the remaining rows.

Viewing Replies

Clicking the reply count number for any post opens a filtered view showing only the replies for that post. Replies use the same toolbar, status filter, and inline-edit actions as posts.

Status Definitions

Status Meaning
Published Visible to all users with read access
Pending Created by a member at trust level 0 and awaiting first-post review
Spam Flagged or manually marked as spam
Trash Soft-deleted; not visible on the front end

Note: Pending posts are held for review when the anti-spam settings require first-post moderation. Once you approve a member's first post, subsequent posts from that member publish immediately.

What's Next?

Organize your community's spaces into categories.

Admin Categories →

Categories let you group related spaces under a shared label so members can browse a subset of your community without seeing everything at once.

This is the admin reference for the Categories screen. For how categories fit alongside spaces in your community structure, see Categories in the Spaces & Categories guide.

What You Will Learn

  • How to create, edit, and delete categories
  • How category visibility works
  • How to reorder categories with drag and drop
  • How icons and colors work

Go to Jetonomy → Categories to access this screen.

Required Capability

The Categories admin page requires jetonomy_manage_settings, which is administrator-only by default. Both jetonomy_manage_settings and jetonomy_manage_spaces are granted only to administrators - Editors do not receive either capability, so they cannot open this page.

Page Layout

The Categories screen is split into two panels side by side:

  • Left - Add New Category form for creating a new category
  • Right - Categories table listing existing categories and their children

Categories admin screen showing the two-panel layout: the Add New Category form on the left and the drag-to-reorder categories table on the right

Creating a Category

Fill in the Add New Category form and click Add Category.

Field Required Notes
Name Yes Displayed in navigation and on the category page
Slug No Auto-generated from the name if left blank. Used in URLs.
Description No Optional text shown on the category listing page
Parent Category No Nest this category under an existing one. Two levels max.
Visibility No Controls who can see this category (see Visibility section below)
Icon No Choose from the Lucide icon picker
Color No Color swatch displayed next to the category name in navigation

Visibility Options

Option Who can see the category
Public All visitors (including logged-out) when guest access is on
Private Logged-in members only
Hidden Not shown in navigation or listings; direct URL still works

The category's visibility does not override the visibility of individual spaces within it. A public category can contain private spaces.

Editing a Category

Click Edit in the row actions under any category name. An Edit Category modal opens with the same fields as the creation form. Make your changes and click Update Category.

Deleting a Category

Click Delete in the row actions. A browser confirmation prompt appears before the delete runs.

Warning: Deleting a category does not delete the spaces inside it. Spaces that belonged to the deleted category lose their category assignment and move to "uncategorized." There is no undo - confirm you have reassigned or are okay losing the grouping before deleting.

Reordering Categories

Drag the handle icon at the far left of any row to reorder categories. The order is saved automatically when you drop the row. Child categories follow their parent when the parent moves.

Child Categories

Set Parent Category when creating or editing a category to nest it under an existing top-level category. The table renders children indented below their parent. Two nesting levels are supported.

Use the search box in the table toolbar to filter categories by name. Clear the search to see all categories again. The search does not affect the Add New Category form.

Rows Per Page

The dropdown in the table toolbar controls how many categories appear per page (20, 50, or 100). The selection submits the form immediately.

What's Next?

Enable or disable Jetonomy Pro extensions if you have the Pro plugin active.

Extensions →

The Extensions screen is your control panel for turning individual Jetonomy Pro features on or off. It appears in the Jetonomy menu only when Jetonomy Pro is active.

What You Will Learn

  • Where the Extensions screen lives and who can access it
  • How to enable or disable an extension
  • What happens to data when you disable an extension

Go to Jetonomy → Extensions to access this screen. This menu item is added by Jetonomy Pro and is not visible on free-only installs.

Extensions screen showing the Pro extension cards in a grid with category filters and on/off toggles

Required Capability

The Extensions screen is gated by jetonomy_manage_settings, which is administrator-only by default. Only WordPress Administrators can open the screen and enable or disable extensions.

The Extension Grid

Extensions are displayed as cards in a grid. Each card shows:

  • Extension name and category tag
  • Version number
  • Short description of what the extension does
  • Toggle switch (on = enabled, off = disabled)

Active extensions have a highlighted card border. Inactive extensions appear muted.

Filtering by Category

Use the filter buttons above the grid to show only extensions in a specific category. Available categories include Communication, Engagement, Administration, Moderation, Gamification, Content, Integration, Branding, SEO, and AI.

Click All to return to the full list.

Enabling an Extension

Click the toggle switch on the card. The page reloads and the extension is now active. On first enable, the extension's activate() method runs - this creates any database tables the extension needs and schedules any cron hooks.

Disabling an Extension

Click the toggle switch on an active card. The page reloads and the extension is now off. The extension's deactivate() method runs - this removes scheduled cron hooks and deregisters rewrite rules.

Note: Disabling an extension does not delete its data. Database tables and stored options are preserved. Re-enabling the extension restores full functionality with all existing data intact.

Available Extensions

Extension Category What It Adds
Private Messaging Communication Direct and group message threads at /community/messages/
Analytics Administration Engagement graphs, top spaces, top contributors
Emoji Reactions Engagement Per-post and per-reply emoji reaction picker
Polls Engagement Inline polls inside posts
Custom Badges Gamification Award and display custom achievement badges
Custom Fields Content Add custom profile and post fields
Webhooks Integration Outgoing webhooks on community events
Advanced Moderation Moderation Keyword rules, regex patterns, auto-action on matched content
White Label Branding Replace Jetonomy branding with your own
Email Digest Communication Daily and weekly summary emails for members
Web Push Communication Browser push notifications
SEO Pro SEO Schema.org markup, sitemaps, canonical handling
Reply By Email Communication Members reply to threads by replying to notification emails
AI Integration AI Spam detection, post summarization, semantic search, content suggestions
Site Announcements Moderation Pin a post to the top of every space for site-wide updates

For detailed setup instructions for each extension, see the Pro Features documentation.

What's Next?

For the full feature documentation for each Pro extension, see the Pro Features section.

Pro Features →

The License tab is where you activate your Jetonomy Pro license key. Activating unlocks every Pro extension and turns on automatic updates. This tab appears only when Jetonomy Pro is installed and active.

What You Will Learn

  • Where to find the License tab and what it does
  • How to activate your license key
  • How the license unlocks Pro extensions
  • What happens when a license is missing, expired, or deactivated

Go to Jetonomy → Settings → License to open this screen. The tab is added by Jetonomy Pro and is not present on free-only installs.

Activating Your License

  1. Open Jetonomy → Settings → License.
  2. Paste your license key into the License Key field. You receive this key in your purchase receipt and in your store account.
  3. Click Activate License.

On success you see a "License activated successfully" confirmation, and the screen switches to a status view showing your masked key and the expiry date (or "Never (Lifetime License)" for lifetime plans).

How the License Unlocks Extensions

A valid license unlocks all Pro extensions - there is no per-feature or per-tier gating once the key is active. Each extension only runs when two conditions are both true:

  1. The extension is switched on under Jetonomy → Extensions.
  2. Your license is currently valid.

If the license is missing or expired, enabled extensions stop booting and their features (private messaging, polls, reactions, analytics, and so on) become unavailable, even though their toggles still show on the Extensions screen. Re-activating a valid key restores them immediately - your data is never deleted.

Updates

The license also powers automatic updates. With a valid key, Jetonomy Pro receives new versions through the normal WordPress Updates screen. Without an active license you can keep using the version you have, but you will not be offered Pro updates.

Deactivating a License

To move your license to a different site, click Deactivate License on the status view. This frees the activation slot so you can activate the same key elsewhere. Deactivating removes the stored key from this site and stops Pro updates and extensions until a valid key is activated again.

Troubleshooting

  • "License is not active for this site." - The key is valid but its activation limit is reached, or it is registered to a different site. Deactivate it on the other site, or check your plan's site limit.
  • Expired license - Renew from your store account, then re-activate. Extensions resume the moment a valid key is in place.
  • Key not accepted - Confirm you pasted the full key with no trailing spaces, and that you are using the Pro license key (not an order number).

What's Next?

Turn individual Pro features on or off from the Extensions screen.

Extensions →

The Integrations tab holds the settings that keep Jetonomy and BuddyPress group activity in sync. It appears in Jetonomy → Settings only when BuddyPress with the Groups component is active on your site.

What You Will Learn

  • Where the Integrations tab appears and when it is visible
  • What the two BuddyPress sync toggles do
  • The dependency between the two toggles

Integrations tab showing the two BuddyPress sync toggles

Go to Jetonomy → Settings → Integrations to access these settings. If you do not see the tab, BuddyPress (with Groups) is not active - the tab is hidden until then.

Broadcast topics to group activity

Setting: jetonomy_bp_broadcast Default: On Location: Integrations tab → BuddyPress card

When on, every new Jetonomy topic created in a space that is paired with a BuddyPress group is posted into that group's activity stream. Members browsing the group see the new discussion in their activity feed without leaving BuddyPress.

Turn it off if you want Jetonomy discussions to stay inside the community and not appear in group activity.

Round-trip activity comments

Setting: jetonomy_bp_comment_bridge Default: On Location: Integrations tab → BuddyPress card

When on, comments members add to a broadcast activity item in BuddyPress are mirrored back into Jetonomy as replies on the original topic - so a conversation that starts in either place stays in sync in both.

Note: This toggle depends on Broadcast topics to group activity being enabled. If broadcast is off, there are no broadcast items for comments to round-trip, and this setting has no effect.

What's Next?

For step-by-step setup of the BuddyPress integration (pairing spaces with groups, member sync), see the integration guide.

BuddyPress Integration →

Migration

Import from bbPress, wpForo, and other forum plugins.

Bringing an existing forum into Jetonomy? This page covers everything that is the same across all three importers - which source to pick, how to read the import screen, and the checklist to run after any import. Then follow the guide for your specific forum software.

Jetonomy Import screen showing detected forum sources with stat previews and Import buttons

Which Importer Do I Need?

Jetonomy ships with three built-in importers. Pick the one that matches the forum plugin you are moving away from:

You are coming from Use this guide
bbPress Importing from bbPress
wpForo Importing from wpForo
Asgaros Forum Importing from Asgaros Forum

These three are the only built-in sources. Developers can add support for other forum software through the jetonomy_importers filter - see the developer reference for details.

Before Any Import: Back Up

Always take a full database backup before importing, no matter which source you use. The importers read from your old forum's tables and never modify them, but importing creates new records in Jetonomy and cannot be automatically undone. A backup is your safety net if you want to start fresh.

Keep your old forum plugin (bbPress, wpForo, or Asgaros) active during the import - each importer reads directly from that plugin's live tables. You can deactivate it once you have confirmed the import looks right.

Browser or WP-CLI?

You can run any import two ways. Use this to decide:

  • Browser (Jetonomy → Import) - the simplest option, with a live progress bar. Best for small to medium communities (under roughly 50,000 topics + replies). The risk on large databases is a browser or server timeout part-way through.

  • WP-CLI (command line) - the reliable option for large communities, because it is not subject to browser timeouts. Run it from your server's command line (SSH). The valid source values are bbpress, wpforo, and asgaros (all lowercase):

    wp jetonomy import bbpress
    wp jetonomy import wpforo
    wp jetonomy import asgaros
    

    If you run the command on a managed host where you must point at the WordPress install, add --path:

    wp --path="/path/to/wordpress" jetonomy import bbpress
    

    If you type a source name that does not exist, the command lists the valid ones back to you.

Reading the Import Screen

When you open Jetonomy → Import, each forum plugin that Jetonomy detects appears as its own card. Here is what every part of the card means:

  • No Forum Data Detected - if none of bbPress, wpForo, or Asgaros is installed with content, you see this empty state instead of cards. Install and add content to one of those plugins, then return.
  • Stat preview - each detected source shows a live count of what it found (for example Forums, Topics, Replies). This is read straight from your old forum so you can confirm Jetonomy sees your data before you start.
  • Status badge - one badge per card tells you the card's state:
    • Available - detected and ready to import; this is the normal first-time state.
    • Previously Imported - you have already run this import once. The card shows the date of the last import and how many records it brought over.
    • Import Interrupted - a browser import stopped before finishing. The card offers Resume Import to continue, or Start Over to begin again.
  • Re-Import warning - once a source shows Previously Imported, its button changes to Re-Import and the card warns that re-importing may create duplicate content. Clicking it asks you to confirm first. Only re-import if the previous import had a problem - running it a second time on top of a successful import will duplicate your topics and replies.
  • Progress tracker - while an import runs, a five-step tracker shows where it is: Forums → Topics → Replies → Profiles → Finalize, with a percentage progress bar underneath.

After Any Import

These steps apply to every source. The individual guides list the same checklist with source-specific notes, but the essentials are:

  • Visit your community home and confirm your spaces match your old forums.
  • Open several posts and confirm the content and replies came across intact.
  • Re-assign moderators. No importer brings over moderator assignments - set Space Moderator roles manually under Jetonomy → Spaces.
  • Flush permalinks if spaces 404. Go to Jetonomy → Settings → Permalinks and click Save. (The bbPress importer does this for you automatically; wpForo and Asgaros do not, so do it by hand if new spaces return a 404.)
  • Clean up old shortcodes. If your pages or widgets used your old forum's shortcodes, remove or replace them - they will print raw shortcode text while the old plugin is still active.
  • Once everything checks out, you can deactivate the old forum plugin.

What's Next?

Ready to import? Start with the guide for your forum software:

Move your existing bbPress community into Jetonomy - forums, topics, replies, user data, and vote history - using the built-in importer.

Import tool interface with source selection and progress tracking

New to migration? Read the Migration overview first - it explains how to read the import screen (stat previews, status badges, the progress tracker) and the backup rule that applies to every import.

What You Will Learn

  • What data the bbPress importer brings over and what it leaves behind
  • How to prepare your site before running the import
  • How to start the import, monitor progress, and resume if it stops
  • How to use the CLI dry-run option to validate before writing data
  • What to verify after the import completes

What Gets Imported

bbPress Data Imported As Notes
Forums Jetonomy Spaces Forum description → space description
Topics Jetonomy Posts Topic title + content preserved
Replies Jetonomy Replies Imported as flat replies on the post (bbPress reply threading is flattened)
User accounts Linked to existing WP users Matched by user ID
Sticky topics Pinned posts Preserved

Not imported:

  • bbPress topic tags
  • bbPress user activity counts / reputation
  • bbPress votes (no standard bbPress vote data is read)
  • Forum moderator assignments (assign Space Moderator roles manually after import)
  • bbPress subscriptions (replaced by Jetonomy follow/subscribe)
  • bbPress private messages (import to Jetonomy Pro private messaging separately)
  • Custom bbPress meta fields (use the jetonomy_importers filter to extend)
  • Forum avatars (WordPress avatars carry over via Gravatar/WP user accounts)

What to do about the gaps: Jetonomy replies are flat by design - every reply attaches to the topic, not to another reply - so the conversation stays intact even though bbPress's nested threading is not carried over. Topic tags are not imported; if tags matter to you, re-tag your highest-value topics by hand after the import (it is usually a small number that drive most of the traffic).

Pre-Import Checklist

Complete these steps before starting the import:

  1. Back up your database. The importer does not modify bbPress tables, but a backup is essential.
  2. Activate Jetonomy and complete the setup wizard. Your community base URL should be set.
  3. Keep bbPress active during the import. The importer reads directly from bbPress tables.
  4. Set your server timeout high. Large imports (100,000+ records) take time. Increase max_execution_time in php.ini or use WP-CLI (recommended for large sites).
  5. Disable other heavy plugins during import if your server is resource-constrained.

Tip: For large communities (10,000+ topics), run the import via WP-CLI to avoid browser timeouts entirely. See the WP-CLI section below.

Running the Import

  1. Go to Jetonomy → Import in your WordPress admin.
  2. Select bbPress as the source.
  3. Click Start Import.

The importer processes records in batches of 500. A progress bar shows completion percentage, current batch, and estimated time remaining.

Do not close the browser tab while the import is running. If the page refreshes or you navigate away, the import will pause - but can be resumed (see below).

Dry-Run Mode

Dry-run mode is available via WP-CLI only (--dry-run). It runs the import logic without writing any data and reports the imported / skipped / error totals it would have produced:

wp jetonomy import bbpress --dry-run

The summary line looks like [DRY RUN] Import complete. Imported: 1240, Skipped: 12, Errors: 0. No database writes are made, so you can run it as many times as you need.

Estimated Import Times

Community Size Topics + Replies Estimated Time
Small Under 10,000 2-5 minutes
Medium 10,000-100,000 10-40 minutes
Large 100,000-500,000 1-4 hours
Very large 500,000+ Use WP-CLI

These are estimates for a typical shared hosting server. Dedicated servers will be significantly faster.

Resuming a Paused Import

If the import stops (browser closed, timeout, server restart), return to Jetonomy → Import. The card shows an Import Interrupted badge with the phase it stopped at. Click Resume Import to continue from the last completed batch, or Start Over to begin again from scratch.

You can safely resume multiple times. Records that were already imported are skipped.

Running via WP-CLI

For large communities, WP-CLI is more reliable than the browser-based importer. Run it from your server's command line (SSH); on most managed hosts you point it at the WordPress install with --path. The valid source value is bbpress (lowercase) - if you mistype it, the command lists the sources it recognizes.

wp --path="/path/to/wordpress" jetonomy import bbpress

The only flag is --dry-run:

# Dry run - validate and count without writing any data
wp jetonomy import bbpress --dry-run

WP-CLI runs without a browser timeout limit and prints an Imported / Skipped / Errors summary when the import finishes.

Post-Import Checklist

After the import completes, verify the following:

  • Navigate to your community home - spaces should match your old bbPress forums
  • Open several posts and confirm content and replies are intact
  • Check that user profiles show post counts
  • Assign Space Moderator roles to your former forum moderators (moderator assignments are not imported)
  • Test creating a new post as a regular user
  • If new spaces return a 404, visit Jetonomy → Settings → Permalinks and click Save to flush rewrite rules (normally done automatically on import completion)
  • If you used bbPress shortcodes on pages, remove or replace them - they will output raw shortcode text now that bbPress is still active

Note: After a successful import, you can deactivate bbPress. Your community data is now in Jetonomy's tables and bbPress is no longer needed.

Re-running an Import

Once bbPress has been imported, its card on Jetonomy → Import changes to a Previously Imported badge that shows the date of the last import and how many records it brought over. The Start button becomes Re-Import, and Jetonomy warns you before you proceed because re-importing creates duplicate content - it does not detect and skip what you already imported. Only re-import if the first import had a real problem; otherwise leave it alone.

What's Next?

Migrating from wpForo? The process is similar with a few wpForo-specific field mappings.

Importing from wpForo →

Move your existing wpForo community into Jetonomy - forums, topics, replies, and user profiles - using the built-in wpForo importer.

Import tool with wpForo source selected and migration progress

New to migration? Read the Migration overview first - it explains how to read the import screen (stat previews, status badges, the progress tracker) and the backup rule that applies to every import.

What You Will Learn

  • What the wpForo importer brings over and how wpForo structures map to Jetonomy
  • How to prepare your site before running the import
  • How to start and monitor the import
  • How wpForo's multi-board and forum structures map onto Jetonomy
  • What to verify after the import

What Gets Imported

wpForo Data Imported As Notes
Forums Jetonomy Spaces Forum name, slug, description preserved
Topics Jetonomy Posts Title and first post content preserved
Replies (posts) Jetonomy Replies Reply parent relationships preserved
User accounts Linked to existing WP users Matched by WP user ID
Liked posts Vote score wpForo likes mapped to upvotes
Pinned topics Pinned posts Preserved
Closed topics Closed posts Preserved

Not imported:

  • wpForo sub-forum hierarchy (all forums, including sub-forums, are flattened into spaces under the board's category)
  • wpForo topic tags
  • wpForo user reputation / points
  • wpForo user roles and moderator assignments (assign Space Moderator roles manually after import)
  • wpForo private conversations (different data structure; import to Jetonomy Pro private messaging separately)
  • wpForo groups and group memberships (map manually to Jetonomy spaces)
  • wpForo custom user groups beyond standard roles
  • Embedded wpForo media that uses shortcodes instead of standard <img> tags

wpForo Data Structure Differences

wpForo and Jetonomy structure their data differently in a few key areas:

Multi-board support - wpForo lets you run multiple boards, each with its own set of forums and topics. The importer automatically detects all of your active boards and imports each one into its own Jetonomy category. Single-board installs work without any extra configuration.

Forums and categories - Within each board, wpForo nests forums inside forums. Jetonomy separates categories (top-level groups) from spaces (discussion areas), so the importer creates one Jetonomy category per board and one space per wpForo forum. Sub-forum nesting is not preserved - every forum (parent or child) becomes a flat space under the board's category.

For developers: wpForo stores each board's data in its own set of tables (wp_wpforo1_*, wp_wpforo2_*, and so on) and tracks boards in wpforo_boards. The importer reads wpforo_boards to discover boards and auto-detects the table prefix, so a custom prefix needs no configuration.

Post structure - In wpForo, the first "post" of a topic is a reply in the same table. In Jetonomy, topics and replies are separate entities. The importer promotes the first wpForo post as the Jetonomy post body and imports subsequent posts as replies.

Reputation - wpForo reputation and points are not imported. After import, trust levels are re-evaluated by the cron job based on activity within Jetonomy and your configured thresholds.

Pre-Import Checklist

  1. Back up your database. The importer reads but never modifies wpForo tables, but a backup protects against any edge cases.
  2. Activate Jetonomy and complete the setup wizard.
  3. Keep wpForo active during the import - the importer reads from wpForo's live tables.
  4. Check your wpForo table prefix. If wpForo uses a custom prefix, confirm it in wpforo_boards - the importer auto-detects it.
  5. Disable wpForo page caching if active, to avoid stale data during the import process.

Tip: If you have over 50,000 topics, use WP-CLI to run the import. Browser-based imports on large databases can time out on shared hosting.

Running the Import

  1. Go to Jetonomy → Import in your WordPress admin.
  2. Select wpForo as the source.
  3. Click Start Import.

The wpForo importer runs the entire import in a single pass - the progress bar advances in one step from start to complete. (The bbPress importer, by contrast, runs in true incremental batches.) Because it is single-pass, larger wpForo databases are best imported via WP-CLI to avoid browser timeouts.

Preview Before You Import

Always take a full database backup before you run the wpForo import - that is your way to undo if you want to start over. There is no preview mode for wpForo: only the bbPress importer supports a true --dry-run that counts records without writing them. The wpForo importer always writes data, so a backup (not a dry run) is your safety net.

Heads up: The --dry-run flag is accepted on the wp jetonomy import wpforo command, but the wpForo importer does not act on it - it performs the real import either way. Do not use it expecting a preview.

Estimated Import Times

Community Size Topics + Replies Estimated Time
Small Under 10,000 2-5 minutes
Medium 10,000-100,000 10-40 minutes
Large 100,000-500,000 1-4 hours
Very large 500,000+ Use WP-CLI

Resuming a Paused Import

The wpForo import runs as a single pass, so there is no mid-import resume point. If it is interrupted (timeout, server restart, or closed browser), it cannot be resumed partway through - return to Jetonomy → Import and click Start Over to run it again. For this reason, run large wpForo imports via WP-CLI, which is not subject to browser timeouts.

Running via WP-CLI

Run this from your server's command line (SSH); on most managed hosts you point it at the WordPress install with --path. The valid source value is wpforo (lowercase) - if you mistype it, the command lists the sources it recognizes.

wp --path="/path/to/wordpress" jetonomy import wpforo

WP-CLI is the recommended way to import larger wpForo databases - it is not subject to browser timeouts and prints an Imported / Skipped / Errors summary when finished.

Note: The --dry-run flag is accepted by the command but is not honored by the wpForo importer - it will still write data. Take a backup first.

Space Types After Import

All imported wpForo forums become standard Forum spaces in Jetonomy. wpForo post types (Normal, Question/Answer, Debate) are not mapped to Jetonomy space types - if you want a space to behave as Q&A, change its type in Jetonomy → Spaces after the import.

Post-Import Checklist

After the import completes:

  • Visit your community home and confirm spaces match your old wpForo forums
  • Open several posts from different spaces and verify content is intact
  • Assign Space Moderator roles to your former forum moderators (moderator assignments are not imported)
  • Go to Settings → Permalinks and click Save to flush rewrite rules (the wpForo importer does not flush them automatically, so this step is needed if new spaces return a 404)
  • Remove or update any wpForo shortcodes on pages and widgets
  • Consider deactivating wpForo after confirming the import - it is no longer needed

Note: If your wpForo installation used a third-party plugin for member ratings or post reactions, those values are not included in the standard import. Developers can extend the importer through the jetonomy_importers filter.

Re-running an Import

Once wpForo has been imported, its card on Jetonomy → Import changes to a Previously Imported badge showing the date and record count of the last import, and the Start button becomes Re-Import. Jetonomy warns you first because re-importing creates duplicate content - it does not skip what you already brought over. Only re-import if the first attempt had a real problem.

What's Next?

Migrating from Asgaros Forum instead? The process is similar with a few Asgaros-specific mappings.

Importing from Asgaros →

Already imported? Configure who can read your community and how members earn trust.

General Settings →

Move your existing Asgaros Forum community into Jetonomy - forums, topics, replies, and user profiles - using the built-in Asgaros importer.

Import tool with Asgaros source selected and migration progress

New to migration? Read the Migration overview first - it explains how to read the import screen (stat previews, status badges, the progress tracker) and the backup rule that applies to every import.

What You Will Learn

  • What the Asgaros importer brings over and what it leaves behind
  • How Asgaros forum hierarchy maps onto Jetonomy spaces
  • How to start and monitor the import
  • What to verify after the import

What Gets Imported

Asgaros Data Imported As Notes
Forums Jetonomy Spaces Forum name and description preserved
Sub-forums Jetonomy Sub-spaces Parent/child forum hierarchy is preserved
Topics Jetonomy Posts Topic title + first post content preserved
Replies (posts) Jetonomy Replies Imported as flat replies on the post
User accounts Linked to existing WP users Matched by WP user ID
Sticky topics Pinned posts Preserved
Closed topics Closed posts Preserved
Unapproved topics Pending posts Topics not approved in Asgaros import as pending

Not imported:

  • Asgaros topic tags
  • Asgaros user reputation / points
  • Asgaros likes / reactions
  • Asgaros moderator assignments (assign Space Moderator roles manually after import)
  • Asgaros subscriptions (replaced by Jetonomy follow/subscribe)
  • Custom Asgaros meta fields (use the jetonomy_importers filter to extend)

Asgaros Data Structure Differences

Forum hierarchy - Asgaros keeps your forums and sub-forums in a single nested list. The importer creates one Jetonomy category ("Imported from Asgaros") and one space per Asgaros forum, importing parent forums before their children so your sub-forums come across as Jetonomy sub-spaces.

Post structure - In Asgaros, a topic's opening message and all its replies are stored together. The importer promotes the opening message as the Jetonomy post body and imports the remaining messages as replies.

For developers: Asgaros stores forums in one table with a parent_forum column (hence the parent-before-child import order), and stores the opening post plus all replies together in the forum_posts table.

Pre-Import Checklist

  1. Back up your database. The importer reads but never modifies Asgaros tables, but a backup protects against any edge cases.
  2. Activate Jetonomy and complete the setup wizard.
  3. Keep Asgaros Forum active during the import - the importer reads from its live tables.
  4. Disable page caching if active, to avoid stale data during the import.

Tip: For large Asgaros communities, run the import via WP-CLI to avoid browser timeouts.

Preview Before You Import

Always take a full database backup before you run the Asgaros import - that is your way to undo if you want to start over. There is no preview mode for Asgaros: only the bbPress importer supports a true --dry-run that counts records without writing them. The Asgaros importer always writes data, so a backup (not a dry run) is your safety net.

Heads up: The --dry-run flag is accepted on the wp jetonomy import asgaros command, but the Asgaros importer does not act on it - it performs the real import either way. Do not use it expecting a preview.

Running the Import

  1. Go to Jetonomy → Import in your WordPress admin.
  2. Select Asgaros Forum as the source.
  3. Click Start Import.

The Asgaros importer runs the entire import in a single pass - the progress bar advances in one step from start to complete. Because it is single-pass, it cannot be resumed partway through; if it is interrupted, click Start Over to run it again.

Estimated Import Times

Community Size Topics + Replies Estimated Time
Small Under 10,000 2-5 minutes
Medium 10,000-100,000 10-40 minutes
Large 100,000-500,000 1-4 hours
Very large 500,000+ Use WP-CLI

Running via WP-CLI

Run this from your server's command line (SSH); on most managed hosts you point it at the WordPress install with --path. The valid source value is asgaros (lowercase) - if you mistype it, the command lists the sources it recognizes.

wp --path="/path/to/wordpress" jetonomy import asgaros

WP-CLI is the recommended way to import larger Asgaros databases - it is not subject to browser timeouts and prints an Imported / Skipped / Errors summary when finished.

Note: The --dry-run flag is accepted by the command but is not honored by the Asgaros importer - it will still write data. Take a backup first.

Post-Import Checklist

After the import completes:

  • Visit your community home and confirm spaces match your old Asgaros forums
  • Confirm that sub-forums appear as sub-spaces under their parent
  • Open several posts from different spaces and verify content is intact
  • Assign Space Moderator roles to your former forum moderators (moderator assignments are not imported)
  • Go to Settings → Permalinks and click Save to flush rewrite rules (the Asgaros importer does not flush them automatically, so this step is needed if new spaces return a 404)
  • Consider deactivating Asgaros after confirming the import - it is no longer needed

Re-running an Import

Once Asgaros has been imported, its card on Jetonomy → Import changes to a Previously Imported badge showing the date and record count of the last import, and the Start button becomes Re-Import. Jetonomy warns you first because re-importing creates duplicate content - it does not skip what you already brought over. Only re-import if the first attempt had a real problem.

What's Next?

Now that your community is live, configure who can read it and how members earn trust.

General Settings →

Why Jetonomy

How Jetonomy compares to bbPress, wpForo, and other solutions.

Why Jetonomy - a modern, scalable discussion platform that brings forums, Q&A, idea boards, and a social feed together in one WordPress plugin.

Jetonomy community home page with modern UI and space listings

What Makes Jetonomy Different

Most WordPress forum plugins do one thing: threaded discussions. Jetonomy gives your members four discussion formats in a single community - traditional forums, Stack Overflow style Q&A with accepted answers, idea boards with a status workflow, and a social activity feed - all sharing the same members, voting, search, and moderation.

It is built WordPress-first (custom database tables, the WordPress REST API, real-time updates with no page reload, and theme colors that adapt automatically) so it scales from a handful of members to a community with tens of thousands of topics without slowing down the rest of your site.

Try a live Jetonomy community before you commit - Wbcom runs its own public support community on Jetonomy at community.wbcomdesigns.com. Browse spaces, read real support threads, and get a feel for the voting, trust-level badges, reply threading, and moderation flow on a production site.

Who Jetonomy Is For

  • Product teams who want a support forum, a Q&A knowledge base, and a public roadmap (idea board) in one place
  • Membership and course sites that need to gate discussions behind MemberPress, Paid Memberships Pro, WooCommerce, or an LMS
  • Growing communities that have outgrown a CPT-based forum and need real database performance at 10,000+ topics
  • Site owners who do not want to babysit moderation - the trust-level system promotes reliable members automatically instead of relying on hand-assigned roles
  • Anyone migrating from bbPress, wpForo, or Asgaros Forum who wants a built-in importer, not a manual re-build
  • Developers who want a documented REST API, hooks, blocks, shortcodes, and WP-CLI commands to extend the platform

Compare Jetonomy

What's Next?

How Jetonomy compares to bbPress - and why communities are switching to a modern forum experience.

Jetonomy community home page with modern UI and space listings

What You Will Learn

  • Key differences between Jetonomy and bbPress
  • Where Jetonomy excels for growing communities
  • What bbPress still does well

Try a live Jetonomy community before you commit - Wbcom runs its own public support community on Jetonomy at community.wbcomdesigns.com. Browse spaces, read real support threads, and get a feel for the voting, trust-level badges, reply threading, and moderation flow on a production site.

Feature Comparison

Feature bbPress Jetonomy
Data storage WordPress custom post types Custom database tables (20 tables)
Threaded replies 1 level 3 levels
Voting Not built-in (requires add-on) Built-in upvote/downvote
Q&A with accepted answers Not available Built-in (per-space type)
Idea boards Not available Built-in with status workflow
Trust levels Not available 6-level auto-promotion system
Full-text search WordPress default search Full-text search with filters
Real-time interactions Page reload required Real-time updates with no page reload
Moderation queue Basic Flag system + queue + auto-rules (Pro)
Anti-spam Akismet only Akismet + reCAPTCHA + Turnstile
REST API Limited 68+ endpoints (127+ with Pro)
Private messaging Not built-in Built-in (Pro)
Polls Not built-in Built-in (Pro)
Analytics Not available Dashboard with export (Pro)
Migration N/A Built-in bbPress importer

Where Jetonomy Excels

Performance at Scale

bbPress stores every topic and reply as a WordPress post. On sites with 10,000+ topics, this bloats the wp_posts and wp_postmeta tables, slowing down your entire WordPress installation - not just the forum.

Jetonomy uses its own database tables with proper indexes and cursor-based pagination. Your forum can grow to tens of thousands of topics without affecting the rest of your site.

Self-Moderating Community

bbPress relies entirely on WordPress roles. You either trust someone to moderate or you do not. There is no middle ground.

Jetonomy's trust level system automatically promotes members as they contribute. New users start restricted. Active, helpful members gradually earn the ability to edit, moderate, and manage - without any manual role changes.

A trust-level badge shown next to a member's name on a reply

Modern User Experience

bbPress was designed before mobile-first became standard. Jetonomy adapts to any theme's colors automatically, works on mobile out of the box, and offers inline editing, instant voting, and real-time notifications - all without page reloads.

Where bbPress Still Works

bbPress is a good choice if you need a simple, lightweight forum with minimal features and your community will stay small (under 1,000 topics). It has been around since 2011 and has a large ecosystem of third-party add-ons.

If you are already running bbPress and considering a switch, Jetonomy includes a built-in bbPress importer that migrates all your forums, topics, replies, and user data.

What's Next?

How Jetonomy compares to wpForo - two modern forum plugins with different approaches.

Jetonomy Q&A space showing an accepted-answer callout - a feature wpForo's basic question/answer mode does not offer

What You Will Learn

  • Key architectural differences between Jetonomy and wpForo
  • Feature comparison across both plugins
  • Which plugin fits your use case

Feature Comparison

Feature wpForo Jetonomy
Data storage Custom tables Custom tables
Forum layouts 4 built-in layouts 4 space types (forum, Q&A, ideas, feed)
Threaded replies Flat + nested option 3-level threading
Voting Likes only Upvote/downvote with reputation
Trust system Manual user groups Auto-promoting trust levels (0-5)
Q&A mode Basic question/answer Full Q&A with accepted answers
Idea boards Not built-in Built-in with status workflow
Real-time UI Page reload Real-time updates with no page reload
Search Built-in search Full-text search with advanced filters
Anti-spam reCAPTCHA v2 reCAPTCHA v3 + Turnstile (invisible)
Topic management Move topics Move + merge + split
Draft posts Not available Save as draft + scheduling
REST API Limited 68+ endpoints (127+ with Pro)
Theme integration Custom styling Inherits your theme's colors automatically (theme.json design tokens)
Membership gating Built-in groups Adapter system (MemberPress, PMPro, WooCommerce, LearnDash)
Analytics Basic stats Full dashboard with export (Pro)
Migration N/A Built-in wpForo importer

Where Jetonomy Stands Out

WordPress-Native Architecture

wpForo was originally built as a standalone forum that happens to run inside WordPress. Jetonomy was built WordPress-first - it uses the same building blocks WordPress itself uses: real-time updates with no page reload (the WordPress Interactivity API), colors that adapt to your theme automatically (theme.json design tokens), WordPress's own caching and scheduled-task systems, and the WordPress REST API as its foundation.

This means Jetonomy integrates more deeply with WordPress features like block themes, the Site Editor, and the new WordPress Abilities API (the standard way AI assistants and apps can take actions on your site).

Trust Over Roles

wpForo uses manual user groups (similar to WordPress roles). You create groups, assign permissions, and manually move users between groups.

Jetonomy automates this entirely. New members start restricted and earn trust through participation. The community moderates itself as members advance through trust levels. You configure the thresholds once and the system handles promotions automatically.

A trust-level badge shown next to a member's name on a reply

Invisible Anti-Spam

wpForo supports reCAPTCHA v2 - the "I'm not a robot" checkbox that interrupts every user. Jetonomy uses reCAPTCHA v3 and Cloudflare Turnstile, both invisible. Members never see a CAPTCHA, and trusted members (Trust Level 2+) are completely exempt.

Adapter-Based Integrations

wpForo has built-in membership gating but requires wpForo-specific extensions for each membership plugin. Jetonomy uses a universal adapter pattern - MemberPress and PMPro work out of the box in free, and Pro adds WooCommerce, LearnDash, and Restrict Content Pro. Custom adapters can be built for any membership system.

Where wpForo Works Well

wpForo is a mature product with a large installed base. It offers built-in user groups, a forum-specific SEO system, and multiple layout options. If you need a traditional forum with minimal configuration, wpForo is a solid choice.

If you are running wpForo and want to migrate, Jetonomy includes a built-in wpForo importer.

What's Next?

How Jetonomy is built to handle communities of any size - from 10 members to 100,000+.

Space page with sidebar showing topic listings and member activity

What You Will Learn

  • Why custom database tables matter for performance
  • How cursor-based pagination prevents slowdowns
  • Caching strategies that keep page loads fast
  • Real-world performance benchmarks

The Problem with CPT-Based Forums

Most WordPress forum plugins (including bbPress) store every topic and reply as a row in wp_posts, with metadata in wp_postmeta. This approach works for small forums but creates serious problems as you grow:

  • Table bloat: 10,000 topics with 50,000 replies means 60,000 extra rows in wp_posts - slowing down every WordPress query, not just forum queries.
  • Meta queries: Fetching vote counts, view counts, or sticky status requires JOIN operations against wp_postmeta - one of the slowest query patterns in WordPress.
  • No proper indexes: wp_posts was designed for blog posts, not forums. It lacks indexes for common forum queries like "sort by vote score" or "filter by space."

How Jetonomy Solves This

Custom Database Tables

Jetonomy stores all community data in 20 dedicated tables with the wp_jt_ prefix. Each table has purpose-built columns and indexes:

  • Posts table: vote_score, reply_count, view_count, last_reply_at are real columns - not meta. Sorting by popularity is a simple ORDER BY vote_score DESC with an index hit.
  • Replies table: Indexed by post_id and parent_id for fast threaded reply loading.
  • Votes table: A combined index on who voted and what they voted on means "did this user already vote?" is answered with a single fast lookup instead of a scan.

Your WordPress wp_posts table stays clean. Your forum can grow without slowing down the rest of your site.

Cursor-Based Pagination

Traditional pagination uses LIMIT/OFFSET. On page 500 of a 10,000-topic space, the database must scan and skip 9,980 rows before returning 20. This gets slower as your community grows.

Jetonomy uses cursor-based pagination: "give me 20 topics after ID 9980." The database uses the primary key index to jump directly to the right position. Page 500 loads as fast as page 1.

Smart Reply Loading

A topic with 400 replies does not load all 400 at once. Jetonomy loads the first 10 and last 10 replies, with a "load more" gap in between. Members see the opening conversation and the latest activity immediately.

When they click the gap, only the missing replies are fetched in the background - no full page reload.

Built-In Caching

Jetonomy uses WordPress object cache (wp_cache) throughout:

  • Permission checks: Cached for 60 seconds per user per space. A page with 30 replies does not run 30 permission queries.
  • Online status: Cached for 60 seconds. Showing green dots on 30 reply avatars requires 0 extra database queries.
  • Last seen tracking: Rate-limited to 1 database write per user per minute, not per page view.

If you run an object cache plugin (Redis, Memcached), Jetonomy benefits automatically.

Denormalized Counters

Jetonomy does not run COUNT(*) queries to show "42 replies" on a topic card. The reply_count column is updated incrementally when replies are created or deleted. Displaying a list of 20 topics with accurate counts requires zero extra queries.

Real-World Performance

Community Size Page Load (no cache) Page Load (Redis)
100 topics, 500 replies ~120ms ~80ms
1,000 topics, 5,000 replies ~180ms ~100ms
10,000 topics, 50,000 replies ~350ms ~150ms
50,000 topics, 200,000 replies ~500ms ~200ms

These are topic listing page loads (20 topics per page) on a standard VPS (2 CPU, 4GB RAM, SSD). Single topic pages with 30 replies load in similar times.

About these numbers: Measured on Jetonomy 1.5 with PHP 8.2, MySQL 8, and the default theme, on a 2 CPU / 4GB RAM SSD VPS. Real-world times vary with your host, theme, and other active plugins - treat these as a relative guide to how Jetonomy scales, not a guaranteed figure for your site.

Tip: For the best performance on communities with 5,000+ members, enable an object cache plugin like WP Redis or W3 Total Cache with Memcached.

What You Can Do

For Small Communities (under 1,000 members)

No special configuration needed. Jetonomy works well on shared hosting with default settings.

For Medium Communities (1,000-10,000 members)

  • Enable object caching (Redis or Memcached)
  • Set posts per page to 20-30 (default)
  • Use a CDN for static assets

For Large Communities (10,000+ members)

  • Object caching required
  • Consider a VPS or managed WordPress host
  • Monitor with Query Monitor plugin
  • Review trust level thresholds - fewer moderators means fewer permission lookups

What's Next?

How Jetonomy compares to Asgaros Forum - moving up from a lightweight forum to a full discussion platform.

Jetonomy community home page with modern spaces, voting, and trust-level badges

What You Will Learn

  • Key differences between Jetonomy and Asgaros Forum
  • Where Jetonomy excels for growing communities
  • What Asgaros Forum still does well

Try a live Jetonomy community before you commit - Wbcom runs its own public support community on Jetonomy at community.wbcomdesigns.com. Browse spaces, read real support threads, and get a feel for the voting, trust-level badges, reply threading, and moderation flow on a production site.

Feature Comparison

Feature Asgaros Forum Jetonomy
Data storage Custom tables Custom tables (20 tables)
Forum formats Forums + sub-forums 4 space types (forum, Q&A, ideas, feed)
Threaded replies Flat 3-level threading
Voting Not built-in Built-in upvote/downvote with reputation
Q&A with accepted answers Not available Built-in (per-space type)
Idea boards Not available Built-in with status workflow
Trust levels Not available 6-level auto-promotion system (0-5)
Search Built-in search FULLTEXT index with advanced filters
Real-time interactions Page reload required Real-time updates with no page reload
Moderation Approve / unapprove topics Flag system + queue + auto-rules (Pro)
Anti-spam reCAPTCHA / honeypot Akismet + reCAPTCHA v3 + Turnstile (invisible)
Membership gating Not built-in Adapter system (MemberPress, PMPro free; WooCommerce, LMS Pro)
REST API Limited 68+ endpoints (127+ with Pro)
Private messaging Not built-in Built-in (Pro)
Polls Not built-in Built-in (Pro)
Analytics Basic stats Dashboard with export (Pro)
Migration N/A Built-in Asgaros importer

Where Jetonomy Excels

More Than a Forum

Asgaros Forum is a focused, traditional forum: categories, forums, sub-forums, topics, and replies. Jetonomy gives you that same forum format plus three more - Stack Overflow style Q&A with accepted answers, idea boards with a Planned / In Progress / Shipped / Declined workflow, and a social activity feed - all in the same community with one set of members.

Self-Moderating Community

Asgaros relies on you (or assigned moderators) to approve content and watch for problems. Jetonomy's trust level system automatically promotes members as they contribute. New users start restricted; active, helpful members gradually earn the ability to edit, moderate, and manage - without any manual role changes. You set the thresholds once and the community moderates itself.

A trust-level badge shown next to a member's name on a reply

Voting and Reputation

Asgaros has no built-in voting. Jetonomy gives every topic and reply upvote/downvote controls, ranks replies by score, and turns those votes into a reputation score that drives the leaderboard and trust-level promotions.

Performance at Scale

Both plugins use their own database tables instead of WordPress posts, so both avoid the bloat that slows down CPT-based forums. Jetonomy goes further with cursor-based pagination, smart reply loading on long threads, and denormalized counters, so a space with tens of thousands of topics loads as fast as a small one. See the Scalability page for the details.

Where Asgaros Forum Still Works

Asgaros Forum is free, lightweight, and genuinely simple to set up. If you want a basic, traditional forum with no membership gating, no Q&A or idea boards, and a small-to-medium community, Asgaros is a solid, no-cost choice maintained by a dedicated developer.

If you are already running Asgaros and want the additional formats, voting, trust levels, and scalability, Jetonomy includes a built-in Asgaros importer that brings over your forums, sub-forums, topics, and replies.

What's Next?

How Jetonomy compares to other community platforms - FluentCommunity, Discourse, and BuddyBoss forums.

Jetonomy community home page with modern spaces, voting, and trust-level badges

What You Will Learn

  • How Jetonomy positions against FluentCommunity, Discourse, and BuddyBoss forums
  • Where Jetonomy fits best
  • When another platform might suit you better

Jetonomy is built WordPress-first and integrates with several of these tools rather than only competing with them. If you already run FluentCommunity, Jetonomy can coexist with it and pair spaces, and the same is true for BuddyPress / BuddyBoss communities.

Jetonomy vs FluentCommunity

FluentCommunity is a modern WordPress community plugin with courses, feeds, and spaces. It is a strong all-in-one social platform.

Jetonomy is discussion-first. Where FluentCommunity centers on a social feed and learning, Jetonomy centers on structured discussion - traditional forums, Stack Overflow style Q&A with accepted answers, and idea boards with a status workflow - on top of the same custom-table performance model. Jetonomy also adds an auto-promoting trust-level system (0-5) that moderates the community for you, built-in upvote/downvote voting with reputation, and a built-in importer path from bbPress, wpForo, and Asgaros.

If you want courses plus a social feed as the heart of your site, FluentCommunity is a natural fit. If you want a fast, structured discussion platform - forum + Q&A + ideas - that can also coexist with FluentCommunity, choose Jetonomy. The two can run side by side and share members through the FluentCommunity integration.

Jetonomy vs Discourse

Discourse is the dominant standalone (non-WordPress) discussion platform. It is powerful, but it runs as a separate application you host and maintain apart from WordPress, with its own user accounts, hosting requirements, and login.

Jetonomy gives you a comparable modern discussion experience - voting, trust levels, real-time updates, full-text search - but inside WordPress. Your members use their existing WordPress accounts, your community lives on your domain, it inherits your theme's colors automatically, and you manage it from wp-admin. There is no second server to run, no SSO bridge to maintain, and no separate billing.

Choose Discourse if you specifically want a hosted, standalone forum decoupled from WordPress. Choose Jetonomy if you want that modern experience native to your WordPress site.

Jetonomy vs BuddyBoss Forums

BuddyBoss is a social-network platform for WordPress, with member profiles, groups, and activity feeds; its forum component is built on bbPress.

Because BuddyBoss forums run on bbPress, they inherit bbPress's CPT-based storage and feature set - one level of threaded replies, no built-in voting, no Q&A or idea boards, and no trust-level automation. Jetonomy replaces that forum layer with custom-table storage, 3-level threading, voting and reputation, four space types, and auto-promoting trust levels, while still coexisting with BuddyPress / BuddyBoss for profiles, groups, and activity.

If your community is primarily a social network and the forum is secondary, BuddyBoss covers the social side well - and Jetonomy can supply the discussion layer alongside it.

Where Jetonomy Fits Best

Jetonomy is the right choice when discussion is the core of your community and you want it native to WordPress: multiple discussion formats in one place, real database performance at scale, voting and trust-level automation, and the option to coexist with the social and learning platforms above rather than replace them.

What's Next?

Developer Guide

REST API, hooks, template overrides, and extending Jetonomy.

The Developer Guide is the technical reference for extending, embedding, and integrating Jetonomy. Every page here is written for developers - if you are configuring the community from wp-admin, start with the Getting Started and Admin Settings sections instead.

Use this page as a map: each guide is grouped by what you are trying to do, so you can jump straight to the right reference no matter where you landed.

Extend

Hook into Jetonomy's data and behaviour, or swap out a back-end service.

  • Hooks Reference - every jetonomy_* action and filter, with the arguments each one passes.
  • Adapter System - the membership, search, real-time, and email adapter interfaces you implement to plug in your own service.
  • Template Overrides - copy any community template into your theme's jetonomy/ directory to change its layout.

Embed

Surface community content on any page, post, sidebar, or page-builder canvas.

  • Shortcodes, Widgets, and Blocks - the eight shortcodes, four classic widgets, and eight Gutenberg blocks, with attributes and block/shortcode parity notes.

Integrate

Read and write community data from another application, agent, or platform.

  • REST API Reference - the full jetonomy/v1 endpoint listing with methods, payloads, responses, and permission contracts.
  • Abilities API - expose the community to AI agents and automation tools through the WordPress Abilities API.
  • FluentCommunity Integration - developer reference for the FluentCommunity coexistence layer.
  • BuddyPress Integration - developer reference for the BuddyPress Groups coexistence layer, including how to disable leave-sync.

Front-end toolkit

JavaScript and access-control building blocks for custom front-end code.

  • Modal Toolkit - the jetonomyConfirm / jetonomyAlert / jetonomyPrompt globals that replace native browser dialogs.
  • Visibility and Access Matrix - the Jetonomy\Visibility helper that enforces the public/private community toggle, plus the access-matrix regression runner.

Operations

Drive and test the community from the command line.

  • WP-CLI Commands - the full wp jetonomy and wp jetonomy-pro command surface, plus the qa-actions smoke suite.

Jetonomy exposes a full REST API under the jetonomy/v1 namespace: 48+ endpoints in the free plugin, plus 40+ additional endpoints when Jetonomy Pro is active (90+ total). All endpoints return JSON and integrate with WordPress nonce authentication via the wp_rest nonce.

Base URL: https://example.com/wp-json/jetonomy/v1/

Authentication

Public endpoints (marked Public below) return data without authentication. Write operations and moderation endpoints require a logged-in user and the X-WP-Nonce header:

const nonce = window.wpApiSettings?.nonce
           ?? jetonomyState?.nonce;  // Injected via wp_interactivity_state()

fetch( '/wp-json/jetonomy/v1/spaces/1/posts', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-WP-Nonce': nonce,
    },
    body: JSON.stringify({ title: 'My topic', content: '<p>Hello</p>' }),
} );

The Interactivity API store exposes apiBase and _nonce in the jetonomy namespace so the bundled frontend needs no extra configuration.


Categories

Manage the top-level taxonomy that groups Spaces.

Method Route Auth Description
GET /categories Public List all categories
POST /categories manage_options Create a category
GET /categories/{id} Public Get a single category
PATCH /categories/{id} manage_options Update a category
DELETE /categories/{id} manage_options Delete a category

GET /categories - example

const res  = await fetch( '/wp-json/jetonomy/v1/categories' );
const data = await res.json();
// data.data → array of category objects
// { id, name, slug, description, position, space_count }

Spaces

Spaces are the primary containers for posts (equivalent to forums or boards).

Method Route Auth Description
GET /spaces Public List spaces (paginated)
POST /spaces manage_options Create a space
GET /spaces/{id} Public Get a single space
PATCH /spaces/{id} Moderator / Admin Update space settings
DELETE /spaces/{id} manage_options Delete a space
GET /spaces/{id}/members Public / Members only if private List space members
POST /spaces/{id}/members Logged in Join a space
PATCH /spaces/{id}/members/{user_id} Moderator / Admin Change a member's role
DELETE /spaces/{id}/members/{user_id} Moderator / Admin Remove a member
POST /spaces/{id}/invite Moderator / Admin Generate an invite link
GET /invite/{token} Public Resolve an invite token
GET /spaces/{id}/privileged-members Public List admins and moderators of a space

GET /spaces - parameters

Parameter Type Default Description
page int 1 Page number
per_page int 20 Results per page (max 100)
category_id int - Filter by category
search string - Search by title
orderby string position position, title, member_count, post_count
const res  = await fetch( '/wp-json/jetonomy/v1/spaces?per_page=10&category_id=3' );
const data = await res.json();
// data.data → array of space objects
// data.meta → { total, pages, page }

Posts

Posts are individual discussion threads (topics) inside a Space.

Method Route Auth Description
GET /spaces/{space_id}/posts Public List posts in a space
POST /spaces/{space_id}/posts Logged in Create a post
GET /posts/{id} Public Get a single post
PATCH /posts/{id} Author / Moderator Update a post
DELETE /posts/{id} Author / Moderator Delete a post
POST /posts/{id}/close Moderator / Admin Toggle closed status
POST /posts/{id}/pin Moderator / Admin Toggle pinned status
POST /posts/{id}/move Moderator / Admin Move to another space
POST /posts/{id}/merge Moderator / Admin Merge into another post
POST /posts/{id}/idea-status Space Moderator Set the roadmap status on an idea-type post (planned, in_progress, shipped, declined)
GET /posts/drafts Logged in List current user's drafts
GET /link-preview Public Fetch OG metadata for a URL

GET /spaces/{space_id}/posts - parameters

Parameter Type Default Description
page int 1 Page number
per_page int 20 Max 100
sort string latest latest, oldest, votes, replies
type string - Filter by post type (discussion, question, idea)
tag string - Filter by tag slug
status string publish publish, draft (author/mod only)

POST /spaces/{space_id}/posts - body

await fetch( `/wp-json/jetonomy/v1/spaces/${spaceId}/posts`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce },
    body: JSON.stringify({
        title:   'How do I configure caching?',
        content: '<p>Looking for recommendations...</p>',
        type:    'question',     // discussion | question | idea
        tags:    ['caching', 'performance'],
        status:  'publish',      // or 'draft'
    }),
} );

POST /posts/{id}/move - body

{ target_space_id: 42 }

POST /posts/{id}/merge - body

{ target_post_id: 17 }

GET /link-preview - parameters

Parameter Type Required Description
url string Yes URL to fetch OG data for

Response: { title, description, image, domain }


Replies

Replies are threaded responses to a Post.

Method Route Auth Description
GET /posts/{post_id}/replies Public List replies on a post
POST /posts/{post_id}/replies Logged in Create a reply
GET /replies/{id} Public Get a single reply
PATCH /replies/{id} Author / Moderator Update a reply
DELETE /replies/{id} Author / Moderator Delete a reply
POST /replies/{id}/accept Post author / Moderator Accept as answer
POST /replies/{id}/split Moderator / Admin Split this reply into a new standalone post

GET /posts/{post_id}/replies - parameters

Parameter Type Default Description
page int 1 Page number
per_page int 30 Max 100
sort string oldest oldest, newest, best

POST /replies/{id}/accept

Marks this reply as the accepted answer. Only the original post author or a moderator can call this. Fires the jetonomy_reply_accepted action hook and awards +15 reputation to the reply author.

await fetch( `/wp-json/jetonomy/v1/replies/${replyId}/accept`, {
    method: 'POST',
    headers: { 'X-WP-Nonce': nonce },
} );

Votes

Votes record up/down signals on Posts and Replies. Calling the endpoint again with the same direction removes the vote (toggle).

Method Route Auth Description
POST /posts/{id}/vote Logged in Cast or toggle a post vote
DELETE /posts/{id}/vote Logged in Remove vote from a post
POST /replies/{id}/vote Logged in Cast or toggle a reply vote
DELETE /replies/{id}/vote Logged in Remove vote from a reply

Body for both vote endpoints

{ direction: 'up' }  // or 'down'

Response includes vote_score (current net score) and user_vote (the caller's current vote direction or null).


Full-text search across Posts, Replies, Spaces, and Tags. Uses MySQL FULLTEXT with Boolean Mode by default. Swap to a custom search adapter (Meilisearch, Algolia, etc.) via the Adapter System. See 05-adapters.md.

Method Route Auth Description
GET /search Public Search across content types

Parameters

Parameter Type Required Default Description
q string Yes - Query string (min 2 chars)
type string - post post, reply, space, tag, all
space_id int - - Restrict to a specific space
date_from string - - ISO date YYYY-MM-DD
date_to string - - ISO date YYYY-MM-DD
author_id int - - Filter by author's WP user ID
tag string - - Filter by tag slug
sort string - relevance relevance, newest, votes

Using type=all returns a grouped response with posts, spaces, and tags keys.

const params = new URLSearchParams({
    q:        'caching strategies',
    type:     'post',
    space_id: 5,
    sort:     'votes',
} );

const res  = await fetch( `/wp-json/jetonomy/v1/search?${params}` );
const data = await res.json();
// data.data → array of matching post objects
// data.meta → { total, has_more }

Tags

Method Route Auth Description
GET /tags Public List all global tags

Removed in 1.5.0: the GET /space-tags route. It read tables that were never wired to any feature; tags have always been global. Existing integrations calling it receive a 404 and should switch to GET /tags.


Notifications

Method Route Auth Description
GET /notifications Logged in List notifications for current user
GET /notifications/unread-count Logged in Get unread count (cached 30s)
POST /notifications/mark-all-read Logged in Mark all notifications read
PATCH /notifications/{id} Logged in Mark a single notification read
DELETE /notifications/{id} Logged in (own only) Delete a single notification
POST /notifications/bulk Logged in (own only) Bulk mark-as-read or delete a batch of notifications

GET /notifications - parameters

Parameter Type Default Description
per_page int 20 Max 50
unread_only bool false Return only unread notifications

Subscriptions

Subscriptions track which Spaces or Posts a user follows for new-content notifications.

Method Route Auth Description
GET /subscriptions Logged in List current user's subscriptions
POST /subscriptions Logged in Create a subscription to a space or post
DELETE /subscriptions/{id} Logged in Remove a subscription

Moderation

All moderation endpoints require the jetonomy_moderate capability (granted to admins, editors, and users with Moderator role by default).

Method Route Auth Description
GET /moderation/queue Moderator List items pending review
POST /moderation/approve/{type}/{id} Moderator Approve a flagged item
POST /moderation/spam/{type}/{id} Moderator Mark as spam
POST /moderation/trash/{type}/{id} Moderator Send to trash
POST /moderation/bulk (new in 1.4.1) Moderator Approve / spam / trash many posts in one call
POST /flags Logged in Submit a flag on a post or reply
GET /posts/{id}/flags (new in 1.4.1) Moderator The flags raised against a specific post
GET /moderation/flags Moderator List all open flags
POST /moderation/flags/{id}/resolve Moderator Resolve a flag (valid or dismissed)
POST /moderation/ban Moderator Ban a user (global ban, space ban, or silence)
DELETE /moderation/ban/{id} Moderator Remove a ban
GET /spaces/{id}/moderation/flags Space Admin List flags filed within a specific space
POST /spaces/{id}/moderation/flags/{flag_id}/resolve Space Admin Resolve a flag within a specific space
POST /spaces/{id}/moderation/{action}/{type}/{obj_id} Space Admin Moderate content in a specific space (action: approve, spam, or trash; type: post or reply)

Resolving a flag as valid applies the full resolution contract on every surface (1.5.0 fix): the flagged content is trashed, any other pending flags on the same object are cleared with it, the reporter earns +5 reputation, and the jetonomy_flag_resolved action fires (so Pro webhooks see the event). Earlier versions skipped these side effects when the flag was resolved through this global REST route specifically.

POST /moderation/bulk - body

{
    action:     'approve',  // approve | spam | trash
    object_type: 'post',    // or 'reply'
    object_ids: [101, 104, 109, 117]
}

Returns per-item results so partial failures are visible:

{
    succeeded: [101, 104, 117],
    failed:    [{ id: 109, reason: 'already_spam' }]
}

{type} in approve/spam/trash routes is either post or reply.

POST /flags - body

{
    object_type: 'post',   // or 'reply'
    object_id:   42,
    reason:      'spam',   // spam | offensive | off_topic | harassment | other
}

POST /moderation/ban - body

{
    user_id:  123,
    reason:   'Repeated spam',
    duration: 7,           // days - omit for permanent ban
}

Leaderboards

Method Route Auth Description
GET /leaderboards Public Get top contributors

Parameters

Parameter Type Default Description
period string week week, month, all-time
per_page int 10 Max 50
space_id int - Restrict to a space

Users

Method Route Auth Description
GET /users/me Logged in Get the current user's profile
PATCH /users/me Logged in (own account) Update the current user's profile
GET /users/{id} Public Get a user's public profile
PATCH /users/{id} Owner / Admin Update a user profile
GET /users/by-login/{login} Public Look up a user by login slug
GET /users/{id}/posts Public List posts by this user
GET /users/suggest Public Typeahead - suggest users by name or login prefix

PATCH /users/{id} - updatable fields

{
    bio:         'Forum moderator and PHP developer.',
    website:     'https://example.com',
    location:    'Berlin',
    twitter:     'janedoe',
    github:      'janedoe',
    avatar_url:  'https://example.com/avatar.jpg',
}

Updates (Polling)

The Updates endpoint powers the "N new replies" banner in single-post view. It is polled periodically by the Interactivity API store.

Method Route Auth Description
GET /updates Public Check for new activity since a timestamp

Parameters

Parameter Type Description
since string ISO 8601 timestamp. Returns items created after this time.
post_id int If provided, returns new reply count for that post

Bookmarks

Method Route Auth Description
GET /bookmarks Logged in List the current user's bookmarked posts
POST /bookmarks Logged in Toggle a bookmark on a post (adds if absent, removes if present)
DELETE /bookmarks/{post_id} Logged in Remove a specific bookmark by post ID

Media

Method Route Auth Description
POST /media Logged in (jetonomy_upload_media) Upload an image, video, or file attachment

oEmbed

Method Route Auth Description
GET /oembed Public oEmbed endpoint for forum posts - returns embed metadata for the given post URL

Authentication and Registration

These endpoints are unauthenticated and rate-limited. They are used by the headless frontend or when the native WordPress login form is not in use.

Method Route Auth Description
POST /auth/login Public (rate limited) Log in and receive an authentication cookie
GET /auth/nonce (new in 1.5.0) Logged in (cookie) Mint a fresh REST nonce for the current session
POST /auth/register Public (rate limited) Register a new user account
POST /auth/lost-password Public (rate limited) Request a password reset email
GET /auth/verify-email Public Verify an email confirmation token
POST /auth/resend-verification Public (rate limited) Resend the email verification message

GET /auth/nonce backs the frontend's automatic session recovery: when a long-lived tab's REST nonce expires (403 rest_cookie_invalid_nonce), the bundled restFetch client calls this endpoint, receives a fresh nonce minted against the still-valid login cookie, and retries the original request once - so members never lose a reply to "Cookie nonce is invalid". The endpoint re-validates the login cookie itself and sends no-cache headers; it never mints a nonce for an anonymous session.


Admin

These endpoints require the manage_options capability (administrators only).

Method Route Auth Description
POST /admin/recount Admin (manage_options) Rebuild all denormalized counters (reply counts, vote scores, post counts)
POST /admin/users/trust-level Admin (manage_options) Manually set a user's trust level

Pro Endpoints

The following endpoints are available only when Jetonomy Pro is active and the relevant extension is enabled.

Private Messaging (private-messaging extension)

Method Route Auth Description
GET /conversations Logged in List conversations
POST /conversations Trust Level 1+ Start a new conversation
GET /conversations/{id} Participant Get conversation details
PATCH /conversations/{id} Participant Update conversation settings (is_muted boolean); see also the dedicated POST /conversations/{id}/mute
GET /conversations/{id}/messages Participant List messages (paginated)
POST /conversations/{id}/messages Participant + TL 1+ Send a message
POST /conversations/{id}/mute Participant Mute/unmute the conversation (muted boolean)
POST /conversations/{id}/archive Participant Archive/unarchive the conversation for the caller (archived boolean)
POST /conversations/{id}/leave Participant Leave a group conversation
POST /conversations/{id}/block Participant Block/unblock the other participant (blocked boolean)
GET /conversations/unread-count Logged in Unread message count (30s cache)
GET /messaging/recipient-suggestions Logged in Typeahead for the DM composer, scoped to shared-space members (q required, 3-64 chars)

POST /conversations - body

{
    participants: [4, 17],          // WP user IDs
    title:        'Project sync',   // Optional for group conversations
    message:      'Hey, quick question...',
}

Analytics (analytics extension)

All analytics endpoints require the jetonomy_view_analytics capability.

Method Route Description
GET /analytics/overview Daily series + period comparison
GET /analytics/top-spaces Ranked by period activity
GET /analytics/top-contributors Ranked by posts + replies
GET /analytics/engagement Engagement rate, avg reply time, unanswered %
GET /analytics/moderation Flags, bans, spam actions
GET /analytics/export CSV download

Analytics parameters (all endpoints)

Parameter Type Default Description
range string 30d 7d, 30d, 90d, custom
start string - ISO date (required when range=custom)
end string - ISO date (required when range=custom)
const res  = await fetch(
    '/wp-json/jetonomy/v1/analytics/overview?range=30d',
    { headers: { 'X-WP-Nonce': nonce } }
);
const data = await res.json();

Polls (polls extension)

Method Route Auth Description
GET /posts/{post_id}/poll Public Get a post's poll and current results
POST /posts/{post_id}/poll Logged in (can post) Create a poll on a post
POST /polls/{id}/vote Logged in Cast a vote on a poll option
DELETE /polls/{id}/vote Logged in Retract a vote
PATCH /polls/{id} Author / Moderator Update or close a poll

Reactions (reactions extension)

Method Route Auth Description
GET /posts/{id}/reactions Public List reactions on a post
POST /posts/{id}/reactions Logged in Toggle an emoji reaction on a post
GET /replies/{id}/reactions Public List reactions on a reply
POST /replies/{id}/reactions Logged in Toggle an emoji reaction on a reply

Custom Badges (custom-badges extension)

Method Route Auth Description
GET /badges Logged in List all defined badges
POST /badges Admin (manage_options) Create a new badge definition
PATCH /badges/{id} Admin (manage_options) Update a badge definition
DELETE /badges/{id} Admin (manage_options) Delete a badge definition
POST /users/{user_id}/badges Admin (manage_options) Manually award a badge to a user

Custom Fields (custom-fields extension)

Method Route Auth Description
GET /custom-fields Logged in List all custom field definitions
POST /custom-fields Admin (manage_options) Create a custom field definition
PATCH /custom-fields/{id} Admin (manage_options) Update a custom field definition
DELETE /custom-fields/{id} Admin (manage_options) Delete a custom field definition
POST /custom-field-values Logged in Set a custom field value on a post, reply, or user profile

Email Digest (email-digest extension)

Method Route Auth Description
GET /users/me/digest-preferences Logged in Get the current user's digest frequency and topic preferences
PATCH /users/me/digest-preferences Logged in Update digest frequency and topics
POST /admin/digest/test manage_options Send a test digest email
GET /admin/digest/stats manage_options Digest delivery statistics

Webhooks (webhooks extension)

Method Route Auth Description
GET /webhooks Admin (manage_options) List all registered webhook endpoints
POST /webhooks Admin (manage_options) Register a new webhook endpoint
DELETE /webhooks/{id} Admin (manage_options) Delete a webhook endpoint

White Label (white-label extension)

Method Route Auth Description
GET /settings/white-label Admin (manage_options) Get current white-label settings (logo, colors, footer text)
PATCH /settings/white-label Admin (manage_options) Save white-label settings

AI (ai extension)

All AI endpoints require the manage_options capability.

Method Route Auth Description
GET /ai/providers Admin List configured AI providers and their status
POST /ai/suggestions Admin Generate AI-powered content suggestions
POST /ai/spam-detection Admin Run AI spam detection on a piece of content
GET /ai/usage Admin Get per-request AI usage statistics
GET /ai/usage/summary Admin Get monthly usage summary grouped by provider

Web Push (web-push extension)

Method Route Auth Description
POST /push/subscribe Logged in Register a browser push subscription
DELETE /push/subscribe Logged in Remove a push subscription
GET /push/vapid-key Logged in Get the public VAPID key needed to subscribe
GET /push/service-worker.js Public Serves the push service-worker script

SEO Pro (seo-pro extension)

Method Route Auth Description
GET /spaces/{id}/seo Space Admin Get SEO metadata for a space (title, description, OG image)
POST /spaces/{id}/seo Space Admin Save SEO metadata for a space

Reply by Email (reply-by-email extension)

Method Route Auth Description
POST /reply-by-email/process Shared secret (webhook) Inbound webhook endpoint for processing email replies - authenticated via a shared secret header, not a user session

Advanced Moderation (advanced-moderation extension)

All advanced moderation endpoints require the manage_options capability.

Method Route Auth Description
GET /moderation/rules Admin List all auto-moderation rules
POST /moderation/rules Admin Create a new auto-moderation rule
PATCH /moderation/rules/{id} Admin Update an auto-moderation rule
DELETE /moderation/rules/{id} Admin Delete an auto-moderation rule
GET /moderation/rules/{id}/stats Admin Get trigger statistics for a specific rule

Analytics - additional endpoint (analytics extension)

Method Route Auth Description
GET /analytics/diff-report Admin (manage_options) Per-metric drift report comparing the direct-query path against the event-driven aggregate path; returns from_query, from_events, drift_pct, and within_tolerance for each metric

Community Announcements (site-announcements extension)

Namespace: these routes live under jetonomy-pro/v1, not jetonomy/v1.

All routes require the manage_options or jetonomy_manage_spaces capability (administrators by default).

Method Route Description
GET /site-announcements List the currently pinned (announced) posts
POST /site-announcements/{id} Pin a post site-wide (capped at 5; returns 400 past the cap)
DELETE /site-announcements/{id} Remove a post from the announcements
// Pin post 395 to the whole community
await fetch( '/wp-json/jetonomy-pro/v1/site-announcements/395', {
    method:  'POST',
    headers: { 'X-WP-Nonce': nonce },
} );

This is distinct from the free space-level pin (POST /posts/{id}/pin), which only stickies a topic within its own space.


Error Responses

All errors follow the standard WP REST API format:

{
  "code":    "rest_forbidden",
  "message": "You are not allowed to do this.",
  "data":    { "status": 403 }
}

Common error codes:

Code HTTP Meaning
rest_forbidden 403 Missing capability or nonce
rest_not_found 404 Resource does not exist
validation_error 422 Invalid or missing parameters
rate_limited 429 Too many requests from this user

What's Next?

Jetonomy fires over 140 hooks in the free plugin, plus another two dozen in Jetonomy Pro. This page documents the most useful ones; every hook follows the jetonomy_ prefix convention. Use them in your theme's functions.php, a site-specific mu-plugin, or a companion plugin.

Hook naming prefix: jetonomy_ Namespace: Jetonomy\


Content Hooks

These hooks fire around the full lifecycle of posts and replies.


jetonomy_after_create_post

Fires immediately after a new post is saved successfully via REST.

Parameters

Parameter Type Description
$post_id int ID of the newly created post
$space_id int ID of the space the post was created in

Source: includes/api/class-posts-controller.php, includes/class-abilities.php

add_action( 'jetonomy_after_create_post', function( int $post_id, int $space_id ) {
    // Push an event to your analytics pipeline.
    my_analytics_track( 'forum_post_created', [
        'post_id'  => $post_id,
        'space_id' => $space_id,
        'user_id'  => get_current_user_id(),
    ] );
}, 10, 2 );

For a hook that fires on every insert path (REST, admin, CLI, abilities, import) see jetonomy_post_created below.


jetonomy_post_created

Fires from the Post model right after a row is inserted, so it covers every insert path - REST, admin AJAX, WP-CLI, Abilities, imports. Use this when you want to score the creation event itself regardless of how it was triggered.

Fires for every status. Listeners that only care about published posts should inspect $context['status'].

Parameters

Parameter Type Description
$post_id int Inserted post ID
$space_id int Parent space ID (0 if unset)
$user_id int Author user ID (0 if unset)
$context array The inserted column data (status, post_type, idea_status, slug, etc.)

Source: includes/models/class-post.php

// WB Gamification example: award points the moment a post lands, not when it gets upvoted.
add_action( 'jetonomy_post_created', function( int $post_id, int $space_id, int $user_id, array $context ) {
    if ( $user_id <= 0 || 'publish' !== ( $context['status'] ?? 'publish' ) ) {
        return;
    }
    wb_gam_award_points( $user_id, 'forum_post_created', [
        'post_id'  => $post_id,
        'space_id' => $space_id,
    ] );
}, 10, 4 );

jetonomy_after_create_reply

Fires immediately after a new reply is saved successfully via REST. The built-in Notifier also listens to this hook to dispatch reply notifications.

Parameters

Parameter Type Description
$reply_id int ID of the newly created reply
$post_id int ID of the post being replied to

Source: includes/api/class-replies-controller.php, includes/class-abilities.php

add_action( 'jetonomy_after_create_reply', function( int $reply_id, int $post_id ) {
    // Award XP in your gamification plugin.
    my_gamification_award_xp( get_current_user_id(), 5, 'reply_created' );
}, 10, 2 );

For a hook that fires on every insert path see jetonomy_reply_created below.


jetonomy_reply_created

Mirrors jetonomy_post_created for the reply path. Fires from the Reply model so every insert path (REST, admin AJAX, CLI, Abilities, imports) is covered.

Parameters

Parameter Type Description
$reply_id int Inserted reply ID
$post_id int Parent post ID (0 if unset)
$user_id int Author user ID (0 if unset)
$context array The inserted column data (status, parent_id, content, etc.)

Source: includes/models/class-reply.php

add_action( 'jetonomy_reply_created', function( int $reply_id, int $post_id, int $user_id, array $context ) {
    if ( $user_id <= 0 || 'publish' !== ( $context['status'] ?? 'publish' ) ) {
        return;
    }
    wb_gam_award_points( $user_id, 'forum_reply_created', [
        'reply_id' => $reply_id,
        'post_id'  => $post_id,
    ] );
}, 10, 4 );

jetonomy_post_updated

Fires after a post is updated.

Parameters

Parameter Type Description
$post_id int ID of the updated post

Source: includes/api/class-posts-controller.php

add_action( 'jetonomy_post_updated', function( int $post_id ) {
    // Bust an external cache when a post changes.
    my_cdn_purge( 'post', $post_id );
} );

jetonomy_post_deleted

Fires after a post is permanently deleted (not trashed).

Parameters

Parameter Type Description
$post_id int ID of the deleted post

Source: includes/api/class-posts-controller.php


jetonomy_reply_updated

Fires after a reply is updated.

Parameters

Parameter Type Description
$reply_id int ID of the updated reply

Source: includes/api/class-replies-controller.php


jetonomy_reply_deleted

Fires after a reply is permanently deleted.

Parameters

Parameter Type Description
$reply_id int ID of the deleted reply

Source: includes/api/class-replies-controller.php


jetonomy_reply_accepted

Fires after a reply is marked as the accepted answer. The free plugin uses this to award +15 reputation to the reply author.

Parameters

Parameter Type Description
$reply_id int ID of the accepted reply
$post_id int ID of the parent post

Source: includes/api/class-replies-controller.php

add_action( 'jetonomy_reply_accepted', function( int $reply_id, int $post_id ) {
    // Grant a badge for having a reply accepted.
    my_badges_award( get_current_user_id(), 'answer-accepted' );
}, 10, 2 );

jetonomy_post_publish_transition

New in 1.5.0. Fires whenever a post enters or leaves the publish status - on publish-at-creation, on approval from the pending queue, on trashing a published post, and on restore. Consumers that maintain published-content counters subscribe here instead of guessing from create/update events; Jetonomy Pro's analytics aggregator uses it to keep daily totals accurate when content is trashed or approved later.

Parameters

Parameter Type Description
$post_id int ID of the post
$delta int +1 when the post became published, -1 when it left published
$created_at string The post's original created_at datetime - attribute the delta to this date, not today

Source: includes/models/class-post.php

add_action( 'jetonomy_post_publish_transition', function( int $post_id, int $delta, string $created_at ) {
    // Keep an external "published posts per day" metric honest.
    my_metrics_adjust( 'posts_published', $delta, substr( $created_at, 0, 10 ) );
}, 10, 3 );

jetonomy_space_feed_posts

New in 1.5.0. Filters the posts included in a space RSS feed (/community/s/{slug}/feed/) before rendering - newest first, capped at 20.

Parameter Type Description
$posts array Post rows to render as feed items
$space object The space the feed belongs to

Source: includes/class-feed.php


jetonomy_reply_publish_transition

New in 1.5.0. The reply mirror of jetonomy_post_publish_transition - same parameters and semantics with a reply ID.

Source: includes/models/class-reply.php


Voting

jetonomy_after_vote

Fires after a vote is cast or changed on a post or reply via REST. Use this for receiver-side analytics; for voter-side gamification see jetonomy_vote_cast / jetonomy_vote_retracted below.

Parameters

Parameter Type Description
$object_type string 'post' or 'reply'
$object_id int ID of the voted-on item
$direction string 'up', 'down', or 'none' (vote removed)
$user_id int The voting user's WP ID

Source: includes/api/class-votes-controller.php, includes/class-abilities.php

add_action( 'jetonomy_after_vote', function( string $type, int $id, string $direction, int $user_id ) {
    if ( 'up' === $direction && 'post' === $type ) {
        // Award XP to the post author for receiving an upvote.
        $post = \Jetonomy\Models\Post::find( $id );
        if ( $post ) {
            my_xp_award( (int) $post->author_id, 2, 'post_upvoted' );
        }
    }
}, 10, 4 );

jetonomy_vote_cast

Fires when a voter casts a new vote (or flips an existing one). Used by gamification to reward the voter directly. Reputation handles the receiver; this hook is the missing voter-side signal.

When a voter flips from upvote to downvote (or vice versa) a jetonomy_vote_retracted fires for the old value, then jetonomy_vote_cast fires for the new value.

Parameters

Parameter Type Description
$vote_type int Raw vote value the voter chose (1 for upvote, -1 for downvote)
$object_type string 'post' or 'reply'
$object_id int Target object ID
$voter_id int Voting user ID

Source: includes/models/class-vote.php

// "Voted 10x this week" challenge.
add_action( 'jetonomy_vote_cast', function( int $vote_type, string $object_type, int $object_id, int $voter_id ) {
    wb_gam_award_points( $voter_id, 'forum_vote_cast', [
        'vote_type'   => $vote_type,
        'object_type' => $object_type,
        'object_id'   => $object_id,
    ] );
}, 10, 4 );

jetonomy_vote_retracted

Fires when a voter retracts an existing vote (clicks the same arrow again or flips to the opposite arrow).

Parameters

Parameter Type Description
$vote_type int Raw value of the retracted vote (1 or -1)
$object_type string 'post' or 'reply'
$object_id int Target object ID
$voter_id int Voting user ID

Source: includes/models/class-vote.php

add_action( 'jetonomy_vote_retracted', function( int $vote_type, string $object_type, int $object_id, int $voter_id ) {
    wb_gam_revoke_points( $voter_id, 'forum_vote_cast', [
        'object_type' => $object_type,
        'object_id'   => $object_id,
    ] );
}, 10, 4 );

Ideas / Roadmap

jetonomy_idea_status_changed

Fires after an idea's roadmap status changes (e.g. plannedin_progressshipped). Use this to reward the post author on every transition, not just planned.

Parameters

Parameter Type Description
$post_id int Post ID
$new_status string New idea_status value
$old_status string Previous value (empty if unset)
$actor_id int Moderator who changed it
$author_id int Original post author (0 if unset) - added so listeners can reward the author without a second lookup

Source: includes/api/class-posts-controller.php

add_action( 'jetonomy_idea_status_changed', function( int $post_id, string $new_status, string $old_status, int $actor_id, int $author_id ) {
    if ( $author_id <= 0 || $author_id === $actor_id ) {
        return; // Author can't farm their own status changes.
    }
    if ( 'shipped' === $new_status ) {
        wb_gam_award_points( $author_id, 'idea_shipped', [ 'post_id' => $post_id ] );
    }
}, 10, 5 );

Moderation

jetonomy_content_moderated

Fires when a moderator takes an action on a post or reply: approve, spam, or trash.

Parameters

Parameter Type Description
$action string 'approve', 'spam', or 'trash'
$object_type string 'post' or 'reply'
$object_id int ID of the moderated item
$moderator_id int WP user ID of the moderator

Source: includes/api/class-moderation-controller.php, includes/admin/class-admin.php

add_action( 'jetonomy_content_moderated', function( string $action, string $type, int $id, int $mod_id ) {
    if ( 'spam' === $action ) {
        my_spam_log( $type, $id, $mod_id );
    }
}, 10, 4 );

Trust & Reputation

jetonomy_trust_level_pre_change

Filter (not action). Lets you intercept an automatic trust-level promotion before it is written - to veto promotions for sandboxed users, fast-track a cohort during onboarding, or apply per-tenant ladder rules.

Only fires on automatic promotion paths: the daily cron evaluator and wp jetonomy trust-evaluate. Manual admin/CLI overrides bypass this filter on purpose so admins can always force-set a level.

Returning the user's current level short-circuits the write (no DB update, no jetonomy_trust_level_changed action).

Parameters

Parameter Type Description
$new_level int Level the evaluator chose (the proposed level)
$user_id int Target user ID
$stats array Stats fed to the evaluator: post_count, days_active, reputation, replies_received

Returns: int - the level to actually write.

Source: includes/class-cron.php, includes/class-cli.php

// WB Gamification example: veto auto-promotion for users in the sandbox.
add_filter( 'jetonomy_trust_level_pre_change', function( int $new_level, int $user_id, array $stats ): int {
    if ( get_user_meta( $user_id, 'wb_gam_sandboxed', true ) ) {
        $current = (int) \Jetonomy\Models\UserProfile::find( $user_id )->trust_level;
        return $current; // short-circuit the write.
    }
    return $new_level;
}, 10, 3 );

jetonomy_trust_level_changed

Fires when a user's trust level is recalculated and changes. Runs from the daily cron job and the wp jetonomy recalculate-trust WP-CLI command.

Parameters

Parameter Type Description
$user_id int WP user ID
$old_level int Previous trust level (0-5)
$new_level int New trust level (0-5)

Source: includes/class-cron.php, includes/class-cli.php

add_action( 'jetonomy_trust_level_changed', function( int $user_id, int $old, int $new ) {
    if ( $new > $old ) {
        // Grant a WP capability when a user reaches Trust Level 3.
        if ( 3 === $new ) {
            $user = get_user_by( 'ID', $user_id );
            $user->add_cap( 'my_plugin_advanced_features' );
        }
    }
}, 10, 3 );

jetonomy_reputation_changed

Fires whenever a user's reputation score changes.

Parameters

Parameter Type Description
$user_id int WP user ID
$action string Action slug that triggered the change (e.g. 'post_upvoted', 'reply_accepted'). Revocations append _revoked (e.g. 'post_upvoted_revoked').
$delta int Points added (positive) or removed (negative)
$context array Optional context payload supplied by Reputation::award_custom() (e.g. [ 'badge_id' => 42 ]). Empty array for award() / revoke() calls.

Source: includes/trust/class-reputation.php

add_action( 'jetonomy_reputation_changed', function( int $user_id, string $action, int $delta, array $context ) {
    // Sync reputation to BuddyPress profile.
    bp_update_user_meta( $user_id, 'jetonomy_rep', \Jetonomy\Models\UserProfile::get_reputation( $user_id ) );
}, 10, 4 );

Notifications

jetonomy_notification_created

Fires after a notification is created and stored.

Parameters

Parameter Type Description
$notification_id int ID of the new notification record
$user_id int Recipient WP user ID
$type string Notification type slug (e.g. 'reply', 'mention', 'accepted')

Source: includes/notifications/class-notifier.php

add_action( 'jetonomy_notification_created', function( int $notif_id, int $user_id, string $type ) {
    // Forward notifications to a mobile push service.
    if ( 'mention' === $type ) {
        my_push_service_notify( $user_id, 'You were mentioned in a discussion.' );
    }
}, 10, 3 );

Spaces

jetonomy_user_joined_space

Fires after a user successfully joins a space.

Parameters

Parameter Type Description
$space_id int ID of the space joined
$user_id int WP user ID of the new member
$role string The member's role in the space (e.g. member)

Source: includes/models/class-space-member.php

// Note the argument order: $space_id comes first, then $user_id, then $role.
add_action( 'jetonomy_user_joined_space', function( int $space_id, int $user_id, string $role ) {
    // Auto-subscribe the user to a MailChimp list tied to this space.
    my_mailchimp_subscribe( $user_id, "space_{$space_id}" );
}, 10, 3 );

Membership

These hooks fire from both the MemberPress and PMPro adapters.

jetonomy_membership_activated

Fires when a user's membership subscription becomes active.

Parameters

Parameter Type Description
$user_id int WP user ID
$level_id string Membership level identifier
$adapter string Adapter identifier (e.g. 'memberpress', 'pmpro', 'woocommerce')

Source: includes/adapters/class-member-press-adapter.php, class-pmpro-adapter.php


jetonomy_membership_deactivated

Fires when a user's membership expires or is cancelled.

Parameters

Parameter Type Description
$user_id int WP user ID
$level_id string Membership level identifier
$adapter string Adapter identifier (e.g. 'memberpress', 'pmpro', 'woocommerce')

Source: includes/adapters/class-member-press-adapter.php, class-pmpro-adapter.php

add_action( 'jetonomy_membership_deactivated', function( int $user_id, string $level_id, string $adapter ) {
    // Revoke access to private spaces when membership lapses.
    $private_spaces = \Jetonomy\Models\Space::get_by_membership_level( $level_id );
    foreach ( $private_spaces as $space ) {
        \Jetonomy\Models\SpaceMember::remove( $user_id, $space->id );
    }
}, 10, 3 );

Topic Management

jetonomy_post_merged

Fires after two posts are merged (all replies moved to the target, source deleted).

Parameters

Parameter Type Description
$source_post_id int The post that was merged and deleted
$target_post_id int The post that received the replies

jetonomy_reply_split

Fires after a reply is split into a new standalone post.

Parameters

Parameter Type Description
$new_post_id int ID of the newly created post
$original_reply_id int ID of the reply that was split out

jetonomy_max_space_pins (filter)

Filters the maximum number of topics that can be pinned (made sticky) in a single space. Returning 0 (or a negative value) disables the cap entirely. Default is 3.

Parameters

Parameter Type Description
$max int Default maximum (3)
$space_id int The space the pin is being attempted in
// Allow up to 5 pinned topics in every space.
add_filter( 'jetonomy_max_space_pins', fn() => 5 );

// Different caps per space.
add_filter( 'jetonomy_max_space_pins', function ( $max, $space_id ) {
	return 10 === (int) $space_id ? 8 : $max;
}, 10, 2 );

This only governs the space-level pin (is_sticky). Community announcements ("Pin to community", Pro) have their own separate cap.


Template Hooks

These hooks fire inside the PHP templates and let you inject content without overriding template files.

jetonomy_before_content

Fires inside the .jt-app wrapper, before the header partial and content container. Bridge plugins (such as BuddyNext) use this to inject a community subnav in place of the default Jetonomy community nav.

Parameters

Parameter Type Description
$data array Route data: ['route' => string, 'slug' => string]

Source: includes/class-template-loader.php

add_action( 'jetonomy_before_content', function( array $data ) {
    echo '<div class="my-subnav">Custom nav here</div>';
} );

jetonomy_after_content

Fires after the main .container closes, before the .jt-app wrapper closes.

Parameters

Parameter Type Description
$data array Route data

jetonomy_new_post_fields

Fires inside the new-post form, after the built-in fields. Use this to inject custom form fields (e.g. for Pro custom fields extension).

Source: templates/views/new-post.php

add_action( 'jetonomy_new_post_fields', function() {
    // Render an additional "Estimated time" field.
    echo '<label for="jt-estimated-time">' . esc_html__( 'Estimated time (hours)', 'my-plugin' ) . '</label>';
    echo '<input type="number" id="jt-estimated-time" name="estimated_time" min="0" />';
} );

jetonomy_post_meta_fields

Fires inside the single-post view, after the post meta line.

Source: templates/views/single-post.php


jetonomy_post_actions

Fires inside the single-post view, inside the post action toolbar.

Source: templates/views/single-post.php


jetonomy_post_card_after_badges

Fires right after the built-in status badges (sticky/Pinned, private) so add-ons can append their own markers - for example the Pro "Announcement" badge for community-pinned posts. As of 1.4.4 this fires in both the listing card and the single-post header, so a badge added here appears consistently on both surfaces.

Parameters

Parameter Type Description
$post object The post row being rendered
$space object|null The post's space, if loaded

Source: templates/partials/post-card.php, templates/views/single-post.php


jetonomy_reply_actions

Fires inside the reply card, inside the reply action row.

Source: templates/partials/reply-card.php


jetonomy_profile_after_stats

Fires on user profile pages, after the reputation/trust stats block.

Source: templates/views/user-profile.php


jetonomy_profile_display_fields

Fires on user profile pages in the display (read-only) section. Use this to render extra profile fields.

Source: templates/views/user-profile.php

add_action( 'jetonomy_profile_display_fields', function() {
    $user_id = get_queried_object_id(); // or extract from the URL
    $company = get_user_meta( $user_id, 'company', true );
    if ( $company ) {
        printf( '<p class="jt-profile-field"><strong>%s</strong> %s</p>',
            esc_html__( 'Company:', 'my-plugin' ),
            esc_html( $company )
        );
    }
} );

jetonomy_profile_edit_fields

Fires inside the edit-profile form. Pair with jetonomy_profile_display_fields and a custom save_post / REST action to persist data.

Source: templates/views/edit-profile.php


jetonomy_header_nav_items

Fires inside the community header, after the built-in nav items. Add extra navigation links here.

Source: templates/partials/header.php

add_action( 'jetonomy_header_nav_items', function() {
    echo '<a href="/community/events/" class="jt-nav-link">Events</a>';
} );

jetonomy_sidebar_before

Fires at the top of the Jetonomy sidebar, before any widgets render. Prime slot for ad plugins, announcement banners, or custom cards.

Parameters

Parameter Type Description
$space object|null Current space object, or null outside a space

Source: templates/partials/sidebar.php

add_action( 'jetonomy_sidebar_before', function( $space ) {
    echo do_shortcode( '[wb_ads position="jetonomy_sidebar_top"]' );
} );

jetonomy_sidebar_after

Fires at the bottom of the Jetonomy sidebar, after all widgets render.

Parameters

Parameter Type Description
$space object|null Current space object, or null outside a space

Source: templates/partials/sidebar.php

add_action( 'jetonomy_sidebar_after', function( $space ) {
    echo do_shortcode( '[wb_ads position="jetonomy_sidebar_bottom"]' );
} );

jetonomy_sidebar_after_about

Fires in the sidebar immediately after the "About" space card closes. Only fires when a space is present (i.e. on space-scoped pages). Ideal for ads, announcements, or CTAs pinned below the space intro, before Trending and other widgets.

Parameters

Parameter Type Description
$space object Current space object

Source: templates/partials/sidebar.php

add_action( 'jetonomy_sidebar_after_about', function( $space ) {
    echo do_shortcode( '[wbam_ad id="42"]' );
} );

jetonomy_after_post_article

Fires after the main post <article> element and before the replies section on a single post view. Ideal for ads, related-topic blocks, or CTAs between the topic body and the reply list.

⚠️ Do not confuse with the jetonomy_after_post_content filter (below) which fires inside the post body. This hook is an action named _article to avoid collision.

Parameters

Parameter Type Description
$post object Current post object

Source: templates/views/single-post.php

add_action( 'jetonomy_after_post_article', function( $post ) {
    echo do_shortcode( '[wb_ads position="jetonomy_after_topic"]' );
} );

jetonomy_before_replies

Fires inside .jt-replies-section, immediately before the replies list (above both the empty state and the populated list).

Parameters

Parameter Type Description
$post object Current post object
$total_replies int Total reply count for the post

Source: templates/views/single-post.php

add_action( 'jetonomy_before_replies', function( $post, $total_replies ) {
    if ( $total_replies > 5 ) {
        echo do_shortcode( '[wb_ads position="jetonomy_replies_top"]' );
    }
}, 10, 2 );

jetonomy_between_replies

Fires after each top-level reply in the reply list. Use the $index parameter to inject content every Nth reply (e.g. an ad every 5 replies).

Parameters

Parameter Type Description
$reply object The reply object just rendered
$index int Zero-based index within the current batch (first batch or last batch)
$post object Current post object

Source: templates/views/single-post.php

The replies list renders in two batches (opening + latest). The index resets at the start of each batch. Use $reply->id for absolute identity.

add_action( 'jetonomy_between_replies', function( $reply, $index, $post ) {
    // Inject an ad after every 5th reply.
    if ( 4 === $index % 5 ) {
        echo '<div class="jt-reply-ad">' . do_shortcode( '[wb_ads position="jetonomy_between_replies"]' ) . '</div>';
    }
}, 10, 3 );

jetonomy_after_replies

Fires inside .jt-replies-section, after the replies list and before the composer.

Parameters

Parameter Type Description
$post object Current post object
$total_replies int Total reply count for the post

Source: templates/views/single-post.php

add_action( 'jetonomy_after_replies', function( $post, $total_replies ) {
    echo do_shortcode( '[wb_ads position="jetonomy_replies_bottom"]' );
}, 10, 2 );

Admin Extension Hooks

Use these to add content to the Jetonomy admin pages without overriding core admin files.

Hook Parameters Where it fires
jetonomy_admin_dashboard_widgets none Dashboard page - add custom stat cards
jetonomy_admin_dashboard_after_stats none Dashboard - below the stats row
jetonomy_admin_settings_tabs none Settings page - register new tab nav items
jetonomy_admin_settings_tab_content $active_tab (string) Settings page - render tab content
jetonomy_admin_moderation_tabs none Moderation page - extra tab nav items
jetonomy_admin_moderation_tab_content $active_tab (string) Moderation page - render tab content
jetonomy_admin_space_edit_tabs $space_id (int) Space edit page - extra tab nav items
jetonomy_admin_space_edit_tab_content $active_tab (string), $space_id (int) Space edit page - render tab content
jetonomy_admin_render_extensions none Admin - Extensions tab placeholder
jetonomy_admin_render_license none Admin - License tab placeholder

Example: adding a Settings tab

// Register the tab nav item.
add_action( 'jetonomy_admin_settings_tabs', function() {
    $active = $_GET['tab'] ?? 'general';
    $class  = 'my-custom' === $active ? 'nav-tab-active' : '';
    printf(
        '<a href="?page=jetonomy-settings&tab=my-custom" class="nav-tab %s">%s</a>',
        esc_attr( $class ),
        esc_html__( 'My Settings', 'my-plugin' )
    );
} );

// Render the tab content.
add_action( 'jetonomy_admin_settings_tab_content', function( string $active_tab ) {
    if ( 'my-custom' !== $active_tab ) {
        return;
    }
    echo '<div class="jt-settings-card">';
    echo '<div class="jt-settings-card__head">';
    echo '<p class="jt-settings-card__title">My Settings</p>';
    echo '</div>';
    // Your settings form here.
    echo '</div>';
} );

Performance & Cron

jetonomy_cron_batch_size

Filters the maximum number of rows processed per run by any of Jetonomy's background cleanup handlers. The default is 500 rows per run, which prevents cron jobs from timing out on large sites with high activity volumes.

Parameters

Parameter Type Description
$batch_size int Maximum rows to process. Default: 500
$handler string The handler name, e.g. 'prune_activity_log', 'expire_restrictions', 'cleanup_notifications', 'publish_scheduled_posts'

Return: int

Source: includes/class-cron.php

Use the $handler parameter to set different limits per job:

add_filter( 'jetonomy_cron_batch_size', function( int $batch_size, string $handler ): int {
    // Allow the activity log pruner to work through larger batches on this high-traffic site.
    if ( 'prune_activity_log' === $handler ) {
        return 1000;
    }
    return $batch_size;
}, 10, 2 );

Filter Hooks

jetonomy_template_map

Filters the route-to-template map used by Template_Loader. Pass an absolute path to override an existing template or add a completely new route. See Template Overrides for the complete guide.

Parameters

Parameter Type Description
$map array ['route' => 'relative/path.php']

Return: array Modified map

add_filter( 'jetonomy_template_map', function( array $map ): array {
    // Register a new 'events' route resolved against the Pro plugin directory.
    $map['events'] = MYPLUGIN_DIR . 'templates/events.php';
    return $map;
} );

jetonomy_check_content

Filters content before it is saved as a post or reply. Return a WP_Error to reject the content with a message shown to the user.

Parameters

Parameter Type Description
$result true|WP_Error Pass through or return a WP_Error to block
$content string The sanitized HTML content string
$user_id int Author's WP user ID

Return: true|WP_Error

Source: includes/api/class-posts-controller.php, class-replies-controller.php

add_filter( 'jetonomy_check_content', function( $result, string $content, int $user_id ) {
    // Block posts containing a forbidden phrase.
    if ( str_contains( strtolower( $content ), 'buy cheap followers' ) ) {
        return new WP_Error( 'spam_blocked', __( 'This content was flagged as spam.', 'my-plugin' ) );
    }
    return $result;
}, 10, 3 );

jetonomy_after_post_content

Filters output rendered after the main post content area in single-post view. Return an HTML string.

Parameters

Parameter Type Description
$html string HTML to render after post content (empty by default)
$post \Jetonomy\Models\Post The current post object

Return: string

Source: templates/views/single-post.php

add_filter( 'jetonomy_after_post_content', function( string $html, $post ): string {
    $html .= '<div class="my-related-posts">' . my_get_related_posts( $post->id ) . '</div>';
    return $html;
}, 10, 2 );

jetonomy_notification_email_headers

Filters the email headers array passed to wp_mail() for all Jetonomy notifications.

Parameters

Parameter Type Description
$headers array Array of mail headers

Return: array

Source: includes/adapters/class-wp-mail-adapter.php

add_filter( 'jetonomy_notification_email_headers', function( array $headers ): array {
    $headers[] = 'Reply-To: noreply@example.com';
    return $headers;
} );

jetonomy_profile_url

Filters the public URL for a user's community profile.

Parameters

Parameter Type Description
$url string Default profile URL (e.g. /community/u/janedoe/)
$user_id int WP user ID

Return: string

Source: includes/functions.php

add_filter( 'jetonomy_profile_url', function( string $url, int $user_id ): string {
    // Point profile links to a BuddyPress profile instead.
    $bp_url = bp_core_get_user_domain( $user_id );
    return $bp_url ?: $url;
}, 10, 2 );

jetonomy_admin_menu_label

Filters the top-level admin menu label.

Return: string

add_filter( 'jetonomy_admin_menu_label', fn() => 'Forum' );

jetonomy_admin_menu_icon

Filters the Dashicons icon for the admin menu item.

Return: string (Dashicons class, e.g. 'dashicons-format-chat')


jetonomy_show_community_nav

Filters whether the built-in community nav bar is displayed. Return false to hide it (useful when a bridge plugin provides its own nav).

Parameters

Parameter Type Description
$show bool true by default

Return: bool


jetonomy_importers

Filters the list of registered importers shown in the Import tool.

Parameters

Parameter Type Description
$importers array ['id' => Importer_Instance]

Return: array

Source: includes/import/class-import-manager.php

add_filter( 'jetonomy_importers', function( array $importers ): array {
    $importers['my-forum'] = new My_Forum_Importer();
    return $importers;
} );

jetonomy_search_query_args

Fires inside the Search controller before the SQL is built. Use this to modify search parameters.

Parameters

Parameter Type Description
$args array Keys: q, space_id, date_from, date_to, author_id, tag_slug, sort

Return: array

Source: includes/api/class-search-controller.php


Registration & Boot Hooks

jetonomy_admin_license_tab_content

Fires inside the Settings page License tab placeholder. Use this to render a license activation form or status block.

Parameters

None.

Source: includes/admin/views/settings.php


User Lifecycle Hooks

jetonomy_user_registered

Fires after a new user account is created via the REST registration endpoint.

Parameters

Parameter Type Description
$user_id int WP user ID of the newly registered user

Source: includes/api/class-auth-controller.php


jetonomy_user_pending_verification

Fires after a new user is created but email verification is required and the account is in a pending state.

Parameters

Parameter Type Description
$user_id int WP user ID of the pending user

Source: includes/api/class-auth-controller.php


jetonomy_email_verified

Fires after a user successfully verifies their email address via the verification token link.

Parameters

Parameter Type Description
$user_id int WP user ID of the verified user

Source: includes/api/class-auth-controller.php


jetonomy_verification_reminder_sent

Fires after the cron-driven single-shot verification reminder email is dispatched to an unverified user.

Parameters

Parameter Type Description
$user_id int WP user ID of the nudged user
$user WP_User WP_User object for the nudged user

Source: includes/notifications/class-verification-reminder.php


Content Lifecycle Hooks

jetonomy_before_create_post

Filter (not action). Runs immediately before a new post row is inserted. Modify the data array to change what gets written, or use it to pre-process content.

Parameters

Parameter Type Description
$data array Column data about to be inserted (keys: title, content, status, space_id, author_id, post_type, etc.)
$author_id int Author user ID (convenience copy from $data['author_id'])
$space_id int Target space ID (convenience copy from $data['space_id'])

Return: array Modified data array.

Source: includes/models/class-post.php


jetonomy_before_create_reply

Filter (not action). Runs immediately before a new reply row is inserted.

Parameters

Parameter Type Description
$data array Column data about to be inserted (keys: content, status, post_id, author_id, parent_id, etc.)
$author_id int Author user ID (convenience copy from $data['author_id'])
$post_id int Parent post ID (convenience copy from $data['post_id'])

Return: array Modified data array.

Source: includes/models/class-reply.php


jetonomy_before_delete_post

Filter (not action). Fires before a post is permanently deleted. Return false to abort the delete.

Parameters

Parameter Type Description
$proceed bool true to allow deletion; return false to cancel
$post_id int ID of the post about to be deleted

Return: bool

Source: includes/models/class-post.php


jetonomy_before_delete_reply

Filter (not action). Fires before a reply is permanently deleted. Return false to abort.

Parameters

Parameter Type Description
$proceed bool true to allow deletion
$reply_id int ID of the reply about to be deleted

Return: bool

Source: includes/models/class-reply.php


jetonomy_reply_unaccepted

Fires after the accepted-answer mark is removed from a reply.

Parameters

Parameter Type Description
$reply_id int ID of the reply that was un-accepted
$post_id int ID of the parent post

Source: includes/api/class-replies-controller.php


jetonomy_scheduled_post_published

Fires after a scheduled post is automatically published by the cron handler when its published_at datetime passes.

Parameters

Parameter Type Description
$post_id int ID of the published post
$space_id int ID of the space the post belongs to

Source: includes/models/class-post.php


Moderation & Flagging Hooks

jetonomy_flag_created

Fires after a new flag is saved against a post or reply.

Parameters

Parameter Type Description
$flag_id int ID of the created flag record
$object_type string 'post' or 'reply'

Source: includes/api/class-moderation-controller.php


jetonomy_flag_resolved

Fires after a flag is resolved (approved, dismissed, or actioned). For a version that includes the full flag object see jetonomy_after_resolve_flag below.

Parameters

Parameter Type Description
$flag_id int ID of the resolved flag
$status string Resolution status (e.g. 'approved', 'dismissed')
$user_id int ID of the moderator who resolved it

Source: includes/moderation/class-moderation-service.php


jetonomy_after_resolve_flag

Fires after a flag is resolved and provides the full flag object plus context. Counterpart to jetonomy_flag_resolved - use this when you need to read the flag's fields without a second lookup.

Parameters

Parameter Type Description
$flag object The full flag row object (post-resolution state)
$context array Associative array with keys status (string) and user_id (int)

Source: includes/moderation/class-moderation-service.php


Space Membership Hooks

jetonomy_before_join_space

Filter (not action). Fires before a user is added to a space. Return false to block the join.

Parameters

Parameter Type Description
$proceed bool true to allow the join
$user_id int User attempting to join
$space_id int Target space ID
$role string Role being assigned (e.g. 'member', 'admin')

Return: bool

Source: includes/models/class-space-member.php


jetonomy_user_left_space

Fires after a user is removed from a space.

Parameters

Parameter Type Description
$space_id int ID of the space the user left
$user_id int WP user ID of the departing member

Source: includes/models/class-space-member.php


jetonomy_space_member_joined

Alias of jetonomy_user_joined_space without the role argument, matching the Pro webhooks listener contract. Fires at the same time as jetonomy_user_joined_space.

Parameters

Parameter Type Description
$space_id int ID of the space
$user_id int WP user ID of the new member

Source: includes/models/class-space-member.php


jetonomy_space_member_left

Alias of jetonomy_user_left_space, matching the Pro webhooks listener contract.

Parameters

Parameter Type Description
$space_id int ID of the space
$user_id int WP user ID of the departing member

Source: includes/models/class-space-member.php


jetonomy_join_request_created

Fires after a join request is submitted for a private space.

Parameters

Parameter Type Description
$space_id int ID of the space being requested
$user_id int ID of the requesting user
$message string Optional message submitted with the request (empty string if none)

Source: includes/api/class-spaces-controller.php


Voting Hooks

jetonomy_before_vote

Filter (not action). Fires before a vote is recorded. Return false to block the vote entirely.

Parameters

Parameter Type Description
$proceed bool true to allow the vote
$user_id int Voting user ID
$object_type string 'post' or 'reply'
$object_id int Target object ID
$value int Vote value: 1 for upvote, -1 for downvote

Return: bool

Source: includes/models/class-vote.php


Trust & Reputation Hooks

jetonomy_reputation_points_map

Filter (not action). Filters the entire POINTS_MAP (action → delta) before per-action resolution. Use this to add new action keys or wholesale-replace the scoring table per community. Composes with jetonomy_reputation_points_for, which runs afterwards on the resolved value for the requested action.

Parameters

Parameter Type Description
$map array<string,int> Default POINTS_MAP keyed by action slug.

Return: array<string,int>

Source: includes/trust/class-reputation.php

add_filter( 'jetonomy_reputation_points_map', function( array $map ): array {
    // Boost the entire ladder by 50% for this community.
    return array_map( fn( int $points ) => (int) round( $points * 1.5 ), $map );
} );

jetonomy_reputation_points_for

Filter (not action). Filters the point value for a specific reputation action after the map / settings override resolves. Allows per-site tuning of the reputation ladder without editing plugin settings.

Parameters

Parameter Type Description
$points int Default point value for the action
$action string Action slug (e.g. 'post_upvoted', 'reply_accepted', 'flag_validated')

Return: int

Source: includes/trust/class-reputation.php

add_filter( 'jetonomy_reputation_points_for', function( int $points, string $action ): int {
    // Double the reward for accepted answers on this site.
    if ( 'reply_accepted' === $action ) {
        return $points * 2;
    }
    return $points;
}, 10, 2 );

jetonomy_reputation_pre_change

Filter (not action). Filters the signed delta immediately before it is persisted to user_profiles.reputation. Returning 0 short-circuits the write entirely - the jetonomy_reputation_changed action will not fire and no DB row is touched. Use this to scale deltas during campaigns, veto changes for sandboxed users, or redirect reputation to an external scoring engine.

Parameters

Parameter Type Description
$delta int Signed point delta about to be applied.
$user_id int WP user ID whose reputation will change.
$action string Action slug (revocations append _revoked).
$context array Optional context payload (e.g. [ 'badge_id' => 42 ]).

Return: int - return 0 to veto the change.

Source: includes/trust/class-reputation.php

add_filter( 'jetonomy_reputation_pre_change', function( int $delta, int $user_id, string $action, array $context ): int {
    // Veto rep changes for sandboxed users.
    if ( get_user_meta( $user_id, 'wb_gam_sandboxed', true ) ) {
        return 0;
    }
    // Double points during a weekend campaign.
    if ( wb_gam_campaign_active( 'double_points' ) ) {
        return $delta * 2;
    }
    return $delta;
}, 10, 4 );

jetonomy_leaderboard_items

Filter (not action). Filters the leaderboard response rows in GET /jetonomy/v1/leaderboards immediately before they are wrapped in the paginated envelope. Use this to enrich each row with cross-engine totals (badge count, level name, alternate currency) without a second REST round-trip.

Parameters

Parameter Type Description
$items array Leaderboard rows. Each row has rank, user_id, display_name, user_login, avatar_url, profile_url, reputation, post_count, reply_count, trust_level.
$request WP_REST_Request Original REST request - inspect get_param('period'), etc.

Return: array

Source: includes/api/class-leaderboards-controller.php

add_filter( 'jetonomy_leaderboard_items', function( array $items, WP_REST_Request $request ): array {
    foreach ( $items as &$row ) {
        $row['wb_gam_points'] = (int) WB_Gam\Points::for_user( $row['user_id'] );
        $row['wb_gam_badges_count'] = (int) WB_Gam\Badges::count_for_user( $row['user_id'] );
    }
    return $items;
}, 10, 2 );

Email & Notification Filter Hooks

jetonomy_email_subject

Filter (not action). Filters the email subject line before the notification is sent.

Parameters

Parameter Type Description
$subject string Rendered subject string
$type string Notification type slug (e.g. 'reply_to_post', 'mention', 'accepted_answer')
$user WP_User Notification recipient

Return: string

Source: includes/notifications/class-notifier.php


jetonomy_email_body

Filter (not action). Filters the plain-text email body before the notification is sent.

Parameters

Parameter Type Description
$body string Plain-text body string
$type string Notification type slug
$user WP_User Notification recipient

Return: string

Source: includes/notifications/class-notifier.php


jetonomy_email_html

Filter (not action). Filters the fully rendered HTML of the notification email just before it is passed to wp_mail().

Parameters

Parameter Type Description
$html string Full rendered HTML string
$type string Notification type slug
$user WP_User Notification recipient

Return: string

Source: includes/notifications/class-notifier.php


jetonomy_email_headers

Filter (not action). Filters the headers array passed to wp_mail() for all notification emails. Note: for adding a Reply-To header for reply-by-email support, use jetonomy_notification_email_headers instead (also available).

Parameters

Parameter Type Description
$headers array Array of mail header strings
$type string Notification type slug
$user WP_User Notification recipient

Return: array

Source: includes/notifications/class-notifier.php


jetonomy_email_logo_url

Filter (not action). Filters the logo URL rendered inside notification emails. Return an empty string to suppress the logo.

Parameters

Parameter Type Description
$url string Logo URL (empty string if none configured)
$type string Notification type slug providing context for per-type overrides

Return: string

Source: includes/notifications/class-notifier.php


jetonomy_email_accent_color

Filter (not action). Filters the hex accent color used in notification email templates for buttons and highlights.

Parameters

Parameter Type Description
$color string Hex color string (e.g. '#3B82F6')
$type string Notification type slug

Return: string

Source: includes/notifications/class-notifier.php


jetonomy_email_template_context

Filter (not action). Filters the full template context array before it is passed to the email template renderer. Use this to inject extra variables into any notification email template.

Parameters

Parameter Type Description
$ctx array Template variables array (keys vary by notification type)
$type string Notification type slug
$user WP_User Notification recipient

Return: array

Source: includes/notifications/class-notifier.php


jetonomy_email_template_path

Filter (not action). Filters the resolved filesystem path to the email template file before it is loaded.

Parameters

Parameter Type Description
$path string Absolute path to the email template .php file
$type string Notification type slug

Return: string

Source: includes/notifications/class-notifier.php


jetonomy_disposable_email_domains

Filter (not action). Filters the list of blocked disposable email domains used during registration validation.

Parameters

Parameter Type Description
$domains array Array of blocked domain strings (e.g. ['mailinator.com', 'guerrillamail.com'])

Return: array

Source: includes/api/class-auth-controller.php


REST Response Filter Hooks

jetonomy_rest_prepare_post

Filter (not action). Filters the prepared post data array before it is returned in any REST response. Use this for fine-grained control over individual fields. For appending extension-level payload use jetonomy_post_response instead.

Parameters

Parameter Type Description
$data array Prepared REST response data for the post
$post object Raw post row object
$request WP_REST_Request|null The current request, or null in non-request contexts

Return: array

Source: includes/api/class-posts-controller.php


jetonomy_rest_prepare_reply

Filter (not action). Filters the prepared reply data array before it is returned in any REST response.

Parameters

Parameter Type Description
$data array Prepared REST response data for the reply
$reply object Raw reply row object
$request WP_REST_Request|null The current request, or null in non-request contexts

Return: array

Source: includes/api/class-replies-controller.php


jetonomy_rest_prepare_space

Filter (not action). Filters the prepared space data array before it is returned in any REST response.

Parameters

Parameter Type Description
$data array Prepared REST response data for the space
$space object Raw space row object
$request WP_REST_Request|null The current request, or null

Return: array

Source: includes/api/class-spaces-controller.php


jetonomy_rest_prepare_user

Filter (not action). Filters the prepared user data array before it is returned in any REST response.

Parameters

Parameter Type Description
$data array Prepared REST response data for the user
$wp_user WP_User WP user object
$request WP_REST_Request|null The current request, or null

Return: array

Source: includes/api/class-users-controller.php


jetonomy_rest_prepare_notification

Filter (not action). Filters the prepared notification data array before it is returned in any REST response.

Parameters

Parameter Type Description
$data array Prepared REST response data for the notification
$notification object Raw notification row object
$request WP_REST_Request|null The current request, or null

Return: array

Source: includes/api/class-notifications-controller.php


jetonomy_post_response

Filter (not action). Alias filter matching the Pro custom-fields listener contract. Lets extensions append per-post payload (custom field values, reactions, polls) to the REST response. The $context array carries object_type and object_id so generic extension handlers can route on type.

Parameters

Parameter Type Description
$data array Prepared REST response data
$context array Associative array with keys object_type ('post') and object_id (int)

Return: array

Source: includes/api/class-posts-controller.php


jetonomy_profile_response

Filter (not action). Lets extensions append data to user profile REST responses (custom fields, badges).

Parameters

Parameter Type Description
$data array Prepared profile response data
$context array Associative array with keys object_type ('user') and object_id (int)

Return: array

Source: includes/api/class-users-controller.php


jetonomy_oembed_response

Filter (not action). Filters the oEmbed response data for a forum post before it is returned.

Parameters

Parameter Type Description
$data array oEmbed response fields (title, url, thumbnail_url, etc.)
$post object The post row object
$space object The parent space row object

Return: array

Source: includes/api/class-oembed-controller.php


jetonomy_link_preview_data

Filter (not action). Filters the extracted link preview data (OG metadata) for a URL before it is cached and returned.

Parameters

Parameter Type Description
$out array Extracted metadata: title, description, image, url, site_name
$url string The URL being previewed

Return: array

Source: includes/services/links/class-preview-service.php


jetonomy_link_preview_cache_ttl

Filter (not action). Filters the cache TTL (in seconds) for link preview results.

Parameters

Parameter Type Description
$ttl int Cache duration in seconds (default: 3600)
$url string The URL being previewed

Return: int

Source: includes/services/links/class-preview-service.php


jetonomy_link_preview_providers

Filter (not action). Filters the list of registered link preview provider handlers.

Parameters

Parameter Type Description
$providers array Ordered list of provider objects/callables

Return: array

Source: includes/services/links/class-preview-service.php


jetonomy_link_preview_user_agent

Filter (not action). Filters the User-Agent header used when fetching remote URLs for link preview extraction.

Parameters

Parameter Type Description
$ua string User-Agent string
$url string The URL about to be fetched

Return: string

Source: includes/services/links/class-html-fetcher.php


Template Filter Hooks

jetonomy_show_sidebar

Filter (not action). Return false to hide the sidebar entirely on the current page.

Parameters

Parameter Type Description
$show bool true by default

Return: bool

Source: templates/partials/sidebar.php


jetonomy_sidebar_auth_card

Filter (not action). Filters whether the default anonymous-user auth card is rendered in the sidebar. Return false (or an HTML string to replace it) to suppress or override it. Jetonomy Pro's White Label extension uses this to inject a custom card via jetonomy_sidebar_before.

Parameters

Parameter Type Description
$show bool true to render the default auth card

Return: bool

Source: includes/class-blocks.php


jetonomy_sidebar_about_after_meta

Fires inside the sidebar "About this space" card, after the meta row (member count, post count). Only fires on space-scoped pages where a space object is available.

Parameters

Parameter Type Description
$space object Current space row object

Source: templates/partials/sidebar.php


Filter (not action). Filters the URL of the logo shown in the community header bar. Return an empty string to hide the logo.

Parameters

Parameter Type Description
$url string Default logo URL (empty string if none set)

Return: string

Source: includes/functions.php


jetonomy_footer_text

Filter (not action). Filters the text shown in the community footer. Return an empty string to suppress the footer text.

Parameters

Parameter Type Description
$text string Default footer text

Return: string

Source: includes/functions.php


jetonomy_new_post_submit_action

Filter (not action). Filters the Interactivity API store action name wired to the new-post form's submit event. Jetonomy Pro overrides this to 'actions.submitNewPostWithPoll' when the polls extension is active.

Parameters

Parameter Type Description
$action string Default action name: 'actions.submitNewPost'

Return: string

Source: templates/views/new-post.php


jetonomy_search_filters

Fires inside the search results page, inside the filter panel, after the built-in filters. Use this to render additional search filter controls.

Parameters

Parameter Type Description
$q string Current search query string
$filter string Active content-type filter ('all', 'posts', 'replies', 'spaces', 'users')
$context array Other active filter values: date_from, date_to, author_id, tag_slug, sort

Source: templates/views/search.php


Permissions Filter Hooks

jetonomy_space_role_permissions

Filter (not action). Filters the permissions array for a given space role. Use this to grant or revoke individual permissions for custom role configurations.

Parameters

Parameter Type Description
$permissions array Array of allowed action strings for the role (e.g. ['create_posts', 'vote', 'flag'])
$role string Role name: 'member', 'moderator', or 'admin'
$space_id int ID of the space the check applies to

Return: array

Source: includes/permissions/class-permission-engine.php


jetonomy_use_frontend_space_edit

Filter (not action). Filters whether the space settings form should be served via the frontend (in-page) UI rather than redirecting to the admin panel. Return false to force the admin redirect.

Parameters

Parameter Type Description
$use_frontend bool true by default (uses frontend form)
$space object Space row object

Return: bool

Source: includes/functions.php


Theme Integration Filter Hooks

jetonomy_theme_light_tokens

Filter (not action). Filters the CSS custom property token map written for light mode. Return a modified array to override or add tokens injected into the page <head>.

Parameters

Parameter Type Description
$tokens array Associative array of ['--token-name' => 'value'] pairs

Return: array

Source: includes/integrations/class-theme-integration.php


jetonomy_theme_dark_tokens

Filter (not action). Filters the CSS custom property token map written for dark mode.

Parameters

Parameter Type Description
$tokens array Associative array of ['--token-name' => 'value'] pairs

Return: array

Source: includes/integrations/class-theme-integration.php


Admin Filter Hooks

jetonomy_admin_footer_text

Filter (not action). Filters the footer text shown at the bottom of all Jetonomy admin pages (replaces the default WordPress "Thank you" text).

Parameters

Parameter Type Description
$text string Default footer text string

Return: string

Source: includes/admin/class-admin.php


Pro Hooks

These hooks are available only when Jetonomy Pro is active. Pro injects into core admin via the standard admin hooks (jetonomy_admin_dashboard_widgets, jetonomy_admin_settings_tabs) and registers its own extension lifecycle events.

Hook Type Description
jetonomy_pro_extension_booted action Fires after a Pro extension's boot() runs. Params: $extension_id (string)
jetonomy_pro_extension_enabled action Fires when an extension is toggled on in admin. Params: $extension_id (string)
jetonomy_pro_extension_disabled action Fires when an extension is toggled off. Params: $extension_id (string)
jetonomy_pro_message_sent action Fires after a private message is sent. Params: $message_id (int), $conversation_id (int), $sender_id (int)
jetonomy_pro_dm_received action Fires once per recipient when a DM is delivered. Counterpart to jetonomy_pro_message_sent - lets you build "received first DM" or "active inbox" rules. Skipped for system messages. Params: $message_id (int), $conversation_id (int), $sender_id (int), $recipient_id (int)
jetonomy_pro_webhook_sent action Fires after a webhook is dispatched. Params: $webhook_id (int), $event (string), $response_code (int)
jetonomy_pro_digest_sent action Fires after an email digest is sent. Params: $user_id (int), $frequency (string)

jetonomy_pro_conversation_created

Fires after a new private conversation is created (both direct and group).

Parameters

Parameter Type Description
$conversation_id int ID of the newly created conversation
$user_id int ID of the user who created the conversation
$participants array Array of all participant user IDs (includes creator)

Source: jetonomy-pro/includes/extensions/private-messaging/class-extension.php


jetonomy_pro_message_notified

Fires after in-app and/or email notifications are dispatched to conversation participants for a new message. The $preview string is the truncated message preview sent in the notification.

Parameters

Parameter Type Description
$conversation_id int ID of the conversation
$sender_id int WP user ID of the message sender
$preview string Truncated plain-text preview of the message

Source: jetonomy-pro/includes/extensions/private-messaging/class-extension.php


jetonomy_pro_poll_created

Fires after a poll is created and attached to a post.

Parameters

Parameter Type Description
$poll_id int ID of the newly created poll
$post_id int ID of the post the poll is attached to
$user_id int ID of the user who created the poll

Source: jetonomy-pro/includes/extensions/polls/class-extension.php


jetonomy_pro_poll_voted

Fires after a user casts a vote on a poll.

Parameters

Parameter Type Description
$poll_id int ID of the poll
$user_id int ID of the voting user
$option_ids array Array of option IDs the user voted for (multi-select polls may have more than one)

Source: jetonomy-pro/includes/extensions/polls/class-extension.php


jetonomy_pro_poll_unvoted

Fires after a user removes their vote from a poll.

Parameters

Parameter Type Description
$poll_id int ID of the poll
$user_id int ID of the user who removed their vote

Source: jetonomy-pro/includes/extensions/polls/class-extension.php


jetonomy_pro_badge_earned

Fires after a badge is awarded to a user (both manual awards via the REST API and auto-awards from the daily cron evaluator).

Parameters

Parameter Type Description
$user_id int ID of the user who earned the badge
$badge_id int ID of the badge definition
$badge object Full badge row object (name, description, icon, criteria, etc.)

Source: jetonomy-pro/includes/extensions/custom-badges/class-extension.php


jetonomy_pro_field_created

Fires after a custom field definition is created.

Parameters

Parameter Type Description
$field_id int ID of the newly created custom field
$context array Creation context, including object_type ('post', 'user', or 'space') and the full field data

Source: jetonomy-pro/includes/extensions/custom-fields/class-extension.php


jetonomy_pro_reaction_toggled

Fires after an emoji reaction is added or removed. The $action parameter tells you which direction the toggle went.

Parameters

Parameter Type Description
$object_type string 'post' or 'reply'
$object_id int ID of the object that was reacted to
$emoji string The emoji slug or character (e.g. 'thumbs_up', '+1')
$user_id int ID of the reacting user
$action string 'added' or 'removed'

Source: jetonomy-pro/includes/extensions/reactions/class-extension.php


jetonomy_pro_ai_all_providers_failed

Fires when every configured AI provider has been tried and all returned an error or exception. Use this to log failures or alert an ops channel.

Parameters

Parameter Type Description
$feature string The feature that requested AI ('summary', 'spam', 'moderation', 'suggestion')
$exception \Throwable The last exception thrown

Source: jetonomy-pro/includes/extensions/ai/ (class-summarizer.php, class-spam-detector.php, class-moderator.php, class-suggester.php)


jetonomy_create_reply_from_email

Fired by the Pro Reply-by-Email extension to request that the free plugin create a reply from an inbound email. The free plugin listens to this action and routes it through the standard reply creation path so all free-side hooks (moderation, notifications, reputation) still fire.

Parameters

Parameter Type Description
$post_id int ID of the post to reply to
$user_id int ID of the user whose email was matched
$content string Cleaned plain-text or HTML content extracted from the email
$source string Source label; always 'reply_by_email' for replies created via this hook

Source: jetonomy-pro/includes/extensions/reply-by-email/class-extension.php


jetonomy_pro_reaction_icon_renderer

Filter (not action). Filters the renderer strategy used for a reaction icon. The default renderer is 'emoji', which uses the native platform emoji. Override with a custom renderer slug to swap in SVG icons or image sprites.

Parameters

Parameter Type Description
$renderer string Current renderer slug ('emoji' by default)
$slug string The reaction slug being rendered (e.g. '+1', 'heart')
$size int Requested icon size in pixels

Return: string Renderer slug to use.

Source: jetonomy-pro/includes/extensions/reactions/class-extension.php


What's Next?

Jetonomy's template system is designed to be overridden without touching plugin files. Place your custom templates in your theme and they will be loaded automatically - no hooks, no filters required for simple overrides.


How It Works

When Jetonomy loads a template, Template_Loader checks your active theme directory first. If a matching file exists there, it loads that file instead of the plugin's copy. This means your overrides survive plugin updates.

Resolution order:

  1. {your-theme}/jetonomy/{relative-path} - checked first
  2. {jetonomy-plugin}/templates/{relative-path} - fallback default

The {relative-path} is always the same path the plugin uses internally - for example, views/home.php or partials/reply-card.php.


Directory Structure

Create the following folder structure in your active theme:

your-theme/
└── jetonomy/
    ├── views/
    │   ├── home.php
    │   ├── category.php
    │   ├── space.php
    │   ├── space-members.php
    │   ├── space-roadmap.php
    │   ├── single-post.php
    │   ├── new-post.php
    │   ├── user-profile.php
    │   ├── edit-profile.php
    │   ├── leaderboard.php
    │   ├── notifications.php
    │   ├── moderation.php
    │   ├── search.php
    │   ├── tag.php
    │   └── invite.php
    └── partials/
        ├── avatar.php
        ├── breadcrumb.php
        ├── composer.php
        ├── header.php
        ├── pagination.php
        ├── post-card.php
        ├── reply-card.php
        └── sidebar.php

You do not need to copy all of these. Only create the files you want to customize - any file not present in your theme directory is loaded from the plugin.


Available Templates

Views (full-page templates)

File Route URL Pattern
views/home.php home /community/
views/category.php category /community/category/{slug}/
views/space.php space /community/s/{slug}/
views/space-members.php space-members /community/s/{slug}/members/
views/space-roadmap.php space-roadmap /community/s/{slug}/roadmap/
views/space-edit.php edit-space /community/s/{slug}/edit/
views/space-moderation.php space-moderation /community/s/{slug}/mod/
views/single-post.php post /community/s/{slug}/t/{slug}/
views/new-post.php new-post /community/s/{slug}/new/
views/new-space.php new-space /community/new-space/
views/my-spaces.php my-spaces /community/my-spaces/
views/drafts.php drafts /community/drafts/
views/bookmarks.php bookmarks /community/bookmarks/
views/user-profile.php profile /community/u/{login}/
views/edit-profile.php edit-profile /community/u/{login}/edit/
views/leaderboard.php leaderboard /community/leaderboard/
views/notifications.php notifications /community/notifications/
views/moderation.php moderation /community/mod/
views/search.php search /community/search/
views/tag.php tag /community/tag/{slug}/
views/invite.php invite /community/invite/{code}/

Partials (reusable template fragments)

File Rendered via
partials/header.php Loaded at the top of every community page
partials/sidebar.php Loaded in space and home views
partials/breadcrumb.php Loaded in space, category, and post views
partials/post-card.php Iterated over in space and home views
partials/reply-card.php Iterated over in single-post view
partials/pagination.php Loaded at the bottom of listing pages
partials/avatar.php Used inside post-card, reply-card, and profile views
partials/composer.php Rich-text composer used in new-post and reply forms

Step-by-Step: Overriding the Post Card

This example adds a "Sponsored" badge to posts from a specific space.

Step 1: Copy the original template

Copy wp-content/plugins/jetonomy/templates/partials/post-card.php to:

your-theme/jetonomy/partials/post-card.php

Step 2: Modify your copy

Open your-theme/jetonomy/partials/post-card.php and add your customization. The variable $post (a \Jetonomy\Models\Post object) is available inside the partial.

<?php
// your-theme/jetonomy/partials/post-card.php

// The $post variable is passed via Template_Loader::partial()
$is_sponsored = ( (int) $post->space_id === MY_SPONSORED_SPACE_ID );
?>

<div class="jt-row <?php echo $is_sponsored ? 'jt-row--sponsored' : ''; ?>">
    <?php if ( $is_sponsored ) : ?>
        <span class="my-sponsored-badge">Sponsored</span>
    <?php endif; ?>

    <?php
    // Continue with the original template output.
    // Tip: call Template_Loader::partial() for nested partials so they also
    // respect theme overrides.
    \Jetonomy\Template_Loader::partial( 'avatar', [ 'user_id' => $post->author_id ] );
    ?>

    <div class="jt-row__body">
        <a href="<?php echo esc_url( \Jetonomy\post_url( $post ) ); ?>">
            <?php echo esc_html( $post->title ); ?>
        </a>
    </div>
</div>

Step 3: Add styles

Add CSS to your theme for the new .jt-row--sponsored class. Reference Jetonomy's CSS tokens so your styles adapt to dark mode automatically:

/* your-theme/style.css or an enqueued stylesheet */

.jt-row--sponsored {
    border-left: 3px solid var(--jt-accent);
}

.my-sponsored-badge {
    display: inline-block;
    font-size: 0.75rem;
    color: var(--jt-text-secondary);
    background: var(--jt-accent-light);
    border-radius: var(--jt-radius-sm);
    padding: 2px 6px;
}

Calling Partials from Templates

Inside any view or partial, use Template_Loader::partial() instead of a raw include. This ensures the theme-override check runs for nested partials too:

// Inside your custom view or partial:
\Jetonomy\Template_Loader::partial( 'pagination', [
    'total'    => $total,
    'per_page' => 20,
    'page'     => $current_page,
] );

The second argument is passed as local variables to the partial (via extract()).


Available Variables in Templates

Templates receive route data via $data (array with route and slug keys). Most views also query the database directly at the top of the file. When you copy a template, review the top of the plugin's original file to understand which variables are set before the HTML output begins.

Common objects available in plugin templates:

Variable Type Available in
$data array All views
$space \Jetonomy\Models\Space space, space-members, new-post
$post \Jetonomy\Models\Post single-post, post-card partial
$reply \Jetonomy\Models\Reply reply-card partial
$user WP_User user-profile, edit-profile
$posts array home, space, search, tag
$settings array All views (from get_option('jetonomy_settings'))

The jetonomy_template_map Filter

For cases where you need to register a completely new route - or override the template for an existing route with a file stored outside the theme - use the jetonomy_template_map filter.

add_filter( 'jetonomy_template_map', function( array $map ): array {
    // Override an existing route with an absolute path.
    $map['leaderboard'] = get_stylesheet_directory() . '/jetonomy/views/leaderboard.php';

    // Register a brand-new route (accessible at /community/events/).
    $map['events'] = MY_PLUGIN_DIR . 'templates/community-events.php';

    return $map;
} );

Important: If you provide an absolute path (starting with /), the theme-override check is bypassed - the file you point to is loaded directly. This is the correct approach for Pro extensions and companion plugins that ship their own templates.

The Jetonomy Router must know about new routes before they can receive traffic. Register rewrite rules alongside the template map:

// Register a custom rewrite rule for /community/events/.
add_action( 'init', function() {
    $settings  = get_option( 'jetonomy_settings', [] );
    $base_slug = $settings['base_slug'] ?? 'community';

    add_rewrite_rule(
        '^' . preg_quote( $base_slug, '^' ) . '/events/?$',
        'index.php?jetonomy_route=events',
        'top'
    );
} );

// Teach WordPress to recognize the query var.
add_filter( 'query_vars', function( array $vars ): array {
    $vars[] = 'jetonomy_route';
    return $vars;
} );

After adding rewrite rules, flush permalinks once: go to Settings → Permalinks and click Save Changes, or run:

wp --path="/path/to/wordpress" rewrite flush

Child Theme Compatibility

If you are using a child theme, place overrides in the child theme directory - get_stylesheet_directory() resolves to the child theme path when a child theme is active. The plugin does not check the parent theme separately, so all overrides must live in the active (child) theme.


Pro Template Overrides

Jetonomy Pro registers its own templates for Private Messaging via the jetonomy_template_map filter using absolute paths. You can override Pro templates in your theme using the same directory structure:

your-theme/
└── jetonomy/
    └── views/
        ├── messages.php      # /community/messages/
        └── conversation.php  # /community/messages/{id}/

Place overrides here and they will be detected automatically because Pro's Template_Loader::partial() calls still respect the theme directory check for non-absolute paths.


What's Next?

Jetonomy includes eight shortcodes, four classic widgets, and eight Gutenberg blocks so you can embed community content anywhere on your WordPress site - sidebars, pages, posts, or block-based layouts.

What You Will Learn

  • How to use the eight built-in shortcodes and their attributes
  • How to add the four classic widgets to sidebar areas
  • How to insert the eight Gutenberg blocks in the block editor
  • How shortcodes and blocks share the same rendering logic
  • Which surfaces are block-only and which are shortcode-only

At a Glance

Type Slug Purpose Since
Shortcode [jetonomy_recent_posts] Recent posts feed 1.0
Shortcode [jetonomy_trending_posts] Hot-scored trending posts 1.3.0
Shortcode [jetonomy_spaces] Space directory grid 1.0
Shortcode [jetonomy_leaderboard] Top members by reputation 1.0
Shortcode [jetonomy_user_profile] Single user profile card 1.2
Shortcode [jetonomy_space_members] Members of one space 1.2
Shortcode [jetonomy_compose_topic] New in 1.3.7 - inline topic composer (fixed space or member picker) 1.3.7
Shortcode [jetonomy_widget] Embed any of the four classic widgets on a page or page-builder canvas 1.4.0
Block jetonomy/forum-feed Live post feed 1.3.0
Block jetonomy/trending Trending topics with time-decayed hot score 1.3.6
Block jetonomy/space-list Space grid 1.3.0
Block jetonomy/leaderboard Top members 1.3.0
Block jetonomy/navigation Permission-aware category + space tree 1.3.5
Block jetonomy/user-panel Logged-in sidebar profile card 1.3.5
Block jetonomy/login Inline login/register panel 1.3.5
Block jetonomy/compose-topic New in 1.3.7 - topic composer embeddable anywhere 1.3.7

Block-only vs shortcode-only

Most surfaces are available as both a block and a shortcode (Forum Feed, Trending, Space List, Leaderboard, Compose Topic). Three are available one way only:

  • Block-only (no shortcode twin): jetonomy/navigation, jetonomy/user-panel, jetonomy/login. To place these outside the block editor, add the block inside a reusable/synced pattern or a block-based template part.
  • Shortcode-only (no block twin): [jetonomy_user_profile], [jetonomy_space_members], [jetonomy_widget]. Use these in classic editors, page builders, and widget areas.

Shortcodes

All shortcodes are registered by Jetonomy\Shortcodes::register() and are available on any page or post.

Self-styling on any page (1.4.0+): every shortcode auto-enqueues assets/css/blocks.css at render time and ships its own --jtb-* token block, so a bare [jetonomy_recent_posts] paste on a regular WordPress page renders fully styled - no need to put it inside a Forum Feed block container. Works in classic editor, page builders (Elementor, Divi, Bricks, WPBakery), widget areas, and template parts.


[jetonomy_recent_posts]

Displays a list of the most recent published posts across your community or within a specific space.

Attributes

Attribute Type Default Description
count int 5 Number of posts to display
space_id int 0 Restrict to a space. 0 = all spaces
sort string latest latest or votes
[jetonomy_recent_posts count="5" space_id="3" sort="votes"]

Each post card shows the title, author name, space name, time ago, vote score, and reply count.


[jetonomy_trending_posts]

Displays a ranked list of "hot" posts using a time-decayed score of recent votes + replies.

Attributes

Attribute Type Default Description
count int 5 Number of posts to display
space_id int 0 Restrict to a space. 0 = all spaces
window int 7 Days of history used for the hot score
[jetonomy_trending_posts count="10" window="14"]

[jetonomy_spaces]

Displays a list of public, active spaces, ordered by post count.

Attributes

Attribute Type Default Description
count int 6 Number of spaces to display
category_id int 0 Filter by category. 0 = all categories
[jetonomy_spaces count="6" category_id="2"]

Each space card shows the title, a short description excerpt, and the post count.


[jetonomy_leaderboard]

Displays a ranked list of the top community members by reputation score.

Attributes

Attribute Type Default Description
count int 10 Number of members to display
[jetonomy_leaderboard count="10"]

[jetonomy_user_profile]

Displays a compact profile card for a specific user or the currently logged-in user.

Attributes

Attribute Type Default Description
user_id int 0 Target user. 0 = current logged-in user
[jetonomy_user_profile user_id="0"]

The card shows the display name, trust level badge, bio excerpt, reputation score, and post count.


[jetonomy_space_members]

Displays a list of members for a specific space, ordered by reputation.

Attributes

Attribute Type Default Description
space_id int - Required. ID of the space
count int 10 Number of members to display
[jetonomy_space_members space_id="5" count="20"]

[jetonomy_compose_topic] (new in 1.3.7)

Lets signed-in members start a new topic from any WordPress page, post, or page-builder canvas. Two modes: lock to one space, or show a picker of spaces the current user is a member of.

Attributes

Attribute Type Default Description
mode string picker picker (show a space select) or fixed (post to one space)
space_id int 0 Space ID to post into. Only used when mode="fixed". Invalid IDs degrade to picker at render time.
types CSV topic,question,idea Allowed post types for this embed
[jetonomy_compose_topic mode="picker"]
[jetonomy_compose_topic mode="fixed" space_id="5"]

Compose Topic shortcode rendered on a regular WordPress page

Behavior

  • Logged-out viewers see a "Sign in to start a new topic" CTA that redirects back to the current URL after login - no form exposure, no wasted scroll.
  • Picker mode queries Permission_Engine::can($uid, 'create_posts', $space_id) against every space the user is a member of. Only spaces where they actually have posting rights appear.
  • Fixed mode hides the picker entirely. If the hardcoded space_id is missing or the user cannot post in it, the embed silently degrades to picker mode rather than breaking.
  • Assets (blocks.css + the Interactivity API bundle) enqueue on-demand at render time so pages that don't use the shortcode carry no overhead. Works inside page builders that render shortcodes outside the_content (Elementor, Divi, Bricks, WPBakery).

Companion REST endpoint: GET /jetonomy/v1/spaces?postable_by_me=1 returns the user's postable spaces.

When the title is filled but the body is empty, an inline error banner appears above the title - no silent failures, no lost input:

Inline validation banner when the body is empty


Classic Widgets

Jetonomy registers four classic widgets for use in any theme widget area. Each widget is configured through the standard WordPress widget admin screen or the Customizer.

Recent Posts Widget

Displays recent forum posts in any sidebar or widget area.

Settings: Title, Count, Space (optional filter), Sort order

Leaderboard Widget

Displays top community contributors ranked by reputation.

Settings: Title, Count

Active Spaces Widget

Displays the most active spaces by post count.

Settings: Title, Count

User Stats Widget

Displays the currently logged-in user's stats: reputation, post count, reply count, and trust level.

Settings: Title (no other configuration - always reflects the current user)

[jetonomy_widget] shortcode (new in 1.4.0)

Each classic widget above can also be embedded directly into any page or page-builder canvas - without dropping into the Customizer or a sidebar - using the [jetonomy_widget] shortcode.

Attributes

Attribute Type Required Description
id string yes Widget id: jetonomy_recent_posts, jetonomy_leaderboard, jetonomy_active_spaces, or jetonomy_user_stats
title string no Override the widget's title (otherwise the widget's saved Customizer title or the default)
count int no For Recent Posts, Leaderboard, and Active Spaces
space_id int no For Recent Posts, optional space filter
sort string no For Recent Posts: latest or votes
[jetonomy_widget id="jetonomy_recent_posts" count="8" sort="latest"]
[jetonomy_widget id="jetonomy_leaderboard" count="10"]
[jetonomy_widget id="jetonomy_active_spaces" count="6"]
[jetonomy_widget id="jetonomy_user_stats" title="Your stats"]

Internally [jetonomy_widget] wraps WordPress core's the_widget() so the rendered markup matches what the same widget would output in a sidebar - same hooks, same CSS classes, same i18n. Useful for landing pages, footer columns, and page-builder canvases where the Customizer's sidebar widget area isn't available.


Gutenberg Blocks

Jetonomy registers eight server-side rendered blocks. Each block uses a render_callback that delegates to the matching shortcode (for most) or a dedicated render component (for Navigation, User Panel, and Login). Output is consistent wherever they appear.

All blocks live in the Widgets category of the block inserter and answer to the search term jet.

This is how the content blocks render on a published page - Forum Feed, Trending, Space List, and Leaderboard dropped onto a regular WordPress page. Because blocks and shortcodes share the same render path, the matching [jetonomy_*] shortcodes produce identical output:

Forum Feed, Trending, Spaces, and Leaderboard blocks rendered on a published WordPress page

Backend (editor) vs frontend (published) render (1.4.0+)

The two surfaces render differently - by design.

  • Backend (block editor) - each block paints a framed static preview card with a "JETONOMY" pill badge, the block title, and an attribute-aware hint that reflects the current settings (Filtered to space #3, 7 day window, All public spaces, etc.). No REST calls fire. Dropping a block onto a page is instant; switching between Visual and Code editors does not trigger a network roundtrip. The preview is a mock - what the editor shows is not the actual queried data.
  • Frontend (published page) - the block's PHP render_callback runs against the live database on every request. Output is the same markup the matching [jetonomy_*] shortcode produces, with the block's wp-block-jetonomy-* wrapper class applied. Output is permission-aware: private spaces, banned authors, and silenced posts are filtered exactly as they would be on a regular community page.

Reason for the split: a live-data preview in the editor would (a) hammer the REST API on every keystroke in the title field, (b) leak permission-gated content to anyone who can edit the post, and (c) require a working REST connection at edit time. The static-card pattern mirrors what core blocks like Latest Posts do at the editor level, with the exception that core's render path can hit useEntityRecords() cheaply because the data is already cached client-side.

Each block exposes its settings through Inspector controls in the right sidebar, sized at the WordPress 6.7+ default (40px) with no deprecated bottom margins. The controls map one-to-one to the block attributes documented per block below.

Block inserter visibility was tightened in 1.4.0 - every block now registers an editor-side script (assets/js/blocks-editor.js) so all eight blocks appear in the inserter at once. Pre-1.4.0 only Compose Topic was visible because it was the only block carrying its own editor_script.

In the block editor each block paints the same lightweight preview card - a JETONOMY badge, the block name, and a hint that reflects the current settings (All public spaces, 7 day window, Categories → spaces tree, permission-aware) - so you can lay out a page without firing a single REST call:

Jetonomy blocks shown as static preview cards in the Gutenberg block editor

jetonomy/forum-feed

Renders a live post feed from a selected space or all spaces.

Block Attributes

Attribute Type Default Description
count number 5 Posts to show
spaceId number 0 Space ID (0 = all spaces)
sort string latest latest or votes
showHeader boolean false Render a space header above the feed
title string '' Custom title when showHeader is on

jetonomy/trending (1.3.6+)

Renders a ranked list of hot topics using a time-decayed score of recent engagement. Same render_callback plumbing as [jetonomy_trending_posts].

Block Attributes

Attribute Type Default Description
count number 5 Posts to show
spaceId number 0 Restrict to a space (0 = all)
window number 7 Days of history for the hot score
showHeader boolean true Render a "Trending" header
title string '' Custom title

jetonomy/space-list

Renders a list of community spaces. Supports category filtering.

Block Attributes

Attribute Type Default Description
count number 6 Spaces to show
categoryId number 0 Filter by category (0 = all)

jetonomy/leaderboard

Renders a leaderboard of top community members by reputation.

Block Attributes

Attribute Type Default Description
count number 10 Members to show

jetonomy/navigation (1.3.5+)

Renders the Category → Space tree as permission-aware sidebar navigation. Designed for the community sidebar of any block theme or widget area.

Why this block exists

Most community themes render the space list with a hand-maintained nav menu. That list rots the moment you add a space, and it leaks private spaces to anonymous viewers. This block queries the live category/space tree on every render and honors Jetonomy's permission layer, so private spaces stay hidden from viewers who do not have access.

Block Attributes

Attribute Type Default Description
showCategoryHeadings boolean true Group spaces by parent category
collapsible boolean false Collapsible category headings
showPostCount boolean false Show topic count next to each space
hideEmptyCategories boolean true Hide categories that have no visible spaces
title string '' Optional wrapper title

Scales to sites with thousands of spaces - the rendered tree uses Jetonomy's cached category/space index, not a per-request DB scan.

This block is block-only - there is no shortcode twin - so the rendered output is shown here:

Jetonomy Navigation block rendered in a community sidebar as a permission-aware Category to Space tree


jetonomy/user-panel (1.3.5+)

Renders a compact profile card for logged-in viewers - avatar, display name, notifications count, quick links to Profile / Notifications / Messages / Edit Profile / Logout. Empty for logged-out viewers so the sidebar layout doesn't shift.

Jetonomy User Panel block showing a logged-in member's avatar, name, notifications count, and quick links

Block Attributes

Attribute Type Default Description
title string '' Optional wrapper title above the card

Auto-injects at the top of the community sidebar for logged-in viewers so admins don't need to add it by hand (disable with add_filter( 'jetonomy_sidebar_auth_card', '__return_false' )).


jetonomy/login (1.3.5+)

Renders an inline login and register panel for the community sidebar. Logged-out viewers see Login and Register tabs without leaving the page. Logged-in viewers get nothing rendered - no layout shift when state changes.

Jetonomy Login block showing the Login and Register tabs rendered inline on a community page

Block Attributes

Attribute Type Default Description
title string '' Header above the tabs
showRegister boolean true Show the Register tab alongside Login (honours users_can_register)

Security

  • Both forms are nonce-protected (wp_ajax_jetonomy_quick_login / wp_ajax_jetonomy_quick_register)
  • Failed login attempts are rate-limited via Jetonomy\Security\Rate_Limiter (5 attempts / 15 minutes per IP)
  • Registration respects whatever users_can_register is set to in your WP admin and any anti-spam adapter you have active (Akismet, AI spam detection)

jetonomy/compose-topic (new in 1.3.7)

Gutenberg equivalent of [jetonomy_compose_topic]. Drop it on any page, post, or template part and signed-in members can start a topic without leaving the page.

Block Attributes

Attribute Type Default Description
mode string picker picker or fixed
spaceId number 0 Space ID (fixed mode only)
types string topic,question,idea Allowed post types

Editor experience

Compose Topic block in the Gutenberg editor

  • The block editor shows a static preview (no live REST calls) - safe to drop into any page without hitting the server.
  • Inspector controls: Mode select (picker / fixed), Space ID (visible only when Mode is fixed), Allowed types (comma-separated).
  • Falls back to picker mode at render time if the fixed spaceId doesn't resolve to a space the viewer can post in - so themes/pages that were built before a space was deleted keep working instead of 500'ing.

Rendering

  • Server render delegates to [jetonomy_compose_topic], so the block + shortcode output are pixel-identical.
  • Styles come from assets/css/blocks.css - self-contained, inherits theme tokens through --wp--preset--* fallbacks so it looks correct outside Jetonomy templates.
  • Built-in mobile breakpoint at 640px - submit button spans the column width, actions stack vertically.

CSS Classes for Styling

All shortcode and block output uses the jt-shortcode CSS class prefix so you can style them in your theme without affecting core community pages:

Class Element
.jt-shortcode Wrapper on all shortcode output
.jt-shortcode-recent-posts Recent posts container
.jt-shortcode-post Individual post card
.jt-shortcode-post-title Post title link
.jt-shortcode-post-meta Author, space, and time line
.jt-shortcode-post-stats Vote and reply counts
.jt-shortcode-spaces Spaces container
.jt-shortcode-space Individual space card
.jt-shortcode-space-desc Space description excerpt
.jt-shortcode-space-stats Space post-count line
.jt-shortcode-trending-post Trending post row
.jt-shortcode-trending-rank Trending rank badge (1, 2, 3 …)
.jt-shortcode-trending-body Trending row body (title + meta + stats)
.jt-shortcode-leaderboard Leaderboard container
.jt-shortcode-rep Reputation pill in leaderboard / member rows
.jt-shortcode-profile-card User profile card
.jt-shortcode-profile-stats Reputation + post-count line on profile card
.jt-shortcode-members Members list container
.jt-shortcode-member Individual member row
.jt-shortcode-empty Empty state message
.jt-compose-topic-embed Compose-topic shortcode/block wrapper
.jt-compose-topic-embed.jt-compose-topic-login Logged-out sign-in CTA variant
.jt-compose-topic-field Label + input group
.jt-compose-topic-space Space picker <select>
.jt-compose-topic-title Title <input>
.jt-compose-topic-body Details <textarea>
.jt-compose-topic-submit Post topic button
.jt-compose-topic-error Inline error banner (shown via state.submitError)
.jt-compose-topic-posting-to "Posting in …" line in fixed mode

Building Companion Shortcodes or Blocks

If you are building a companion plugin that needs to query Jetonomy data, guard your code with a class existence check:

if ( ! defined( 'JETONOMY_VERSION' ) ) {
    return;
}

Use the model classes for server-side rendering or the REST API for client-side fetches. See the REST API Reference for available endpoints.


What's Next?

Jetonomy uses a universal adapter pattern for every external integration point. Instead of hard-coding a dependency on a specific search engine, email provider, membership plugin, or AI provider, each integration is represented by a PHP interface. You implement the interface, register your adapter, and Jetonomy uses it everywhere.

All adapters are managed through the static Adapter_Registry class (includes/adapters/class-adapter-registry.php).


The Four Adapter Types

Interface Class (namespace Jetonomy\Adapters\) What it controls
Search_Adapter interface-search-adapter.php Full-text search for posts, replies, spaces
Email_Adapter interface-email-adapter.php Outbound notification emails
Membership_Adapter interface-membership-adapter.php Membership level checks and gating
AI_Adapter interface-ai-adapter.php AI chat completions and embeddings (text generation, moderation, semantic features)

Built-in Adapters (Free)

Adapter Class Type Active When
Fulltext_Search (Jetonomy\Search\) Search Always (MySQL FULLTEXT - built-in)
WP_Mail_Adapter Email Always (uses wp_mail())
WP_Roles_Adapter Membership Always (WP role-based membership fallback)
MemberPress_Adapter Membership MemberPress plugin is active
PMPro_Adapter Membership Paid Memberships Pro is active
Ollama_AI_Adapter AI A local Ollama endpoint is configured

Pro Adapters (Jetonomy Pro)

Adapter Class Type Active When
WooCommerce_Adapter Membership WooCommerce Memberships is active
RCP_Adapter Membership Restrict Content Pro is active
LearnDash_Adapter Membership LearnDash is active (4.x and 5.x)
Tutor_Adapter Membership Tutor LMS is active
LifterLMS_Adapter Membership LifterLMS is active
Sensei_Adapter Membership Sensei LMS is active
MasterStudy_Adapter Membership MasterStudy LMS is active
OpenAI_AI_Adapter AI The AI extension is enabled with an OpenAI provider configured
Anthropic_AI_Adapter AI The AI extension is enabled with an Anthropic provider configured
Custom_AI_Adapter AI The AI extension is enabled with a custom OpenAI-compatible provider configured

Pro registers membership adapters via Adapter_Registry::register_membership() and AI adapters via Adapter_Registry::register_ai() at plugins_loaded priority 20.


Adapter_Registry API

// Register adapters.
\Jetonomy\Adapters\Adapter_Registry::register_search( 'my-search', $adapter );
\Jetonomy\Adapters\Adapter_Registry::register_email( 'my-mailer', $adapter );
\Jetonomy\Adapters\Adapter_Registry::register_membership( 'my-membership', $adapter );
\Jetonomy\Adapters\Adapter_Registry::register_ai( 'my-ai', $adapter );

// Retrieve the active adapter (first registered adapter where is_active() returns true).
$search     = \Jetonomy\Adapters\Adapter_Registry::get_search();
$email      = \Jetonomy\Adapters\Adapter_Registry::get_email();
$membership = \Jetonomy\Adapters\Adapter_Registry::get_membership();
$ai         = \Jetonomy\Adapters\Adapter_Registry::get_ai();

// Retrieve a specific adapter by ID.
$mp     = \Jetonomy\Adapters\Adapter_Registry::get_membership( 'memberpress' );
$openai = \Jetonomy\Adapters\Adapter_Registry::get_ai( 'openai' );

// List all registered membership / AI adapters.
$all    = \Jetonomy\Adapters\Adapter_Registry::get_all_membership();
$all_ai = \Jetonomy\Adapters\Adapter_Registry::get_all_ai();

The Registry returns null when no active adapter is found for a type - always null-check before calling methods.

Registration timing: Register your adapters at plugins_loaded. Use priority 9 if you want your adapter to override a built-in default (e.g. replacing built-in search). Use priority 15 for additive adapters that do not need to override defaults (e.g. adding a new membership source):

add_action( 'plugins_loaded', function() {
    if ( ! class_exists( '\Jetonomy\Adapters\Adapter_Registry' ) ) {
        return; // Jetonomy not active.
    }
    \Jetonomy\Adapters\Adapter_Registry::register_search(
        'meilisearch',
        new My_Plugin\Meilisearch_Adapter()
    );
}, 15 );

Search Adapter Interface

namespace Jetonomy\Adapters;

interface Search_Adapter {
    /** Return true when this adapter is ready to handle queries. */
    public function is_active(): bool;

    /** Index a document. Called when a post or reply is created or updated. */
    public function index( string $object_type, int $object_id, array $data ): void;

    /**
     * Execute a search query.
     *
     * @param string   $query      The search string.
     * @param string   $type       'post', 'reply', or 'space'.
     * @param int|null $space_id   Optional space filter.
     * @param int      $limit      Max results (default 20).
     * @param int      $offset     Pagination offset.
     * @return array               Array of result objects with at least: id, title (posts/spaces) or content (replies).
     */
    public function search( string $query, string $type, ?int $space_id, int $limit, int $offset ): array;

    /** Remove a document from the index. Called when a post or reply is deleted. */
    public function delete( string $object_type, int $object_id ): void;
}

Example: Custom Elasticsearch Adapter

<?php
namespace My_Plugin;

use Jetonomy\Adapters\Search_Adapter;

class Elasticsearch_Adapter implements Search_Adapter {

    private \Elasticsearch\Client $client;

    public function __construct() {
        // Build your Elasticsearch client here.
        $this->client = \Elasticsearch\ClientBuilder::create()
            ->setHosts( [ get_option( 'my_plugin_es_host', 'localhost:9200' ) ] )
            ->build();
    }

    public function is_active(): bool {
        // Only activate when the Elasticsearch host option is set and the client connects.
        $host = get_option( 'my_plugin_es_host' );
        return ! empty( $host ) && $this->client->ping();
    }

    public function index( string $object_type, int $object_id, array $data ): void {
        $this->client->index( [
            'index' => 'jetonomy_' . $object_type,
            'id'    => $object_id,
            'body'  => $data,
        ] );
    }

    public function search( string $query, string $type, ?int $space_id, int $limit, int $offset ): array {
        $must = [
            [ 'multi_match' => [ 'query' => $query, 'fields' => [ 'title^3', 'content' ] ] ],
        ];

        if ( $space_id ) {
            $must[] = [ 'term' => [ 'space_id' => $space_id ] ];
        }

        $params = [
            'index' => 'jetonomy_' . $type,
            'body'  => [
                'query' => [ 'bool' => [ 'must' => $must ] ],
                'from'  => $offset,
                'size'  => $limit,
            ],
        ];

        $raw = $this->client->search( $params );

        // Map Elasticsearch hits to the flat object array Jetonomy expects.
        return array_map(
            fn( $hit ) => (object) array_merge( $hit['_source'], [ 'id' => (int) $hit['_id'] ] ),
            $raw['hits']['hits'] ?? []
        );
    }

    public function delete( string $object_type, int $object_id ): void {
        $this->client->delete( [
            'index' => 'jetonomy_' . $object_type,
            'id'    => $object_id,
        ] );
    }
}

Register it:

add_action( 'plugins_loaded', function() {
    if ( ! class_exists( '\Jetonomy\Adapters\Adapter_Registry' ) ) {
        return;
    }
    \Jetonomy\Adapters\Adapter_Registry::register_search(
        'elasticsearch',
        new My_Plugin\Elasticsearch_Adapter()
    );
}, 15 );

Jetonomy will call is_active() on every registered search adapter and use the first one that returns true. Because the built-in Fulltext_Search adapter always returns true, register your custom adapter before the defaults are initialized - or override it by making sure your adapter is registered first.

The built-in defaults are initialized at plugins_loaded priority 10 via Adapter_Registry::init_defaults(). Registering at priority 15 means your adapter is added after the defaults, but since get_search() iterates in insertion order, you need to register at priority 9 if you want your adapter to take precedence:

add_action( 'plugins_loaded', function() {
    // Priority 9 - runs before Jetonomy's init_defaults() at priority 10.
    \Jetonomy\Adapters\Adapter_Registry::register_search( 'elasticsearch', new My_Plugin\Elasticsearch_Adapter() );
}, 9 );

Email Adapter Interface

namespace Jetonomy\Adapters;

interface Email_Adapter {
    public function is_active(): bool;

    /**
     * Send a single transactional email.
     *
     * @param string   $to            Recipient email address.
     * @param string   $subject       Email subject line.
     * @param string   $html          HTML body.
     * @param string   $plain         Plain-text fallback.
     * @param string[] $extra_headers Additional mail headers.
     * @return bool True on success.
     */
    public function send( string $to, string $subject, string $html, string $plain, array $extra_headers = [] ): bool;

    /**
     * Send a batch of emails.
     *
     * @param array $messages Array of ['to', 'subject', 'html', 'plain'] arrays.
     * @return array          Results array indexed by recipient.
     */
    public function send_batch( array $messages ): array;

    /** Register any hooks needed (e.g. intercepting wp_mail for logging). */
    public function register_hooks(): void;
}

Example: Postmark Adapter

class Postmark_Adapter implements \Jetonomy\Adapters\Email_Adapter {

    public function is_active(): bool {
        return ! empty( get_option( 'my_plugin_postmark_token' ) );
    }

    public function send( string $to, string $subject, string $html, string $plain, array $extra_headers = [] ): bool {
        $token = get_option( 'my_plugin_postmark_token' );
        $from  = get_option( 'admin_email' );

        $response = wp_remote_post( 'https://api.postmarkapp.com/email', [
            'headers' => [
                'Accept'                  => 'application/json',
                'Content-Type'            => 'application/json',
                'X-Postmark-Server-Token' => $token,
            ],
            'body' => wp_json_encode( [
                'From'     => $from,
                'To'       => $to,
                'Subject'  => $subject,
                'HtmlBody' => $html,
                'TextBody' => $plain,
            ] ),
        ] );

        return ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response );
    }

    public function send_batch( array $messages ): array {
        $results = [];
        foreach ( $messages as $msg ) {
            $results[ $msg['to'] ] = $this->send( $msg['to'], $msg['subject'], $msg['html'], $msg['plain'] );
        }
        return $results;
    }

    public function register_hooks(): void {
        // Optional - intercept wp_mail if you want to route ALL site email through Postmark.
    }
}

Membership Adapter Interface

namespace Jetonomy\Adapters;

interface Membership_Adapter {
    public function is_active(): bool;

    /** Return all active membership level IDs for a user. */
    public function get_user_levels( int $user_id ): array;

    /** Check whether a user has a specific membership level. */
    public function user_has_level( int $user_id, string $level_id ): bool;

    /** Return all available membership levels as ['id' => ..., 'name' => ...] objects. */
    public function get_all_levels(): array;

    /** Return the human-readable label for a level ID. */
    public function get_level_label( string $level_id ): string;

    /** Register any hooks needed for lifecycle events (e.g. activation/deactivation). */
    public function register_hooks(): void;
}

The register_hooks() method is where you fire jetonomy_membership_activated and jetonomy_membership_deactivated - see 02-hooks-reference.md.

Example: Custom Membership Adapter

class My_Membership_Adapter implements \Jetonomy\Adapters\Membership_Adapter {

    public function is_active(): bool {
        return defined( 'MY_MEMBERSHIP_VERSION' );
    }

    public function get_user_levels( int $user_id ): array {
        return (array) get_user_meta( $user_id, 'my_membership_levels', true );
    }

    public function user_has_level( int $user_id, string $level_id ): bool {
        return in_array( $level_id, $this->get_user_levels( $user_id ), true );
    }

    public function get_all_levels(): array {
        return my_membership_get_all_plans(); // Your own function.
    }

    public function get_level_label( string $level_id ): string {
        return my_membership_get_plan_name( $level_id ) ?? $level_id;
    }

    public function register_hooks(): void {
        // Fire Jetonomy's membership hooks so space access is updated automatically.
        add_action( 'my_membership_activated', function( int $user_id, string $plan_id ) {
            do_action( 'jetonomy_membership_activated', $user_id, $plan_id );
        }, 10, 2 );

        add_action( 'my_membership_cancelled', function( int $user_id, string $plan_id ) {
            do_action( 'jetonomy_membership_deactivated', $user_id, $plan_id );
        }, 10, 2 );
    }
}

AI Adapter Interface

namespace Jetonomy\Adapters;

interface AI_Adapter {
    /** Whether this adapter is configured and ready. */
    public function is_active(): bool;

    /** Unique provider identifier (e.g. 'openai', 'anthropic', 'ollama'). */
    public function get_id(): string;

    /** Human-readable provider name. */
    public function get_name(): string;

    /**
     * Send a chat completion request.
     *
     * @param array $messages Array of ['role' => 'system'|'user'|'assistant', 'content' => string].
     * @param array $options  Optional: model, temperature, max_tokens, json_mode.
     * @return array{content: string, usage: array{prompt_tokens: int, completion_tokens: int, total_tokens: int}, model: string}
     * @throws \RuntimeException On API failure.
     */
    public function chat( array $messages, array $options = [] ): array;

    /**
     * Generate embeddings for text.
     *
     * @param string $text    Input text.
     * @param array  $options Optional: model.
     * @return array{embedding: float[], model: string, usage: array{total_tokens: int}}
     * @throws \RuntimeException On API failure or if provider does not support embeddings.
     */
    public function embed( string $text, array $options = [] ): array;

    /** Return supported models as id => display_name. */
    public function get_models(): array;

    /** Test the connection (validates API key + reachability). Returns ['ok' => bool, 'error'? => string, 'model'? => string]. */
    public function test(): array;
}

The built-in Ollama_AI_Adapter (free) talks to a local Ollama endpoint and activates only when one is configured. Jetonomy Pro's AI extension registers OpenAI_AI_Adapter, Anthropic_AI_Adapter, and Custom_AI_Adapter (any OpenAI-compatible endpoint). Adapter_Registry::get_ai() returns the first registered adapter whose is_active() returns true; pass an explicit ID to target a specific provider.

Example: Custom AI Adapter

class My_AI_Adapter implements \Jetonomy\Adapters\AI_Adapter {

    public function is_active(): bool {
        return ! empty( get_option( 'my_plugin_ai_key' ) );
    }

    public function get_id(): string {
        return 'my-ai';
    }

    public function get_name(): string {
        return 'My AI Provider';
    }

    public function chat( array $messages, array $options = [] ): array {
        $response = wp_remote_post( 'https://api.example.com/v1/chat', [
            'headers' => [
                'Authorization' => 'Bearer ' . get_option( 'my_plugin_ai_key' ),
                'Content-Type'  => 'application/json',
            ],
            'body' => wp_json_encode( [
                'model'    => $options['model'] ?? 'default',
                'messages' => $messages,
            ] ),
        ] );

        if ( is_wp_error( $response ) ) {
            throw new \RuntimeException( $response->get_error_message() );
        }

        $body = json_decode( wp_remote_retrieve_body( $response ), true );

        return [
            'content' => $body['choices'][0]['message']['content'] ?? '',
            'usage'   => $body['usage'] ?? [ 'prompt_tokens' => 0, 'completion_tokens' => 0, 'total_tokens' => 0 ],
            'model'   => $body['model'] ?? ( $options['model'] ?? 'default' ),
        ];
    }

    public function embed( string $text, array $options = [] ): array {
        throw new \RuntimeException( 'Embeddings not supported.' );
    }

    public function get_models(): array {
        return [ 'default' => 'Default Model' ];
    }

    public function test(): array {
        return $this->is_active()
            ? [ 'ok' => true ]
            : [ 'ok' => false, 'error' => 'API key not configured.' ];
    }
}

Connecting Adapters to Jetonomy Events

Adapters do not self-wire - you need to connect them to Jetonomy's lifecycle hooks to trigger indexing, emailing, or broadcasting at the right time.

Search: Index content on create/update

add_action( 'jetonomy_after_create_post', function( int $post_id, int $space_id ) {
    $search = \Jetonomy\Adapters\Adapter_Registry::get_search();
    if ( ! $search ) return;

    $post = \Jetonomy\Models\Post::find( $post_id );
    if ( $post ) {
        $search->index( 'post', $post_id, [
            'title'      => $post->title,
            'content'    => wp_strip_all_tags( $post->content ),
            'space_id'   => $post->space_id,
            'author_id'  => $post->author_id,
            'created_at' => $post->created_at,
        ] );
    }
}, 10, 2 );

add_action( 'jetonomy_post_deleted', function( int $post_id ) {
    $search = \Jetonomy\Adapters\Adapter_Registry::get_search();
    $search?->delete( 'post', $post_id );
} );

AI: Summarize a new post on demand

add_action( 'jetonomy_after_create_post', function( int $post_id, int $space_id ) {
    $ai = \Jetonomy\Adapters\Adapter_Registry::get_ai();
    if ( ! $ai ) return;

    $post = \Jetonomy\Models\Post::find( $post_id );
    if ( $post ) {
        $result = $ai->chat( [
            [ 'role' => 'system', 'content' => 'Summarize the following topic in one sentence.' ],
            [ 'role' => 'user',   'content' => wp_strip_all_tags( $post->content ) ],
        ] );
        // Persist $result['content'] wherever you need it.
    }
}, 10, 2 );

Summary: Registration Cheat Sheet

add_action( 'plugins_loaded', function() {
    if ( ! class_exists( '\Jetonomy\Adapters\Adapter_Registry' ) ) {
        return;
    }

    // Search - replace built-in MySQL FULLTEXT.
    \Jetonomy\Adapters\Adapter_Registry::register_search(
        'meilisearch',
        new My_Plugin\Meilisearch_Adapter()
    );

    // Email - replace wp_mail for notification emails.
    \Jetonomy\Adapters\Adapter_Registry::register_email(
        'postmark',
        new My_Plugin\Postmark_Adapter()
    );

    // Membership - add a custom membership source.
    $adapter = new My_Plugin\My_Membership_Adapter();
    $adapter->register_hooks();
    \Jetonomy\Adapters\Adapter_Registry::register_membership( 'my-membership', $adapter );

    // AI - add a custom AI provider for chat completions / embeddings.
    \Jetonomy\Adapters\Adapter_Registry::register_ai(
        'my-ai',
        new My_Plugin\My_AI_Adapter()
    );
}, 9 ); // Priority 9 ensures search adapter runs before built-in defaults at priority 10.

What's Next?

Developer reference for the FluentCommunity coexistence integration shipped in Jetonomy 1.3.8. This page is for plugin/theme developers extending or debugging the integration. End users should start with the FluentCommunity integration guide.

What You Will Learn

  • Where the integration lives and when it loads
  • Which WordPress options persist its state
  • Which FluentCommunity and Jetonomy hooks it consumes
  • Which helpers you can reuse from your own code
  • How loop protection, identity keying, and stale-pair handling work

File Layout

The entire integration lives in one class:

includes/integrations/class-fluent-community.php

Loaded from includes/class-jetonomy.php only when FluentCommunity is active:

if ( class_exists( '\\FluentCommunity\\App\\App' ) ) {
    require_once JETONOMY_DIR . 'includes/integrations/class-fluent-community.php';
    new Integrations\Fluent_Community();
}

No autoload entry beyond this gate. Deactivate FluentCommunity and nothing from this file is parsed or instantiated.

Persisted State

Four WordPress options hold the entire integration footprint. No custom tables, no post meta, no user meta.

Option Type Default Purpose
jetonomy_fc_space_pairs array {fc_space_id: jt_space_id} [] Space pairing map. One row holds every pair.
jetonomy_fc_tab_label string Discussions Label used on the FC tab, the Jetonomy sidebar card, and the FC profile Discussions block.
jetonomy_fc_sync_members '1' / '0' '1' Toggle for bidirectional member sync.
jetonomy_fc_broadcast '1' / '0' '1' Toggle for topic broadcast to the paired FC feed.

All four options are removed on uninstall by Jetonomy's standard jetonomy_* option sweep in uninstall.php.

Reading the pair map

$pairs = get_option( 'jetonomy_fc_space_pairs', array() );
if ( is_array( $pairs ) ) {
    foreach ( $pairs as $fc_space_id => $jt_space_id ) {
        // Use as needed. Both IDs are integers when the map is valid.
    }
}

Reverse lookup

To find the Jetonomy space paired with a given FC space (or the reverse), walk the map:

$fc_id_for_jt = function ( int $jt_id ) {
    $pairs = get_option( 'jetonomy_fc_space_pairs', array() );
    if ( ! is_array( $pairs ) ) {
        return 0;
    }
    foreach ( $pairs as $fc => $jt ) {
        if ( (int) $jt === $jt_id ) {
            return (int) $fc;
        }
    }
    return 0;
};

FluentCommunity Hooks Consumed

Hook Type Surface
get_avatar_url (core WP) filter Unifies the avatar across both sides by reading wp_fcom_xprofile.avatar keyed on user_id.
fluent_community/space_header_links filter Appends the Discussions tab to the FC space header.
fluent_community/activity/after_contents_user filter Renders the Discussions block on the FC profile.
fluent_community/space/joined action Triggers member sync from FC to Jetonomy.
fluent_community/comment_added action Triggers the comment-to-reply bridge on broadcast feed comments.

All FC hook names were verified against FluentCommunity 2.3.0.

Jetonomy Hooks Consumed

Hook Type Surface
jetonomy_admin_settings_tabs action Registers the FluentCommunity settings tab.
jetonomy_admin_settings_tab_content action Renders the tab body when active.
jetonomy_sidebar_after_about action Renders the "Also on {community}" sidebar card on paired Jetonomy spaces.
jetonomy_profile_after_stats action Renders the cross-link to the member's FluentCommunity profile.
jetonomy_user_joined_space action Triggers member sync from Jetonomy to FC.
jetonomy_after_create_post action Triggers the broadcast of a new topic to the paired FC feed.

Identity Keying

Everything joins on user_id, never on username. user_id is the primary key in both wp_fcom_xprofile and wp_jt_user_profiles, so the integration stays correct no matter how usernames diverge across the two plugins.

The integration ships a static helper to map user_id to the FC username for URL construction:

// Private in the integration class. Shape reproduced here for reference.
// Returns null when the user has no FC xprofile row.
fc_username_for_user( int $user_id ): ?string

If you need this elsewhere, query wp_fcom_xprofile.username by user_id directly. The result is request-scoped cached inside the integration class.

Community Name Helper

fc_site_title(): string reads FC's configured site_title from the fluent_community_settings option and falls back to the WP site name, then to the translated string Community. This is what drives the dynamic button and card labels. Reuse the same option key if you are rendering your own cross-links:

$settings = get_option( 'fluent_community_settings', array() );
$title    = is_array( $settings ) && ! empty( $settings['site_title'] )
    ? (string) $settings['site_title']
    : get_bloginfo( 'name' );

Loop Protection

Member sync and broadcast use a static $syncing flag so a join or post on one side never triggers a boomerang write back:

// Pseudocode matching the real implementation.
if ( self::$syncing ) {
    return;
}
self::$syncing = true;
try {
    // Write to the other side.
} finally {
    self::$syncing = false;
}

For the comment-to-reply bridge, only comments on broadcast feed posts round-trip. Broadcast feed rows are tagged with a meta marker when Jetonomy creates them, and the bridge listens only for comments on rows carrying that marker. Native FC feed posts never create Jetonomy replies.

Stale Pair Handling

At render time, every surface re-resolves the paired space ID. If the referenced FC or Jetonomy space no longer exists (deleted, trashed, or the pair option references an invalid ID), the tab or card silently disappears and no admin cleanup is required. The integration never fatals on a stale pair.

Add-Only Semantics

Member sync is deliberately add-only:

  • Joins propagate in both directions.
  • Leaves do not propagate. Removing yourself from one side never yanks you out of the other.
  • Role changes do not propagate. Each plugin manages its own role structure.

If you build on top of this integration and need leave-sync or role-sync behaviour, do it in a separate extension with an explicit per-pair toggle and a visible admin warning. The defaults stay add-only to avoid accidental bulk removals.

Privacy Guard

Topics marked as private (is_private = 1) are never broadcast to FluentCommunity. The FC feed audience can be broader than the private-topic scope, so the guard prevents leaking private content to a wider audience. If you add your own broadcast surfaces on top, apply the same guard:

if ( ! empty( $post->is_private ) ) {
    return; // Skip broadcast.
}

REST Architecture Note

FluentCommunity ships as a Vue SPA consuming its REST API. All the PHP filters the integration uses run inside REST response preparation, and their output flows through to the SPA render automatically. No Jetonomy-side REST additions or JS injection are needed for v1 of the integration.

Verified against live FC endpoints at build time:

Endpoint Filter that lands output in SPA
GET /fluent-community/v2/spaces/{slug}/by-slug fluent_community/space_header_links populates header_links
GET /fluent-community/v2/profile/{username} fluent_community/profile_view_data populates profile_navs (not used in v1)
GET /fluent-community/v2/activities?... fluent_community/activity/after_contents_user appends to the user activity view

Extending

Want to build on top? Two clean extension points:

  • Listen for the broadcast. The integration calls fluent_community/feed/created after creating the FC feed row, so your code can react to broadcasts with your own handler.
  • Replace a surface. Because every render hook exits early when its pair resolves to nothing, you can remove the integration's handler from jetonomy_sidebar_after_about (priority 10) and register your own without code-level conflicts.

Destructive extensions (leave-sync, role-sync, privacy mirroring) belong in a Pro extension with explicit per-pair toggles and a backfill tool, not as drop-in replacements for the free integration.

Developer reference for the BuddyPress coexistence integration. This page is for plugin/theme developers extending or debugging the integration. End users should start with the BuddyPress integration guide.

What You Will Learn

  • Where the integration lives and when it loads
  • What state persists (group meta + options) and where
  • Which BuddyPress and Jetonomy hooks the integration consumes
  • How the activity broadcast and comment-to-reply bridge work, and how to extend them
  • How loop protection, identity keying, and stale-pair handling are implemented

File Layout

The integration lives in a single class:

includes/integrations/class-buddypress.php

Loaded from includes/class-jetonomy.php only when the BuddyPress Groups component is active:

if ( function_exists( 'bp_is_active' ) && bp_is_active( 'groups' ) ) {
    require_once JETONOMY_DIR . 'includes/integrations/class-buddypress.php';
    new Integrations\BuddyPress();
}

The broadcast and comment-bridge methods additionally gate themselves on bp_is_active( 'activity' ) at runtime, so a BP install with Groups but not Activity stays fatal-free.

Persisted State

Where Key Type Purpose
BP group meta jetonomy_space_id int Points a group at its paired Jetonomy space. One value per group.
WP option jetonomy_bp_broadcast '1' / '0' Toggle for JT topic → BP group activity broadcast. Defaults on.
WP option jetonomy_bp_comment_bridge '1' / '0' Toggle for BP activity comment → JT reply bridge. Defaults on.
BP activity meta jetonomy_post_id int Tags a broadcast activity row with its originating Jetonomy post ID. The comment bridge reads this to decide which activity comments should round-trip as JT replies.

Class constants

BuddyPress::META_KEY              = 'jetonomy_space_id';
BuddyPress::OPT_BROADCAST         = 'jetonomy_bp_broadcast';
BuddyPress::OPT_COMMENT_BRIDGE    = 'jetonomy_bp_comment_bridge';
BuddyPress::ACTIVITY_META_POST    = 'jetonomy_post_id';
BuddyPress::ACTIVITY_TYPE         = 'jetonomy_topic';

Reading the pair

$space_id = (int) groups_get_groupmeta( $group_id, \Jetonomy\Integrations\BuddyPress::META_KEY, true );

Reverse lookup

$group_id = \Jetonomy\Integrations\BuddyPress::find_group_by_space( $space_id );

This runs a single meta-keyed query, no get_posts() loop.

BuddyPress Hooks Consumed

Group lifecycle

Hook Handler Note
groups_created_group on_group_created + save_group_forum_settings_on_create Reads the jt_bp_forum_action form field ('create', 'link_{id}', 'none'). Only creates a new space when explicitly requested.
groups_delete_group on_group_deleted Unlinks the space. Space itself is preserved.
groups_details_updated on_group_updated Syncs name, description, and visibility (public/private/hidden) to the paired space.

Member sync

Hook Handler Direction
groups_join_group on_member_join BP → JT
groups_leave_group on_member_leave BP → JT
groups_remove_member on_member_leave BP → JT
groups_ban_member on_member_leave BP → JT
groups_unban_member on_member_join BP → JT
groups_promote_member on_member_promote BP → JT (admin/mod)
groups_demote_member on_member_demote BP → JT (back to member)

Activity

Hook Handler Note
bp_register_activity_actions register_activity_type Registers the jetonomy_topic activity type with bp_activity_set_action so BP renders it alongside native types.
bp_activity_comment_posted on_bp_activity_comment_posted Runs the comment-to-reply bridge when the parent activity carries the broadcast meta marker.
bp_activity_allowed_tags filter_broadcast_allowed_tags Adds <br> and <p> to BP's kses allowlist so broadcast paragraphs survive save AND display. Both tags carry no attributes, so no XSS surface.

Render

Hook Handler
bp_setup_nav (priority 20) register_group_forum_tab + register_profile_forum_tab
groups_custom_group_fields_editable render_group_forum_settings (the dropdown in Create + Manage > Details)
groups_group_details_edited save_group_forum_settings
bp_after_group_details_creation_step render_group_forum_settings (creation step)

Jetonomy Hooks Consumed

Hook Handler Surface
jetonomy_before_content render_back_to_group_banner Renders the "← Group Name" link at the top of paired space / topic pages.
jetonomy_sidebar_about_after_meta render_sidebar_group_link Renders the small tag in the sidebar About card linking back to the BP group.
jetonomy_user_joined_space not directly hooked; member sync is BP → JT only (BP is the source of truth for group membership). n/a
jetonomy_after_create_post on_jt_post_created_for_bp Triggers the broadcast to the paired BP group activity stream.

Activity Broadcast Flow

On jetonomy_after_create_post:

  1. If broadcast is disabled or no pair exists for the space, return.
  2. If the post is private (is_private), return.
  3. If the BP Activity component is not active, return.
  4. Build the activity body: excerpt converted to <p> paragraphs with block-level tag boundaries preserved, plus a trailing "Shared from the forum · View discussion" attribution line.
  5. Call bp_activity_add with component=groups, type=jetonomy_topic, item_id=$group_id, secondary_item_id=$post_id, and hide_sitewide set when the group is not public.
  6. Store the post ID in activity meta: bp_activity_update_meta( $activity_id, 'jetonomy_post_id', $post_id ).

The bp_activity_allowed_tags filter that whitelists <br> and <p> is attached globally while broadcast is enabled. BP runs kses both on save and on display, so a per-call toggle would strip the tags when the activity is rendered later.

Comment-to-Reply Bridge Flow

On bp_activity_comment_posted( $comment_id, $r, $activity ):

  1. If the loop-guard flag is set, return. Prevents boomerang writes.
  2. If bp_activity_get_meta( $activity->id, 'jetonomy_post_id' ) is empty, the parent activity is not one of ours, return.
  3. Load the Jetonomy post; if it is not published, return (the broadcast survives, but we do not create replies against draft/trashed topics).
  4. Build the reply content: wp_kses_post on the comment HTML for display, wp_strip_all_tags for the plain version.
  5. Create the reply via Reply::create with the same author as the BP commenter.

Edits and deletes on BP do NOT propagate. The JT thread is the durable record.

Loop Protection

A shared static $syncing flag stops a write on one side from triggering a boomerang write back. Every member-sync, broadcast, and bridge method flips it for the duration of the write:

self::$syncing = true;
// do the write that might fire hooks we listen to
self::$syncing = false;

Both the group-lifecycle handlers (on_group_created, on_group_updated) and the member-sync handlers read self::$syncing at entry.

Identity Keying

Everything joins on user_id. BP member profiles and Jetonomy user profiles share the same WP user ID, so username divergence is not a problem.

Stale Pair Handling

Every render hook resolves the paired entity lazily. If the paired space no longer exists when the forum tab is about to render, the tab callback returns early without emitting markup. The same pattern applies to the sidebar link and back-banner.

Extending

Three clean extension points:

  • Disable member-leave propagation. Remove the groups_leave_group, groups_remove_member, and groups_ban_member actions from the integration at init + 30 or later if you want the add-only semantics the FluentCommunity integration uses.
  • Custom activity rendering. Filter bp_activity_action_before_save or add a filter on bp_get_activity_action to override how jetonomy_topic rows render without touching the integration.
  • Custom permission gate on forum tab. Filter bp_is_user_in_group (or call groups_is_user_member directly) inside your own hook handler on register_group_forum_tab (priority < 20) to restrict the Forum tab to certain roles.

Destructive or privacy-affecting extensions (forcing role sync one-way, propagating flags cross-surface, cascading deletes) belong in a Pro extension with explicit per-pair toggles, not as drop-in replacements for the free integration.

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:

  1. 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?"
  2. 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. Apply Visibility::rest_check to 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_read to 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?

Jetonomy ships a small JavaScript toolkit that replaces native window.confirm, window.alert, and window.prompt with branded, accessible modal dialogs. The toolkit lives in assets/js/jetonomy-modals.js and is enqueued on every community page and inside wp-admin.

Globals: window.jetonomyConfirm, window.jetonomyAlert, window.jetonomyPrompt Localisation contract: window.jetonomyModalsI18n (added in 1.4.2) Source: assets/js/jetonomy-modals.js


Why the toolkit exists

Native browser dialogs are ugly, untranslatable, blocking, not styleable, and inconsistent across browsers - some hide them, some show "Prevent this page from creating additional dialogs" checkboxes, mobile Safari renders them at the bottom of the viewport. They also bypass any focus-management or screen-reader contract that the rest of the community UI follows.

The toolkit gives you:

  • A consistent visual language that matches Jetonomy's --jt-* token system
  • Promise-based async / await syntax instead of blocking calls
  • Keyboard support - ESC dismisses, Enter confirms (or commits a single-line prompt)
  • Backdrop click to cancel
  • Focus trapping while the modal is open, focus restoration on close
  • Built-in translatable labels via window.jetonomyModalsI18n

Every custom JS that ships in the Jetonomy ecosystem should use these globals instead of native dialogs. That includes Pro extensions, theme bridge plugins, and third-party integrations that hook into community pages.


API Reference

jetonomyConfirm( message, opts? )

Asks the user a yes/no question. Resolves true when the user confirms, false when they cancel, press ESC, or click the backdrop.

Parameters

Parameter Type Description
message string The body text shown inside the modal
opts.title string? Heading text. Omit for a body-only modal
opts.confirmLabel string? Confirm button label. Defaults to the localised "Confirm" string
opts.cancelLabel string? Cancel button label. Defaults to the localised "Cancel" string
opts.danger boolean? When true, the confirm button uses the danger style (red). Use for destructive actions

Returns: Promise<boolean>

Example:

const proceed = await window.jetonomyConfirm(
    'Delete this post? This cannot be undone.',
    {
        title:        'Delete post',
        confirmLabel: 'Delete',
        cancelLabel:  'Keep it',
        danger:       true,
    }
);

if ( ! proceed ) {
    return;
}
await myPlugin.deletePost( postId );

jetonomyAlert( message, opts? )

Shows a message and waits for the user to dismiss it. Resolves true once the user clicks the confirm button, presses Enter, presses ESC, or clicks the backdrop.

Parameters

Parameter Type Description
message string The body text shown inside the modal
opts.title string? Heading text
opts.confirmLabel string? Confirm button label. Defaults to "OK"

Returns: Promise<true>

Example:

await window.jetonomyAlert(
    'Your changes have been saved.',
    { title: 'Saved' }
);

// Code here runs after the user dismisses the dialog.
location.reload();

jetonomyPrompt( message, opts? )

Asks the user for a string input. Resolves the submitted string on submit, or null on cancel / ESC / backdrop click.

Parameters

Parameter Type Description
message string The body text shown above the input field
opts.title string? Heading text
opts.placeholder string? Placeholder text shown inside the empty input
opts.defaultValue string? Pre-filled value. The input is auto-selected on open so the user can overwrite or accept it
opts.multiline boolean? When true, renders a <textarea> instead of an <input type="text">
opts.confirmLabel string? Submit button label. Defaults to "Submit"
opts.cancelLabel string? Cancel button label. Defaults to "Cancel"

Returns: Promise<string|null> - the input value on submit, null on cancel

Example:

const reason = await window.jetonomyPrompt(
    'Tell us why you are reporting this reply.',
    {
        title:        'Report reply',
        placeholder:  'Optional context for the moderator team',
        multiline:    true,
        confirmLabel: 'Submit report',
    }
);

if ( reason === null ) {
    return; // User cancelled.
}

await myPlugin.reportReply( replyId, reason );

Single-line prompts commit on Enter; multiline prompts require an explicit button click (Enter inserts a newline as expected).


End-to-end Example

A custom moderator action that confirms, prompts for a note, then alerts on success - all without touching a native dialog:

async function quarantinePost( postId ) {
    const proceed = await window.jetonomyConfirm(
        'Quarantine this post? It will be hidden from public view until reviewed.',
        {
            title:        'Quarantine post',
            confirmLabel: 'Quarantine',
            danger:       true,
        }
    );

    if ( ! proceed ) {
        return;
    }

    const note = await window.jetonomyPrompt(
        'Add a moderator note (optional).',
        {
            title:        'Moderator note',
            placeholder:  'e.g. flagged for review by 3 members',
            multiline:    true,
            confirmLabel: 'Save note',
        }
    );

    if ( note === null ) {
        return; // User backed out at the note stage.
    }

    await fetch( `/wp-json/my-plugin/v1/quarantine/${ postId }`, {
        method:  'POST',
        headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': wpApiSettings.nonce },
        body:    JSON.stringify( { note } ),
    } );

    await window.jetonomyAlert(
        'Post quarantined. Moderators have been notified.',
        { title: 'Done' }
    );
}

The user gets three branded, translatable, keyboard-friendly modals in sequence instead of three jarring native dialogs.


Localisation: window.jetonomyModalsI18n

Jetonomy localises four default button labels onto window.jetonomyModalsI18n via wp_localize_script. The script is registered on both the front-end and inside wp-admin, so the global is reliably available wherever the toolkit JS is loaded.

Shape:

window.jetonomyModalsI18n = {
    cancel:  'Cancel',  // Default cancel button label (jetonomyConfirm, jetonomyPrompt)
    confirm: 'Confirm', // Default confirm button label (jetonomyConfirm)
    submit:  'Submit', // Default submit button label (jetonomyPrompt)
    ok:      'OK',      // Default OK button label (jetonomyAlert)
};

The values are translated through WordPress's standard i18n pipeline - if your site loads a jetonomy translation file, the strings arrive pre-translated and the modals adopt the active locale automatically.

How third-party callers should use it

The global is provided so you can read the localised strings when you need additional context inside your own UI (for example, to label a custom action that mirrors one of the toolkit buttons):

const cancelLabel = ( window.jetonomyModalsI18n && window.jetonomyModalsI18n.cancel ) || 'Cancel';

myDropdown.appendChild( makeMenuItem( cancelLabel, onCancel ) );

Do not override the global. Overrides are not supported and may be reset on the next page load. If you want a different label on a single modal, pass it via the per-call opts.confirmLabel / opts.cancelLabel instead:

// Correct - per-call override
await window.jetonomyConfirm( 'Publish?', { confirmLabel: 'Publish now', cancelLabel: 'Keep as draft' } );

// Wrong - mutating the global
window.jetonomyModalsI18n.confirm = 'Publish now'; // do not do this

This keeps the global predictable for every other piece of code that reads from it.


What's Next?

Jetonomy ships a full WP-CLI surface covering every core domain of the plugin: 14 command roots in the free plugin and 15 command roots in Jetonomy Pro, totalling 75+ subcommands across both plugins.

The 14 free roots are the 13 domain commands listed under Free Commands below (category, space, post, reply, vote, flag, member, mod, notification, config, tag, user, scenario), plus the standalone qa-actions command, documented under Testing and QA Commands.

All free commands live under wp jetonomy <subject> <subcommand>. All Pro commands live under wp jetonomy-pro <subject> <subcommand> (note the separate root - Pro commands require both plugins active).

On this local dev install you must prefix every wp call with --path:

wp --path="/path/to/wp" jetonomy space list

Customers running from their WordPress root directory can omit --path.


Free Commands

category

Manage top-level categories that group spaces.

Subcommand Description
create Create a new category
list List all categories
update <id> Update category fields
delete <id> Delete a category

Flags - create: --name=<name> --slug=<slug> [--description=<text>] [--parent=<id>] [--format=<format>]

Flags - update: [--name=<name>] [--slug=<slug>] [--description=<text>] [--parent=<id>] [--sort=<order>] [--format=<format>]

wp jetonomy category create --name="General" --slug=general
wp jetonomy category create --name="Support" --slug=support --parent=1
wp jetonomy category update 3 --name="Renamed" --sort=10
wp jetonomy category list --format=json

space

Create and manage spaces (forums, Q&A boards, ideas boards, feeds).

Subcommand Description
create Create a new space
list List spaces
update <id> Update space settings
delete <id> Delete a space
add-member Add a member to a space
remove-member Remove a member from a space

Flags - create: --title=<title> --slug=<slug> --category=<id> [--description=<text>] [--type=<type>] [--visibility=<vis>] [--join-policy=<policy>] [--format=<format>]

Types: forum (default), qa, ideas, feed. Visibility: public, private, hidden. Join policy: open, approval, invite.

Flags - update: All optional - [--title=<title>] [--description=<text>] [--type=<type>] [--visibility=<vis>] [--join-policy=<policy>] [--status=<status>] [--format=<format>]

wp jetonomy space create --title="General" --slug=general --category=1
wp jetonomy space create --title="Q&A" --slug=qa --category=1 --type=qa --visibility=private --join-policy=approval
wp jetonomy space update 5 --visibility=private
wp jetonomy space list --format=table

post

Create and manage posts within spaces.

Subcommand Description
create Create a new post
list List posts
update <id> Update a post
delete <id> Delete a post

Flags - create: --space=<id> --author=<id> --title=<title> --content=<content> [--status=<status>] [--slug=<slug>] [--format=<format>]

Status values: published (default), draft.

Flags - update: [--title=<title>] [--content=<content>] [--status=<status>] [--slug=<slug>] [--format=<format>]

wp jetonomy post create --space=5 --author=3 --title="Hello" --content="First post"
wp jetonomy post create --space=5 --author=3 --title="Draft" --content="..." --status=draft
wp jetonomy post update 42 --title="New title"
wp jetonomy post list --format=json

reply

Create and manage replies on posts.

Subcommand Description
create Create a reply
list List replies for a post
update <id> Update a reply
delete <id> Delete a reply
accept Mark a reply as the accepted answer

Flags - create: --post=<id> --author=<id> --content=<content> [--parent=<id>] [--status=<status>] [--format=<format>]

Flags - accept: --post=<id> --reply=<id> [--format=<format>]

wp jetonomy reply create --post=42 --author=3 --content="Great idea"
wp jetonomy reply create --post=42 --author=3 --content="Nested reply" --parent=17
wp jetonomy reply accept --post=42 --reply=17

tag

Manage post tags.

Subcommand Description
create Create a tag
list List all tags
update <id> Update a tag
delete <id> Delete a tag
get-by-slug Fetch a tag by its slug
attach Attach a tag to a post
detach Detach a tag from a post
list-for-post List tags on a specific post

Flags - create: --name=<name> [--format=<format>]

Flags - get-by-slug: --slug=<slug> [--format=<format>]

Flags - attach / detach: --post=<id> --tag=<id> [--format=<format>]

Flags - list-for-post: --post=<id> [--format=<format>] [--fields=<fields>]

wp jetonomy tag create --name="announcement"
wp jetonomy tag attach --post=42 --tag=7
wp jetonomy tag detach --post=42 --tag=7
wp jetonomy tag list-for-post --post=42

user

Manage community users - ban/unban, trust levels, profiles, and reputation.

Subcommand Description
create Create a new WordPress + Jetonomy user
ban <id> Ban a user site-wide
unban <id> Remove a site-wide ban
promote <id> Increase a user's trust level by one step
demote <id> Decrease a user's trust level by one step
set-trust <id> Set a user's trust level to an exact value (0-5)
get-trust <id> Read a user's current trust level
update-profile <id> Update display name, bio, or avatar URL
adjust-reputation <id> Add or subtract reputation points

Flags - create: --login=<login> --email=<email> [--password=<pw>] [--role=<role>] [--trust-level=<0-5>] [--display-name=<name>] [--format=<format>]

Flags - set-trust: --level=<0-5> [--format=<format>]

Flags - update-profile: [--display-name=<name>] [--bio=<bio>] [--avatar-url=<url>] [--format=<format>]

Flags - adjust-reputation: --delta=<int> (use negative values to subtract) [--format=<format>]

wp jetonomy user create --login=alice --email=alice@example.com
wp jetonomy user create --login=mod1 --email=m1@ex.com --trust-level=4 --role=editor
wp jetonomy user set-trust 42 --level=3
wp jetonomy user adjust-reputation 42 --delta=25
wp jetonomy user adjust-reputation 42 --delta=-10
wp jetonomy user update-profile 42 --bio="Hello world" --avatar-url="https://example.com/a.png"

member

Manage space membership - join, leave, and role assignment.

Subcommand Description
add Add a user to a space (admin shortcut)
remove Remove a user from a space
promote Promote a member to moderator
demote Demote a member from moderator
join Record a user joining a space (respects join policy)
leave Record a user leaving a space
set-role Set a member's role directly
is-member Check whether a user is a member

Note: --by is used for the user ID in all subcommands because --user is a reserved WP-CLI global flag.

Flags - join: --space=<id> --by=<user_id> [--role=<role>] [--format=<format>]

Flags - set-role: --space=<id> --by=<user_id> --role=<role> [--format=<format>]

Flags - is-member: --space=<id> --by=<user_id> [--format=<format>]

wp jetonomy member join --space=15 --by=4
wp jetonomy member join --space=15 --by=4 --role=moderator
wp jetonomy member set-role --space=15 --by=4 --role=moderator
wp jetonomy member leave --space=15 --by=4
wp jetonomy member is-member --space=15 --by=4

vote

Cast and inspect votes on posts and replies.

Subcommand Description
create Cast a vote (upvote or downvote)
delete Retract a vote
list List votes on a post or reply
cast Alias for create with explicit flags

Note: --voter is used for the voter's user ID because --user is a reserved WP-CLI global flag.

Flags - cast: --voter=<id> --type=<type> --id=<id> --value=<value> [--format=<format>]

Type: post or reply. Value: 1 (upvote) or -1 (downvote).

wp jetonomy vote cast --voter=3 --type=post --id=42 --value=1
wp jetonomy vote cast --voter=3 --type=reply --id=17 --value=-1

flag

Create and manage content flags (user reports).

Subcommand Description
list List flags (filterable by status)
resolve Resolve or dismiss a flag
create File a new flag against a post or reply

Note: --reporter is used for the reporting user ID because --user is reserved.

Flags - create: --type=<type> --id=<id> --reporter=<id> --reason=<reason> [--description=<description>] [--format=<format>]

Type: post or reply. Reason values: spam, harassment, off-topic, other.

wp jetonomy flag create --type=post --id=42 --reporter=3 --reason=spam
wp jetonomy flag create --type=reply --id=17 --reporter=3 --reason=harassment --description="Context here"
wp jetonomy flag list --format=json

notification

Trigger and inspect notifications.

Subcommand Description
send Trigger a notification event
list List notifications for a user
trigger Alias for send with explicit flags
mark-read Mark notifications as read for a user

Note: --to is used for the recipient user ID because --user is reserved.

Flags - trigger: --type=<type> --to=<user_id> --actor=<user_id> --object-type=<type> --object-id=<id> --message=<text> [--format=<format>]

Flags - list: --to=<user_id> [--limit=<n>] [--offset=<n>] [--fields=<fields>] [--format=<format>]

wp jetonomy notification trigger --type=reply_to_post --to=1 --actor=2 --object-type=post --object-id=5 --message="Someone replied"
wp jetonomy notification list --to=1
wp jetonomy notification list --to=1 --limit=5 --format=json

config

Read and write Jetonomy settings using dotted key paths.

Subcommand Description
get Read a setting value
set Write a setting value
list List all settings
reset Reset a single key to its default
reset-all Reset all settings to defaults
keys List available keys under a parent path

Flags - get: [--key=<dotted_path>] [--format=<format>]

Flags - set: --key=<dotted_path> --value=<value> [--format=<format>]

Flags - keys: [--key=<parent_path>] [--format=<format>] [--fields=<fields>]

wp jetonomy config get --key=trust_thresholds.1.posts
wp jetonomy config get --key=rate_limits --format=json
wp jetonomy config set --key=trust_thresholds.1.posts --value=7
wp jetonomy config set --key=notification_defaults.mention.email --value=false
wp jetonomy config keys --key=trust_thresholds
wp jetonomy config list

mod

Advanced moderation actions: bans, flag management, and content decisions.

Subcommand Description
approve Approve flagged content
spam Mark content as spam
trash Trash content
flags List flags with optional status filter
resolve Resolve or dismiss a flag
ban Ban a user (site-wide or space-scoped)
unban Lift a ban
is-banned Check whether a user is banned

Note: --target is used for the affected user and --issuer for the moderator, avoiding the reserved --user flag.

Flags - flags: [--status=<status>] [--format=<format>] [--fields=<fields>]

Status values: valid, dismissed.

Flags - resolve: --resolver=<user_id> --decision=<decision> [--format=<format>]

Flags - ban: --target=<user_id> --issuer=<user_id> [--type=<type>] [--space=<id>] [--reason=<text>] [--expires=<datetime>] [--format=<format>]

Flags - is-banned: --target=<user_id> [--space=<id>] [--format=<format>]

wp jetonomy mod flags --status=valid
wp jetonomy mod resolve 42 --resolver=1 --decision=valid
wp jetonomy mod resolve 17 --resolver=1 --decision=dismissed
wp jetonomy mod ban --target=5 --issuer=1 --reason="spam"
wp jetonomy mod ban --target=5 --issuer=1 --type=space_ban --space=3
wp jetonomy mod ban --target=5 --issuer=1 --type=silence --expires="2026-05-01 00:00:00"
wp jetonomy mod unban 5
wp jetonomy mod is-banned --target=5 --space=3

scenario

Run end-to-end PHP scenarios that exercise full user journeys against the live database.

Subcommand Description
run <name> Run a named scenario
list List all available scenarios

Flags - run: [--cleanup] (roll back all data created by the scenario) [--format=<format>]

Flags - list: [--format=<format>] [--fields=<fields>]

Bundled scenarios: basic-forum-flow, notification-delivery-sweep, multi-user-voting-thread, moderation-lifecycle, space-member-journey.

wp jetonomy scenario list
wp jetonomy scenario list --format=json
wp jetonomy scenario run basic-forum-flow
wp jetonomy scenario run notification-delivery-sweep --cleanup
wp jetonomy scenario run multi-user-voting-thread --format=json

Pro Commands

Pro commands use wp jetonomy-pro as the top-level namespace. Every Pro subcommand requires both Jetonomy (free) and Jetonomy Pro to be active.


extension

Enable, disable, and inspect Pro extensions.

Subcommand Description
list List all extensions and their current state
enable <id> Enable an extension
disable <id> Disable an extension
activate <id> Activate (boot) an extension that is already enabled
deactivate <id> Deactivate a running extension
status <id> Show status for a single extension
wp jetonomy-pro extension list
wp jetonomy-pro extension list --format=json
wp jetonomy-pro extension enable private-messaging
wp jetonomy-pro extension disable polls
wp jetonomy-pro extension status webhooks

custom-fields

Manage custom fields that extend post or user objects.

Subcommand Description
list List all defined custom fields
create Define a new custom field
delete <id> Remove a custom field definition

Flags - create: --key=<slug> --label=<text> --type=<type> --applies-to=<target> [--description=<text>] [--options=<csv>] [--required] [--default=<value>] [--format=<format>]

Types: text, textarea, select, checkbox, number, url. Applies-to: post or user.

wp jetonomy-pro custom-fields create --key=company --label=Company --type=text --applies-to=user
wp jetonomy-pro custom-fields create --key=priority --label=Priority --type=select --applies-to=post --options="low,medium,high"
wp jetonomy-pro custom-fields list --format=json
wp jetonomy-pro custom-fields delete 4

white-label

Set white-label branding for the community frontend.

Subcommand Description
set-logo Replace the community logo
set-colors Set primary and accent brand colors
wp jetonomy-pro white-label set-logo --url=https://example.com/logo.png
wp jetonomy-pro white-label set-colors --primary="#1a73e8" --accent="#fbbc04"

reactions

Manage emoji reactions on posts and replies.

Subcommand Description
list List all reactions on an object
purge Remove all reactions from an object
add Add a reaction from a user
remove Remove a user's reaction

Note: --by is used for the acting user, --on-type and --on-id for the target object.

Flags - add / remove: --on-type=<type> --on-id=<id> --by=<user_id> --emoji=<slug> [--format=<format>]

wp jetonomy-pro reactions add --on-type=post --on-id=12 --by=1 --emoji=thumbsup
wp jetonomy-pro reactions add --on-type=reply --on-id=45 --by=2 --emoji=heart
wp jetonomy-pro reactions list --on-type=post --on-id=12
wp jetonomy-pro reactions purge --on-type=post --on-id=12

ai

Inspect and test the AI moderation / summarization provider.

Subcommand Description
test-provider <provider> Send a test prompt to a named provider
clear-cache Purge the AI response cache
export-usage Export AI API usage records
status Show current provider health
list-providers List all configured AI providers
provider-status <provider> Show status for a specific provider

Flags - test-provider: [--prompt=<text>] [--format=<format>]

wp jetonomy-pro ai status
wp jetonomy-pro ai list-providers --format=json
wp jetonomy-pro ai test-provider anthropic --prompt="Say hi"
wp jetonomy-pro ai clear-cache
wp jetonomy-pro ai export-usage --format=json

advanced-moderation

Inspect and test automated moderation rules.

Subcommand Description
list-rules List all active moderation rules
test-rule <id> Test a rule against sample content
wp jetonomy-pro advanced-moderation list-rules
wp jetonomy-pro advanced-moderation list-rules --format=json
wp jetonomy-pro advanced-moderation test-rule 3

custom-badges

Award and inspect custom reputation badges.

Subcommand Description
list List all badge definitions
award Award a badge to a user

Flags - award: --badge=<id> --to=<user_id> [--format=<format>]

wp jetonomy-pro custom-badges list
wp jetonomy-pro custom-badges award --badge=5 --to=42

polls

Create and manage polls attached to posts.

Subcommand Description
list List polls
close <id> Close a poll early
create Create a poll on a post
get <id> Get poll details and current results
vote Cast a vote on a poll option

Note: --by is used for the voter user ID because --user is reserved.

Flags - create: --post=<id> --question=<text> --options=<csv> [--multiple] [--closes-at=<datetime>] [--format=<format>]

Flags - vote: --post=<id> --by=<user_id> and the option index/id.

wp jetonomy-pro polls create --post=12 --question="Favourite colour?" --options="Red,Green,Blue"
wp jetonomy-pro polls create --post=12 --question="Pick many" --options="A,B,C" --multiple
wp jetonomy-pro polls get 4
wp jetonomy-pro polls close 4

email-digest

Manage user email digest preferences and trigger sends.

Subcommand Description
send-now Send a digest immediately for a user
export-digests Export digest records
get-prefs Get a user's digest preferences
set-prefs Update a user's digest preferences

Note: --for is used for the target user ID because --user is reserved.

Flags - get-prefs / send-now: --for=<user_id> [--format=<format>]

Flags - set-prefs: --for=<user_id> [--frequency=<frequency>] [--enabled] [--disabled] [--types=<csv>] [--format=<format>]

Frequency values: daily, weekly, off.

wp jetonomy-pro email-digest get-prefs --for=1
wp jetonomy-pro email-digest set-prefs --for=1 --frequency=weekly --enabled
wp jetonomy-pro email-digest set-prefs --for=1 --frequency=off
wp jetonomy-pro email-digest send-now --for=1

web-push

Manage browser push subscriptions and send push notifications.

Subcommand Description
send Send a push notification to a user
list-subscriptions List a user's active push subscriptions
subscribe Register a push subscription for a user
unsubscribe Remove a push subscription

Note: --for is used for the subscriber user ID, --to for the notification recipient.

Flags - subscribe: --for=<user_id> --endpoint=<url> --p256dh=<key> --auth=<key> [--format=<format>]

Flags - unsubscribe: --for=<user_id> --endpoint=<url> [--format=<format>]

wp jetonomy-pro web-push list-subscriptions --for=1
wp jetonomy-pro web-push send --to=1 --title="New reply" --body="Alice replied to your post"

analytics

Export and report on community analytics.

Subcommand Description
export Export raw analytics data
report Print a formatted summary report
overview High-level stats for a date range
top-spaces Rank spaces by activity for a period

Flags - overview: [--range=<range>] [--start=<date>] [--end=<date>] [--format=<format>]

Range values: 7d, 30d, 90d, custom. When using custom, provide --start=YYYY-MM-DD and --end=YYYY-MM-DD.

Flags - top-spaces: [--range=<range>] [--limit=<n>] [--format=<format>]

wp jetonomy-pro analytics overview --range=7d
wp jetonomy-pro analytics overview --range=custom --start=2026-03-01 --end=2026-03-15
wp jetonomy-pro analytics top-spaces --range=30d --limit=5
wp jetonomy-pro analytics export --range=30d --format=csv

seo-pro

Generate SEO sitemaps for community content.

Subcommand Description
generate-sitemaps Rebuild all Jetonomy sitemaps
wp jetonomy-pro seo-pro generate-sitemaps

webhooks

Manage outbound webhook endpoints.

Subcommand Description
list List all registered webhooks
test <id> Send a test ping to a webhook
retry <id> Retry failed deliveries for a webhook
create Register a new webhook
update <id> Update webhook settings

Note: --target-url is used instead of --url because WP-CLI reserves --url globally for multisite routing.

Flags - create: --target-url=<url> --events=<csv> [--name=<text>] [--secret=<text>] [--description=<text>] [--disabled] [--format=<format>]

Secret is auto-generated if omitted. Events are a comma-separated list of event slugs such as post.created, reply.created, user.registered.

Flags - update: [--target-url=<url>] [--events=<csv>] [--name=<text>] [--description=<text>] [--format=<format>]

wp jetonomy-pro webhooks list
wp jetonomy-pro webhooks create --target-url=https://example.com/hook --events=post.created,reply.created
wp jetonomy-pro webhooks create --target-url=https://example.com/hook --events=user.registered --disabled
wp jetonomy-pro webhooks test 3
wp jetonomy-pro webhooks retry 3

messaging

Manage private message conversations.

Subcommand Description
export-conversations Export conversation records for a user
purge-old Delete conversations older than a given age
create-conversation Start a new private conversation
send Send a message in an existing conversation

Note: --by is the conversation initiator, --with is a comma-separated list of participant IDs, --from is the message sender.

Flags - create-conversation: --by=<user_id> --with=<csv> [--title=<text>] [--type=<type>] [--message=<text>] [--format=<format>]

Flags - send: --conversation=<id> --from=<user_id> --content=<text> [--format=<format>]

wp jetonomy-pro messaging create-conversation --by=1 --with=3,4
wp jetonomy-pro messaging create-conversation --by=1 --with=2 --message="Hi there"
wp jetonomy-pro messaging send --conversation=12 --from=1 --content="hello"
wp jetonomy-pro messaging export-conversations --by=1

reply-by-email

Configure and test inbound reply-by-email processing.

Subcommand Description
configure Set SMTP / IMAP connection settings
test-smtp Send a test email to verify outbound settings
wp jetonomy-pro reply-by-email configure --host=mail.example.com --user=inbox@example.com
wp jetonomy-pro reply-by-email test-smtp

Testing and QA Commands

These commands run the built-in quality assurance suites against a live WordPress + Jetonomy install. Run them before every release to catch regressions early.

qa-actions (free)

Runs all four smoke-test phases in sequence and reports a pass/fail total. Takes no arguments.

Phase What it covers
Phase 1 REST round-trip tests (creates, reads, deletes via the REST API)
Phase 2 Model unit tests (direct model-layer assertions)
Phase 3 Pro extension tests (skipped automatically on free-only installs)
Phase 4 Journey smoke tests (C1-C12 - full end-to-end user journeys)
wp jetonomy qa-actions

Expected output when all tests pass:

--- Jetonomy Action Tests ---

Phase 1: REST Round-Trip Tests
...
Phase 4: Journey Smoke Tests (C1-C12)
...
  REST Tests:     42/42
  Model Tests:    58/58
  Pro Tests:      64/64
  Journey Tests:  46/46
  Total: 210/210 PASS

scenario run (free)

Run a named end-to-end scenario against the live database. Use --cleanup to roll back all data the scenario creates.

# List available scenarios first
wp jetonomy scenario list

# Run a scenario and keep the data (useful for manual inspection after)
wp jetonomy scenario run basic-forum-flow

# Run and clean up all created data
wp jetonomy scenario run notification-delivery-sweep --cleanup
wp jetonomy scenario run moderation-lifecycle --cleanup

Scenarios are PHP classes under includes/cli/scenarios/ and can be run directly by PHPUnit via composer test:combo if you prefer not to use a live database.

Expose your community to AI agents and automation through the WordPress Abilities API - 19 free abilities plus 20 more with Pro, each enforcing the same permissions as the REST API.

What You Will Learn

  • What the Abilities API is and when to use it instead of REST
  • Every ability Jetonomy and Jetonomy Pro register
  • How permissions work (they mirror REST exactly)
  • How to execute an ability from PHP or WP-CLI

What Is the Abilities API?

The WordPress Abilities API is a machine-readable registry of "things a site can do", each with a name, description, JSON-Schema input/output contracts, and a permission callback. AI agents, MCP servers, and automation tools discover abilities at runtime and call them without knowing your REST routes.

Where the API comes from: the Abilities API ships in WordPress core from version 7.0 onward. On earlier versions (6.7-6.9) it is available as the standalone WordPress Abilities API feature plugin - install and activate that plugin and the API works the same way.

Jetonomy registers its abilities only when the API is actually present. It hooks the API's own wp_abilities_api_init / wp_abilities_api_categories_init actions, which fire whether the API came from core (7.0+) or from the feature plugin on an older release. If neither core nor the plugin provides the API, those hooks never fire and Jetonomy simply does not register abilities - no errors, no changed behaviour, and the REST API remains the way to drive the community.

Free Abilities

All free abilities live under the jetonomy/ namespace, grouped into categories (jetonomy-content, jetonomy-spaces, jetonomy-users, jetonomy-moderation, jetonomy-search).

Ability What it does
jetonomy/list-spaces, jetonomy/get-space Browse spaces
jetonomy/create-space, jetonomy/join-space, jetonomy/list-space-members Space membership
jetonomy/list-posts, jetonomy/get-post, jetonomy/create-post Topics
jetonomy/list-replies, jetonomy/create-reply Replies
jetonomy/vote Vote on posts and replies
jetonomy/search Full-text search
jetonomy/get-activity, jetonomy/get-user-profile Member data
jetonomy/list-notifications, jetonomy/mark-notifications-read Notifications
jetonomy/flag-content, jetonomy/list-flags, jetonomy/moderate-content Moderation

Pro Abilities

Pro adds 20 abilities under jetonomy-pro/ covering its extensions:

Area Abilities
Messaging list-conversations, get-conversation, send-message
Polls create-poll, vote-poll, get-poll-results
Reactions get-reactions, add-reaction
Badges list-badges, get-user-badges, award-badge
Custom fields list-custom-fields, set-custom-field
Analytics get-analytics, export-analytics
Webhooks list-webhooks, create-webhook, delete-webhook
Moderation rules list-moderation-rules, create-moderation-rule

Permissions Mirror REST

Every ability executes through the same REST stack that powers the frontend (improved in 1.5.0 - abilities previously used a separate code path). That means the permission model is identical: an agent acting as a subscriber cannot read someone else's conversation, list webhooks, or award badges, and gets the same jetonomy_forbidden / rest_forbidden errors the REST API returns. There is no separate "abilities permission system" to audit.

Executing an Ability

From PHP:

$ability = wp_get_ability( 'jetonomy/create-post' );
if ( $ability ) {
    $result = $ability->execute( [
        'space_id' => 8,
        'title'    => 'Posted by an agent',
        'content'  => 'Hello from the Abilities API.',
    ] );
}

Abilities that take no input are executed with no arguments: wp_get_ability( 'jetonomy/list-spaces' )->execute().

From WP-CLI (WordPress 7.0+):

wp ability run jetonomy/search --input='{"q":"onboarding"}'

What's Next?

The same operations are available over plain HTTP if you prefer direct REST calls.

REST API →

Something unclear? Open a support ticket →

Buy Jetonomy