TBC App - Community App (Managed)

Your own branded community app on iOS and Android — built, published and kept up to date by us, under your accounts. You bring the content and branding; we handle every build and update.

Price range: $33.00 to $130.00
$33.00 per month

v1.3.27
Changelog · v1.3.27

1.3.27 — 2026-10-19

🛠 Fixed

  • A member who signed up in the app and then pays on your website gets in. In membership mode the gate counted only in-app purchases, so someone who joined in the app and then bought a WooCommerce or Fluent Cart subscription on your website was locked out of the app and the community. Now the FluentCRM tag or role one of your plans gives lets them in wherever it came from, and when your website takes it away they meet the renewal screen again. Your website's own automations need no changes. A Video Test Kit account still always meets the paywall.
  • Deleting a member takes the app's tags off their FluentCRM contact. FluentCRM keeps the contact by default, so someone who signed up again with the same email inherited the access the app had given them.

🔧 Changed

  • A member's profile page says why the membership gate lets them in or keeps them out: an in-app purchase, a tag or role from outside the app, or a Fluent Community block, which is flagged when it shuts out someone still paying in the app.
  • The Membership ended message warns you not to send members to pay on your website. The app shows that message too, and Apple and Google reject an app that sends members outside it to buy.

1.3.26 — 2026-10-19

Sync — lockstep bump, no plugin changes.

1.3.25 — 2026-10-14

✨ New

  • Members can arrange and hide the widgets on the screens you choose. Widget screens stay locked by default, which suits a menu-like page that should look the same for everyone. For a screen that works as a home page, Customize › Widget Screens gives each screen two switches, "Members can rearrange widgets on this screen" and "Members can hide widgets on this screen": turn on either or both. Members then press and hold that screen in the app to open a map of it, where they drag widgets into their own order or tap a widget's eye to hide it, as far as you allow, and bring a hidden one back from the map's Hidden list. Pinned widgets stay where you put them whatever the switches say, and the help under Pin to top says so. Each member's arrangement is kept on their own device, and turning a switch off keeps it without using it. Every screen starts locked after the update, and an order a member saved before comes back when you turn rearranging on. A member whose app hasn't taken its update yet can still drag widgets on any screen until it does. In English, Spanish, Greek and Dutch.
  • Every push setting is on one Push Notifications tab. The on/off switch (from Config), which notifications members get (the old Notifications tab), and the Send Push Notification, Test Push to Yourself, phone count and Push Notification Log cards (from Tools) now sit together, in the order you set push up. Nothing about what they do or where they are saved changed, and a bookmark to the old Notifications tab opens this one. Without a licence the on/off switch stays usable while the app is still sending, and the phone count and the log stay open, as before.
  • Customize › Theme warns when colours are hard to read. If text on the background, button text on the button, or links on the background fall under the 4.5:1 contrast that most people need to read comfortably, in light or dark mode, a warning above the colours names the pair and its ratio. It only warns; saving works as before. In English, Spanish, Greek and Dutch.
  • The app cart names each pricing rule and strikes the original price. With FluentCart Pro's Dynamic Pricing on, the cart now tells the app which rules took money off, under the names you gave them, shipping rules included, so the app lists one row per rule as your checkout page does. What coupons take stays in the Discount row. A shipping discount no rule accounts for is called "Shipping discount", in English, Spanish, Greek and Dutch. Each cart line a coupon or rule made cheaper also sends what it costs now, and the app shows the original unit price struck through beside what one costs now. An app that hasn't taken its update yet shows the one Discount row as before, with the same total.
  • The Managed tab asks which stores your app goes to. Config's App & Site card has "Which stores will your app go to?", with App Store and Google Play (the default), App Store only, or Google Play only. If you pick one store, the other store's account card on Access & Credentials says it is skipped and no longer holds the tab's dot orange or shows on Submit's Still missing list. Nothing else is hidden. We get your answer with the snapshot once you have saved the tab. In English, Spanish, Greek and Dutch.
  • My Courses in the Menus picker. Customize › Menus offers My Courses beside Courses. It opens the app's Courses screen on My Courses, so you can place both, for example My Courses in the launcher and Courses in the tab bar. It is in the picker only and never placed for you, and like Courses it shows only while Fluent Community's course module is on. The app shows it from 1.3.25.
  • A blocked member can sign in to the app and subscribe, where you sell membership in the app. With In-App Purchases on in membership mode, a member Fluent Community has blocked (as a FluentCRM automation does when a paid tag is removed) now signs in to the app as on your website, and lands on an Access denied screen with your site's words, Subscribe, Restore purchases and Sign out. Their session reaches only the app config, purchase checks, token refresh and sign-out; every other request, push registration included, is refused. Their purchase is tied to their account as anyone's is, and once your automation lifts the block the app lets them in. Apps older than 1.3.25, and sites that don't sell membership in the app, still refuse a blocked member as before. Pending members are not affected. A member a moderator blocked is shown Subscribe too, and paying won't lift that block, so ban by removing the account or role instead.

