Skip to content

Developer notes

Overview · Installation · Configuration · Usage · FAQ

app/addons/kv_google_merchant_feed_pro/
addon.xml, init.php, func.php
controllers/backend/kv_google_merchant_feed_pro.php feeds, categories, rules, report, taxonomy search, console cron
controllers/backend/products.post.php "Google Merchant" product tab
controllers/backend/kv_google_merchant_feed_pro_license.php "Check now" / cron license check
controllers/frontend/kv_google_merchant_feed_pro.php feed URL (get) and web cron (cron)
resources/taxonomy-with-ids.en-US.txt Google product taxonomy (bundled)
schemas/menu/menu.post.php, menu_vendor.post.php
schemas/permissions/admin.post.php, vendor_multivendor.post.php
schemas/product_variations/product_types.post.php tab and data for child variations
schemas/settings/variants.functions.post.php cost feature selector
Tygh/Addons/KvGoogleMerchantFeedPro/
Feeds.php repository, defaults, file paths, URLs
Attributes.php attribute definitions, limits, enumerations, GTIN check
ProductSource.php keyset-paginated batches; categories, features, variation groups, overrides, sales
ItemBuilder.php product -> item (mapping, labels, availability, prices, shipping, rules)
Rules.php rule storage and evaluation
Validator.php normalization and issue detection
Promotions.php cart promotions -> Google promotions, promotion_id linking
Generator.php locking, streaming, atomic publish, statistics
XmlWriter.php, TsvWriter.php
Taxonomy.php taxonomy lookup and search
License/Client.php license check client (generated from the shared Kavio Labs template)
design/backend/templates/addons/kv_google_merchant_feed_pro/license/info.tpl License tab (points to the card)
design/backend/templates/addons/kv_google_merchant_feed_pro/license/card.tpl License card (add-on page) / banner
design/backend/templates/addons/kv_google_merchant_feed_pro/license/status_bar.tpl status chip/banner for own admin pages
design/backend/templates/addons/kv_google_merchant_feed_pro/license/badge.tpl badge in Add-ons > Manage add-ons
design/backend/templates/addons/kv_google_merchant_feed_pro/hooks/addons/ tabs_content.pre.tpl (card), manage.post.tpl (badge)
design/backend/templates/addons/kv_google_merchant_feed_pro/hooks/index/styles.post.tpl loads license.less
design/backend/css/addons/kv_google_merchant_feed_pro/license.less card, chip and badge styles
Table Content
?:kv_gmf_feeds Feeds: target, format, access key, generation mode, JSON settings, last statistics
?:kv_gmf_category_map category_id → Google category ID
?:kv_gmf_product_data Product-level overrides (JSON)
?:kv_gmf_rules Rules: feed (0 = all), JSON conditions, action, attribute, value, position
?:kv_gmf_issues Validation issues of the last generation (feed, product, attribute, code, severity)
  1. Generator::generate() takes a non-blocking lock (feed_<id>.lock). A concurrent request gets busy and serves the previous file.
  2. A storefront-like context is set: a guest auth (guest prices and catalog promotions), runtime.company_id = the storefront (Ultimate) or 0 (Multi-Vendor).
  3. ProductSource::nextIds() selects the next batch with product_id > last_id ORDER BY product_id LIMIT batch_size, with SQL-level filters. Keyset pagination keeps every batch equally fast.
  4. ProductSource::load() calls fn_get_products(['pid' => ids, 'area' => 'C', 'include_child_variations' => true, ...]) and fn_gather_additional_products_data() (images, options, discounts). It then loads feature values, variation groups, overrides and sales for the batch with one query each.
  5. ItemBuilder::build() → Validator::validate() → XmlWriter|TsvWriter::writeItem() writes each item straight to a temporary file. Issues are bulk-inserted per batch.
  6. The temporary file is renamed over the published file (atomic publish).

Memory stays flat: a test that streamed 12,350 items through the real pipeline in 50-product batches peaked at 25 MB, growing by about 1 MB (the duplicate-ID index).

Feed files live in var/files/kv_google_merchant_feed_pro/ with a name that contains a hash of the access key. The directory gets .htaccess and index.php guards, and the files are served only through the controller.

What How
Feed index.php?dispatch=kv_google_merchant_feed_pro.get&feed_id=N&key=KEY (supports If-None-Match / If-Modified-Since → 304)
Web cron index.php?dispatch=kv_google_merchant_feed_pro.cron&cron_key=KEY[&feed_id=N][&force=Y]
Console cron php admin.php --dispatch=kv_google_merchant_feed_pro.cron [--feed_id=N] [--force=Y]
Taxonomy search (admin, JSON) admin.php?dispatch=kv_google_merchant_feed_pro.taxonomy&q=...
Hook Purpose
update_product_post Save product_data[kv_gmf] overrides
delete_product_post Remove overrides and issues
delete_category_after Remove the category mapping
Template products:tabs_content (post) Product tab
Template product_variations:tabs_content (post) Product tab for child variations
Template index:scripts / index:styles (backend) Admin JS and LESS
before_dispatch (admin area and console only; static handler License\Client::onBeforeDispatch) Runs the due license check and shows license notices
addons:tabs_content (pre, admin template) License card at the top of the add-on page
addons:manage (post, admin template) License badge, moved into the add-on’s row (4.17–4.21 have no per-row hook)
index:styles (post, admin template) license.less (kv-license block)

