Skip to content
View in the app

A better way to browse. Learn more.

ernestdefoe.online

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
ernestdefoe.online

Extensions, themes & support for Flarum and Invision Community

Vibe coding for the community web. Report a bug, request a feature, or dig into the source — this is where the tools you use get built, in the open.

We do custom Bespoke Invision Community apps. If you have an idea for something you want then use the contact form to get in touch with us.
Knowledge base

Things that cost me a day, so they cost you none

Working notes from building Invision Community and Flarum applications. Mostly the failures that give no error at all — the ones where everything installs cleanly and quietly does the wrong thing.

92 articles

Invision Community 5

86 articles

Extensions and contracts

39

What each extension point is for, what it must declare, and what happens when it is wrong — which is usually nothing visible.

Languages and text

5

The string table, translation, and the places where text does not appear where you expected it to.

Theming, templates and forms

9

Theme hooks, CSS that survives both colour schemes, and building forms that do not throw on render.

Background work and scheduled tasks

5

The queue system, work that has to happen after the response, and jobs that finish without doing anything.

Data, settings and storage

11

The database layer, settings, tags, file storage, and backing up a live site.

AI features and expectations

5

What these features do, what they cost, and what buyers reasonably but wrongly assume they do.

Application structure and releases

11

The JSON files an application is made of, versioning and upgrade steps, and testing from the command line.

Realtime, chat and calls

1

WebSocket gateways, relays and the server-side pieces live features depend on — where "it works when I test it" and "it works for your members" are different claims.

Nothing matches that.

Extensions and contracts

What each extension point is for, what it must declare, and what happens when it is wrong — which is usually nothing visible.