🛠 Fixed

  • A notification type with all three switches off saves as off. On the Push Notifications tab, a type with Send, On by default and Members can change all turned off was left out of what the form saved, and the plugin treats a type it has no setting for as sent, so members kept getting it. A type you turn fully off now stays off. If you turned one off that way before, it shows as on again here: turn it off and save.
  • The app stops asking for a live chat connection your site doesn't serve. With Better Messages in charge of messages, or the app's own Messages turned off in Customize, /app-config still handed the app Fluent Messaging's live-connection settings, so the app connected and asked /chat/broadcast/auth for a chat channel nobody needed. The settings are now sent only while the app's own chat is on.
  • The Managed tab's Play short description is never cut short. The field stopped at 80 characters without a word, so a pasted line that ran over was saved cut mid-word ("…build financial confiden") and would have gone to Google Play that way. The field is now one line that takes the whole text and counts it as you type. At 80 characters it notes "The short description can be up to 80 characters.", and past 80 it shows that in red. Saving one that is longer is refused with the same message, and what you typed stays in the field for you to shorten. The message is in English, Spanish, Greek and Dutch.
  • The app cart adds up when FluentCart Pro's Dynamic Pricing is on. A pricing rule's discount was left out of the cart's Discount row, and Tax showed less than the real tax, or no Tax row at all, to make up the difference. The Total was always right. Discount now includes what the rules take, a shipping rule's share too, and Tax shows the real tax. A cart that comes back after a failed payment no longer takes the rule's discount twice in the app.
  • The app cart shows the currency it is priced in. With FluentCart Pro's multi-currency on (FluentCart 2.0 and later), a member who picked another currency on your website saw that currency's amounts in the app cart with your store's symbol, so £40.00 read as $40.00. Changing the cart in the app also moved it into your store's currency, and a coupon's fixed amount and minimum spend were read in your store's currency. The app cart now stays in the member's currency through every change, coupons convert into it, and checkout opens in it, just as on your website. The charge was always right: checkout happens on your website.
  • The Community Menu gets each space's picture. Fluent Community's sidebar data, which the app's Community Menu widget reads, carries only each space's small icon (its logo, emoji or shape), so the widget's carousel, browse tiles and hero card drew a course with an emoji icon as the emoji, even with "Show the picture" chosen. The plugin now adds each space's and course's picture to that data, the one the app's own cards show: a space's "Thumbnail / Open Graph Image", else its cover photo; a course's cover photo first. Never Fluent Community's stock placeholder. Custom sidebar links are left as they are, and the website's own sidebar doesn't change. The Customize › Widget Screens preview draws the pictures too. The app shows them from its next update; until then it draws the icons as before.
  • A space or course picked as a tile shows the picture its space card shows. A tile pointing at a space (Links, or a hand-picked Spaces widget) took its cover photo, while the app's space cards take the thumbnail first. Space tiles now take the thumbnail, then the cover photo, then the logo; course tiles keep the cover photo first, as the course cards do. Neither shows Fluent Community's stock placeholder.
  • Customize › widgets lists space groups in your sidebar's order. The Community Menu's Groups tick-list and the Spaces widget's group picker listed your Fluent Community space groups by their internal number rather than as your sidebar arranges them. The space and category pickers had the same fault and listed by number rather than alphabetically. Each now lists in its proper order. What a saved widget shows doesn't change.
  • Customize › widgets: the Call to Action preview draws its button in your site's button colour. With no colour set on the card, the app now fills the button with your site's button colour instead of the accent (which follows the link colour), so the words on it read the way they do on your other buttons. The builder's preview of the card, and its placeholder shape, draw the button the same way. A colour set on the card still paints the button.
  • The push log's numbers say what they count. "Recipients" counted members while "Delivered" and "Failed" counted phones, a member with no phone counted in neither, and "Delivered" only meant Expo had accepted the notification. The columns are now Members, Sent to phones and Failed, a send that reached no phone says "Nobody to send to", each row has a Result, and a note says why the numbers never add up to each other. The "Last 30 days" summary also left out up to a day of sends on a site whose timezone is ahead of UTC, and counted extra on one behind it; it now uses the site's own clock, the one the log is written in.
  • A phone's push mark on Tools › Active Sessions by User goes amber at the right time, and old push tokens are cleared on the right day. The time a phone last registered for push is kept in the site's own clock, but the sessions table read it as UTC and the daily clean-up measured its 90 days in UTC, so both ran early or late by the site's distance from UTC. Both now read it in the site's clock.
  • An old ?tab=iap link opens the Config tab again. 1.3.24 renamed the tab and said an old link would still land on it, but nothing sent it there, so the page opened with no tab chosen.
  • A link to a card in the plugin's guide opens it, even inside a closed section. A link straight to a card that sits inside one of the guide's folded sections opened the card but left its section shut, so the page showed nothing where the link pointed. Every fold around the card now opens, so a link to a card's old place on Tools still lands on it now that it lives on Config.
  • Customize › widgets: the Call to Action preview draws an icon's disc in your site's button colour. On a card with an icon and no picture, the app now fills the icon's disc with your site's button colour, as it does the button, so the icon reads whatever your link colour is. The builder's preview draws the disc the same way. A colour set on the card still paints it.
  • The app says why a member can't start a chat. When Fluent Messaging's settings let only moderators start new chats, or ask for a number of points first, a member it refused saw "This member's profile isn't visible to you" in the app, and New Message said member search isn't available. The plugin now tells the app which rule refused and how many points are needed, so the app says "Only moderators can start new chats in this community." or "You need 50 points to start new chats in this community." When Message Roles' rules are the reason, its own Restriction Message still shows.
  • The Managed tab's warnings read as one paragraph again. A warning with bold words or an email in it, like the In-App Purchase key's "this is the third Apple .p8" note, was laid out in narrow columns, one for each bold phrase and each run of text. The text now sits beside its icon as ordinary lines.
  • The Managed tab's cards fit a narrow window. A card's title and its status badge now wrap onto two lines instead of squeezing each other, a help line under a pair of fields runs the full width, a button in a field keeps its own width, and in right-to-left languages lists, error lists, the licence link and the Test Kit's list of leftovers on Tools keep their indent on the correct side.
  • The Managed tab's Expo steps match Expo's sign-up screens. The steps said to choose Personal and to invite us as Admin in the sign-up's Invite members box, but that box has no role choice. They now say to choose Business, leave Invite members empty, press Skip on Create a project (we create the build project), then invite us from Members with the Invite button and choose Admin, because Expo picks Viewer by default. The invitation then shows on Members with an Admin badge, so you can check the role. In English, Spanish, Greek and Dutch.
  • The Managed tab's icons come from the plugin. The tab loaded its icons with a script from a public CDN (unpkg), so each visit sent a request to a third party. It now draws them from the plugin's own copy, and wp-admin asks nothing of anyone else. The plugin's docs pages no longer load an icon script from unpkg either.
  • An unlinked purchase stays unlinked when the old owner's app reports a renewal. Unlink on Subscribers released a purchase, and the store's own renewal notice already left it alone. But the store also hands each renewal to the old owner's app while it runs, and the app checked it with your site as whoever was signed in, so the plugin linked the purchase straight back to them and gave back the spaces and courses it unlocks. Now a purchase that was unlinked, or released because its member was deleted, is linked only when a member taps Restore Purchases or buys it again in the app. Any other check records the renewal on the purchase, leaves it unlinked, and adds a "Verified, kept unlinked" line to its history. A purchase nobody has claimed yet still links to the member who checks it, as before. Apps older than 1.3.25 can't say which check is which, so for them the old rule stays until the member updates; that keeps their Restore Purchases working. In English, Spanish, Greek and Dutch.
  • A subscription cancelled on an iPhone shows as Cancelled straight away. When a member turned off renewal in Apple's settings, the plugin stored the change but kept showing the subscription as Active on Subscribers until its next full check with Apple, up to a day later. The status now changes as soon as Apple says so, and back to Active if the member turns renewal on again. They keep their access until the period they paid for ends, as before.
  • Unlink notes what it took back. Unlinking a purchase on Subscribers removed the spaces, courses, roles and tags it had opened, but its history showed only "Released from its member". It now also has an "Access revoked" line saying how many it removed, as an expiry does.
  • The app sees a member lose one of two purchases. /app-config told the app only whether a member's in-app purchases still let them in at all, so when one of two ran out, or you unlinked one on Subscribers, nothing the app read changed and a space or course the member had open stayed open until they left it. It now also tells the app what the member's purchases open, and when that changes the app shows the lock on the open space or course the next time it reads its settings from your site, as it does when the member comes back to the app.
  • A space bought in the app shows its posts straight away when FluentCRM tags grant access. With In-App Purchases set to grant through FluentCRM tags, the plugin applied the tag and Fluent Community Pro's tag map added the member to the space, but Fluent Community's list of the spaces each member can read was not updated, so the space's feed said "No posts" in the app for up to 15 minutes, or until the member signed in again or opened the website. The plugin now updates that list once the tags are applied. When a tag is taken back and Fluent Community Pro removes the member ("Sync this tag with the Space"), the list was already updated.
  • A member blocked while signed in to the app is signed out with your site's message. Sign-in already refused a member whose Fluent Community profile is blocked, but a member blocked after signing in, by you or by an automation such as a FluentCRM funnel that blocks a member when their paid tag comes off, stayed signed in for days, and every Fluent Community screen in the app came back empty with no message. The app's settings read (/app-config, each time the member comes back to the app) and its session renewal now refuse a blocked member with the same tbc_auth_account_blocked code and words as sign-in ("Sorry, you cannot access this community."), end the session on that phone and stop its notifications. The app signs them out and shows the message on its sign-in screen. Lifting the block lets them sign in again. A pending member is not affected.
  • /app-config offers passkeys only on a phone your site's link file names. features.passkey_login and /two-factor's passkeys.allowed were FluentAuth's answer alone, so on a site whose assetlinks.json or apple-app-site-association answered 503 (no package name or fingerprint, no Team ID or bundle ID) the app offered passkeys the phone refused. /app-config now also sends features.passkeys_ios and features.passkeys_android, true where that platform's file is complete, and the app reads the one for its phone. passkey_login, passkeys.allowed and, for passkeys, viewer.can_use_two_factor now need at least one of them, so an older app on a site with neither file stops offering passkeys too.
  • A password reset refused by FluentAuth's attempt limit says so. After too many failed sign-ins from one network, FluentAuth refuses reset emails to it, but /password/forgot dropped the refusal and answered that reset instructions were on their way. It now answers tbc_password_reset_blocked (429) with FluentAuth's own message, as FluentAuth's reset form does on the website. An unknown address now goes through WordPress's reset the same way a known one does, so FluentAuth counts it too, and every other reply is still the same for both, so the endpoint never shows whether an account exists.
  • The test accounts' pictures show on iPhones. The profile pictures and covers the App Review Account and Video Test Kit cards give their accounts, the kit's space banner and its audio clip could be saved with an http:// address when your site sits behind a proxy or the card ran from the command line. iPhones refuse http pictures, so Apple's reviewer could meet blank profiles. They are now saved with your site's own https address, and updating the plugin corrects the ones already saved.
  • A Google Play purchase no longer shows a refund warning it doesn't have. When Google's notification of a purchase and the app's own check of it reached your site in the same second, both told Google the purchase was received, and Google turned the second one away because the first was still going through. The purchase's history on Subscribers then showed "Acknowledged with Google Play" followed by "Google acknowledgement failed" and its three-day auto-refund warning, on a purchase that was safe. The plugin now checks with Google before it writes that warning, and leaves it out when the purchase is acknowledged. A purchase Google really hasn't accepted still gets the warning.
  • Fewer database reads on every request. On a site without an object cache such as Redis, each TBC add-on read its licence key and its last licence answer from the database on every page and app request, two reads per add-on. From its next licence check (within a day of the update) WordPress loads both with its other settings, in the one read it already makes. Activating, checking and renewing a licence work as before. Every TBC add-on shares this licence code and WordPress runs the copy from the add-on that loads first, so keep your TBC add-ons current to get the whole saving.
  • Space badges clear in the app on Fluent Community 2.12. Fluent Community 2.12 counts a space's unread badge from the member's last visit to that space, which the app didn't record, so a space opened once on the website kept its badge in the app. /app-config now tells the app when your Fluent Community can record a visit, and the app records one each time a member opens one of their spaces.
  • The App Review Account's test chat is formatted once. The card formatted each line of the chat it starts between the two test accounts, and Fluent Messaging (2.9 and later) formatted it again as it saved it, so each message was stored formatted twice. The card now hands Fluent Messaging the plain text, as Fluent Messaging's own chat does.

