Website Migration from Another CMS to 1C-Bitrix
Moving a site from WordPress, OpenCart, or MODx to Bitrix isn't simply copying files. Data structures differ fundamentally: what WordPress stores in wp_posts + wp_postmeta, Bitrix distributes across b_iblock_element, b_iblock_element_property, and b_iblock_element_prop_m. Migration is an ETL-project (Extract, Transform, Load) with serious analytical phase.
Source CMS Audit
First step — inventory what must be transferred:
Content:
- Static pages (quantity, URL structure)
- News, articles, blog (volume, tags, categories)
- Galleries and media files
Catalog (for stores):
- Product count and SKU (trade offers)
- Attribute and property structure
- Prices and stock
- Product images
Users and Orders:
- Customer base (email, hashed passwords)
- Order history
- Loyalty 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 | Notes |
|---|---|---|
wp_posts (post) |
Info block "Articles", element b_iblock_element |
|
wp_posts (page) |
Page in file structure or info block | |
wp_postmeta |
Info block properties b_iblock_element_property |
|
wp_terms |
Info block sections b_iblock_section |
|
wp_users |
b_user |
OpenCart → Bitrix (catalog):
| OpenCart | Bitrix | Notes |
|---|---|---|
oc_product |
b_iblock_element (catalog) |
|
oc_product_attribute |
Info block properties | |
oc_product_option + value |
Trade offers (SKU) | |
oc_category |
Info block sections b_iblock_section |
|
oc_order |
b_sale_order |
Migration Script Approach
Migration is implemented via PHP-scripts working with Bitrix API. Direct database writes only for bulk data with subsequent index rebuilding.
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');
Preserving SEO and URL Structure
This is commercially critical. Losing search rankings during CMS migration is a real risk.
URL preservation strategy:
- Form mapping: old URLs → new URLs in Bitrix
- Configure
301redirects via.htaccessor nginx - In Bitrix, set element codes (
CODE) as close to old URLs as possible
# .htaccess — redirects from WordPress URLs
RewriteRule ^blog/(.+)/$ /news/$1/ [R=301,L]
RewriteRule ^product/(.+)/$ /catalog/item/$1/ [R=301,L]
- Transfer meta tags: store in info block properties or via Bitrix SEO-filter module
Redirect map — mandatory project artifact, exported to CSV for verification.
User Transfer
Passwords from WordPress (bcrypt) cannot transfer directly — hashing algorithm differs in Bitrix. Options:
- Forced reset — users receive email to set new password
- Temporary email login — first login after migration requires only email, then password setup
- Hybrid hash — on login, check password against old algorithm, on success rehash to Bitrix-format
Third option preserves UX — users don't notice migration.
Testing and Acceptance
Post-migration: data verification:
# Pseudocode for verification
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}"
Verify: product count, section count, user count, order count. Spot-check content of 20–30 random elements.
Execution Timeline
| 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 full development project, not just "export-import". Result quality depends on audit depth at start.







