Important
There are a few differences between CS-Cart 4.18.1 Beta and the final release. See the differences below.
// Old:
function fn_filter_uploaded_data($name, array $filter_by_ext = [], $show_default_error_notifications = true, $sanitaze_filename = true)
// New:
function fn_filter_uploaded_data($name, array $filter_by_ext = [], $show_default_error_notifications = true, $sanitaze_filename = true, $filter_by_file_size_bytes = false)
// Old:
function fn_check_uploaded_data(array $uploaded_data, array $filter_by_ext)
// New:
function fn_check_uploaded_data(array $uploaded_data, array $filter_by_ext, $filter_by_file_size_bytes = false)
Gets language direction:
\Tygh\Template\IContext::getLanguageDirection()
Gets language direction:
\Tygh\Template\Snippet\Table\ItemContext::getLanguageDirection()
Gets language direction:
\Tygh\Template\Mail\Context::getLanguageDirection()
Gets language direction:
\Tygh\Template\Internal\Context::getLanguageDirection()
Gets language direction:
\Tygh\Template\Document\Order\Context::getLanguageDirection()
The dynamic actions $navigation.dynamic.actions display is updated. They are now shown in the right upper corner of the page. From now on, dynamic actions are the preferred interface elements for displaying actions and subpages. Dynamic actions appear as buttons. When there are multiple dynamic actions, some of them are displayed in a drop-down menu.
Dynamic actions requirements:
app/addons/my_changes/controllers/backend/products.post.php
<?php
use Tygh\ Registry;
defined('BOOTSTRAP') or die('Access denied');
if ($mode === 'manage') {
Registry::set('navigation.dynamic.actions', [
'my_changes.test_button' => [
'href' => 'categories.manage',
'text' => __('my_changes.view_my_changes'),
]
]);
}
Full list of available options is in the Dynamic actions in the header of the site section.
The dynamic sections $navigation.dynamic.sections have been deprecated. Use dynamic actions instead.
Gear buttons in the right upper corner of the page have been deprecated. Use dynamic actions instead. Please note that dynamic actions can appear both as standalone buttons and as items in the dropdown menu.
Search filters on the product list page (?dispatch=products.manage) are now set using an array. Use the products:search_data hook to extend it. For example, to add a text field, use hook:
design/backend/templates/addons/my_changes/hooks/products/search_data.post.tpl
{$search_filters.data.my_changes_filter = [
id => "my_changes_filter",
type => "input",
category => "secondary",
label => __("my_changes_filter"),
value => $search.my_changes_filter_value,
placeholder => __("my_changes_filter_placeholder")
]}
{* Export *}
{$search_filters = $search_filters scope=parent}
Hooks products:simple_search, companies:products_advanced_search, products:search_form, products:search_in_orders and products:advanced_search for extending the products list page have been deprecated. The products:select_search hook have been deprecated, use the products:sort_by_content hook instead.
The example of connecting search filters can be found in the Search filters on the product list page section.
To display saved searches, use the saved_search parameter. An example of saved searches for a product list page:
design/backend/templates/views/products/manage.tpl
{$search_form_dispatch = $dispatch|default:"products.manage"}
{$saved_search = [
dispatch => $search_form_dispatch,
view_type => "products"
]}
{include file="common/mainbox.tpl"
...
saved_search=$saved_search
}
Now extending Dashboard analytics blocks should be done through a schema.
app/addons/my_changes/schemas/dashboard/blocks.post.php
<?php
use Tygh\Enum\DashboardSections;
defined('BOOTSTRAP') or die('Access denied');
$schema[DashboardSections::TERTIARY]['my_changes'] = [
'id' => 'my_changes',
'title' => __('my_changes.dashboard.my_changes'),
'position' => 100,
'dispatch' => 'products.manage',
'content_data_function' => 'fn_my_changes_get_dashboard_block_data'
];
return $schema;
app/addons/my_changes/func.php
<?php
if (!defined('BOOTSTRAP')) { die('Access denied'); }
function fn_my_changes_get_dashboard_block_data()
{
$content_data = [
'id' => 'my_changes',
'title' => __('my_changes.dashboard.title'),
'title_button' => [
'href' => 'products.manage',
'name' => __('my_changes.dashboard.title_button'),
],
'number' => 1234,
];
return $content_data;
}
See the full list of available parameters in the Analytics card for Dashboard section.
You can expand the content of existing blocks using the get_dashboard_XXX hooks. Refer to the New Hooks section for a list of all hooks and their descriptions.
The Setup wizard has been deprecated. Use the Settings tab of your add-on instead. Learn more about scheme 3.0 structure.
Icons must now be connected through the component common/icon.tpl. Other methods are considered deprecated and will no longer work. The Font Awesome icon library has been replaced with CS-Cart’s custom icons. Now, instead of an icon font, vector SVG icons are used. Connection parameters for icons have changed. Connecting icons using the class parameter (e.g., class="icon-warning-sign") is deprecated. It is necessary to use the source parameter (e.g., source="warning_sign") with a value in snake_case and without the icon- prefix. See the example of connecting an icon in SVG icons section.
Top and central menu are now displayed on the left. Consequently, the available width for displaying page content has decreased. Please check the display of your pages on small screens.
The width restriction for page display has been removed. Now, the site is displayed across the entire available width of the window. Please check the appearance of interface elements on large screens.
Some Less style variables (colors, sizes, etc.) have been modified or removed. Now, CS-Cart’s Less-variables align with Bootstrap 2’s.
Instead of hardcoding values in styles, use Less variables and CSS custom properties from css/config.less for styles in your add-ons. For obtaining other values, utilize Less functions. For example, functions like spin(desaturate(lighten(@textColor, 30%), 25%), -15%) create the Text muted color. For more information about lessphp and Less, refer to their documentation. For details on removed Less variables, see Deleted style variables section.
fn_master_products_generate_navigation_sectionsExecutes after getting dashboard block data, allows editing it:
fn_set_hook('get_dashboard_block_data', $content_data, $this);
Executes after filling content information for block with sales statistics, allows editing it:
fn_set_hook('get_dashboard_sales_block_data', $content_data, $this);
Executes after filling content information for block with products statistics, allows editing it:
fn_set_hook('get_dashboard_products_block_data', $content_data, $this);
Executes after filling content information for block with orders statistics, allows editing it:
fn_set_hook('get_dashboard_orders_block_data', $content_data, $this);
Executes after filling content information for block with orders by statuses statistics, allows editing it:
fn_set_hook('get_dashboard_orders_by_statuses_block_data', $content_data, $this);
Executes after filling content information for block with vendor balance, allows editing it:
fn_set_hook('get_dashboard_vendor_balance_block_data', $content_data, $this);
Executes after filling content information for block with vendor activity statistics, allows editing it:
fn_set_hook('get_dashboard_vendor_with_sales_block_data', $content_data, $this);
Executes after filling content information for block with companies or vendors statistics, allows editing it:
fn_set_hook('get_dashboard_stores_block_data', $content_data, $this);
Executes after filling content information for block with users statistics, allows editing it:
fn_set_hook('get_dashboard_customers_block_data', $content_data, $this);
Executes after filling content information for block with last logs, allows editing it:
fn_set_hook('get_dashboard_logs_block_data', $content_data, $this);
Executes when changing order status before products are recalculated:
fn_set_hook('change_order_status_pre', $order_id, $status_to, $status_from, $force_notification, $place_order, $order_info, $allow_status_update);
Executes after updating data about the availability of products in warehouses:
fn_set_hook('warehouses_recalculate_destination_products_stocks', $this, $params, $product_condition);
Executes after deleting product stocks:
fn_set_hook('warehouses_remove_product_stocks_post', $this, $product_id);
Executes before updating/creating a banner:
fn_set_hook('banners_update_banner_pre', $data, $banner_id, $lang_code);
// Old:
fn_set_hook('create_order_details', $order_id, $cart, $order_details, $extra);
// New:
fn_set_hook('create_order_details', $order_id, $cart, $order_details, $extra, $k, $v);
// Old:
fn_set_hook('add_to_cart', $cart, $product_id, $_id);
// New:
fn_set_hook('add_to_cart', $cart, $product_id, $_id, $_data);
// Old:
fn_set_hook('filter_uploaded_data_post', $name, $filter_by_ext, $filtered, $udata_local, $udata_other, $utype);
// New:
fn_set_hook('filter_uploaded_data_post', $name, $filter_by_ext, $filtered, $udata_local, $udata_other, $utype, $filter_by_file_size_bytes);
// Old:
fn_set_hook('check_uploaded_data_pre', $uploaded_data, $filter_by_ext, $result, $processed);
// New:
fn_set_hook('check_uploaded_data_pre', $uploaded_data, $filter_by_ext, $result, $processed, $filter_by_file_size_bytes);
// Old:
fn_set_hook('check_uploaded_data_post', $uploaded_data, $filter_by_ext, $result, $processed);
// New:
fn_set_hook('check_uploaded_data_post', $uploaded_data, $filter_by_ext, $result, $processed, $filter_by_file_size_bytes);
Template: design/backend/templates/components/menu/actions_menu.tpl
Dynamic actions are displayed as buttons. If there are many buttons, some of them are displayed as a dropdown menu. The properties correspond to the {btn} helper from buttons/helpers.tpl, plus an additional parameter wrapper_class. The default type used is text. The usage of dynamic actions is described in The display of dynamic actions is updated section.
Example usage:
app/addons/my_changes/schemas/menu/actions.post.php
<?php
defined('BOOTSTRAP') or die('Access denied');
/** @var array $schema */
$schema['my_changes.manage']['my_changes.test_button'] = [
'href' => 'categories.manage',
'text' => __('my_changes.actions.view_my_changes'),
'text_mobile' => __('my_changes.actions.view_my_changes_mobile'),
'id' => 'my_changes_id',
'class' => 'my-changes-class',
'data' => [
'data-ca-my-changes-param-1' => 'my_value_1',
'data-ca-my-changes-param-2' => 'my_value_2',
],
'wrapper_class' => 'my-changes-wrapper-class',
'position' => 100
];
return $schema;
Available parameters:
typehreftext. If the parameter is unavailable, the language variable of the array key is used (up to 30 characters).text_mobile. If the parameter is unavailable, the text is used (up to 20 characters).titleidclassmetadispatchformmethodtargettarget_idprocessonclickicondatawrapper_classTemplate: views/products/components/search_filters/get_product_search_filters.tpl
Usage
design/backend/templates/addons/my_changes/hooks/products/search_data.post.tpl
{$search_filters.data.my_changes_filter = [
id => "my_changes_filter",
type => "input",
category => "secondary",
label => __("my_changes_filter"),
value => $search.my_changes_filter_value,
placeholder => __("my_changes_filter_placeholder"),
is_enabled => true,
is_hidden => false,
content => "HTML content",
data => [
name_from => "my_changes_filter_from",
value_from => $search.my_changes_filter_from,
label_from => __("my_changes_filter_from"),
name_to => "my_changes_filter_to",
value_to => $search.my_changes_filter_to,
label_to => __("my_changes_filter_to")
],
nested_data => [
my_changes_filter_param => [
key => "my_changes_filter_param",
label => __("my_changes_filter_param"),
value => true,
is_checked => ($search.my_changes_filter_param === "YesNo::YES"|enum)
]
]
]}
{* Export *}
{$search_filters = $search_filters scope=parent}
where:
| Parameter | Type | Description or values |
|---|---|---|
| id | String | Search filter ID. |
| type | Enum | Optional. Search filter type.
input (default)rangeradiocheckboxdropdownpopup |
| category | Enum | Optional. Display the search filter in the Add filter menu or display it always.
secondary (default)primary |
| priority | Number | Optional. It is necessary for context search only. Set the priority for contextual search. |
| label | String | Search filter label. |
| value | String | Optional. Search filter value. |
| placeholder | String | Optional. Search filter placeholder. |
| is_enabled | Boolean | A boolean value to determine whether the search filter should be render or not. |
| is_hidden | Boolean | Optional. A boolean value to determine whether the search filter should be display or not. In this case, the render will be executed. |
| content | String | Optional. HTML content for dropdown and popup types, or hidden props. |
| data | String | Optional. Required for the range type. Use name_from, value_from, label_from, name_to, value_to, or label_to props for name attribute, value, and label for “From” and “To” fields. |
| nested_data | String | Optional. Required for the checkbox and radio types. Use key, label, value, and is_checked props for ID, label, value and checked attribute. |
Examples of extensions
addons/tags/hooks/products/search_data.post.tpladdons/bestsellers/hooks/products/search_data.post.tpladdons/ebay/hooks/products/search_data.post.tpladdons/product_variations/hooks/products/search_data.post.tplExample of an array of product search filters: views/products/components/search_filters/get_product_search_filters.tpl.
The contextual search text field situated next to the saved search can be changed on the products list page.
Usage
addons/my_changes/hooks/products/search_data.post.tpl
For example:
{$search_filters.my_changes_query = [
id => "my_changes_query",
type => "input",
category => "primary",
label => __("search_my_changes"),
value => $search.my_changes_query,
priority => 1000
]}
{* Export *}
{$search_filters = $search_filters scope=parent}
For contextual search, a type equal to input is required. The field with the largest priority will be displayed in the context search. The rest of the search fields will be displayed in the search filter. The standard field Search products has 100 priority.
Template: views/index/components/analytics_section/analytics_card/analytics_card.tpl
Usage
The usage of the analytics card for the Dashboard is described in Extending Dashboard analytics blocks through template hooks has been deprecated section.
Example usage:
app/addons/my_changes/schemas/dashboard/blocks.post.php
<?php
use Tygh\Enum\DashboardSections;
defined('BOOTSTRAP') or die('Access denied');
$schema[DashboardSections::TERTIARY]['my_changes'] = [
'id' => 'my_changes',
'title' => __('my_changes.dashboard.my_changes'),
'position' => 100,
'dispatch' => 'products.manage',
'content_data_function' => 'fn_my_changes_get_dashboard_block_data'
];
return $schema;
app/addons/my_changes/func.php
<?php
if (!defined('BOOTSTRAP')) { die('Access denied'); }
function fn_my_changes_get_dashboard_block_data()
{
$content_data = [
'id' => 'my_changes',
'preheader' => __('my_changes.dashboard.preheader'),
'is_selected_date' => false,
'title' => __('my_changes.dashboard.title'),
'title_button' => [
'href' => 'products.manage',
'name' => __('my_changes.dashboard.title_button'),
],
'number' => 1234,
'number_dynamics' => 15,
'use_price_for_number' => false,
'content' => [
'<strong>Hello</strong>',
'<em>world!</em>',
],
'content_tpl' => [
'addons/my_changes/views/my_changes/components/my_changes_component.tpl'
],
'buttons' => [
'button_1' => [
'name' => __('my_changes.dashboard.button_1'),
'href' => 'products.manage',
'class' => 'my-changes-button-1',
],
],
'graph' => [
'content' => [
[
'date' => '2024, (0-0), 30',
'prev' => 150,
'cur' => 200
],
[
'date' => '2024, (0-0), 31',
'prev' => 160,
'cur' => 300,
],
]
],
'bar_chart' => [
'id' => 'bar_chart',
'title' => __('my_changes.dashboard.bar_chart'),
'content' => [
[
'id' => 'bar_1',
'name' => __('products'),
'href' => 'products.manage',
'type' => 'primary',
'value' => 10,
'is_price' => false,
'total' => 100,
'ratio' => 10,
],
[
'id' => 'bar_1',
'name' => __('categories'),
'href' => 'categories.manage',
'value' => 70,
'is_price' => false,
'total' => 100,
'ratio' => 70,
],
]
],
'resource_list' => [
'title' => __('my_changes.dashboard.resource_list'),
'content' => [
[
'id' => 'resource_list',
'href' => 'products.manage',
'name' => __("my_changes.dashboard.resource_list_name"),
'label_text' => __("my_changes.dashboard.resource_list_label_text"),
'label_class' => 'my-changes-resource-list',
'value_href' => 'products.manage',
'value' => '100',
'use_price_for_value' => false,
'description' => __("my_changes.dashboard.resource_list_description"),
'description_href' => 'products.manage',
'small_text' => __("my_changes.dashboard.resource_list_small_text"),
// 'image' => [],
]
]
],
'resource_list_tabs' => [
'id' => 'resource_list_tabs',
'content' => [
'resource_list_tabs_1' => [
'id' => 'resource_list_tabs_1',
'title' => __('resource_list_tabs_1'),
'content' => [
// Same thing as $content_data['resource_list']['content']
]
],
]
],
'scripts' => [
'js/addons/my_changes/func.js'
],
];
return $content_data;
}
design/backend/templates/addons/my_changes/views/my_changes/components/my_changes_component.tpl
<h3>My changes test</h3>
js/addons/my_changes/func.js
Template: common/icon.tpl
Usage
{include_ext file="common/icon.tpl"
source="warning_sign"
tone="warning"
color="#f00"
accessibility_label="No user"
show_icon=$is_show_user_require_warning_icon
class="user-require-warning"
id="user_warning_icon"
render="inline"
data=[
"data-ca-param-1" => "value_1",
"data-ca-param-2" => "value_2"
]
}
where:
| Parameter | Type | Description or values |
|---|---|---|
| source | String | The SVG contents (icon name (warning_sign), icon path (addons/my_changes/icons/my_icon.svg) or <svg>...</svg> source) to display in the icon (icons should fit in a 20 × 20 pixel viewBox). Use snake_case without the icon- prefix. The available icons can be viewed in the design/backend/template/icons/ directory. You can connect custom icons by specifying the icon path. |
| tone | Enum | Optional
basemutederrorinteractiveinfosuccessprimarytext_warningtext_errortext_infotext_success |
| accessibility_label | String | Optional. Descriptive text to be read to screenreaders. |
| color | String | Optional. The fill attribute of the <svg> tag for setting a custom icon color. |
| show_icon | Boolean | Optional. A boolean value that determines whether the icon should be displayed. |
| class | String | Optional. CSS class of an icon. |
| id | String | A unique icon ID. |
| data | Array | An array of HTML attributes of the icon. |
| render | Enum | Render the icon as an inline
<svg> tag or connect as an external <img src="..."> image.inline (default)img_data |
Deprecated parameters
| Parameter | Type | Description or values |
|---|---|---|
| title | String | Deprecated. Optional. A hint for the icon. Now it is recommended to set the hints at a higher level. For example, to set suggestions for buttons containing such icons. For accessibility, use accessibility_label. |
| icon_text | String | Deprecated. Optional. The text for the icon. Use accessibility_label for accessibility. |
Using custom icons
To display a custom icon, pass the path of the SVG icon to the source parameter. For example:
{include_ext file="common/icon.tpl" source="addons/my_changes/icons/my_icon.svg"}
where:
design/backend/templates/addons/my_changes/icons/my_icon.svg
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h20v20h-20z"/></svg>
SVG icons should fit in a 20x20 pixel viewBox.
Template: common/select_object.tpl
The value of the style parameter for accordion has been removed. Please use one of the following parameters: dropdown, graphic, or field.
Template: common/tabsbox.tpl
Now you have the option to display tabs navigation in the top navigation. To achieve this, add the parameter show_tabs_navigation=false when including the common/tabsbox.tpl template. Also, pass the parameter tabs_navigation=$tabs_navigation when including the common/mainbox.tpl template. Example of a tabs navigation in the top navigation: views/products/update.tpl.
index:headmenu:top_bar_rightbanners:statusindex:analytics_data: use dashboard/blocks schema instead.products:action_buttons: use dynamic actions instead.products:simple_search on the product list: use products:search_data instead.companies:products_advanced_search on the product list: use products:search_data instead.products:search_form on the product list: use products:search_data instead.products:search_in_orders on the product list: use products:search_data instead.products:advanced_search on the product list: use products:search_data instead.products:select_search on the product list: use products:sort_by_content instead.enable_sticky_scrollnavigation_accordionvendor_data_premoderation: vendor_data_premoderationvendor_plans: plan_usage and plan_data@wide-width: use var(--content-width) instead.@mainSidebarWidth: use var(--sidebar-width) instead.@mainSidebarThinWidth: use 50px instead.@headerOffset: use 89px instead.@textMutedColor: use spin(desaturate(lighten(@textColor, 30%), 25%), -15%) instead.@mainSidebarBackgroundColor: use #333940 instead.@topPanelBackground: use #f9f9f9 instead.@topPanelTextColorLight: use #daedf7 instead.@topPanelDropdownBackgroundColor: use #4c6b8a instead.@topPanelDropdownTextColor: use #272b31 instead.@brandFontColor: use #fff instead.@brandFontWeight: use 500 instead.@topPanelMenuBackgroundStart: use @mainColor instead.@topPanelMenuBackgroundEnd: use @mainColor instead.@topPanelMenuBackgroundHoverStart: use @mainColor instead.@topPanelMenuBackgroundHoverEnd: use @mainColor instead.@topPanelMenuBackgroundActiveStart: use @mainColor instead.@topPanelMenuBackgroundActiveEnd: use @mainColor instead.@topPanelMenuBackgroundDisabled: use @gray instead.@topPanelMenuCaret: use #fff instead.@topPanelMenuDividerLeft: use transparent instead.@topPanelMenuDividerRight: use transparent instead.@topPanelBoxShadow: use 0 1px 4px rgba(0,0,0,0.1) instead.@successColor: use @btnSuccessBackground instead.@mutedBackground: use #f7f7f9 instead.@mutedBorder use #e1e1e8 instead.@btnPrimaryText: use #daedf7 instead.@btnPrimaryBackgroundBorder: use @btnPrimaryBackground instead.@successButton: use @btnSuccessBackground instead.@textButtonColor: use @btnPrimaryBackground instead.@textButtonCaretColor: use #1010107b instead.@tabsBackgroundColor: use #f4f3f3 instead.@tabsActiveBackgroundColor: use @mainColor instead.@extraIconsSprite: use url(../media/images/exicons.png) instead.@extraIconsSpriteWhite: use url(../media/images/exicons_white.png) instead.@zIndexPopup: use 1500 instead.btn-text: use btn-link instead.Since the release of the Beta, we’ve made some changes to CS-Cart 4.18.1. The document above has already been updated accordingly. This section is for those who used an older version of the document; it covers what has changed.
This part of the Gear buttons have been deprecated section has been changed completely and is not relevant:
Gear buttons on the list of objects have been deprecated (for example, on the product list page). To perform the actions, use the Context menu. The appearance of gear buttons on the list of products and orders has changed (hooksproducts:list_extra_linksandorders:list_extra_links).
This part of the Search filter extension through product list page template deprecated has been changed and is not relevant:
Search filters on the product list are now set using an array. Use the
products:search_datahook to extend it.
Instead, a new search filter is now only on the products list page (?dispatch=products.manage). For example, it is not used when you add a product while creating an order.
my_changes_filter now needs to be placed in $search_filters.data instead of $search_filters. You should use the parameter category => "secondary".The following changes in the Dynamic actions in the header of the site section have been made:
text.schemas, not controllers.text parameter up to 30 characters in length.text_mobile parameter up to 20 characters in length.raw parameter is not available anymore.The following changes in the Search filters on the product list page section have been made:
get_product_search_filters.tpl is used instead of products_search_form.tpl.$search_filters, now use the sub-array $search_filters.data.The following changes in the Context search section have been made:
Now there is no need to include context_search.tpl in your template and pass the parameter to common/mainbox.tpl. It is enough to hook into addons/my_changes/hooks/products/search_data.post.tpl, create an array {$search_filters.my_changes_query = [ ... ]} and export $search_filters.
Questions & Feedback
Have any questions that weren't answered here? Need help with solving a problem in your online store? Want to report a bug in our software? Find out how to contact us.