🔧 Changed

  • The settings page reads in plain words and looks the same throughout. The push types table has three labelled switches per row (Send, On by default, Members can change), each column saying in one line what its switch does, and a row that isn't sent fades its other two. Labels and help on the Tools and Config cards drop jargon ("Pages opened in the app" for "App View (WebView chrome hiding)", "Sign Everyone Out" for "Purge All Sessions", "Test Crash Reports" for "Test Crash Reporting"). Every card is the same folding card, every row of tabs inside a tab (Managed, Backup's Back up / Restore, In-App Purchases' Apple / Google) is the same tray, and the push switch and Deep Linking now save through the Save bar and say "Saved" like every other form. Where one tab holds two forms (Push) or four (Config), each with unsaved changes shows its own Save, one above the other, and the tab keeps its unsaved dot until every one is saved. Right-to-left languages get mirrored switches, arrows and borders. "Remove the Test Kit" is no longer styled as the main button. In English, Spanish, Greek and Dutch.
  • The Managed tab asks every client for Owner on their Firebase project, once. The Firebase card asked for Editor, or Owner to sell inside the Android app, and Sell in your app asked for Owner a second time. The Firebase card now asks for Owner whether or not you sell, and says that Google emails us the role as an invitation, which changes nothing until we accept it. Sell in your app's Google card now covers only what selling adds, the Blaze plan, and Sell in your app moved to the end of Access & Credentials, below the Firebase card its Blaze step needs. In English, Spanish, Greek and Dutch.
  • The Managed tab says what the stores will ask of you later. The Apple card warns that a fee-waived account (offered to nonprofits, schools and government bodies) can publish free apps only and never sell in them, and the Paid Applications step says a missing row means that kind of account. The Google Play card no longer says organization accounts skip the 12-tester closed test: Google's help names only personal accounts opened after November 13, 2023, and an organization account has been asked for the test too, so the card links Google's page and says to plan for it either way. It also says only the account owner can press Apply for production once the test ends, so we will ask you to. The Apple intro names both keys and the Team values instead of calling the API key the only thing you hand over, the Expo step says what the Admin role covers, and the Store Listing step says Publishing's dot turns green once every row is filled in. In English, Spanish, Greek and Dutch.
  • Tools holds only tools, and each setting sits beside its test. Test Apple delivery is on Config now, under the Apple notification URL it checks, and its Recent deliveries record is in the In-App Purchases card's footer beside Subscribers. Crash Reporting (Sentry) moved to Config with Test Crash Reports at the foot of its card, and Pages opened in the app moved with it; the two still save together. Tools keeps Diagnostics, Active Sessions by User and Re-apply access, then App Review Account and Video Test Kit side by side under "App Store review". Nothing about what any of them does, or where it is saved, changed, and neither test saves the page: each runs against the saved settings, as the guides now say. A link to a moved card's old place in the guide still lands on it. In English, Spanish, Greek and Dutch.
  • Open apps pick up your setting changes right away. The app read your settings when it opened and when it came back to the front, at most once a minute, so a colour, a menu or a feature you switched on or off reached a member with the app open only later. Every answer to the app now says which version of the settings is current, and the app reads them again when it changes. Fluent Community's own settings count too, and so does a plugin you switch on or off.
  • The app's tablet sign-in panel matches your website's login banner. The app now gets the look of Fluent Community's login and sign-up banners: background colour, picture, logo, title and text colours, which side the banner sits on, and whether it is hidden. Change them in Fluent Community's login customizer and the website and the app follow together. A site that never set up its banner shows Fluent Community's default light grey panel in the app. The banner's words still come from Customize › Sign-in screens, and the tablet preview on that page now shows the same panel, on its side, or the phone's layout when the banner is hidden.
  • The app lists Spaces and Courses in Fluent Community's order, and Customize › Spaces shows it. Fluent Community 2.12 has a Spaces sort and a Courses sort in Settings › Customizations: a default order, its Featured Order among them, and whether members can change it. The app now follows both, and the Sorting panel in Customize › Spaces shows Fluent Community's Spaces setting, read-only, with where to change it. The plugin keeps no Spaces sort of its own, so the panel's default sort and its "members can change" box are gone, and a sort saved there before is ignored. If you set one, set it again in Fluent Community's Settings › Customizations. With a Fluent Community older than 2.12, the app lists Spaces A–Z with members free to change the order, as your website does. The view settings (cards or rows, and group headings) stay in Customize › Spaces.

