Skip to content

Developer notes

Table Contents
cscart_kv_pop_options One row per option with a rule: code, input_type (N = number), num_min/num_max/num_step/num_default, unit, max_length, max_lines, required_visible, price_mode (none, formula, chars, words, lines, files), formula, rate, free_units, charge (U per item, O once per cart line), conditions (JSON list of {o, op, v}), cond_match (A all, O any).
cscart_kv_pop_variants Formula value of a variant (variant_id, option_id, value).
cscart_kv_pop_products Product formula: formula, mode (A add, R replace base price), min_price, setup_formula, status.
cscart_kv_pop_order_fees One-time fees of an order (parent and sub-orders): lines (JSON), total, tax, display total.

The breakdown of a cart item is stored in the item’s extra.kv_pop and therefore in cscart_order_details.extra (version, input hash, base, core modifiers, per-item amount, once amount, lines).

Formulas are tokenised and parsed by Tygh\Addons\KvProductOptionsPricing\Expression (recursive descent) into a small tree that is evaluated by a tree walker. There is no PHP evaluation and no callback: only numbers, variables, the operators + - * / % ^ < <= > >= == != and or not ?: and the functions min max round ceil floor abs sqrt pow clamp if round_to ceil_to floor_to exist. Limits: 500 characters, 200 tokens, nesting depth 24, 10 function arguments, values up to 10^12. Division by zero, roots of negative numbers and overflows raise an error; at runtime such an amount counts as 0.

  • apply_option_modifiers_pre: options hidden by their conditions are removed from the selection, so their core modifiers are not applied either.
  • apply_option_modifiers_post (type P): the per-item amount (product formula, option rules, minimum price) is added. It runs for every price fn_apply_options_modifiers() calculates (price, list price, quantity tiers, cart, order management), with the value of that call as base/price.
  • pre_add_to_cart: server-side validation; hidden option values and files are removed and number defaults written.
  • calculate_cart_items: the breakdown is stored in extra.kv_pop.
  • calculate_cart (priority 140): one-time fees are added to the cart total and taxed with fn_calculate_tax_rates() (cart taxes applies.KVPOP_<cart id>), like the core payment surcharge.
  • place_order: the fees of each order (parent and sub-orders) are stored.
  • Placed orders: while an item’s options, quantity and files are unchanged (input hash), the stored amounts are used (order details, editing a placed order).

PHP: apply_option_modifiers_pre, apply_option_modifiers_post, pre_add_to_cart, calculate_cart_items, calculate_cart, gather_additional_product_data_post, apply_options_rules_post, update_product_option_post, get_product_option_data_post, delete_product_option_post, clone_product_option_post, update_product_post, clone_product, delete_product_post, get_product_data_post, place_order, get_order_info, delete_order, template_document_order_context_init. All exist with the same arguments in 4.17.2 and 4.21.2.

Templates: storefront products:product_option_content (breakdown and option configuration), checkout:product_options, checkout:checkout_totals, checkout:summary, orders:product_info, orders:order_total; admin product_options:properties, product_options:edit_product_options, products:tabs_content, orders:product_info, orders:totals_content, order_management:totals; mail orders:totals.

The product page block cache (products.view main block and product lists) gets the add-on tables as update handlers and the license state as a cache key. The breakdown printed with the page contains no session data; option changes are POST requests, so the 4.21 full page cache is not involved.

  • GET /api/options/:id returns kv_pop (the option rule) and kv_pop_value for each variant. PUT /api/options/:id and POST /api/options accept kv_pop with the same fields (conditions as a list of {"o": option_id, "op": "in", "v": [variant ids]}) and variants[n][kv_pop_value].
  • GET /api/products/:id returns kv_pop (formula, mode, min_price, setup_formula, status); PUT /api/products/:id accepts it.
  • GET /api/orders/:id: items carry extra.kv_pop and kv_pop_rows; the order carries kv_pop_fees.
app/addons/kv_product_options_pricing/
addon.xml init.php func.php
controllers/backend/kv_product_options_pricing.php overview, test calculator, formula check
controllers/backend/products.post.php Price formula tab
controllers/backend/product_options.post.php option editor data
controllers/backend/kv_product_options_pricing_license.php
schemas/menu/menu.post.php schemas/permissions/admin.post.php schemas/permissions/vendor_multivendor.post.php
schemas/block_manager/blocks.post.php
Tygh/Addons/KvProductOptionsPricing/
Expression.php ExpressionException.php formula parser and evaluator
Rules.php rules storage and normalisation
Engine.php visibility, validation, price calculation
Hooks.php hook logic
Fees.php one-time fees (cart surcharge, order storage, documents)
Display.php storefront view data
Admin.php product tab, test calculator, overview
Config.php settings and license state
License/ license client Upgrade/ synchronizer
design/backend/templates/addons/kv_product_options_pricing/ option editor section, product tab, overview, order hooks, license
var/themes_repository/responsive/templates/addons/kv_product_options_pricing/ breakdown, cart, order and totals hooks
js/addons/kv_product_options_pricing/func.js storefront behaviour backend.js option editor and calculator
var/langs/en/addons/kv_product_options_pricing.po

License\Client::isActive() gates the storefront and cart features (Config::isActive()); placed orders and order editing work without a license. See License.