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.

Creating a Pages database and categories in code

The supported entry point is Databases::createDatabase(), which builds the records table, the default title and content fields, and a default category.

$db = new \IPS\cms\Databases;
$db->key            = 'kb';
$db->use_categories = 1;
$db->save();

// createDatabase() READS these while building the fields, so write them first
\IPS\Lang::saveCustom( 'cms', 'content_db_' . $db->id, 'Knowledge Base' );
\IPS\Lang::saveCustom( 'cms', 'content_db_lang_pu_' . $db->id, 'articles' );

\IPS\cms\Databases::createDatabase( $db );

Four traps

1. There are no database_template_* columns. Setting $db->template_listing throws Unknown column 'database_template_listing' in 'field list'. Templates moved out of the row entirely.

2. Categories<id> and Records<id> are generated on demand from a cached database list. In a fresh CLI process that cache is stale, so class_exists() returns false for a database that plainly exists. Clear the datastore and load the database first.

3. setPermissions() inserts your array verbatim. It does not fill in app, perm_type or perm_type_id. Omit them and every category collides on an empty key, surfacing as Duplicate entry '0' for key core_permission_index.perm_type, leaving categories with no permission row at all — invisible to everybody including an administrator.

$insert = array(
    'app'          => $catClass::$permApp,
    'perm_type'    => $catClass::$permType,
    'perm_type_id' => $id,
);

foreach ( $catClass::$permissionMap as $what => $column )
{
    $insert[ 'perm_' . $column ] = '*';
}

$catClass::load( $id )->setPermissions( $insert );

4. Categories::$permType is NULL on the base class. The generated per-database subclass sets it (categories_2 for database 2). Read it at runtime.

The page

A database is invisible until a page hosts it. The page body needs the database tag, the page needs a populated page_full_path and a permission row, and Page::buildPageUrlStore() must be rebuilt afterwards or it 404s despite every row being correct.

Note that a permission row existing is not the same as it being populated: save() writes an empty one, so checking only for presence will leave perm_view blank and the page will 403.

Naming the page

A page title is a language string keyed cms_page_<id>, not a column. Create a page in code and the key is never written, so breadcrumbs, the browser title and menus all display the raw key — cms_page_4.

\IPS\Lang::saveCustom( 'cms', 'cms_page_' . $pageId, 'Knowledge Base' );
\IPS\Lang::saveCustom( 'cms', 'cms_page_' . $pageId . '_desc', 'What it is for.' );

Setting page_name on the row is not a substitute — that is only the label shown in the AdminCP. Set both, or the two disagree.

Category paths, or every article redirects forever

Creating a category in code sets category_furl_name and leaves category_full_path NULL. Record URLs are assembled as <page>/<category_full_path>/<record>, so a NULL path produces a double slash:

https://example.com/kb//my-article-r7/

Invision Community then issues a 301 to what it considers canonical, computes the same double-slash URL, and the browser stops with ERR_TOO_MANY_REDIRECTS.

The category listing works perfectly throughout, so it presents as a problem with articles rather than with categories.

// top-level: the path is just the slug
// nested:    parent path . '/' . slug
Db::i()->update( 'cms_database_categories',
    array( 'category_full_path' => $path ),
    array( 'category_id=?', $id ) );

Build them parent-first so a child can prepend its parent, then clear the datastore.


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.