Developer notes
app/addons/kv_vendor_holiday_mode/├── addon.xml scheme 3.0, priority 2100, MULTIVENDOR only├── init.php hook registration├── func.php API functions and hook handlers├── controllers/backend/kv_vendor_holiday_mode.php admin + vendor panel pages├── controllers/backend/kv_vendor_holiday_mode_license.php "Check now" / cron license check├── controllers/frontend/checkout.pre.php "block" mode: redirect checkout → cart├── controllers/frontend/checkout.post.php cart/checkout warnings├── controllers/frontend/call_requests.pre.php refuses "Buy now with one click" requests (Call requests add-on)├── schemas/menu/menu_multivendor.post.php Vendors → Vacation mode (admin, vendor panel without configurator)├── schemas/menu/menu_vendor.post.php Seller tools → Vacation mode (Vendor panel configurator)├── schemas/permissions/admin.post.php view_/manage_kv_vendor_holiday_mode privileges├── schemas/permissions/vendor_multivendor.post.php vendor access (only if "Allow vendors" is on)├── schemas/block_manager/blocks.post.php block cache invalidation (product/vendor blocks, main content block)├── schemas/block_manager/block_cache_properties.post.php license state in every block cache key└── Tygh/Addons/KvVendorHolidayMode/ ├── Enum/{ProductModes,CheckoutModes,HolidayStates}.php ├── License/Client.php license check client (generated from the shared Kavio Labs template) └── Upgrade/Synchronizer.php self-healing in-place upgradesdesign/backend/templates/addons/kv_vendor_holiday_mode/├── views/kv_vendor_holiday_mode/{manage,update}.tpl├── components/state_label.tpl├── license/info.tpl License tab└── hooks/companies/{list_extra_links,tools_list}.post.tplvar/themes_repository/responsive/templates/addons/kv_vendor_holiday_mode/├── components/{banner,unavailable}.tpl└── hooks/{companies/products.pre, companies/view.pre, products/main_info_title.post, products/product_additional_info.post, products/add_to_cart.override, buttons/add_to_cart.override, call_requests/call_request_button.override, index/styles.post}.tplvar/themes_repository/responsive/css/addons/kv_vendor_holiday_mode/styles.lessvar/langs/en/addons/kv_vendor_holiday_mode.poDatabase
Section titled “Database”The add-on uses its own tables instead of new columns in cscart_companies:
- core tables stay untouched, so CS-Cart upgrades, vendor import/export and the Vendor data premoderation profile diff are not affected;
- the multilingual message needs a separate descriptions table anyway;
- uninstalling drops two tables instead of running
ALTER TABLEon a large core table.
cscart_kv_vendor_holiday_mode (MyISAM, utf8)
| Column | Type | Notes |
|---|---|---|
company_id |
int unsigned, PK | Vendor |
enabled |
char(1) | Y/N: the vendor’s switch |
start_date |
int unsigned | Timestamp, 00:00:00 of the start day; 0 = immediately |
end_date |
int unsigned | Timestamp, 23:59:59 of the last day; 0 = until turned off |
is_active |
char(1) | Last known computed state. Kept in sync automatically (see below) |
locked |
char(1) | Y = only administrators may change it |
updated_at |
int unsigned | Timestamp of the last change |
updated_by |
int unsigned | User ID of the last change |
cscart_kv_vendor_holiday_mode_descriptions: company_id, lang_code, message (text), PK (company_id, lang_code).
The record is deleted when the vendor is deleted (delete_company hook).
State and caching
Section titled “State and caching”fn_kv_vendor_holiday_mode_get_state() derives the state (active, scheduled, ended, off) from enabled and the dates. fn_kv_vendor_holiday_mode_get_active_holidays() loads the records in effect once per request (static cache). It is called from before_dispatch on every storefront request. When the computed state differs from is_active, it runs an UPDATE on the add-on table. CS-Cart then marks the table as changed and drops block caches whose update_handlers include kv_vendor_holiday_mode. schemas/block_manager/blocks.post.php adds both add-on tables to every cache definition that already depends on products or companies: block types such as products and vendors, and the per-dispatch caches of the main content block (products.view, categories.view, companies.products). Saving a vacation in the vendor or admin panel writes to the same tables, so the storefront updates right away. Dates take effect without cron and without stale cached blocks.
License check
Section titled “License check”Tygh\Addons\KvVendorHolidayMode\License\Client verifies the license against the Kavio Labs license server.
fn_kv_vendor_holiday_mode_is_licensed()is the storefront gate. Every storefront entry point reads vacations throughfn_kv_vendor_holiday_mode_get_storefront_holidays(), which returns no vacations when the license does not cover the storefront:get_storefront_holiday()(all banners, notes and button overrides),get_blocked_product_holiday()(call requests),get_cart_holidays()(cart/checkout warnings, checkout redirect,pre_place_order),get_products(hide mode) andpre_add_to_cart. The storefront state sync inbefore_dispatchis skipped too. It reads the stored state only (one storage read per request) and never contacts the server.- Not gated: the vendor panel and admin pages (vacation settings, list, end, lock, delete), the e-mail to the administrator,
fn_kv_vendor_holiday_mode_get_active_holidays()andfn_kv_vendor_holiday_mode_is_on_holiday(). - The license state is part of every block cache key (
block_cache_properties.post.php,callable_handlerskv_vhm_license), so cached product and vendor blocks switch at once. Pages stored by the 4.21 full page cache keep their output until they expire (180 s). 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.- Admin license UI (generated): the License card at the top of the add-on page (
license/card.tplthrough theaddons:tabs_contentpre hook), the badge in Add-ons > Manage (license/badge.tpl,addons:managepost hook), the status bar (license/status_bar.tpl, first line inside the mainbox capture ofviews/kv_vendor_holiday_mode/{manage,update}.tpl; nothing for vendors) andcss/addons/kv_vendor_holiday_mode/license.less(index:stylespost hook). The off-effect sentence is the language variablekv_vendor_holiday_mode.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"}, 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_vendor_holiday_mode(?:storage_data), orvar/kv_storage/kv_vendor_holiday_mode/license.jsonwhile the full page cache is active, protected by an HMAC with the store’s crypt key. - Cron:
php admin.php --dispatch=kv_vendor_holiday_mode_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.
The license check endpoint (kv_vendor_holiday_mode_license.check) accepts only CSRF-protected POST requests of administrators, and console requests. Vendors cannot use it.
PHP hooks used
Section titled “PHP hooks used”| Hook | Handler | Purpose |
|---|---|---|
before_dispatch |
fn_kv_vendor_holiday_mode_before_dispatch |
Sync the stored state with the dates (storefront, while licensed) |
before_dispatch (admin area and console only) |
static License\Client::onBeforeDispatch |
Run the due license check and show license notices |
get_products |
fn_kv_vendor_holiday_mode_get_products |
Select products.company_id on the storefront; exclude vendors on vacation in hide mode |
pre_add_to_cart |
fn_kv_vendor_holiday_mode_pre_add_to_cart |
Remove products of vendors on vacation from add-to-cart requests (not from quantity updates) |
pre_place_order |
fn_kv_vendor_holiday_mode_pre_place_order |
Refuse orders in block mode (storefront only) |
delete_company |
fn_kv_vendor_holiday_mode_delete_company |
Cleanup |
The add-on priority is 2100, so pre_add_to_cart runs after Common products for vendors (1510) has replaced a common product with a vendor offer.
PHP hooks provided
Section titled “PHP hooks provided”/** * Before a vacation record is saved. Change $data or set $can_update = false to cancel. */fn_set_hook('kv_vendor_holiday_mode_update_holiday_pre', $company_id, $data, $auth, $current, $can_update);
/** * After a vacation record is saved. $row is the saved record, $current the record before the update. */fn_set_hook('kv_vendor_holiday_mode_update_holiday_post', $company_id, $row, $current, $auth);
/** * After storefront display data of a vendor on vacation is prepared (cached per request). * Change $holiday to alter the banner, e.g. set add_to_cart_disabled for some vendors only. */fn_set_hook('kv_vendor_holiday_mode_get_storefront_holiday_post', $company_id, $lang_code, $holiday);Example: let a specific vendor keep selling while others are blocked:
// init.php of your add-onfn_register_hooks('kv_vendor_holiday_mode_get_storefront_holiday_post');
function fn_my_addon_kv_vendor_holiday_mode_get_storefront_holiday_post($company_id, $lang_code, &$holiday){ if ($company_id == 5) { $holiday['product_mode'] = 'notice'; $holiday['add_to_cart_disabled'] = false; }}The server-side add-to-cart check follows the global setting; extend pre_add_to_cart in your add-on (priority above 2100) if you need per-vendor server rules.
Public functions
Section titled “Public functions”| Function | Returns |
|---|---|
fn_kv_vendor_holiday_mode_is_on_holiday($company_id) |
bool: vendor on vacation right now |
fn_kv_vendor_holiday_mode_get_active_holidays($reset = false) |
[company_id => row] of vacations in effect |
fn_kv_vendor_holiday_mode_get_holiday($company_id, $lang_code = DESCR_SL) |
Record (or default off record) with message and state |
fn_kv_vendor_holiday_mode_get_storefront_holiday($company_id, $lang_code = CART_LANGUAGE) |
Display data or []: company_name, start_date, end_date, show_return_date, message, product_mode, add_to_cart_disabled |
fn_kv_vendor_holiday_mode_update_holiday($company_id, array $data, array $auth, $lang_code = DESCR_SL) |
bool. $data: enabled (Y/N), start_date, end_date (store date format), message, locked (ignored for vendor users) |
fn_kv_vendor_holiday_mode_end_holidays(array $company_ids, $user_id = 0) |
Number of updated records |
fn_kv_vendor_holiday_mode_delete_holidays(array $company_ids) |
— |
fn_kv_vendor_holiday_mode_get_holidays(array $params, $items_per_page = 0, $lang_code = DESCR_SL) |
[$holidays, $params] for the admin list. Params: state, q, company_id, page, sort_by (company, start_date, end_date, updated_at), sort_order |
fn_kv_vendor_holiday_mode_get_cart_holidays(array $cart) |
Vendors on vacation in the cart with product names (empty without a valid license) |
fn_kv_vendor_holiday_mode_get_storefront_holidays() |
Like get_active_holidays(), but empty without a valid license: what the storefront applies |
fn_kv_vendor_holiday_mode_is_licensed() |
bool: the license covers this storefront (see License check) |
To skip the hide filter for one fn_get_products() call, pass kv_vendor_holiday_mode_skip => true in the params.
Template hooks used (storefront, responsive)
Section titled “Template hooks used (storefront, responsive)”| Hook | File | Output |
|---|---|---|
companies:products (pre) |
views/companies/products.tpl |
Banner on the vendor’s product list |
companies:view (pre) |
views/companies/view.tpl |
Banner on the vendor information page |
products:main_info_title (post) |
product templates (default, big picture) | Banner under the product title |
buttons:add_to_cart (override) |
buttons/add_to_cart.tpl |
“Vendor is on vacation until…” instead of the button. Outputs nothing otherwise, so the default button is kept |
products:product_additional_info (post) |
cart items | Per-item note (only on checkout.* pages) |
index:styles (post) |
common/styles.tpl |
styles.less |
In templates, use the modifier: {$kv_holiday = $product.company_id|fn_kv_vendor_holiday_mode_get_storefront_holiday} and {include file="addons/kv_vendor_holiday_mode/components/banner.tpl" kv_holiday=$kv_holiday kv_context="product"}.
All CSS is scoped under .kv-vendor-holiday-mode* classes (__banner, __title, __message, __note, __unavailable, __cart-note). Override them in your theme’s custom CSS.
Template hooks used (admin)
Section titled “Template hooks used (admin)”companies:list_extra_links (post) and companies:tools_list (post) add a Vacation mode link to the vendor list and the vendor profile.
Controller and permissions
Section titled “Controller and permissions”kv_vendor_holiday_mode.manage (admin list; vendors are redirected to their own page), .update (GET/POST), .end, .m_end, .delete, .m_delete (POST). Vendors and administrators switched to a vendor are always limited to runtime.company_id. The bulk and delete modes are refused for them. Vendor users cannot change locked, and cannot save or end a locked record.
Customization tips
Section titled “Customization tips”- Texts: change language variables
kv_vendor_holiday_mode.*in Administration → Languages → Translations. - Position of the product banner: copy
components/banner.tplusage into another hook from your own add-on and turn off Show a banner on the vendor’s product pages. - Email: Design → Email templates → Vendor vacation mode: vendor went on vacation.
Third-party code
Section titled “Third-party code”Tygh/Addons/KvVendorHolidayMode/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.