Developer notes
Overview · Installation · Configuration · Usage · FAQ
Structure
Section titled “Structure”app/addons/kv_multichannel_feeds/ addon.xml, init.php, func.php controllers/backend/kv_multichannel_feeds.php feeds, preview, report (+CSV), categories, taxonomy search, generate step, console cron controllers/backend/kv_multichannel_feeds_license.php "Check now" / cron license check controllers/frontend/kv_multichannel_feeds.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 Tygh/Addons/KvMultichannelFeeds/ Channels.php channel templates: columns, requirement, max length, value type, enumerations, formats Fields.php canonical fields, mapping sources, enumerations, GTIN check Feeds.php repository, defaults, settings merge, tokens, file paths, URLs, schedule ProductSource.php keyset-paginated batches with SQL filters; categories, features, variation groups, sales ItemBuilder.php product -> canonical item (mapping, labels, availability, prices, shipping, UTM, rules) Formatter.php canonical item -> channel row + validation issues Writer.php CSV / TSV / XML (RSS 2.0 + g: or plain) / JSON streaming writer, resumable Generator.php resumable job steps, publish (gzip, atomic rename), preview, cron Validator.php text length and truncation helpers Taxonomy.php taxonomy lookup and search License/Client.php license check client (generated from the shared Kavio Labs template)design/backend/templates/addons/kv_multichannel_feeds/views/kv_multichannel_feeds/{manage,update,preview,report,categories}.tpldesign/backend/templates/addons/kv_multichannel_feeds/views/kv_multichannel_feeds/components/{nav,taxonomy_picker,generate_button}.tpldesign/backend/templates/addons/kv_multichannel_feeds/settings/{overview,cron}.tpldesign/backend/templates/addons/kv_multichannel_feeds/hooks/index/{scripts,styles}.post.tpldesign/backend/templates/addons/kv_multichannel_feeds/license/{info,card,status_bar,badge}.tpl, hooks/addons/{tabs_content.pre,manage.post}.tpldesign/backend/css/addons/kv_multichannel_feeds/{styles,license}.lessjs/addons/kv_multichannel_feeds/admin.jsTables
Section titled “Tables”| Table | Content |
|---|---|
?:kv_mcf_feeds |
Feeds: channel, company, format, gzip, country, language, currency, token, schedule, JSON settings, statistics of the last run |
?:kv_mcf_jobs |
Running generation per feed: run token, last product ID, totals, counters (resume state) |
?:kv_mcf_issues |
Validation issues per run token (feed, product, column, code, severity); only the last finished run is kept |
?:kv_mcf_category_map |
Store category → Google category ID |
Generation pipeline
Section titled “Generation pipeline”Generator::step($feed, $budget)takes a non-blocking lock per feed (feed_<id>.lock). A concurrent call getsbusy.- A new job writes the file header to
<file>.tmp, empties<file>.idsand stores the total count. A running job continues from its last product ID. - A storefront-like context is set: guest
auth,runtime.company_id= storefront (Ultimate) or 0 (Multi-Vendor). ProductSource::nextIds()selectsproduct_id > last ORDER BY product_id LIMIT batchwith SQL filters;load()callsfn_get_products()andfn_gather_additional_products_data()and loads features, variation groups and sales of the batch with one query each.ItemBuilder::build()makes the canonical item,Formatter::format()the channel row with its issues; duplicate IDs are found through<file>.ids(also across steps). Rows are appended, issues inserted per batch, the job row updated per batch.- When the time budget is used up the step returns
partial. The last step writes the footer, gzips when asked, renames the file over the published one and drops the issues of older runs.
Memory stays flat: 50,000 products peaked at 104 MB in a console run (54 MB of it is CS-Cart itself).
Channel specifications
Section titled “Channel specifications”The templates follow the published specifications (checked 2026-10-23):
| Channel | Specification |
|---|---|
| Meta | Catalog fields reference |
| TikTok | Catalog product parameters |
| Data source specification | |
| Microsoft | Products resource, Merchant Center feed files (tab-delimited text or Google XML) |
| Snapchat | Dynamic Product Ads guide |
| Criteo | Product feed parameters |
| idealo | CSV importer |
Value conventions: prices 12.00 USD (Meta, TikTok, Pinterest, Microsoft, Snapchat) or 12.00 (Criteo, idealo, custom); availability values per channel (backorder becomes available for order on TikTok and Snapchat and in stock elsewhere); CSV is RFC 4180 with every cell quoted and CRLF line ends; list values are comma-separated (idealo: ;); XML for the shopping channels is RSS 2.0 with xmlns:g="http://base.google.com/ns/1.0".
URLs and commands
Section titled “URLs and commands”| What | How |
|---|---|
| Feed | index.php?dispatch=kv_multichannel_feeds.get&feed_id=N&key=TOKEN (If-None-Match / If-Modified-Since → 304; wrong token or disabled feed → 404; not generated yet → 503) |
| Web cron | index.php?dispatch=kv_multichannel_feeds.cron&cron_key=KEY[&feed_id=N][&force=Y] |
| Console cron | php admin.php --dispatch=kv_multichannel_feeds.cron [--feed_id=N] [--force=Y] [--budget=SECONDS] |
| Generate step (admin, AJAX) | POST kv_multichannel_feeds.generate with kv_mcf_step=1 → {kv_mcf_step: {status, done, processed, total, ...}} |
Hooks used
Section titled “Hooks used”| Hook | Purpose |
|---|---|
delete_product_post |
Remove report rows of the deleted product |
delete_category_after |
Remove the category mapping |
Template index:scripts / index:styles (backend) |
Admin JS and LESS |
before_dispatch (admin area and console only; License\Client::onBeforeDispatch) |
Runs the due license check and shows license notices |
addons:tabs_content (pre), addons:manage (post) |
License card and badge |
Extending
Section titled “Extending”- Programmatic generation:
(new \Tygh\Addons\KvMultichannelFeeds\Generator())->generate(\Tygh\Addons\KvMultichannelFeeds\Feeds::get($feed_id)); - A new column: add it to the channel in
Channels::getAll()with a canonical field fromFields::getAll(); the writers and the Fields tab pick it up.
License check
Section titled “License check”Tygh\Addons\KvMultichannelFeeds\License\Client verifies the license against the Kavio Labs license server. The client, the “Check now”/cron controller controllers/backend/kv_multichannel_feeds_license.php and the license templates are generated from the shared Kavio Labs template; don’t edit them by hand.
fn_kv_multichannel_feeds_is_licensed($feed = [])(func.php) is the gate. It reads the stored state only and never contacts the server. In the admin area and cron on Ultimate it checks the host of the feed’s storefront.- Gated:
Generator::step()(Generate now, AJAX steps, console cron, web cron) returns the statuspausedand touches nothing. Not gated: the feed URL (serves the last file), the editor, preview, report and category mapping. - The status bar is the first line inside the mainbox capture of every own admin page. The “what is switched off” sentence is
kv_multichannel_feeds.license_off_effect. - Request:
POST https://cs-cart.kaviolabs.com/index.php?dispatch=kv_licenses.checkwith JSON{"v":1, "license", "addon", "version", "hosts":[…], "platform":{"version", "edition"}, "nonce"}; the answer is accepted only with a valid Ed25519 signature and the echoed nonce. - State: storage key
kv_license_kv_multichannel_feeds(?:storage_data), orvar/kv_storage/kv_multichannel_feeds/license.jsonwhile the full page cache is active, protected by an HMAC. - Cron:
php admin.php --dispatch=kv_multichannel_feeds_license.check.
Third-party code
Section titled “Third-party code”Tygh/Addons/KvMultichannelFeeds/License/Ed25519.php is derived from paragonie/sodium_compat, ISC License, Copyright (c) 2016-2023 Paragon Initiative Enterprises and Copyright (c) 2013-2019 Frank Denis. resources/taxonomy-with-ids.en-US.txt is the Google product taxonomy as published by Google for merchant feeds.