15%

Save 15% on All Hosting Services

Test your skills and get Discount on any hosting plan

Use code:

Skills
Get Started
23.10.2024
1 +1

How to Migrate a Drupal Website to WordPress: A Complete Technical Guide

Migrating from Drupal to WordPress means transferring your database content, media files, URL structure, and user accounts from Drupal's entity-based CMS architecture to WordPress's post-type model — without losing SEO equity, breaking internal links, or causing downtime. The process involves a database-level content import via the FG Drupal to WordPress plugin, followed by permalink mapping, 301 redirect configuration, and theme reconstruction.

This guide covers every phase of that migration in precise technical detail: pre-migration backup strategy, environment setup, database credential extraction, plugin-driven import, URL structure reconciliation, and post-launch validation. Whether you are running Drupal 7, 9, or 10, the workflow below applies.

Why Migrate from Drupal to WordPress

Drupal is a powerful framework, but its complexity carries a real operational cost. Module updates frequently introduce breaking changes, theming requires Twig template expertise, and routine content edits demand developer involvement. WordPress, by contrast, offers a shallower learning curve, a vastly larger plugin ecosystem, and lower total cost of ownership for content-heavy sites that do not require Drupal's granular access control or complex content modeling.

The performance argument also matters. A WordPress installation on a properly configured VPS Hosting environment with LiteSpeed, object caching, and NVMe storage will consistently outperform a bloated Drupal stack on shared infrastructure.

Key migration motivations by use case:

  • Editorial teams frustrated by Drupal's admin UX and slow publishing workflows
  • Agencies consolidating client sites onto a single manageable CMS
  • Developers reducing maintenance overhead from Drupal's module dependency chains
  • SEO teams seeking tighter integration with WordPress-native tools like Yoast or Rank Math

Drupal vs. WordPress: Architecture Comparison

Understanding the structural differences between the two platforms is essential before you begin. Mismatched assumptions about how content is stored are the primary cause of failed or incomplete migrations.

DimensionDrupalWordPress
Content modelEntities (nodes, taxonomy terms, fields)Post types (posts, pages, CPTs)
Database schemaHighly normalized, multi-table per content typeFlat wp_posts + wp_postmeta model
URL routingPath aliases stored in path_alias tablePermalink rewrite rules via .htaccess
Theming engineTwig templates + Preprocess hooksPHP template hierarchy + hooks
User rolesGranular permissions per roleFixed role hierarchy (Subscriber → Admin)
Media handlingManaged files entity with field attachmentsMedia Library with attachment post type
MultilingualCore Language moduleRequires WPML or Polylang plugin
REST APIJSON:API + REST core modulesWP REST API built-in
Hosting complexityHigh (requires Composer, Drush)Low (standard LAMP/LEMP stack)
Plugin/module ecosystem~50,000 modules~60,000+ plugins

The most critical architectural gap is the content entity model. Drupal stores paragraphs, custom fields, and taxonomy references across multiple joined tables. The FG Drupal to WordPress plugin maps these to WordPress post meta and taxonomy terms, but complex paragraph-based layouts will require manual reconstruction.

Pre-Migration Checklist

Before touching either environment, complete every item on this list. Skipping steps here is the leading cause of data loss and extended downtime.

  • Audit your Drupal content inventory: node types, taxonomy vocabularies, user count, file count, and total database size
  • Identify any Drupal modules with no WordPress equivalent (e.g., Rules, Webform complex logic, Commerce)
  • Confirm your WordPress server meets minimum requirements: PHP 8.1+, MySQL 8.0+ or MariaDB 10.6+, 256 MB PHP memory limit
  • Decide on a migration window — ideally a low-traffic period
  • Enable maintenance mode on Drupal during the final import pass to prevent content drift
  • Verify that the WordPress server can reach the Drupal database host (same server, remote host, or SSH tunnel)

Step 1: Back Up Your Drupal Website

A full, verified backup is non-negotiable. You need both the database dump and the files directory.

Database Backup via Drush

If you have Drush installed (standard for Drupal 9/10), this is the fastest method:

drush sql-dump --result-file=/var/backups/drupal_backup_$(date +%Y%m%d).sql --gzip

Database Backup via mysqldump

mysqldump -u drupal_user -p drupal_database_name | gzip > /var/backups/drupal_backup_$(date +%Y%m%d).sql.gz

Files Directory Backup

tar -czf /var/backups/drupal_files_$(date +%Y%m%d).tar.gz /var/www/html/drupal/sites/default/files/

