How to Migrate Your Concrete5 to WordPress: Step-by-Step Guide
How to Migrate Your Concrete5 to WordPress: Step-by-Step Guide
Migrating an enterprise or business web property from Concrete5 to WordPress requires a deep understanding of divergent data schemas, server-level file structures, and HTTP routing mechanics. Because Concrete5 utilizes an object-relational mapping (ORM) system centered around attributes, collections, and custom block tables (such as btContent, btFAQ, and CollectionAttributeValues), whereas WordPress relies on a normalized relational layout (wp_posts, wp_postmeta, wp_terms), a direct database swap is impossible. A successful migration preserves SEO equity, maintains strict data integrity across relational boundaries, mitigates security risks during the transfer window, and enforces production-grade hardening measures.
Problem Statement & Impact
The core technical challenge in a Concrete5-to-WordPress migration lies in bridging disparate content architectures. Concrete5 stores page metadata, hierarchical parent-child relationships, and block contents inside fragmented, entity-specific tables. Conversely, WordPress consolidates all post types, pages, custom post types, and revisions into the single wp_posts table, augmenting them with key-value pairs stored in wp_postmeta.
Failing to account for these structural variances introduces severe technical and operational consequences:
Chat with an engineer on WhatsApp within 15 minutes.
- Data Loss and Corruption: Incompatible character sets (e.g., transitioning from `utf8mb4_unicode_ci` to mismatched WordPress database configurations) often corrupt multibyte characters, custom attributes, and serialized PHP arrays.
- SEO Degradation: Altering URL slugs, category structures, or neglecting proper 301 redirect mapping results in broken internal links, a spike in 404 HTTP response codes, and an immediate drop in search engine rankings.
- Security Exposure: Leaving legacy Concrete5 files, unprotected staging environments, or default database credentials exposed during the transition phase creates attack surfaces for remote code execution and unauthorized data extraction.
These risks affect production environments across shared hosting, virtual private servers (VPS), and containerized cloud architectures running LEMP (Linux, Nginx, MySQL, PHP) or LAMP stacks. Meticulous planning and execution are mandatory to prevent prolonged downtime and security degradation.
Root Cause Analysis & Database Architecture Differences
To execute a flawless migration, engineers must analyze the underlying mechanics of both platforms. Concrete5 builds pages as hierarchical collections tracked in the Pages table, where each page possesses a unique collection ID (cID). Content blocks reside in separate database tables prefixed by their block type handle (e.g., a content block named content maps to table btContent), linked via block IDs (bID) and collection versions (cvID).
WordPress simplifies this architecture by standardizing content ingestion into the following core tables:
wp_posts: Stores all post types, pages, attachments, and custom navigation items. Key columns includeID,post_author,post_date,post_content,post_title,post_name(slug), andpost_type.wp_postmeta: Holds arbitrary metadata associated with posts viapost_id, utilizingmeta_keyandmeta_valuepairs.wp_term_relationships,wp_terms, andwp_term_taxonomy: Manages taxonomies (categories and tags) and maps them to respective posts.
When migrating, custom blocks in Concrete5 must be systematically extracted, transformed into HTML strings or Gutenberg block markup, and injected directly into the post_content field of the target WordPress database, or mapped into custom post types and meta fields.
Step-by-Step Implementation & Remediation Guide
Phase 1: Environment Provisioning and Comprehensive Backup
Before initiating any data transformation, establish a secure staging environment for WordPress and capture complete backups of the source Concrete5 system.
# SSH into your Concrete5 server and export the database
mysqldump -u c5_user -p --single-transaction --routines --triggers c5_database > /var/backups/concrete5_migration_$(date +%F).sql
# Compress and archive the Concrete5 root directory (excluding cache files)
tar --exclude='application/files/cache' -czvf /var/backups/concrete5_files_$(date +%F).tar.gz /var/www/html/concrete5/
Next, deploy a clean WordPress instance on your target server. Ensure PHP execution parameters are optimized for heavy data processing:
; php.ini recommendations for migration processing
memory_limit = 512M
max_execution_time = 300
upload_max_filesize = 128M
post_max_size = 128M
Phase 2: Data Extraction and Transformation via Custom Scripts
For mid-to-large-scale migrations, manual copy-pasting is inefficient and error-prone. Developers should utilize a custom PHP migration script to query the Concrete5 database, transform the data structures, and insert them directly into the WordPress database.
Create a migration script (migrate-c5-to-wp.php) that connects to both databases:
<?php
// Database credentials
$c5_host = 'localhost';
$c5_db = 'c5_database';
$c5_user = 'c5_user';
$c5_pass = 'c5_secure_password';
$wp_host = 'localhost';
$wp_db = 'wordpress_database';
$wp_user = 'wp_user';
$wp_pass = 'wp_secure_password';
try {
$pdo_c5 = new PDO("mysql:host=$c5_host;dbname=$c5_db;charset=utf8mb4", $c5_user, $c5_pass);
$pdo_wp = new PDO("mysql:host=$wp_host;dbname=$wp_db;charset=utf8mb4", $wp_user, $wp_pass);
// Fetch pages and corresponding content blocks from Concrete5
$stmt = $pdo_c5->query("
SELECT p.cID, pv.cvName, pv.cvDescription, cv.cvDateCreated
FROM Pages p
JOIN CollectionVersions pv ON p.cID = pv.cID
WHERE pv.cvIsApproved = 1
");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$title = $row['cvName'];
$content = "Migrated from Concrete5 ID: " . $row['cID']; // Append block parsing logic here
$slug = sanitize_title_custom($title);
$date = $row['cvDateCreated'];
// Insert into WordPress wp_posts table
$wp_insert = $pdo_wp->prepare("
INSERT INTO wp_posts (post_author, post_date, post_date_gmt, post_content, post_title, post_status, post_name, post_type)
VALUES (1, ?, ?, ?, ?, 'publish', ?, 'page')
");
$wp_insert->execute([$date, $date, $content, $title, $slug]);
}
echo "Migration script executed successfully.";
} catch (PDOException $e) {
echo "Database Error: " . $e->getMessage();
}
function sanitize_title_custom($title) {
return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $title)));
}
?>
Phase 3: Media Library and Asset Migration
Concrete5 stores uploaded files within application/files/, often organized in nested subdirectories based on file storage locations. These assets must be migrated to the WordPress uploads directory, typically structured as wp-content/uploads/YYYY/MM/.
Use a recursive shell script to sync and normalize file permissions:
# Copy files from Concrete5 file repository to WordPress uploads
rsync -avzh /var/www/html/concrete5/application/files/ /var/www/html/wordpress/wp-content/uploads/
# Adjust file ownership and permissions for the web server user (e.g., www-data)
chown -R www-data:www-data /var/www/html/wordpress/wp-content/uploads/
find /var/www/html/wordpress/wp-content/uploads/ -type d -exec chmod 755 {} \;
find /var/www/html/wordpress/wp-content/uploads/ -type f -exec chmod 644 {} \;
Once files are transferred, update database references if image URLs have changed, utilizing WP-CLI to perform serialized search-and-replace operations safely:
wp search-replace 'https://old-site.com/application/files' 'https://new-site.com/wp-content/uploads' --path=/var/www/html/wordpress --all-tables
Phase 4: URL Structure Mapping and 301 Redirects
Concrete5 URLs often lack strict extension requirements or rely on path-based routing that differs from WordPress permalink structures. To prevent catastrophic SEO failures, implement precise 301 redirects.
If utilizing Nginx as your web server, configure mapping rules directly within your server block configuration:
server {
listen 80;
server_name new-site.com www.new-site.com;
root /var/www/html/wordpress;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
# Concrete5 legacy path redirects
location ~* ^/about-us/?$ {
return 301 https://new-site.com/about/;
}
location ~* ^/services/web-development/?$ {
return 301 https://new-site.com/services/development/;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
Production Hardening & Edge Cases
Migrating enterprise CMS platforms introduces subtle edge cases that can compromise application stability if left unaddressed.
- Serialization Breakage during Search-and-Replace: PHP serialized data (common in WordPress options and widget settings) breaks if modified with standard string replacement tools. Always utilize WP-CLI (`wp search-replace`) or dedicated serialization-aware migration scripts to prevent fatal deserialization errors.
- Rewrite Rule Flushes: After importing post types and updating permalink structures via database scripts, the WordPress rewrite cache becomes stale. Flush rewrite rules immediately via CLI:
wp rewrite flush --hard --path=/var/www/html/wordpress
- Server-Level Security Hardening: Lock down sensitive files and execution permissions in the new WordPress root directory:
# Secure wp-config.php and disable file editing from the WordPress dashboard
chmod 400 /var/www/html/wordpress/wp-config.php
chown root:www-data /var/www/html/wordpress/wp-config.php
Add the following directives to your wp-config.php to enforce administrative security:
define('DISALLOW_FILE_EDIT', true);
define('FORCE_SSL_ADMIN', true);
define('WP_AUTO_UPDATE_CORE', 'minor');
Diagnostic Verification & Checklist
Execute the following verification matrix before pointing DNS records to the new WordPress production environment. Ensure every diagnostic metric returns expected operational values.
| Check Item | Verification Method | Expected Result / Target Metric |
|---|---|---|
| HTTP Status Validation | curl -I https://new-site.com/about/ |
HTTP/2 200 OK (No unexpected 302 loops) |
| Legacy Redirect Verification | curl -I https://new-site.com/old-c5-path |
HTTP/2 301 Moved Permanently pointing to target URL |
| Database Character Encoding | SQL Query: SELECT @@character_set_database; |
utf8mb4_unicode_ci across all migrated tables |
| Error Log Monitoring | tail -n 100 /var/log/nginx/wordpress_error.log |
Zero PHP fatal errors or undefined function notices |
| SSL/TLS Handshake & Cipher Strength | Qualys SSL Labs / OpenSSL CLI test | A+ Rating with TLS 1.3 support enabled |
Monitor application performance metrics for a minimum of 72 hours post-migration. Keep automated daily backups active, verify database replication pipelines, and ensure your Web Application Firewall (WAF) rules are tuned to block unauthorized access attempts targeting legacy Concrete5 endpoints.
Secure Your WordPress Migration with SiteSuraksha
Our team specializes in secure enterprise website migrations, architecture hardening, and ongoing security posture management. Let our engineers execute your platform transition with zero downtime and ironclad protection.
Is Your Website Fast & Secure?
Run an instant scan for security vulnerabilities, bloated plugins, and TTFB latency.
Need Help Securing or Speeding Up Your Site?
Get 24/7 proactive security WAF, daily cloud backups, and sub-second speed optimization from ₹3,470/mo.