Overview & Extension-Point Map
- Version
- 4.0 preview
- Updated
The orientation guide for the whole customization track. It explains what the customization layer is, the one rule that governs almost all of it (your file shadows the core file; yours wins), every extension point CBX exposes and where each resolves in code, and a decision guide that maps "I want to change X" to the right mechanism. Read this first; the other guides in this folder are deep dives into the individual mechanisms listed here.
All paths below are relative to the component root docroot/components/com_configbox/ unless stated
otherwise. Source references are point-in-time (component 3.4.1) — verify against the code.
1. What the customization layer is
data/customization/ is CBX's supported extension point. Files you place there:
- shadow their core counterparts — the framework looks in
data/customization/before the core location and uses the first file it finds, so your file pre-empts the shipped one; - survive component updates — updates overwrite core files (
controllers/,models/,views/,external/kenedo/,helpers/), but never touchdata/customization/; - are local code, not part of this repository — the directory is gitignored (it is the integrator's own code). These guides therefore describe the contracts you build against, not checked-in examples.
1.1 Where the layer lives, per platform
Every mechanism in this document is anchored to one method,
KenedoPlatform::p()->getDirCustomization() — and each platform adapter resolves it to a location
that its host's update mechanism cannot touch. The docs in this track write paths as
data/customization/<x> (the Joomla spelling); resolve <x> against your platform's directory:
| Platform | getDirCustomization() resolves to | Source |
|---|---|---|
| Joomla | components/com_configbox/data/customization/ | external/kenedo/platforms/joomla/general.php |
| WordPress | wp-content/plugins/configbox-customization/ — a sibling directory of the configbox plugin, deliberately outside it | external/kenedo/platforms/wordpress/general.php |
| Magento 2 | the Rovexo_ConfigboxCustomizations module's view/customizations/ directory — conventionally app/code/Rovexo/ConfigboxCustomizations/view/customizations/ | external/kenedo/platforms/magento2/general.php |
| Standalone | data/customization/ in the component | external/kenedo/platforms/standalone/general.php |
Platform particulars:
- WordPress: plugin updates replace the whole
configboxplugin folder, so the layer must live outside it.configbox-customizationis not a real WordPress plugin — no plugin header, no activation; ConfigBox reads the directory itself. (The in-pluginapp/data/customization/is the pre-3.3.0 legacy location, still exposed asgetOldDirCustomization()for the 3.3.0 movers.) - Magento 2: the layer sits inside a real (but skeletal) Magento module,
Rovexo_ConfigboxCustomizations, which declares<sequence>Rovexo_Configbox</sequence>so it loads after the base module; the module also carries any Magento-level overrides (routes/blocks/templates), while ConfigBox auto-discovers its own subtree atview/customizations/by the folder conventions in this track (view/customizations/is a ConfigBox convention, not a Magento area). If the module is not installed,getDirCustomization()falls back to a tmp path — i.e. the layer is effectively off. Assets are the one relocation: they live at the module'sview/base/web/(Magento's static-content path), not underview/customizations/assets/. - Joomla:
data/customization/sits inside the component dir but is preserved across updates (the installer does not clear it).
The golden rule: never edit core files. Anything you change in controllers/, models/, views/,
external/kenedo/ or helpers/ is lost on the next update. Put your change in data/customization/
instead, using the matching mechanism below.
2. The one resolution rule (and its variations)
Almost every mechanism is the same idea: build two candidate paths — a customization path and a core
path — and use one if it exists. The mechanisms differ only in which path is preferred. A
customization-first loader (e.g. PSP connectors, helpers/psp.php:33) checks data/customization/ first
so your file shadows core; a core-first loader (the class loaders) checks core first so your file only
loads as a new addition. The shape is otherwise identical:
$regularPath = KenedoPlatform::p()->getComponentDir($component) .'/controllers/'. $filename; // core
$customPath = KenedoPlatform::p()->getDirCustomization() .'/controllers/'. $filename; // customization
if ($path == '') {
if (is_file($regularPath)) { // class loaders are CORE-first:
$path = $regularPath; // core wins …
}
elseif (is_file($customPath)) { // … customization is the fallback (new files only)
$path = $customPath;
}
}
require_once($path);
The example above is the controller loader (
KenedoController::getController(),external/kenedo/classes/KenedoController.php:101-108). All three class loaders — controllers, models, and view classes — are core-first, so the customizationcontrollers//models//views/folders add new classes and do not shadow existing core ones. To shadow an existing core class, see thesystem_overrides/escape hatch (§3, last rows). Customization-first loaders (properties, rule conditions, PSP connectors, and the template chain) flip the twois_filechecks.
The mechanisms differ in two dimensions:
- Resolution mode — how the customization version takes effect:
- Customization-first shadow (properties, rule conditions, PSP connectors): the loader checks
data/customization/first, so your file is picked instead of the core file — you can shadow an existing core file or add a new one. - Core-first / new-only (controllers, models, view classes): the loader checks the core path
first and only falls back to
data/customization/when no core file of that name exists. This slot is for new controllers/models/views; it does not shadow an existing core one. See the ⚠ note after the table. - Template fallback chain (view templates): three candidates tried in order — Joomla template override → customization template → core template (first that exists is used).
- Merge / append (model property injection, language overrides): your data is combined with the core data, not substituted for it.
- Eager pre-emption at boot (system overrides, boot/settings hooks): your files are
require_once'd early so a class/function you define is in memory before the core would lazily load its version. This is how you change an existing core class — including a core controller, model, or view. - Registration (events/observers): your code is added to a dispatch list and runs alongside core observers.
- Customization-first shadow (properties, rule conditions, PSP connectors): the loader checks
- Naming contract — what the file must be called and (for class-based mechanisms) what class/function it must declare. These are the contracts that trip people up; each guide states its contract precisely.
Keep these two questions in mind for any mechanism: does mine replace or combine with the core's? and what exactly must I name the file/class/function so the loader finds it?
3. The extension-point map
Every supported extension point, the directory it lives in, how it resolves, and the dedicated guide.
| You want to … | Put it in data/customization/ … | Resolution | Contract (file / class / fn) | Guide |
|---|---|---|---|---|
| Change a screen's HTML | templates/<view>/<tmpl>.php | Fallback chain (KenedoView.php:482-486) | file named like the core template | com_configbox_overriding_views_and_templates.md |
| Add a new view's class logic | views/<view>/view.html.php (etc.) | New views only — see ⚠ note (KenedoView.php:202-207) | class ConfigboxView<Name> | com_configbox_overriding_views_and_templates.md |
| Add a new controller | controllers/<name>.php | New controllers only — see ⚠ note (KenedoController.php:101-108) | class ConfigboxController<Name> | com_configbox_overriding_controllers_and_models.md |
| Add a new model | models/<name>.php | New models only — see ⚠ note (KenedoModel.php:168-176) | class ConfigboxModel<Name> | com_configbox_overriding_controllers_and_models.md |
| Add a new field type (widget) | properties/<type>.php + properties/tmpl/<type>.php | First-match shadow (KenedoModel::getPropertyObject) | class KenedoProperty<Type> | com_configbox_custom_properties.md — but check ../technical/com_configbox_property_types.md first |
| Add a field to a stock model | model_property_customization/<model>.php | Merge (KenedoModel.php:802-836) | fn customPropertyDefinitions<Model>() | com_configbox_extending_stock_models.md; type from ../technical/com_configbox_property_types.md |
| Add a new question type | views/question_<type>/ (+ optional question_types/ConfigboxQuestion<Type>.php) | The view folder registers the type; the class is first-match (ConfigboxQuestion.php:79-91) | class ConfigboxQuestion<Type> | com_configbox_custom_question_types.md |
| Change what a selection means (its output value, comparable value, order-line SKU, validation) | question_types/ConfigboxQuestion<Type>.php | Sub-class, per question type | overridable methods on ConfigboxQuestion | com_configbox_custom_question_types.md §3 |
| Add a new rule condition | rule_condition_types/<name>.php | First-match (ConfigboxCondition.php:79-112) | condition-type class | com_configbox_custom_rule_conditions.md |
| React to a domain event | custom_observers/<File>.php (+ DB connector) | Registration, before/after core (KenedoObserver.php:29-62) | class Observer<File> | com_configbox_events_and_observers.md |
| Add/replace a payment method | psp_connectors/<name>/ | First-match shadow (helpers/psp.php:9) | connector file layout | com_configbox_payment_connectors.md |
| Change an existing core class' behavior (controller / model / view / framework / helper) | system_overrides/<Class>.php | Eager pre-emption at boot (helpers/overrides.php:24-39) | same class name as core | com_configbox_system_overrides_and_boot_hooks.md |
| Run code/SQL at boot or DB-connect | system_overrides/ (incl. getInitQueries.php) | Eager include (KenedoDatabase.php:83-90) | fn getPostDbConnectQueries() etc. | com_configbox_system_overrides_and_boot_hooks.md |
| Change displayed text | language_overrides/<tag>/overrides.ini | Merge (KText.php:195) | INI keys | com_configbox_language_overrides.md |
| Add CSS / JS modules | assets/css/…, assets/javascript/… | configbox/custom AMD namespace + customPaths (assets/main.js:43,100) | AMD define(...) | com_configbox_assets_and_amd.md |
| Add a site-specific CLI command | cli/commands.php | Lazy dispatch (ConfigboxCliHelper::loadCustomCliCommands()) | file returns name → callback defs | com_configbox_custom_cli_commands.md |
| Add a DB column/table a customization needs | updates/<version>.php | Customization migration track | versioned, idempotent script | technical/com_configbox_migrations.md |
⚠️ The class loaders are "core wins" — they add new classes, they don't shadow core. All three class loaders check the core path first and fall back to
data/customization/only when no core file of that name exists:
- Controllers —
KenedoController.php:101-108. The customizationcontrollers/slot is for new controllers only; it does not shadow an existing core controller.- Models —
KenedoModel.php:168-176. The customizationmodels/slot is for new models only; it does not shadow an existing core model.- Views (classes) —
KenedoView.php:202-207. For new views only; does not shadow an existing core view.So to change an existing core controller, model, or view you cannot drop a same-named file in the customization
controllers//models//views/folder. Instead: for a model, usemodel_property_customization/(data shape) or, for behavior, asystem_overrides/class override; for a view/screen, use a template override (markup) or change the model/controller behind it; for a controller, use asystem_overrides/class override. Templates (not view classes) do follow the "customization wins" fallback chain. Seecom_configbox_overriding_controllers_and_models.mdandcom_configbox_overriding_views_and_templates.md§3.1.
System overrides are an escape hatch, not the default. Prefer the targeted mechanism (override the specific controller/model/view/template). Reach for
system_overrides/only when the thing you must change is a framework or helper class with no per-type loader — and know that replacing the whole class means you inherit the maintenance of keeping it in sync with core updates.
4. Decision guide — pick the smallest mechanism
Work top-down; stop at the first row that fits. Smaller mechanisms are less code to maintain across updates.
- Only the wording/labels change? →
language_overrides/(no PHP at all). - Only the markup/layout of one screen? → a template override (
templates/<view>/…). No class. - A field needs adding to an existing admin form/list? → model property injection
(
model_property_customization/) + a migration for the column. No core edits. Pick itstypefrom the shipped catalogue:../technical/com_configbox_property_types.md§4. - A field type/widget that doesn't exist yet? → a custom property (
properties/). Check the catalogue first —../technical/com_configbox_property_types.md, one article per type under../technical/property-types/. One of the ~28 shipped types usually fits, and astringwithUSE_TEXTAREA, adropdownfed by amodelMethod, or ajsoncolumn covers most of what people write a new class for. - Behavior of one controller action or model method? → override the class via
system_overrides/, subclassing the core class and overriding only the method you need (the per-typecontrollers//models/folders can't shadow an existing core class — they're core-first). - Conditional-logic vocabulary (rules)? → a custom rule condition type.
- You need to react to something happening (order placed, record stored, user logs in)? →
an event observer (
custom_observers/). This is additive and the safest way to inject logic. - A payment integration? → a PSP connector.
- Custom front-end interactivity/styling? → assets (CSS + AMD JS under
assets/), wired via theconfigbox/customnamespace, or attached to a property (see the properties guide §8). - Work an operator or cron initiates (exports, imports, one-off fixes)? → a custom CLI command
(
cli/commands.php, surfaced aswp configbox custom <command>). Additive and isolated: a broken commands file cannot affect the stock CLI suite. - None of the above — you must change a framework/helper class itself? →
system_overrides/, accepting the sync cost. Consider asking the vendor for a hook instead.
A useful tie-breaker: prefer "combine/add" mechanisms (observers, property injection, language overrides) over "replace" mechanisms (class shadows, system overrides) — additive changes don't drift out of sync when the core file they would have replaced gets updated.
5. Layer layout (full)
data/customization/ ← getDirCustomization(); gitignored, upgrade-safe
controllers/<name>.php ← a NEW controller (ConfigboxController<Name>); does NOT shadow a core controller
models/<name>.php ← a NEW model (ConfigboxModel<Name>); does NOT shadow a core model
views/<view>/… ← a NEW view class; does NOT shadow a core view
templates/<view>/<tmpl>.php ← override a view template (markup only)
properties/<type>.php + tmpl/<type>.php ← custom Kenedo property type
model_property_customization/<model>.php← inject property defs into a stock model
rule_condition_types/<name>.php ← custom rule condition type
custom_observers/<File>.php ← event observers (registered via DB connectors)
psp_connectors/<name>/ ← payment connectors
system_overrides/<Class>.php ← eager class/function pre-emption at boot
system_overrides/getInitQueries.php ← SQL run right after each DB connect
language_overrides/<tag>/overrides.ini ← text overrides per language tag
assets/css/… assets/javascript/… ← custom CSS + AMD JS modules (configbox/custom)
cli/commands.php ← custom CLI commands (`wp configbox custom <command>`)
updates/<version>.php ← customization-track DB migrations
Two paths people confuse with the customization layer but which are separate:
data/store/private/settings/—getDirCustomizationSettings()(general.php:1015). Boot-time settings/override PHP files loaded byloadOverrideFiles()before thesystem_overrides/files (helpers/overrides.php:9-22). Covered in the boot-hooks guide.- Joomla template overrides —
getTemplateOverridePath(...)under the active site template, tried beforedata/customization/templates/in the template chain (KenedoView.php:482). This is the Joomla-native override slot; the customization slot is the platform-neutral one.
6. Cross-cutting rules (apply to every guide)
- Override the minimum. Subclass and override one method; copy one template and change a few lines. Never copy a whole core file to change one part of it — you inherit its future bug fixes as drift.
- Escape on output, sanitize on input. SQL is traditionally hand-built mysqli:
getQuoted()backtick-quotes identifiers,getEscaped()escapes values (add the surrounding quotes yourself) — or bind values withsetPreparedQuery($sql, $params)and skip manual escaping entirely. In templates usehsc(); validate/normalize request data before it touches a query. (See the project'sCLAUDE.md.) - Schema changes go through migrations. A property/model maps existing columns; it never creates them.
Deliver any new column/table via a customization migration (
updates/<version>.php), guarded withConfigboxUpdateHelper::tableFieldExists()/tableExists(). Seetechnical/com_configbox_migrations.md. - Match the surrounding idioms. No namespaces, no PSR-4, static singletons, PHP templates, AMD modules served without a build step. Follow Kenedo conventions, not modern Joomla/PSR ones.
- Verify manually. CBX has zero automated tests. Exercise the real admin form / frontend flow after every change, including XHR-injected views (many admin forms load via XHR, not full reloads).
- Customization wins — so don't shadow by accident. A file at
data/customization/properties/string.phpreplaces the built-instringtype install-wide. Use a fresh name unless replacement is the goal.
7. Prerequisites & reading order
Read technical/com_configbox_kenedo_mvc.md first if the Kenedo MVC model (controllers → models →
properties → views/templates) is unfamiliar; this overview assumes that vocabulary.
Suggested path through this folder:
- This overview (the map and the decision guide).
com_configbox_overriding_views_and_templates.md— the most common task (change a screen).com_configbox_extending_stock_models.md+com_configbox_custom_properties.md— add data/fields.com_configbox_overriding_controllers_and_models.md— change behavior.com_configbox_events_and_observers.md— react to events (the safest injection point).- The domain/integration guides —
com_configbox_custom_rule_conditions.md,com_configbox_payment_connectors.md. com_configbox_assets_and_amd.md,com_configbox_language_overrides.md— presentation polish.com_configbox_system_overrides_and_boot_hooks.md— last-resort framework overrides.
See also
customization/com_configbox_custom_properties.md— the first and most complete guide (the style/depth bar for this track).technical/com_configbox_kenedo_mvc.md— the framework these mechanisms hook into.technical/com_configbox_migrations.md— delivering the schema a customization needs.external/kenedo/classes/KenedoController.php,…/KenedoModel.php,…/KenedoView.php— the loaders that implement the resolution rule.helpers/overrides.php,external/kenedo/classes/KenedoObserver.php— the boot-override and observer mechanisms.