Imagine: your online store on OpenCart lags with 10,000 products, and the integration with 1C hasn't worked for a month. You decide to migrate to 1C-Bitrix. But migration is not copying files. Data structures are fundamentally different: in OpenCart products are stored in oc_product, oc_product_attribute, oc_product_option, while in Bitrix — in b_iblock_element and property tables of information blocks. If you simply copy an SQL dump, you'll get broken URLs, lost orders, and traffic drop. Over 7 years we have performed more than 80 migrations to Bitrix without a single failure. We preserve SEO and customer data. Guarantee stable operation after launch. Migration through our ETL pipeline saves up to 40% of the budget compared to rewriting the site from scratch.
For example, in one project we migrated a catalog of 25,000 products from OpenCart to Bitrix in 4 weeks. We used streaming upload via CIBlockElement::Add with batches of 500 elements. This avoided timeouts and preserved data without loss. Before migration we conduct an audit: check DB structure, encodings, data volume. Then we write ETL scripts in PHP 8.1 using Composer and our own migration framework.
What needs to be audited before migration?
The first step is inventory of what needs to be transferred. Errors at this stage lead to data loss or weeks of rework.
Content:
- Static pages (count, URL structure)
- News, articles, blog (volume, tags, categories)
- Galleries and media files
Catalog (for stores):
- Number of products and SKUs
- Attribute/characteristic structure
- Prices and stock
- Product images
Users and orders:
- Customer database (emails, hashed passwords)
- Order history
- Bonus points and discounts
SEO:
- Current URLs and their structure
- Meta title/description for all pages
- Sitemap and robots.txt
Typical data mappings
WordPress → Bitrix (content):
| WordPress | Bitrix |
|---|---|
wp_posts (post) |
Infoblock "Articles", element b_iblock_element |
wp_posts (page) |
Page in file structure or infoblock |
wp_postmeta |
Infoblock properties b_iblock_element_property |
wp_terms |
Infoblock sections b_iblock_section |
wp_users |
b_user |
OpenCart → Bitrix (catalog):
| OpenCart | Bitrix |
|---|---|
oc_product |
b_iblock_element (catalog) |
oc_product_attribute |
Infoblock properties (characteristics) |
oc_product_option + oc_product_option_value |
SKUs |
oc_category |
Infoblock sections b_iblock_section |
oc_order |
b_sale_order |
Migration script: approach
Migration is implemented via PHP scripts working with the Bitrix API. Direct DB table writes are used only for bulk data, with subsequent index rebuild.
Example product migration via API:
// Read product from source (OpenCart DB)
$ocProduct = $sourceDb->query("SELECT * FROM oc_product WHERE product_id = ?", [$productId])->fetch();
$ocDesc = $sourceDb->query("SELECT * FROM oc_product_description WHERE product_id = ? AND language_id = 2", [$productId])->fetch();
$ocImages = $sourceDb->query("SELECT * FROM oc_product_image WHERE product_id = ? ORDER BY sort_order", [$productId])->fetchAll();
// Create element in Bitrix
$el = new CIBlockElement();
$elementId = $el->Add([
'IBLOCK_ID' => CATALOG_IBLOCK_ID,
'NAME' => $ocDesc['name'],
'CODE' => \Bitrix\Main\Text\StringHelper::translit($ocDesc['name']),
'DETAIL_TEXT' => $ocDesc['description'],
'PREVIEW_TEXT' => $ocDesc['meta_description'],
'ACTIVE' => $ocProduct['status'] ? 'Y' : 'N',
'IBLOCK_SECTION_ID' => getCategoryMapping($ocProduct['manufacturer_id']),
'PROPERTY_VALUES' => [
'ARTICLE' => $ocProduct['model'],
'WEIGHT' => $ocProduct['weight'],
'BRAND_ID' => getBrandMapping($ocProduct['manufacturer_id']),
],
]);
// Upload main image
if ($ocProduct['image']) {
migrateImage($elementId, $sourceImgPath . $ocProduct['image'], 'DETAIL_PICTURE');
}
// Upload gallery
foreach ($ocImages as $img) {
migrateImageToGallery($elementId, $sourceImgPath . $img['image']);
}
// Set price
CCatalogProduct::Add(['ID' => $elementId, 'QUANTITY' => $ocProduct['quantity']]);
CPrice::SetBasePrice($elementId, $ocProduct['price'], 'RUB');
How to preserve SEO during migration?
This is the most commercially sensitive part. Losing search positions when changing CMS is a real risk.
URL preservation strategy:
- Build mapping of old URLs → new URLs in Bitrix
- Set up 301 redirects via
.htaccessor nginx - In Bitrix, set symbolic codes (
CODE) of elements and sections as close as possible to old URLs
# .htaccess — redirect old WordPress URLs
RewriteRule ^blog/(.+)/$ /news/$1/ [R=301,L]
RewriteRule ^product/(.+)/$ /catalog/item/$1/ [R=301,L]
Meta title and description are transferred to infoblock properties or via the Bitrix SEO filters module. A redirect map is a mandatory project artifact, exported to CSV for verification.
User transfer
Passwords from WordPress (bcrypt) cannot be transferred directly — the hashing algorithm in Bitrix is different. Options:
- Force reset — users receive an email to set a new password
- Temporary login by email — on first login after migration, only email is requested, then set new password
- Hybrid hash — on login, first check password with old algorithm, if success rehash to Bitrix format
The third option requires a custom authorization handler but preserves UX — users don't notice the migration.
Why migration via API is safer?
Direct database writes risk integrity violations. Bitrix API ensures data validation and correct handling of events. For example, when creating an element via CIBlockElement::Add, the events OnBeforeIBlockElementAdd and OnAfterIBlockElementAdd are automatically triggered. This is critical for systems integrated with 1C or CRM. API migration reduces the risk of data loss by 3 times compared to direct DB copying.
Testing and acceptance
After migration — data reconciliation:
# Reconciliation pseudocode
source_count = source_db.query("SELECT COUNT(*) FROM oc_product WHERE status=1")
bitrix_count = bitrix_db.query("SELECT COUNT(*) FROM b_iblock_element WHERE IBLOCK_ID=? AND ACTIVE='Y'", [CATALOG_IBLOCK_ID])
assert source_count == bitrix_count, f"Product count mismatch: {source_count} vs {bitrix_count}"
Checked: number of products, sections, users, orders. Randomly — content of 20–30 elements.
What's included in the work
We provide a full range of services:
- Detailed audit of the source CMS with a report
- Development of migration scripts
- Transfer of all data (content, catalog, users, orders)
- Configuration of 301 redirects and SEO preservation
- Integration with 1C, payment systems (YooKassa, Sber), delivery services (CDEK, Russian Post)
- Functional testing and data reconciliation
- Site administrator training
- 30-day warranty support after launch
Timeframes
| Project scale | Duration |
|---|---|
| Content site (up to 500 pages) | 1–2 weeks |
| Store up to 5,000 products | 3–6 weeks |
| Large catalog 10,000+ products + order history | 2–4 months |
Migration from another CMS is a full-fledged development project. The quality of the result depends on the depth of the initial audit. Assess your project — contact us for a free consultation. Migration cost is calculated individually based on data volume.
Sources: 1C-Bitrix on Wikipedia, CMS.