Tygh\Addons\KvGoogleMerchantFeedPro\License\Client verifies the license against the Kavio Labs license server. The client, the “Check now”/cron controller controllers/backend/kv_google_merchant_feed_pro_license.php and the License tab template design/backend/templates/addons/kv_google_merchant_feed_pro/license/info.tpl are generated from the shared Kavio Labs template; don’t edit them by hand.

  • Admin license UI (generated, REVISION 3; don’t edit by hand): design/backend/templates/addons/kv_google_merchant_feed_pro/license/card.tpl (License card at the top of the add-on page, every tab; hooks/addons/tabs_content.pre.tpl), license/badge.tpl (badge in Add-ons > Manage add-ons; hooks/addons/manage.post.tpl), license/status_bar.tpl (chip/banner for the add-on’s own admin pages), design/backend/css/addons/kv_google_merchant_feed_pro/license.less (loaded by the kv-license block of hooks/index/styles.post.tpl). The status bar is the first line inside the mainbox capture of views/kv_google_merchant_feed_pro/{manage,update,categories,rules,report}.tpl. All of them render nothing for vendors and for administrators without the “Manage settings” privilege. The “what is switched off” sentence is the language variable kv_google_merchant_feed_pro.license_off_effect. License\Client assigns the view data to $kv_lic_kv_google_merchant_feed_pro in its before_dispatch handler (only for administrators with the Manage settings privilege); the templates only read this variable, so they render nothing (and no error) while an older version of the PHP code is loaded, for example in the request that uploads a new zip over the installed add-on. Templates never call add-on functions; PHP code can call fn_kv_google_merchant_feed_pro_license_ui($context).
  • fn_kv_google_merchant_feed_pro_is_licensed($feed = []) (func.php) is the gate. It reads the stored state only and never contacts the server. In the admin area/cron on Ultimate it checks the host of the feed’s storefront.
  • Frontend kv_google_merchant_feed_pro.get: 404 “Feed not available” before any on-the-fly generation.
  • Generator::runCron() (console cron and cron URL) skips the feed with the status paused (Generator::STATUS_PAUSED); the last published file is kept.
  • Not gated: the admin editor, rules, category mapping, product fields and product saves, Generate now and the validation report.
  • Client::boot() (init.php) registers a before_dispatch handler for the admin area and the console only. On admin page views and console requests it runs the check when it is due (key changed, or 24 hours after the last check; 1 hour after a failure) and shows the admin notice once per session.
  • Request: POST https://cs-cart.kaviolabs.com/index.php?dispatch=kv_licenses.check with JSON {"v":1, "license", "addon", "version", "hosts":[…], "platform":{"version", "edition"}, "nonce"}, sent through Tygh\Http (3 s connect, 5 s total; kept out of the CS-Cart request log). The answer is accepted only when its Ed25519 signature matches a public key embedded in the client and it echoes the nonce.
  • State: storage key kv_license_kv_google_merchant_feed_pro (?:storage_data), or var/kv_storage/kv_google_merchant_feed_pro/license.json while the full page cache is active, protected by an HMAC with the store’s crypt key.
  • Cron: php admin.php --dispatch=kv_google_merchant_feed_pro_license.check.
  • Development stores only (http_host and https_host are development hosts): the constants KV_LICENSE_SERVER_URL, KV_LICENSE_TEST_HOST (act as if the development storefronts ran on that host) and KV_LICENSE_TEST_TIME_OFFSET (seconds). They are ignored on production hosts.
  • Item data: the item array is plain PHP. To add an attribute, add it to Attributes::getOutputOrder() (and to getMappable() for UI mapping). Both writers pick it up automatically.
  • Rules from code: insert into ?:kv_gmf_rules with conditions = {"match":"all","items":[{"field":"price","operator":"gt","value":"100"}]}.
  • Programmatic generation: (new \Tygh\Addons\KvGoogleMerchantFeedPro\Generator())->generate(\Tygh\Addons\KvGoogleMerchantFeedPro\Feeds::get($feed_id));
Item Status
Local inventory feed (store_code, availability, quantity, price per store, for local inventory ads) Stub. Planned for 1.1 together with the CS-Cart Warehouses / Store locator integration. The feed type is reserved in the code (Feeds::getTypes() only exposes products and promotions).
Merchant API direct sync Not in 1.0. The Content API for Shopping reached its sunset on 2026-08-18 and is shut down in early 2027, so direct sync will target the Merchant API v1 (productInputs.insert, localInventories, promotions). Scheduled file fetches, which this add-on uses, are not affected by the sunset.
XML promotions feed 1.0 sends promotions as TSV, the documented file format.
Tax-inclusive prices from CS-Cart tax rules per country 1.0 offers a percentage adjustment.
Multiple shipping entries per feed (regions, weight tiers) Planned.
product_highlight, product_detail, certification, unit pricing attributes Planned.
Multiple Multi-Vendor storefronts 1.0 uses the default storefront URL for Multi-Vendor links.

Tygh/Addons/KvGoogleMerchantFeedPro/License/Ed25519.php (checks the signature of the license server’s answers on servers whose PHP has no sodium extension) is derived from paragonie/sodium_compat, ISC License, Copyright (c) 2016-2023 Paragon Initiative Enterprises and Copyright (c) 2013-2019 Frank Denis. The full license notice is in the file header.