📡 OTA & Internal

  • /app-config's iap block gains grants for a signed-in member: 12 hex characters of an md5 over the sorted spaces, courses, roles and tags TBC_CA_IAP_Grants::targets_for_products() names for their still-granting products. refresh_entitlement() writes it to the new _tbc_ca_iap_grants user meta beside _tbc_ca_iap_entitled, and TBC_CA_IAP_Grants::grants() reads it from there, so serving it costs no query. '' until the member's first refresh; absent when logged out or with in-app purchases off. Uninstall removes the meta.
  • Widget screens store allowRearrange and allowHide (only when on) in place of locked, and the app payload and the builder read emit both as booleans (TBC_CA_App_Widgets). locked is no longer read, sanitized or emitted, with no migration, so an app from before core 1.3.25 reads every screen as unlocked.
  • Each push type switch posts a hidden 0 ahead of its checkbox, so a row with all three off still reaches sanitize_settings(); is_enabled() reads a missing type as sent. handle_save() and both Re-apply access handlers also check tools_locked(), as the disabled forms already did, so a POST without a licence saves and runs nothing.
  • TBC_CA_Config_Version (includes/class-config-version.php) builds X-TBC-Config-Version, sent on every authenticated app response (any namespace, with the other X-TBC headers) and in /app-config as config_version. It is the plugin version, a counter in the autoloaded tbc_ca_config_version option, bumped by added_option, updated_option and deleted_option for the options /app-config reads (this plugin's settings, menu, widget screens, profile tabs and controls, terms page and staging list, WordPress's general settings, fluent_community_settings, FluentAuth's __fls_auth_settings, active_plugins), and a hash of the keys and values of Fluent Community's fcom_meta options, read with one query because Fluent Community writes them without a WordPress hook (last_* bookkeeping rows and the leaderboard cache left out, ten seconds in the object cache). Add-ons add their option names with the new tbc_ca_config_version_options filter. Uninstall removes the option.
  • New TBC_CA_Chat_Restriction (includes/class-chat-restriction.php) runs on rest_post_dispatch at priority 20, batch sub-requests included. On a GET /chat/threads?user_id= that resolved no thread, and on a 422 from GET /chat/users, with no restriction already set, it checks Fluent's own verdict, which it hears on fluent_messaging/can_initiate_message at priority 1, before any add-on's filter changes it, and on the answer that stands at PHP_INT_MAX. When both refused, it reads points_to_initiate_message from _messaging_settings to pick the reason and adds restriction: { title: '', message: '', reason: 'moderators_only' | 'points', points? }. Under "everyone" it adds nothing, since Fluent refuses no new chat there.
  • The FluentCart cart response (GET /tbc-ca/v1/cart and every cart change) gains two optional fields. discounts is a list of { name, amount }, sent only while Pro answers fluent_cart/dynamic_pricing/last_applied_rules, built from that filter and last_shipping_rules, each read straight after our own item_dynamic_discount / order_shipping_charge call, and capped so the rows never add up to more than totals.discount. Each item's total is its priced line_total, sent when Fluent Cart's CartItemRenderer would strike the line (below subtotal, with a coupon or manual_discount on it). The new price_cart() runs both filters once for the items, the totals and the named rows together. totals.discount still means all money off, and tbc-cart sends neither field.
  • TBC_CA_App_Config::get_auth_copy() adds the look keys to each banner block from the new auth_banner_looks(), which reads AuthenticationService::getAuthSettings() with Fluent Community's defaults merged in and resolves a colour cleared in Fluent Community's editor to what its login page draws (#f6f7f7 behind, #606266 for the title and text). The words keep the raw read, so Fluent Community's English defaults never replace a localized app's text. The Customize payload's authSettings gains look from the same method for the island's tablet preview.
  • The widget builder runs one space-group query per load, not two: the Community Menu's Groups tick-list reads fc_space_groups, the same source as the Spaces widget's group picker, and skips its placeholder row in the island. fc_space_groups_set still answers, as the same list, for an add-on that used it. The builder's ambient Community Menu payload drops each row's unused permalink (cache prefix v4).
  • Every dynamic options source reaches the island as an ordered [[value, label], …] list (resolve_options_sources()), read through optionPairs() in settingFields.js; a schema's static options stay maps. A filter that hands a non-scalar label is skipped, not cast.
  • The site snapshot carries tbc_pcom_accept_gravatar, tbc-profile-completion's new "Accept a Gravatar as the profile photo" setting.
  • Push Notifications tab (?tab=push; ?tab=notifications → push and ?tab=iap → config through the $legacy_tabs map in TBC_CA_Admin_Settings::render()): render_push_tab() composes render_push_switch_card(), render_push_types_card(), TBC_CA_Push_Manual::render_form(), render_test_push_card(), render_push_devices_card() and render_push_log_card(). Every form keeps its fields, nonce and handler: the switch posts tbc_ca_settings[features][push_notifications] with tbc_ca_tool_save_push under tbc_ca_tools_nonce (handle_tools()), the types post tbc_ca_settings[notification_types][<type>][enabled|default|user_configurable] with submit under tbc_ca_settings_nonce (handle_save() → sanitize_settings()), the test posts tbc_ca_tool_test_push, the send card keeps its admin-ajax nonce. render_push_config_card(), render_stats() and render_stats_card() are gone; the Statistics card's session counts live on in Active Sessions by User.
  • TBC_CA_Push_Log::get_stats() and cleanup() take their cutoff from cutoff(), wp_date() in the site timezone, matching created_at (current_time('mysql')); it was gmdate(). get_stats() adds total_unsent (rows with sent = 0 AND failed = 0 and no error_code, the rule the Result column uses). TBC_CA_Push_Devices::cleanup_old_tokens() takes the same local cutoff, and the Active Sessions push mark reads updated_at with date_create(…, wp_timezone()).
  • The plugin's .tbc-ca-tool-card is gone: every card is the shared .tbc-accordion__item. The sub-tab look is one rule set in admin/admin.css on .tbc-ca-subtabs / .tbc-ca-subtab, which the Managed .tab-bar, .tbc-snap-subtabs__nav and .tbc-iap-verify-tabs rows now carry, matching the island's .tbc-segment--screens; markup and switching unchanged, so Backup's radio tabs still work with JavaScript off. Where a tab holds several save bars, the shared lib/tbc-save-bar.js now stacks the showing pills in page order, each above the one before by its measured height, and keeps each nav tab's tbc-has-unsaved dot on while any bar that names it is dirty (syncShared()); it used to draw every pill at one spot and set the dot from its own bar alone. The suite's other add-ons carry the same copy. The custom checkbox and .tbc-ca-core-badge styles are removed with the checkboxes and the CORE chip they styled.
  • The settings page's five save bars go through TBC_CA_Admin_Settings::save_bar() and its locked forms through gate_open() / gate_close(). TBC_CA_Auth::get_active_sessions_by_user_device() reports the expired count through an optional by-reference argument, and get_session_aggregate() is removed (nothing else called it).
  • Config is TBC_CA_Admin_Settings::render_config_tab() (the In-App Purchases panel, Deep Linking, one tbc_ca_tools_nonce form holding render_app_view_card() and render_sentry_card() with the tbc_ca_tool_save_settings bar, and Staging Site) and Tools is render_tools(); the review pair sits under a .tbc-ca-group-label (the push types' group label, renamed from .tbc-ca-types-group) inside the tab's one accordion. The two tests sit inside the forms they belong to and post forms of their own through the button's form attribute: TBC_CA_IAP_Admin::TEST_FORM, rendered after the IAP form with only NONCE and the tbc_ca_iap_test_notification button, and TBC_CA_Admin_Settings::TEST_CRASH_FORM with tbc_ca_tools_nonce and tbc_ca_tool_test_crash; the IAP dialogs render in the same panel. render_test_tool_card() and render_test_crash_card() are gone, the test becoming render_test_notification_row() under the Apple URL and render_test_crash_section() in the Sentry card. No field name, nonce, capability check, option or handler changed. The admin docshot catalog gains a region option (a shot of one part of a card), which keeps tools-test-apple-delivery and tools-test-crash-reporting as shots of the cards they now sit in, and a whole-tab tools shot.
  • The right-to-left accordion caret moved from admin/admin.css into the shared lib/tbc-admin-base.css, so every add-on's folding cards point the reading way.
  • The Theme warning is worked out in the Customize island (contrastRatio(), hardToReadPairs(), WCAG relative luminance) over each mode's resolvePreviewPalette(); dark mode is checked only while it is offered.
  • The Customize island is rebuilt with react-easy-crop 6.2.4. Its one fix is for objectFit="cover" with a crop restored on load, which the crop dialog doesn't use, so nothing changes on screen.
  • The Customize builder is built with @wordpress/scripts 36.1.0 (was 30.27.0); nothing changes on screen.
  • The bundled JWT library is php-jwt 7.2.1 (was 7.1.1) and the Apple purchase library is readdle/app-store-server-api 3.19.1 (was 3.17.0). A buyer sees no difference: php-jwt 7.2.x moved its repository to Google and only rewrapped comments, and the Apple library adds Retention Messaging calls the plugin doesn't use and rejects a malformed Apple certificate chain with a clean error instead of a PHP warning.
  • POST /iap/verify takes a boolean restore. On a row with wp_user_id 0 and a non-empty TBC_CA_IAP_Orders::released_from(), a verify with restore: false (TBC_CA_IAP_API::holds_release(); a request with no restore key is a pre-1.3.25 app and binds as before) writes the fetched state with no owner through record_released() (history type rebind_refused, labelled in history_label()), acknowledges on Google, skips the linked-token supersede, and answers the new TBC_CA_IAP_Errors::ERR_TRANSACTION_RELEASED (iap_transaction_released, 409). The app sends restore: true from its Restore button and for a product the member is buying, false on every other verify.
  • An Apple DID_CHANGE_RENEWAL_STATUS re-derives the row's status with TBC_CA_IAP_Apple::derive_status() from the notification's own signed renewal info, written only while both the row and the result are active or canceled. Toggles are ordered by their own signing time (raw.auto_renew_signed_at), so an older one delivered late is skipped as notification_stale. order_unlink() writes a revoked history row from reapply_for_user()'s removed count.
  • The shared lib/class-tbc-licenser.php: licensed_state() reads the verdict from the <license_option>_meta option's last_status (written by activate() and every answered /check in refresh_one(), the same verdict the tbc_license_check_<slug> transient holds) instead of the transient, and the key and _meta are saved autoloaded; autoload_options() flips rows saved before (wp_set_option_autoload_values(), on activate and each refresh). The transient still feeds the update screens. Every add-on carries the same copy.
  • /app-config's features gains space_mark_seen, true where Fluent Community has Helper::markSpaceSeen() (2.12 and later). It tells the app it can call POST /spaces/{slug}/mark-seen, which older Fluent Community doesn't register.
  • TBC_CA_App_Config::fc_listing_sort() reads Fluent Community's listing sort, gated on Utility::getListingSort(): default_<type>_sort_by, disable_<type>_sort_by, and whether fluent_community_spaces_order / fluent_community_courses_order holds an id once CustomSanitizer::sanitizeIdList() has cleaned it, as Fluent's own applyCustomOrder does. spaces_sort() feeds /app-config's spaces.sort ({ default, user_choice, has_custom_order }, always sent, source gone) and the Sorting panel, and is Fluent's A–Z with member choice below 2.12; courses.sort is sent only where Fluent has a Courses sort. sanitize_spaces_settings() and the Spaces save keep only the view keys, so a stored sort is ignored, with no migration. Four strings left the catalogs (es, el, nl).
  • The review kit sends each line of the test chat to ChatHelper::sendMessage() as plain markdown; its own chat_html() wrapper is gone.

1.3.24 — 2026-10-10

✨ New

  • Config › Staging Site: the app switches between this site and its copies. One installed app can move to your staging site, or to a sandbox set up for one person, and back, with no new build. Staging URL is your staging site's address, and Who sees it is Admins only, Admins + roles (the roles you pick), or Everyone, for a demo app where people try your setup. Sandbox access gives one person a sandbox of their own, such as a copy set up for a client: Give a sandbox, pick the member, enter the address (ones you have given before are suggested). A person can have more than one, to compare setups. Admins get the staging site and every sandbox; anyone else sees only what you give them. The card saves with the Save bar like the rest of the settings. In the app the switch is in Diagnostics › Tools › Site. Every address must be a full https address and not this site's own. A site snapshot carries none of it, since it names this site's own copies, and "Delete all plugin data" removes the card's settings and every sandbox given when the plugin is deleted.
  • The Managed tab walks each client through their part. Config, Publishing, WordPress Access and Submit open with a short numbered "Your steps" list, using the same step names as the walkthrough videos. Every unfinished tab shows its orange dot, not just the open one, and Submit lists what is still missing card by card instead of "Complete and save every other tab first."
  • Customize › widgets: the Community Menu widget picks its groups and its layout. Groups is All groups, Only these, or All except these, with a tick-list of your Fluent Community space groups; "All except these" takes in a group you add later on its own. Layout is Menu rows (the sidebar look, as before), Carousel, Browse tiles, Hero card, Buttons or Chips, and the five tile layouts take the same look settings as the Links widget. Show group headings can be turned off, so a widget showing one group reads as one list. The builder's preview draws each layout with your site's real sidebar, and Fluent Community still decides what each member may see. A Community Menu saved before this update keeps its look.

🛠 Fixed

  • Push notifications leave right away again after a plugin is switched off. Since 1.3.21 the site sends a push right after the action that caused it. For a while after any plugin on the site was switched off, and on a brand-new site, that send failed and every push waited for the site's job queue instead: late, but never lost. Sites on 1.3.21 to 1.3.23 were affected. Pushes now leave right away in both cases.
  • Blog authors link to the right profile. The byline on a blog post, and a comment's author, carried the member's WordPress name, but the app opens profiles by the community username, which can differ and which members can change. For those members a tap opened "profile not found". Both now carry the community username. A post containing a Query Loop block could also show the byline of the last post in that loop; the byline now always comes from the post itself.
  • Set Up Review Account and Top Up Access never dress a real member. Pointed at an existing member with an empty profile, Tools › App Review Account could give them the reviewer picture, cover and an "app reviewer" bio. It now dresses only an account it created or one that is already a review account.
  • Top Up Access asks before it makes an account a review account. Top Up gave the App Tester tag to whatever account was named, and that tag is what lets Reset Password and Remove Account act on an account, so one mistyped username could hand a real member to those two buttons. On an account that is not a review account yet, Top Up now stops and names it, and tags it only when you press "Yes, make … a review account".
  • Publishing's test-account buttons work only on a review account. "Reset its password" and "use an account you already made" both replace the account's password, and they refused only staff. A real member's login typed into the field, or picked from the list of members, got a new password, the App Tester tag and a place in every space and course. Both now refuse anything that isn't a review account, and the list shows only review accounts. A reviewer account the Managed tab made before this update has no App Tester tag yet, but these buttons still take it: they know it by its apptester login and its email at this site's address. Reset its password tags it on the first press.
  • Publishing's test account is a full App Review account. "Create the test account" made a bare member in no space, so an app reviewer signed in to an empty app. It now makes the same account as Tools › App Review Account: tagged App Tester, with a profile picture, cover and bio, and a member of every space and course. Both cards show it.
  • A new review or test account gets its own profile picture. Creating an account through Tools › App Review Account or the Video Test Kit could put its picture, cover and bio on the member created just before it.
  • The Managed tab checks what you type, on the field. A colour typed without "#" is taken with the "#" added. Anything that isn't a colour is refused with a message naming the field ("Accent colour: use a colour like #B5412C"), and what you typed stays. An email address with no dot used to wipe the saved address without a word; it is now refused with a message, and the saved one is kept. A refused save reopens on the tab with the problem, and "Saved" shows only when the save went through.
  • A picture you choose on a Managed tile shows at once. The dark splash tile kept reading "Not set — light image used for both" after a file was chosen, until the next save.
  • Store Listing counters count as you type, a line break counts as one character, and line breaks no longer carry a stray "\r" into the site snapshot.

🔧 Changed

  • Submit works as soon as the licence is active. It sends what is done so far, so a client still waiting on one account does not hold up the rest. The Submit tab lists what is still missing, and Submit Update sends it later.
  • Config needs the Terms of Use page as well as the privacy policy before it turns green. A "Not set" privacy row links to WordPress's Settings › Privacy ("Use a page you already have"), and the policy dialog says when the legal name and contact email were filled in from the site, so the client checks them.
  • Publishing marks Contact email as required. It is who Apple contacts if the review hits a problem, and Publishing's dot turns green only once it is in.
  • "Notes for the reviewer" is gone from Publishing. The dashboard writes the notes for the app reviewer. Site snapshots no longer carry them, and an updated site deletes any notes it had saved, since they could hold demo sign-in details.
  • The Managed tab's Staging URL field is gone. The staging site is set in Config › Staging Site. Snapshots no longer carry the old field, and an updated site deletes its saved value.
  • Our administrator has a profile picture. WordPress Access › Create the user gives the Two Birds Code administrator our logo as its picture, a plain cover and a one-line bio, so members who see it post or reply know who it is. An administrator made before this update gets them the next time the card is opened, if it has already joined the community. Only our own account is dressed, once, and anything already set on it stays as it is. Uninstalling the plugin clears the picture and cover, since their files go with it.
  • The tile help matches the dashboard: a 61% safe zone, an all-white notification icon, PNG-only splash images (anything else is refused on upload), and #1a1a1a as the dark splash default. "Saved" flashes only for Save Progress; the create, user and Submit buttons report their own result.

📡 OTA & Internal

  • The staging site is its own option, tbc_ca_staging (url, audience, roles; autoloaded, since every /app-config reads it), not a tbc_ca_settings key. Sandboxes are user meta, tbc_ca_switch_site. TBC_CA_Core::normalize_staging() is the one audience rule for reads and saves. /app-config sends features.staging_sites, the sites this viewer may switch to (TBC_CA_App_Config::staging_sites_for_viewer()); a signed-out caller gets the staging URL only when it is open to everyone, so the public, cacheable answer carries nothing else. The card is an admin-app island (StagingSite.js) that keeps its state in a hidden field the save bar submits.
  • The push hook claims its jobs by hook alone and clears Action Scheduler's leftover claim filters around it; a group filter threw "The group … does not exist" while the hybrid store was active.
  • Database version 1.0.22: the upgrade routine and activation drop review_notes and staging_url from tbc_ca_managed.
  • fcom_author.slug and fcom_author_slug are the Fluent Community username (null without a Fluent profile), and fcom_avatar is null, not false, when an avatar filter clears the URL.
  • The shared save bar (lib/tbc-save-bar.*) skips its "Saved" flash on a page that reports a refused save.
  • A Branding tile's preview revokes its object URL once drawn, so a picked file (up to 4 MB) no longer stays in memory until the page closes.
  • The submit email says whether it is a Submit or a Submit Update and lists the cards still missing when it was sent. TBC_CA_Admin_Managed_Build::tabs() and missing_cards() are the one table the tab dots, the Submit card and that email read. TBC_CA_Managed_State::all_prerequisites_complete() is gone.
  • Widget registrations gain a checklist setting type: a tick-list over options or options_source that stores the array of ticked values (ints under an id-keyed source such as the new fc_space_groups_set). button_fields() and tile_view_gates() give the Links and Community Menu widgets one declaration of the button and tile-look settings. The builder's menu payload carries up to 20 groups with their ids and each row's permalink.
  • New strings translated into Spanish, Greek and Dutch.

1.3.23 — 2026-10-08

🛠 Fixed

  • Blog posts carry their author for the app. Every post the app reads now includes its author: name, profile link for signed-in readers, Fluent Community photo (or Gravatar), verified tick and badges. Members see the byline even on a site that hides its member list from the REST API, as FluentAuth's "Disable users REST" setting does. Before, they saw "Unknown".

📡 OTA & Internal

  • The post's byline is the fcom_author REST field. The author fields on the REST user object (fcom_avatar, fcom_is_verified, fcom_badge_slugs) have no reader in the current app; they stay for older app builds and are marked for removal by 2026-12-31.

1.3.22 — 2026-10-07

✨ New

  • Comment box in Customize › App Screens › Feed. Pick how members start a comment: the floating "Write a comment…" bar (as before), a round floating button, or a box at the top of the comments. It is set apart from the post box, so the two can differ, and its own "Members can change this in the app" switch lets each member choose under Settings › Comment Box in the app.
  • Backup & Restore knows the User Switching add-on. A site snapshot carries TBC User Switching for Fluent Community's license key (with "Include secrets" on) and its "Delete all plugin data" switch, the same as every other add-on.

🛠 Fixed

  • Customize's Post actions settings are translated. The Reaction, Comment and Reaction summary sizes added in 1.3.21 showed in English on Spanish, Greek and Dutch sites. They are now translated, along with the new Comment box setting.

1.3.21 — 2026-10-02

✨ New

  • Post actions sizes in Customize › App Screens › Feed. Pick Small, Medium or Large for the react button, the comment button and the reaction summary under each post. Medium is the size they've always been. The phone preview now shows the reaction summary too, and redraws all three as you choose.

🛠 Fixed

  • WordPress's "Check again" finds our updates. Dashboard › Updates › Check again now asks our licence server too, so an update we've just published shows at once instead of up to 12 hours later. Before, only the plugin's License tab Refresh did that.
  • Push notifications arrive in seconds. A comment, reply, mention or message used to wait in your site's job queue until its scheduled tasks next ran: about two minutes on average on a server that runs them every five, and on a site that relies on visitors to run them, until someone visited. Your site now sends each notification right after the action that caused it, once the member's own request has been answered, so nobody waits for it. A send to more than 100 people still goes through the queue, and a notification is sent once even when the queue runs at the same moment.
  • The Push Log shows failed pushes. On every site that installed the plugin before its log learned to record errors, a push that failed was missing from the log and wrote a database error to the site's PHP log instead. The update adds the two missing columns and keeps every existing log row.

📡 OTA & Internal

  • The three post-action size settings are checked against one list when the app's settings are sent, when Customize loads and when it saves.

1.3.20 — 2026-09-29

✨ New

  • A Chat setting picks the app's chat look, Classic or Modern, in Customize › App Screens › Chat. Members can pick their own in the app's Settings unless you turn off Members can change this in the app.
  • Sign up follows your custom sign-up page. When Fluent Community takes sign-ups on a page of its own and the app follows your site, the app's Sign up opens that page, and the app's own form refuses sign-ups the way Fluent Community does; invitations still work. The Sign-in screens settings warn you if that page takes payment, because Apple rejects apps that send people to pay on a website.
  • The settings page shows the installed plugin version beside its title, on every tab, so you can tell at a glance which release your site runs.
  • The Video Test Kit's members look like real people on camera: Maya Brooks and Leo Hart, each with an illustrated portrait, in place of "Test Member" and a lettered tile. The App Review account's portrait is new too.

🛠 Fixed

  • Security: an app request only ever runs as the member its app token belongs to. A WordPress login in the same browser can no longer decide who the request runs as, and a signed-in browser without an app token keeps WordPress's own safety check. A sign-in token that is used twice ends that sign-in everywhere, and the app's browser session lasts two days, not fourteen. Update soon.
  • The plugin can't take your site down. If a Fluent Community update changes something the plugin relies on, the app's features stop and the website keeps running. A malformed app token gets a plain "not signed in" instead of a server error, and a push that fails no longer loses the member's comment or reaction.
  • The app still connects when Fluent Messaging can't give its live-chat details, for example while Fluent Community is switched off. The app checks for new messages on a timer instead of every member seeing Unable to Connect.
  • Sign-in follows FluentAuth's own protections. FluentAuth's "Secure now" signs every app out too, its IP blocks and role rules apply when a member signs in through the app's browser, emailed sign-in codes stop at FluentAuth's own limit, and a two-step setup the community requires at sign-in runs through FluentAuth's own steps. A member with only a passkey gets recovery codes instead of being signed out on every refresh.
  • The settings page opens with Fluent Community switched off. It used to crash.
  • A link to your site's www. address, or the address in different capitals, opens signed in in the app's browser, instead of failing with "Redirect URL must be on the same domain".
  • Setting up two-step sign-in no longer uses up your sign-in attempts.
  • Fluent Cart prices in the app use your store's number format. A store set to comma decimals shows 1.234,56, as the website does.
  • Deleting a member's account removes their app devices and notification tokens too. They used to stay behind in the plugin's tables.
  • Adding members to a space in bulk no longer sends moderators a notification for each one. A 500-member import sent 500.
  • An app caught in a loop can't flood your site with website sign-in links; it stops at 10 unused.
  • Errors the app hit reach your Sentry. A failure the member only saw as "An internal error occurred" is now reported, with personal details in database errors masked, and a live site no longer files its errors as development.
  • Sign-in keeps working beside other plugins that bundle the same token library. Our copy now has its own name, so whichever loaded first no longer breaks the other. Nobody is signed out.
  • Accounts that can publish are protected. In-app account deletion is refused for an account that can publish posts, since deleting it would delete everything it wrote, and the App Review account picker leaves those accounts out. An in-app purchase can never grant a staff role. Grant Access never promotes an existing account just because it uses the vendor email address. An app sign-up, and the App Review tester, never get a staff role, whatever your site's default role is set to.
  • An in-app purchase can't take away access a member already had. Buying a membership they already held is no longer recorded as bought, so a refund or lapse can't remove a space, course or moderator seat from before.
  • The message shown when your site can't read Google Play purchases gives advice that works: set the robot's permissions in the Play Console invite itself, at app level, and invite it again if it was invited without them. In all four languages.

🔧 Changed

  • Urgent notifications go out at once. A notification that has to arrive within seconds, like an incoming call, is sent straight away at high priority instead of waiting in the queue.
  • Lighter on your site. App traffic no longer writes to the options table on every request, and a member's device check-in costs one lookup. Push jobs are split small enough that none is silently dropped, a push type you switched off queues nothing, and sends to Expo give up after 10 seconds. Apple purchase checks give up after 15 seconds instead of 60.

1.3.19 — 2026-09-19

✨ New

  • A new password or Log Out Everywhere also ends the member's app sessions. Changing or resetting a password signs the app out on the member's other devices — keeping the one that made the change, as Fluent Community keeps the browser — and Log Out Everywhere on the profile ends every one. Setting the same password again changes nothing — WordPress does exactly that when it upgrades a stored password at sign-in, and the review-account tools do it when they re-apply one.

🛠 Fixed

  • A message in a space's chat no longer sends a push to every member of the space. It sends none, the same as Fluent Messaging, which never alerts members one by one about a space message. Before, each member got a push that opened a private chat with the sender.
  • A passkey finishes the sign-in on a site that asks for one more step after it. Where the community wants a further step once the phone has answered, the member is sent to the website to complete it there, instead of being told the passkey could not be used. Requires FluentAuth 3.0.3.
  • The YouTube hero's preview says which source you picked. In Customize → Widgets, the note under the preview now reads "Show: One playlist" (or Latest uploads, and so on) beside the playlist name. It was looking for a setting under a name no widget uses, so that line never appeared.
  • Signing up in the app finishes with the second step your community requires. On a community that asks every account for a second sign-in step, a member who joins in the app now sets one up as the last step of signing up, exactly as the website makes them — instead of being let straight in and not asked until they next signed in from scratch. Communities that do not require a second step see no change.
  • Verifying your email while signing up is not followed by a second code. On a community whose second sign-in step is an emailed code, a member who had just typed the code from their sign-up email was immediately sent another one to type. Proving the mailbox during sign-up now counts, the way it does on the website, so the same address is never asked for twice in a minute.
  • Emails look like the community's own. Sign-in and sign-up codes, gate emails and space emails go out through Fluent Community's mailer and template, and show in its email log, instead of a plain box sent straight through WordPress.
  • The in-app cart follows the store's rules. A store that shows prices including tax gets the same totals in the app; quantity limits, add-on details and unit prices come from WooCommerce's and Fluent Cart's own rules.
  • Member tiles follow Fluent Community's avatar rules, so a site with Gravatar switched off no longer loads it for tiles; push titles use each member's public display name.
  • The generated Terms of Use stop saying the app sells nothing on a site with in-app purchases switched on. With IAP active they say purchases are handled by Apple or Google under their own terms; Terms generated before are flagged for regeneration once.
  • Google Play's subscription notifications count as signed only when the verification service account sent them. The audience alone identified no one.
  • A closed-sign-up message written before the hide-or-message setting existed keeps showing, instead of the Sign up link disappearing.
  • Test Push's MismatchSenderId hint says to rebuild the app with the current google-services.json.
  • The Customize picker's website links follow Fluent Community's own portal address, so a site using its hash routing gets working links, and the base-URL filter is honoured.
  • Deactivation is offered only to an active profile, the only kind Fluent Community will deactivate.
  • Config snapshots carry the in-app selling confirmations faithfully. The Paid Applications tick travels both ways between the managed wizard and the dashboard, a snapshot naming one confirmation no longer unticks the other, and a step unticked in the snapshot no longer unticks one the site already confirmed.
  • A page's title shows as text in the Customize menu picker and in the app — a curly apostrophe read "You&#8217;re".

🔧 Changed

  • "Delete all plugin data" removes the license key too. With that switch on, uninstalling removes everything the plugin stored — the license key, its licenser records and cached checks included — so a reinstall asks for the key again. With it off, nothing is deleted, as before. Every TBC plugin now does the same; before, some kept the key and some did not.
  • Support for app releases older than 1.3.17 goes — the legacy unlock string, the pre-split IAP bucket, and fallbacks for older Fluent plugins. An unreadable purchase scope now opens nothing.
  • /password/reset is gone. Forgot password hands off to WordPress's own reset email.
  • /account/deactivate is gone — the app deactivates through Fluent Community's own profile endpoint. An app older than 1.3.19 can no longer deactivate an account against this version: its request fails, and nothing is changed. Push the 1.3.19 OTA with this update.
  • The Managed tab's Google Play step is one Admin invite, through which the app's own upload robot — made in the client's own Firebase project — is added; no shared robot is invited any more. The Firebase step asks for Owner when the client will sell inside the Android app, and says the free Spark plan covers push otherwise; Sell in your app gains the Android step only the client can take; and a note warns that a Google Workspace organisation may block robot keys.

📡 OTA & Internal

  • The plugin reference and setup guide match the plugin as it ships: the two-factor and passkey endpoints with the FluentAuth 3.0.3 floor, the admin's seven tabs and its Tools cards in order, the review tools where they are, and the managed onboarding as it now runs.
  • Sign-in asks FluentAuth what an account still owes at the one place tokens are handed out, rather than in each sign-in route. Nothing changes for a member; a route added later cannot skip the question.
  • A successful sign-up in the app returns the sign-in reply — the same tokens and the fuller account block /auth/login sends, answered 200 rather than 201.
  • /auth/register no longer accepts a context of web, which nothing ever sent, and every caller's device identifier is checked. Any reply that does not carry tokens once the account has been made says account_created, so the app can send the member to sign-in rather than back to a form that can no longer succeed.
  • The settings screens drop dead routes, inputs and CSS, and the two legal generators share one set of helpers.
  • The shared licenser drops hooks and an argument nothing used, and its comments say what it does rather than how it got there.
  • Sessions are revoked through one loop, and purge-all-sessions deletes through WordPress's metadata API rather than raw SQL.
  • Logged-in REST responses keep WordPress's own no-cache headers instead of a weaker copy.

1.3.18 — 2026-09-17

✨ New

  • Two-factor sign-in, answered in the app. Five self-service endpoints for an authenticator app — what the member has set up, start a pairing, finish it with a code, turn it off, issue fresh recovery codes — and the sign-in endpoint now parks a challenge for whatever the account owes, so an authenticator code or a recovery code finishes the sign-in instead of sending the member to the website. Finishing a pairing issues recovery codes only where the account holds none — issuing a set retires the old one, and a member who has printed theirs should never lose them to a set-up they were not told about. FluentAuth decides every question, so the app and the website can never disagree about an account.
  • Passkeys. Two public routes hand out a passkey challenge and take the answer for a passwordless sign-in, four more add, rename and remove passkeys over FluentAuth own store, and the site-association files now tell both phones that this app may hold the site passkeys — including the Android origin FluentAuth compares against, without which every passkey from the Android app is refused. A passkey registered with nothing behind it comes back with its recovery codes, so it can be asked for at sign-in from the moment it exists rather than sitting dormant until the member goes looking.
  • Every block in Fluent Community's editor says whether the app can draw it. Writing a lesson or a Space Page, each block in the inserter carries a small mark: green where the app paints it as the web does, amber where it renders with a different shape — a two-column row becomes one column, a button arrives as a tappable link. Hovering says which, and a line under the first heading explains the colours. Every block carries one or the other, so an unmarked button never means nobody checked.

🛠 Fixed

  • A join request reaches the people who can answer it. The push went to moderators as well, who cannot approve one. It goes to space admins only, opens the members screen on its Requests tab, and its switch appears for the admins who now receive it rather than for everyone.
  • A hand-set JWT secret shorter than 32 bytes no longer fatals every login. The bundled php-jwt refuses to sign or verify with one from version 7, so a site whose key had been set by hand could not sign anybody in. A short key is replaced.
  • A wrong sign-in code counts as a failed login, so the site rate limiter and security log see it.
  • Turning the authenticator off does nothing when none is set up, as FluentAuth own handler checks.
  • A build installed straight from EAS gets App Links and passkeys. Those builds are signed with the EAS upload keystore, not the Play app-signing key the site trusted, so the phone refused them. The Deep Linking card has a second field for that key; both are published and both are accepted.

🔧 Changed

  • The plugin now asks for PHP 8.1, the setup guide's hosting requirement all along. The bundled php-jwt moved from 6.10.0 to 7.1.1, which drops PHP 7.4 (end of life since 2022) and stops PHP 8.4 filling debug.log with a deprecation notice on every token. WordPress refuses to install the plugin on an older PHP rather than letting it break.
  • /app-config sends one colour wire. The plugin used to resolve the app palette and then rebuild Fluent section bags from it, shipping the same theme twice on its hottest payload. A phone on a store build from before core 1.3.4 shows the app default colours until it takes a store update; it cannot crash.
  • The manual push composer takes id lists only. A stale Tools tab gets "No users found for the selected audience" and works after a reload. It fails closed — a narrowed audience can never turn into a broadcast.

Managed · we build it, you own it

Your community. Your brand. A real native app — without becoming an app developer.

A polished iOS and Android app for your WordPress + Fluent Community site, with the entire technical side run for you. Configure it from a panel inside WordPress, grant us access to your store accounts, and click Submit. No source to manage. No Expo, no Xcode, no build pipeline.

Yourspublished under your own Apple and Google accounts — you own the listing
2stores, built and submitted by us, every release
$0build tooling to learn. The technical side is not yours to run
Cancelanytime — your published app keeps working, because it is yours

Start now · no licence needed

Install the plugin and set up before you pay.

Apple and Google both have to approve your developer accounts, and that can take days. The Managed setup panel works without a licence, so you can get your accounts open and your details entered while you wait. Buying unlocks the Submit step.

Download the plugin

Always the current version. The plugin’s other settings stay read-only until your licence is active.

Three steps

  • Install it — in WordPress, Plugins › Add New Plugin › Upload Plugin, then activate. Your site needs Fluent Community, HTTPS and PHP 8.1 or newer.
  • Set up — open TBC Community App › Managed and work through Access & Credentials. Everything saves as you go.
  • Buy and submit — purchase Managed, activate your licence on the License tab, then click Submit. We take it from there.

Three parts · one service

What members get, what you control, what we do.

Click a tab. Every capture opens full size. Deeper pages: The App, The Plugin.

Managed › How it works
Choose a view

A complete community experience

Not a wrapper around your website

Feeds and threaded comments, spaces, courses with progress, real-time messaging, member profiles and native push — in light and dark, on phone and tablet. Every screen below is a real capture.

The app home screenThe app home screen
Home, arranged from WordPress.
The activity feed on a phoneThe activity feed on a phone
Posts, comments and reactions.
The course list on a phoneThe course list on a phone
Courses, lessons and progress.
The member directory on a phoneThe member directory on a phone
Members, profiles and connections.

Your command centre

You run it from WordPress — no code, no rebuild

The companion plugin is where the app is shaped. Server-side changes reach members the next time they open it, with no new build and no store review.

  • Menus & navigation — add, rename, reorder and hide tab-bar, launcher and header items, with role-based visibility
  • Push notifications — enable types, set defaults, broadcast announcements, send test pushes and review a full log
  • Version gating — require a minimum app version, with a built-in update screen
  • Maintenance mode — a blocking screen with your message, and a role bypass
  • Staging and sandboxes — the same installed app switches to your staging site, or a sandbox you give one person, and back
  • Feature toggles — show or hide profile tabs, home widgets and more
  • Widget screens — build Home and any other screen from widgets, then keep it locked in your order or let members rearrange it and hide what they don’t use
  • Space admin on the phone — your space admins manage members and join requests, the space’s own menu, its links and its pages without opening WordPress
  • Moderation in the feed — a flagged post carries its reports for the people who moderate it, and a verdict settles it in place
The Customizer editing a launcher item beside a live phone preview
Editing a launcher item, previewed on a real phone frame.

Configure once, then click Submit

The technical side is ours, the app is yours

Everything we need lives in one Managed App Setup panel inside your WordPress admin. After that:

  • We build it. Native iOS and Android binaries, done by us, every release
  • We publish it — on your accounts. Your app lives under your Apple Developer and Google Play accounts, so you own the listing
  • We keep it current. New features and fixes land in your app as we ship them
  • You stay in control day to day through the companion plugin
The Managed App Setup panel in WordPress, ready to submit
One panel, then Submit. We take it from there.

The options · and why this one

Every other way onto a phone gives something up.

A custom-built app used to cost tens of thousands. The cheaper ways that followed each trade away something your members notice, or something you own. Managed is priced below.

The other ways

A web app — members follow browser steps to save your site to their home screen. Every screen is still the website, it is in neither store, and on iPhone push only works once the site has been added.

A shared app — every community’s members download the same app from someone else’s listing, then find their way into yours. Quick and cheap, but the app on the phone carries their name.

A branded-app platform — a native app with your name on it, which can cost $1,000 to $4,000 a year, every year, and on some, the app stops working the day you stop paying.

TBC Managed — native, with your site built in

In both stores, under your name — put “Download on the App Store” on your site, your emails and your printed cards, and members install it like every other app.

Native where members spend their time, your whole site behind it — the feed, messaging, spaces, courses and profiles are native screens, and anything else your WordPress site can do, from a form to a checkout, opens inside the app already signed in.

Push with real depth — up to nineteen kinds of event with a switch each, settings per space, announcements you send from WordPress, and a tap that lands on the exact post.

Shaped without code, built by us — menus, widget screens and the theme are arranged in WordPress on a live preview, add-ons bring new screens, and we handle every build and store submission. On your own accounts, and it keeps working if you stop paying.

Everything members get

  • Real-time feed — posts, threaded comments, multi-reactions, polls, mentions, bookmarks
  • Spaces and groups — public, private and secret, each with its own feed and members
  • Direct and group messaging — real-time chat, reactions, images, typing indicators, unread badges
  • Courses and lessons — progress tracking, quizzes of every question type, drip content, completion celebrations
  • Passkey sign-in, an authenticator app and recovery codes, set up without leaving the app
  • Member profiles — follow and unfollow, custom fields, badges, connections
  • Native push — granular, per-category, deep-linked straight to the content

And across the app

  • Search and directory — find posts, spaces, courses and members
  • Light and dark mode — colours sync automatically from your Fluent Community theme
  • Tablet and phone ready — one app that adapts from phone to tablet to foldable
  • English, Spanish, Greek and Dutch built in, with more languages addable

Pricing

A monthly price per app. No setup fee.

One app is $33 a month. From three apps, each app is $26 a month. Choose how many apps at checkout. You get one subscription and one license key, and the key works on that many sites.

Six apps or more? Email us and we will set it up by hand, at $26 an app.

Cancel anytime. Your published app keeps working — it is yours. You simply stop receiving new updates, new builds and new submissions.

Want the source later? Start on Managed, and buy the Dev Bundle when you want the code and to run the builds yourself. Your app stays on your own store accounts either way.

Making apps for clients? The Dev Bundle is priced per site, and from three sites each one is $299 once. You run the builds yourself and can charge your clients for managing their apps.

Store fees are paid to Apple and Google, not to us: Apple Developer Program $99/year, Google Play Console $25 one-time. Nonprofit, school or church? Apple waives its yearly fee for eligible organisations whose apps are free (no in-app purchases); Google has no waiver. You will also need a WordPress site running Fluent Community (Pro recommended).

1 appfirst build and submission, then every update and republish$33 / mo
2 apps$33 an app$66 / mo
3 apps$26 an app$78 / mo
4 apps$26 an app$104 / mo
5 apps$26 an app$130 / mo
6 apps or moreemail us, $26 an appContact us
Apple Developerpaid to Apple · waived for eligible free-app orgs$99 / yr
Google Play Consolepaid once to Google$25

0 Reviews

Loading reviews...

No reviews yet. Be the first to write a review!

Related Products

TBC - Web - Admin Columns

TBC - Web - Admin Columns

Fluent Community fields, stats, roles and user-meta as sortable, inline-editable columns on the Users list and WooCommerce Orders.

Price: $0.00
TBC - Web - Automations

TBC - Web - Automations

Eighteen Uncanny Automator triggers and actions for Fluent Community — DMs, notifications, follows, points, spaces, posts.

Price: $0.00
TBC - Web - User Switching

TBC - Web - User Switching

Puts the free User Switching plugin's buttons in the Fluent Community portal: Switch user on a member's profile, and Switch back in the header to return to your own account.

Price: $0.00
TBC -App - Better Messages Addon

TBC -App - Better Messages Addon

Hand the app’s messaging to Better Messages — threads, group chats, attachments, reactions, rooms — with push that deep-links to the conversation.

Price: $0.00
TBC App - Community App (Dev Bundle)

TBC App - Community App (Dev Bundle)

The full React Native source plus the build dashboard. Configure your site, drop in your assets, and ship to both stores yourself — no coding required.

From $50.00
TBC App - Youtube Widget

TBC App - Youtube Widget

Your latest uploads on the home screen, tapping through to playlists and videos — cached server-side so it never burns API quota.

Price: $29.00