phpMyAdmin Backup (GUI Method)

  1. Log in to phpMyAdmin via your hosting control panel
  2. Select the Drupal database from the left sidebar
  3. Click Export, choose Quick export method, format SQL
  4. Click Go to download the .sql file

Store all backup archives off-server — upload them to remote storage or download locally via SFTP. A backup that lives only on the same server as the site being migrated is not a real backup.

Step 2: Set Up WordPress on Your Target Server

Install a clean WordPress instance on your target environment. Do not import Drupal content into an existing WordPress site unless you have explicitly planned for content merging — the importer will not deduplicate.

Server Requirements

RequirementMinimumRecommended
PHP version7.48.2
MySQL/MariaDBMySQL 5.7 / MariaDB 10.3MySQL 8.0 / MariaDB 10.11
PHP memory limit64 MB256 MB
max_execution_time30s300s
upload_max_filesize8 MB128 MB

For large Drupal sites (10,000+ nodes, multi-GB media libraries), a VPS with cPanel gives you direct access to PHP configuration, MySQL tuning parameters, and cron job management — all of which you will need during a heavy migration.

WordPress Installation via WP-CLI

cd /var/www/html/wordpress
wp core download
wp config create --dbname=wp_database --dbuser=wp_user --dbpass=secure_password --dbhost=localhost
wp core install --url="https://yourdomain.com" --title="Site Title" --admin_user=admin --admin_password=strongpassword --admin_email=admin@yourdomain.com

One-Click Installation via cPanel

If your host provides cPanel, navigate to Softaculous Apps Installer, select WordPress, fill in the database and admin credentials, and click Install. The process takes under two minutes.

After installation, immediately configure these PHP settings in php.ini or via .htaccess:

php_value max_execution_time 300
php_value memory_limit 256M
php_value post_max_size 128M
php_value upload_max_filesize 128M

Step 3: Install and Configure the FG Drupal to WordPress Plugin

The FG Drupal to WordPress plugin (free tier available; Premium recommended for large sites) handles the database-level migration of nodes, taxonomy terms, users, and media files.

Installation

  1. In your WordPress admin, go to Plugins > Add New
  2. Search for FG Drupal to WordPress
  3. Click Install Now, then Activate

Alternatively, install via WP-CLI:

wp plugin install fg-drupal-to-wp --activate

Free vs. Premium Feature Comparison

FeatureFreePremium
Drupal 6/7 supportYesYes
Drupal 8/9/10 supportPartialFull
Paragraphs migrationNoYes
User migrationNoYes
Webform migrationNoYes
E-commerce (Drupal Commerce)NoYes
Multilingual contentNoYes
Priority supportNoYes

For any production site running Drupal 8 or later, the Premium version is worth the cost. Attempting to manually reconstruct paragraph-based content is far more expensive in developer time.

Step 4: Gather Drupal Database Credentials

The FG Drupal to WordPress plugin connects directly to your Drupal database. You need four values: database name, username, password, and host.

Finding Credentials in Drupal's settings.php

grep -A 20 "'database'" /var/www/html/drupal/sites/default/settings.php

The output will contain a block like this:

$databases['default']['default'] = [
  'database' => 'drupal_db_name',
  'username' => 'drupal_db_user',
  'password' => 'drupal_db_password',
  'host' => 'localhost',
  'port' => '3306',
  'driver' => 'mysql',
];

Remote Database Access Considerations

If WordPress and Drupal are on different servers, the Drupal database must accept remote connections. On the Drupal database server:

GRANT SELECT ON drupal_database.* TO 'drupal_user'@'wordpress_server_ip' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

Also ensure port 3306 is open in the firewall for the WordPress server's IP only — never expose MySQL to 0.0.0.0.

If you cannot open a direct MySQL port, use an SSH tunnel:

ssh -L 3307:localhost:3306 user@drupal_server_ip -N -f

Then set the plugin's database host to 127.0.0.1 and port to 3307.

Step 5: Run the Content Import

Navigate to Tools > Import in your WordPress dashboard, scroll to the Drupal section, and click Run Importer.

Importer Settings Configuration

Database connection tab:

  • Database host: localhost (or remote IP / SSH tunnel address)
  • Port: 3306 (or your custom port)
  • Database name: value from settings.php
  • Username / Password: values from settings.php
  • Drupal files URL: the public URL of your Drupal sites/default/files/ directory — required for media download

