diff --git a/.gitignore b/.gitignore
index e74f02643..9bf0f9414 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,11 @@
/.gitignore
/.idea
+/.opencode/
+/.cursorrules
+/.github/copilot-instructions.md
+*.md
+*.MD
+!/AGENTS.md
/system/config/config.php
/system/config/theme_default.yml
/upload/u1/
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 000000000..e18451e78
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,1105 @@
+# AGENTS.md - InstantCMS 2 Development Guide
+
+## Project Overview
+
+**InstantCMS 2** is a PHP 7.2+ open-source CMS written in Russian. It features:
+- Modular architecture with controllers (addons)
+- Content types system with fields
+- Event/hook system for extensibility
+- Custom template engine
+- Widget system for page composition
+- User management and permissions
+- Multilingual support
+
+**Repository**: `/Users/maxisoft/Sites/icms2`
+**PHP Version**: 7.2+
+
+---
+
+## Directory Structure
+
+```
+icms2/
+├── system/
+│ ├── core/ # Core CMS classes
+│ │ ├── autoloader.php # Custom autoloader
+│ │ ├── core.php # Main singleton (cmsCore)
+│ │ ├── controller.php # Base controller class
+│ │ ├── backend.php # Backend controller base
+│ │ ├── frontend.php # Frontend controller base
+│ │ ├── database.php # Database wrapper (cmsDatabase)
+│ │ ├── model.php # Base model class (cmsModel)
+│ │ ├── config.php # Configuration singleton
+│ │ ├── request.php # HTTP request wrapper
+│ │ ├── response.php # HTTP response
+│ │ ├── user.php # User object
+│ │ ├── template.php # Template engine
+│ │ ├── form.php # Form base class
+│ │ ├── formfield.php # Base field class
+│ │ ├── grid.php # Data grid builder
+│ │ ├── eventsmanager.php # Event/hook system
+│ │ ├── permissions.php # Permission system
+│ │ ├── uploader.php # File upload handling
+│ │ ├── images.php # Image processing
+│ │ ├── mailer.php # Email sending
+│ │ ├── cache.php # Caching abstraction
+│ │ ├── cachefiles.php # File-based cache
+│ │ ├── paginator.php # Pagination
+│ │ └── ...
+│ ├── controllers/ # Addons/controllers (38 controllers)
+│ │ ├── content/ # Content types system
+│ │ ├── users/ # User profiles
+│ │ ├── auth/ # Authentication
+│ │ ├── admin/ # Admin panel
+│ │ ├── comments/ # Comments system
+│ │ ├── messages/ # Private messages
+│ │ ├── photos/ # Photo galleries
+│ │ ├── groups/ # User groups
+│ │ ├── tags/ # Tags system
+│ │ ├── rating/ # Rating system
+│ │ ├── search/ # Search functionality
+│ │ ├── sitemap/ # Sitemap generation
+│ │ └── ...
+│ ├── fields/ # Field types (32 field types)
+│ │ ├── string.php # Text input field
+│ │ ├── text.php # Textarea field
+│ │ ├── html.php # HTML editor field
+│ │ ├── image.php # Single image field
+│ │ ├── images.php # Multiple images field
+│ │ ├── file.php # File upload field
+│ │ ├── list.php # Dropdown list field
+│ │ ├── checkbox.php # Checkbox field
+│ │ ├── date.php # Date picker field
+│ │ ├── number.php # Number input field
+│ │ ├── url.php # URL field
+│ │ ├── user.php # User selector field
+│ │ ├── category.php # Category selector field
+│ │ └── ...
+│ ├── traits/ # Reusable traits
+│ │ ├── controllers/
+│ │ │ ├── actions/
+│ │ │ │ ├── listgrid.php # List/grid actions trait
+│ │ │ │ ├── formItem.php # Item form actions
+│ │ │ │ └── formFieldItem.php
+│ │ │ └── models/
+│ │ │ ├── fieldable.php # Content fields trait
+│ │ │ └── transactable.php
+│ │ ├── services/
+│ │ │ └── fieldsParseable.php
+│ │ ├── corePropertyLoadable.php
+│ │ └── eventDispatcher.php
+│ ├── libs/ # Third-party libraries
+│ │ ├── phpmailer/ # Email library
+│ │ ├── scssphp/ # SCSS compiler
+│ │ ├── jevix.class.php # HTML/XHTML filter
+│ │ ├── spyc.class.php # YAML parser
+│ │ ├── mobile_detect.class.php
+│ │ ├── google_authenticator.class.php
+│ │ ├── strings.helper.php
+│ │ ├── html.helper.php
+│ │ ├── files.helper.php
+│ │ └── template.helper.php
+│ ├── languages/ # Language files
+│ │ ├── ru/ # Russian
+│ │ │ ├── language.php # Core language strings
+│ │ │ ├── functions.php
+│ │ │ ├── controllers/
+│ │ │ ├── fields/
+│ │ │ ├── letters/ # Email templates
+│ │ │ └── widgets/
+│ │ └── en/ # English
+│ └── config/ # Configuration files
+│ ├── autoload.php # Autoloader config
+│ ├── config.php # Main config
+│ └── timezones.php
+├── templates/ # Site templates
+│ ├── default/
+│ ├── modern/
+│ └── admincoreui/
+├── install/ # Installation files
+│ ├── index.php
+│ ├── manifest.php
+│ ├── manifests/ # Addon manifests
+│ ├── steps/ # Installation steps
+│ └── languages/
+├── upload/ # User-uploaded files
+├── cache/ # Cache files
+├── bootstrap.php # Environment initialization
+├── index.php # HTTP entry point
+└── cron.php # CLI entry point
+```
+
+---
+
+## Entry Points
+
+### HTTP Request Flow
+```
+index.php → bootstrap.php → cmsCore::runHttp() → cmsController::runController()
+```
+
+1. **index.php** - Main entry point, defines `VALID_RUN` and `SESSION_START` constants
+2. **bootstrap.php** - Initializes environment:
+ - Defines `PATH` constant
+ - Loads Composer autoloader (if exists)
+ - Loads CMS autoloader
+ - Initializes config (`cmsConfig::getInstance()`)
+ - Connects to database
+ - Starts cache
+ - Fires `core_start` event
+3. **cmsCore::runHttp()** - Handles HTTP request:
+ - Detects browser language
+ - Routes URI to controller/action
+ - Initializes template
+ - Loads matched widget pages
+ - Checks access permissions
+ - Runs controller action
+
+### Cron Request Flow
+```
+cron.php → bootstrap.php → cmsCore::runCli() → cmsController::runController()
+```
+
+---
+
+## Autoloading System
+
+The CMS uses a **custom autoloader** (`system/core/autoloader.php`). Class naming conventions map to file paths:
+
+| Class Prefix | File Path | Example |
+|--------------|-----------|---------|
+| `cms` | `system/core/{name}.php` | `cmsDatabase` → `system/core/database.php` |
+| `field` | `system/fields/{name}.php` | `fieldString` → `system/fields/string.php` |
+| `model` | `system/controllers/{ctrl}/model.php` | `modelContent` → `system/controllers/content/model.php` |
+| `modelBackend` | `system/controllers/{ctrl}/backend/model.php` | `modelBackendContent` → `system/controllers/content/backend/model.php` |
+| `icms\` | `system/{path}.php` | `icms\traits\corePropertyLoadable` → `system/traits/corePropertyLoadable.php` |
+
+Register additional namespaces:
+```php
+cmsAutoloader::register('Namespace\Subnamespace', 'path/to/classes');
+cmsAutoloader::registerList([['Namespace', 'path/to/classes']]);
+```
+
+---
+
+## Core Classes Reference
+
+### cmsCore
+Main singleton. Access via `cmsCore::getInstance()`.
+
+**Key Properties:**
+- `$uri` - Current URI without root
+- `$uri_controller` - Detected controller name
+- `$uri_action` - Detected action name
+- `$uri_params` - Action parameters from URI
+- `$controller` - Current controller instance
+- `$request` - `cmsRequest` object
+- `$response` - `cmsResponse` object
+- `$db` - `cmsDatabase` object
+
+**Key Methods:**
+- `getInstance()` - Get singleton instance
+- `route($request_uri)` - Parse URI and determine controller/action
+- `runHttp($request_uri)` - Handle HTTP request
+- `runController()` - Execute current controller action
+- `connectDB()` - Connect to database
+- `loadLib($name)` - Load helper library
+- `loadLanguage($name)` - Load language file
+- `error404()` - Show 404 error page
+- `error($message)` - Show error page
+
+### cmsController
+Base controller class. All controllers extend this.
+
+**Key Properties:**
+- `$name` - Controller name (auto-detected)
+- `$model` - Associated model instance
+- `$request` - Current request object
+- `$options` - Controller options
+- `$root_url` - Controller root URL
+- `$root_path` - Controller filesystem path
+
+**Key Methods:**
+- `runAction($action_name, $params)` - Execute an action
+- `renderTemplate($template_path, $data)` - Render template
+- `halt($text)` - Stop execution with output
+- `redirect($url)` - Redirect to URL
+- `error404()` - Show 404 error
+
+**Subclasses:**
+- `cmsFrontend` - Frontend controllers (public pages)
+- `cmsBackend` - Backend controllers (admin panel)
+
+### cmsModel
+Base model class for database operations.
+
+**Key Constants:**
+- `LEFT_JOIN`, `RIGHT_JOIN`, `INNER_JOIN` - Join types
+- `READ_UNCOMMITTED`, `READ_COMMITTED`, etc. - Transaction isolation
+- `DEFAULT_TABLE_PREFIX = 'con_'` - Content tables prefix
+- `DEFAULT_TABLE_CATEGORY_POSTFIX = '_cats'` - Category table suffix
+
+**Key Properties:**
+- `$db` - Database instance
+- `$table` - Current table name
+- `$select` - SELECT fields
+- `$where` - WHERE conditions
+- `$join` - JOIN clauses
+- `$order_by` - ORDER BY clause
+- `$limit` - Query limit
+
+**Key Methods:**
+- `select($fields)` - Add SELECT fields
+- `where($field, $value)` - Add WHERE condition
+- `join($table, $condition, $type)` - Add JOIN
+- `orderBy($field, $direction)` - Add ORDER BY
+- `limit($limit, $offset)` - Set LIMIT
+- `get()` - Execute query and return results
+- `getItem()` - Get single item
+- `insert($table, $data)` - Insert record
+- `update($table, $data, $id)` - Update record
+- `delete($table, $id)` - Delete record
+
+### cmsDatabase
+Database connection wrapper (mysqli).
+
+**Key Properties:**
+- `$prefix` - Table prefix
+- `$query_count` - Query counter
+- `$query_quiet` - Suppress errors if true
+
+**Key Methods:**
+- `getInstance()` - Get singleton
+- `query($sql)` - Execute SQL query
+- `escape($string)` - Escape string for SQL
+- `affectedRows()` - Get affected rows count
+- `insertId()` - Get last inserted ID
+- `fetchAssoc($result)` - Fetch row as associative array
+- `fetchRow($result)` - Fetch row as numeric array
+
+### cmsForm
+Base class for forms.
+
+**Structure:**
+```php
+class formContentCategory extends cmsForm {
+ public function init($ctype, $action) {
+ $fieldsets = [
+ 'base' => [
+ 'title' => LANG_BASIC_OPTIONS,
+ 'type' => 'fieldset',
+ 'childs' => [
+ new fieldString('title', [
+ 'title' => LANG_CATEGORY_TITLE,
+ 'rules' => [['required']]
+ ]),
+ // ... more fields
+ ]
+ ]
+ ];
+ return $fieldsets;
+ }
+}
+```
+
+### cmsFormField
+Base class for all field types.
+
+**Key Properties:**
+- `$name` - Field name
+- `$title` - Field title for display
+- `$sql` - SQL definition for database
+- `$filter_type` - Filter type (false, 'like', 'eq', 'int', 'date')
+- `$is_public` - Can be used in content types
+- `$allow_index` - Allow database index
+
+**Field Types** (in `system/fields/`):
+- `string.php` - Single line text
+- `text.php` - Multi-line text
+- `html.php` - HTML content (with WYSIWYG)
+- `number.php` - Numeric value
+- `date.php` - Date/time picker
+- `checkbox.php` - Boolean checkbox
+- `list.php` - Dropdown select
+- `listmultiple.php` - Multi-select
+- `listbitmask.php` - Bitmask list
+- `listgroups.php` - Groups list
+- `image.php` - Single image upload
+- `images.php` - Multiple images
+- `file.php` - File upload
+- `url.php` - URL field
+- `user.php` - User selector
+- `category.php` - Category selector
+- `parent.php` - Parent item selector
+- `child.php` - Child items selector
+- `age.php` - Age field
+- `color.php` - Color picker
+- `captcha.php` - CAPTCHA
+- `toolbar.php` - Toolbar field
+- `fieldsgroup.php` - Group of fields
+- `forms.php` - Form selector
+- `hidden.php` - Hidden field
+- `city.php` - City selector (geo)
+- `paypal.php` - Payment field
+
+### cmsGrid
+Data grid builder for admin pages.
+
+**Grid Options:**
+```php
+$grid = [
+ 'source_url' => '/admin/controller/get_data',
+ 'options' => [
+ 'order_by' => 'id',
+ 'order_to' => 'asc',
+ 'show_id' => true,
+ 'is_sortable' => true,
+ 'is_filter' => true,
+ 'is_pagination' => true,
+ 'perpage' => 30,
+ 'is_draggable' => false,
+ 'is_selectable' => false,
+ ],
+ 'columns' => [
+ [
+ 'title' => 'Title',
+ 'width' => 200,
+ 'href' => href_to('controller', 'edit', ['{id}']),
+ ],
+ // ...
+ ],
+ 'actions' => [
+ ['title' => 'Edit', 'href' => href_to('controller', 'edit', ['{id}'])],
+ ['title' => 'Delete', 'href' => href_to('controller', 'delete', ['{id}']), 'class' => 'text-danger'],
+ ]
+];
+```
+
+Load grid in controller:
+```php
+$grid = $this->loadDataGrid('grid_name');
+```
+
+### cmsEventsManager
+Event/hook system.
+
+**Trigger Hook:**
+```php
+// Call hook and get modified data
+$data = cmsEventsManager::hook('event_name', $data);
+
+// Call all hooks, each receives original data
+cmsEventsManager::hookAll('event_name', $data);
+
+// Hook with default return value
+$result = cmsEventsManager::hook('event_name', $data, $default_return);
+```
+
+**Core Events:**
+- `core_start` - After bootstrap, before anything else
+- `engine_start` - Template engine started
+- `page_is_allowed` - Check page access
+- `user_registered` - New user registered
+- `user_login` - User logged in
+- `user_logout` - User logged out
+- `user_delete` - User deleted
+- `content_added` - Content item created
+- `content_after_add` - After content created
+- `content_updated` - Content item updated
+- `content_deleted` - Content item deleted
+- `comment_add` - Comment added
+- `html_filter` - Filter HTML content
+
+### cmsRequest
+HTTP request wrapper.
+
+**Access:**
+- `cmsCore::getInstance()->request` - Current request
+- `$this->request` - In controllers
+
+**Key Methods:**
+- `get($key, $default)` - GET parameter
+- `post($key, $default)` - POST parameter
+- `getServer($key)` - Server variable
+- `isAjax()` - AJAX request check
+- `hasFiles()` - File uploads check
+
+### cmsUser
+User object.
+
+**Key Properties:**
+- `id` - User ID
+- `email` - User email
+- `nickname` - Display name
+- `avatar` - Avatar path
+- `is_admin` - Admin flag
+- `is_logged` - Logged in flag
+
+**Key Methods:**
+- `get()` - Get current user
+- `getId()` - Get user ID
+- `isLogged()` - Check if logged in
+- `isAdmin()` - Check if admin
+- `isAllowed($controller, $type, $id)` - Check permission
+- `addSessionMessage($message, $type)` - Add flash message
+
+### cmsTemplate
+Template engine.
+
+**Key Methods:**
+- `render($template_file, $data)` - Render template file
+- `renderPartial($template_file, $data)` - Render without layout
+- `getVar($key)` - Get template variable
+- `setVar($key, $value)` - Set template variable
+
+**Template Files:**
+- Use `.tpl.php` extension
+- Access template via `$phpfen` variable in templates
+- URL helpers: `href_to()`, `href_to_abs()`, `uri_to()`
+
+### cmsConfig
+Configuration singleton.
+
+**Access:** `cmsConfig::getInstance()` or `cmsConfig::get('key')`
+
+**Key Config Values:**
+- `db_host` - Database host
+- `db_name` - Database name
+- `db_user` - Database user
+- `db_pass` - Database password
+- `db_prefix` - Table prefix
+- `language` - Default language
+- `time_zone` - Server timezone
+- `root_path` - Installation root
+- `sitename` - Site name
+- `debug` - Debug mode flag
+
+### cmsCache
+Caching abstraction.
+
+**Usage:**
+```php
+cmsCache::getInstance()->start();
+cmsCache::getInstance()->stop();
+// Or use direct methods
+```
+
+**Cache Backends:**
+- `cachefiles.php` - File-based cache
+- `cachememcache.php` - Memcache
+- `cachememcached.php` - Memcached
+- `cacheredis.php` - Redis
+
+---
+
+## Hooks/Events System
+
+Hooks are stored in `system/controllers/{controller}/hooks/` directory.
+
+**File Naming:** `{event}_{action}.php` (e.g., `wall_after_add.php`, `content_after_add_approve.php`)
+
+**Hook Class Structure:**
+```php
+class onUsersWallAfterAdd extends cmsAction {
+ public function run($param1, $param2) {
+ // Handler code
+ return $result; // Optional return value
+ }
+}
+```
+
+**Hook Class Naming:** `on{Controller}{EventName}` → `on{Event}_{Action}`
+
+**Example Hook File** (`wall_after_add.php`):
+```php
+class onUsersWallAfterAdd extends cmsAction {
+ public function run($profile_type, $profile_id, $entry, $wall_model) {
+ if ($profile_type != 'user') { return false; }
+ // ... handler code
+ return true;
+ }
+}
+```
+
+**Triggering Hooks:**
+```php
+// Single hook, data passes through chain
+$result = cmsEventsManager::hook('wall_after_add', $data);
+
+// All hooks, each gets original data, returns array of results
+$results = cmsEventsManager::hookAll('wall_after_add', $data);
+
+// Multiple events with same data
+$data = cmsEventsManager::hook(['event1', 'event2'], $data);
+```
+
+---
+
+## Controller Structure
+
+### Frontend Controller
+```php
+class mycontroller extends cmsFrontend {
+ const perpage = 15;
+
+ public function route($uri) {
+ // Custom routing logic
+ $action_name = parent::parseRoute($this->cms_core->uri);
+ if (!$action_name) {
+ return cmsCore::error404();
+ }
+ $this->runAction($action_name);
+ }
+
+ public function actionIndex() {
+ // Default action
+ }
+}
+```
+
+### Backend Controller
+```php
+class mycontroller extends cmsBackend {
+ public function __construct($request) {
+ parent::__construct($request);
+ $this->root_url = '/admin/mycontroller';
+ }
+
+ public function getIndexComps() {
+ return [
+ 'items' => 'My Items',
+ ];
+ }
+
+ public function actionIndex() {
+ // Admin list
+ }
+}
+```
+
+### Controller Directory Structure
+```
+system/controllers/{name}/
+├── frontend.php # Frontend controller class
+├── backend.php # Backend controller class (if admin)
+├── model.php # Frontend model
+├── routes.php # Custom routing rules
+├── actions/ # Action files
+│ ├── item_view.php
+│ ├── item_add.php
+│ └── item_edit.php
+├── backend/
+│ ├── backend.php # Backend controller (if separate)
+│ └── model.php # Backend model
+├── forms/ # Form classes
+│ ├── form_item.php
+│ └── form_options.php
+├── hooks/ # Event hooks
+│ ├── engine_start.php
+│ └── content_after_add.php
+└── widgets/ # Widget files
+ └── widget_mylist.php
+```
+
+### Controller Actions
+Actions are methods prefixed with `action` or files in `actions/` directory.
+
+**Method-based action:**
+```php
+public function actionMyAction($param1, $param2) {
+ // Returns string or cmsResponse
+}
+```
+
+**File-based action** (`actions/my_action.php`):
+```php
+public function run($param1, $param2) {
+ // Action code
+}
+```
+
+---
+
+## Model Structure
+
+### Frontend Model
+```php
+class modelContent extends cmsModel {
+ const DEFAULT_TABLE_PREFIX = 'con_';
+
+ public function getContentTypes() {
+ return $this->get('content_types')->fetchAll();
+ }
+
+ public function getContentType($id) {
+ return $this->get('content_types')->where('id', $id)->fetchOne();
+ }
+}
+```
+
+### Backend Model
+```php
+class modelBackendContent extends cmsModel {
+ public function getContentTypes() {
+ return $this->get('content_types')->fetchAll();
+ }
+}
+```
+
+---
+
+## Form Structure
+
+Forms extend `cmsForm` and define structure in `init()` method.
+
+```php
+class formMyItem extends cmsForm {
+ public function init($options = []) {
+ return [
+ 'basic' => [
+ 'title' => LANG_BASIC_OPTIONS,
+ 'type' => 'fieldset',
+ 'childs' => [
+ new fieldString('title', [
+ 'title' => LANG_TITLE,
+ 'rules' => [
+ ['required'],
+ ['max_length', 255]
+ ]
+ ]),
+ new fieldText('description', [
+ 'title' => LANG_DESCRIPTION
+ ]),
+ new fieldCheckbox('is_active', [
+ 'title' => LANG_IS_ACTIVE,
+ 'default' => true
+ ])
+ ]
+ ]
+ ];
+ }
+}
+```
+
+**Field Options:**
+- `title` - Field display title
+- `hint` - Help text
+- `default` - Default value
+- `rules` - Validation rules array
+- `options` - Field-specific options
+- `generator` - Callback for dynamic options
+- `disabled` - Disable field
+
+**Validation Rules:**
+```php
+['required']
+['max_length', 255]
+['min_length', 3]
+['email']
+['url']
+['regexp', '/^[a-z]+$/']
+['custom_rule', $param]
+```
+
+---
+
+## Language Files
+
+### Core Language File
+`system/languages/{lang}/language.php`
+```php
+define('LANG_LOADING', 'Загрузка...');
+define('LANG_SENDING', 'Отправка...');
+define('LANG_TITLE', 'Заголовок');
+define('LANG_CONTENT_TYPE', 'Тип контента');
+```
+
+### Controller Language File
+`system/languages/{lang}/controllers/{name}/content.php`
+```php
+
+
+// Conditional
+
+ Active
+
+
+// Loop
+
+
+
+
+// Widget inclusion
+renderWidget('widget_name', $options); ?>
+```
+
+---
+
+## Widget System
+
+Widgets are in `system/controllers/{name}/widgets/` or `templates/{name}/widgets/`.
+
+### Widget Structure
+```php
+class widgetMyList extends cmsWidget {
+ public function run($options) {
+ $model = cmsCore::getModel('content');
+ $items = $model->getItems($options['limit'] ?? 10);
+
+ return [
+ 'items' => $items,
+ 'options' => $options
+ ];
+ }
+}
+```
+
+### Widget Templates
+`templates/{name}/widgets/{widget_name}.tpl.php`
+
+---
+
+## Database Tables
+
+**Core Tables:**
+- `cms_users` - User accounts
+- `cms_user_tokens` - Auth tokens
+- `cms_user_sessions` - User sessions
+- `cms_user_warnings` - User warnings
+- `cms_content_types` - Content type definitions
+- `cms_content_items` - Content items base table
+- `cms_con_{ctype}_fields` - Per-content-type fields
+- `cms_categories` - Categories (nested sets)
+- `cms_comments` - Comments
+- `cms_ratings` - Ratings
+- `cms_tags` - Tags
+- `cms_tags_items` - Tag relations
+- `cms_widgets` - Widget instances
+- `cms_widgets_pages` - Page-widget bindings
+- `cms_menus` - Menu definitions
+- `cms_menu_items` - Menu items
+- `cms_events` - Event subscriptions
+- `cms_controllers` - Registered controllers
+- `cms_permissions` - Permission rules
+- `cms_sessions` - PHP sessions storage
+- `cms_cache` - Cache table
+
+---
+
+## Build, Test, and Lint Commands
+
+**No formal testing framework is set up.** No PHPUnit, phpunit.xml, or tests directory.
+
+### PHP Syntax Check
+```bash
+php -l
+```
+
+### Code Formatting
+- **4-space indentation** (not tabs)
+- No automated formatter configured
+
+### Static Analysis
+- None configured (no phpstan, phan, etc.)
+
+---
+
+## Code Style Guidelines
+
+### PHP Tag and Encoding
+- Always use `` tag (except pure class files)
+- Add `#[\AllowDynamicProperties]` attribute to classes using dynamic properties
+
+### Indentation
+- Use **4 spaces** for indentation
+- Section dividers: `//============================================================================//`
+
+### Naming Conventions
+| Element | Convention | Example |
+|---------|-----------|---------|
+| Classes | CamelCase | `cmsController`, `cmsDatabase` |
+| Methods | camelCase | `getInstance()`, `setOptions()` |
+| Properties | camelCase | `$table_prefix`, `$query_count` |
+| Constants | UPPER_SNAKE_CASE | `LEFT_JOIN`, `READ_COMMITTED` |
+| Core classes | `cms` prefix | `cmsDatabase`, `cmsController` |
+| Field classes | `field` prefix | `fieldString`, `fieldText` |
+| Model classes | `model` prefix | `modelContent`, `modelBackendContent` |
+| Hook classes | `on` prefix | `onUsersWallAfterAdd` |
+| Namespaces | `icms\` prefix | `icms\traits\corePropertyLoadable` |
+| Table names | snake_case | `content_items`, `user_sessions` |
+
+### PHPDoc and Comments
+- Use **Russian comments** for internal documentation
+- PHPDoc format:
+```php
+/**
+ * Description of method
+ * @param string $param_name Description
+ * @return array|null
+ * @throws Exception
+ */
+```
+- Property doc format:
+```php
+/**
+ * Description of property
+ * @var string
+ */
+public $property_name;
+```
+
+### Error Handling
+- Use `Exception` class (not custom exceptions unless necessary)
+- `throw new Exception('Error message')`
+- `cmsCore::error404()` for page not found
+- Set `$this->query_quiet = true` on database object to suppress query errors
+
+### Best Practices
+1. Use `cmsDatabase::getInstance()` for DB connection
+2. Use `cmsCore::getInstance()` for core access
+3. Check `$this->cms_config->debug` before debug output
+4. Use `cmsUser::isAllowed()` for permission checks
+5. Use `cmsObject::merge()` for combining options arrays
+6. Use lang constants instead of hardcoded strings
+7. Use prepared statements for SQL queries
+
+---
+
+## Important Constants
+
+```php
+PATH // Root path (set in bootstrap.php)
+ROOT // Document root (legacy)
+ICMS_CONFIG_DIR // Config directory
+VALID_RUN // HTTP mode flag (timestamp)
+SESSION_START // Session needed flag
+```
+
+---
+
+## Quick Reference
+
+### Getting Started with New Controller
+1. Create directory: `system/controllers/{name}/`
+2. Create `frontend.php` extending `cmsFrontend`
+3. Create `model.php` extending `cmsModel`
+4. Create `routes.php` for custom URLs (optional)
+5. Create `actions/` directory for file-based actions
+6. Create `hooks/` directory for event hooks
+7. Create `forms/` directory for form classes
+8. Create language file: `system/languages/ru/controllers/{name}/content.php`
+9. Create manifest: `install/manifests/{name}.php`
+
+### Getting Started with New Field Type
+1. Create file: `system/fields/{fieldname}.php`
+2. Extend `cmsFormField` class
+3. Implement required methods: `parse()`, `getSQL()`, `applyFilter()`
+4. Register in content type via admin panel
+
+---
+
+## Installation System
+
+The `install/` directory contains the web-based installation wizard and CLI rebuild script.
+
+### Directory Structure
+```
+install/
+├── index.php # Main entry point
+├── functions.php # Helper functions
+├── manifest.php # Build configuration
+├── rebuild.php # CLI distribution builder
+├── steps/ # Installation step handlers
+│ ├── start.php # Welcome screen
+│ ├── license.php # GPL license acceptance
+│ ├── php.php # PHP requirements check
+│ ├── paths.php # Path configuration
+│ ├── site.php # Site settings (name, template)
+│ ├── database.php # DB connection, table creation, SQL import
+│ ├── admin.php # Admin user creation
+│ ├── config.php # Config file generation
+│ ├── cron.php # Cron configuration
+│ ├── addons.php # External addons selection
+│ ├── addons_install.php # External addons installation (after bootstrap)
+│ └── finish.php # Completion
+├── manifests/ # Per-controller file lists for uninstall
+│ ├── billing.php
+│ ├── comments.php
+│ └── ...
+├── templates/ # Step HTML templates
+│ ├── main.php # Main layout wrapper
+│ └── step_*.php # Individual step templates
+├── languages/ # Localization
+│ ├── ru/
+│ │ ├── language.php # Russian strings
+│ │ └── sql/ # SQL dumps
+│ │ ├── base.sql # Core tables
+│ │ ├── base_demo_*.sql # Demo content
+│ │ ├── widgets_bind_*.sql # Widget layouts
+│ │ └── packages/ # Per-controller SQL
+│ └── en/
+├── css/, js/, images/ # Frontend assets
+├── upload/ # Default uploaded files per template
+└── externals/ # Downloaded external addons
+```
+
+### Installation Flow
+1. **Session-based navigation** - Each step stores data in `$_SESSION['install']`
+2. **AJAX-driven** - Steps submitted via XMLHttpRequest, responses JSON
+3. **11 total steps** - Plus optional addons step if `externals/` directory exists
+4. **SQL Dumps** - `base.sql` creates core tables, `packages/*/` for controllers
+5. **Config generation** - PHP config file written to `system/config/config.php`
+6. **Admin creation** - User ID 1 updated with credentials + auth token
+
+### Step Files
+Each step file (`steps/{step}.php`) must define:
+```php
+function step($is_submit) {
+ // $is_submit indicates form submission vs initial display
+ return [
+ 'html' => render('step_template_name', $data),
+ 'error' => false,
+ 'message' => 'optional error message'
+ ];
+}
+```
+
+### Key Helper Functions (`functions.php`)
+```php
+render($template_name, $data) // Simple template renderer (output buffering)
+run_step($step, $is_submit) // Includes step file, calls step()
+get_db_list() // Lists MySQL databases
+import_dump($mysqli, $file, $prefix, $engine, $delimiter, $charset, $innodb_full_text)
+ // Generator-based SQL parser with prefix replacement
+copy_folder($dir_source, $dir_target) // Recursive directory copy
+preinstall_addon($addon) // Downloads and extracts addon from API
+get_api_method($name, $params) // CURL wrapper for instantcms.ru API
+```
+
+### SQL Structure
+```
+languages/{lang}/sql/
+├── base.sql # Core tables (users, content, widgets, etc.)
+├── base_demo_{template}.sql # Demo content data
+├── widgets_bind_{template}.sql # Default widget positions
+├── widgets_bind_demo_{template}.sql
+└── packages/
+ ├── billing/
+ ├── comments/
+ ├── forms/
+ └── ...
+```
+
+### Manifest Files (`install/manifests/*.php`)
+Define which files/dirs belong to each addon for uninstall:
+```php
+return [
+ 'dirs' => [
+ 'system/controllers/billing',
+ 'system/languages/ru/controllers/billing',
+ ],
+ 'files' => [
+ 'system/languages/ru/letters/billing_*.txt',
+ ]
+];
+```
+
+### Rebuild Script (`rebuild.php`)
+CLI tool to create custom InstantCMS distributions:
+```bash
+php -f rebuild.php
+```
+
+Features:
+- Removes components listed in `manifest['removed']`
+- Adds paid/free addons from API via `manifest['added']`
+- Sets file permissions (644 files, 755 dirs)
+- Creates ZIP archive
+- Marks as custom: `is_custom = 1` in version.ini
+
+### Build Manifest (`install/manifest.php`)
+Configuration for archive building:
+```php
+return [
+ 'removed' => ['billing', 'photos'], // Components to exclude
+ 'create_archive' => true, // Create ZIP
+ 'archive_name' => 'my_custom_build', // Archive filename
+ 'added' => ['[addon]123[/addon]'] // Addons to include from API
+];
+```
+
+### Addons API
+- **Endpoint**: `https://api.instantcms.ru/{lang}api/method/`
+- **API Key**: `8e13cb202f8bdc27dc765e0448e50d11` (hardcoded)
+- Downloads addon ZIP, extracts to `externals/`, copies `package/` to site root
+
+### Config Generation (`steps/config.php`)
+Writes `system/config/config.php`:
+```php
+$config = [
+ 'root' => '/',
+ 'db_host' => 'localhost',
+ 'db_base' => 'instantcms',
+ 'db_user' => 'root',
+ 'db_pass' => '',
+ 'db_prefix' => 'cms_',
+ 'language' => LANG,
+ 'template' => 'default',
+ 'debug' => 0,
+ // ... 100+ options
+];
+write_config($file, $config);
+```
+
+### Admin Creation (`steps/admin.php`)
+Updates User ID 1 with:
+- Nickname, email, bcrypt password hash
+- Auth token (SHA512 of md5's)
+- Auto-login via cookie
diff --git a/install/data/components.php b/install/data/components.php
new file mode 100644
index 000000000..e7fe042dd
--- /dev/null
+++ b/install/data/components.php
@@ -0,0 +1,186 @@
+ [
+ 'admin', 'content', 'users', 'messages', 'auth',
+ 'moderation', 'images', 'wysiwygs', 'languages', 'typograph'
+ ],
+
+ 'categories' => [
+ 'social' => [
+ 'title' => 'LANG_CAT_SOCIAL',
+ 'components' => [
+ 'comments' => [
+ 'title' => 'LANG_COMMENTS',
+ 'desc' => 'LANG_COMMENTS_DESC',
+ 'deps' => []
+ ],
+ 'rating' => [
+ 'title' => 'LANG_RATING',
+ 'desc' => 'LANG_RATING_DESC',
+ 'deps' => []
+ ],
+ 'activity' => [
+ 'title' => 'LANG_ACTIVITY',
+ 'desc' => 'LANG_ACTIVITY_DESC',
+ 'deps' => ['comments', 'rating']
+ ],
+ 'wall' => [
+ 'title' => 'LANG_WALL',
+ 'desc' => 'LANG_WALL_DESC',
+ 'deps' => ['comments', 'activity']
+ ],
+ 'groups' => [
+ 'title' => 'LANG_GROUPS',
+ 'desc' => 'LANG_GROUPS_DESC',
+ 'deps' => ['wall', 'activity']
+ ],
+ ]
+ ],
+ 'content' => [
+ 'title' => 'LANG_CAT_CONTENT',
+ 'components' => [
+ 'tags' => [
+ 'title' => 'LANG_TAGS',
+ 'desc' => 'LANG_TAGS_DESC',
+ 'deps' => []
+ ],
+ 'search' => [
+ 'title' => 'LANG_SEARCH',
+ 'desc' => 'LANG_SEARCH_DESC',
+ 'deps' => []
+ ],
+ 'sitemap' => [
+ 'title' => 'LANG_SITEMAP',
+ 'desc' => 'LANG_SITEMAP_DESC',
+ 'deps' => []
+ ],
+ 'rss' => [
+ 'title' => 'LANG_RSS',
+ 'desc' => 'LANG_RSS_DESC',
+ 'deps' => []
+ ],
+ ]
+ ],
+ 'media' => [
+ 'title' => 'LANG_CAT_MEDIA',
+ 'components' => [
+ 'photos' => [
+ 'title' => 'LANG_PHOTOS',
+ 'desc' => 'LANG_PHOTOS_DESC',
+ 'deps' => []
+ ],
+ ]
+ ],
+ 'tools' => [
+ 'title' => 'LANG_CAT_TOOLS',
+ 'components' => [
+ 'forms' => [
+ 'title' => 'LANG_FORMS',
+ 'desc' => 'LANG_FORMS_DESC',
+ 'deps' => []
+ ],
+ 'geo' => [
+ 'title' => 'LANG_GEO',
+ 'desc' => 'LANG_GEO_DESC',
+ 'deps' => []
+ ],
+ ]
+ ],
+ 'security' => [
+ 'title' => 'LANG_CAT_SECURITY',
+ 'components' => [
+ 'recaptcha' => [
+ 'title' => 'LANG_RECAPTCHA',
+ 'desc' => 'LANG_RECAPTCHA_DESC',
+ 'deps' => []
+ ],
+ 'csp' => [
+ 'title' => 'LANG_CSP',
+ 'desc' => 'LANG_CSP_DESC',
+ 'deps' => []
+ ],
+ ]
+ ],
+ 'monetization' => [
+ 'title' => 'LANG_CAT_MONETIZATION',
+ 'components' => [
+ 'billing' => [
+ 'title' => 'LANG_BILLING',
+ 'desc' => 'LANG_BILLING_DESC',
+ 'deps' => []
+ ],
+ ]
+ ],
+ 'seo' => [
+ 'title' => 'LANG_CAT_SEO',
+ 'components' => [
+ 'redirect' => [
+ 'title' => 'LANG_REDIRECT',
+ 'desc' => 'LANG_REDIRECT_DESC',
+ 'deps' => []
+ ],
+ ]
+ ],
+ 'notifications' => [
+ 'title' => 'LANG_CAT_NOTIFICATIONS',
+ 'components' => [
+ 'subscriptions' => [
+ 'title' => 'LANG_SUBSCRIPTIONS',
+ 'desc' => 'LANG_SUBSCRIPTIONS_DESC',
+ 'deps' => []
+ ],
+ ]
+ ],
+ ],
+
+ 'install_types' => [
+ 'minimal' => [
+ 'title' => 'LANG_INSTALL_MINIMAL',
+ 'desc' => 'LANG_INSTALL_MINIMAL_DESC',
+ 'components' => [],
+ 'demo' => false
+ ],
+ 'standard' => [
+ 'title' => 'LANG_INSTALL_STANDARD',
+ 'desc' => 'LANG_INSTALL_STANDARD_DESC',
+ 'components' => ['comments', 'rating', 'activity', 'wall', 'groups', 'tags', 'search', 'photos'],
+ 'demo' => 'standard'
+ ],
+ 'full' => [
+ 'title' => 'LANG_INSTALL_FULL',
+ 'desc' => 'LANG_INSTALL_FULL_DESC',
+ 'components' => ['comments', 'rating', 'activity', 'wall', 'groups', 'tags', 'search', 'sitemap', 'rss', 'photos', 'forms', 'geo', 'recaptcha', 'csp', 'billing', 'subscriptions', 'redirect'],
+ 'demo' => 'full'
+ ],
+ 'custom' => [
+ 'title' => 'LANG_INSTALL_CUSTOM',
+ 'desc' => 'LANG_INSTALL_CUSTOM_DESC',
+ 'components' => [],
+ 'demo' => true
+ ]
+ ],
+
+ 'dependencies' => [
+ 'photos' => [],
+ 'comments' => [],
+ 'rating' => [],
+ 'activity' => ['comments', 'rating'],
+ 'wall' => ['comments', 'activity'],
+ 'groups' => ['wall', 'activity'],
+ 'tags' => [],
+ 'search' => [],
+ 'sitemap' => [],
+ 'rss' => [],
+ 'photos' => [],
+ 'forms' => [],
+ 'geo' => [],
+ 'recaptcha' => [],
+ 'csp' => [],
+ 'billing' => [],
+ 'redirect' => [],
+ 'subscriptions' => [],
+ ]
+];
diff --git a/install/functions.php b/install/functions.php
index ebaa227b8..c7be968d1 100755
--- a/install/functions.php
+++ b/install/functions.php
@@ -10,6 +10,15 @@ function is_ajax_request() {
return $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
}
+function format_size($bytes) {
+ if ($bytes >= 1048576) {
+ return number_format($bytes / 1048576, 1) . ' MB';
+ } elseif ($bytes >= 1024) {
+ return number_format($bytes / 1024, 1) . ' KB';
+ }
+ return $bytes . ' B';
+}
+
function render($template_name, $data = []) {
extract($data);
ob_start();
@@ -414,3 +423,51 @@ function preinstall_addon ($addon) {
return true;
}
+
+function find_component_sql_file($component, $type = 'base') {
+
+ $data = include PATH . 'data/components.php';
+
+ $sql_dir = PATH . 'languages' . DS . LANG . DS . 'sql';
+ $template = $_SESSION['install']['site']['template'] ?? 'default';
+
+ foreach ($data['categories'] as $cat_id => $cat) {
+ if (!isset($cat['components'][$component])) {
+ continue;
+ }
+
+ if ($type === 'base') {
+ $file = $cat_id . DS . $component . '_base.sql';
+ $path = $sql_dir . DS . $file;
+ if (file_exists($path)) {
+ return $file;
+ }
+ }
+
+ if ($type === 'demo') {
+ $demo_file = $cat_id . DS . $component . '_demo_' . $template . '.sql';
+ $demo_path = $sql_dir . DS . $demo_file;
+ if (file_exists($demo_path)) {
+ return $demo_file;
+ }
+
+ $default_demo = $cat_id . DS . $component . '_demo_default.sql';
+ $default_path = $sql_dir . DS . $default_demo;
+ if (file_exists($default_path)) {
+ return $default_demo;
+ }
+ }
+ }
+
+ return null;
+}
+
+function get_mandatory_components() {
+ $data = include PATH . 'data/components.php';
+ return $data['mandatory'];
+}
+
+function get_component_dependencies($component) {
+ $data = include PATH . 'data/components.php';
+ return $data['dependencies'][$component] ?? [];
+}
diff --git a/install/index.php b/install/index.php
index d0e41c9d2..8fdff1e22 100755
--- a/install/index.php
+++ b/install/index.php
@@ -45,10 +45,12 @@
['id' => 'php', 'title' => LANG_STEP_PHP_CHECK],
['id' => 'paths', 'title' => LANG_STEP_PATHS],
['id' => 'site', 'title' => LANG_STEP_SITE],
+ ['id' => 'components', 'title' => LANG_STEP_COMPONENTS],
['id' => 'database', 'title' => LANG_STEP_DATABASE],
['id' => 'admin', 'title' => LANG_STEP_ADMIN],
['id' => 'config', 'title' => LANG_STEP_CONFIG],
['id' => 'cron', 'title' => LANG_STEP_CRON],
+ ['id' => 'cleanup', 'title' => LANG_STEP_CLEANUP],
['id' => 'finish', 'title' => LANG_STEP_FINISH]
];
diff --git a/install/languages/en/language.php b/install/languages/en/language.php
index 43782998e..734678daa 100755
--- a/install/languages/en/language.php
+++ b/install/languages/en/language.php
@@ -3,6 +3,7 @@
define('LANG_PAGE_TITLE', 'InstantCMS Installation');
define('LANG_INSTALLATION_WIZARD', 'Installation wizard');
define('LANG_NEXT', 'Next →');
+ define('LANG_BACK', '← Back');
define('LANG_ERROR', 'Error');
define('LANG_FROM', 'from');
define('LANG_DEPRECATED', 'Deprecated');
@@ -161,3 +162,82 @@
define('LANG_RB_SUCCES_ARCH', 'Archiving is complete. The file is located at %s');
define('LANG_RB_DONE', 'Customization successfully completed.');
define('LANG_RB_DONE_HINT', 'You can start InstantCMS installation.');
+
+// =============================================================================
+// Install Types and Components
+// =============================================================================
+
+ define('LANG_INSTALL_TYPE', 'Installation type');
+ define('LANG_INSTALL_MINIMAL', 'Minimal');
+ define('LANG_INSTALL_MINIMAL_DESC', 'Only basic functions. Suitable for development or if you only need pages.');
+ define('LANG_INSTALL_STANDARD', 'Standard');
+ define('LANG_INSTALL_STANDARD_DESC', 'Social features, search, tags. Recommended for most sites.');
+ define('LANG_INSTALL_FULL', 'Full');
+ define('LANG_INSTALL_FULL_DESC', 'All available system components.');
+ define('LANG_INSTALL_CUSTOM', 'Custom');
+ define('LANG_INSTALL_CUSTOM_DESC', 'Select components manually.');
+ define('LANG_INSTALL_DEMO_CONTENT', 'Install demo content');
+
+ define('LANG_CAT_SOCIAL', 'Social');
+ define('LANG_CAT_CONTENT', 'Content');
+ define('LANG_CAT_MEDIA', 'Media');
+ define('LANG_CAT_TOOLS', 'Tools');
+ define('LANG_CAT_SECURITY', 'Security');
+ define('LANG_CAT_MONETIZATION', 'Monetization');
+ define('LANG_CAT_SEO', 'SEO');
+ define('LANG_CAT_NOTIFICATIONS', 'Notifications');
+
+ define('LANG_COMMENTS', 'Comments');
+ define('LANG_COMMENTS_DESC', 'Comments system for content entries');
+ define('LANG_RATING', 'Rating');
+ define('LANG_RATING_DESC', 'Content voting system');
+ define('LANG_ACTIVITY', 'Activity stream');
+ define('LANG_ACTIVITY_DESC', 'User and friends activity feed');
+ define('LANG_WALL', 'Wall');
+ define('LANG_WALL_DESC', 'Wall in user profiles');
+ define('LANG_GROUPS', 'Groups');
+ define('LANG_GROUPS_DESC', 'User groups');
+ define('LANG_TAGS', 'Tags');
+ define('LANG_TAGS_DESC', 'Content tags');
+ define('LANG_SEARCH', 'Search');
+ define('LANG_SEARCH_DESC', 'Full-text site search');
+ define('LANG_SITEMAP', 'Sitemap');
+ define('LANG_SITEMAP_DESC', 'XML sitemap generation');
+ define('LANG_RSS', 'RSS');
+ define('LANG_RSS_DESC', 'RSS feeds for content');
+ define('LANG_PHOTOS', 'Photo gallery');
+ define('LANG_PHOTOS_DESC', 'Image gallery');
+ define('LANG_FORMS', 'Form builder');
+ define('LANG_FORMS_DESC', 'Create custom forms');
+ define('LANG_GEO', 'Geolocation');
+ define('LANG_GEO_DESC', 'User location detection');
+ define('LANG_RECAPTCHA', 'reCAPTCHA');
+ define('LANG_RECAPTCHA_DESC', 'Google reCAPTCHA spam protection');
+ define('LANG_CSP', 'CSP');
+ define('LANG_CSP_DESC', 'Content Security Policy protection');
+ define('LANG_BILLING', 'Billing');
+ define('LANG_BILLING_DESC', 'Payment system for the site');
+ define('LANG_REDIRECT', 'Redirects');
+ define('LANG_REDIRECT_DESC', 'URL redirect management');
+ define('LANG_SUBSCRIPTIONS', 'Subscriptions');
+ define('LANG_SUBSCRIPTIONS_DESC', 'Content update subscriptions');
+
+ define('LANG_STEP_COMPONENTS', 'Component selection');
+ define('LANG_STEP_COMPONENTS_HINT', 'Select installation type or choose components manually');
+ define('LANG_MANDATORY', 'mandatory');
+ define('LANG_REQUIRES', 'Requires');
+ define('LANG_COMPONENT_REQUIRES', 'Component "%s" requires component "%s"');
+ define('LANG_CUSTOM_COMPONENTS', 'Component selection');
+ define('LANG_CUSTOM_COMPONENTS_HINT', 'Check components to install. Mandatory components are already checked and cannot be disabled.');
+
+ define('LANG_STEP_CLEANUP', 'Cleanup');
+ define('LANG_CLEANUP_INFO', 'Select files to delete. This will free up disk space.');
+ define('LANG_CLEANUP_NOTHING', 'Nothing to delete. All installed components are present.');
+ define('LANG_CLEANUP_TOTAL', 'Total to delete');
+ define('LANG_CLEANUP_SELECT', 'Select what to delete');
+ define('LANG_CLEANUP_TYPE_COMPONENT', 'component');
+ define('LANG_CLEANUP_REMOVED', 'Removed');
+ define('LANG_CLEANUP_ERRORS', 'Errors while removing');
+ define('LANG_CLEANUP_COMPLETE', 'Cleanup complete');
+ define('LANG_SELECT_ALL', 'Select all');
+ define('LANG_DESELECT_ALL', 'Deselect all');
diff --git a/install/languages/en/sql/packages/rss/base.sql b/install/languages/en/sql/content/rss_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/rss/base.sql
rename to install/languages/en/sql/content/rss_base.sql
diff --git a/install/languages/en/sql/packages/rss/base_demo_default.sql b/install/languages/en/sql/content/rss_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/rss/base_demo_default.sql
rename to install/languages/en/sql/content/rss_demo_default.sql
diff --git a/install/languages/en/sql/packages/rss/base_demo_modern.sql b/install/languages/en/sql/content/rss_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/rss/base_demo_modern.sql
rename to install/languages/en/sql/content/rss_demo_modern.sql
diff --git a/install/languages/en/sql/packages/search/base.sql b/install/languages/en/sql/content/search_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/search/base.sql
rename to install/languages/en/sql/content/search_base.sql
diff --git a/install/languages/en/sql/packages/sitemap/base.sql b/install/languages/en/sql/content/sitemap_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/sitemap/base.sql
rename to install/languages/en/sql/content/sitemap_base.sql
diff --git a/install/languages/en/sql/packages/tags/base.sql b/install/languages/en/sql/content/tags_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/tags/base.sql
rename to install/languages/en/sql/content/tags_base.sql
diff --git a/install/languages/en/sql/packages/tags/base_demo_default.sql b/install/languages/en/sql/content/tags_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/tags/base_demo_default.sql
rename to install/languages/en/sql/content/tags_demo_default.sql
diff --git a/install/languages/en/sql/packages/tags/base_demo_modern.sql b/install/languages/en/sql/content/tags_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/tags/base_demo_modern.sql
rename to install/languages/en/sql/content/tags_demo_modern.sql
diff --git a/install/languages/en/sql/base_demo_modern.sql b/install/languages/en/sql/core/full_demo.sql
similarity index 100%
rename from install/languages/en/sql/base_demo_modern.sql
rename to install/languages/en/sql/core/full_demo.sql
diff --git a/install/languages/en/sql/base_demo_default.sql b/install/languages/en/sql/core/standard_demo.sql
similarity index 100%
rename from install/languages/en/sql/base_demo_default.sql
rename to install/languages/en/sql/core/standard_demo.sql
diff --git a/install/languages/en/sql/widgets_bind_default.sql b/install/languages/en/sql/core/widgets_default.sql
similarity index 100%
rename from install/languages/en/sql/widgets_bind_default.sql
rename to install/languages/en/sql/core/widgets_default.sql
diff --git a/install/languages/en/sql/widgets_bind_demo_default.sql b/install/languages/en/sql/core/widgets_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/widgets_bind_demo_default.sql
rename to install/languages/en/sql/core/widgets_demo_default.sql
diff --git a/install/languages/en/sql/widgets_bind_demo_modern.sql b/install/languages/en/sql/core/widgets_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/widgets_bind_demo_modern.sql
rename to install/languages/en/sql/core/widgets_demo_modern.sql
diff --git a/install/languages/en/sql/widgets_bind_modern.sql b/install/languages/en/sql/core/widgets_modern.sql
similarity index 100%
rename from install/languages/en/sql/widgets_bind_modern.sql
rename to install/languages/en/sql/core/widgets_modern.sql
diff --git a/install/languages/en/sql/packages/photos/base.sql b/install/languages/en/sql/media/photos_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/photos/base.sql
rename to install/languages/en/sql/media/photos_base.sql
diff --git a/install/languages/en/sql/packages/photos/base_demo_default.sql b/install/languages/en/sql/media/photos_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/photos/base_demo_default.sql
rename to install/languages/en/sql/media/photos_demo_default.sql
diff --git a/install/languages/en/sql/packages/photos/base_demo_modern.sql b/install/languages/en/sql/media/photos_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/photos/base_demo_modern.sql
rename to install/languages/en/sql/media/photos_demo_modern.sql
diff --git a/install/languages/en/sql/packages/billing/base.sql b/install/languages/en/sql/monetization/billing_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/billing/base.sql
rename to install/languages/en/sql/monetization/billing_base.sql
diff --git a/install/languages/en/sql/packages/billing/base_demo_default.sql b/install/languages/en/sql/monetization/billing_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/billing/base_demo_default.sql
rename to install/languages/en/sql/monetization/billing_demo_default.sql
diff --git a/install/languages/en/sql/packages/billing/base_demo_modern.sql b/install/languages/en/sql/monetization/billing_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/billing/base_demo_modern.sql
rename to install/languages/en/sql/monetization/billing_demo_modern.sql
diff --git a/install/languages/en/sql/packages/subscriptions/base.sql b/install/languages/en/sql/notifications/subscriptions_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/subscriptions/base.sql
rename to install/languages/en/sql/notifications/subscriptions_base.sql
diff --git a/install/languages/en/sql/packages/activity/widgets_bind_demo_default.sql b/install/languages/en/sql/packages/activity/widgets_bind_demo_default.sql
deleted file mode 100755
index b0549499f..000000000
--- a/install/languages/en/sql/packages/activity/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'activity' AND `name` = 'list'), 'Activity feed', 'All | activity\r\n{My friends | activity/index/friends}\r\n{My | activity/index/my}', NULL, NULL, NULL, 1, NULL, '---\n- 0\n', NULL, '---\ndataset: all\nshow_avatars: 1\ndate_group: null\nlimit: 5\n', NULL, 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'left-bottom', 3);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/activity/widgets_bind_demo_modern.sql b/install/languages/en/sql/packages/activity/widgets_bind_demo_modern.sql
deleted file mode 100755
index 5f8941da5..000000000
--- a/install/languages/en/sql/packages/activity/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'activity' AND `name` = 'list'), 'Activity feed', 'All | activity\r\n{My friends | activity/index/friends}\r\n{My | activity/index/my}', NULL, NULL, NULL, 1, NULL, '---\n', NULL, '---\ndataset: all\nshow_avatars: 1\ndate_group: null\nlimit: 8\n', 'list', 'wrapper', 'icms-widget__transparent', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_8', 5);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/billing/photos/base.sql b/install/languages/en/sql/packages/billing/photos/base.sql
deleted file mode 100755
index 7a19c1a4d..000000000
--- a/install/languages/en/sql/packages/billing/photos/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}billing_actions` (`controller`, `name`, `title`, `prices`) VALUES
-('content', 'albums_add', 'Photo albums: adding', '---\n3: 0\n4: 0\n5: 0\n6: 0\n');
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/comments/activity/base.sql b/install/languages/en/sql/packages/comments/activity/base.sql
deleted file mode 100755
index ff10dc617..000000000
--- a/install/languages/en/sql/packages/comments/activity/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(1, 'comments', 'vote.comment', 'Rating comments', 'evaluate a comment on the %s page');
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/comments/rss/base.sql b/install/languages/en/sql/packages/comments/rss/base.sql
deleted file mode 100755
index a75e511b4..000000000
--- a/install/languages/en/sql/packages/comments/rss/base.sql
+++ /dev/null
@@ -1 +0,0 @@
-INSERT INTO `{#}rss_feeds` (`ctype_id`, `ctype_name`, `title`, `description`, `image`, `mapping`, `limit`, `is_enabled`, `is_cache`, `cache_interval`, `date_cached`) VALUES (NULL, 'comments', 'Comments', NULL, NULL, '---\r\ntitle: target_title\r\ndescription: content_html\r\npubDate: date_pub\r\n', 15, 1, NULL, 60, NULL);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/comments/widgets_bind_demo_default.sql b/install/languages/en/sql/packages/comments/widgets_bind_demo_default.sql
deleted file mode 100755
index 8dfb6f5ce..000000000
--- a/install/languages/en/sql/packages/comments/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'comments' AND `name` = 'list'), 'Latest comments', 'All | comments\r\n{My friends | comments/index/friends}\r\n{My | comments/index/my}', NULL, NULL, NULL, 1, 1, '---\n- 0\n', NULL, '---\nshow_avatars: 1\nshow_text: 1\nlimit: 10\n', NULL, 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'left-bottom', 4);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/comments/widgets_bind_demo_modern.sql b/install/languages/en/sql/packages/comments/widgets_bind_demo_modern.sql
deleted file mode 100755
index b2ca6cf7c..000000000
--- a/install/languages/en/sql/packages/comments/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'comments' AND `name` = 'list'), 'Comments', 'All | comments', NULL, NULL, NULL, 1, 1, '---\n', NULL, '---\nshow_list:\n - 0\nshow_avatars: 1\nshow_text: 1\nlimit: 10\n', 'list', 'wrapper', NULL, NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_8', 6);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/groups/activity/base.sql b/install/languages/en/sql/packages/groups/activity/base.sql
deleted file mode 100755
index 2223e9adb..000000000
--- a/install/languages/en/sql/packages/groups/activity/base.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(1, 'groups', 'join', 'Group joining', 'joined the group %s'),
-(1, 'groups', 'leave', 'Group leaving', 'left the group %s');
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/photos/activity/base.sql b/install/languages/en/sql/packages/photos/activity/base.sql
deleted file mode 100755
index 2e05ec02b..000000000
--- a/install/languages/en/sql/packages/photos/activity/base.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(0, 'content', 'add.albums', 'Adding albums', 'added album %s'),
-(1, 'photos', 'add.photos', 'Photo uploading', 'uploaded photos to the album %s');
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/photos/rss/base.sql b/install/languages/en/sql/packages/photos/rss/base.sql
deleted file mode 100755
index 6eff39cb6..000000000
--- a/install/languages/en/sql/packages/photos/rss/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}rss_feeds` (`ctype_id`, `ctype_name`, `title`, `description`, `image`, `mapping`, `limit`, `is_enabled`, `is_cache`, `cache_interval`, `date_cached`) VALUES
-(7, 'albums', 'Photo albums', NULL, NULL, '---\ntitle: title\ndescription: content\npubDate: date_pub\nimage: cover_image\nimage_size: normal\n', 15, 1, NULL, 60, NULL);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/photos/widgets_bind_demo_default.sql b/install/languages/en/sql/packages/photos/widgets_bind_demo_default.sql
deleted file mode 100755
index f87da67ca..000000000
--- a/install/languages/en/sql/packages/photos/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'content' AND `name` = 'list'), 'Photo albums', 'All albums | albums\r\n{Upload photos | photos/upload}', NULL, NULL, NULL, 1, 1, '---\n- 0\n', NULL, '---\nctype_id: 7\ndataset:\nimage_field: cover_image\nteaser_field:\nshow_details: null\nlimit: 5\n', 'list_tiles_big', 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'left-bottom', 2);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/photos/widgets_bind_demo_modern.sql b/install/languages/en/sql/packages/photos/widgets_bind_demo_modern.sql
deleted file mode 100755
index 1aba83ffe..000000000
--- a/install/languages/en/sql/packages/photos/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'photos' AND `name` = 'list'), 'Photos', 'All albums | albums\r\n{Upload photos | photos/upload}', NULL, NULL, NULL, 1, 1, '---\n', NULL, '---\nauto_user: null\nauto_group: null\nauto_ctype_item: null\ntarget: 0\nalbum_id:\nordering:\norientation:\ntype:\nwidth:\nheight:\nlimit: 10\n', 'list', 'wrapper', 'icms-widget__transparent', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_8', 4);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/search/widgets_bind_demo_default.sql b/install/languages/en/sql/packages/search/widgets_bind_demo_default.sql
deleted file mode 100755
index 4686d140b..000000000
--- a/install/languages/en/sql/packages/search/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'search' AND `name` = 'search'), 'Search', NULL, NULL, NULL, NULL, NULL, NULL, '---\n- 0\n', NULL, '---\nshow_input: 1\nshow_btn: null\nshow_search_params: null\n', 'search', 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'right-top', 0);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/search/widgets_bind_demo_modern.sql b/install/languages/en/sql/packages/search/widgets_bind_demo_modern.sql
deleted file mode 100755
index a6326ee5f..000000000
--- a/install/languages/en/sql/packages/search/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'search' AND `name` = 'search'), '{solid%search} Search', NULL, NULL, NULL, NULL, 1, NULL, '---\n', NULL, '---\nshow_input: 1\nshow_btn: null\nshow_search_params: null\n', 'search', 'wrapper', 'icms-widget__transparent', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_9', 1);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/subscriptions/activity/base.sql b/install/languages/en/sql/packages/subscriptions/activity/base.sql
deleted file mode 100755
index 4de738892..000000000
--- a/install/languages/en/sql/packages/subscriptions/activity/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(1, 'subscriptions', 'subscribe', 'Subscription to content', 'subscribes to the %s list');
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/tags/photos/base_demo_default.sql b/install/languages/en/sql/packages/tags/photos/base_demo_default.sql
deleted file mode 100755
index b40a648bb..000000000
--- a/install/languages/en/sql/packages/tags/photos/base_demo_default.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-INSERT INTO `{#}tags` (`tag`, `frequency`) VALUES
-('photo', 1);
-SET @albums_tag_id = LAST_INSERT_ID();
-
-INSERT INTO `{#}tags_bind` (`tag_id`, `target_controller`, `target_subject`, `target_id`) VALUES
-(43, 'content', 'albums', 16),
-(@albums_tag_id, 'content', 'albums', 16);
-
-UPDATE `{#}tags` SET `frequency` = 6 WHERE `id` = 43;
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/tags/photos/base_demo_modern.sql b/install/languages/en/sql/packages/tags/photos/base_demo_modern.sql
deleted file mode 100755
index b40a648bb..000000000
--- a/install/languages/en/sql/packages/tags/photos/base_demo_modern.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-INSERT INTO `{#}tags` (`tag`, `frequency`) VALUES
-('photo', 1);
-SET @albums_tag_id = LAST_INSERT_ID();
-
-INSERT INTO `{#}tags_bind` (`tag_id`, `target_controller`, `target_subject`, `target_id`) VALUES
-(43, 'content', 'albums', 16),
-(@albums_tag_id, 'content', 'albums', 16);
-
-UPDATE `{#}tags` SET `frequency` = 6 WHERE `id` = 43;
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/tags/widgets_bind_demo_default.sql b/install/languages/en/sql/packages/tags/widgets_bind_demo_default.sql
deleted file mode 100755
index 368b793f1..000000000
--- a/install/languages/en/sql/packages/tags/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'tags' AND `name` = 'cloud'), 'Tag cloud', NULL, NULL, NULL, NULL, 1, NULL, '---\n- 0\n', NULL, '---\nordering: tag\nstyle: cloud\nmax_fs: 22\nmin_fs: 12\nlimit: 10\n', NULL, 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'right-bottom', 3);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/tags/widgets_bind_demo_modern.sql b/install/languages/en/sql/packages/tags/widgets_bind_demo_modern.sql
deleted file mode 100755
index a9b9e1415..000000000
--- a/install/languages/en/sql/packages/tags/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'tags' AND `name` = 'cloud'), 'Tag Cloud', NULL, NULL, NULL, NULL, 1, NULL, '---\n', NULL, '---\nsubjects:\n - 0\nordering: tag\nstyle: cloud\nmax_fs: 22\nmin_fs: 12\nmin_freq: 0\nmin_len: 0\nlimit: 10\ncolors: \'#008cba,#6610f2,#e83e8c,#f04124,#e99002,#43ac6a,#5bc0de\'\nshuffle: null\n', 'cloud', 'wrapper', 'icms-widget__compact', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_40', 0);
\ No newline at end of file
diff --git a/install/languages/en/sql/packages/csp/base.sql b/install/languages/en/sql/security/csp_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/csp/base.sql
rename to install/languages/en/sql/security/csp_base.sql
diff --git a/install/languages/en/sql/packages/recaptcha/base.sql b/install/languages/en/sql/security/recaptcha_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/recaptcha/base.sql
rename to install/languages/en/sql/security/recaptcha_base.sql
diff --git a/install/languages/en/sql/packages/redirect/base.sql b/install/languages/en/sql/seo/redirect_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/redirect/base.sql
rename to install/languages/en/sql/seo/redirect_base.sql
diff --git a/install/languages/en/sql/packages/activity/base.sql b/install/languages/en/sql/social/activity_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/activity/base.sql
rename to install/languages/en/sql/social/activity_base.sql
diff --git a/install/languages/en/sql/packages/activity/base_demo_default.sql b/install/languages/en/sql/social/activity_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/activity/base_demo_default.sql
rename to install/languages/en/sql/social/activity_demo_default.sql
diff --git a/install/languages/en/sql/packages/activity/base_demo_modern.sql b/install/languages/en/sql/social/activity_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/activity/base_demo_modern.sql
rename to install/languages/en/sql/social/activity_demo_modern.sql
diff --git a/install/languages/en/sql/packages/comments/base.sql b/install/languages/en/sql/social/comments_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/comments/base.sql
rename to install/languages/en/sql/social/comments_base.sql
diff --git a/install/languages/en/sql/packages/comments/base_demo_default.sql b/install/languages/en/sql/social/comments_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/comments/base_demo_default.sql
rename to install/languages/en/sql/social/comments_demo_default.sql
diff --git a/install/languages/en/sql/packages/comments/base_demo_modern.sql b/install/languages/en/sql/social/comments_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/comments/base_demo_modern.sql
rename to install/languages/en/sql/social/comments_demo_modern.sql
diff --git a/install/languages/en/sql/packages/groups/base.sql b/install/languages/en/sql/social/groups_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/groups/base.sql
rename to install/languages/en/sql/social/groups_base.sql
diff --git a/install/languages/en/sql/packages/groups/base_demo_default.sql b/install/languages/en/sql/social/groups_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/groups/base_demo_default.sql
rename to install/languages/en/sql/social/groups_demo_default.sql
diff --git a/install/languages/en/sql/packages/groups/base_demo_modern.sql b/install/languages/en/sql/social/groups_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/groups/base_demo_modern.sql
rename to install/languages/en/sql/social/groups_demo_modern.sql
diff --git a/install/languages/en/sql/packages/rating/base.sql b/install/languages/en/sql/social/rating_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/rating/base.sql
rename to install/languages/en/sql/social/rating_base.sql
diff --git a/install/languages/en/sql/packages/rating/base_demo_default.sql b/install/languages/en/sql/social/rating_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/rating/base_demo_default.sql
rename to install/languages/en/sql/social/rating_demo_default.sql
diff --git a/install/languages/en/sql/packages/rating/base_demo_modern.sql b/install/languages/en/sql/social/rating_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/rating/base_demo_modern.sql
rename to install/languages/en/sql/social/rating_demo_modern.sql
diff --git a/install/languages/en/sql/packages/wall/base.sql b/install/languages/en/sql/social/wall_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/wall/base.sql
rename to install/languages/en/sql/social/wall_base.sql
diff --git a/install/languages/en/sql/packages/wall/base_demo_default.sql b/install/languages/en/sql/social/wall_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/wall/base_demo_default.sql
rename to install/languages/en/sql/social/wall_demo_default.sql
diff --git a/install/languages/en/sql/packages/wall/base_demo_modern.sql b/install/languages/en/sql/social/wall_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/wall/base_demo_modern.sql
rename to install/languages/en/sql/social/wall_demo_modern.sql
diff --git a/install/languages/en/sql/packages/forms/base.sql b/install/languages/en/sql/tools/forms_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/forms/base.sql
rename to install/languages/en/sql/tools/forms_base.sql
diff --git a/install/languages/en/sql/packages/geo/base.sql b/install/languages/en/sql/tools/geo_base.sql
similarity index 100%
rename from install/languages/en/sql/packages/geo/base.sql
rename to install/languages/en/sql/tools/geo_base.sql
diff --git a/install/languages/en/sql/packages/geo/base_demo_default.sql b/install/languages/en/sql/tools/geo_demo_default.sql
similarity index 100%
rename from install/languages/en/sql/packages/geo/base_demo_default.sql
rename to install/languages/en/sql/tools/geo_demo_default.sql
diff --git a/install/languages/en/sql/packages/geo/base_demo_modern.sql b/install/languages/en/sql/tools/geo_demo_modern.sql
similarity index 100%
rename from install/languages/en/sql/packages/geo/base_demo_modern.sql
rename to install/languages/en/sql/tools/geo_demo_modern.sql
diff --git a/install/languages/ru/language.php b/install/languages/ru/language.php
index d5f931a1d..93eb80d8c 100755
--- a/install/languages/ru/language.php
+++ b/install/languages/ru/language.php
@@ -3,6 +3,7 @@
define('LANG_PAGE_TITLE', 'Установка InstantCMS');
define('LANG_INSTALLATION_WIZARD', 'Мастер установки');
define('LANG_NEXT', 'Далее →');
+ define('LANG_BACK', '← Назад');
define('LANG_ERROR', 'Ошибка');
define('LANG_FROM', 'от');
define('LANG_DEPRECATED', 'Устаревшее');
@@ -161,3 +162,82 @@
define('LANG_RB_SUCCES_ARCH', 'Архивирование завершено. Файл находится по пути %s');
define('LANG_RB_DONE', 'Кастомизация успешно завершена.');
define('LANG_RB_DONE_HINT', 'Можете приступать к установке InstantCMS.');
+
+// =============================================================================
+// Типы установки и компоненты
+// =============================================================================
+
+ define('LANG_INSTALL_TYPE', 'Тип установки');
+ define('LANG_INSTALL_MINIMAL', 'Минимальная');
+ define('LANG_INSTALL_MINIMAL_DESC', 'Только базовые функции. Подходит для разработки или если нужны только страницы.');
+ define('LANG_INSTALL_STANDARD', 'Стандартная');
+ define('LANG_INSTALL_STANDARD_DESC', 'Социальные функции, поиск, теги. Рекомендуется для большинства сайтов.');
+ define('LANG_INSTALL_FULL', 'Полная');
+ define('LANG_INSTALL_FULL_DESC', 'Все доступные компоненты системы.');
+ define('LANG_INSTALL_CUSTOM', 'Своя');
+ define('LANG_INSTALL_CUSTOM_DESC', 'Выберите компоненты самостоятельно.');
+ define('LANG_INSTALL_DEMO_CONTENT', 'Установить демо-контент');
+
+ define('LANG_CAT_SOCIAL', 'Социальные');
+ define('LANG_CAT_CONTENT', 'Контент');
+ define('LANG_CAT_MEDIA', 'Медиа');
+ define('LANG_CAT_TOOLS', 'Инструменты');
+ define('LANG_CAT_SECURITY', 'Безопасность');
+ define('LANG_CAT_MONETIZATION', 'Монетизация');
+ define('LANG_CAT_SEO', 'SEO');
+ define('LANG_CAT_NOTIFICATIONS', 'Уведомления');
+
+ define('LANG_COMMENTS', 'Комментарии');
+ define('LANG_COMMENTS_DESC', 'Система комментариев для записей контента');
+ define('LANG_RATING', 'Рейтинг');
+ define('LANG_RATING_DESC', 'Система голосования за контент');
+ define('LANG_ACTIVITY', 'Лента активности');
+ define('LANG_ACTIVITY_DESC', 'Лента событий пользователя и друзей');
+ define('LANG_WALL', 'Стена');
+ define('LANG_WALL_DESC', 'Стена в профилях пользователей');
+ define('LANG_GROUPS', 'Группы');
+ define('LANG_GROUPS_DESC', 'Группы пользователей');
+ define('LANG_TAGS', 'Теги');
+ define('LANG_TAGS_DESC', 'Теги для контента');
+ define('LANG_SEARCH', 'Поиск');
+ define('LANG_SEARCH_DESC', 'Полнотекстовый поиск по сайту');
+ define('LANG_SITEMAP', 'Карта сайта');
+ define('LANG_SITEMAP_DESC', 'Генерация XML-карты сайта');
+ define('LANG_RSS', 'RSS');
+ define('LANG_RSS_DESC', 'RSS-ленты для контента');
+ define('LANG_PHOTOS', 'Фотогалерея');
+ define('LANG_PHOTOS_DESC', 'Галерея изображений');
+ define('LANG_FORMS', 'Конструктор форм');
+ define('LANG_FORMS_DESC', 'Создание собственных форм');
+ define('LANG_GEO', 'Геолокация');
+ define('LANG_GEO_DESC', 'Определение местоположения пользователей');
+ define('LANG_RECAPTCHA', 'reCAPTCHA');
+ define('LANG_RECAPTCHA_DESC', 'Google reCAPTCHA защита от спама');
+ define('LANG_CSP', 'CSP');
+ define('LANG_CSP_DESC', 'Content Security Policy защита');
+ define('LANG_BILLING', 'Биллинг');
+ define('LANG_BILLING_DESC', 'Платёжная система для сайта');
+ define('LANG_REDIRECT', 'Редиректы');
+ define('LANG_REDIRECT_DESC', 'Управление перенаправлениями URL');
+ define('LANG_SUBSCRIPTIONS', 'Подписки');
+ define('LANG_SUBSCRIPTIONS_DESC', 'Подписки на обновления контента');
+
+ define('LANG_STEP_COMPONENTS', 'Выбор компонентов');
+ define('LANG_STEP_COMPONENTS_HINT', 'Выберите тип установки или укажите компоненты вручную');
+ define('LANG_MANDATORY', 'обязательный');
+ define('LANG_REQUIRES', 'Требует');
+ define('LANG_COMPONENT_REQUIRES', 'Компонент "%s" требует наличия компонента "%s"');
+ define('LANG_CUSTOM_COMPONENTS', 'Выбор компонентов');
+ define('LANG_CUSTOM_COMPONENTS_HINT', 'Отметьте компоненты для установки. Обязательные компоненты уже отмечены и не могут быть отключены.');
+
+ define('LANG_STEP_CLEANUP', 'Очистка');
+ define('LANG_CLEANUP_INFO', 'Выберите файлы для удаления. Это освободит место на диске.');
+ define('LANG_CLEANUP_NOTHING', 'Нечего удалять. Все установленные компоненты присутствуют.');
+ define('LANG_CLEANUP_TOTAL', 'Всего к удалению');
+ define('LANG_CLEANUP_SELECT', 'Выберите что удалить');
+ define('LANG_CLEANUP_TYPE_COMPONENT', 'компонент');
+ define('LANG_CLEANUP_REMOVED', 'Удалено');
+ define('LANG_CLEANUP_ERRORS', 'Ошибки при удалении');
+ define('LANG_CLEANUP_COMPLETE', 'Очистка завершена');
+ define('LANG_SELECT_ALL', 'Выбрать все');
+ define('LANG_DESELECT_ALL', 'Снять выбор');
diff --git a/install/languages/ru/sql/packages/rss/base.sql b/install/languages/ru/sql/content/rss_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/rss/base.sql
rename to install/languages/ru/sql/content/rss_base.sql
diff --git a/install/languages/ru/sql/packages/rss/base_demo_default.sql b/install/languages/ru/sql/content/rss_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/rss/base_demo_default.sql
rename to install/languages/ru/sql/content/rss_demo_default.sql
diff --git a/install/languages/ru/sql/packages/rss/base_demo_modern.sql b/install/languages/ru/sql/content/rss_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/rss/base_demo_modern.sql
rename to install/languages/ru/sql/content/rss_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/search/base.sql b/install/languages/ru/sql/content/search_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/search/base.sql
rename to install/languages/ru/sql/content/search_base.sql
diff --git a/install/languages/ru/sql/packages/sitemap/base.sql b/install/languages/ru/sql/content/sitemap_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/sitemap/base.sql
rename to install/languages/ru/sql/content/sitemap_base.sql
diff --git a/install/languages/ru/sql/packages/tags/base.sql b/install/languages/ru/sql/content/tags_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/tags/base.sql
rename to install/languages/ru/sql/content/tags_base.sql
diff --git a/install/languages/ru/sql/packages/tags/base_demo_default.sql b/install/languages/ru/sql/content/tags_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/tags/base_demo_default.sql
rename to install/languages/ru/sql/content/tags_demo_default.sql
diff --git a/install/languages/ru/sql/packages/tags/base_demo_modern.sql b/install/languages/ru/sql/content/tags_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/tags/base_demo_modern.sql
rename to install/languages/ru/sql/content/tags_demo_modern.sql
diff --git a/install/languages/ru/sql/base_demo_modern.sql b/install/languages/ru/sql/core/full_demo.sql
similarity index 100%
rename from install/languages/ru/sql/base_demo_modern.sql
rename to install/languages/ru/sql/core/full_demo.sql
diff --git a/install/languages/ru/sql/base_demo_default.sql b/install/languages/ru/sql/core/standard_demo.sql
similarity index 100%
rename from install/languages/ru/sql/base_demo_default.sql
rename to install/languages/ru/sql/core/standard_demo.sql
diff --git a/install/languages/ru/sql/widgets_bind_default.sql b/install/languages/ru/sql/core/widgets_default.sql
similarity index 100%
rename from install/languages/ru/sql/widgets_bind_default.sql
rename to install/languages/ru/sql/core/widgets_default.sql
diff --git a/install/languages/ru/sql/widgets_bind_demo_default.sql b/install/languages/ru/sql/core/widgets_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/widgets_bind_demo_default.sql
rename to install/languages/ru/sql/core/widgets_demo_default.sql
diff --git a/install/languages/ru/sql/widgets_bind_demo_modern.sql b/install/languages/ru/sql/core/widgets_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/widgets_bind_demo_modern.sql
rename to install/languages/ru/sql/core/widgets_demo_modern.sql
diff --git a/install/languages/ru/sql/widgets_bind_modern.sql b/install/languages/ru/sql/core/widgets_modern.sql
similarity index 100%
rename from install/languages/ru/sql/widgets_bind_modern.sql
rename to install/languages/ru/sql/core/widgets_modern.sql
diff --git a/install/languages/ru/sql/packages/photos/base.sql b/install/languages/ru/sql/media/photos_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/photos/base.sql
rename to install/languages/ru/sql/media/photos_base.sql
diff --git a/install/languages/ru/sql/packages/photos/base_demo_default.sql b/install/languages/ru/sql/media/photos_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/photos/base_demo_default.sql
rename to install/languages/ru/sql/media/photos_demo_default.sql
diff --git a/install/languages/ru/sql/packages/photos/base_demo_modern.sql b/install/languages/ru/sql/media/photos_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/photos/base_demo_modern.sql
rename to install/languages/ru/sql/media/photos_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/billing/base.sql b/install/languages/ru/sql/monetization/billing_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/billing/base.sql
rename to install/languages/ru/sql/monetization/billing_base.sql
diff --git a/install/languages/ru/sql/packages/billing/base_demo_default.sql b/install/languages/ru/sql/monetization/billing_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/billing/base_demo_default.sql
rename to install/languages/ru/sql/monetization/billing_demo_default.sql
diff --git a/install/languages/ru/sql/packages/billing/base_demo_modern.sql b/install/languages/ru/sql/monetization/billing_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/billing/base_demo_modern.sql
rename to install/languages/ru/sql/monetization/billing_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/subscriptions/base.sql b/install/languages/ru/sql/notifications/subscriptions_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/subscriptions/base.sql
rename to install/languages/ru/sql/notifications/subscriptions_base.sql
diff --git a/install/languages/ru/sql/packages/activity/widgets_bind_demo_default.sql b/install/languages/ru/sql/packages/activity/widgets_bind_demo_default.sql
deleted file mode 100755
index 1e4593384..000000000
--- a/install/languages/ru/sql/packages/activity/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'activity' AND `name` = 'list'), 'Активность', 'Вся | activity\r\n{Моих друзей | activity/index/friends}\r\n{Моя | activity/index/my}', NULL, NULL, NULL, 1, NULL, '---\n- 0\n', NULL, '---\ndataset: all\nshow_avatars: 1\ndate_group: null\nlimit: 5\n', NULL, 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'left-bottom', 3);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/activity/widgets_bind_demo_modern.sql b/install/languages/ru/sql/packages/activity/widgets_bind_demo_modern.sql
deleted file mode 100755
index b06198273..000000000
--- a/install/languages/ru/sql/packages/activity/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'activity' AND `name` = 'list'), 'Активность', 'Вся | activity', NULL, NULL, NULL, 1, NULL, '---\n', NULL, '---\ndataset: all\nshow_avatars: 1\ndate_group: null\nlimit: 8\n', 'list', 'wrapper', 'icms-widget__transparent', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_8', 5);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/billing/photos/base.sql b/install/languages/ru/sql/packages/billing/photos/base.sql
deleted file mode 100755
index e55a45f0d..000000000
--- a/install/languages/ru/sql/packages/billing/photos/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}billing_actions` (`controller`, `name`, `title`, `prices`) VALUES
-('content', 'albums_add', 'Фотоальбомы: добавление', '---\n3: 0\n4: 0\n5: 0\n6: 0\n');
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/comments/activity/base.sql b/install/languages/ru/sql/packages/comments/activity/base.sql
deleted file mode 100755
index eff970de5..000000000
--- a/install/languages/ru/sql/packages/comments/activity/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(1, 'comments', 'vote.comment', 'Оценка комментария', 'оценил комментарий на странице %s');
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/comments/rss/base.sql b/install/languages/ru/sql/packages/comments/rss/base.sql
deleted file mode 100755
index 099b91d1f..000000000
--- a/install/languages/ru/sql/packages/comments/rss/base.sql
+++ /dev/null
@@ -1 +0,0 @@
-INSERT INTO `{#}rss_feeds` (`ctype_id`, `ctype_name`, `title`, `description`, `image`, `mapping`, `limit`, `is_enabled`, `is_cache`, `cache_interval`, `date_cached`) VALUES (NULL, 'comments', 'Комментарии', NULL, NULL, '---\r\ntitle: target_title\r\ndescription: content_html\r\npubDate: date_pub\r\n', 15, 1, NULL, 60, NULL);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/comments/widgets_bind_demo_default.sql b/install/languages/ru/sql/packages/comments/widgets_bind_demo_default.sql
deleted file mode 100755
index e04e35eca..000000000
--- a/install/languages/ru/sql/packages/comments/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'comments' AND `name` = 'list'), 'Комментарии', 'Все | comments\r\n{Моих друзей | comments/index/friends}\r\n{Мои | comments/index/my}', NULL, NULL, NULL, 1, 1, '---\n- 0\n', NULL, '---\nshow_avatars: 1\nshow_text: 1\nlimit: 10\n', NULL, 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'left-bottom', 4);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/comments/widgets_bind_demo_modern.sql b/install/languages/ru/sql/packages/comments/widgets_bind_demo_modern.sql
deleted file mode 100755
index 61910cec8..000000000
--- a/install/languages/ru/sql/packages/comments/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'comments' AND `name` = 'list'), 'Комментарии', 'Все | comments', NULL, NULL, NULL, 1, 1, '---\n', NULL, '---\nshow_list:\n - 0\nshow_avatars: 1\nshow_text: 1\nlimit: 10\n', 'list', 'wrapper', NULL, NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_8', 6);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/groups/activity/base.sql b/install/languages/ru/sql/packages/groups/activity/base.sql
deleted file mode 100755
index 3bafb3df1..000000000
--- a/install/languages/ru/sql/packages/groups/activity/base.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(1, 'groups', 'join', 'Вступление в группу', 'вступает в группу %s'),
-(1, 'groups', 'leave', 'Выход из группы', 'выходит из группы %s');
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/photos/activity/base.sql b/install/languages/ru/sql/packages/photos/activity/base.sql
deleted file mode 100755
index d39002dc4..000000000
--- a/install/languages/ru/sql/packages/photos/activity/base.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(0, 'content', 'add.albums', 'Добавление альбомов', 'добавляет фотоальбом %s'),
-(1, 'photos', 'add.photos', 'Добавление фотографий', 'загружает фото в альбом %s');
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/photos/rss/base.sql b/install/languages/ru/sql/packages/photos/rss/base.sql
deleted file mode 100755
index 343e63381..000000000
--- a/install/languages/ru/sql/packages/photos/rss/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}rss_feeds` (`ctype_id`, `ctype_name`, `title`, `description`, `image`, `mapping`, `limit`, `is_enabled`, `is_cache`, `cache_interval`, `date_cached`) VALUES
-(7, 'albums', 'Фотоальбомы', NULL, NULL, '---\ntitle: title\ndescription: content\npubDate: date_pub\nimage: cover_image\nimage_size: normal\n', 15, 1, NULL, 60, NULL);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/photos/widgets_bind_demo_default.sql b/install/languages/ru/sql/packages/photos/widgets_bind_demo_default.sql
deleted file mode 100755
index 439ac0d7b..000000000
--- a/install/languages/ru/sql/packages/photos/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'content' AND `name` = 'list'), 'Фотоальбомы', 'Все альбомы | albums\r\n{Загрузить фото | photos/upload}', NULL, NULL, NULL, 1, 1, '---\n- 0\n', NULL, '---\nctype_id: 7\ndataset:\nimage_field: cover_image\nteaser_field:\nshow_details: null\nlimit: 5\n', 'list_tiles_big', 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'left-bottom', 2);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/photos/widgets_bind_demo_modern.sql b/install/languages/ru/sql/packages/photos/widgets_bind_demo_modern.sql
deleted file mode 100755
index 854da62cf..000000000
--- a/install/languages/ru/sql/packages/photos/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'photos' AND `name` = 'list'), 'Фото', 'Все альбомы | albums\r\n{Загрузить фото | photos/upload}', NULL, NULL, NULL, 1, 1, '---\n', NULL, '---\nauto_user: null\nauto_group: null\nauto_ctype_item: null\ntarget: 0\nalbum_id:\nordering:\norientation:\ntype:\nwidth:\nheight:\nlimit: 10\n', 'list', 'wrapper', 'icms-widget__transparent', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_8', 4);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/search/widgets_bind_demo_default.sql b/install/languages/ru/sql/packages/search/widgets_bind_demo_default.sql
deleted file mode 100755
index 5b5cce3e7..000000000
--- a/install/languages/ru/sql/packages/search/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'search' AND `name` = 'search'), 'Поиск', NULL, NULL, NULL, NULL, NULL, NULL, '---\n- 0\n', NULL, '---\nshow_input: 1\nshow_btn: null\nshow_search_params: null\n', 'search', 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'right-top', 0);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/search/widgets_bind_demo_modern.sql b/install/languages/ru/sql/packages/search/widgets_bind_demo_modern.sql
deleted file mode 100755
index 3ee87aa65..000000000
--- a/install/languages/ru/sql/packages/search/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'search' AND `name` = 'search'), '{solid%search} Поиск', NULL, NULL, NULL, NULL, 1, NULL, '---\n', NULL, '---\nshow_input: 1\nshow_btn: null\nshow_search_params: null\n', 'search', 'wrapper', 'icms-widget__transparent', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_9', 1);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/subscriptions/activity/base.sql b/install/languages/ru/sql/packages/subscriptions/activity/base.sql
deleted file mode 100755
index 97bfc775d..000000000
--- a/install/languages/ru/sql/packages/subscriptions/activity/base.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO `{#}activity_types` (`is_enabled`, `controller`, `name`, `title`, `description`) VALUES
-(1, 'subscriptions', 'subscribe', 'Подписка на контент', 'подписывается на список %s');
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/tags/photos/base_demo_default.sql b/install/languages/ru/sql/packages/tags/photos/base_demo_default.sql
deleted file mode 100755
index f7ca2d6de..000000000
--- a/install/languages/ru/sql/packages/tags/photos/base_demo_default.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-INSERT INTO `{#}tags` (`tag`, `frequency`) VALUES
-('фото', 1);
-SET @albums_tag_id = LAST_INSERT_ID();
-
-INSERT INTO `{#}tags_bind` (`tag_id`, `target_controller`, `target_subject`, `target_id`) VALUES
-(1, 'content', 'albums', 16),
-(@albums_tag_id, 'content', 'albums', 16);
-
-UPDATE `{#}tags` SET `frequency` = 6 WHERE `id` = 1;
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/tags/photos/base_demo_modern.sql b/install/languages/ru/sql/packages/tags/photos/base_demo_modern.sql
deleted file mode 100755
index f7ca2d6de..000000000
--- a/install/languages/ru/sql/packages/tags/photos/base_demo_modern.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-INSERT INTO `{#}tags` (`tag`, `frequency`) VALUES
-('фото', 1);
-SET @albums_tag_id = LAST_INSERT_ID();
-
-INSERT INTO `{#}tags_bind` (`tag_id`, `target_controller`, `target_subject`, `target_id`) VALUES
-(1, 'content', 'albums', 16),
-(@albums_tag_id, 'content', 'albums', 16);
-
-UPDATE `{#}tags` SET `frequency` = 6 WHERE `id` = 1;
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/tags/widgets_bind_demo_default.sql b/install/languages/ru/sql/packages/tags/widgets_bind_demo_default.sql
deleted file mode 100755
index f1c685481..000000000
--- a/install/languages/ru/sql/packages/tags/widgets_bind_demo_default.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `device_types`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'tags' AND `name` = 'cloud'), 'Облако тегов', NULL, NULL, NULL, NULL, 1, NULL, '---\n- 0\n', NULL, '---\nordering: tag\nstyle: cloud\nmax_fs: 22\nmin_fs: 12\nlimit: 10\n', NULL, 'wrapper', NULL);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'default', 1, 1, 'right-bottom', 3);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/tags/widgets_bind_demo_modern.sql b/install/languages/ru/sql/packages/tags/widgets_bind_demo_modern.sql
deleted file mode 100755
index 5d8124188..000000000
--- a/install/languages/ru/sql/packages/tags/widgets_bind_demo_modern.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO `{#}widgets_bind` (`template_layouts`, `languages`, `widget_id`, `title`, `links`, `class`, `class_title`, `class_wrap`, `is_title`, `is_tab_prev`, `groups_view`, `groups_hide`, `options`, `tpl_body`, `tpl_wrap`, `tpl_wrap_style`, `device_types`, `is_cacheable`) VALUES
-(NULL, NULL, (SELECT id FROM `{#}widgets` WHERE `controller` = 'tags' AND `name` = 'cloud'), 'Облако тегов', NULL, NULL, NULL, NULL, 1, NULL, '---\n', NULL, '---\nsubjects:\n - 0\nordering: tag\nstyle: cloud\nmax_fs: 22\nmin_fs: 12\nmin_freq: 0\nmin_len: 0\nlimit: 10\ncolors: \'#008cba,#6610f2,#e83e8c,#f04124,#e99002,#43ac6a,#5bc0de\'\nshuffle: null\n', 'cloud', 'wrapper', 'icms-widget__compact', NULL, 1);
-
-INSERT INTO `{#}widgets_bind_pages` (`bind_id`, `template`, `is_enabled`, `page_id`, `position`, `ordering`) VALUES
-((SELECT LAST_INSERT_ID()), 'modern', 1, 1, 'pos_40', 0);
\ No newline at end of file
diff --git a/install/languages/ru/sql/packages/csp/base.sql b/install/languages/ru/sql/security/csp_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/csp/base.sql
rename to install/languages/ru/sql/security/csp_base.sql
diff --git a/install/languages/ru/sql/packages/recaptcha/base.sql b/install/languages/ru/sql/security/recaptcha_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/recaptcha/base.sql
rename to install/languages/ru/sql/security/recaptcha_base.sql
diff --git a/install/languages/ru/sql/packages/redirect/base.sql b/install/languages/ru/sql/seo/redirect_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/redirect/base.sql
rename to install/languages/ru/sql/seo/redirect_base.sql
diff --git a/install/languages/ru/sql/packages/activity/base.sql b/install/languages/ru/sql/social/activity_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/activity/base.sql
rename to install/languages/ru/sql/social/activity_base.sql
diff --git a/install/languages/ru/sql/packages/activity/base_demo_default.sql b/install/languages/ru/sql/social/activity_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/activity/base_demo_default.sql
rename to install/languages/ru/sql/social/activity_demo_default.sql
diff --git a/install/languages/ru/sql/packages/activity/base_demo_modern.sql b/install/languages/ru/sql/social/activity_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/activity/base_demo_modern.sql
rename to install/languages/ru/sql/social/activity_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/comments/base.sql b/install/languages/ru/sql/social/comments_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/comments/base.sql
rename to install/languages/ru/sql/social/comments_base.sql
diff --git a/install/languages/ru/sql/packages/comments/base_demo_default.sql b/install/languages/ru/sql/social/comments_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/comments/base_demo_default.sql
rename to install/languages/ru/sql/social/comments_demo_default.sql
diff --git a/install/languages/ru/sql/packages/comments/base_demo_modern.sql b/install/languages/ru/sql/social/comments_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/comments/base_demo_modern.sql
rename to install/languages/ru/sql/social/comments_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/groups/base.sql b/install/languages/ru/sql/social/groups_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/groups/base.sql
rename to install/languages/ru/sql/social/groups_base.sql
diff --git a/install/languages/ru/sql/packages/groups/base_demo_default.sql b/install/languages/ru/sql/social/groups_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/groups/base_demo_default.sql
rename to install/languages/ru/sql/social/groups_demo_default.sql
diff --git a/install/languages/ru/sql/packages/groups/base_demo_modern.sql b/install/languages/ru/sql/social/groups_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/groups/base_demo_modern.sql
rename to install/languages/ru/sql/social/groups_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/rating/base.sql b/install/languages/ru/sql/social/rating_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/rating/base.sql
rename to install/languages/ru/sql/social/rating_base.sql
diff --git a/install/languages/ru/sql/packages/rating/base_demo_default.sql b/install/languages/ru/sql/social/rating_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/rating/base_demo_default.sql
rename to install/languages/ru/sql/social/rating_demo_default.sql
diff --git a/install/languages/ru/sql/packages/rating/base_demo_modern.sql b/install/languages/ru/sql/social/rating_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/rating/base_demo_modern.sql
rename to install/languages/ru/sql/social/rating_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/wall/base.sql b/install/languages/ru/sql/social/wall_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/wall/base.sql
rename to install/languages/ru/sql/social/wall_base.sql
diff --git a/install/languages/ru/sql/packages/wall/base_demo_default.sql b/install/languages/ru/sql/social/wall_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/wall/base_demo_default.sql
rename to install/languages/ru/sql/social/wall_demo_default.sql
diff --git a/install/languages/ru/sql/packages/wall/base_demo_modern.sql b/install/languages/ru/sql/social/wall_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/wall/base_demo_modern.sql
rename to install/languages/ru/sql/social/wall_demo_modern.sql
diff --git a/install/languages/ru/sql/packages/forms/base.sql b/install/languages/ru/sql/tools/forms_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/forms/base.sql
rename to install/languages/ru/sql/tools/forms_base.sql
diff --git a/install/languages/ru/sql/packages/geo/base.sql b/install/languages/ru/sql/tools/geo_base.sql
similarity index 100%
rename from install/languages/ru/sql/packages/geo/base.sql
rename to install/languages/ru/sql/tools/geo_base.sql
diff --git a/install/languages/ru/sql/packages/geo/base_demo_default.sql b/install/languages/ru/sql/tools/geo_demo_default.sql
similarity index 100%
rename from install/languages/ru/sql/packages/geo/base_demo_default.sql
rename to install/languages/ru/sql/tools/geo_demo_default.sql
diff --git a/install/languages/ru/sql/packages/geo/base_demo_modern.sql b/install/languages/ru/sql/tools/geo_demo_modern.sql
similarity index 100%
rename from install/languages/ru/sql/packages/geo/base_demo_modern.sql
rename to install/languages/ru/sql/tools/geo_demo_modern.sql
diff --git a/install/steps/cleanup.php b/install/steps/cleanup.php
new file mode 100644
index 000000000..ac9cfcf90
--- /dev/null
+++ b/install/steps/cleanup.php
@@ -0,0 +1,151 @@
+ render('step_cleanup', [
+ 'cleanup_items' => $data['items'],
+ 'total_size' => $data['total_size']
+ ])
+ ];
+}
+
+function get_cleanup_list() {
+
+ $items = [];
+ $total_size = 0;
+
+ $installed = $_SESSION['install']['components'] ?? [];
+ $data = include PATH . 'data/components.php';
+
+ $mandatory = $data['mandatory'];
+
+ $all_components = [];
+ foreach ($data['categories'] as $cat) {
+ $all_components = array_merge($all_components, array_keys($cat['components']));
+ }
+
+ $not_installed = array_diff($all_components, $installed);
+
+ $controllers_path = dirname(PATH) . '/system/controllers/';
+ if (is_dir($controllers_path)) {
+ $dirs = scandir($controllers_path);
+ foreach ($dirs as $dir) {
+ if ($dir === '.' || $dir === '..') continue;
+ if (in_array($dir, $mandatory)) continue;
+ if (in_array($dir, $installed)) continue;
+ if (in_array($dir, $not_installed)) {
+ $path = $controllers_path . $dir;
+ $size = get_dir_size($path);
+ $items[] = [
+ 'type' => 'component',
+ 'name' => $dir,
+ 'path' => $path,
+ 'size' => $size,
+ 'title' => constant($data['categories'][get_component_category($dir, $data)]['components'][$dir]['title'] ?? 'LANG_' . strtoupper($dir))
+ ];
+ $total_size += $size;
+ }
+ }
+ }
+
+ return [
+ 'items' => $items,
+ 'total_size' => $total_size
+ ];
+}
+
+function get_component_category($component, $data) {
+ foreach ($data['categories'] as $cat_id => $cat) {
+ if (isset($cat['components'][$component])) {
+ return $cat_id;
+ }
+ }
+ return null;
+}
+
+function get_dir_size($dir) {
+ $size = 0;
+ if (is_dir($dir)) {
+ $files = new RecursiveIteratorIterator(
+ new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
+ RecursiveIteratorIterator::CHILD_FIRST
+ );
+ foreach ($files as $file) {
+ if ($file->isFile()) {
+ $size += $file->getSize();
+ }
+ }
+ }
+ return $size;
+}
+
+function do_cleanup() {
+
+ $remove_components = get_post_array('remove_components');
+
+ $errors = [];
+ $removed = [];
+
+ foreach ($remove_components as $item) {
+ $path = urldecode($item);
+ if (is_dir($path)) {
+ if (files_remove_directory($path)) {
+ $removed[] = basename($path);
+ } else {
+ $errors[] = basename($path);
+ }
+ }
+ }
+
+ $message = '';
+ if ($removed) {
+ $message = LANG_CLEANUP_REMOVED . ': ' . implode(', ', $removed);
+ }
+ if ($errors) {
+ $message .= ($message ? "\n" : '') . LANG_CLEANUP_ERRORS . ': ' . implode(', ', $errors);
+ }
+
+ return [
+ 'error' => !empty($errors),
+ 'message' => $message ?: LANG_CLEANUP_COMPLETE
+ ];
+}
+
+function files_remove_directory($directory, $is_clear = false) {
+
+ if (!is_dir($directory)) {
+ return false;
+ }
+
+ if (!is_writable($directory)) {
+ @chmod($directory, 0755);
+ }
+
+ $items = array_diff(scandir($directory), ['.', '..']);
+
+ foreach ($items as $item) {
+ $path = $directory . DS . $item;
+ if (is_dir($path)) {
+ if (!files_remove_directory($path)) {
+ return false;
+ }
+ } else {
+ if (!@unlink($path)) {
+ return false;
+ }
+ }
+ }
+
+ if (!$is_clear) {
+ return @rmdir($directory);
+ }
+
+ return true;
+}
diff --git a/install/steps/components.php b/install/steps/components.php
new file mode 100644
index 000000000..5f9b6cee6
--- /dev/null
+++ b/install/steps/components.php
@@ -0,0 +1,94 @@
+ render('step_components', [
+ 'categories' => $data['categories'],
+ 'mandatory' => $data['mandatory'],
+ 'install_types' => $data['install_types'],
+ 'selected' => $selected,
+ 'install_type' => $install_type,
+ 'is_install_demo' => $is_install_demo
+ ])
+ ];
+}
+
+function check_components() {
+
+ $data = include PATH . 'data/components.php';
+
+ $install_type = strip_tags(get_post('install_type'));
+ $is_install_demo = (int) get_post('is_install_demo');
+
+ if (!isset($data['install_types'][$install_type])) {
+ $install_type = 'standard';
+ }
+
+ $type_data = $data['install_types'][$install_type];
+
+ if ($install_type === 'custom') {
+ $selected = get_post_array('components');
+ $selected = array_unique(array_merge($selected, $data['mandatory']));
+
+ $errors = validate_component_dependencies($selected, $data);
+
+ if ($errors) {
+ return [
+ 'error' => true,
+ 'message' => implode("\n", $errors)
+ ];
+ }
+ } else {
+ $selected = $type_data['components'];
+ }
+
+ $_SESSION['install']['site']['install_type'] = $install_type;
+ $_SESSION['install']['site']['is_install_demo'] = $is_install_demo;
+ $_SESSION['install']['components'] = $selected;
+
+ return [
+ 'error' => false
+ ];
+}
+
+function validate_component_dependencies($selected, $data) {
+
+ $errors = [];
+
+ foreach ($data['categories'] as $cat_id => $cat) {
+ foreach ($cat['components'] as $comp_id => $comp) {
+ if (in_array($comp_id, $selected) && !empty($comp['deps'])) {
+ foreach ($comp['deps'] as $dep) {
+ if (!in_array($dep, $selected)) {
+ $dep_title = constant($dep);
+ foreach ($data['categories'] as $dc => $dcat) {
+ if (isset($dcat['components'][$dep])) {
+ $dep_title = constant($dcat['components'][$dep]['title']);
+ break;
+ }
+ }
+ $comp_title = constant($comp['title']);
+ $errors[] = sprintf(LANG_COMPONENT_REQUIRES, $comp_title, $dep_title);
+ }
+ }
+ }
+ }
+ }
+
+ return $errors;
+}
\ No newline at end of file
diff --git a/install/steps/database.php b/install/steps/database.php
index da2a07fa2..0c7aff2d7 100755
--- a/install/steps/database.php
+++ b/install/steps/database.php
@@ -134,7 +134,7 @@ function check_db() {
$success = true;
- // Основные дампы
+ // Основные дампы (base.sql и виджеты)
foreach ($dumps as $dump_name) {
if ($success === true) {
$success = import_dump(
@@ -149,49 +149,43 @@ function check_db() {
}
}
- // Импортируем дампы отдельных компонентов
- $packages_list = get_packages_sql_list();
-
- foreach ($packages_list as $controller_name) {
- foreach ($dumps as $dump_name) {
- if ($success === true) {
- $success = import_dump(
- $mysqli,
- 'packages' . DS . $controller_name . DS . $dump_name,
- $db['prefix'],
- $db['engine'],
- ';',
- $db['db_charset'],
- $db['innodb_full_text']
- );
- }
- }
+ // Импортируем демо контент если нужно
+ $install_type = $_SESSION['install']['site']['install_type'] ?? 'standard';
+ $is_install_demo = !empty($_SESSION['install']['site']['is_install_demo']);
+
+ if ($is_install_demo && $install_type !== 'minimal') {
+ $demo_file = ($install_type === 'full') ? 'core/full_demo.sql' : 'core/standard_demo.sql';
+ import_dump($mysqli, $demo_file, $db['prefix'], $db['engine'], ';', $db['db_charset'], $db['innodb_full_text']);
+
+ // Виджеты демо
+ $template = $_SESSION['install']['site']['template'];
+ import_dump($mysqli, "core/widgets_demo_{$template}.sql", $db['prefix'], $db['engine'], ';', $db['db_charset'], $db['innodb_full_text']);
}
- // Теперь импортируем дампы по зависимостям контроллеров
- $result = $mysqli->query("SELECT `name` FROM `{$db['prefix']}controllers`");
- $controllers = [];
- if (!$mysqli->errno) {
- while ($item = $result->fetch_assoc()) {
- $controllers[] = $item['name'];
+ // Импортируем базовые виджеты для шаблона
+ $template = $_SESSION['install']['site']['template'];
+ import_dump($mysqli, "core/widgets_{$template}.sql", $db['prefix'], $db['engine'], ';', $db['db_charset'], $db['innodb_full_text']);
+
+ // Получаем выбранные компоненты
+ $selected_components = $_SESSION['install']['components'] ?? [];
+ $data = include PATH . 'data/components.php';
+
+ // Импортируем SQL компонентов (только не mandatory)
+ $components_to_import = array_diff($selected_components, $data['mandatory']);
+ foreach ($components_to_import as $component) {
+ $sql_file = find_component_sql_file($component, 'base');
+ if ($sql_file) {
+ $success = import_dump($mysqli, $sql_file, $db['prefix'], $db['engine'], ';', $db['db_charset'], $db['innodb_full_text']);
+ if ($success !== true) { break; }
}
- $result->close();
}
- foreach ($packages_list as $controller_name) {
- foreach ($controllers as $rel_controller_name) {
- foreach ($dumps as $dump_name) {
- if ($success === true) {
- $success = import_dump(
- $mysqli,
- 'packages' . DS . $controller_name . DS . $rel_controller_name . DS. $dump_name,
- $db['prefix'],
- $db['engine'],
- ';',
- $db['db_charset'],
- $db['innodb_full_text']
- );
- }
+ // Импортируем демо выбранных компонентов
+ if ($is_install_demo && $install_type !== 'minimal') {
+ foreach ($components_to_import as $component) {
+ $demo_file = find_component_sql_file($component, 'demo');
+ if ($demo_file) {
+ import_dump($mysqli, $demo_file, $db['prefix'], $db['engine'], ';', $db['db_charset'], $db['innodb_full_text']);
}
}
}
@@ -260,17 +254,8 @@ function get_sql_file_names($is_install_demo_content = false) {
$dumps = [
// Основной дамп
'base.sql',
- // Базовые виджеты для шаблона
- 'widgets_bind_' . $_SESSION['install']['site']['template'] . '.sql',
];
- if ($is_install_demo_content) {
- // Демо данные
- $dumps[] = 'base_demo_' . $_SESSION['install']['site']['template'] . '.sql';
- // Демо виджеты для шаблона
- $dumps[] = 'widgets_bind_demo_' . $_SESSION['install']['site']['template'] . '.sql';
- }
-
return $dumps;
}
diff --git a/install/templates/step_cleanup.php b/install/templates/step_cleanup.php
new file mode 100644
index 000000000..b370f19e2
--- /dev/null
+++ b/install/templates/step_cleanup.php
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+ >
+
+
+
diff --git a/install/templates/step_components.php b/install/templates/step_components.php
new file mode 100644
index 000000000..b003dc8e7
--- /dev/null
+++ b/install/templates/step_components.php
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/install/templates/step_database.php b/install/templates/step_database.php
index c923b9625..3d057654a 100755
--- a/install/templates/step_database.php
+++ b/install/templates/step_database.php
@@ -80,13 +80,6 @@
-
-
-
-
diff --git a/install/templates/step_site.php b/install/templates/step_site.php
index 444706ad3..c12cae440 100755
--- a/install/templates/step_site.php
+++ b/install/templates/step_site.php
@@ -49,4 +49,5 @@
-
\ No newline at end of file
+
+