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.

Theme hook types are an enum of four, there is no "replace", and how to change the page title anyway

You want to change what a theme outputs at a specific point. The obvious approach is a custom template hook with type replace. Install the application and the log says:

Data truncated for column 'template_hookpoint_type' at row 1

The application installs, the hook does not, and nothing on the front end changes.

The four types

The column is an enum:

template_hookpoint_type  enum('before','inside-start','inside-end','after')

That is the whole list. The string 'replace' does appear in core's own PHP, which is what sends you down this path, but it is not a storable value for a custom template hook. Theme hooks in Invision Community 5 are insert-only. You can add before, at the start, at the end, or after — you cannot swap an element out.

Which matters most for the <title>

The title is emitted like this:

<title data-ips-hook="title">{expression="output.getTitle( $title )"}</title>

There is a hook point right there, and every option is wrong:

  • inside-start / inside-end — appends to the existing title: <title>Old New</title>.
  • before / after — emits a second <title>. Browsers and crawlers take the first one, so which wins depends on which side you picked, and having two is wrong regardless.

The seam that does work

Read Output::getTitle():

public function getTitle( ?string $title ): string
{
    if( $this->metaTagsTitle )
    {
        $title = $this->metaTagsTitle;    // <- used verbatim
    }
    else
    {
        $title = htmlspecialchars( $title, ENT_DISALLOWED, 'UTF-8', FALSE );
    }
    ...

metaTagsTitle wins outright. It is the same field the Meta Tags manager writes to, so using it is the sanctioned route rather than a workaround. Set it from an inside-start hook on <head>, which the template renders two lines before <title>:

{
    "hookpoint": "core/front/global/globalTemplate:head",
    "type": "inside-start",
    "content": "{expression=\"\\IPS\\yourapp\\Meta\\Tags::apply()\"}"
}

Your apply() returns an empty string and its only job is the assignment. Two things to get right:

  • Escape it yourself. getTitle() escapes only in the else branch — a metaTagsTitle is emitted raw.
  • Bail if it is already set. Somebody using the Meta Tags manager has said exactly what they want; do not overwrite it.

A content listener is too early

The tempting alternative is onItemView. It does not work, and the reason is ordering. In Content\Controller:

Event::fire( 'onItemView', $item );     // your listener runs here
...
$this->_setBreadcrumbAndTitle( $item, FALSE );   // title composed here

The title has not been built yet when your listener runs, so anything you write is overwritten a moment later — silently, because nothing errors and the page renders fine with the wrong title.

Why bother

Invision Community chains the page, its section and the site name: "Some long article title - Invision Community 5 - example.com". On a real article that is 120+ characters and Google shows about 60, so the words a searcher is looking for are the ones cut off — and the site name is already displayed beside the result, so it is being paid for twice. Dropping to {title} · {site} took a 120-character title to 97, and a forum topic from 72 to 57.


User Feedback

Recommended Comments

There are no comments to display.

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.