Developer notes
Overview · Installation · Configuration · Usage · FAQ
How the checks work
Section titled “How the checks work”Auditor::check($product_ids) reads a batch of products with a few queries (product row, descriptions in the audited language, base price, category links, image pairs with sizes and alt texts, SEO names, variation groups, feature values) and returns the issues per product plus three fingerprints: an MD5 of the normalized name, the product code and an MD5 of the plain-text description (30 characters and more). Image files are checked through Storage::instance('images')->isExist(), so remote storage works too.
Store::saveResults() replaces the product’s row and issues. Duplicates are computed afterwards from the fingerprints, within the same company (Store::refreshDuplicates(), one INSERT ... SELECT ... GROUP BY per rule), for the whole catalog at the end of a scan or only for the fingerprints a re-checked product had before and after. Scores are recomputed in SQL from the open issues: 100 - 20 x critical - 8 x warning - 3 x notice, at least 0.
Scanner::start($company_id) creates a scan (0 = whole catalog). Scanner::step($scan_id, $seconds) takes an atomic lock on the scan row (lock_until), checks batches by product ID cursor until the time budget is used, and on the last batch removes rows of products that no longer exist or are no longer audited, rebuilds the duplicates and scores and writes the history points (scope A = all, C = per company, one per day). “Scan now” calls scan_step over AJAX until the scan is done; the cron calls the same code.
| Hook | Use |
|---|---|
update_product_post |
Re-check after a save (at the end of the request, 25 inline, the rest queued). Minimum score: a vendor product saved as Active is checked at once and set to Disabled below the minimum. |
tools_update_status_before_query |
Minimum score: keeps the old status when a vendor switches a low-score product to Active. |
tools_change_status |
Re-check after a status change in a list. |
update_product_amount |
Stock change: product queued for the cron (never checked during checkout). |
delete_product_post |
Results and ignored issues of a deleted product removed; its duplicates refreshed. |
delete_company |
Results and history of a deleted vendor or storefront removed. |
All hook signatures are identical in 4.17.2 and 4.21.2.
Data model
Section titled “Data model”| Table | Content |
|---|---|
?:kv_cqa_products |
One row per audited product: company, main category, status, score, issue counts, fingerprints, check time |
?:kv_cqa_issues |
One row per product and rule: severity, details (JSON), company, category, ignored |
?:kv_cqa_ignores |
Ignored issues (kept across checks) |
?:kv_cqa_scans |
Scans with cursor, counters, lock and status |
?:kv_cqa_history |
Daily score points for the whole catalog and per company |
?:kv_cqa_queue |
Products waiting for a re-check |
?:kv_cqa_meta |
The rule set (JSON) and the last digest time |
No ?:storage_data writes.
Permissions and scoping
Section titled “Permissions and scoping”The admin permission schema maps the controller to view_catalog (GET) and manage_catalog (POST; the Rules page needs manage_catalog). The vendor schema allows the controller only when Vendors see their catalog quality is on and never the Rules page, the test digest or the cron mode. Every query is limited by runtime.company_id; changes check the ownership of each product (Access::ownProducts()).
Full page cache
Section titled “Full page cache”The add-on has no storefront output. The cron URL is a non-cacheable JSON dispatch (Cache-Control: no-store).
License check
Section titled “License check”See License. The gate is Access::licensed(): Scan now, scan steps, the cron (scans, queue, digest), the inline re-check after saves (without a license products are only queued), bulk fixes and the minimum-score rule. The dashboard, the issue list, ignore/restore and the CSV export keep working.
Extending
Section titled “Extending”The rule definitions are in Config::definitions(); a new rule needs a check in Auditor::check(), a group and the language variables rule_<key>, rule_desc_<key> and optionally detail_<key>.
File map
Section titled “File map”| Path | Purpose |
|---|---|
app/addons/kv_catalog_quality_audit/addon.xml, init.php, func.php |
Scheme, settings, tables, digest e-mail template, hooks, settings info |
controllers/backend/kv_catalog_quality_audit.php |
Dashboard, issues, rules, export, scan endpoints (JSON), ignore, fixes, console cron |
controllers/frontend/kv_catalog_quality_audit.php |
Cron URL |
Tygh/Addons/KvCatalogQualityAudit/Auditor.php |
The checks |
.../Store.php |
Tables: results, duplicates, scores, history, queue, dashboard and list queries |
.../Scanner.php |
Scans, re-checks, queue, cron |
.../Fixer.php |
Bulk fixes and meta templates |
.../Digest.php |
Weekly e-mail |
.../Config.php, Access.php |
Rules, settings, scoping, license gate |
.../License/*, controllers/backend/kv_catalog_quality_audit_license.php |
License client and “Check now” |
.../Upgrade/Synchronizer.php |
Self-healing upgrades |
schemas/permissions/*, schemas/menu/* |
Privileges, vendor access, menu |
design/backend/templates/addons/kv_catalog_quality_audit/ |
Dashboard, issue list, rules, components, license UI |
js/addons/kv_catalog_quality_audit/admin.js, design/backend/css/addons/kv_catalog_quality_audit/ |
Admin script and styles |
var/langs/en/addons/kv_catalog_quality_audit.po |
Language variables |