39 Articles in this category

  1. Ernest Defoe ·
    You write an extension, the file lints clean, and installing the application dies: Fatal error: Declaration of IPS\myapp\extensions\core\FileStorage\Audio::move(?int $offset = null): void must be compatible with IPS\Extensions\FileStorageAbstract::move(int $offset, int $storageConfiguration, ?int $oldConfiguration = null): void Extension methods are declared by an abstract class, and PHP enforces the signature exactly. This is not a warning you can ship past — the application will not install
    • 0 comments
    • 24 views
  2. Ernest Defoe ·
    If your application needs to react to content being posted anywhere — forum topics, gallery images, calendar events, downloads, blog entries, and every record in every Pages database — you do not need a listener per class. You need one, declared against the right base class. Why the obvious approach does not scale A content listener is registered in data/listeners.json with the class it watches: { "Post": { "type": "ContentListenerType", "classname": "IPS\\myapp\\listen
    • 0 comments
    • 18 views
  3. Ernest Defoe ·
    If your application connects members to an outside service — Discord, Telegram, anything with OAuth — the temptation is to add a table: myapp_links, member id, remote id, done. Do not. Invision Community already stores that relationship, and keeping a second copy creates a class of bug you cannot fix later. core_login_links When a member signs in with, or connects, an OAuth login handler, the link is recorded in core_login_links: token_login_method — the id of the login handler token_mem
    • 0 comments
    • 23 views
  4. Ernest Defoe ·
    Achievements are the points, badges and ranks a member collects for taking part. A core/AchievementAction extension is one thing a member can do that an administrator is then allowed to attach a rule to. "Member starts a topic", "member votes on a poll", "member's answer is marked as the best answer" and "member downloads a file" are all AchievementAction extensions; each one appears as an option in the drop-down at ACP → Members → Achievements → Rules → Add Rule, brings its own filter fields to
    • 0 comments
    • 22 views
  5. Ernest Defoe ·
    The core/AdminNotifications extension is how something on the site gets an administrator's attention. It defines a type of ACP notification. Once one has been raised, the bell in the AdminCP header gains a count, the notification appears in the dropdown behind that bell and on the notification centre at app=core&module=overview&controller=notifications, and — if you declared it high or critical — it is also rendered as a coloured banner across the top of every AdminCP page. Critical ones
    • 0 comments
    • 20 views
  6. Ernest Defoe ·
    An administrator opening AdminCP → Site Features → Integrations sees a grid of cards, one per third-party service: Google Analytics, Mailchimp, Giphy, Zapier, Mapbox, Postmark, MaxMind and so on. Each card carries a title, a short description, a logo, an Enable or Disable button, and — once the service is on — a Configure Service button that opens a settings form. The core/CommunityEnhancements extension is what puts one of those cards on that page. That is the whole of its job. It does not make
    • 0 comments
    • 22 views
  7. Ernest Defoe ·
    A core/EditorMedia extension adds a tab to the Insert existing attachment dialog — the folder icon in the editor's attachment bar. A member composing a post clicks it, and gets a grid of files they already own on the site, with a search box and pagination, and a button to insert one or several into the post they are writing. Core ships one source (their previous post attachments), Gallery adds their gallery images, and Downloads adds the files they have uploaded to Downloads. Your extension adds
    • 0 comments
    • 23 views
  8. Ernest Defoe ·
    An administrator types an IP address into AdminCP → Members → IP Address Tools and gets a grid of tiles: "Posts 14", "Registrations 1", "Device Logins 3", "Transactions 0". Clicking a tile opens a table of the matching records. The same screen exists for moderators in the ModCP under "IP Tools", and the reverse view — every IP a given member has ever used, with a first-seen and last-seen date — appears on a member's ACP profile, in the ban form, and in the GDPR personal-information export. Every
    • 0 comments
    • 24 views
  9. Ernest Defoe ·
    When an administrator opens a member in the AdminCP — app=core&module=members&controller=members&do=view&id=1 — the page they see is not a template. It is a two-column grid assembled at runtime from a list of small classes, one per panel: the header with the 30-day posting sparkline, the groups panel, the warnings and restrictions panel, the known devices panel, the quota bars, the Commerce customer panel. Each of those is a core/MemberACPProfileBlocks extension. The extension po
    • 0 comments
    • 25 views
  10. Ernest Defoe ·
    Invision Community keeps an audit trail of things that happen to a member's account — group changes, display name changes, password changes, warnings, purchases, and so on. Each entry is one row in core_member_history, and the row itself is nothing but an application key, a type string and a blob of JSON. A core/MemberHistory extension is what turns that JSON back into a readable sentence. Without one, an administrator looking at ACP → Members → (a member) → History sees a blank cell where the d
    • 0 comments
    • 20 views
  11. Ernest Defoe ·
    In the AdminCP, every member's profile page carries a box headed "Warnings & Restrictions". It lists, in red, the things this particular account is currently not allowed to do — "Restricted from submitting files", "Restricted from using tags", "Restricted from accessing Gallery" — and it has an Edit link that opens a dialog where an administrator can turn those restrictions on and off for that one member. A core/MemberRestrictions extension is how an application adds its own rows to that lis
    • 0 comments
    • 24 views
  12. Ernest Defoe ·
    The core/MetaData extension point backs three things a member sees on a content item: the coloured staff notice pinned above the first post ("Item Message"), the box of recommended replies shown above the comment list ("Featured Comments"), and the moderator toggle that makes every new reply to one particular topic require approval ("Item Moderation"). All three store their state as rows in a single shared table, core_content_meta, rather than in the content item's own table, and the three exten
    • 0 comments
    • 25 views
  13. Ernest Defoe ·
    A core/ModCp extension adds one section to the front-end Moderator Control Panel — the page at /modcp that moderators use to work through reports, the approval queue, hidden and deleted content, warnings, alerts, announcements and IP lookups. Each extension owns one entry in the left-hand menu, owns the whole content pane when that entry is selected, and may optionally contribute a counter badge to the strip along the top of the page. There is no other way to add a section to that screen; the me
    • 0 comments
    • 22 views
  14. Ernest Defoe ·
    A moderator who opens the Moderator Control Panel and clicks "Member Management" gets a member search box and, under it, a strip of tabs: Banned, Restricted, Queued. Each tab is a table of members who are in some administrative state the moderator may need to act on — members serving a ban or suspension, members whose posts are being held for approval, members whose content is queued. A core/ModCpMemberManagement extension is one of those tabs. It supplies the tab key and the HTML of the table b
    • 0 comments
    • 24 views
  15. Ernest Defoe ·
    The core/Notifications extension is what puts an entry behind the bell in the site header. It does two separate jobs for one type of member-facing notification. First, it declares the switches a member sees under Account Settings → Notification Settings — the rows that let somebody choose whether "somebody replied to content you follow" arrives in the notifications list, as a web push notification, as an email, or not at all. Second, it turns a stored notification row back into something readabl
    • 0 comments
    • 21 views
  16. Ernest Defoe ·
    A core/OverviewStatistics extension adds a tile to the statistics dashboards an administrator sees under ACP → Statistics → Key Statistics. There are two such dashboards — "User Activity" (app=core&module=stats&controller=overview) and "Content Activity" (app=core&module=activitystats&controller=overview) — and a third page, "Saved Reports" (app=core&module=overview&controller=mycharts), where an admin can pin individual tiles into a named report and download the whole re
    • 0 comments
    • 23 views
  17. Ernest Defoe ·
    When a member with an unfinished profile loads any front-end page, Invision Community shows a small panel above the content: a progress bar, "Next Step: Birthday", and a "Complete my profile" button. Pressing it opens a wizard at app=core&module=system&controller=settings&do=completion that walks the member through the outstanding items one form at a time. An administrator decides what those items are under AdminCP → Members → Profiles → Profile Completion, where each row is a "step"
    • 0 comments
    • 23 views
  18. Ernest Defoe ·
    A core/Statistics extension is one graph on the ACP Statistics tab. It is the thing an administrator sees when they open Statistics → Registrations or Statistics → Posts: a chart with a timescale selector, a date range, optional filter tabs, a data table underneath, and a "save this chart" action. Saving is the part that makes the extension worth writing rather than just building a chart inline in your controller. A saved chart is pinned to Statistics → Key Statistics → Saved Reports (app=core&a
    • 0 comments
    • 23 views
  19. Ernest Defoe ·
    A core/Build extension is a hook into the developer's "build application" step in the AdminCP. Nobody browsing the community ever triggers it. What they experience is its output: files that are generated at build time and shipped inside the application tar, rather than committed to the repository. Core's only implementation is the reason the ACP code editor has syntax highlighting at all — the CodeMirror sources live under applications/core/dev/codemirror/, the build filter deliberately excludes
    • 0 comments
    • 21 views
  20. Ernest Defoe ·
    The core/ContactUs extension controls what happens on the site's Contact Us page. A visitor opens app=core&module=contact&controller=contact, types a message, and presses send. What that page looks like, and what actually happens to the message afterwards, is decided entirely by these extensions. Each one contributes one or more choices to the "Contact Us behavior" radio in the ACP (Settings → Contact Us), contributes the configuration fields that go with those choices, may add fields to
    • 0 comments
    • 23 views
  21. Ernest Defoe ·
    A member in Invision Community has one primary group and any number of secondary groups. Every per-group setting therefore has several candidate values at once, and something has to decide which one the member actually gets: five attachments or fifty, a signature or no signature, a thirty-second flood control or none at all. A core/GroupLimits extension is how an application declares that decision for the group columns it owns. It does not add settings and it does not enforce anything — it is a
    • 0 comments
    • 23 views
  22. Ernest Defoe ·
    Every AdminCP page has a search box in the header. An administrator types three or more characters into it, an overlay drops down, and down the left of that overlay is a list of areas — Settings, Members, Groups, Clubs, Forums, Downloads Categories, and so on — each with its own result count. Clicking an area shows that area's results as a list of links. A core/LiveSearch extension is one of those areas. It decides whether the area is visible to this administrator, whether it should be the pre-s
    • 0 comments
    • 21 views
  23. Ernest Defoe ·
    When an administrator opens a member in the AdminCP — app=core&module=members&controller=members&do=view&id=1 — they see a two-column page of blocks: basic information, groups, warnings, content statistics, and so on. The core/MemberACPProfileTabs extension adds a second (third, fourth) whole page of blocks to that screen, reached by a tab bar across the top. On a stock install with Commerce installed there are exactly two: "Member View" and "Customer View". Your extension is wha
    • 0 comments
    • 24 views
  24. Ernest Defoe ·
    The core/MemberExportPersonalInformation extension decides what goes into the XML file a community produces when someone asks for a copy of their personal data. There are two places on a site where that file is produced: a member can request their own copy from Account Settings → Privacy, an administrator approves the request, and the member then downloads it; or an administrator with the member_export_pi restriction can go to a member in the ACP and export the file directly. In both cases the b
    • 0 comments
    • 25 views
  25. Ernest Defoe ·
    The core/MFAArea extension adds one tick box to a single ACP form. That form is the ACP screen registered in applications/core/data/acpmenu.json as settings → mfa and labelled "Two Factor Authentication" — app=core&module=settings&controller=mfa — and the field is "Require two factor authentication when". Each MFAArea extension in the suite contributes one option to that list — "Logging into AdminCP", "Changing email address", "Managing stored cards", and so on. When an administrator tic
    • 0 comments
    • 23 views

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.