Developer notes
Overview · Installation · Configuration · Usage · FAQ
Structure
Section titled “Structure”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) / bannerdesign/backend/templates/addons/kv_google_merchant_feed_pro/license/status_bar.tpl status chip/banner for own admin pagesdesign/backend/templates/addons/kv_google_merchant_feed_pro/license/badge.tpl badge in Add-ons > Manage add-onsdesign/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.lessdesign/backend/css/addons/kv_google_merchant_feed_pro/license.less card, chip and badge stylesTables
Section titled “Tables”| 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) |
Generation pipeline
Section titled “Generation pipeline”Generator::generate()takes a non-blocking lock (feed_<id>.lock). A concurrent request getsbusyand serves the previous file.- A storefront-like context is set: a guest
auth(guest prices and catalog promotions),runtime.company_id= the storefront (Ultimate) or 0 (Multi-Vendor). ProductSource::nextIds()selects the next batch withproduct_id > last_id ORDER BY product_id LIMIT batch_size, with SQL-level filters. Keyset pagination keeps every batch equally fast.ProductSource::load()callsfn_get_products(['pid' => ids, 'area' => 'C', 'include_child_variations' => true, ...])andfn_gather_additional_products_data()(images, options, discounts). It then loads feature values, variation groups, overrides and sales for the batch with one query each.ItemBuilder::build()→Validator::validate()→XmlWriter|TsvWriter::writeItem()writes each item straight to a temporary file. Issues are bulk-inserted per batch.- 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.
URLs and commands
Section titled “URLs and commands”| 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=... |
Hooks used
Section titled “Hooks used”| 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) |
License check
Section titled “License check”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 ofhooks/index/styles.post.tpl). The status bar is the first line inside the mainbox capture ofviews/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 variablekv_google_merchant_feed_pro.license_off_effect.License\Clientassigns the view data to$kv_lic_kv_google_merchant_feed_proin itsbefore_dispatchhandler (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 callfn_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 statuspaused(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 abefore_dispatchhandler 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.checkwith JSON{"v":1, "license", "addon", "version", "hosts":[…], "platform":{"version", "edition"}, "nonce"}, sent throughTygh\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), orvar/kv_storage/kv_google_merchant_feed_pro/license.jsonwhile 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_hostandhttps_hostare development hosts): the constantsKV_LICENSE_SERVER_URL,KV_LICENSE_TEST_HOST(act as if the development storefronts ran on that host) andKV_LICENSE_TEST_TIME_OFFSET(seconds). They are ignored on production hosts.
Extending
Section titled “Extending”- Item data: the item array is plain PHP. To add an attribute, add it to
Attributes::getOutputOrder()(and togetMappable()for UI mapping). Both writers pick it up automatically. - Rules from code: insert into
?:kv_gmf_ruleswithconditions={"match":"all","items":[{"field":"price","operator":"gt","value":"100"}]}. - Programmatic generation:
(new \Tygh\Addons\KvGoogleMerchantFeedPro\Generator())->generate(\Tygh\Addons\KvGoogleMerchantFeedPro\Feeds::get($feed_id));
Roadmap
Section titled “Roadmap”| 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. |
Third-party code
Section titled “Third-party code”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.