Skip to main content
Version: 3.x

The element → question rename — before → after reference

Version
3.x
Updated
View markdown

The exhaustive reference for the CBX 4 rename of the "element" entity to "question". Read this for any customization that touches the configurator question entity — its model, DB table, columns, the pricing/assignment caches, the rules/calc engine, or the calc-formula DSL. It carries the full before → after tables plus the per-file decision procedure and the shim inventory you can verify against the core.

This is the sibling of answers-collapse-deep-dive.md. That one is about the option/answer collapse; this one is about the element→question rename. A heavily-customized site is likely to have touched both.


Why this change​

The core entity was called element in the code, DB and admin MVC, but question everywhere in the UI and the frontend DOM/JS. That split was legacy debt: the same thing had two names depending on which layer you were in. CBX 4 finishes the transition — element → question everywhere: the DB table and every *element_id*/feature column, the admin model/controller/view classes, the pricing/assignment cache keys, the ionCube rules/calc engine, the rule/calc condition classes and their stored JSON, and the calc-formula DSL tokens.

The mental-model swap: wherever you thought "element" (the configurator question a customer answers), it is now "question". The entity's id is unchanged — a question keeps the same id its element had — so carts, orders, rules, calc formulas and translations all keep pointing at the right rows. Only the names changed.

Not touched (do not "fix" these — they are not ours):

  • Joomla core #__extensions.element and #__updates.element — a Joomla concept, unrelated.
  • WordPress WPML translation ids read as $translation->element_id in helpers/wordpress.php — a WordPress concept, unrelated.

The DB migration ships with the core​

The schema + stored-data half is applied automatically by the versioned update script helpers/updates/3.5.2.php (runs on init and via php cli/joomla.php configbox:migrate). It renames the table, all columns and the 8 foreign keys, and rewrites the stored rule/calc JSON and the calc-code DSL text. It does not touch data/customization/ — your custom SQL, custom columns and custom code are yours to realign using the tables below. If your customization added its own rules-bearing column, the migration's model-driven discovery converts its stored JSON automatically (see the "stored data" section).


Before → after — DB tables & columns​

The core migration renames these for you. Update any raw SQL in your customization that names them.

Table​

BeforeAfter
#__configbox_elements#__configbox_questions

The question-id foreign keys (every *element_id* column)​

TableBefore columnAfter columnFK
#__configbox_answerselement_idquestion_id(index only)
#__cbcheckout_order_configurationselement_idquestion_id(index only)
#__configbox_cart_position_configurationselement_idquestion_idFK, CASCADE/CASCADE
#__configbox_calculation_codeselement_id_a … element_id_dquestion_id_a … question_id_d4 FKs
#__configbox_calculation_matricescolumn_element_idcolumn_question_idFK
#__configbox_calculation_matricesrow_element_idrow_question_idFK
#__configbox_calculation_matricesmultielementidmultiquestionidFK

Feature columns (renamed on every table that carried them, incl. frozen order history)​

TableBeforeAfter
#__configbox_questionselement_custom_1 … element_custom_4question_custom_1 … question_custom_4
#__configbox_questionselement_css_classesquestion_css_classes
#__cbcheckout_order_configurationselement_custom_1 … element_custom_4question_custom_1 … question_custom_4
#__cbcheckout_order_configurationselement_typequestion_type
#__cbcheckout_order_configurationselement_codequestion_code
#__configbox_configlabel_element_custom_1 … _4label_question_custom_1 … _4
#__configbox_configlabel_element_custom_translatable_1 / _2label_question_custom_translatable_1 / _2
#__configbox_configpm_regular_show_elements, pm_recurring_show_elementspm_regular_show_questions, pm_recurring_show_questions
#__configbox_configpm_regular_show_elementprices, pm_recurring_show_elementpricespm_regular_show_questionprices, pm_recurring_show_questionprices
#__configbox_productspm_regular_show_elements / _elementprices (+ recurring)pm_regular_show_questions / _questionprices (+ recurring)

