Humblee

A humble PHP framework & CMS

Personalization (p13n) & Internationalization (i18n)

Humblee includes a content personalization system that lets you serve different versions of any content block to different visitors. Internationalization — showing different content based on a URL language prefix — is built on top of that same system.


Personalization (p13n)

What it does

By default, every content block on a page has a single live version that every visitor sees. Personalization breaks that assumption. When p13n is enabled, any content block can have multiple versions — a default and any number of personalized variants. Humblee evaluates the current visitor against a set of rules you define and serves the matching variant automatically.

If no variant matches, the visitor sees the default content. No code changes are required in your view files — Draw::content() handles the version selection internally before output.

Enabling personalization

In your environment configuration file (humblee/configuration/env_*.php), set:

'use_p13n' => true,

With this set to false (the default), Humblee skips all personalization logic and always loads the default content version.

How p13n rules work

Each p13n variant in the CMS has a criteria definition stored as JSON. The rule structure uses two levels:

  • Outer level — OR: if any group of conditions passes, the variant matches.
  • Inner level — AND: all conditions within a group must pass for that group to count.

The currently supported condition types are:

Type Operators What it tests
required_role =, != Whether the current user has (or does not have) a given role
i18n =, != Whether the current URL's language prefix matches a given value
time_of_day <, > Whether the current server time is before or after a given time

Variants are prioritized. When multiple variants match the current visitor, the one with the highest priority wins. Only active variants are evaluated.

What gets personalized

Personalization works at the content block level, not the page level. A single page can have a mix of blocks — some with personalized variants, some without. The p13n_id field on a content row ties it to a specific variant; 0 means it is the default version.

When a page contains at least one personalized content block, Humblee automatically adds a Cache-Control: private header to the response, preventing shared (CDN or proxy) caches from serving a personalized page to the wrong visitor.


Internationalization (i18n)

What it does

i18n is a special case of personalization that triggers on a URL prefix rather than on user attributes. You define a list of language or locale identifiers (country codes, locale strings, or any string you choose) in the config. When a visitor hits a URL that starts with one of those identifiers, the router strips the prefix from the slug lookup and instead uses the i18n identifier to select the matching personalized content variant for that locale.

In other words: /fr/about and /about resolve to the same page in the CMS — but if a French-language content variant exists and the i18n criteria matches fr, the visitor sees the French version.

Enabling i18n

First, use_p13n must be true. Then set i18n_segments to an array of the URL prefixes you want to support:

'use_p13n'      => true,
'i18n_segments' => ['fr', 'es', 'de'],

With this configuration, all three of these URLs resolve to the same about page record:

/about        → default content
/fr/about     → French variant (if defined)
/es/about     → Spanish variant (if defined)
/de/about     → German variant (if defined)

If no variant is defined for the matched prefix, the visitor sees the default content.

Set i18n_segments to false (the default) to disable i18n URL handling entirely.

How the routing works

Core::getURIparts() is the method that parses the URI into segments for page lookup. When i18n_segments is configured, it checks whether the first URI segment appears in the allowed list. If it does, that segment is stripped from the array before the slug is matched against the database.

When the personalization engine evaluates criteria for the current request, the i18n condition type reads the first URI segment before stripping (via Core::getURIparts(true)) and compares it against the value in the rule. This is how the content system knows which locale variant to serve.

Defining an i18n variant in the CMS

In the admin interface, create a new personalization entry. Define its criteria with a condition of type i18n, operator =, and the locale string as the value — for example, fr. Then, when editing content on any page, select that personalization variant when saving the French version of each block. Mark it live the same way you would default content.


Summary

Feature Config key Default
Enable personalization use_p13n false
Enable i18n URL routing i18n_segments false

The two features are independent in configuration but share the same underlying mechanism. i18n requires use_p13n to be true because locale-based content variants are just p13n variants with an i18n criterion.