AEM to WordPress: Pre-migration
As the name suggests, the pre-migration phase involves all the preparatory work required before the actual migration begins. This includes auditing the existing system, cleaning data, taking backups, mapping the ecosystem (including content), setting up development environments, and more.
Getting the technical setup in place
In this chapter, we’ll cover the essential technical groundwork for your AEM to WordPress migration. From setting up your development environment(s) to organizing assets and taking backups, every step is designed to set the stage for a successful transition to WordPress.
Setting up local, testing, and live environment(s)
Setting up a local development environment is your crucial first step when migrating from AEM to WordPress. We’ll now walk you through the process of creating a local WordPress installation for development, testing, and staging purposes for your migration project.
Local WordPress installation setup
To successfully migrate from AEM to WordPress, it’s important to have a proper local setup that mirrors your final environment as closely as possible. This section will focus on establishing the basic local environment and tools needed for the migration.
Choosing a local WordPress setup method
When setting up your local WordPress installation, there are different methods you can use depending on your preferences and technical requirements.
Using Docker
Docker allows you to create a standardized environment that mimics production, making it an ideal choice for teams. Follow these steps if you wish to use Docker:
- Install Docker and Docker Compose.
- Set up a Docker Compose file to define your WordPress, MySQL, and other services.
- Run Docker Compose to get the environment up and running:
docker-compose up -d
This setup ensures consistency and can be versioned easily for different developers.
Using local tools
If you prefer a simpler setup, you can use tools like LocalWP or MAMP to install WordPress locally. These tools offer a user-friendly interface and reduce the need for manual configuration, making them ideal for less technical users or for quickly setting up an environment.
A side note: Setting up a multisite installation
If you have multiple sites, like example.com and blog.example.com, setting up a WordPress Multisite can be highly beneficial. You can structure your multisite in one of two ways: subdirectory or subdomain. Let’s see each in detail
Subdirectory vs subdomain structure
A subdirectory structure is used when your sites are part of the same domain, like example.com/site1 or example.com/site2.
In wp-config.php, add the following lines: define('WP_ALLOW_MULTISITE', true);
A subdomain structure is used when your sites are in separate subdomains, like site1.example.com or site2.example.com.
This setup requires DNS configuration to point each subdomain to your local server.
Once you’ve your local WordPress environment set up, it’s time to customize your WordPress directory.
Preparing the wp-content directory
To prepare your environment for migration, it’s essential to customize the default wp-content directory based on your project’s requirements. Below is a structured approach to ensure your local environment is ready for migration:
Remove default content
The default wp-content
directory contains the standard themes and plugins included with a fresh WordPress installation. These are not necessary for your project, so you should remove them:
“`rm -rf wp-content“`
By deleting this directory, you are clearing out all default themes and plugins to make space for the custom setup that will be used during the migration.
Clone the project repository
Next, replace the default wp-content with your project-specific content by cloning the appropriate repository. This repository will serve as the foundation for your migration:
“`
# Clone the repository
git clone git@github.com:YOUR_ORG/YOUR_PROJECT.git wp-content
“`
This repository should contain:
- Custom theme: A theme that mirrors your brand-specific design, serving as the base for the migrated site.
- Plugin skeletons: Backend developers can use this to create the foundational features needed for the project.
- Migration plugin (optional): Migration engineers may build a custom plugin to facilitate the migration process if needed.
By setting up this repository, you ensure that your local environment is ready with all necessary components, which will support the migration activities effectively.
Setting up a version control system (and a branching strategy)
With your local environment ready, the next step is effectively managing your code changes using GitHub or some other version control system. This ensures all development work is organized and easily accessible for collaboration. Here’s how to go about this:
- Create a new branch: Always create a new branch from the main/master branch on GitHub
git checkout master
git pull origin master
git checkout -b migration-branch
This allows you to keep all changes organized and easily accessible for collaboration within your team. This ensures that your work remains separate until it is ready to be merged.
Avoid the develop branch: Avoid branching from develop unless explicitly required, as it might contain changes not yet present on production. Doing so ensures that your branches are always stable and aligned with production.
Push changes regularly: Regularly push your changes to GitHub to keep them backed up and shared with your team
git push origin migration-branch
Use GitHub pull requests to ensure all changes are reviewed and quality-checked before merging. This helps maintain code quality and allows for team feedback.
Staging environment setup
Once your local environment is ready and changes have been committed, it’s time to set up a staging environment. (Your hosting provider may also help with this, so get touch with them.)
Pay attention to these things when working with your staging environment:
Mirror production setup
Set up a staging environment that closely mirrors the production setup.
Sort staging URLs
The staging environment should include the same database and configuration as production but with staging-specific URLs.
Build a staging workflow
Push any code you write or changes you make to the staging environment to validate before going live.
Also perform QA testing on the staging environment, including link checks, media availability, and functionality.
We’ll discuss QA in a later section in detail.
Live environment setup
The final AEM to WordPress migration step is deploying your staging environment instance to the live environment. But before you do (when we get to the launch), keep these in mind:
- Backing up before deployment: Always back up both the current AEM environment and the new WordPress database before switching.
- Final testing: Test thoroughly for any missing content or broken functionalities or integrations.
Key considerations when setting up your different migration environments:
- Always maintain separation between local, staging, and live environments.
- Version control all changes to themes, plugins, and configurations.
- Utilize backups and test thoroughly to avoid unexpected issues in the live environment.
This structured approach to the different environments and development best practices help ensure a smooth migration process and minimizes risks associated with the transition from AEM to WordPress.
Backing up your AEM setup
Backing up your Adobe Experience Manager (AEM) setup is key to making sure you don’t lose your hard work and can recover quickly if something goes wrong. Let’s dive into how each piece of your AEM setup can be backed up step by step.
Images, media, and videos
AEM stores digital assets like images, media, and videos in the Digital Asset Management (DAM) repository. Here’s how you can back these up:
Export method
Assets are exported as compressed files (e.g., ZIP format) to preserve their structure and metadata.
Storage location
Typically, these assets are saved in the AEM repository (CRX) or external storage solutions like Amazon S3 to ensure safety.
Content
Your content, including web pages and structured data, resides within the repository.
Export method
AEM’s Package Manager can be used to create packages containing pages, templates, and related assets. These packages can be exported in .zip or .xml formats for easy restoration when needed.
Users
User data such as login credentials and profiles is also crucial for maintaining a seamless user experience when migrating.
Backing up users
If user data is stored in AEM, you can export it using the User Management Console, typically in formats like .json or .xml.
External systems
If you’re using an external identity provider like LDAP, ensure that separate backups of those systems are managed, usually through database exports or dedicated tools provided by those systems.
Metadata
Metadata includes information like keywords, captions, and technical specifications associated with assets.
Backup process
Metadata is backed up alongside digital assets. Using AEM’s Metadata Schema Forms, you can export metadata in .json format or as part of asset packages created with the Package Manager. This ensures compatibility when restoring or migrating your assets.
Analytics
Analytics data is often collected and stored in external systems like Adobe Analytics, which requires its own approach.
Backup procedure
Since this data resides outside AEM, it should be backed up in coordination with the analytics provider. Adobe Analytics, for example, allows for exporting reports in .csv or .json formats. It’s important to ensure that all essential analytics data is captured during the backup process.
Feature/integration configurations
Custom features and integrations must be preserved to maintain site functionality. So backing up their configurations is another key step.
Code backups
Store custom features in Git repositories such as GitHub or GitLab. Create snapshots of branches and tags as a single backup process to maintain a complete record of the current state.
Configurations
Integration configurations should be exported from AEM using the Package Manager or saved as .yaml or .xml files, ensuring they are ready to be restored when needed.
Forms data
Forms are a key part of interacting with users, and their data needs careful handling.
Forms and configurations
Export forms from AEM as .zip packages that include all form fields and configurations.
Form submission data
If form submissions are stored externally, export them as .csv or .sql files. Perform a comprehensive backup using database management tools to ensure all data is safely preserved.
Additional considerations when backing up your AEM instance
Workflows
Back up your workflows using AEM’s Package Manager. Export workflow models and instances as .zip packages to retain a record of active workflows.
Taxonomy and tags
Export content classification data, such as taxonomy and tags, using CRXDE Lite or AEM Package Manager. This will help retain the original structure and classification during migration or recovery.
Securing backups
Once you’ve backed up all your AEM components, it’s equally important to secure the backed-up data. Utilize secure cloud storage solutions, such as AWS S3, with encryption enabled. Regularly verify the integrity of these backups to prevent data corruption, and store at least one backup version offsite to mitigate risks.
In summary, creating backups for AEM is about more than just copying data—it’s about creating a strategic approach that ensures seamless recovery and keeps your environment running smoothly in case of an issue.
Preparing your AEM content for migration
Getting content ready is one of the most important steps for a smooth migration from AEM to WordPress. Here, we’ll dive into content mapping, the process of identifying how existing AEM content transitions to WordPress. This ensures we preserve your content structure, relationships, and user experience effectively. But before that we’ll prepare the content for migration.
Cleaning data before backing up
The data cleanup process is all about getting rid of what’s unnecessary, standardizing what’s inconsistent, and making sure everything is optimized for migration.
Identify what stays and what goes
Start by listing out all your content using AEM’s Content Inventory Reports. This will help you decide which pages, blog posts, and other content pieces are worth migrating. Don’t forget to archive anything that is outdated or irrelevant to avoid clutter in WordPress.
Remove duplicate or outdated content
Use AEM tools like Version Purging to delete older, redundant versions of content. This keeps things neat and prevents outdated material from moving over to your new site.
Standardize metadata and format
It’s a good idea to review and update metadata, like title tags and descriptions, so they align with your SEO goals. Missing alt texts or keywords? Now’s the time to add those.
Link validation
Use the AEM Link Checker to detect and correct broken internal links. Ensuring that all links are updated before migration makes the transition smoother and prevents broken links on your new WordPress site.
Preparing digital assets for migration
Once your content is cleaned up, it’s time to focus on your digital assets like images, videos, documents, and other files. This step ensures that your assets are organized and optimized for migration.
Consolidate asset storage
Make sure all your assets are centralized in the AEM Digital Asset Management (DAM) system. Keeping everything in one place makes it easier to move and track assets during migration. Read AEM DAM overview for more.
Optimize file sizes
Compress images and videos to ensure they’re web-friendly. You can use tools like TinyPNG for image compression and HandBrake for video compression. Optimizing assets not only saves space but also helps improve the performance of your new WordPress site.
Clean up tags and metadata
Go through and standardize tags and metadata for your assets. Having a consistent tagging system makes it easier to find what you need later on. Tools like AEM’s Tagging Interface are helpful for cleaning up and applying new tags.
Optimize folder structure and naming conventions
Before migrating, make sure assets are stored in a clear, logical folder structure. Group assets by type or campaign, and use consistent naming conventions. Descriptive file names make it easy to identify assets, think homepage-banner.jpg instead of img123.jpg.
Content mapping
Once you’ve cleaned up your data, it’s time to work on content mapping. Content mapping is like creating a blueprint for how each part of your AEM content fits into WordPress. Below, we’ll show you how we can understand the data exported from AEM, map it to WordPress, and even automate the whole process with custom scripts.
Exporting AEM data
The first step is to get our content out of AEM. Luckily, AEM provides a few different ways to do this:
- AEM Package Manager is the go-to tool for most situations. It helps you export content as packages. Think of these as a ZIP file with all your pages, templates, and assets neatly bundled together.
- AEM Content Exporter plugin is another helpful utility, especially if we want our data in a more structured format like JSON. JSON makes it easier to work with the data programmatically, like when we use scripts to automate the mapping.
Here’s a sample of AEM export data (in JSON Format)
This is what your AEM content looks like once it’s exported using the JSON format:
{
"homepage": {
"jcr:primaryType": "cq:Page",
"jcr:content": {
"jcr:primaryType": "cq:PageContent",
"jcr:title": "Welcome to Our Site",
"jcr:description": "A brief description of the homepage",
"sling:resourceType": "project/components/page/home",
"header": {
"jcr:primaryType": "nt:unstructured",
"title": "Header Title",
"subtitle": "Welcome to our website"
},
"mainContent": {
"jcr:primaryType": "nt:unstructured",
"text": "This is the main content area of the homepage."
}
}
}
}
Content mapping from AEM to WordPress
Let’s break down the AEM export data that we just saw and see how it maps over to WordPress. First there’s some page level information.
Page level information
The “homepage” key represents the whole page. It’s like the foundation, we’ll map this to a WordPress Page.
The “jcr:title”: “Welcome to Our Site” is straightforward, it becomes the title of the WordPress page.
“jcr:description” can either be used as an excerpt in WordPress or even as the meta description if we’re using an SEO plugin like Yoast.
Sections within the page
The “header” node in AEM contains a “title” and a “subtitle”. In WordPress, we could create custom fields to store this information. Plugins like Advanced Custom Fields (ACF) are perfect for this kind of data because it allows us to easily add fields like “Header Title” and “Header Subtitle”.The “mainContent” holds the main text on the page, and this content will go directly into the WordPress Editor, it’s the core content users will see.
Here’s a mapping table for easy reference:
AEM Data Property | WordPress Mapping | Details |
“jcr:title” | Page Title | This becomes the WordPress page title. |
“jcr:description” | Excerpt / Meta Description | Useful for SEO (e.g., via Yoast plugin). |
“header.title” | Custom Field (Header Title) | Created with ACF for easy management. |
“mainContent.text” | Main Page Content | Maps to the WordPress Editor. |
Automating content mapping with custom scripts
Now, let’s talk about automating this process. If we had to do all this manually, it would take forever, especially when dealing with thousands of pages. This is where custom scripts come in handy. You can use a language like JavaScript or Python to automate the migration.
Here’s a sample JavaScript migration script:Here’s an example of how you can do it with JavaScript and Axios. We’ll use Node.js to read the AEM JSON and send the content to WordPress.
const axios = require('axios');
const fs = require('fs');
// Load AEM data from JSON file
fs.readFile('aem_content.json', 'utf8', (err, data) => {
if (err) {
console.error('Error reading the AEM JSON file:', err);
return;
}
const aemData = JSON.parse(data);
const homepage = aemData?.homepage?.['jcr:content'];
if (!homepage) {
console.error('Invalid AEM data structure.');
return;
}
// Prepare data for WordPress
const wpData = {
title: homepage['jcr:title'],
content: homepage?.mainContent?.text || '',
excerpt: homepage['jcr:description'],
status: 'publish'
};
// WordPress REST API endpoint
const wpApiUrl = 'https://your-wordpress-site.com/wp-json/wp/v2/pages';
const username = 'your_username';
const password = 'your_application_password'; // Create an application password in WordPress
// Encode credentials for Basic Authentication
const encodedCredentials = Buffer.from(`${username}:${password}`).toString('base64');
// Send data to WordPress using Axios
axios
.post(wpApiUrl, wpData, {
headers: {
'Authorization': `Basic ${encodedCredentials}`,
'Content-Type': 'application/json'
}
})
.then(response => {
if (response.status === 201) {
console.log('Page created successfully:', response.data);
} else {
console.error('Failed to create page. Status:', response.status);
}
})
.catch(error => {
console.error('Error creating the page:', error.response ? error.response.data : error.message);
});
});
Metadata mapping
Map AEM’s custom metadata (like SEO tags, authors, publication dates) to fields in WordPress, possibly using plugins like Yoast SEO.
Mapping content hierarchies and URL structures
It’s important to keep URL structures intact for SEO. For instance, an AEM URL like /services/cloud-solutions should ideally be preserved in WordPress to avoid breaking links.
(We will see these in detail in the migration section.)
AEM to WordPress content mapping elements
AEM Component | WordPress Equivalent | Action Needed / Tools | Details |
Page Nodes (cq:Page) | Pages or Posts | Map AEM pages to WordPress Pages or Posts | Use the WordPress REST API to create new Pages or Posts. Preserve titles, slugs, and metadata. |
Structured Content (cq:PageContent) | Custom Post Types (CPTs) | Use Custom Post Types UI or custom code to define CPTs | For content that doesn’t fit WordPress standard posts/pages (e.g., Locations, Policies). |
Digital Assets (DAM) | Media Library | Use the WordPress Media Library REST API to upload | Download assets from AEM DAM, then upload to WordPress and update content links. |
Metadata (jcr:description, dc:title) | Yoast SEO Metadata or Custom Fields | Map AEM metadata to SEO fields via Yoast SEO plugin | Use Advanced Custom Fields (ACF) if metadata requires custom handling beyond SEO. |
Images, Media, Videos | Media Library | Upload via REST API and link in content | Make sure to preserve ALT text, titles, and descriptions for accessibility and SEO. |
Tags and Categories | Tags and Categories | Define tags and categories in WordPress | Reflect the categorization and tagging structure from AEM to ensure content remains discoverable. |
Sub-pages / Page Hierarchies | Parent-Child Page Relationships | Maintain relationships using WordPress Page attributes | Use a hierarchical structure in WordPress to retain SEO and user navigation paths. |
Content Fragments | Reusable Blocks or CPTs | Create Reusable Blocks in Gutenberg | Use Custom Post Types if the content fragment is used across multiple sections but requires custom fields. |
Embedded Components (sling:resourceType) | Gutenberg Blocks or Shortcodes | Develop custom Gutenberg blocks or use shortcodes | Convert AEM-specific components (e.g., carousels, callouts) to Gutenberg blocks for better editing flexibility. |
Forms (AEM Forms) | Gravity Forms or Contact Form 7 | Use a form builder plugin to recreate the forms | Migrate submission data as CSV and import into Gravity Forms or another plugin. Preserve all form fields and logic. |
User Roles | WordPress User Roles | Use User Role Editor to create custom roles if needed | Map AEM user roles to WordPress (e.g., Author, Editor). Custom roles may need to be created to match AEM capabilities. |
Permissions (rep:Policy) | Custom Capabilities | Use User Role Editor or Members plugin | If AEM has specific access control, create custom roles with equivalent permissions in WordPress. |
URL Structure | Permalink Structure and 301 Redirects | Update permalinks to match AEM URLs or use a Redirection plugin | Ensure consistent URLs for SEO purposes. Create 301 redirects for any changes. |
Workflows (cq:workflow) | Editorial Workflows (via plugins) | Implement using plugins like Edit Flow or PublishPress | Workflows in AEM can be recreated to manage content creation and approval processes in WordPress. |
Taxonomy (tags, categories) | Custom Taxonomies | Use Custom Taxonomies to replicate AEM content categories | Preserve the same tagging and categorization schema for consistent content organization. |
Analytics (Adobe Analytics) | Google Analytics or another Analytics Plugin | Embed tracking codes into theme files or use Site Kit | Export historical data from Adobe Analytics to maintain reporting continuity. Implement new tracking tags in WordPress. |
Experience Fragments | Reusable Content Blocks | Convert to Gutenberg Reusable Blocks | Experience fragments from AEM can be turned into reusable blocks for use in various parts of the site. |
Personalization (targeted components) | Personalization Plugins or custom coding | Use WP Engine Personalization or custom scripts | AEM personalizations need to be replaced by plugins or custom logic for targeted content delivery in WordPress. |
Language Copies / Translation | Multilingual Plugin (e.g., WPML, Polylang) | Use a plugin to manage language copies and translations | Ensure that translated pages in AEM are properly mapped to translated pages in WordPress using a multilingual plugin. |
Redirect Rules | Redirection Plugin | Set up using the Redirection Plugin in WordPress | Migrate existing AEM redirect rules to WordPress to maintain SEO and user experience. |
Scripts and Integrations | Code Snippets Plugin or in Theme Files | Add tracking codes, third-party integrations manually | Scripts for services like analytics, CRMs, or marketing tags should be placed in theme files or using plugins like Insert Headers and Footers. |
Embedded Video and Media | Gutenberg Video Block or Shortcode | Insert media using Gutenberg video blocks or via oEmbed URLs | Ensure that all media URLs are preserved, and use responsive video blocks for mobile compatibility. |
DAM Renditions | Image Sizes (Responsive Images) | Upload different image sizes to WordPress Media Library | Replicate AEM DAM renditions by generating multiple image sizes for different screen resolutions using WordPress. |
Forms Data (Submitted Responses) | Gravity Forms Entries | Export form submissions from AEM and import to Gravity Forms | Ensure data is imported properly to preserve user information and past submissions. |
Author Information | Custom User Meta | Use ACF to create additional fields for author details | AEM’s author data like biographies can be added to WordPress using custom user meta fields or ACF. |
Vanity URLs (vanityUrl property) | Custom Redirects | Use Redirection Plugin for vanity URLs | Set up vanity URLs in WordPress to redirect to their target pages, preserving any custom short URLs. |