The frozen order-history columns are renamed too. cbcheckout_order_configurations is a denormalized snapshot of placed orders — but only the column names changed; every value is preserved, and the row's question_id still equals the id it had as element_id. Custom code that reads order configs must use the new column names.


Before → after — admin model / controller / views​

The model class was renamed (ConfigboxModelAdminelements → ConfigboxModelQuestions); file and view dirs moved with it.

KindBeforeAfterStatus
Model classConfigboxModelAdminelementsConfigboxModelQuestions🟢 getModel() aliases old→new
Model filemodels/adminelements.phpmodels/adminquestions.php—
Controllercontrollers/adminelements.php (ConfigboxControllerAdminelements)controllers/adminquestions.php (…Adminquestions)🔴 update controller=adminelements URLs
List viewviews/adminelements/ (ConfigboxViewAdminelements)views/adminquestions/ (…Adminquestions)🔴 update view=/getView() refs
Form viewviews/adminelement/ (ConfigboxViewAdminelement)views/adminquestion/ (…Adminquestion)🔴 update view=/getView() refs
Copy-remap bucket$copyIds['adminelements']$copyIds['adminquestions']🔴 rename in custom copy code
Answer→question join propelement_id (join to adminelements)question_id (join to adminquestions)🔴 update filter names
Derived join-prop namesjoinedby_element_id_to_adminelements_*joinedby_question_id_to_adminquestions_*🔴 rename if you read these props
model_property_customization/ fileadminelements.phpstill loads (see below)🟢 auto-loaded via legacy alias

Editor sub-views for the rule/calc "question attribute" term also moved:

BeforeAfter
views/adminruleeditor_elementattribute/views/adminruleeditor_questionproperty/
views/admincalcformula_elementattribute/views/admincalcformula_questionproperty/