Click Test the connection before proceeding. A failed connection at this stage is almost always caused by one of three issues: incorrect credentials, a firewall blocking the MySQL port, or the Drupal database user lacking SELECT privileges on the target database.

Behavior tab — recommended settings for most migrations:

  • Import posts: Yes
  • Import pages: Yes
  • Import categories and tags: Yes
  • Download images and attachments: Yes (required to copy media into WordPress's upload directory)
  • Remove WordPress data before import: Yes (on a fresh install only — this truncates wp_posts and related tables)

Starting the Import

Click Start / Resume the Importer. The plugin processes content in batches. For large sites, the import may time out and require multiple resume cycles — this is expected behavior, not an error. Simply click Resume each time.

Monitor the import log displayed on-screen. Watch for:

    Error downloading file — indicates the Drupal files URL is incorrect or the files directory is not publicly accessible
    Duplicate entry errors — usually harmless, indicating the plugin is skipping already-imported records on a resume
    MySQL server has gone away — indicates wait_timeout is too low on the MySQL server; increase it to at least 600 seconds
    
    SET GLOBAL wait_timeout = 600;
    SET GLOBAL interactive_timeout = 600;
    Step 6: Reconcile URL Structure and Configure Redirects
    This is the step most guides underestimate. URL structure mismatches between Drupal and WordPress are the primary cause of post-migration SEO ranking drops.
    Drupal URL Patterns (Common)
    
    
    
    
    Drupal URL pattern
    Description
    
    
    
    
    /node/123
    Default node path (no alias)
    
    
    /about-us
    Path alias (most common)
    
    
    /taxonomy/term/5
    Taxonomy term page
    
    
    /user/1
    User profile
    
    
    /content/article-title
    Content-type prefixed alias
    
    
    
    
    WordPress Permalink Configuration
    Go to Settings > Permalinks and select a structure that matches your Drupal path aliases as closely as possible. For most Drupal sites using clean aliases, /%postname%/ is the correct choice.
    /%postname%/
    If your Drupal site used category-prefixed URLs like /blog/article-title, use:
    /%category%/%postname%/
    Implementing 301 Redirects
    Install the Redirection plugin (by John Godley) for managing redirect rules. For bulk redirects, export your Drupal path aliases from the database:
    SELECT source, alias FROM path_alias WHERE langcode = 'en';
    Then import the resulting CSV into the Redirection plugin, mapping each Drupal alias to its WordPress equivalent. For /node/123 style URLs that were never aliased, create regex-based redirects:
    /node/([0-9]+)$ → /?p=$1
    This maps Drupal node IDs to WordPress post IDs — but only works if the FG plugin preserved the original node IDs as post IDs, which it does by default.
    Critical: Test every redirect with curl -I before going live:
    curl -I https://yourdomain.com/old-drupal-path
    Verify the response is HTTP/2 301 with the correct Location header, not a 302 or a 200 with a soft redirect.
    Step 7: Migrate Themes and Rebuild Design
    Drupal themes (Twig-based) have no direct equivalent in WordPress. You must rebuild the visual design using a WordPress theme as the foundation.
    Theme Selection Strategy
    
    Block-based themes (FSE): Use the WordPress Site Editor for full layout control without page builders. Best for developers comfortable with block markup.
    Classic themes with page builder: Themes like Astra or GeneratePress paired with Elementor or Bricks Builder offer the closest equivalent to Drupal's Layout Builder.
    Custom child theme: If your Drupal site had a heavily customized design, build a child theme based on a minimal parent (Underscores, Blocksy) and replicate the CSS.
    
    Rebuilding Navigation Menus
    Drupal menus do not migrate automatically. Rebuild them under Appearance > Menus (classic themes) or the Site Editor's Navigation block (FSE themes). Cross-reference your Drupal menu structure:
    drush eval "print_r(menu_tree_all_data('main', NULL));"
    Or query the database directly:
    SELECT ml.link_path, ml.link_title, ml.weight, ml.depth
    FROM menu_links ml
    WHERE ml.menu_name = 'main-menu' AND ml.hidden = 0
    ORDER BY ml.weight;
    Widgets and Blocks
    Drupal blocks map loosely to WordPress widgets and Gutenberg blocks. Rebuild sidebar and footer regions under Appearance > Widgets or directly in the Site Editor. Custom Drupal block types with PHP logic will need to be rebuilt as WordPress shortcodes or custom blocks.
    Step 8: Post-Migration Content Audit
    Do not skip this phase. Automated migration tools handle structured content well but fail silently on edge cases.
    Content Integrity Checks
    
    Embedded media: Drupal's inline file references use a custom token format ([file:123] or <drupal-media uuid="..."/>). These will not render in WordPress. Search the database for these tokens:
    
    SELECT ID, post_title FROM wp_posts WHERE post_content LIKE '%drupal-media%' OR post_content LIKE '%[file:%';
    
    Shortcodes and Views: Drupal Views have no WordPress equivalent. Any page that rendered a View (e.g., a filtered content listing) will be blank. Rebuild these using WP_Query, custom post type archives, or a plugin like Posts Table Pro.
    
    
    Custom fields: Drupal field data migrated via the Premium plugin lands in wp_postmeta. Verify field values are present:
    
    SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_key LIKE 'field_%' LIMIT 50;
    
    User accounts: If you migrated users, verify role mapping. Drupal's authenticated user role maps to WordPress Subscriber. Drupal editor maps to WordPress Editor. Drupal administrator maps to WordPress Administrator. Audit the mapping and adjust as needed.
    
    Broken Link Detection
    Install Broken Link Checker or run a crawl with Screaming Frog against your staging environment before DNS cutover. Fix all internal 404s before going live — do not rely on post-launch monitoring to catch these.
    Step 9: Performance and Security Hardening
    A freshly migrated WordPress site needs hardening before it is production-ready.
    Caching Configuration
    Install LiteSpeed Cache (if on a LiteSpeed server) or W3 Total Cache / WP Rocket for Apache/Nginx environments. Configure:
    
    Page cache with a TTL of at least 3600 seconds for static pages
    Object cache backed by Redis or Memcached
    Browser cache headers via .htaccess or server config
    
    SSL/HTTPS
    Ensure your WordPress site is served exclusively over HTTPS. If you do not already have a certificate, SSL Certificates can be provisioned quickly and configured to auto-renew. Update WordPress's site URL settings:
    wp option update siteurl 'https://yourdomain.com'
    wp option update home 'https://yourdomain.com'
    Force HTTPS in .htaccess:
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    Security Hardening Checklist
    
    Disable XML-RPC if not needed: add add_filter('xmlrpc_enabled', '__return_false'); to functions.php
  • Change the default wp_ table prefix (requires database rename — do this before import if possible)
  • Install Wordfence or Solid Security for firewall and login protection
  • Set file permissions: directories 755, files 644, wp-config.php 600
  • find /var/www/html/wordpress -type d -exec chmod 755 {} ;
    find /var/www/html/wordpress -type f -exec chmod 644 {} ;
    chmod 600 /var/www/html/wordpress/wp-config.php

    Step 10: DNS Cutover and Launch

    Perform the DNS cutover during your lowest-traffic window. The process should take under 15 minutes of actual work, with a propagation window of up to 48 hours (typically 1–4 hours for most resolvers).

    Pre-Cutover Final Checks

    • Run a full crawl of the staging URL and confirm zero 404s
    • Verify all 301 redirects return correct Location headers
    • Test contact forms, search functionality, and any e-commerce flows
    • Confirm Google Search Console is verified on the new site
    • Generate and submit a fresh XML sitemap via Yoast SEO or Rank Math

    DNS Update Process

    If you registered your domain through Domain Registration, update the A record directly in the DNS management panel. Lower the TTL to 300 seconds at least 24 hours before the cutover to minimize propagation delay.

    A record: yourdomain.com → [new WordPress server IP]
    TTL: 300 (pre-cutover), restore to 3600 post-cutover

    Post-Launch Monitoring

    • Enable Google Search Console change of address tool if the domain itself changed
    • Monitor Core Web Vitals in Search Console for the first 30 days — expect a temporary ranking fluctuation as Google recrawls and re-indexes
    • Set up UptimeRobot or equivalent for availability monitoring
    • Check server error logs daily for the first week:
    tail -f /var/log/apache2/error.log
    # or for Nginx:
    tail -f /var/log/nginx/error.log

    Search Engine Resubmission

    Submit your updated sitemap in Google Search Console:

    1. Go to Search Console > Sitemaps
    2. Enter sitemap.xml (or sitemap_index.xml for large sites)
    3. Click Submit

    Also submit to Bing Webmaster Tools and verify the site independently there — Bing's index is used by several AI search engines including Copilot.

    Hosting Infrastructure Recommendations

    The performance of your migrated WordPress site depends heavily on the underlying infrastructure. A Drupal-to-WordPress migration is an ideal time to also modernize your hosting stack.

    For sites with moderate traffic (10,000–100,000 monthly visits), a VPS Hosting plan with at least 2 vCPUs, 4 GB RAM, and NVMe storage provides sufficient headroom for WordPress with full-page caching. For high-traffic or resource-intensive sites, Dedicated Servers eliminate the noisy-neighbor problem entirely and give you full control over kernel parameters, MySQL configuration, and network stack tuning.

    If you are managing multiple client sites or prefer a GUI-driven server management experience, VPS Control Panels offer a range of options including cPanel, Plesk, and DirectAdmin — each supporting multi-site WordPress management, automated backups, and SSL provisioning from a single interface.

    Technical Decision Matrix: When to Use Each Migration Approach

    ScenarioRecommended ApproachKey Tool
    Drupal 7, small site (<500 nodes)FG plugin free tier, same serverFG Drupal to WordPress (free)
    Drupal 9/10, paragraph-heavy contentFG plugin Premium, staging serverFG Drupal to WordPress Premium
    Drupal Commerce → WooCommerceFG Premium + WooCommerce add-onFG + WooCommerce migration module
    Multilingual Drupal siteFG Premium + WPMLFG + WPML plugin
    Drupal with complex ViewsManual rebuild requiredWP_Query + CPT UI
    Different server migrationSSH tunnel for DB accessSSH port forwarding
    Zero-downtime requirementBlue-green deploymentDNS TTL reduction + staging

    Key Technical Takeaways

    • Back up before anything else. A compressed SQL dump and a tarball of sites/default/files/ are your safety net. Verify both are complete and restorable before starting.
    • Test database connectivity before running the importer. The majority of failed migrations stall at the connection test due to firewall rules or missing SELECT grants.
    • Paragraph-based Drupal content requires the Premium plugin. The free tier will silently skip paragraph fields, leaving content incomplete with no error message.
    • 301 redirects are not optional. Every Drupal URL that has external backlinks or search engine indexing must redirect to its WordPress equivalent with a permanent 301. A missing redirect is a lost ranking signal.
    • Lower DNS TTL 24 hours before cutover. Set it to 300 seconds so propagation completes in minutes, not hours, when you flip the A record.
    • Audit wp_postmeta for unmapped Drupal fields. Custom field data lands there after import — verify it is present and correctly keyed before decommissioning the Drupal instance.
    • Do not decommission Drupal immediately. Keep the Drupal environment running (in maintenance mode, not publicly accessible) for at least 30 days post-launch as a reference and rollback option.
    • Resubmit your sitemap the same day you go live. Do not wait for Googlebot to discover the new structure organically — active submission accelerates recrawling.

    FAQ

    Can I migrate a Drupal multisite installation to WordPress?

    Yes, but each Drupal subsite must be migrated individually. The FG Drupal to WordPress plugin does not natively handle Drupal multisite in a single pass. Run a separate import for each subsite, targeting either a WordPress Multisite network or standalone WordPress installations depending on your architecture.

    Will my Drupal user passwords transfer to WordPress?

    No. Drupal uses a salted SHA-512 hash (or bcrypt in newer versions) that is incompatible with WordPress's phpass-based hashing. The FG Premium plugin migrates user accounts but resets passwords, triggering a password reset email to each user. Plan user communication accordingly.

    How do I handle Drupal content types with no WordPress equivalent?

    Register equivalent Custom Post Types (CPTs) in WordPress before running the import. The FG Premium plugin allows you to map Drupal content types to WordPress CPTs. Without this mapping, all nodes default to the post post type, collapsing your content taxonomy.

    What happens to Drupal's taxonomy terms during migration?

    Drupal vocabularies map to WordPress taxonomies. The default mapping converts Drupal tags to WordPress tags and Drupal categories to WordPress categories. Custom vocabularies require manual taxonomy registration in WordPress before import, or they will be dropped.

    How long does the migration take for a large Drupal site?

    For a site with 5,000 nodes and 2 GB of media, expect 2–4 hours of import time on a well-resourced server, plus 4–8 hours of post-migration content auditing and redirect configuration. The actual DNS cutover takes under 15 minutes. Total elapsed time from start to live is typically one to two business days for a thorough, production-quality migration.

    15%

    Save 15% on All Hosting Services

    Test your skills and get Discount on any hosting plan

    Use code:

    Skills
    Get Started