(Both …_questionproperty sub-views were removed again in 3.8.26: the editors list a question's conditions and terms per question from the fields its type declares, see technical/com_configbox_rule_engine.md §2.3.)


Before → after — pricing API (public methods on ConfigboxPrices)​

BeforeAfterStatus
ConfigboxPrices::getElementPrice($id, …)getQuestionPrice($id, …)🟢 legacy alias kept
ConfigboxPrices::getElementPriceRecurring($id, …)getQuestionPriceRecurring($id, …)🟢 legacy alias kept
ConfigboxPrices::getElementWeight($id)getQuestionWeight($id)🟢 legacy alias kept

The old names still work (thin aliases, each marked @deprecated); rename your calls at leisure.


Before → after — the in-memory caches (assignment map + pricing cache)​

These are the string keys of the per-request caches (ConfigboxCacheHelper::getAssignments() and the pricing cache). They are rebuilt from the DB each request — no stored state, so this is a code-only change. The core keeps the old keys populated as aliases, so cleanly-written cache readers keep working.

CacheBefore keyAfter keyStatus
assignmentselement_to_productquestion_to_product🟢 old key kept as alias
assignmentsproduct_to_elementproduct_to_question🟢 old key kept as alias
assignmentselement_to_pagequestion_to_page🟢 old key kept as alias
assignmentspage_to_elementpage_to_question🟢 old key kept as alias
assignmentsanswer_to_elementanswer_to_question🟢 old key kept as alias
assignmentselement_to_answerquestion_to_answer🟢 old key kept as alias
pricingcalcModelByElementcalcModelByQuestion🟢 old key kept as alias
pricingcalcModelRecurringByElementcalcModelRecurringByQuestion🟢 old key kept as alias
pricingcalcModelWeightByElementcalcModelWeightByQuestion🟢 old key kept as alias
pricingtaxClassIdByElementtaxClassIdByQuestion🟢 old key kept as alias
pricingtaxClassIdByElementRecurringtaxClassIdByQuestionRecurring🟢 old key kept as alias
pricingcalcModel*ByAnswer[…]['regardingElement']['regardingQuestion']🟢 old sub-key kept as alias

The old keys are deprecated — update your cache readers to the question_* keys; the aliases will be removed in a future release.


Before → after — the rules / calc engine (ionCube) + stored JSON​

The rule condition and calc term for "a question's attribute/selection" were renamed. This is a hard rename with no runtime alias — instead the core migration rewrites the stored JSON so the new classes receive the migrated data.

KindBeforeAfterStatus
Rule condition classConfigboxConditionElementAttributeConfigboxConditionQuestionProperty🔴 rename a custom subclass/ref
Calc term classConfigboxCalcTermElementAttributeConfigboxCalcTermQuestionProperty🔴 rename a custom subclass/ref
Rule/calc JSON type value"ElementAttribute""QuestionProperty"🟢 migrated in stored data
Rule/calc JSON key"elementId""questionId"🟢 migrated in stored data
Method on those classesgetElementAttributes()getQuestionProperties()🔴 rename if you call it

The dispatcher builds the class name from the stored type string (ConfigboxCondition + ucfirst($type)), so a stored "type":"QuestionProperty" resolves to ConfigboxConditionQuestionProperty. That is why the class rename requires the stored-JSON migration — they must move together. The sentinel value "questionId":"regarding" (meaning "the question this formula is attached to") is preserved verbatim.

The calc-formula DSL tokens (user-authored calc code)​

Hard rename, no alias — the migration rewrites the stored calculation_codes.code text.

Before tokenAfter token
ElementAttribute(QuestionProperty(
ElementEntry(QuestionSelection(
ElementPrice(QuestionPrice(
ElementPriceRecurring(QuestionPriceRecurring(
RegardingElement(RegardingQuestion(

DSL field paths that named a feature column also change: QuestionProperty(22.element_custom_1) → QuestionProperty(22.question_custom_1) (the path resolves against the question's renamed property).

The field-path prefix crumbs changed too (part of the option→answer rename — see answers-collapse-deep-dive.md):

Before prefixAfter prefix
selectedOption.selectedAnswer.
regardingOption.regardingAnswer.

The engine's ConfigboxQuestion::getField() now resolves the crumbs selectedAnswer / regardingAnswer only — there is no alias for the old *Option. prefixes. The suffix after the dot (.id, .assignment_custom_N, .option_custom_N, .weight, .basePriceStatic, …) is unchanged. If your customization stores calc code outside the calculation_codes table (e.g. generated in custom code), rewrite these prefixes and the Element*( tokens the same way.


Stored data — what the core migrates, and what you may still owe​

The migration (3.5.2.php) transforms all stock stored rule/calc data, and — importantly — is model-driven for rules: it discovers every model that declares a rule (or calculationOverride) property, reads its effective property definitions (merging your model_property_customization/ overrides) and transforms whichever table+column that property is stored in. So if your customization added its own rule-typed property on a model, its stored JSON is converted for you. The raw calculation_formulas.calc column and the calculation_codes.code DSL are transformed explicitly.

What you may still owe — a DATA migration the core cannot do for you:

  • calc code / rule JSON your customization stores in a table or column the core does not know about (e.g. an external append table, a JSON blob in a custom settings row). The core migrates only columns it can discover via the model layer or the two explicit stock columns. Ship your own data/customization/updates/ migration applying the same transforms (JSON key elementId→questionId, type value ElementAttribute→QuestionProperty; the field-path prefixes selectedOption.→selectedAnswer. and regardingOption.→regardingAnswer.; DSL tokens per the table above). See ../technical/com_configbox_migrations.md in the CBX developer docs.

Per-file decision procedure (for a heavily-customized site)​

For each file under data/customization/:

  1. Is it loaded on this install? Custom models/controllers/views only matter if this deployment uses them. model_property_customization/adminelements.php is still loaded — see the shim below.
  2. Which bucket?
    • References only renamed-but-shimmed things (the ConfigboxModelAdminelements class name, the element_* cache keys, getElementPrice*, the adminelements customization filename) → 🟢 works today, but update at leisure; a deprecation is logged.
    • References renamed things with no shim — raw SQL on #__configbox_elements / the *element_id* columns / feature columns, controller=adminelements/view=adminelement(s) URLs, the ConfigboxConditionElementAttribute/ConfigboxCalcTermElementAttribute classes, the DSL tokens in calc code you generate → 🔴 must edit (see the tables above for each old → new).
  3. Does it also need a data migration? If it stores rule/calc JSON in a column the core migration doesn't reach (step above), write a data/customization/updates/ script. A code rename alone won't move that data.
  4. Prove it's clean with this grep (should return nothing but intentional legacy-alias lines):
    grep -rnE "configbox_elements|element_id|element_custom_|element_css_classes|ConfigboxModelAdminelements|ConfigboxConditionElementAttribute|ConfigboxCalcTermElementAttribute|joinedby_element_id_to_adminelements|column_element_id|row_element_id|multielementid|ElementAttribute\(|ElementPrice\(|ElementEntry\(|RegardingElement\(|element_to_|_to_element|ByElement|regardingElement|getElementPrice|getElementWeight" data/customization/
    Exclude only your own intentional back-compat lines. Do not flag helpers/wordpress.php-style $translation->element_id (WPML) — that is a WordPress concept, not this entity.

Worked conversions​

Raw SQL on the questions table:

// before
$db->setQuery("SELECT `id`, `element_custom_1` FROM `#__configbox_elements` WHERE `page_id` = ".$pid);
// after
$db->setQuery("SELECT `id`, `question_custom_1` FROM `#__configbox_questions` WHERE `page_id` = ".$pid);

Answers joined to their question:

// before
"LEFT JOIN `#__configbox_elements` AS e ON e.id = answer.element_id"
// after
"LEFT JOIN `#__configbox_questions` AS q ON q.id = answer.question_id"

Reading the assignment cache:

// before — still works via the alias, but deprecated
$questionIds = $assignments['product_to_element'][$productId];
// after
$questionIds = $assignments['product_to_question'][$productId];

A calc-code DSL formula:

// before
ElementAttribute(22.element_custom_1) * RegardingElement(regardingOption.basePriceStatic)
// after
QuestionProperty(22.question_custom_1) * RegardingQuestion(regardingAnswer.basePriceStatic)

An admin edit-link URL in a custom view:

// before
'index.php?option=com_configbox&controller=adminelements&task=edit&id='.$id
// after
'index.php?option=com_configbox&controller=adminquestions&task=edit&id='.$id

The core shims that do the auto-conversion (verify these)​

  • KenedoModel::getModel() — aliases ConfigboxModelAdminelements → ConfigboxModelQuestions (same pattern as the answers-collapse aliases). Logs a legacy call. So getModel('ConfigboxModelAdminelements') keeps returning the right model.
  • ConfigboxModelQuestions::getLegacyCustomizationAliases() returns array('adminelements') — so the merge in KenedoModel::getCustomPropertyDefinitions() still loads your existing model_property_customization/adminelements.php and applies it to the renamed model. No need to rename that file.
  • ConfigboxCacheHelper assignment build — re-exposes the old element_* assignment keys as aliases of the new question_* keys ($legacyAssignmentKeyAliases), and the old *ByElement/regardingElement pricing keys as aliases ($legacyPricingKeyAliases). Cleanly-written cache readers keep working.
  • ConfigboxPrices::getElementPrice() / getElementPriceRecurring() / getElementWeight() — thin @deprecated aliases that call the getQuestion* methods.

No shim (hard rename, stored data migrated instead): the rule/calc type strings and the calc DSL tokens. There is no runtime alias for "ElementAttribute" or ElementAttribute( — the migration rewrites the stored data so the new classes/parsers receive it. If you author rule/calc JSON or DSL code in customization at runtime, emit the new names.