<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Complex CMS Migration Service - Migrate Content</title><link>https://migratecontent.com/</link><description>Complex, business-critical CMS migrations for digital agencies and site owners. E-commerce, custom content types, zero-downtime. All Drupal versions.</description><atom:link href="https://migratecontent.com/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Tue, 24 Mar 2026 17:27:02 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Platform Migrations Aren't Website Design Projects</title><link>https://migratecontent.com/platform-migrations-arent-website-design-projects/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;figure&gt;&lt;img src="https://migratecontent.com/images/posts/platform-migrations-arent-website-projects-og-1200x630.jpg"&gt;&lt;/figure&gt; &lt;p class="intro"&gt;Platform migrations fail more often than they should. The cause, rather than being bad work, is almost always because everyone involved missed key considerations they didn't know about. If you're a business or agency moving from a legacy platform to WordPress, Shopify, BigCommerce, or any modern CMS, this article will help you understand where migration projects go wrong and how to avoid a massive headache.&lt;/p&gt;

&lt;h2&gt;How the Mismatch Happens&lt;/h2&gt;

&lt;p&gt;A business hires a design agency because...well, that's who builds websites, right? The agency does what they're good at, like design, templates, front-end development. However, a platform migration isn't just a website redesign. There's a whole integration layer underneath. Payment gateways, ERPs, subscription management, accounting feeds, and all that needs to be rebuilt on the new platform. Unless you've hired a Big Agency, all that work sits outside what most shops are set up to deliver. There's no-one on the team who can spot the gaps until the project is already underway, and that's when things get expensive.&lt;/p&gt;

&lt;p&gt;Here's how things usually start. The agency scopes what they've been asked to scope. They'll put together a proposal covering design, templates, front-end build, maybe some content migration. It's good work and it's what they do every day. The problem is that any business that's been running for more than a couple of years will have accumulated a stack of connected systems, and those connections are where the real complexity lives.&lt;/p&gt;

&lt;p&gt;If you haven't been through one of these projects before, you'll have no idea about how complex things can get.&lt;/p&gt;

&lt;p&gt;So you end up with a project where the visible part is moving along nicely but the bit that actually determines success for the business isn't on anybody's plan. Someone dropped the ball. They just didn't realise it because they didn't have the expertise to know better. So the project was framed as a website build from the start when it was far bigger.&lt;/p&gt;

&lt;h2&gt;What's Actually Underneath&lt;/h2&gt;

&lt;p&gt;This type of project is my bread and butter, and the pattern is almost always the same regardless of the platform. An e-commerce business moving between platforms will typically have five to ten third-party systems all wired together. Payment gateways (Stripe, PayPal, sometimes both plus the platform's own), subscription management, an ERP for fulfilment, something piping transactions into the accounting software, a marketing automation tool, and usually a couple more that nobody remembered to mention at the start. Large content-heavy sites, like news publishers and membership organisations, have a different but equally complex set of dependencies: editorial workflows, access control, syndication feeds, and integrations with publishing tools or paywall systems.&lt;/p&gt;

&lt;p&gt;All of those systems talk to each other through APIs and webhooks, and every one of those connections has to be unpicked, understood, and reassembled on the new platform. This is assuming the new platform even supports them the same way, which isn't always the case. So the finance team can't sign off on going live until the ERP integration works; without it they have no way to record sales. The marketing team can't run their relaunch campaign until they know the date is solid. Customer service needs the new subscription management system working before they can handle enquiries. And all of that has to be coordinated across vendors who live in silos and don't report to each other.&lt;/p&gt;

&lt;p&gt;That's plumbing, not page design.&lt;/p&gt;

&lt;p&gt;Somebody needs to map all of it before anyone writes a line of code or designs a single page. When I come onto a migration project, the first thing I do is a structured discovery phase. I know from experience that it's vital to document how everything on the old platform translates to the new one. This means how the business actually operates as well as code and third-party services. On one project that meant cataloguing requirements across business processes, integrations, customer workflows, and admin functions. It's not glamorous work, but without it you're building on guesswork.&lt;/p&gt;

&lt;h2&gt;Where the Gap Opens Up&lt;/h2&gt;

&lt;p&gt;The agencies on these projects are usually good shops. They have strong portfolios and experienced teams. (Why else would they have been hired in the first place?) But a few weeks in, the client asks for an architecture diagram showing how the integrations connect and the agency's response is some version of "the integrations aren't part of our scope."&lt;/p&gt;

&lt;p&gt;And quite honestly, they usually have a point. They were hired to design and build a website. The contract was broad enough that "design and build" could cover anything from a complete platform implementation to what one client described to me as "a set of pretty pictures." The scope gap was there from day one but it took time for anyone to notice.&lt;/p&gt;

&lt;aside class="pullquote"&gt;
&lt;blockquote class="blockquote text-center red p-0"&gt;
&lt;p&gt;The contract was broad enough that "design and build" could cover anything from a complete platform implementation to "a set of pretty pictures."&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/aside&gt;

&lt;p&gt;On another project, the agency lead had to explain to the client that back-end functionality was the platform vendor's responsibility, right at the point when everyone was expecting to see the site actually working. That's a reasonable assumption if you're used to building marketing sites where the platform handles everything out of the box. But none of that mattered half-way into the project. Somebody still needed to deal with the payment token migration, the subscription data, the ERP integration, the accounting feeds, and the go-live sequencing. No-one on the team had the expertise and I was hired too late, just when the migration was about to begin.&lt;/p&gt;

&lt;p&gt;So I ended up building the requirements specification, the business process documentation, the test case templates, and the go-live checklist, because if I didn't, nobody would.&lt;/p&gt;

&lt;p&gt;There's a similar problem on the technical side. An experienced developer who's strong in one stack can usually pick up a new platform by reading the documentation. Under normal circumstances that's fine but a migration project doesn't give you the luxury of a learning curve. You're already juggling a whole bunch of unknowns. Figuring out an unfamiliar platform on top of all that leads to delays, wrong decisions that have to be unpicked later, and problems that don't surface until you're about to go live.&lt;/p&gt;

&lt;h2&gt;Business Analysis Is Boring. It's Also the Most Important Part.&lt;/h2&gt;

&lt;p&gt;Here's something I learned very early on doing site migrations for businesses. There's more at stake than for a hobby site so before anyone writes a line of code or designs a single page, someone needs to sit down and understand how the business actually operates. How do orders flow from the website through to fulfilment and accounting? What happens when a customer modifies a subscription, or requests a return, or changes their payment method? For a content-heavy site, the questions are different but equally important: how does content move from draft to publication, and what integrations feed content to apps, newsletters, or syndication partners? What are the dependencies between systems, and which ones are hard blockers for going live?&lt;/p&gt;

&lt;p&gt;This is business analysis, and it's not something most design agencies do because it's not really their job. Their project managers are, quite rightly, geared towards managing creative output, not mapping data flows between an ERP and an accounting package.&lt;/p&gt;

&lt;p&gt;There was one migration where the client's finance manager had flagged a hard dependency: the invoice consolidation between the ERP and their accounting software wasn't ready for the new platform. Without it, they couldn't record sales correctly and this would be a complete blocker at go-live. This fell through the gaps and went unnoticed. Again, I was hired too late and only found it because I sat down with the finance team in a discovery session. I asked boring questions about how they actually do their job, then documented everything.&lt;/p&gt;

&lt;p&gt;I say boring deliberately. One thing's for sure: migration work is genuinely unglamorous. Agencies take it on because they want the fun creative work. Migrations are about spreadsheets, data mapping, test cases and checklists. It needs a methodical, detail-oriented mindset, rather than creative genius. Of course, the flashy design work is important as that's what customers see, but it's really not the core of a migration project. The core is making sure that everything underneath still works when you flip the switch.&lt;/p&gt;

&lt;h2&gt;Going Live Is Not "Take the Site Down for a Bit"&lt;/h2&gt;

&lt;p&gt;So it's time to go live. I've lost count of how many times someone has suggested taking the site down for a period during the switchover. Put up a holding page, swap everything over, bring the new site up.&lt;/p&gt;

&lt;p&gt;This works for a brochure site. A mature e-commerce platform with active subscribers, daily transactions, and payment processing is a different beast. Taking the site down means customers can't place orders, subscriptions don't renew, and the business stops generating revenue. For a news or publishing site, downtime means missed deadlines and broken feeds to syndication partners. And if the switchover hits problems (you can't guarantee it won't, no matter how well you plan), "a few hours" can turn into days unless you have a rollback mechanism.&lt;/p&gt;

&lt;p&gt;This is why I plan different go-live scenarios for every migration. Usually there's a hard switchover and a phased approach where both platforms run in parallel during the transition. The phased approach works like this: the new site is built and tested on staging. We then do an import of historical and current transactions while the live site keeps running. A final delta migration captures any content or orders that came in. Then a DNS cutover switches traffic to the new site with no interruption. If something goes wrong, you roll back. The business keeps running either way.&lt;/p&gt;

&lt;p&gt;Most of the projects I work on end up going with some version of the phased approach, because when you actually sit down with the finance and operations teams and walk through the implications of downtime, nobody wants to take the risk of a hard switchover.&lt;/p&gt;

&lt;aside class="pullquote"&gt;
&lt;blockquote class="blockquote text-center red p-0"&gt;
&lt;p&gt;A go-live plan that only involves the developers is a go-live plan that's going to cause huge problems for the business.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/aside&gt;

&lt;p&gt;It's not just operations and finance you have to factor in. Marketing will often have planned a campaign around the relaunch, with email sequences, social media announcements, and partner notifications all timed to a specific date. Customer service needs to know what's changing and when, because they're the ones fielding calls from confused subscribers. Even the fulfilment team needs advance notice if order processing is going to look different on the new platform.&lt;/p&gt;

&lt;p&gt;A go-live plan that only involves the developers is one that's going to cause huge problems.&lt;/p&gt;

&lt;h2&gt;Coordinating the Moving Parts&lt;/h2&gt;

&lt;p&gt;Here's a question that often falls through the gaps: who's responsible for coordinating everyone? What I usually see is the agency assuming the client will do it, and the client assuming the agency will do it. However, a migration for a typical business has the design agency, the platform vendor, one or two third-party integration providers, maybe a specialist for payment token migration, and the client's own team. Everyone's working to different timelines, different priorities, and a different understanding of what's in scope.&lt;/p&gt;

&lt;p&gt;Design agency project managers are good at managing creative workflows. They track design approvals, development sprints, and QA cycles. But coordinating a migration is a different discipline since you're not just managing one team's output. You also have to track dependencies across multiple independent vendors, any one of whom can block the whole project.&lt;/p&gt;

&lt;p&gt;For example, the ERP provider might need the new platform's API credentials before they can start testing. The payment migration can't happen until the subscription system is configured. The accounting integration needs to be verified before finance will sign off on going live.&lt;/p&gt;

&lt;p&gt;Some of this is sequential while some has to run in parallel. If nobody's responsible for tracking how the pieces connect, one delay can stall the whole project. I've seen this happen many times.&lt;/p&gt;

&lt;p&gt;For example, there was a time when the agency PM was tracking their design milestones while three integration workstreams were running completely independently with no coordination between them. Everyone was doing their job well, but in silos. Again I was hired well after the migration project started (notice a pattern?) so I needed to centralise everything into a single project management system. That way, when an issue came up in one workstream that would block another, I could flag it before it caused a delay rather than discovering it two weeks later.&lt;/p&gt;

&lt;aside class="pullquote"&gt;
&lt;blockquote class="blockquote text-center red p-0"&gt;
&lt;p&gt;Who's responsible for coordinating everyone? The agency assumes the client will do it, and the client assumes the agency will do it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/aside&gt;

&lt;p&gt;And the content migration itself is iterative. People assume you run it once and you're done, but it rarely works like this for a business-critical migration. In practice, it takes multiple iterations to get right. You run a sample, find edge cases, adjust the processes, then run it again. The client's own content editors need to be involved in quality assurance because they know the nuances of how the content should be structured in ways that no external consultant ever will. It's a back-and-forth process that takes patience and attention to detail.&lt;/p&gt;

&lt;h2&gt;Why It Keeps Happening&lt;/h2&gt;

&lt;p&gt;I've seen two different agencies attempt the same migration, one after the other. Months of work, tens of thousands spent, and both hit the same wall. The design work was solid but nobody owned the integration layer.&lt;/p&gt;

&lt;p&gt;When two good agencies hit the same problem on the same project, that's a structural problem. The good news is it doesn't have to go down this way. Agencies that recognise the gap early and bring in the right expertise for the integration side end up delivering better projects and keeping their clients happy.&lt;/p&gt;

&lt;h2&gt;Before You Start: What to Check&lt;/h2&gt;

&lt;p&gt;If you're a business planning a migration, or an agency about to take one on, here are the questions worth asking before anything gets signed.&lt;/p&gt;

&lt;h3&gt;For business owners&lt;/h3&gt;

&lt;table class="table table-bordered"&gt;
&lt;thead&gt;&lt;tr&gt;&lt;th&gt;#&lt;/th&gt;&lt;th&gt;Question&lt;/th&gt;&lt;th&gt;Why it matters&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;How many third-party systems are connected to your current platform?&lt;/td&gt;&lt;td&gt;More than two or three and you're looking at a systems integration project, not a website redesign. The risk is in the connections, not the pages.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Does your agency contract cover back-end configuration and integrations, or just design and front-end build?&lt;/td&gt;&lt;td&gt;If the contract says "design and build" without specifying integrations, nobody owns the plumbing. Clarify this before work starts.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Has anyone mapped your business processes onto the new platform?&lt;/td&gt;&lt;td&gt;How do orders, subscriptions, returns, and payments actually flow through your systems? If nobody has documented this, critical dependencies will surface mid-project.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;What's the go-live plan? Is anyone suggesting "take the site down for a bit"?&lt;/td&gt;&lt;td&gt;For active e-commerce with subscribers and daily transactions, downtime means lost revenue. You need a cutover plan with a rollback option.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Who is coordinating the work across all your vendors?&lt;/td&gt;&lt;td&gt;If that's not clearly assigned to a named person, it's not happening.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;Have you involved finance, marketing, operations, and customer service in the go-live plan?&lt;/td&gt;&lt;td&gt;Finance needs accounting integrations working. Marketing has campaigns timed to launch. Operations and customer service need to know what's changing. If any of these teams are surprised on go-live day, you have a problem.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3&gt;For agencies&lt;/h3&gt;

&lt;table class="table table-bordered"&gt;
&lt;thead&gt;&lt;tr&gt;&lt;th&gt;#&lt;/th&gt;&lt;th&gt;Question&lt;/th&gt;&lt;th&gt;Why it matters&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;How many third-party integrations does the client's current platform have?&lt;/td&gt;&lt;td&gt;More than two or three and the project is bigger than a website build. Scope accordingly.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Is back-end configuration and integration work in your scope?&lt;/td&gt;&lt;td&gt;If it isn't, say so clearly in the contract. "Design and build" is ambiguous enough to cause problems later. Specificity protects both sides.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Does the client need business continuity during the switchover?&lt;/td&gt;&lt;td&gt;If the client has subscribers, recurring payments, or daily transactions, someone needs to plan a phased cutover. That someone probably isn't your PM.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;Does your team have direct experience with the target platform's APIs and back-end?&lt;/td&gt;&lt;td&gt;Front-end design skills don't transfer to API-driven integration work. If your developers are strong in WordPress but the target is BigCommerce or Shopify Plus, you probably need a specialist.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Do you need a systems integration partner?&lt;/td&gt;&lt;td&gt;Bringing in someone for business analysis, integration work, and vendor coordination lets your team focus on design and build. It protects the client relationship and it protects yours.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h2&gt;What It Looks Like When It Works&lt;/h2&gt;

&lt;p&gt;When a migration project has the right structure, what the client gets is straightforward: a complete picture of their system before any work begins; a clear scope that everyone has signed off on; a go-live plan that protects revenue; and a single point of coordination across all their vendors. The agency gets to focus on what they're best at without being blamed for integration failures that were never in their scope.&lt;/p&gt;

&lt;p&gt;That's what I provide on these projects. The article you've just read is basically my job description and sometimes it requires telling people things they don't want to hear. That once meant recommending the client terminate the project entirely. They kept their existing platform and their active subscribers, and avoided pouring more money into a project that wasn't going to succeed. That recommendation was harder to make than it sounds because I was being paid to oversee the project. Not only are you telling a client who's already spent tens of thousands that the best use of that money was the lesson it taught them, it also meant money out of my pocket. But it was the right call, and they agreed.&lt;/p&gt;

&lt;h2&gt;Get Someone in the Room on Day One&lt;/h2&gt;

&lt;p&gt;If there's one thing I'd want someone to take away from this article, it's this: bring in someone to own the whole picture from day one. Right at the start, when the project is being scoped and the contracts are being written.&lt;/p&gt;

&lt;p&gt;By the time the agency has been hired and the work is underway, it's too late. The structural gaps are already baked in.
&lt;/p&gt;

&lt;p&gt;That person doesn't have to be a specialist migration consultant but at the very least, it should be an experienced project manager. Someone who understands multi-vendor coordination and systems integration; someone who's going to map the data flows and business processes before anyone starts designing pages. If you have that person in-house, great. If you don't, that's what I do.&lt;/p&gt;

&lt;p&gt;If you're a business looking at a migration with a serious integration layer, have a look at &lt;a href="https://migratecontent.com/services/"&gt;how I handle these projects&lt;/a&gt; or &lt;a href="https://migratecontent.com/content-migration-process/"&gt;the process I follow&lt;/a&gt;. If you're an agency and you'd rather bring in someone to handle the business analysis, integration work, and multi-vendor coordination while you focus on the design and build, I work that way too. I'm based in London and work with clients and agencies across the UK and internationally.&lt;/p&gt;

&lt;section class="mt-4 pt-4"&gt;
&lt;h2 class="text-center pb-4"&gt;Common Questions&lt;/h2&gt;
&lt;div class="container border bg-light p-4"&gt;
&lt;p&gt;&lt;strong&gt;Why do platform migration projects go wrong?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It's usually not the agency's fault. Design agencies get hired for the website but the integration layer underneath (payment gateways, ERP connections, subscription management, accounting feeds) needs to be rebuilt too. When the contract doesn't specify who owns that work, the project is already underway by the time the gap becomes visible. The most common pattern is that nobody with systems integration expertise was involved when the project was scoped.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What systems need to be migrated besides the website?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A typical e-commerce platform migration involves five to ten connected third-party systems. Payment gateways (Stripe, PayPal), subscription management, an ERP for fulfilment, accounting integrations, marketing automation tools, and more. Every one of those connections has to be rebuilt and tested on the new platform before you can go live.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do I still need a design agency for my platform migration?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Probably yes. Design agencies handle the visual output well: wireframes, mockups, page templates, front-end code. But you also need someone who understands the business processes and systems underneath, and can coordinate the integration work across vendors. These are different disciplines, and the best results come from having both covered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I know if my migration is too complex for a design agency alone?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Count how many third-party systems feed data into or out of your current platform. More than two or three and the risk isn't in the page design, it's in the integration layer. If you've got payment gateways, an ERP, subscription management, or accounting feeds connected to your platform, you need someone looking at the whole system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I'm an agency. How do I avoid this problem on migration projects?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Be upfront about scope from day one. If the project has a serious integration layer, flag it early and bring in someone to handle the business analysis and systems integration side. It protects your client relationship, keeps the project on track, and lets your team focus on the design and build work you're best at.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why can't we just take the site down during the migration?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For a brochure site, brief downtime might be acceptable. For an active e-commerce platform or a high-traffic content site, taking the site down means lost revenue, missed deadlines, and disrupted customers. Go-live needs a cutover plan that accounts for business continuity, with input from finance, marketing, operations, and customer service, not just the development team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When should I bring in a migration consultant?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At the very start, when the project is being scoped and contracts are being written. Most migration problems are structural gaps that get baked in early. By the time the agency is hired and work is underway, it's much harder to fix. If you can't hire a specialist, at the very least bring in an experienced project manager who understands multi-vendor coordination and systems integration.&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;

&lt;div class="mt-5"&gt;
    &lt;h2&gt;You may also like&lt;/h2&gt;

    &lt;div class="row"&gt;

      &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
            &lt;div class="card h-100"&gt;
                &lt;a href="https://migratecontent.com/how-we-migrate-technical-process/"&gt;
                        &lt;img src="https://migratecontent.com/images/featured-image-std.jpg" class="card-img-top" alt="How We Migrate: The Technical Process"&gt;&lt;/a&gt;
                &lt;div class="card-body d-flex flex-column"&gt;
                    &lt;h3 class="card-title"&gt;&lt;a href="https://migratecontent.com/how-we-migrate-technical-process/" class="listtitle"&gt;How We Migrate: The Technical Process Behind a Migration&lt;/a&gt;&lt;/h3&gt;
                        &lt;p class="card-text flex-grow-1"&gt;A look inside the technical process of a custom migration. Database mapping, custom scripts, iterative testing, and zero-downtime launch.&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

      &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
            &lt;div class="card h-100"&gt;
                &lt;a href="https://migratecontent.com/why-automated-migration-tools-fail/"&gt;
                        &lt;img src="https://migratecontent.com/images/featured-image-std.jpg" class="card-img-top" alt="Why Automated Migration Tools Fail"&gt;&lt;/a&gt;
                &lt;div class="card-body d-flex flex-column"&gt;
                    &lt;h3 class="card-title"&gt;&lt;a href="https://migratecontent.com/why-automated-migration-tools-fail/" class="listtitle"&gt;Why Automated Migration Tools Fail for Complex Sites&lt;/a&gt;&lt;/h3&gt;
                        &lt;p class="card-text flex-grow-1"&gt;Why off-the-shelf migration tools fall short for complex sites, and when custom scripting is the only reliable option.&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;

      &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
            &lt;div class="card h-100"&gt;
                &lt;a href="https://migratecontent.com/preserving-seo-drupal-wordpress-migration/"&gt;
                        &lt;img src="https://migratecontent.com/images/featured-image-std.jpg" class="card-img-top" alt="Preserving Your SEO During a Migration"&gt;&lt;/a&gt;
                &lt;div class="card-body d-flex flex-column"&gt;
                    &lt;h3 class="card-title"&gt;&lt;a href="https://migratecontent.com/preserving-seo-drupal-wordpress-migration/" class="listtitle"&gt;Preserving Your SEO During a Migration&lt;/a&gt;&lt;/h3&gt;
                        &lt;p class="card-text flex-grow-1"&gt;SEO is consistently the number one concern for site owners considering a migration. With proper planning, your search rankings can survive the transition intact.&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class="mt-4 pt-4 text-muted small border-top border-bottom"&gt;
    &lt;h2 class="text-muted small"&gt;Footnotes&lt;/h2&gt;
    &lt;ul&gt;
      &lt;li&gt;Photo by &lt;a href="https://unsplash.com/@kylejglenn?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="nofollow"&gt;Kyle Glenn&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/white-metal-water-pipe-near-grass-Qo4gei6NvcQ?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="nofollow"&gt;Unsplash&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;

&lt;script type="application/ld+json"&gt;
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Why do platform migration projects go wrong?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "It's usually not the agency's fault. Design agencies get hired for the website but the integration layer underneath (payment gateways, ERP connections, subscription management, accounting feeds) needs to be rebuilt too. When the contract doesn't specify who owns that work, the project is already underway by the time the gap becomes visible. The most common pattern is that nobody with systems integration expertise was involved when the project was scoped."
      }
    },
    {
      "@type": "Question",
      "name": "What systems need to be migrated besides the website?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "A typical e-commerce platform migration involves five to ten connected third-party systems. Payment gateways (Stripe, PayPal), subscription management, an ERP for fulfilment, accounting integrations, marketing automation tools, and more. Every one of those connections has to be rebuilt and tested on the new platform before you can go live."
      }
    },
    {
      "@type": "Question",
      "name": "Do I still need a design agency for my platform migration?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Probably yes. Design agencies handle the visual output well: wireframes, mockups, page templates, front-end code. But you also need someone who understands the business processes and systems underneath, and can coordinate the integration work across vendors. These are different disciplines, and the best results come from having both covered."
      }
    },
    {
      "@type": "Question",
      "name": "How do I know if my migration is too complex for a design agency alone?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Count how many third-party systems feed data into or out of your current platform. More than two or three and the risk isn't in the page design, it's in the integration layer. If you've got payment gateways, an ERP, subscription management, or accounting feeds connected to your platform, you need someone looking at the whole system."
      }
    },
    {
      "@type": "Question",
      "name": "I'm an agency. How do I avoid this problem on migration projects?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Be upfront about scope from day one. If the project has a serious integration layer, flag it early and bring in someone to handle the business analysis and systems integration side. It protects your client relationship, keeps the project on track, and lets your team focus on the design and build work you're best at."
      }
    },
    {
      "@type": "Question",
      "name": "Why can't we just take the site down during the migration?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "For a brochure site, brief downtime might be acceptable. For an active e-commerce platform or a high-traffic content site, taking the site down means lost revenue, missed deadlines, and disrupted customers. Go-live needs a cutover plan that accounts for business continuity, with input from finance, marketing, operations, and customer service, not just the development team."
      }
    },
    {
      "@type": "Question",
      "name": "When should I bring in a migration consultant?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "At the very start, when the project is being scoped and contracts are being written. Most migration problems are structural gaps that get baked in early. By the time the agency is hired and work is underway, it's much harder to fix. If you can't hire a specialist, at the very least bring in an experienced project manager who understands multi-vendor coordination and systems integration."
      }
    }
  ]
}
&lt;/script&gt;</description><category>agency</category><category>bigcommerce</category><category>ecommerce</category><category>magento</category><category>migration</category><category>platform-migration</category><category>project-management</category><category>shopify</category><category>systems-integration</category><category>woocommerce</category><guid>https://migratecontent.com/platform-migrations-arent-website-design-projects/</guid><pubDate>Sat, 21 Mar 2026 09:00:00 GMT</pubDate></item><item><title>Migrating Drupal Commerce to WooCommerce: What You Need to Know</title><link>https://migratecontent.com/migrating-drupal-commerce-to-woocommerce/</link><dc:creator>Aiden</dc:creator><description>&lt;p class="intro"&gt;A typical Drupal Commerce store has 15-20 interconnected database tables: products linked to variations, orders linked to customers, customers linked to addresses and payment tokens. Your online store isn't just content; it's a web of relationships where breaking any single thread corrupts the whole dataset. Here's what's involved in moving from Drupal Commerce to WooCommerce, and why this is one migration you shouldn't try to automate.&lt;/p&gt;

&lt;h2&gt;Why Automated Tools Fail for E-commerce&lt;/h2&gt;

&lt;p&gt;Tools like FG Drupal to WordPress, CMS2CMS, and similar migration plugins handle basic content well enough. However, e-commerce data has relationships that these tools can't handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Products have variations:&lt;/strong&gt; sizes, colours, configurations, each with their own pricing, stock levels, and SKUs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orders reference products, customers, and payments:&lt;/strong&gt; a single order connects to multiple data entities that must arrive together&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom fields and attributes:&lt;/strong&gt; most Drupal Commerce stores have custom product fields that don't map directly to WooCommerce's data model&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Payment gateway tokens:&lt;/strong&gt; stored payment methods and subscription billing need careful handling to maintain PCI compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automated tools treat content as flat data. E-commerce requires preserving the relationships between that data. That requires custom scripting.&lt;/p&gt;

&lt;p&gt;Nevertheless, understanding exactly what needs to move is the first step toward getting it right.&lt;/p&gt;

&lt;h2&gt;What Needs to Migrate&lt;/h2&gt;

&lt;p&gt;What needs to move depends on your store's configuration. A basic catalogue might only need products and categories, but most active stores have order history, customer accounts, and payment records that all need to come across intact.&lt;/p&gt;

&lt;h3&gt;Product Data&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Product titles, descriptions, and images&lt;/li&gt;
&lt;li&gt;Product variations (size, colour, etc.) with individual pricing and stock&lt;/li&gt;
&lt;li&gt;SKUs and inventory levels&lt;/li&gt;
&lt;li&gt;Custom product attributes and metadata&lt;/li&gt;
&lt;li&gt;Product categories and tags&lt;/li&gt;
&lt;li&gt;Related/cross-sell product relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Order History&lt;/h3&gt;
&lt;p&gt;Every order in Drupal Commerce is a composite record: line items, statuses (completed, pending, refunded), payment transaction IDs, shipping details with tracking numbers, and any internal notes attached by staff. All of this needs to arrive in WooCommerce with the relationships intact, so a customer's order history page shows the same information it did before.&lt;/p&gt;

&lt;h3&gt;Customer Data&lt;/h3&gt;
&lt;p&gt;Customer accounts carry login credentials, billing and shipping addresses, and their full order history. Reviews and ratings need to transfer with the correct author attribution. If your store uses wishlists or saved carts, that data is stored separately from the main commerce tables and needs its own migration path.&lt;/p&gt;

&lt;h2&gt;The Migration Process for E-commerce&lt;/h2&gt;

&lt;p&gt;E-commerce migration follows the same iterative approach I use for all complex migrations, with additional steps for the commercial data. The key difference is that Drupal Commerce and WooCommerce store data in fundamentally different ways. Drupal Commerce uses dedicated entity types for products and orders, while WooCommerce consolidates both as custom post types within &lt;code&gt;wp_posts&lt;/code&gt;. This means every migration requires custom mapping.&lt;/p&gt;

&lt;h3&gt;1. Commerce Audit&lt;/h3&gt;
&lt;p&gt;Before writing any migration code, I need to understand your store's data model. Drupal Commerce is highly customisable, which means every store is different. The audit maps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Product types and their field configurations&lt;/li&gt;
&lt;li&gt;Variation types and pricing rules&lt;/li&gt;
&lt;li&gt;Custom checkout flows and payment methods&lt;/li&gt;
&lt;li&gt;Tax and shipping configurations&lt;/li&gt;
&lt;li&gt;Any custom modules or business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;2. WooCommerce Architecture&lt;/h3&gt;
&lt;p&gt;Your Drupal Commerce data model won't map directly to WooCommerce's structure. Drupal Commerce product variations need to become WooCommerce variable products, and custom attributes need sorting into WooCommerce product attributes versus ACF fields. Pricing rules are another consideration: Drupal Commerce's rule-based pricing has no direct WooCommerce equivalent, so the logic often needs rebuilding with a combination of plugins. This planning stage determines which extensions are needed and prevents surprises during scripting.&lt;/p&gt;

&lt;h3&gt;3. Custom Migration Scripts&lt;/h3&gt;
&lt;p&gt;I write custom scripts that handle the relationships between products, orders, and customers as a connected dataset. The scripts run iteratively (typically 5-20 test migrations), with each cycle refining the data mapping and handling edge cases.&lt;/p&gt;

&lt;h3&gt;4. Payment Gateway Transition&lt;/h3&gt;
&lt;p&gt;This is often the most sensitive part of an e-commerce migration. Considerations include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stripe, PayPal, Authorize.net:&lt;/strong&gt; customer tokens and saved payment methods may transfer, depending on your gateway provider's API&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subscription billing:&lt;/strong&gt; active subscriptions need careful coordination between the old and new platforms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCI compliance:&lt;/strong&gt; payment data handling must comply with PCI-DSS requirements throughout the migration&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;5. Zero-Downtime Launch&lt;/h3&gt;
&lt;p&gt;E-commerce sites can't afford downtime. The migration uses a staged approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build and populate the WooCommerce store on a staging server&lt;/li&gt;
&lt;li&gt;Run multiple test migrations until data integrity is verified&lt;/li&gt;
&lt;li&gt;Execute a final delta migration to capture recent orders&lt;/li&gt;
&lt;li&gt;DNS cutover to the new site with no interruption to customers&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Common Pitfalls&lt;/h2&gt;

&lt;p&gt;These are the issues that catch teams off guard in Drupal Commerce to WooCommerce migrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Currency and tax configuration.&lt;/strong&gt; Drupal Commerce and WooCommerce handle tax differently. Make sure your tax rules are properly configured before launch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image handling.&lt;/strong&gt; Product images in Drupal Commerce may use different field structures than WooCommerce expects. Custom mapping is usually required.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URL structure.&lt;/strong&gt; Product URLs will likely change. A complete 301 redirect map is essential for SEO and for customers who have bookmarked products.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email templates.&lt;/strong&gt; Order confirmation, shipping notification, and other transactional emails need to be rebuilt in WooCommerce.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analytics continuity.&lt;/strong&gt; Make sure your analytics tracking carries over so you don't lose conversion data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Timeline and Investment&lt;/h2&gt;

&lt;p&gt;A Drupal Commerce to WooCommerce migration for a mid-size store (typically 1,000 to 10,000 products) takes around 6-10 weeks and starts at $8,400. The timeline depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of product types and variations&lt;/li&gt;
&lt;li&gt;Complexity of custom fields and business logic&lt;/li&gt;
&lt;li&gt;Volume of order history to migrate&lt;/li&gt;
&lt;li&gt;Payment gateway integration requirements&lt;/li&gt;
&lt;li&gt;Custom functionality that needs WordPress plugins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The investment protects against the real costs of a failed migration: lost orders, broken customer accounts, and SEO damage that can take months to recover from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/why-automated-migration-tools-fail/"&gt;Why Automated Migration Tools Fail for Complex Drupal Sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-we-migrate-technical-process/"&gt;How We Migrate: The Technical Process Behind a Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-7-end-of-life-migration-options/"&gt;Drupal 7 End of Life: Your Migration Options in 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/content-migration-process/"&gt;How the migration process works&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Planning a Drupal Commerce to WooCommerce Migration?&lt;/h2&gt;

&lt;p&gt;I've migrated Drupal Commerce stores with thousands of products, complete order histories, and customer reviews. Get a free consultation to discuss your store's requirements.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your e-commerce migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>drupal-commerce</category><category>e-commerce</category><category>migration</category><category>woocommerce</category><guid>https://migratecontent.com/migrating-drupal-commerce-to-woocommerce/</guid><pubDate>Thu, 05 Feb 2026 09:00:00 GMT</pubDate></item><item><title>Preserving Your SEO During a Drupal to WordPress Migration</title><link>https://migratecontent.com/preserving-seo-drupal-wordpress-migration/</link><dc:creator>Aiden</dc:creator><description>&lt;p class="intro"&gt;SEO is consistently the number one concern for site owners considering a Drupal to WordPress migration, and rightly so. Years of ranking authority, backlinks, and organic traffic are at stake. The good news is that with proper planning, your search rankings can survive the transition intact. The key is understanding exactly where the risks are and addressing each one systematically before launch.&lt;/p&gt;

&lt;h2&gt;Why Migration Puts Your SEO at Risk&lt;/h2&gt;

&lt;p&gt;Search engines index your site based on URLs, content structure, and metadata. A platform migration touches all three. When Google crawls your site after launch and finds different URLs, missing pages, or changed metadata, it needs to re-evaluate your content. That re-evaluation doesn't always go in your favour.&lt;/p&gt;

&lt;p&gt;The specific risks fall into four categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;URL changes.&lt;/strong&gt; Drupal and WordPress generate URLs differently. Without proper redirect mapping, every changed URL becomes a dead link in Google's index.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Missing metadata.&lt;/strong&gt; Meta titles, descriptions, and Open Graph data stored in Drupal modules don't transfer automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taxonomy page loss.&lt;/strong&gt; Drupal's vocabulary listing pages may drive significant traffic. If those pages disappear after migration, that traffic goes with them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Broken internal links.&lt;/strong&gt; Links embedded in content that point to old URL structures will return 404 errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;URL Structure: The Critical Difference&lt;/h2&gt;

&lt;p&gt;This is where most SEO damage occurs in Drupal to WordPress migrations. The two platforms handle URLs in fundamentally different ways.&lt;/p&gt;

&lt;h3&gt;How Drupal Handles URLs&lt;/h3&gt;

&lt;p&gt;Drupal stores URL aliases in the &lt;code&gt;url_alias&lt;/code&gt; (Drupal 7) database table, separate from the content itself. Each node can have multiple aliases: &lt;code&gt;/about-us&lt;/code&gt;, &lt;code&gt;/about&lt;/code&gt;, and &lt;code&gt;/node/28&lt;/code&gt; can all point to the same page. Aliases support forward slashes, allowing deep path structures like &lt;code&gt;/services/migration/drupal-to-wordpress&lt;/code&gt;. The character limit is 255.&lt;/p&gt;

&lt;h3&gt;How WordPress Handles URLs&lt;/h3&gt;

&lt;p&gt;WordPress stores a single slug in the &lt;code&gt;post_name&lt;/code&gt; field within &lt;code&gt;wp_posts&lt;/code&gt;. URLs are generated dynamically using rewrite rules based on your permalink settings. Slugs cannot contain forward slashes or quotation marks, and WordPress converts accented characters to their ASCII equivalents. The character limit is 200. Unlike Drupal, WordPress has no mechanism for storing multiple URL variations per page.&lt;/p&gt;

&lt;h3&gt;What This Means for Your Migration&lt;/h3&gt;

&lt;p&gt;Any Drupal alias that contains forward slashes, exceeds 200 characters, or includes special characters can't be replicated directly in WordPress. Each of these cases needs a 301 redirect from the old URL to the new one. For sites with hundreds or thousands of URL aliases, this mapping exercise is a significant piece of work, but it's non-negotiable if you want to preserve your rankings.&lt;/p&gt;

&lt;h2&gt;Building Your Redirect Map&lt;/h2&gt;

&lt;p&gt;The redirect map is the single most important SEO deliverable in any migration. It's a complete list that pairs every old Drupal URL with its new WordPress equivalent.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Export all Drupal URL aliases:&lt;/strong&gt; pull the complete URL alias table, including any &lt;code&gt;/node/NID&lt;/code&gt; paths that may be indexed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Map each alias to its WordPress URL:&lt;/strong&gt; based on your chosen permalink structure and any slug changes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Include taxonomy pages:&lt;/strong&gt; Drupal vocabulary listing pages (&lt;code&gt;/categories/topic-name&lt;/code&gt;) need redirects to their WordPress equivalents&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle user pages and views:&lt;/strong&gt; if your Drupal site has indexed user profiles or Views-generated pages, these need redirects too&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement as server-level redirects:&lt;/strong&gt; &lt;code&gt;.htaccess&lt;/code&gt; rules (Apache) or nginx rewrite rules are faster and more reliable than plugin-based redirects&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I implement redirects at the server level rather than through WordPress plugins. Server-level redirects execute before WordPress even loads, which means faster response times and no dependency on a plugin that might be deactivated or conflict with an update.&lt;/p&gt;

&lt;h2&gt;Meta Data Migration&lt;/h2&gt;

&lt;p&gt;Drupal sites typically store meta titles, descriptions, and Open Graph data through the Metatag module. This data lives in dedicated database tables, separate from node content. WordPress SEO plugins (Yoast, Rank Math, SEOPress) store equivalent data as key-value pairs in the &lt;code&gt;wp_postmeta&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;The migration involves exporting Drupal's metatag records and converting them into the format expected by your chosen WordPress SEO plugin. This isn't something automated migration tools handle, because each SEO plugin uses its own meta key naming convention.&lt;/p&gt;

&lt;p&gt;For high-value pages, I recommend a manual review of meta titles and descriptions during migration. A platform change is a good opportunity to tighten up metadata that's been neglected. However, wholesale rewrites should wait until after migration, once you've confirmed your baseline rankings are stable.&lt;/p&gt;

&lt;h2&gt;Taxonomy Pages and Listing Pages&lt;/h2&gt;

&lt;p&gt;Drupal's taxonomy system is more flexible than WordPress's default categories and tags. Drupal supports multiple vocabularies with custom fields, and each vocabulary can generate listing pages that rank independently in search results.&lt;/p&gt;

&lt;p&gt;Before migration, audit your analytics for taxonomy pages that drive meaningful traffic. These need explicit handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vocabulary-to-taxonomy mapping.&lt;/strong&gt; Decide which Drupal vocabularies become WordPress categories, tags, or custom taxonomies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Listing page URLs.&lt;/strong&gt; Drupal's &lt;code&gt;/taxonomy/term/NID&lt;/code&gt; and friendly alias paths need redirects to the equivalent WordPress archive pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom taxonomy templates.&lt;/strong&gt; If your Drupal taxonomy pages have custom layouts or additional content, you may need custom WordPress archive templates to replicate them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;What Gets Preserved Automatically&lt;/h2&gt;

&lt;p&gt;Not everything requires special handling. Several SEO elements transfer naturally because they're embedded in your content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Heading structure.&lt;/strong&gt; H1, H2, H3 tags within your content body come across as-is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Image filenames and alt text.&lt;/strong&gt; These are stored within the content HTML and transfer with the content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal link structure.&lt;/strong&gt; Links within content bodies migrate with the text, though the target URLs may need updating to match the new structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content freshness signals.&lt;/strong&gt; Publication dates can be preserved during migration, maintaining your content's age signals.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Common SEO Pitfalls&lt;/h2&gt;

&lt;p&gt;These are the issues I see most often in migrations that weren't properly planned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Forgetting the "Discourage search engines" checkbox.&lt;/strong&gt; WordPress has a setting under Settings &amp;gt; Reading that tells search engines not to index the site. It's often enabled during development and forgotten at launch. One checkbox can undo all your SEO work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Changing permalink structure after launch.&lt;/strong&gt; Pick your WordPress permalink structure before migration and don't change it afterwards. Every change invalidates your redirect map.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignoring pagination.&lt;/strong&gt; If your Drupal site has paginated listing pages that are indexed, those &lt;code&gt;?page=2&lt;/code&gt; URLs need handling too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skipping the XML sitemap.&lt;/strong&gt; Submit a new sitemap to Google Search Console immediately after launch. This accelerates re-crawling and helps Google discover your new URL structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not monitoring post-launch.&lt;/strong&gt; The first 4-6 weeks after migration are critical. Monitor Google Search Console for crawl errors, indexing drops, and 404 spikes. Address issues immediately. Delays compound the damage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;When to Invest in SEO Preservation&lt;/h2&gt;

&lt;p&gt;The level of SEO work depends on your site's organic traffic value. A brochure site with minimal search traffic needs basic redirect mapping and not much more. A content-heavy site with thousands of indexed pages and significant organic traffic justifies a thorough audit, complete redirect map, and post-launch monitoring programme.&lt;/p&gt;

&lt;p&gt;I assess this during the initial content audit and provide a recommendation based on your site's actual traffic profile. There's no point over-investing in SEO preservation for pages that don't drive business value, and equally, no point cutting corners on pages that do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-7-end-of-life-migration-options/"&gt;Drupal 7 End of Life: Your Migration Options in 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-prepare-drupal-wordpress-migration/"&gt;How to Prepare for Your Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/content-migration-process/"&gt;How the migration process works&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Concerned About Losing Your Search Rankings?&lt;/h2&gt;

&lt;p&gt;I build SEO preservation into every migration: URL mapping, 301 redirects, metadata transfer, and post-launch monitoring. Get a free consultation to discuss your site's SEO requirements.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your SEO-safe migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>drupal</category><category>migration</category><category>redirects</category><category>seo</category><category>wordpress</category><guid>https://migratecontent.com/preserving-seo-drupal-wordpress-migration/</guid><pubDate>Tue, 04 Nov 2025 09:00:00 GMT</pubDate></item><item><title>Drupal 7 End of Life: Your Migration Options in 2025</title><link>https://migratecontent.com/drupal-7-end-of-life-migration-options/</link><dc:creator>Aiden</dc:creator><description>&lt;p class="intro"&gt;Drupal 7 officially reached end of life on 5 January 2025, yet hundreds of thousands of websites are still running on the platform. If yours is one of them, you're now operating without security updates from the Drupal community. Here's what that means and what your realistic options are in 2025.&lt;/p&gt;

&lt;h2&gt;What Drupal 7 End of Life Actually Means&lt;/h2&gt;

&lt;p&gt;End of life means the Drupal Security Team no longer provides security advisories or patches for Drupal 7. This doesn't mean your site will immediately stop working. It means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No security patches.&lt;/strong&gt; New vulnerabilities won't be fixed by the community. Your site becomes increasingly exposed over time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No module updates.&lt;/strong&gt; Contributed modules (Views, Webform, Commerce, etc.) are no longer maintained for D7.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hosting pressure.&lt;/strong&gt; Many managed hosting providers are phasing out Drupal 7 support or adding surcharges.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compliance risk.&lt;/strong&gt; For sites handling personal data, running unsupported software may put you offside with GDPR, PCI-DSS, or industry-specific regulations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Three Realistic Options in 2025&lt;/h2&gt;

&lt;p&gt;The right path depends on your organisation's technical resources, budget, and long-term platform needs. However, all three options require action. Staying put is not a strategy.&lt;/p&gt;

&lt;h3&gt;Option 1: Extended Support (Short-Term Fix)&lt;/h3&gt;

&lt;p&gt;Several vendors offer paid extended support for Drupal 7, providing security patches beyond the official EOL date. This buys you time but doesn't solve the underlying problem.&lt;/p&gt;

&lt;p&gt;Extended support makes sense if you need 6-12 months to plan a proper migration, your site is low-risk (no e-commerce, no sensitive data), and budget constraints prevent moving immediately. It doesn't make sense if you're running Drupal Commerce (increasingly fragile on D7), handling sensitive user data, or you've already been on extended support for a year and the window is closing.&lt;/p&gt;

&lt;h3&gt;Option 2: Upgrade to Drupal 10/11&lt;/h3&gt;

&lt;p&gt;Drupal 10 and 11 are the current supported versions. However, upgrading from Drupal 7 is not a simple version bump. It's effectively a complete rebuild. Drupal 7 and Drupal 10 have fundamentally different architectures, templating systems, and content management approaches. This is a critical point that catches many organisations off guard.&lt;/p&gt;

&lt;p&gt;The work involved is substantial: a complete theme rebuild (PHPTemplate to Twig), module replacements (many D7 modules have no D10 equivalent), content migration using Drupal's Migrate API, and a custom code rewrite for any bespoke functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When this makes sense:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your team has strong Drupal expertise and wants to stay on the platform&lt;/li&gt;
&lt;li&gt;You have Drupal-specific functionality that's hard to replicate elsewhere&lt;/li&gt;
&lt;li&gt;Your organisation has invested heavily in Drupal training and workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Option 3: Migrate to WordPress&lt;/h3&gt;

&lt;p&gt;For many organisations, Drupal 7's end of life is the catalyst to move to WordPress. This is where the "it's a rebuild either way" reality becomes an opportunity. Since a D7-to-D10 upgrade requires complete theme reconstruction, module replacement, and content migration (the same work involved in moving to WordPress), it's worth evaluating whether a different platform better fits your needs going forward.&lt;/p&gt;

&lt;p&gt;WordPress powers approximately 43% of all websites globally. That scale translates into practical advantages:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why organisations choose WordPress:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lower ongoing costs.&lt;/strong&gt; Industry comparisons consistently show WordPress annual maintenance costs running lower than equivalent Drupal setups, primarily due to a larger developer talent pool and more affordable hosting options.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easier content management.&lt;/strong&gt; WordPress's block editor is more intuitive for non-technical content teams. Your marketing people can publish without developer involvement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E-commerce ready.&lt;/strong&gt; WooCommerce is mature and well-supported, with a vast plugin ecosystem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster time to market.&lt;/strong&gt; WordPress development is typically faster than equivalent Drupal work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That said, WordPress isn't a drop-in replacement. Several areas need careful handling:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you need to consider:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Custom content types.&lt;/strong&gt; Drupal's content type system is more flexible out of the box. WordPress handles this through plugins (ACF, Pods) or custom post types, but it requires planning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex permissions.&lt;/strong&gt; If your site uses Drupal's granular permission system extensively, this needs careful mapping to WordPress roles and capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E-commerce data.&lt;/strong&gt; Migrating from Drupal Commerce to WooCommerce requires specialist handling to preserve products, orders, customer accounts, and reviews.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO preservation.&lt;/strong&gt; URL structures differ between platforms. Proper 301 redirect mapping is essential to protect your search rankings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;What a Professional Migration Looks Like&lt;/h2&gt;

&lt;p&gt;Regardless of which platform you move to, a complex migration follows a predictable process. For most projects, this typically involves six stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Content audit:&lt;/strong&gt; inventory every content type, field, taxonomy, and relationship&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture mapping:&lt;/strong&gt; design the equivalent structure on the new platform&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom scripting:&lt;/strong&gt; write migration scripts tailored to your content structure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Iterative testing:&lt;/strong&gt; run 5-20 test migrations to catch edge cases&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO mapping:&lt;/strong&gt; map old URLs to new, set up 301 redirects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero-downtime launch:&lt;/strong&gt; staged migration with DNS cutover for business-critical sites&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process typically takes 4-12 weeks depending on complexity. Automated migration tools can handle basic content, but the specifics of a real Drupal 7 site (custom content types, complex field relationships, bespoke functionality) all require custom scripting.&lt;/p&gt;

&lt;h2&gt;The Cost of Waiting&lt;/h2&gt;

&lt;p&gt;Every month on unsupported Drupal 7 increases your risk. New vulnerabilities won't be patched, and as browsers, PHP versions, and third-party services evolve, compatibility issues will compound.&lt;/p&gt;

&lt;p&gt;I've worked on D7 sites where a single contributed module stored data across 15 custom database tables, structures that no automated tool even recognises. The longer those sites run without maintenance, the harder they are to unpick. Meanwhile, managed hosting providers are phasing out Drupal 7 support or adding surcharges for legacy environments.&lt;/p&gt;

&lt;p&gt;The migration itself doesn't get cheaper by waiting either. Developer availability tightens as the remaining Drupal 7 talent pool moves on, and the growing technical debt (outdated modules, unpatched core, ageing server dependencies) makes the eventual migration more complex and more expensive.&lt;/p&gt;

&lt;p&gt;If you're still on Drupal 7 in 2025, the time to act is now. Whether you choose Drupal 10 or WordPress, a well-planned migration protects your content, your SEO rankings, and your business.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-prepare-drupal-wordpress-migration/"&gt;How to Prepare for Your Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/preserving-seo-drupal-wordpress-migration/"&gt;Preserving Your SEO During a Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/migrating-drupal-commerce-to-woocommerce/"&gt;Migrating Drupal Commerce to WooCommerce: What You Need to Know&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/content-migration-process/"&gt;How the migration process works&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Need Help With Your Drupal 7 Migration?&lt;/h2&gt;

&lt;p&gt;I specialise in complex Drupal to WordPress migrations, including e-commerce, custom content types, and business-critical sites that need zero-downtime launches. Get a free, no-obligation consultation to discuss your options.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your Drupal 7 migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>drupal</category><category>drupal-7</category><category>migration</category><category>wordpress</category><guid>https://migratecontent.com/drupal-7-end-of-life-migration-options/</guid><pubDate>Wed, 05 Feb 2025 09:00:00 GMT</pubDate></item><item><title>Drupal 7 End of Life: Why WordPress is the Best Migration Option for Lower Maintenance Sites</title><link>https://migratecontent.com/drupal-7-end-of-life-why-wordpress-is-the-best-migration-option/</link><dc:creator>Aiden</dc:creator><description>&lt;figure&gt;&lt;img src="https://migratecontent.com/images/posts/drupal-7-end-of-life-why-wordpress-is-the-best-migration-option-og-1200x630.jpg"&gt;&lt;/figure&gt; &lt;p&gt;&lt;strong&gt;Drupal 7 will reach end-of-life in January 2025. Learn why migrating to WordPress makes sense for small businesses, agencies, and anyone looking for an affordable, flexible CMS solution.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Drupal 7 is reaching the end-of-life (EOL) on 5th January 2025. This means official support will stop, leaving &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#webinar-key-statistics"&gt;around 180,000 websites&lt;/a&gt; vulnerable to security risks, compatibility issues, and rising maintenance costs. If your site is still running on Drupal 7, it's time to make a decision.&lt;/p&gt;
&lt;p&gt;For many, upgrading to the latest version might seem like the logical next step. Currently Drupal 11, which was released in July 2024, the move from Drupal 7 isn't a simple update but rather, it will require a complete rebuild. For smaller teams, freelancers, or businesses, this can mean significant time, money, and stress.&lt;/p&gt;
&lt;p&gt;Drupal is well-suited for large, complex websites that require advanced functionality. This includes enterprise-level businesses, government portals, higher education institutions, and NGOs. That said, Drupal's steep learning curve and resource-intensive nature make it less suitable for small businesses or individuals who need a simple, low-maintenance website.&lt;/p&gt;
&lt;p&gt;This is where WordPress comes in. With its lower costs, ease of use, and massive community support, WordPress has become the go-to CMS for businesses who need a better balance of simplicity and functionality. Whether you're running a small agency, freelancing, or managing your own business site, WordPress offers a practical, future-proof solution.&lt;/p&gt;
&lt;h2 id="final-deadline-announced-after-multiple-extensions"&gt;Final Deadline Announced After Multiple Extensions&lt;/h2&gt;
&lt;p&gt;The Drupal Association has announced several end-of-life dates for Drupal 7 over the years:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/blog/drupal-7-8-and-9" target="_blank" rel="noopener noreferrer"&gt;Initially planned for November 2021&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/psa-2020-06-24" target="_blank" rel="noopener noreferrer"&gt;Extended to November 2022&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/psa-2022-02-23" target="_blank" rel="noopener noreferrer"&gt;Further extended to November 2023&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/psa-2023-06-07" target="_blank" rel="noopener noreferrer"&gt;Final extension to January 5, 2025&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The latest and final EOL date for Drupal 7 is January 5, 2025, was made to give organizations more time to migrate their websites to newer versions of Drupal or other platforms.&lt;/p&gt;
&lt;h2 id="what-happens-if-you-stay-on-drupal-7"&gt;What Happens If You Stay on Drupal 7?&lt;/h2&gt;
&lt;p&gt;It should go without saying that sticking with Drupal 7 after its End of Life isn't a viable long-term option because it will no longer receive official updates, security patches, or technical support.&lt;/p&gt;
&lt;p&gt;This leaves site owners and maintainers with a range of headaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Security Risks&lt;/strong&gt;: Without updates or security patches, your site becomes a prime target for hackers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility Issues&lt;/strong&gt;: Over time, browsers, APIs, and third-party tools will evolve, leaving your site unable to keep up. Things will start breaking—slowly at first, then all at once.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rising Costs&lt;/strong&gt;: Developers who still work with Drupal 7 are becoming harder to find, and their rates reflect that scarcity. Maintaining an outdated platform will only get more expensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're still on Drupal 7, the clock is ticking. It's time to start planning your next move.&lt;/p&gt;
&lt;h2 id="why-choose-wordpress-over-upgrading-drupal"&gt;Why Choose WordPress Over Upgrading Drupal?&lt;/h2&gt;
&lt;p&gt;WordPress has grown into the most widely used CMS in the world, &lt;a href="https://www.hostinger.co.uk/tutorials/wordpress-statistics" target="_blank" rel="noopener noreferrer"&gt;powering around 43%&lt;/a&gt; of websites and &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#webinar-key-statistics"&gt;229,000 of the top 1 million sites by traffic&lt;/a&gt;. Popularity isn't the only reason to choose WordPress though.&lt;/p&gt;
&lt;p&gt;For starters, it's easier to use because WordPress's intuitive interface means you don't need a developer for every little update. Your team can manage content, make changes, and even build pages without technical expertise.&lt;/p&gt;
&lt;p&gt;It's also more affordable. While both Drupal and WordPress are open-source, WordPress generally offers a better return on investment with &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#cost-considerations"&gt;lower build and maintenance costs&lt;/a&gt;. Drupal's complexity leads to higher development expenses and more costly, time-intensive updates.&lt;/p&gt;
&lt;p&gt;And then there's WordPress' massive global user base, which means there's no shortage of resources, tutorials, and developers. If you need help, it's easy to find.&lt;/p&gt;
&lt;h2 id="is-it-worth-upgrading-drupal"&gt;Is it Worth Upgrading Drupal?&lt;/h2&gt;
&lt;p&gt;Upgrading to Drupal 11 is an option, but it's not a simple one. Architecturally, the jump from Drupal 7 to 11 is massive. The two versions are so different that you're essentially rebuilding your site from scratch.&lt;/p&gt;
&lt;p&gt;For some organisations, that's fine. Nevertheless, if you're running a complex site with custom features that rely on Drupal's architecture, it might even be necessary. In fact, Drupal is often overkill for smaller businesses or agencies.&lt;/p&gt;
&lt;p&gt;Futhermore, Drupal has gravitated towards enterprise-level projects over the past few years so if you don't need that complexity, WordPress is a more practical, cost-effective choice.&lt;/p&gt;
&lt;h2 id="real-world-success-stories"&gt;Real-World Success Stories&lt;/h2&gt;
&lt;p&gt;During a recent &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/"&gt;WP Engine webinar&lt;/a&gt;, Emily Averill, Digital Marketing Director at Daniels Health, shared their reasons for migrating from Drupal 7 to WordPress:&lt;/p&gt;
&lt;blockquote class="blockquote red p-0"&gt;
    &lt;p&gt;&lt;em&gt;"The [Drupal] website wasn't a place that our team could work confidently or with pace or agility. It was a friction point, and so we wanted a platform that could grow with us as an organization...Yes, it was going to be a hard migration. But in order to achieve the outcome, the future state we really wanted, it was going to be worth it...Replatforming for us in reality has been easier than migrating from Drupal 7 to 10."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a common theme among businesses that have made the switch. WordPress's user-friendly interface and flexibility make it a better fit for teams that need to move quickly and efficiently.&lt;/p&gt;
&lt;h2 id="the-migration-process"&gt;The Migration Process&lt;/h2&gt;
&lt;p&gt;Migrating a site can feel overwhelming, especially if you've been on the same platform for years. Here's how I handle the process.&lt;/p&gt;
&lt;h3 id="the-process"&gt;The Process:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Project Discovery&lt;/strong&gt;: I analyse your requirements and site's content, custom features, user roles, and integrations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migration Planning&lt;/strong&gt;: I determine what needs to be migrated, what can be replaced with WordPress plugins, and what might need to be rebuilt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Solutions&lt;/strong&gt;: If WordPress doesn't have an out-of-the-box solution for something, I'll build it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimisation&lt;/strong&gt;: Once the migration is complete, I optimise your new site for performance, security, and scalability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Training&lt;/strong&gt;: I provide training so your team knows how to manage the new site.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By the time I'm finished, you'll have a site that's ready for the future.&lt;/p&gt;
&lt;h2 id="why-wordpress-is-the-smarter-choice-today"&gt;Why WordPress is the Smarter Choice Today&lt;/h2&gt;
&lt;p&gt;Continuing to build on outdated Drupal software not only increases complexity but also creates significant technology debt, making future development more costly and inefficient.&lt;/p&gt;
&lt;p&gt;As Scott Jones from Illustrate Digital explains in the WP Engine webinar, continuing on Drupal often means that new features and functionality are being developed on old underlying software and frameworks, which can hinder growth and innovation.&lt;/p&gt;
&lt;p&gt;In contrast, WordPress offers a modern, intuitive interface that empowers marketing teams to take control of content publishing without relying heavily on developers. Webinar panelist PeterJohn from Useful Group highlights that WordPress is more marketer focused, while also evolving its developer tools to rival or surpass Drupal.&lt;/p&gt;
&lt;p&gt;By migrating to WordPress, businesses can reduce costs, streamline workflows, and future-proof their digital presence.&lt;/p&gt;
&lt;h2 id="lets-talk"&gt;Let's Talk&lt;/h2&gt;
&lt;p&gt;If you're still running Drupal 7, it's time to make a move. Whether you're ready to migrate or just exploring your options, I'm here to help.&lt;/p&gt;
&lt;div class="alert alert-info text-center"&gt;
  &lt;h4 style="font-size:1.5em"&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-service/" title="Drupal to WordPress migration"&gt;Drupal to WordPress migration service&lt;/a&gt;&lt;/h4&gt;
  &lt;p&gt;&lt;strong&gt;Any Drupal version · All content · Custom content types · SEO · Plugins&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Get in touch today for a free quote. Let's figure out the best path forward for your site—and your business.&lt;/p&gt;

  &lt;button class="cta-button"&gt;
      &lt;a href="https://migratecontent.com/contact/" title="Contact me to inquire about my Drupal to WordPress migration service"&gt;Get a quote&lt;/a&gt;
  &lt;/button&gt;

&lt;/div&gt;

&lt;section class="mt-4 pt-4"&gt;
    &lt;h3 class="text-center pb-4"&gt;Drupal 7 End of Life Frequently Asked Questions&lt;/h3&gt;

    &lt;p&gt;These FAQs are drawn from the real-world experience of the &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/"&gt;WP Engine webinar&lt;/a&gt; panelists.&lt;/p&gt;
    &lt;div class="container border bg-light p-4"&gt;
        &lt;details&gt;
            &lt;summary&gt;Why are organizations moving away from Drupal?&lt;/summary&gt;
            &lt;p&gt;Several factors contribute to the shift away from Drupal, particularly Drupal 7, which reaches its end of life in January 2025. These include:&lt;/p&gt;
            &lt;ul&gt;
              &lt;li&gt;End of life for older versions: This necessitates full rebuilds, leading to significant effort and cost.&lt;/li&gt;
              &lt;li&gt;Technological debt: Building new features on outdated software creates challenges and limits agility.&lt;/li&gt;
              &lt;li&gt;Shifting decision-making: Marketing teams, who are most impacted by the CMS choice, now have a greater say, leading to a preference for more user-friendly platforms.&lt;/li&gt;
              &lt;li&gt;Rise of alternative platforms: Modern platforms like Next.js and WordPress offer attractive features and benefits.&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/details&gt;
        &lt;details&gt;
            &lt;summary&gt;What are the advantages of WordPress for marketing teams?&lt;/summary&gt;
            &lt;p&gt;WordPress offers several benefits that make it particularly appealing to marketers:&lt;/p&gt;
            &lt;ul&gt;
              &lt;li&gt;Intuitive content management: WordPress's user-friendly interface and familiar structure make it easy to learn and use, even for junior team members.&lt;/li&gt;
              &lt;li&gt;Ease of content publishing: The block-based editor and intuitive design streamline content creation and editing.&lt;/li&gt;
              &lt;li&gt;Extensive plugin ecosystem: A vast library of plugins provides seamless integration with marketing tools and services, expanding functionality without custom development.&lt;/li&gt;
              &lt;li&gt;Flexibility and agility: WordPress allows for quick site deployment and iterative improvements, enabling rapid responses to market changes and opportunities.&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/details&gt;
        &lt;details&gt;
            &lt;summary&gt;How does WordPress benefit technical teams?&lt;/summary&gt;
            &lt;p&gt;Beyond its marketing advantages, WordPress also offers benefits for developers:&lt;/p&gt;
            &lt;ul&gt;
              &lt;li&gt;
                &lt;strong&gt;Gentle learning curve:&lt;/strong&gt; The platform is relatively easy to learn, reducing the training burden and enabling faster onboarding of new team members.
              &lt;/li&gt;
              &lt;li&gt;
                &lt;strong&gt;Strong community support:&lt;/strong&gt; A large and active community provides ample resources, documentation, and support for troubleshooting and development.
              &lt;/li&gt;
              &lt;li&gt;
                &lt;strong&gt;Wide choice and flexibility:&lt;/strong&gt; WordPress offers a vast selection of themes, plugins, and development tools, allowing for customized solutions and integrations.
              &lt;/li&gt;
              &lt;li&gt;
                &lt;strong&gt;Scalability and adaptability:&lt;/strong&gt; WordPress can scale to accommodate large and complex websites, and its open-source nature allows for customization to meet specific needs.
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/details&gt;

&lt;details&gt;
  &lt;summary&gt;What happens to my Drupal 7 website after January 2025?&lt;/summary&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;strong&gt;No more updates:&lt;/strong&gt; Drupal will cease releasing feature developments and security updates for Drupal 7.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Increased security risks:&lt;/strong&gt; Without ongoing security patches, your website becomes vulnerable to exploits and attacks.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Limited functionality:&lt;/strong&gt; You will no longer receive updates for modules and themes, potentially impacting website performance and functionality.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/details&gt;

&lt;details&gt;
  &lt;summary&gt;How do I address security concerns about WordPress?&lt;/summary&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;strong&gt;Present data and evidence:&lt;/strong&gt; Share data on WordPress's adoption rate, security infrastructure, and the expertise of partners like WP Engine and specialised agencies.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Engage IT and security teams:&lt;/strong&gt; Involve them early in the decision-making process, address their concerns directly, and demonstrate how WordPress meets security standards.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Emphasise hosting and infrastructure:&lt;/strong&gt; Highlight the role of managed WordPress hosting providers like WP Engine in ensuring security, performance, and reliability.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/details&gt;

&lt;details&gt;
  &lt;summary&gt;Is it easier to upgrade to the latest Drupal version or migrate to WordPress?&lt;/summary&gt;
  &lt;ul&gt;
    &lt;li&gt;
      Upgrading to the latest Drupal version might seem simpler, but it can involve substantial effort due to significant code changes and underlying technology changes.
    &lt;/li&gt;
    &lt;li&gt;
      Migration complexity can be high regardless of whether you upgrade within Drupal or migrate to a different platform, especially with large amounts of content.
    &lt;/li&gt;
    &lt;li&gt;
      WordPress's iterative approach offers more frequent and gradual updates, minimising disruption and making it easier to maintain the site over time.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/details&gt;

&lt;details&gt;
  &lt;summary&gt;How is content migrated from Drupal to WordPress?&lt;/summary&gt;
  &lt;ol&gt;
    &lt;li&gt;
      &lt;strong&gt;Content evaluation:&lt;/strong&gt; Assess the existing content, identify what needs to be migrated, and determine if any cleansing or restructuring is required.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Data export:&lt;/strong&gt; Export content from Drupal using tools like the Views Export module to create structured data files.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Data import:&lt;/strong&gt; Utilise WordPress import plugins like WP All Import to bring the content into the new platform, with potential customisation for complex data structures.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Testing and validation:&lt;/strong&gt; Thoroughly test the migrated content to ensure accuracy, functionality, and proper display on the new WordPress site.
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/details&gt;

&lt;details&gt;
  &lt;summary&gt;What is a typical timeframe for a Drupal to WordPress migration project?&lt;/summary&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;strong&gt;Content migration:&lt;/strong&gt; Typically takes around 4 weeks, depending on the volume and complexity of the content.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Full website rebuild:&lt;/strong&gt; Including design, development, and content migration, can range from 5 to 12 months, depending on the scope and complexity of the project.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;strong&gt;Global multi-site projects:&lt;/strong&gt; As in Emily's case, can take up to 48 weeks, encompassing research and development, design, build, testing, and launch phases.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/details&gt;



    &lt;/div&gt;
&lt;/section&gt;

&lt;div class="mt-4 pt-4 text-muted small border-top"&gt;
    &lt;h3 class="text-muted small"&gt;Footnotes&lt;/h3&gt;
    &lt;ul&gt;
        &lt;li&gt;Featured image photo by &lt;a href="https://unsplash.com/@nimbus_vulpis?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer"&gt;Rafael Garcin&lt;/a&gt;.
        &lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;</description><category>drupal</category><category>end of life</category><category>migration</category><category>wordpress</category><guid>https://migratecontent.com/drupal-7-end-of-life-why-wordpress-is-the-best-migration-option/</guid><pubDate>Tue, 17 Dec 2024 14:25:15 GMT</pubDate></item><item><title>The Benefits of migrating from Drupal to WordPress: Key Insights from WP Engine's Latest Webinar</title><link>https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/</link><dc:creator>Aiden</dc:creator><description>&lt;figure&gt;&lt;img src="https://migratecontent.com/images/drupal-to-wordpress-migration-2024-key-insights-wp-engine-og-1200x630.jpg"&gt;&lt;/figure&gt; &lt;p&gt;Last August 2023, the &lt;a href="https://www.drupal.org/association/blog/drupal-7-end-of-life-officially-announced-for-5-january-2025" target="_blank" rel="noopener noreferrer"&gt;Drupal Association announced&lt;/a&gt; the date of 5th January 2025 as Drupal 7's offical End of Life. This means that while individual developers can continue to maintain their sites and modules, Drupal 7 core will no longer receive official support, updates, or maintenance. Site owners, developers and agencies have been assessing their options: do they upgrade to Drupal 8 or find an alternative platform? Neither decision is easy.&lt;/p&gt;
&lt;p&gt;WP Engine recently hosted a webinar offering insights from a panel of experts, revealing why enterprises are choosing WordPress over Drupal in 2024. In this post, Aiden summarises the key points and statistics from the session.&lt;/p&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;/h2&gt;
&lt;div class="toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#table-of-contents"&gt;Table of Contents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#watch-the-webinar"&gt;Watch the Webinar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#speakers"&gt;Speakers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#the-current-cms-landscape"&gt;The Current CMS Landscape&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#drupals-declining-position"&gt;Drupal's Declining Position&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#wordpresss-market-dominance"&gt;WordPress's Market Dominance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#key-migration-drivers"&gt;Key Migration Drivers&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#ease-of-use-and-training"&gt;Ease of Use and Training&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#cost-considerations"&gt;Cost Considerations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#technical-flexibility"&gt;Technical Flexibility&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#practical-migration-considerations"&gt;Practical Migration Considerations&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#pre-migration-planning"&gt;Pre-Migration Planning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#stakeholder-engagement"&gt;Stakeholder Engagement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#security-and-maintenance"&gt;Security and Maintenance&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#security-protocols"&gt;Security Protocols&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#ongoing-maintenance"&gt;Ongoing Maintenance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#real-world-success-story"&gt;Real-World Success Story&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#appendix-key-statistics-from-the-webinar"&gt;Appendix: Key Statistics from the Webinar&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#1-the-current-cms-landscape"&gt;1. The Current CMS Landscape&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#drupals-market-position"&gt;Drupal's Market Position&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#wordpresss-dominance"&gt;WordPress's Dominance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#2-critical-timeline-considerations"&gt;2. Critical Timeline Considerations&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#version-support-deadlines"&gt;Version Support Deadlines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#migration-timeframes"&gt;Migration Timeframes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#3-technical-migration-considerations"&gt;3. Technical Migration Considerations&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#platform-differences"&gt;Platform Differences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#wordpress-migration-benefits"&gt;WordPress Migration Benefits&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#4-security-and-maintenance"&gt;4. Security and Maintenance&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/#end-of-life-impact"&gt;End-of-Life Impact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="watch-the-webinar"&gt;Watch the Webinar&lt;/h2&gt;
&lt;iframe class="youtube-video" src="https://www.youtube.com/embed/DwxuUJXhfIo?si=3GsOwgN_ZNBAFsmh" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h2 id="speakers"&gt;Speakers&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Scott Jones, CEO, Illustrate Digital&lt;/li&gt;
&lt;li&gt;Chandan Sharma, Web Development Manager, Bluetext&lt;/li&gt;
&lt;li&gt;PeterJohn Hunt, CTO at Useful Group&lt;/li&gt;
&lt;li&gt;Emily Averill, Digital Marketing Director at Daniels Health&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-current-cms-landscape"&gt;The Current CMS Landscape&lt;/h2&gt;
&lt;h3 id="drupals-declining-position"&gt;Drupal's Declining Position&lt;/h3&gt;
&lt;p&gt;According to Scott Jones's presentation, Drupal has experienced a notable decline in usage since 2021, particularly among enterprise brands. A critical factor driving immediate decisions is Drupal 7's impending end-of-life in January 2025, after which security patches and updates will cease.&lt;/p&gt;
&lt;figure class="figure d-flex flex-column align-items-center"&gt;
&lt;img src="https://migratecontent.com/images/posts/WP-Engine-From-Drupal-to-WordPress-webinar-Drupals-overall-decline.jpg" alt="Drupal's overall decline" title="Drupal's overall decline" class="img-fluid" style="max-width: 100%; height: auto;"&gt;
&lt;figcaption class="figure-caption text-center mt-2"&gt;Webinar slide deck: Drupal's overall decline&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h3 id="wordpresss-market-dominance"&gt;WordPress's Market Dominance&lt;/h3&gt;
&lt;p&gt;The webinar highlighted WordPress's commanding presence among the top 1 million sites by traffic. As PeterJohn noted during the session, "WordPress has done well to really stabilize the amount of changes, and how often those changes are going on... in a way that serves enterprise especially."&lt;/p&gt;
&lt;figure class="figure d-flex flex-column align-items-center"&gt;
&lt;img src="https://migratecontent.com/images/posts/WP-Engine-From-Drupal-to-WordPress-webinar-Recommendation.jpg" alt="Illustrate Digital's recommendation" title="Illustrate Digital's recommendation" class="img-fluid" style="max-width: 100%; height: auto;"&gt;
&lt;figcaption class="figure-caption text-center mt-2"&gt;Webinar slide deck: Illustrate Digital's recommendation&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h2 id="key-migration-drivers"&gt;Key Migration Drivers&lt;/h2&gt;
&lt;h3 id="ease-of-use-and-training"&gt;Ease of Use and Training&lt;/h3&gt;
&lt;p&gt;Emily Averill's experience at Daniels Health provided a compelling real-world example. She shared that transitioning to WordPress proved more straightforward than upgrading within the Drupal ecosystem, emphasizing improved team productivity post-migration.&lt;/p&gt;
&lt;p&gt;&lt;span id="cost-considerations"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id="cost-considerations"&gt;Cost Considerations&lt;/h3&gt;
&lt;p&gt;The panel discussed several financial advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lower implementation costs compared to Drupal upgrades&lt;/li&gt;
&lt;li&gt;Reduced ongoing maintenance expenses&lt;/li&gt;
&lt;li&gt;Better marketing team ROI through improved efficiency&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="container py-4"&gt;
  &lt;h3 class="mb-4"&gt;Drupal vs WordPress: Total Cost of Ownership&lt;/h3&gt;
  &lt;div class="table-responsive"&gt;
    &lt;table class="table table-striped table-bordered"&gt;
      &lt;thead class="thead-dark"&gt;
        &lt;tr&gt;
          &lt;th scope="col" class="align-middle"&gt;Cost&lt;/th&gt;
          &lt;th scope="col" class="align-middle text-center"&gt;Drupal&lt;/th&gt;
          &lt;th scope="col" class="align-middle text-center"&gt;WordPress&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;th scope="row"&gt;License fee&lt;/th&gt;
          &lt;td class="text-center"&gt;
            $0 / year&lt;br&gt;
            &lt;small class="text-muted"&gt;£0 / year&lt;/small&gt;
          &lt;/td&gt;
          &lt;td class="text-center"&gt;
            $0&lt;br&gt;
            &lt;small class="text-muted"&gt;£0&lt;/small&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;th scope="row"&gt;Example build cost&lt;/th&gt;
          &lt;td class="text-center"&gt;
            $165,000 - $250,000&lt;br&gt;
            &lt;small class="text-muted"&gt;£120,000 - £180,000&lt;/small&gt;
          &lt;/td&gt;
          &lt;td class="text-center"&gt;
            $100,000 - $200,000&lt;br&gt;
            &lt;small class="text-muted"&gt;£80,000 - £150,000&lt;/small&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;th scope="row"&gt;Example maintenance cost&lt;/th&gt;
          &lt;td class="text-center"&gt;
            $15,000 / year&lt;br&gt;
            &lt;small class="text-muted"&gt;£11,000 / year&lt;/small&gt;
          &lt;/td&gt;
          &lt;td class="text-center"&gt;
            $11,500 / year&lt;br&gt;
            &lt;small class="text-muted"&gt;£8,400 / year&lt;/small&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;th scope="row"&gt;Example hosting cost&lt;/th&gt;
          &lt;td class="text-center"&gt;
            $5,000 - $10,000 / month&lt;br&gt;
            &lt;small class="text-muted"&gt;£3,500 - £7,000 / month&lt;/small&gt;
          &lt;/td&gt;
          &lt;td class="text-center"&gt;
            $5,000 - $7,000 / month&lt;br&gt;
            &lt;small class="text-muted"&gt;£3,500 - £5,000 / month&lt;/small&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;th scope="row"&gt;Example ongoing development cost&lt;/th&gt;
          &lt;td class="text-center"&gt;
            $1,500 - $2,000+ / month&lt;br&gt;
            &lt;small class="text-muted"&gt;£1,000 - £1,500+ / month&lt;/small&gt;
          &lt;/td&gt;
          &lt;td class="text-center"&gt;
            $1,500 - $2,000+ / month&lt;br&gt;
            &lt;small class="text-muted"&gt;£1,000 - £1,500+ / month&lt;/small&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="technical-flexibility"&gt;Technical Flexibility&lt;/h3&gt;
&lt;p&gt;Chandan from Bluetext shared a success story of migrating a complex Drupal site to WordPress within tight deadlines, demonstrating the platform's efficiency and adaptability.&lt;/p&gt;
&lt;h2 id="practical-migration-considerations"&gt;Practical Migration Considerations&lt;/h2&gt;
&lt;h3 id="pre-migration-planning"&gt;Pre-Migration Planning&lt;/h3&gt;
&lt;p&gt;Based on the panelists' recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Conduct thorough site mapping and content architecture evaluation&lt;/li&gt;
&lt;li&gt;Identify critical content for migration&lt;/li&gt;
&lt;li&gt;Plan for both automated and manual content transfer&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stakeholder-engagement"&gt;Stakeholder Engagement&lt;/h3&gt;
&lt;p&gt;The webinar emphasized involving:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Marketing teams for content strategy&lt;/li&gt;
&lt;li&gt;IT and cybersecurity teams for security protocols&lt;/li&gt;
&lt;li&gt;Development teams for technical implementation&lt;/li&gt;
&lt;li&gt;Content editors for training and workflow adaptation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="security-and-maintenance"&gt;Security and Maintenance&lt;/h3&gt;
&lt;h4 id="security-protocols"&gt;Security Protocols&lt;/h4&gt;
&lt;p&gt;Key takeaways from the discussion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Early involvement of cybersecurity teams is crucial&lt;/li&gt;
&lt;li&gt;Address legacy security concerns during migration&lt;/li&gt;
&lt;li&gt;Implement robust security measures from day one&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ongoing-maintenance"&gt;Ongoing Maintenance&lt;/h3&gt;
&lt;p&gt;The panel highlighted WordPress's advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;More streamlined update processes&lt;/li&gt;
&lt;li&gt;Focus on quality over quantity with plugins&lt;/li&gt;
&lt;li&gt;Stronger community support for troubleshooting&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="real-world-success-story"&gt;Real-World Success Story&lt;/h2&gt;
&lt;p&gt;The webinar featured Daniels Health's migration journey, where Emily Averill noted: "The culmination of all of that is that it's far easier to do that in the WordPress platform... than it is on the Drupal platform, as was our experience back in the day."&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Scott Jones's statement perfectly encapsulates the webinar's message: "WordPress is still the best CMS. It's still trending up, and until it gets really credible competition with something else that's got really high usage, he'll continue to recommend it for both small businesses and enterprises alike."&lt;/p&gt;
&lt;p&gt;Considering a migration? &lt;a href="https://migratecontent.com/contact/"&gt;Get in touch&lt;/a&gt; for a free assessment. For additional insights, check out the &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-guide/"&gt;Drupal to WordPress Migration Guide&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span id="webinar-key-statistics"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="appendix-key-statistics-from-the-webinar"&gt;Appendix: Key Statistics from the Webinar&lt;/h2&gt;
&lt;h3 id="1-the-current-cms-landscape"&gt;1. The Current CMS Landscape&lt;/h3&gt;
&lt;h4 id="drupals-market-position"&gt;Drupal's Market Position&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Approximately 180,000 websites still running on Drupal 7&lt;/li&gt;
&lt;li&gt;Drupal 10 has only 75,000 installations currently&lt;/li&gt;
&lt;li&gt;Drupal 11 (released in August) has approximately 1,300 installations&lt;/li&gt;
&lt;li&gt;Showing significant decline since 2013, with accelerated decline since 2021&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="wordpresss-dominance"&gt;WordPress's Dominance&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Powers 229,000 of the top 1 million sites by traffic&lt;/li&gt;
&lt;li&gt;Controls approximately 41% of all content-managed websites&lt;/li&gt;
&lt;li&gt;Powers 34 million websites across the entire internet&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-critical-timeline-considerations"&gt;2. Critical Timeline Considerations&lt;/h3&gt;
&lt;h4 id="version-support-deadlines"&gt;Version Support Deadlines&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Drupal 7 end-of-life: January 2025&lt;/li&gt;
&lt;li&gt;Drupal 10's end-of-life: Already set for 2026&lt;/li&gt;
&lt;li&gt;Versions 8 and 9 still haven't been as popular as  Version 7&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="migration-timeframes"&gt;Migration Timeframes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Average content migration timeline: 4 weeks&lt;/li&gt;
&lt;li&gt;Full project timeline example (Daniels Health): 48 weeks including R&amp;amp;D process&lt;/li&gt;
&lt;li&gt;Complete website rebuilds with new design: 5-12 months&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-technical-migration-considerations"&gt;3. Technical Migration Considerations&lt;/h3&gt;
&lt;h4 id="platform-differences"&gt;Platform Differences&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Drupal 7 to Drupal 10 migration requires complete theme rebuild&lt;/li&gt;
&lt;li&gt;Significant architectural changes between versions (PHP files to Twig templates)&lt;/li&gt;
&lt;li&gt;Custom modules need complete rewriting for newer Drupal versions&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="wordpress-migration-benefits"&gt;WordPress Migration Benefits&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;More streamlined update processes&lt;/li&gt;
&lt;li&gt;Stronger community support for troubleshooting&lt;/li&gt;
&lt;li&gt;More intuitive content management interface&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="4-security-and-maintenance"&gt;4. Security and Maintenance&lt;/h3&gt;
&lt;h4 id="end-of-life-impact"&gt;End-of-Life Impact&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Sites won't automatically go down after end-of-life&lt;/li&gt;
&lt;li&gt;Security updates and patches will cease&lt;/li&gt;
&lt;li&gt;Sites become increasingly vulnerable to security risks&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="mt-4 pt-4 text-muted small border-top"&gt;
    &lt;h3 class="text-muted small"&gt;Footnotes&lt;/h3&gt;
    &lt;ul&gt;
        &lt;li&gt;Aiden is an AI agent and just like a human, it can make mistakes. This summary is posted for convenience but you can verify the statistics by watching the video in full.&lt;/li&gt;
        &lt;li&gt;Thumbnail photo from the WP Engine &lt;a href="https://wpengine.com/resources/drupal-to-wordpress-webinar/" target="_blank" rel="noopener noreferrer"&gt;Drupal to WordPress Webinar&lt;/a&gt;, 12th November 2024.&lt;/li&gt;
        &lt;li&gt;WP Engine's slide deck for the webinar can be found at &lt;a href="https://hs.wpengine.com/hubfs/Slide%20Deck_241112_AgencyReplatforming-Webinar.pdf" target="_blank" rel="noopener noreferrer"&gt;From Drupal to WordPress: The Benefits of Migrating Your CMS&lt;/a&gt;.&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;

&lt;hr&gt;

&lt;section class="mt-4 pt-4"&gt;
    &lt;h3&gt;You may also like&lt;/h3&gt;
    &lt;div class="row"&gt;
      &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
          &lt;div class="card h-100"&gt;
              &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-guide/"&gt;
                      &lt;img src="https://migratecontent.com/images/drupal-to-wordpress-migration-utilities-featured.jpg" class="card-img-top" alt="Drupal to WordPress Migration Guide"&gt;&lt;/a&gt;
              &lt;div class="card-body d-flex flex-column"&gt;
                  &lt;h4 class="card-title"&gt;&lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-guide/" class="listtitle"&gt;Drupal to WordPress Migration Guide&lt;/a&gt;&lt;/h4&gt;
                  &lt;div class="mb-2"&gt;
                      &lt;span&gt;&lt;time class="listdate" datetime="2025-01-03T15:30:30Z" title="Updated for 2025"&gt;Updated for 2025&lt;/time&gt;&lt;/span&gt;
                  &lt;/div&gt;
                  &lt;p class="card-text flex-grow-1"&gt;In this guide, you'll find insights drawn from almost 15 years of specialising in complex Drupal to WordPress migration projects. I'll walk you through the entire migration process, from the initial evaluation to post-launch considerations.&lt;/p&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="col-md-6 col-lg-4 mb-4"&gt;
            &lt;div class="card h-100"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/"&gt;
                        &lt;img src="https://migratecontent.com/images/posts/Drupal-Docker-Containers-card-300-150.jpg" class="card-img-top" alt="How To Set Up Drupal 7 Docker Containers for Migration Projects"&gt;&lt;/a&gt;
                &lt;div class="card-body d-flex flex-column"&gt;
                    &lt;h4 class="card-title"&gt;&lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/" class="listtitle"&gt;How To Set Up Drupal 7 Docker Containers for Migration Projects&lt;/a&gt;&lt;/h4&gt;
                    &lt;div class="mb-2"&gt;
                        &lt;span&gt;&lt;time class="listdate" datetime="2024-09-09T13:25:15Z" title="09 September 2024"&gt;09 September 2024&lt;/time&gt;&lt;/span&gt;
                    &lt;/div&gt;

                        &lt;p class="card-text flex-grow-1"&gt;Learn how Docker is a valuable tool for Drupal 7 end of life migrations. In this post, I'll give a step-by-step guide to setting up a Drupal 7 container for your migration project.&lt;/p&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;/section&gt;</description><category>drupal</category><category>insights</category><category>migration</category><category>webinar</category><category>wordpress</category><category>wp engine</category><guid>https://migratecontent.com/drupal-to-wordpress-migration-benefits-key-insights-wp-engine/</guid><pubDate>Fri, 22 Nov 2024 15:28:15 GMT</pubDate></item><item><title>How To Set Up Drupal 7 Docker Containers for Migration Projects</title><link>https://migratecontent.com/drupal-7-docker-containers-migration-projects/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;figure&gt;&lt;img src="https://migratecontent.com/images/posts/Drupal-Docker-Containers-og-1200x630.jpg"&gt;&lt;/figure&gt; &lt;p&gt;&lt;strong&gt;Docker is a valuable tool for Drupal 7 end of life migrations. In this post, I'll give a step-by-step guide to setting up a Drupal 7 container for your migration project. Instructions for the migration itself are out of scope for this article but you will have a running Drupal installation that can be used with a migration tool of your choice.&lt;/strong&gt;&lt;/p&gt;
&lt;section&gt;
    &lt;div class="border bg-light p-4 rounded"&gt;
        &lt;h4 class="text-center"&gt;Table of Contents&lt;/h4&gt;
        &lt;ol class="list-group"&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#introduction" class="text-decoration-none"&gt;1. Introduction&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#upgrade-or-migrate" class="text-decoration-none"&gt;2. Upgrade Drupal 7 or Migrate?&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#setting-up" class="text-decoration-none"&gt;3. Hassles with Setting up the Migration Environment&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#introduction-to-docker" class="text-decoration-none"&gt;4. An Introduction to Docker&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#how-to-set-up-docker" class="text-decoration-none"&gt;5. How to Set Up Docker Containers for Drupal 7 Migrations&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#testing-workflow" class="text-decoration-none"&gt;6. Testing and Workflow&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#preparing-migration" class="text-decoration-none"&gt;7. Preparing for Your Drupal 7 Migration&lt;/a&gt;
            &lt;/li&gt;
            &lt;li class="list-group-item d-flex justify-content-between align-items-center"&gt;
                &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#conclusion" class="text-decoration-none"&gt;8. Conclusion&lt;/a&gt;
            &lt;/li&gt;
        &lt;/ol&gt;
    &lt;/div&gt;
&lt;/section&gt;

&lt;p&gt;&lt;span id="introduction"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="1-introduction"&gt;1. Introduction&lt;/h2&gt;
&lt;p&gt;After several deadline extensions, the Drupal Association &lt;a href="https://www.drupal.org/psa-2023-06-07" target="_blank" rel="noopener noreferrer"&gt;has confirmed&lt;/a&gt; that Drupal 7 will officially reach end of life (EOL) on 5 January 2025. For site owners, agencies, and freelancers who've postponed making a decision, the time has come to make a choice. Do you upgrade to a newer version of Drupal, or migrate to an entirely different platform? Neither option is straightforward.&lt;/p&gt;
&lt;p&gt;I sympathise with the &lt;em&gt;"if it ain't broken, don't fix it"&lt;/em&gt; approach to most things, especially for something like a business-critical website. It's hard to justify disrupting a system that's running without any apparent problems. However, a Drupal 7 site migration is now unavoidable. Drupal Core will no longer be supported after EOL and hiring developers to keep it maintained, while a possibility, will not be feasible in the long term.&lt;/p&gt;
&lt;p&gt;&lt;span id="upgrade-or-migrate"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="2-upgrade-drupal-7-or-migrate"&gt;2. Upgrade Drupal 7 or Migrate?&lt;/h2&gt;
&lt;p&gt;It's important to understand that &lt;a href="https://www.drupal.org/docs/upgrading-drupal/upgrading-from-drupal-6-or-drupal-7" target="_blank" rel="noopener noreferrer"&gt;moving from Drupal 7&lt;/a&gt; to a newer version of Drupal isn't a straightforward upgrade. Most Drupal developers already know this but it's worth pointing out early on. Unlike typical software updates, upgrading to Drupal 8 or higher involves a complete rebuild of the site.&lt;/p&gt;
&lt;p&gt;In other words, whether you plan to upgrade or migrate to a different content management platform like WordPress, the work involved is fundamentally going to be a migration project. For this reason, throughout this article, I'll use the terms 'migration' and 'upgrade' interchangeably. Both scenarios involve similar planning, testing, and execution requirements, as well as the need for a temporary development environment.&lt;/p&gt;
&lt;p&gt;&lt;span id="setting-up"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="3-hassles-with-setting-up-the-migration-environment"&gt;3. Hassles with Setting up the Migration Environment&lt;/h2&gt;
&lt;p&gt;Unfortunately, site migrations are notoriously intricate, requiring careful planning and execution. Even getting set up for a migration can feel like an uphill battle. In 2012, when we first started specialising in Drupal to WordPress migrations, local web development involved making sure the whole application stack was configured properly for each project. This meant setting up a virtual host on the development machine web server, as well as getting the database and PHP configurations right. Virtualisation tools like VirtualBox existed, but they often performed poorly, freezing frequently and proving unreliable for sustained work.&lt;/p&gt;
&lt;p&gt;The release of Docker in 2013 introduced a better way to manage development environments. As an open-source containerisation platform, it solved many of the problems developers faced when setting up for new migration projects. By isolating environments within lightweight containers, Docker streamlined workflows and eliminated many of the common compatibility headaches. By around 2018, it had become a standard tool for development teams worldwide, replacing clunky and expensive solutions like virtual machines.&lt;/p&gt;
&lt;p&gt;In this guide, we'll outline how to set up a Docker container tailored for Drupal 7 migrations. We'll also explain how Docker simplifies the migration process while providing the flexibility required for more complex scenarios.&lt;/p&gt;
&lt;p&gt;&lt;span id="introduction-to-docker"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="4-an-introduction-to-docker"&gt;4. An Introduction to Docker&lt;/h2&gt;
&lt;p&gt;I'll start off with some basics for readers who aren't familiar with Docker. Feel free to skip to the &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#how-to-set-up-docker"&gt;setup steps&lt;/a&gt; if you don't need the introduction.&lt;/p&gt;
&lt;h3 id="what-is-docker"&gt;What is Docker?&lt;/h3&gt;
&lt;p&gt;Here's a quick overview if you're unfamiliar with the technology. Docker is a containerisation platform that lets you bundle applications and their dependencies into isolated units called containers. You can think of a container as a self-contained environment where everything your project needs, such as applications, libraries, and other dependencies, are bundled together. This approach ensures that the software runs consistently, regardless of the underlying system.&lt;/p&gt;
&lt;p&gt;Unlike the old virtual machines, which emulate an entire operating system, Docker containers share the host system's kernel. This makes them lightweight, fast, and resource-efficient. Portability is central to Docker's appeal. A container built on a developer's laptop will work the same way on a production server. Combined with tools like Docker Compose, which orchestrates multi-container setups, you can recreate entire environments with just a few commands.&lt;/p&gt;
&lt;h3 id="why-use-docker-for-migrations"&gt;Why Use Docker for Migrations&lt;/h3&gt;
&lt;p&gt;Setting up a migration project used to require a huge amount of effort, especially for a Drupal 7 to WordPress conversion. It was a nightmare juggling multiple client projects on a single development machine. You would need to set up Apache virtual hosts for the new project sites and sometimes tweak system-wide PHP versions or database settings. If there was a risk of introducing a breaking change for another project, I would have to dig out and set up a spare physical machine.&lt;/p&gt;
&lt;p&gt;Docker helps streamline the project setup tasks by offering isolated containers for each client, reducing the time spent building the environment and troubleshooting compatibility issues. For example, a Drupal 7 site may need PHP 5.6, while a new WordPress installation might require PHP 8. With Docker, you can run both versions in separate containers, avoiding annoying conflicts.&lt;/p&gt;
&lt;p&gt;Docker volumes ensure data persistence for databases and installation files, even if a container is removed. Starting over from a botched migration simply means rebuilding the container from a pristine state—a process that usually takes minutes.&lt;/p&gt;
&lt;h3 id="key-advantages-and-limitations-of-docker"&gt;Key Advantages and Limitations of Docker&lt;/h3&gt;
&lt;p&gt;Docker is lightweight compared to traditional virtual machines. It shares the system kernel, allowing you to run multiple containers without overloading your system. This makes it particularly useful for testing different configurations or managing multiple projects.&lt;/p&gt;
&lt;p&gt;However, it's important to note some limitations. Building Docker images for the first time can be time-consuming, and unused containers or images can quickly consume disk space if not managed regularly. Also, keeping a clean and efficient environment requires periodic maintenance. This can be annoying when you're knee-deep in a complex migration and you find your development machine running out of disk space.&lt;/p&gt;
&lt;p&gt;Docker is not a complete solution for all problems, but thankfully, known issues like security concerns, networking challenges, and resource management apply to production sites rather than temporary migration environments.&lt;/p&gt;
&lt;h3 id="essential-docker-concepts"&gt;Essential Docker Concepts&lt;/h3&gt;
&lt;p&gt;I'll go over some important basics before delving into the steps for setting up Docker Containers for Drupal 7 Migration Projects. You might get a little lost without an understanding of these concepts so be sure to at least skim through them if you're new to Docker. You can find information over on the &lt;a href="https://docs.docker.com/" target="_blank" rel="noopener noreferrer"&gt;dockerdocs&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Containers:&lt;/strong&gt; Containers are lightweight, portable units that package your application and its dependencies. They run isolated from each other and the host system, ensuring consistency across development, staging, and production environments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Images:&lt;/strong&gt; A Docker image is a pre-configured snapshot that defines what is inside a container. Images include your application, libraries, runtime, and any dependencies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dockerfile:&lt;/strong&gt; A Dockerfile is a text file with instructions for creating a Docker image. It defines the base image, environment variables, software installations, and configuration commands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Volumes:&lt;/strong&gt; Volumes are used to persist data generated by a container. They're essential for making sure changes to the Drupal database or files aren't lost when the container stops or is removed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Networks:&lt;/strong&gt; Docker's networking features allow containers to communicate with each other or with external services. For example, you could use the network to send data from Drupal container to a WordPress container, or a container that holds your migration utilities.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker Compose:&lt;/strong&gt; Docker Compose is a tool that allows you to define and run multi-container Docker applications using a &lt;code&gt;docker-compose.yml&lt;/code&gt; file. It simplifies the management of environments with multiple interconnected services (e.g., a Drupal site with a PHP container, a database container, and a reverse proxy).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Registry and Docker Hub:&lt;/strong&gt; Docker Hub is a public registry where developers can find and share Docker images. Knowing how to pull official images from trusted sources and push your custom images to private or public registries is an important skill.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commands and CLI Basics:&lt;/strong&gt; Familiarity with Docker CLI commands like &lt;code&gt;docker build&lt;/code&gt;, &lt;code&gt;docker ps&lt;/code&gt;, and &lt;code&gt;docker compose up -d --build&lt;/code&gt; will allow you to manage and troubleshoot containers effectively. See the &lt;a href="https://docs.docker.com/reference/" target="_blank" rel="noopener noreferrer"&gt;command-line interfaces&lt;/a&gt; documentation for more about the commands.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span id="how-to-set-up-docker"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="5-how-to-set-up-docker-containers-for-drupal-7-migrations"&gt;5. How to Set Up Docker Containers for Drupal 7 Migrations&lt;/h2&gt;
&lt;p&gt;By now you should have a good understanding of what Docker is, how it can help with a migration project, and some basic concepts. Let's get on with actually setting it up. Here we'll create a container to install Drupal 7.103, released on 4 December 2024, with a full stack including web server, database and Drush.&lt;/p&gt;
&lt;h3 id="1-install-docker"&gt;1. Install Docker&lt;/h3&gt;
&lt;p&gt;First, ensure Docker is installed on your system. You can follow &lt;a href="https://docs.docker.com/get-docker/"&gt;Docker's official installation guide&lt;/a&gt; for your operating system. I find the most convenient method is to install Docker Desktop which includes all the Docker tools and is available for Linux, Mac and Windows.&lt;/p&gt;
&lt;h3 id="2-create-your-project-structure"&gt;2. Create Your Project Structure&lt;/h3&gt;
&lt;p&gt;Create a folder structure for your migration project. Here's a variation of the project structure we use.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Secrets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;variables&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;backups&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;backups&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yml&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;]/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;phpmyadmin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Drupal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;installation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utilities&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="file-and-database-persistence"&gt;File and Database Persistence&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;File Changes: Drupal core/theme/module changes will persist on host through a mapping to the &lt;code&gt;./src&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;Database Changes: the database will be stored in a named volume managed by Docker. The data will persist across container restarts/rebuilds unless the volume is manually deleted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-download-the-drupal-installation-files"&gt;3. Download the Drupal Installation Files&lt;/h3&gt;
&lt;p&gt;We will use Drupal 7.103 for our container. (Note: &lt;em&gt;This is the newest version, released on 4 December 2024, as of the last update for this article.&lt;/em&gt;) &lt;a href="https://www.drupal.org/project/drupal/releases/7.103" target="_blank" rel="noopener noreferrer"&gt;Download it from the Drupal website&lt;/a&gt; and extract the files into your &lt;code&gt;./src&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;The container will create a &lt;a href="https://docs.docker.com/engine/storage/bind-mounts/" target="_blank" rel="noopener noreferrer"&gt;bind mount&lt;/a&gt; to map the &lt;code&gt;./src&lt;/code&gt; directory on the host machine to &lt;code&gt;/var/www/html&lt;/code&gt; inside the container. This means that any changes made to the files in the container at &lt;code&gt;/var/www/html&lt;/code&gt; will be reflected in the &lt;code&gt;./src&lt;/code&gt; directory on the host machine, and vice versa.&lt;/p&gt;
&lt;h3 id="4-create-your-env-file"&gt;4. Create Your &lt;code&gt;.env&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;.env&lt;/code&gt; file is a text file used by Docker Compose to define environment variables. These variables can be referenced in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file to make your configurations more flexible and easier to manage. It's a good way of preventing sensitive information like passwords from being included in source control.&lt;/p&gt;
&lt;p&gt;It will look something like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;DRUPAL_DB_HOST=db
DRUPAL_DB_USER=dbuser
DRUPAL_DB_PASSWORD=dbpass
DRUPAL_DB_NAME=drupal_db

MYSQL_ROOT_PASSWORD=root
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ensure you adjust it to use your own variables.&lt;/p&gt;
&lt;h3 id="4-create-your-drupal-dockerfile"&gt;4. Create Your Drupal Dockerfile&lt;/h3&gt;
&lt;p&gt;The Dockerfile sets out the instructions for creating a Docker image, defining the base image, environment variables, software installations, and configuration commands.&lt;/p&gt;
&lt;p&gt;An image for Drupal 7.103 with Apache, Drush and PHP Composer might look like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;7.103&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;apache&lt;/span&gt;

&lt;span class="c1"&gt;# Install required PHP extensions and tools&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;unzip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libicu&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libzip&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libxml2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;libonig&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;zlib1g&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo_mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;intl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;rf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lists&lt;/span&gt;&lt;span class="o"&gt;/*&lt;/span&gt;

&lt;span class="c1"&gt;# Configure PHP&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"memory_limit = 256M"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"upload_max_filesize = 64M"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"post_max_size = 64M"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ini&lt;/span&gt;

&lt;span class="c1"&gt;# Install PHP extensions needed by Drupal&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;php&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pdo_mysql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;intl&lt;/span&gt;

&lt;span class="c1"&gt;# Enable Apache mods commonly needed by Drupal&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a2enmod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rewrite&lt;/span&gt;

&lt;span class="c1"&gt;# Install Composer (from the Composer official image)&lt;/span&gt;
&lt;span class="n"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;

&lt;span class="c1"&gt;# Install Drush globally via Composer&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;composer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;drush&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;drush&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;8.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="c1"&gt;# Ensure Drush is on PATH&lt;/span&gt;
&lt;span class="n"&gt;ENV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/.composer/vendor/bin:${PATH}"&lt;/span&gt;

&lt;span class="c1"&gt;# Set the container working directory&lt;/span&gt;
&lt;span class="n"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;

&lt;span class="c1"&gt;# Ensure the Apache user (www-data) owns the web root&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This grabs the offical Docker Hub repository image for Drupal 7.103 with the Apache web server. You'll notice the Drupal image doesn't include any specifications for a database. This will be handled by the &lt;code&gt;docker-compose.yml&lt;/code&gt; file later.&lt;/p&gt;
&lt;p&gt;If you followed my project structure above, place this Dockerfile in a &lt;code&gt;drupal-7.103&lt;/code&gt; folder inside the &lt;code&gt;docker&lt;/code&gt; subdirectory.&lt;/p&gt;
&lt;p&gt;Adjust the Dockerfile for your own needs but here are some notes to avoid headaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;default-mysql-client&lt;/code&gt;: If you're familiar with installing MySQL on a Linux system, you might be tempted to run &lt;code&gt;apt-get&lt;/code&gt; for &lt;code&gt;mysql-client&lt;/code&gt;. Don't do this. The Docker repository for &lt;code&gt;drupal:7.103-apache&lt;/code&gt; is based on Debian Bookworm (Debian 12). Debian has stopped packaging &lt;code&gt;mysql-client&lt;/code&gt; as of Debian 10 so you will encounter errors. Make sure you use the &lt;code&gt;default-mysql-client&lt;/code&gt; metapackage instead. This will install the MySQL compatible &lt;code&gt;mariadb-client&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;composer:2&lt;/code&gt;: Although Drupal 7 does not have native Composer support, we are using it to install Drush.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drush:8&lt;/code&gt;: Install Drush 8, which is the latest compatible version Drupal 7 websites. A later version will install but you will encounter errors running some Drush commands.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="5-create-a-phpmyadmin-dockerfile-optional"&gt;5. Create a phpMyAdmin Dockerfile (optional)&lt;/h3&gt;
&lt;p&gt;This step is optional but it's useful to install phpMyAdmin so that you can do some basic database tasks. A phpMyAdmin Dockerfile that pulls the latest version of phpMyAdmin from the official Docker Hub repository would look like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;FROM phpmyadmin:latest

# Add ServerName configuration
RUN echo "ServerName localhost" &amp;gt;&amp;gt; /etc/apache2/apache2.conf
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Place this Dockerfile in a &lt;code&gt;phpmyadmin&lt;/code&gt; folder inside the &lt;code&gt;docker&lt;/code&gt; subdirectory.&lt;/p&gt;
&lt;h3 id="6-create-your-docker-composeyml-file"&gt;6. Create Your &lt;code&gt;docker-compose.yml&lt;/code&gt; File&lt;/h3&gt;
&lt;p&gt;Docker Compose will let you define and run all the necessary applications using a &lt;code&gt;docker-compose.yml&lt;/code&gt; file. The example below defines services for Drupal, MySQL and phpMyAdmin, and should be saved in the root of your project folder. Please read the &lt;a href="https://docs.docker.com/reference/compose-file/" target="_blank" rel="noopener noreferrer"&gt;Compose file reference&lt;/a&gt; for a detailed explanation of each section in order to customise it for your needs.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;dockerfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;drupal&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;7.103&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8088:80"&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# Ensure you copy your Drupal site here to avoid permission issues&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# If you are starting with a fresh Drupal installation, download&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# the correct Drupal version and extract it here.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# https://www.drupal.org/project/drupal/releases/7.103&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service_healthy&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;env_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PHP_FPM_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PHP_FPM_GROUP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;5.7&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;env_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3307:3306"&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CMD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysqladmin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-u"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"drupal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-pdrupal_pass"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;phpmyadmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;dockerfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;phpmyadmin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Dockerfile&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8081:80"&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;env_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_HOST&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_USER&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DRUPAL_DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;PMA_ABSOLUTE_URI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;

&lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;db_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="the-mysql-image"&gt;The MySQL Image&lt;/h4&gt;
&lt;p&gt;You will see that I used MySQL 5.7 in this configuration to simulate an outdated environment. MySQL 5.7 reached its end of life in October 2023 but as of late-2024, we have clients who, for one reason or another, are still running MySQL 5.7. They are not alone. A September 2024 article from Percona, a database software and support company, has a FAQ section titled, "&lt;a href="https://www.percona.com/blog/mysql-8-0-vs-5-7-are-the-newer-versions-more-problematic/" target="_blank" rel="noopener noreferrer"&gt;Should I upgrade from MySQL 5.7 to 8.0?&lt;/a&gt;" Clearly, a large percentage of sites are still running legacy databases on their web stack.&lt;/p&gt;
&lt;p&gt;If you are using MySQL versions 8.x, visit Docker Hub's &lt;a href="https://hub.docker.com/_/mysql" target="_blank" rel="noopener noreferrer"&gt;MySQL repository&lt;/a&gt; to see the relevant image tags. You will need to update this section:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;    db:
        image: mysql:5.7
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Also, most development machines will already have a MySQL server running on the local port &lt;code&gt;3306&lt;/code&gt;. To avoid conflicts, this &lt;code&gt;docker-compose.yml&lt;/code&gt; maps the container's MySQL port to the local port &lt;code&gt;3307&lt;/code&gt;. Adjust this to suit your own setup.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;        ports:
            - "3307:3306"
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="7-build-and-start-the-environment"&gt;7. Build and Start the Environment&lt;/h3&gt;
&lt;p&gt;Now you're ready to build and start your environment. Open up a terminal and run the following command:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker compose up -d --build
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will use Docker Compose to build the containers and run them in detached mode. It may take a few minutes to complete if you're running this command for the first time. Docker will need to download all the images from the Docker repository before building.&lt;/p&gt;
&lt;h3 id="8-access-your-local-drupal-setup"&gt;8. Access Your Local Drupal Setup&lt;/h3&gt;
&lt;p&gt;If all goes well you should have your environment ready to install Drupal 7. Visit &lt;code&gt;http://localhost:8080&lt;/code&gt; in your browser to access the Drupal 7 instance running in the Docker container.&lt;/p&gt;
&lt;p&gt;Follow the installation wizard and
Use these database settings in your .env file.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span id="testing-workflow"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="6-testing-and-workflow"&gt;6. Testing and Workflow&lt;/h2&gt;
&lt;p&gt;You can use these commands to test your installation. Check the documentation in the &lt;a href="https://migratecontent.com/drupal-7-docker-containers-migration-projects/#additional-resources"&gt;Additional Resources&lt;/a&gt; section below for more commands.&lt;/p&gt;
&lt;h3 id="basic-testing"&gt;Basic Testing&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Container Status:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Check if all containers are running&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;ps
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Expected output: db, drupal and phpMyAdmin services should show "Up" status&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Drupal Installation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access the Drupal site at http://localhost:8088&lt;/li&gt;
&lt;li&gt;You should see the Drupal installation page or site&lt;/li&gt;
&lt;li&gt;Check error logs if needed:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;logs&lt;span class="w"&gt; &lt;/span&gt;drupal
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Drush Functionality:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Test Drush status&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;status

&lt;span class="c1"&gt;# Test Drush version&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;--version

&lt;span class="c1"&gt;# Test site-specific Drush commands&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;core-status
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Composer Functionality:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Test Composer version&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;--version

&lt;span class="c1"&gt;# Test Composer diagnostics&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;diagnose
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Database Connection:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Test database connection via Drush&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;sql-connect

&lt;span class="c1"&gt;# Test phpMyAdmin access&lt;/span&gt;
&lt;span class="c1"&gt;# Visit http://localhost:8081&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="testing-your-migration-utilities-with-sample-content"&gt;Testing Your Migration Utilities With Sample Content&lt;/h3&gt;
&lt;p&gt;You can use Drush to generate sample content. This can be useful for testing your migration utilities.&lt;/p&gt;
&lt;h4 id="1-log-into-the-containers-terminal"&gt;1. Log Into the Container's Terminal&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;bash
&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="2-install-helper-modules"&gt;2. Install Helper Modules&lt;/h4&gt;
&lt;p&gt;Install the &lt;code&gt;devel&lt;/code&gt;, &lt;code&gt;devel_generate&lt;/code&gt;, and &lt;code&gt;taxonomy_manager&lt;/code&gt; modules:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;drush&lt;span class="w"&gt; &lt;/span&gt;en&lt;span class="w"&gt; &lt;/span&gt;devel&lt;span class="w"&gt; &lt;/span&gt;-y
drush&lt;span class="w"&gt; &lt;/span&gt;en&lt;span class="w"&gt; &lt;/span&gt;devel_generate&lt;span class="w"&gt; &lt;/span&gt;-y
drush&lt;span class="w"&gt; &lt;/span&gt;en&lt;span class="w"&gt; &lt;/span&gt;taxonomy_manager&lt;span class="w"&gt; &lt;/span&gt;-y
&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Devel Module:&lt;/strong&gt; The Devel module is a comprehensive toolkit for Drupal developers that offers several submodules and features to aid in development and debugging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Devel Generate Module:&lt;/strong&gt; The Devel Generate module is a submodule of the Devel module, specifically designed for generating dummy content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taxonomy Manager Module:&lt;/strong&gt; Use the Taxonomy Manager module to mass insert taxonomy terms.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-generate-sample-content"&gt;3. Generate Sample Content&lt;/h4&gt;
&lt;p&gt;Now generate some sample content:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Generate nodes with randon content&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-content&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;

&lt;span class="c1"&gt;# Generate users&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-users&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;

&lt;span class="c1"&gt;# Generate taxonomy terms&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-terms&lt;span class="w"&gt; &lt;/span&gt;tags&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;

&lt;span class="c1"&gt;# Generate nodes for a specific content type&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-content&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--types&lt;span class="o"&gt;=&lt;/span&gt;article

&lt;span class="c1"&gt;# Generate comments on random nodes:&lt;/span&gt;
drush&lt;span class="w"&gt; &lt;/span&gt;generate-comments&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;250&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="development-workflow"&gt;Development Workflow&lt;/h3&gt;
&lt;p&gt;Here are some basic commands to support your development and migration workflow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Starting/Stopping Environment:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Start containers&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;-d

&lt;span class="c1"&gt;# Stop containers&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;down

&lt;span class="c1"&gt;# View logs&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;logs&lt;span class="w"&gt; &lt;/span&gt;-f
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Using Drush:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Access Drush&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush

&lt;span class="c1"&gt;# Clear cache&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;cc&lt;span class="w"&gt; &lt;/span&gt;all

&lt;span class="c1"&gt;# Update database&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;drush&lt;span class="w"&gt; &lt;/span&gt;updb
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Working with Composer:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Install dependencies&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;install

&lt;span class="c1"&gt;# Add new package&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;composer&lt;span class="w"&gt; &lt;/span&gt;require&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;package-name&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Service Access:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Drupal: http://localhost:8088&lt;ul&gt;
&lt;li&gt;Username and password as set during the installation process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;phpMyAdmin: http://localhost:8081&lt;ul&gt;
&lt;li&gt;Username: (from .env)&lt;/li&gt;
&lt;li&gt;Password: (from .env)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MySQL: localhost:3307&lt;ul&gt;
&lt;li&gt;Username: (from .env)&lt;/li&gt;
&lt;li&gt;Password: (from .env)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Database Operations:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Export database&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;db&lt;span class="w"&gt; &lt;/span&gt;mysqldump&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;user&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="o"&gt;[&lt;/span&gt;root-password&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;backup.sql

&lt;span class="c1"&gt;# Import database&lt;/span&gt;
docker&lt;span class="w"&gt; &lt;/span&gt;compose&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-T&lt;span class="w"&gt; &lt;/span&gt;db&lt;span class="w"&gt; &lt;/span&gt;mysql&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;user&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="o"&gt;[&lt;/span&gt;root-password&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;drupal&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;backup.sql
&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;p&gt;&lt;span id="preparing-migration"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="7-preparing-for-your-drupal-7-migration"&gt;7. Preparing for Your Drupal 7 Migration&lt;/h2&gt;
&lt;p&gt;If you made it this far, you will have a fully working and tested Docker container with Drupal 7, access to the database, and some basic tools to support migration or upgrade tasks. This environment isolates your development work, ensuring that your live site remains unaffected throughout the process.&lt;/p&gt;
&lt;h3 id="importing-your-live-drupal-installation-into-the-container"&gt;Importing Your Live Drupal Installation into the Container&lt;/h3&gt;
&lt;p&gt;To get started with your migration project, you'll need to transfer your existing live Drupal installation into the container. The Drupal 7 documentation for &lt;a href="https://www.drupal.org/docs/7/backing-up-and-migrating-a-site/migrating-a-site" target="_blank" rel="noopener noreferrer"&gt;migrating a site between environments&lt;/a&gt; will give you an outline of the steps.&lt;/p&gt;
&lt;p&gt;As a summary, you begin by exporting the database and files from your live site. Once you have these, you can load the database into the container's MySQL instance and place the site's files in the &lt;code&gt;./src&lt;/code&gt; directory on your host filesystem. (Remember, we created a bind mount to map the &lt;code&gt;./src&lt;/code&gt; directory to the container's web directory at &lt;code&gt;/var/www/html&lt;/code&gt;.) This gives you a working copy of your live site, but in a safe, sandboxed environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt; &lt;em&gt;In this article we used Drupal 7.103 for our container. To avoid problems with version conflicts, you should update your live Drupal site to the same version before exporting.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="creating-a-pristine-snapshot"&gt;Creating a Pristine Snapshot&lt;/h3&gt;
&lt;p&gt;Before diving into migration tasks, it's a good idea to create a snapshot of the container in its pristine state. This serves as a clean starting point you can revert to if anything goes wrong during the migration process. A snapshot ensures you won't need to repeat the setup steps from scratch if you need to restart or experiment with different migration approaches.&lt;/p&gt;
&lt;p&gt;You create a snapshot by committing the current state of your container to a new Docker image. I'll cover this in a separate article but at this stage you will now be ready to use whatever tools you need to upgrade or migrate your Drupal 7 installation.&lt;/p&gt;
&lt;h3 id="migration-options"&gt;Migration Options&lt;/h3&gt;
&lt;p&gt;Instructions for the migration itself will need to be covered elsewhere as it's a very detailed process. However, you can check these resources for your migration options:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Upgrading to a newer version of Drupal&lt;/strong&gt;: You can use your container to trial-run the upgrade steps in the Drupal documentation, "&lt;a href="https://www.drupal.org/docs/upgrading-drupal/upgrading-from-drupal-6-or-drupal-7" target="_blank" rel="noopener noreferrer"&gt;Upgrading from Drupal 6 or Drupal 7&lt;/a&gt;."&lt;/li&gt;

    &lt;li&gt;&lt;strong&gt;Migrating to another platform:&lt;/strong&gt; If you plan to migrate to another platform such as WordPress, please see our &lt;a href="https://migratecontent.com/how-we-migrate-technical-process/" title="Drupal to WordPress Migration Guide"&gt;Drupal to WordPress Migration Guide&lt;/a&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;hr&gt;
&lt;p&gt;&lt;span id="conclusion"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="8-conclusion"&gt;8. Conclusion&lt;/h2&gt;
&lt;p&gt;Docker provides a very practical and reliable way to set up migration environments. While it requires an initial investment in learning, the long-term benefits include consistent workflows, reliable environments, and over-all, fewer frustrations when getting started with a migration project. Docker won't solve every migration challenge, but in my experience, it definitely simplifies many of the technical hurdles involved.&lt;/p&gt;
&lt;p&gt;If you're facing challenges with Drupal 7 migrations or need expert assistance, &lt;a href="https://migratecontent.com/contact/"&gt;reach out to us&lt;/a&gt;. We can help make your next project smooth, efficient, and future-proof.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;span id="additional-resources"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id="additional-resources"&gt;Additional Resources&lt;/h2&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="https://www.drupal.org/docs" target="_blank" rel="noopener noreferrer"&gt;Official Drupal Documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://docs.docker.com/" target="_blank" rel="noopener noreferrer"&gt;Docker Documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://www.drush.org/latest/" target="_blank" rel="noopener noreferrer"&gt;Drush Documentation&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://getcomposer.org/doc/" target="_blank" rel="noopener noreferrer"&gt;Composer Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h3&gt;Need Help With Your Drupal 7 Migration?&lt;/h3&gt;

&lt;p&gt;I specialise in complex Drupal to WordPress migrations, including setting up Docker-based development environments, custom migration scripts, and zero-downtime launches. Get a free, no-obligation consultation.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your Drupal 7 migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>docker</category><category>drupal</category><category>drupal-7</category><category>migration</category><guid>https://migratecontent.com/drupal-7-docker-containers-migration-projects/</guid><pubDate>Mon, 09 Sep 2024 13:25:15 GMT</pubDate></item><item><title>How to quickly migrate your WordPress site using the Backup Migration plugin</title><link>https://migratecontent.com/how-to-quickly-migrate-your-wordpress-site-using-the-backup-migration-plugin/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;p&gt;&lt;em&gt;This WordPress migration guide using the&lt;strong&gt; Backup Migration plugin&lt;/strong&gt; is a non-sponsored guest post by Emma from &lt;a href="https://backupbliss.com/" target="_blank" rel="noreferrer noopener"&gt;BackupBliss&lt;/a&gt;, creator of the plugin.&lt;/em&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;em&gt;You may not have heard of BackupBliss as, it being a relatively new entrant to the backup and migration plugin space, doesn't appear in the usual 'top plugins' style articles. Nevertheless, I have personally used the Backup Migration plugin and find it a good alternative to more familiar names such as All-in-One WP Migration&lt;/em&gt;, &lt;em&gt;&lt;a href="https://migratecontent.com/how-to-quickly-migrate-your-wordpress-site-using-the-backup-migration-plugin/"&gt;BlogVault&lt;/a&gt; and UpdraftPlus. My standard plugin for many years has been BackUpWordPress, formerly by Human Made and then taken over by XIBO Ltd. Unfortunately, XIBO seems to have abandoned the plugin so I am now looking for a replacement. I am hopeful that BackupBliss may be a contender.&lt;/em&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;em&gt;Read on for the main article.&lt;/em&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:separator {"className":"is-style-wide"} --&gt;
&lt;hr class="wp-block-separator has-alpha-channel-opacity is-style-wide"&gt;
&lt;!-- /wp:separator --&gt;

&lt;!-- wp:heading --&gt;
&lt;h2 class="wp-block-heading"&gt;Migrating your WordPress site using the Backup Migration plugin by BackupBliss&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Migrating today’s average WordPress site, which has around two dozen plugins and weighs about 1GB, can be a swift task for site owners looking for an easy solution through a plugin. In this article, I will guide you through the steps that will lead you to a successful website migration with the free &lt;a href="https://wordpress.org/plugins/backup-backup/" target="_blank" rel="noreferrer noopener nofollow"&gt;Backup Migration plugin&lt;/a&gt;.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Migration with a plugin usually works flawlessly when done on common hosting providers, and when the website uses up-to-date components such as the latest WordPress and PHP versions, as well as widely used page-builders, themes, and plugins.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;However, things might get tricky when in play is outdated software, large databases, highly customized themes, etc. In such cases, and in all other cases where you get stuck with the website migration, I recommend that you &lt;a href="https://anothercoffee.net/content-migration-process/"&gt;turn to a professional&lt;/a&gt;.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 class="wp-block-heading"&gt;Preparation&lt;/h3&gt;
&lt;!-- /wp:heading --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;The whole process of WordPress site migration with a Backup Migration plugin basically consists of two parts - backup creation on the old site and backup restoration on the new site (migration). But let’s mention first a couple of things you should do before migration:&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;1. Installing the Backup Migration plugin on the old site. You can search for and install it as any other free WP plugin, in the website’s Dashboard section “Plugins”.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:image {"id":4936,"sizeSlug":"large","linkDestination":"none"} --&gt;
&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://migratecontent.com/wp-content/uploads/Backup-Migration-Plugin-Install-1024x404.jpg" alt="Backup Migration Plugin Install screen" class="wp-image-4936"&gt;&lt;/figure&gt;
&lt;!-- /wp:image --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;2. Setting up a fresh WordPress instance in the place where the new site will be. Most of the big hosting companies have a one-click solution for this, but it is also not too hard to &lt;a href="https://wordpress.org/support/article/how-to-install-wordpress/"&gt;set it up&lt;/a&gt; yourself if an automated option is not available to you. You will also need to add a Backup Migration plugin to that instance, the same as on the old site.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;3. Excluding unnecessary files from the migration. As a variation of a clean-up, it might be a good time to think about the unused files and plugins that you have on your old site and perhaps add a few exclusion rules when you start creating a website backup in the following chapter.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 class="wp-block-heading"&gt;Backup creation&lt;/h3&gt;
&lt;!-- /wp:heading --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;The website backup is created in a couple of steps:&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;1. Once you have the Backup Migration plugin installed on your website, it will automatically redirect you to its menu page within the WordPress Dashboard. Navigate to the plugin area “What will be backed up?”, where you should checkmark all files, folders, and complete database, and click on the Save button. This assures that a full site backup will be created.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:image {"id":4938,"sizeSlug":"large","linkDestination":"none"} --&gt;
&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://migratecontent.com/wp-content/uploads/Backup-Migration-Plugin-Settings-1024x683.jpg" alt="Backup Migration Plugin Settings screen" class="wp-image-4938"&gt;&lt;/figure&gt;
&lt;!-- /wp:image --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;In this menu, you will be able to see the raw sizes of folders and databases that are on your site. It might give you an idea if there is something that you want to exclude. To exclude any specific files and folders, turn on the option for it to “Yes” and carefully compose the list.&lt;br&gt;&lt;br&gt;By default, this plugin will already suggest some common exclusions, and provide examples on how to make some of your own. Remember to Save these settings if you make any changes.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:image {"id":4935,"sizeSlug":"large","linkDestination":"none"} --&gt;
&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://migratecontent.com/wp-content/uploads/Backup-Migration-Plugin-Exclusions-1024x598.jpg" alt="Backup Migration Plugin Exclusions screen" class="wp-image-4935"&gt;&lt;/figure&gt;
&lt;!-- /wp:image --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;2. Click the “Create backup now!” button, and the plugin will swiftly commence the backup process, typically wrapping up in just a minute or two for average websites. The duration primarily depends on the database size and server setup. If you're dealing with larger sites exceeding 2GB, consider the &lt;a href="https://backupbliss.com/" target="_blank" rel="noreferrer noopener nofollow"&gt;premium Backup Migration plugin&lt;/a&gt; for enhanced performance. Once the backup process concludes, you'll have the option to download the backup file, a highly advisable practice for preserving a local copy of your backup.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 class="wp-block-heading"&gt;Migration job&lt;/h3&gt;
&lt;!-- /wp:heading --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;The second major part, the migration process is taking place on the destination site, which we mentioned in the Preparation section of this article.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Here are the steps to be taken on this site:&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Navigate to the plugin area “Manage &amp;amp; Restore Backup(s)”, where there are three options to restore a backup from the source site. In cases when the site is being moved to a new domain, option A is a fitting choice, and for the cases when domains remain unchanged, then options B or C are more appropriate, as in these cases, site owners will need to take down the source site before making the new website go live&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;strong&gt;A. Super-Quick Migration&lt;/strong&gt;: To use this functionality, simply paste the link to the backup file from the source website and click the "Restore Now!" button. You can obtain these backup links in the same plugin section under "Manage &amp;amp; Restore Backup(s)" by clicking the small link icon.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;strong&gt;B. Upload Backup Files&lt;/strong&gt;: To use this option, you can manually upload backup (zip) files within the same plugin section. You have the choice of selecting the file or using a drag-and-drop method. After successfully uploading the backup file, initiate the restoration process by clicking the "Restore" button located on the right side of the listed backup file.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;strong&gt;C. External Storage Location&lt;/strong&gt;: If you prefer to store your backups in an external location, you can select options like Google Drive (others are yet to come). To use this feature and synchronize your backup files across your online websites, connect your Google account in the Backup Migration plugin section titled "Where Shall the Backup(s) Be Stored?". Once the Google account is connected and the backup file is synchronized, start the restore process by clicking the "Restore" button in the "Manage &amp;amp; Restore Backups" plugin section.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:image {"id":4937,"sizeSlug":"large","linkDestination":"none"} --&gt;
&lt;figure class="wp-block-image size-large"&gt;&lt;img src="https://migratecontent.com/wp-content/uploads/Backup-Migration-Plugin-Restore-1024x379.jpg" alt="Backup Migration Plugin Restore screen" class="wp-image-4937"&gt;&lt;/figure&gt;
&lt;!-- /wp:image --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;If you have migrated your site with option A, and after you have checked out the new site, you may want to archive the old site. Nevertheless, if you want to want to keep the old site online, it's typically recommended to configure suitable redirects from the old domain to the new one.&lt;br&gt;&lt;br&gt;Thankfully, Inisev, a company that developed the Backup Migration plugin, offers a user-friendly Redirection plugin for this purpose, featuring a recognizable intuitive interface that enables a swift and efficient setup of redirections.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 class="wp-block-heading"&gt;Post-migration &lt;/h3&gt;
&lt;!-- /wp:heading --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Once the migration work is over, you might want to keep the Backup Migration plugin on your new site, for multiple reasons.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;The most important one is that you can create regular website backups with it, which can also be scheduled, so you will not have to stress out in case something goes bad on the site and it becomes broken or even unavailable to the users. Though most of the big hosting companies offer the backup option, the solution from the plugin might be a quicker and more user-friendly way to restore your website, especially if you are not a tech-savvy person.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;The Backup Migration plugin can also easily create a staging site for you, so the big changes that you plan for your website will not pose a threat to it, as you can test it all out safely on the &lt;a href="https://anothercoffee.net/wordpress-backups-and-staging-guide/"&gt;staging environment&lt;/a&gt;.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 class="wp-block-heading"&gt;Final Thoughts&lt;/h3&gt;
&lt;!-- /wp:heading --&gt;

&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Migrating a WordPress with a plugin can turn out to be a seamless task. However, it has to be kept in mind, that there are tens of thousands of combinations of servers, hosting providers, and WordPress sites and that migration tools are impossible to optimize to do the job flawlessly on &lt;strong&gt;each &lt;/strong&gt;combination. This is just one of the reasons why having top-notch professionals for help is important, and if you are in such need - you know where to &lt;a href="https://anothercoffee.net/#contact"&gt;contact us&lt;/a&gt;.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;

&lt;!-- wp:html --&gt;
&lt;div style="margin: 2em 0 2em 0; padding: 1em 2em 1em 2em; font-weight: 400; text-align: center; color: #444; background-color: #f5f5f5; border: 3px solid #e9ecef;"&gt;&lt;em&gt;This is a non-sponsored guest post by Emma from &lt;a href="https://backupbliss.com/" target="_blank" and rel="nofollow noopener"&gt;BackupBliss&lt;/a&gt;&lt;/em&gt;.&lt;/div&gt;
&lt;!-- /wp:html --&gt;</description><category>backupbliss</category><category>backups</category><category>migration</category><category>plugin</category><category>wordpress</category><guid>https://migratecontent.com/how-to-quickly-migrate-your-wordpress-site-using-the-backup-migration-plugin/</guid><pubDate>Sat, 28 Oct 2023 10:56:11 GMT</pubDate></item><item><title>Fixing Access Forbidden (403) issues after migrating WordPress to a static site</title><link>https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;p&gt;After migrating a WordPress site to static files, Google Search Console may start sending you notifications about page indexing problems. Often the issue will be marked as '&lt;em&gt;Blocked due to access forbidden (403)&lt;/em&gt;', a fairly common error that can have different causes, depending on how your website and server is set up.&lt;/p&gt;


&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/no-entry-Lucian-Alexe-Unsplash-l0w1ftNPZ9s.jpg" alt="No entry road stock photo - Access Forbidden 403 error" class="figure-img img-fluid rounded" width="800" height="417"&gt;
&lt;/figure&gt;

&lt;p&gt;This article specifically deals with the case when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You previously had a working WordPress installation;&lt;/li&gt;
&lt;li&gt;You migrate the site to static HTML files on an Apache web server;&lt;/li&gt;
&lt;li&gt;Google Search Console starts complaining about page indexing problems.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If this does not apply to your situation, the proposed solution may not work but you will still find the explanation useful in diagnosing the problem.&lt;/p&gt;
&lt;h2&gt;Table of contents&lt;/h2&gt;
&lt;div class="toc"&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/#forbidden-403"&gt;The Forbidden 403 error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/#wordpress-requests"&gt;How WordPress serves your browser requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/#static-files"&gt;Serving static files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/#directory-index"&gt;Web server directory index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/#generating-static-site"&gt;Generating static HTML files from a WordPress site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/#why-forbidden"&gt;Why access is forbidden&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/#how-to-fix"&gt;How to fix the Access Forbidden (403) error&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;

&lt;h2 id="forbidden-403"&gt;The Forbidden 403 error&lt;/h2&gt;
&lt;p&gt;Being in the 4XX category of HTTP response codes, &lt;em&gt;Access Forbidden (403)&lt;/em&gt; is a client-side error that may show in a message similar to the following combinations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Access Forbidden (403)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;403 Forbidden&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTTP 403&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;HTTP Error 403 – Forbidden&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Forbidden: You don't have permission to access [directory path] on this server&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Google Search Console notification email will be about page indexing problems with  '&lt;em&gt;Blocked due to access forbidden (403)&lt;/em&gt;' as one of the Top Issues.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/anothercoffee-google-search-console-page-indexing-issues.png" alt="Google Search Console Page indexing issues" class="figure-img img-fluid rounded" width="498" height="348"&gt;
    &lt;figcaption&gt;A typical Access Forbidden (403) notification from the Google Search Console&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Nevertheless, it being a client-side error doesn't necessary isolate the problem to your browser. Many solutions online will advise you to clear your cache or refresh the page. This is easy to do and usually a sensible first step but if you found the issue via a Google Search Console notification after a WordPress migration, these recommendations won't help.&lt;/p&gt;
&lt;p&gt;The 403 response code essentially means that a web client, such as your browser, does not have permission to access the requested resource. The web server understands the request but can't allow access due to file permissions settings or a server misconfiguration. When it comes to WordPress, the error will almost certainly be due to a misbehaving plugin, a &lt;a href="https://kinsta.com/blog/403-forbidden-error/" target="_blank" rel="noreferrer noopener nofollow"&gt;corrupt .htaccess file or incorrect file permissions&lt;/a&gt;. However, if you've recently converted your WordPress installation to a static site, the error will most likely have a different cause.&lt;/p&gt;
&lt;p&gt;To understand why the &lt;em&gt;Access Forbidden&lt;/em&gt; error happens, it's worth reviewing the differences between how the WordPress content management system (CMS) serves content and how a static site responds to web client requests.&lt;/p&gt;

&lt;h2 id="wordpress-requests"&gt;How WordPress serves your browser requests&lt;/h2&gt;
&lt;p&gt;WordPress is a database-driven Content management system (CMS). Most of the content is stored in a database and URLs generally do not correspond to any files in the web server's filesystem. Instead, URLs are external references to the database content. WordPress calls these references &lt;em&gt;permalinks&lt;/em&gt; and its rewriting engine uses internal &lt;a href="https://codex.wordpress.org/Using_Permalinks"&gt;rules&lt;/a&gt;, specified in the &lt;a href="https://codex.wordpress.org/Using_Permalinks#Choosing_your_permalink_structure"&gt;permalink settings&lt;/a&gt;, to build permalinks dynamically. When a client requests a page from the site, WordPress takes care of serving the correct content. Included with the pages will be any XML-based RSS (Really Simple Syndication) feeds. WordPress will send the HTML page or an XML feed, depending on what the client requests.&lt;/p&gt;
&lt;p&gt;For example, if you set the permalink settings to the &lt;em&gt;Post name&lt;/em&gt; structure, WordPress will generate a HTML post when you browse to the following URL:&lt;br&gt;&lt;code&gt;https://example.com/your-post/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The RSS feed for that post will be at:&lt;br&gt;&lt;code&gt;https://example.com/your-post/feed/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;RSS feeds are normally parsed by an RSS client rather than for displaying directly in the browser window so requesting the RSS feed resource will not send HTML. Instead WordPress will generate XML for the feed.&lt;/p&gt;

&lt;h2 id="static-files"&gt;Serving static files&lt;/h2&gt;
&lt;p&gt;By definition, static sites have no way of dynamically generating content based on the browser request. You make a request to the web server at a given URL and if the resource is present with the correct access permissions, the web server will go ahead and serve the file. The URL for a static site will normally look something like:&lt;br&gt;&lt;code&gt;https://example.com/your-post.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you have an RSS feed, it might look something like:&lt;br&gt;&lt;code&gt;https://example.com/feed.xml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Notice that the request includes the path to the file, such as &lt;code&gt;your-post.html&lt;/code&gt; or &lt;code&gt;feed.xml&lt;/code&gt;. The file is not present in a WordPress permalink because, as mentioned previously, it is only a reference to the actual content stored in the database.&lt;/p&gt;

&lt;h2 id="directory-index"&gt;Web server directory index&lt;/h2&gt;
&lt;p&gt;Web servers such as Apache also have a &lt;a href="https://httpd.apache.org/docs/2.4/mod/mod_dir.html#directoryindex" target="_blank" rel="noreferrer noopener nofollow"&gt;Directory Index directive&lt;/a&gt;. This is a configuration that can set the server to automatically send a file when a client makes a request without a filename in the URL. The file known as the directory index and is normally named &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Web servers such as Apache also have a &lt;a href="https://httpd.apache.org/docs/2.4/mod/mod_dir.html#directoryindex" target="_blank" rel="noreferrer noopener nofollow"&gt;Directory Index directive&lt;/a&gt;. In the early days of the web, you could browse to a folder in the web server filesystem and get a listing of all the files present. For security, most web hosts now disable this feature for most of their hosting services. The Directory Index directive is a configuration that can set the server to automatically send a file when a client request only includes the folder name in the URL. For most hosting services, the standard directory index files are normally &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;index.php&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Say a client makes a request for the following:&lt;br&gt;&lt;code&gt;https://example.com/docs/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If the directory index is set to &lt;code&gt;index.html&lt;/code&gt;, the server would return:&lt;br&gt;&lt;code&gt;http://example.com/docs/index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;index.html&lt;/code&gt; renders as a web page in the browser. Directory index resources can also be set to other file types like &lt;code&gt;index.txt&lt;/code&gt; or &lt;code&gt;index.xml&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="generating-static-site"&gt;Generating static HTML files from a WordPress site&lt;/h2&gt;
&lt;p&gt;WordPress plugins such as &lt;a href="https://wordpress.org/plugins/simply-static/" target="_blank" rel="noreferrer noopener nofollow"&gt;Simply Static&lt;/a&gt; will crawl your site to generate static HTML file copies for the pages. Since WordPress includes RSS feeds, static XML copies will also be generated for these feeds. The tables below show typical WordPress permalinks and their equivalents after static HTML copies are generated.&lt;/p&gt;
&lt;figure class="wp-block-table"&gt;
&lt;table class="has-fixed-layout"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="width:30%"&gt;Page type&lt;/th&gt;
&lt;th&gt;WordPress permalink&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page content&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;code&gt;https://example.com/your-post/&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RSS feed&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;code&gt;https://example.com/your-post/feed/&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/figure&gt;
&lt;figure class="wp-block-table"&gt;
&lt;table class="has-fixed-layout"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="width:30%"&gt;Page type&lt;/th&gt;
&lt;th&gt;Static file URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page content&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;code&gt;https://example.com/your-post/index.html&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RSS feed&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;code&gt;https://example.com/your-post/feed/index.xml&lt;/code&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/figure&gt;
&lt;p&gt;Once again notice that the static site specifies the filename in the path whereas the WordPress permalink, when set to the &lt;em&gt;Post name&lt;/em&gt; structure, does not.&lt;/p&gt;
&lt;h2 id="why-forbidden"&gt;Why access is forbidden&lt;/h2&gt;
&lt;p&gt;We have all the puzzle pieces to understand why you would get the &lt;em&gt;Access Forbidden (403)&lt;/em&gt; error and how you can fix the problem. After you migrate your WordPress site to static files, the old permalink paths to pages will still serve a web page because most hosting providers have &lt;code&gt;index.html&lt;/code&gt; as a directory index resource.&lt;/p&gt;
&lt;p&gt;You can request the URL in the WordPress post name permalink format:&lt;br&gt;&lt;code&gt;https://example.com/your-post/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The static file generator would have created an index.html in this location:&lt;br&gt;&lt;code&gt;https://example.com/your-post/&lt;/code&gt;index.html&lt;/p&gt;
&lt;p&gt;The webserver sees the &lt;code&gt;index.html&lt;/code&gt; in the filesystem and delivers it to the browser which can render the web page content. Human site visitors will be perfectly happy because they receive the web page resources they expect. However, Googlebot, Google's web page crawler, will spider through your site &lt;em&gt;including the RSS feed locations&lt;/em&gt;. Remember, the RSS feed folders will contain an &lt;code&gt;index.xml&lt;/code&gt;. XML files are not normally a default directory index resource for most web hosts. Since there is no &lt;code&gt;index.html&lt;/code&gt; file in the feed folder, the web server thinks it's being asked to deliver a file listing. Again remember that file listings are disabled by most web hosts for security. Thus you get the error:&lt;/p&gt;
&lt;p class="has-text-align-center"&gt;&lt;code&gt;Access Forbidden (403)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You are forbidden by the web server to access that folder listing.&lt;/p&gt;

&lt;h2 id="how-to-fix"&gt;How to fix the Access Forbidden (403) error&lt;/h2&gt;
&lt;p&gt;Now that we know exactly why we get this error we attempt a fix. If your host runs Apache, the solution will likely be simple. Edit or create the &lt;code&gt;.htaccess&lt;/code&gt; file in the root of your site and add &lt;code&gt;index.xml&lt;/code&gt; to the list of directory index resources. For example, if it not already there, add the following line somewhere near the top of the file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DirectoryIndex index.html index.php index.xml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;index.xml&lt;/code&gt; in the list will tell Apache to serve the XML file when Googlebot requests the RSS feed directory. While you're doing this, inspect a few o the feed directories to make sure the &lt;code&gt;index.xml&lt;/code&gt; files have the correct permissions (usually &lt;code&gt;775&lt;/code&gt; for most server setups) and the correct ownership. The ownership settings should be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;user&lt;/code&gt;&lt;/strong&gt; is the user account with root privileges on your web server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;group&lt;/code&gt;&lt;/strong&gt; is usually &lt;strong&gt;&lt;code&gt;www-data&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;apache&lt;/code&gt;&lt;/strong&gt; but you may need to check this with your hosting provider.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can test your changes by pointing your browser to a few feed directories to see if the server returns XML. Remember to leave out the &lt;code&gt;index.xml&lt;/code&gt; file and specify the directory only. For example:&lt;br&gt;&lt;code&gt;https://example.com/your-post/feed/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If your browser displays the RSS feed XML, you know the problem has been solved and can be reasonably confident that Googlebot won't encounter the 403 error.&lt;/p&gt;
&lt;p&gt;This may not work if you're running a VPS server for your site where some more in-depth configuration may be needed, such as editing your Apache configuration files. Also, &lt;code&gt;.htaccess&lt;/code&gt; is not used by other web servers such as NGINX. In these cases, your next port of call should be to contact your hosting provider. Tell them that you would like to add &lt;code&gt;index.xml&lt;/code&gt; to the directory index resources so that the XML file is served when a visitor lands in a directory. Most good hosting companies will be able to guide you on your options or make the change on your behalf. After you've applied the fix, be sure to go to your Google Search Console to revalidate the affected page.&lt;/p&gt;

&lt;div class="footnotes"&gt;
    &lt;p&gt;Photo by &lt;a href="https://unsplash.com/@lucian_alexe?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="nofollow"&gt;Lucian Alexe&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/l0w1ftNPZ9s?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="nofollow"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description><category>apache</category><category>blog</category><category>help</category><category>migration</category><category>seo</category><category>sys admin</category><category>troubleshooting</category><category>wordpress</category><guid>https://migratecontent.com/fixing-access-forbidden-403-issues-after-migrating-wordpress-to-a-static-site/</guid><pubDate>Thu, 09 Feb 2023 01:15:57 GMT</pubDate></item><item><title>How to set up a MySQL database server on Ubuntu for Drupal to WordPress migrations</title><link>https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;p&gt;Content Management System (CMS) migration projects involve moving data between databases with different schemas. Table names, field types and constraints often don't match up, leading to a number of frustrating errors. This is especially the case with &lt;a href="https://migratecontent.com/content-migration-process/"&gt;highly complex Drupal to WordPress migrations&lt;/a&gt; that use custom scripts to extract, transform and load the data. These projects can seem like you're constantly hitting roadblocks throughout. I've found from experience that running the migration in an appropriate development environment can reduce a great deal of effort. In this guide, I will describe how to set up a MySQL database server on Ubuntu for Drupal to WordPress migrations.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/rubaitul-azad-Y9kOsyoWyaU-unsplash.jpg" alt="MySQL database logo" class="figure-img img-fluid rounded" width="800" height="500"&gt;
&lt;/figure&gt;

&lt;h2 id="drupal-to-wordPress-mysql-server-toc"&gt;Table of contents&lt;/h2&gt;
&lt;div class="toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#why-mysql-ubuntu"&gt;Why MySQL and Ubuntu?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#installing-mysql-for-migrations"&gt;Installing MySQL on Ubuntu for CMS migrations&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#setup-lamp-migration-platform"&gt;Set up your Ubuntu LAMP migration platform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#install-mysql"&gt;Install MySQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#setting-sql-mode"&gt;Setting the MySQL server SQL mode&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#set-global-sql-mode"&gt;Option 1: Setting the global sql_mode in the database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#set-mysql-config-file"&gt;Option 2: setting the sql_mode in the MySQL configuration file&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#locating-mysql-conf"&gt;Locating the MySQL configuration file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#edit-mysql-config-file"&gt;Editing the MySQL configuration file&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#potential-errors"&gt;Potential errors&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#mysqldump-access-denied-when-trying-to-dump-tablespaces"&gt;mysqldump access denied when trying to dump tablespaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#ERROR-1067-42000-Invalid-default-value"&gt;ERROR 1067 (42000) Invalid default value&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#Expression-1-of-SELECT-list-is-not-in-GROUP-BY-clause"&gt;Expression #1 of SELECT list is not in GROUP BY clause&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#Error-Code-2013-Lost-connection-to-MySQL-server"&gt;Error Code: 2013. Lost connection to MySQL server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;h2 id="why-mysql-ubuntu"&gt;Why MySQL and Ubuntu?&lt;/h2&gt;
&lt;p&gt;The first thing to address is &lt;em&gt;why MySQL and Ubuntu?&lt;/em&gt; How about MariaDB? How about Arch Linux, Mac OS or Windows? Yes! Any platform that runs Drupal and WordPress will work for your migration environment so you can use whatever you prefer. Personally, I have a fondness for &lt;a href="https://www.openbsd.org/" target="_blank" rel="noreferrer noopener"&gt;OpenBSD&lt;/a&gt; but it's not a practical platform for a CMS migration. OpenBSD's niche user-base means you'll spend much longer installing necessary tools and troubleshooting errors.&lt;/p&gt;
&lt;p&gt;There are all sorts of tutorials covering MySQL on Ubuntu. This means you're more likely to quickly find a solution from a web search when you hit a problem. Furthermore, if you need a software utility or program to help you get the job done, it will probably be available through &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;dpkg&lt;/code&gt;,  &lt;code&gt;snap&lt;/code&gt; or &lt;code&gt;tasksel&lt;/code&gt;. Use whatever you like but for now, MySQL on Ubuntu is my recommended platform for Drupal to WordPress migrations. I expect this will be the case for some time to come. These projects are complex and time-consuming enough without making the &lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#mariadb-mysql-purge"&gt;job more difficult&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="installing-mysql-for-migrations"&gt;Installing MySQL on Ubuntu for CMS migrations&lt;/h2&gt;
&lt;p&gt;There are many detailed tutorials for installing MySQL on Ubuntu. DigitalOcean's &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04" target="_blank" rel="noreferrer noopener nofollow"&gt;How To Install MySQL on Ubuntu 20.04&lt;/a&gt; is a good one and writing another won't add much value. My guide will therefore only give a brief overview of the MySQL server installation steps. Instead, I will focus on the configuration areas specifically related avoiding problems on a CMS migration project.&lt;/p&gt;
&lt;p&gt;You may wonder why the migration environment should be much different from a live server. Migration projects require you to do things that aren't supported by the CMS platform. You're therefore likely to encounter &lt;a href="https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/#potential-errors"&gt;weird errors&lt;/a&gt; that aren't normally found when running standard Drupal or WordPress.&lt;/p&gt;

&lt;h3 id="setup-lamp-migration-platform"&gt;Set up your Ubuntu LAMP migration platform&lt;/h3&gt;
&lt;p&gt;The main source of unusual errors is almost certainly because you're migrating on a setup suited to a live website. Live server configurations are more restrictive than you need for a migration project. You can therefore save yourself a huge headache by rolling your own local migration environment. It might take a little longer to get started but you'll save time by avoiding lots of unnecessary troubleshooting.&lt;/p&gt;
&lt;p&gt;I must highlight that this will be a &lt;em&gt;local migration environment&lt;/em&gt; and should not be accessible from the public internet. The normal security considerations with running a live content management system don't apply when you're working locally. By all means follow basic security measures mentioned the various tutorials for setting up Ubuntu and MySQL. Nevertheless, a highly secure setup is counterproductive for these projects and you can avoid trouble by being a little more permissive.&lt;/p&gt;
&lt;p&gt;Go ahead and &lt;a href="https://ubuntu.com/tutorials/install-ubuntu-desktop" target="_blank" rel="noreferrer noopener"&gt;install Ubuntu Desktop&lt;/a&gt;. Since this will be a development environment, you'll want the Desktop environment rather than the more lightweight server version. Of course, you'll still need to install a web and database server. &lt;a href="https://upcloud.com/community/tutorials/installing-lamp-stack-ubuntu/" target="_blank" rel="noreferrer noopener"&gt;Follow these instructions for installing LAMP stack&lt;/a&gt; but skip the step of installing MariaDB. As mentioned above, we'll be using MySQL.&lt;/p&gt;


&lt;div id="mariadb-mysql-purge" class="alert alert-warning"&gt;
&lt;p class="has-text-align-left"&gt;&lt;strong&gt;WARNING:&lt;/strong&gt; Installing MariaDB over MySQL or vice versa on Ubuntu 20.04 may lead to all sorts of &lt;a href="https://askubuntu.com/questions/1300304/mysql-not-working-after-uninstall-mariadb-in-ubuntu" target="_blank" rel="noreferrer noopener"&gt;problems starting up the database server&lt;/a&gt; with errors like the following:&lt;/p&gt;
&lt;p class="has-text-align-left"&gt;&lt;code&gt;Failed to start mysqld.service: Unit mysqld.service not found&lt;/code&gt;.&lt;/p&gt;
&lt;p class="has-text-align-left"&gt;The last time I did this, none of solutions mentioned online for purging the installation worked. I spent most of a day trying to fix the problem. In the end, I realised it was quicker to start again and rebuild the machine from scratch. This is a big reason why I decided to stick with MySQL as standard for my projects.&lt;/p&gt;
&lt;/div&gt;

&lt;h3 id="install-mysql"&gt;Install MySQL&lt;/h3&gt;
&lt;p&gt;You can read a more detailed tutorial on &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04" target="_blank" rel="noreferrer noopener"&gt;installing MySQL on Ubuntu&lt;/a&gt; but here's an overview.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update the package index on your server: &lt;code&gt;sudo apt update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install MySQL server: &lt;code&gt;sudo apt install mysql-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Secure MySQL: &lt;code&gt;sudo /usr/bin/mysql_secure_installation&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;mysql_secure_installation&lt;/code&gt; script doesn't cause problems for migrations so it's worth running.&lt;/p&gt;
&lt;p&gt;Create an admin user:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE USER 'user'@'localhost' IDENTIFIED BY 'userpassword';
GRANT ALL PRIVILEGES ON *.* to 'user'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
quit;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now create a user and database for your migration project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE USER 'projectuser'@'localhost' IDENTIFIED BY 'password';

CREATE DATABASE project_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;
GRANT ALL ON project_db.* TO 'projectuser'@'localhost';&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can give this user more restrictive permissions but &lt;code&gt;GRANT ALL&lt;/code&gt; avoids errors when running scripts and SQL queries on the database. Only the migration team should have access and you won't need it after the migration so why not make your life easier? &lt;/p&gt;

&lt;h2 id="setting-sql-mode"&gt;Setting the MySQL server SQL mode&lt;/h2&gt;
&lt;p&gt;It's possible that you won't be familiar with &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html" target="_blank" rel="noreferrer noopener"&gt;SQL modes&lt;/a&gt; unless you've done some database administration work. For our purposes, SQL modes do two things:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;change the types of queries you can run on your MySQL server;&lt;/li&gt;
&lt;li&gt;change the validation checks when altering the data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've found that specific SQL modes need to be set for Drupal to WordPress projects. You may find that all sorts of strange errors appear if the correct modes aren't set. The following sections show you two ways to set your MySQL server's SQL mode.&lt;/p&gt;

&lt;h3 id="set-global-sql-mode"&gt;Option 1: Setting the global sql_mode in the database&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Login in to database as an admin user.&lt;/li&gt;
&lt;li&gt;View the current sql-modes using &lt;code&gt;SELECT @@GLOBAL.sql_mode;&lt;/code&gt; and make a copy if necessary.&lt;/li&gt;
&lt;li&gt;Copy the current modes (add or delete modes as needed) and paste in next step.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;ALLOW_INVALID_DATES&lt;/code&gt; and removes both &lt;code&gt;NO_ZERO_DATE, NO_ZERO_IN_DATE&lt;/code&gt; by setting the sql-modes with&lt;br&gt;&lt;code&gt;SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,ALLOW_INVALID_DATES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';&lt;/code&gt; (WARNING: check the modes correspond with your setup.)&lt;/li&gt;
&lt;li&gt;Restart server:&lt;br&gt;&lt;code&gt;sudo systemctl start mysql&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id="set-mysql-config-file"&gt;Option 2: setting the sql_mode in the MySQL configuration file&lt;/h3&gt;
&lt;h4 id="locating-mysql-conf"&gt;Locating the MySQL configuration file&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;my.cnf&lt;/code&gt; configuration file isn't always found in the same place. It's specific to the Linux distribution and server configuration but can normally found in one of the following locations:&lt;/p&gt;
&lt;pre class="wp-block-preformatted"&gt;/etc/my.cnf
/etc/mysql/my.cnf
echo/my.cnf
[datadir]/my.cnf
~/.my.cnf&lt;/pre&gt;

&lt;p&gt;If you can't find your MySQL configuration file, you can try running &lt;code&gt;locate my.cnf&lt;/code&gt; or &lt;code&gt;mysqladmin --help&lt;/code&gt;. The latter will show something like the following in the output:&lt;/p&gt;

&lt;pre class="wp-block-preformatted"&gt;Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf&lt;/pre&gt;
&lt;p&gt;Also keep in mind that it's possible to use &lt;code&gt;!include&lt;/code&gt; directives to include other &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/option-files.html" rel="noreferrer noopener" target="_blank"&gt;option files&lt;/a&gt; and &lt;code&gt;!includedir&lt;/code&gt; to search specific directories for option files. Under Ubuntu, there may be a file &lt;code&gt;/etc/mysql/my.cnf&lt;/code&gt; with &lt;code&gt;!includedir&lt;/code&gt; directives to search &lt;code&gt;/etc/mysql/conf.d/&lt;/code&gt; and &lt;code&gt;/etc/mysql/mysql.conf.d/&lt;/code&gt;&lt;/p&gt;


&lt;h4 id="edit-mysql-config-file"&gt;Editing the MySQL configuration file&lt;/h4&gt;
&lt;p&gt;If the MySQL server finds more than one configuration file, it will load each one in turn. The values override each other and it can be difficult to know which takes priority. Furthermore, the &lt;code&gt;--defaults-file&lt;/code&gt; parameter can also override all configurations. Keep things simple and have only one file and place it the directory that makes sense to you.&lt;/p&gt;
&lt;p&gt;Before editing the &lt;code&gt;my.cnf&lt;/code&gt;, first log in to MySQL with an administrator user and run the &lt;code&gt;SELECT @@GLOBAL.sql_mode&lt;/code&gt; query to see the values used in your setup.&lt;/p&gt;

&lt;figure class="wp-block-image size-full"&gt;&lt;img src="https://migratecontent.com/images/drupal-to-wordpress-mysql-select-global-sql_mode.jpg" alt="Setting the MySQL database server sql mode on Ubuntu for Drupal to WordPress migrations" class="wp-image-3705"&gt;&lt;br&gt;
&lt;figcaption class="wp-element-caption"&gt;&lt;em&gt;Running the &lt;code&gt;SELECT @@GLOBAL.sql_mode&lt;/code&gt; query on MySQL Workbench&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Next, open the configuration file, look for the section &lt;code&gt;[mysqld]&lt;/code&gt; and edit the line starting with:&lt;br&gt;&lt;code&gt;sql_mode = ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add the line if it's not there. Adjust the exact modes to match your project's needs so take a look at the &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sql-mode-full" target="_blank" rel="noreferrer noopener"&gt;list of SQL modes&lt;/a&gt; to see which may apply. I've found the following works well:&lt;br&gt;&lt;code&gt;sql_mode = "STRICT_TRANS_TABLES,ALLOW_INVALID_DATES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Finally, restart the MySQL server. On Ubuntu this will probably be with&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl start mysql&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you are logged in to the MySQL server, you may also need to disconnect your client and reconnect for the changes to take effect for your session.&lt;/p&gt;

&lt;h2 id="potential-errors"&gt;Potential errors&lt;/h2&gt;
&lt;p&gt;Here are some potential errors that you may come across during a CMS migration project. I usually find them when running a Drupal to WordPress migration on a freshly built development environment.&lt;/p&gt;
&lt;h3 id="mysqldump-access-denied-when-trying-to-dump-tablespaces"&gt;mysqldump access denied when trying to dump tablespaces&lt;/h3&gt;
&lt;p&gt;Migrations involve dumping and importing databases and this process is straightforward on a mature development environment. However you may receive an 'Access denied' error out of the blue when dumping your MySQL database:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you see this, perhaps you were working on an environment that was a little too 'mature' (in other words, obsolete!) and you have recently upgraded your installation. The updates for MySQL 5.7.31 and MySQL 8.0.21 in July 2020 introduced an incompatible change that produces this error.&lt;/p&gt;
&lt;p&gt;The fix involves granting the PROCESS privilege to the user running mysqldump, or using the &lt;code&gt;--no-tablespaces&lt;/code&gt; flag.&lt;/p&gt;
&lt;h3 id="ERROR-1067-42000-Invalid-default-value"&gt;ERROR 1067 (42000) Invalid default value&lt;/h3&gt;
&lt;p&gt;Drupal nodes store the date as a Unix timestamp in an &lt;code&gt;int&lt;/code&gt; (e.g. &lt;code&gt;1623427200&lt;/code&gt;) field whereas WordPress stores dates as &lt;code&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/datetime.html" target="_blank" rel="noreferrer noopener nofollow"&gt;datetime&lt;/a&gt;&lt;/code&gt; (e.g. &lt;code&gt;2021-06-11 16:00:00&lt;/code&gt;). There may be a conversion error in your migration script or the source date could simply be zero for some reason. Normally your MySQL server mode will be set to &lt;code&gt;NO_ZERO_DATE, NO_ZERO_IN_DATE&lt;/code&gt; so trying to insert a zero date will give you the error:&lt;/p&gt;
&lt;pre class="wp-block-preformatted"&gt;&lt;code&gt;ERROR 1067 (42000) Invalid default value&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can fix this by replacing &lt;code&gt;NO_ZERO_DATE, NO_ZERO_IN_DATE&lt;/code&gt;  with set to &lt;code&gt;ALLOW_INVALID_DATES&lt;/code&gt; in your global SQL mode.&lt;/p&gt;

&lt;h3 id="Expression-1-of-SELECT-list-is-not-in-GROUP-BY-clause"&gt;Expression #1 of SELECT list is not in GROUP BY clause&lt;/h3&gt;
&lt;p&gt;You run an SQL query and get the rather cryptic error:&lt;/p&gt;
&lt;pre class="wp-block-preformatted"&gt;Expression #1 of SELECT list is not in GROUP BY clause and contains
nonaggregated column 'database.table.pid' which is not functionally dependent
on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by&lt;/pre&gt;
&lt;p&gt;What's wrong? MySQL has a &lt;code&gt;only_full_group_by&lt;/code&gt; mode which, when enabled, strictly applies ANSI SQL rules when using &lt;code&gt;GROUP BY&lt;/code&gt;. Fix this by reworking your script or removing the &lt;code&gt;ONLY_FULL_GROUP_BY&lt;/code&gt; SQL mode.&lt;/p&gt;

&lt;h3 id="Error-Code-2013-Lost-connection-to-MySQL-server"&gt;Error Code: 2013. Lost connection to MySQL server&lt;/h3&gt;
&lt;p&gt;This often happens when an SQL query takes too long to return data. The connection between your MySQL client and database server times out so the connection gets dropped. You can try increasing the &lt;code&gt;net_read_timeout&lt;/code&gt; and &lt;code&gt;net_write_timeout&lt;/code&gt; values in your MySQL configuration, or optimising the query itself.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Setting up a MySQL database server for Drupal or WordPress is a familiar task for web developers and site administrators.  However, CMS migrations have quirks that can cause obscure and baffling errors. In this guide I've shown you some little tricks that may save time and annoyance. While there's no way to provide an exhaustive list of solutions to all the MySQL problems you'll encounter, I hope to have pointed you in the right direction.&lt;/p&gt;
&lt;p&gt;If you have a site migration project and would like to hire me, please &lt;a href="https://migratecontent.com/contact/"&gt;ask for a quote&lt;/a&gt; for my consulting service.&lt;/p&gt;

&lt;div class="footnotes"&gt;
    &lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@rubaitulazad?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Rubaitul Azad&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/text-Y9kOsyoWyaU?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" target="_blank" rel="nofollow"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;


&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Need Help Setting Up Your Migration Environment?&lt;/h2&gt;

&lt;p&gt;I specialise in complex Drupal to WordPress migrations, including database configuration, custom SQL scripts, and troubleshooting tricky migration errors. Get a free, no-obligation consultation.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your Drupal to WordPress migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>database</category><category>drupal</category><category>migration</category><category>mysql</category><category>wordpress</category><guid>https://migratecontent.com/how-to-set-up-mysql-for-drupal-wordpress-migrations/</guid><pubDate>Fri, 11 Jun 2021 15:44:52 GMT</pubDate></item><item><title>How to fix the mysqldump access denied process privilege error</title><link>https://migratecontent.com/how-to-fix-the-mysqldump-access-denied-process-privilege-error/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;em&gt;&lt;strong&gt;How to fix the mysqldump process privilege error after applying a recent MySQL update.&lt;/strong&gt;&lt;/em&gt;

You may receive a new 'Access denied' error when trying to dump your MySQL database:

&lt;code&gt;mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces&lt;/code&gt;

You were able to export database before so what caused this? Here's the answer: updates for MySQL 5.7.31 and MySQL 8.0.21 in July 2020 introduced an &lt;a href="https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-31.html#mysqld-5-7-31-security" target="_blank" rel="noopener noreferrer"&gt;incompatible change&lt;/a&gt;:
&lt;blockquote&gt;&lt;span class="bold"&gt;&lt;strong&gt;Incompatible Change:&lt;/strong&gt;&lt;/span&gt; Access to the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/information-schema-files-table.html" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;INFORMATION_SCHEMA.FILES&lt;/code&gt;&lt;/a&gt; table now requires the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html#priv_process" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;PROCESS&lt;/code&gt;&lt;/a&gt; privilege.

This change affects users of the &lt;strong&gt;mysqldump&lt;/strong&gt; command, which accesses tablespace information in the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/information-schema-files-table.html" target="_blank" rel="noopener noreferrer"&gt;&lt;code class="literal"&gt;FILES&lt;/code&gt;&lt;/a&gt; table, and thus now requires the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html#priv_process" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;PROCESS&lt;/code&gt;&lt;/a&gt; privilege as well. Users who do not need to dump tablespace information can work around this requirement by invoking &lt;strong&gt;mysqldump&lt;/strong&gt; with the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html#option_mysqldump_no-tablespaces" target="_blank" rel="noopener noreferrer"&gt;&lt;code class="option"&gt;--no-tablespaces&lt;/code&gt;&lt;/a&gt; option. (Bug #30350829)&lt;/blockquote&gt;
This error appears when running &lt;code&gt;mysqldump&lt;/code&gt; directly from the command line, exporting the database using a client like MySQL Workbench or if you're &lt;a href="https://migratecontent.com/tag/wordpress/"&gt;managing the WordPress database&lt;/a&gt; through WP-CLI's &lt;code&gt;export&lt;/code&gt; command.

&lt;img class="aligncenter size-full wp-image-3370" src="https://migratecontent.com/wp-content/uploads/how-to-fix-the-mysqldump-access-denied-process-privilege-error-after-mysql-update.png" alt="mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces" width="800" height="120"&gt;

In my case, I encountered the problem when running a routine Python script for a &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-service/"&gt;Drupal to WordPress migration client&lt;/a&gt;. My script uses WP-CLI to export a database dump file and deploy it to a remote server.
&lt;h2&gt;Solutions for fixing the mysqldump process privilege error&lt;/h2&gt;
The &lt;code&gt;mysqldump&lt;/code&gt; command requires at least the following privilege assigned to the user:
&lt;ul&gt;
 	&lt;li&gt;SELECT privilege for dumped tables&lt;/li&gt;
 	&lt;li&gt;SHOW VIEW for dumped views&lt;/li&gt;
 	&lt;li&gt;TRIGGER for dumped triggers&lt;/li&gt;
 	&lt;li&gt;LOCK TABLES if you don't use the &lt;code&gt;--single-transaction&lt;/code&gt; option&lt;/li&gt;
 	&lt;li&gt;PROCESS if you don't use the &lt;code&gt;--no-tablespaces&lt;/code&gt; option&lt;/li&gt;
&lt;/ul&gt;
The last PROCESS privilege is new as of MySQL 5.7.31 and MySQL 8.0.21 and may be the root source of your problem. You can solve the mysqldump process privilege error in two ways:
&lt;ol&gt;
 	&lt;li&gt;Updating the privileges for your database user.&lt;/li&gt;
 	&lt;li&gt;Runing &lt;code&gt;mysqldump&lt;/code&gt; with the &lt;code&gt;--no-tablespaces&lt;/code&gt; option.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Solution 1: Update the user privileges&lt;/h3&gt;
Granting the PROCESS privilege for the user is perhaps the simplest option for fixing the &lt;code&gt;mysqldump&lt;/code&gt; process privilege error. &lt;strong&gt;Keep in mind that this option presents &lt;a href="https://migratecontent.com/how-to-fix-the-mysqldump-access-denied-process-privilege-error/#process-privilege-dangers"&gt;security issues&lt;/a&gt;&lt;/strong&gt;. You should therefore really only use this option for your own local development server installation.

To grant the PROCESS privilege, log in as an administrator user and run the following query:

&lt;code&gt;GRANT PROCESS ON *.* TO user@localhost;&lt;/code&gt;

Note that PROCESS is a global level privilege. It can't apply to individual databases. Global privileges are either administrative or apply to all databases on your MySQL server. Trying to grant them on individual databases deplays the following error:

&lt;code&gt;ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES&lt;/code&gt;

To grant the privilege to all databases you must use the &lt;code&gt;ON *.* ...&lt;/code&gt; syntax.
&lt;h3&gt;Solution 2: Use the &lt;code&gt;--no-tablespaces&lt;/code&gt; option&lt;/h3&gt;
If you cannot assign global level privileges to your user, for example, when doing so presents unacceptable security issues, you must specify the &lt;code&gt;--no-tablespaces&lt;/code&gt; option when dumping your database.

&lt;code&gt;mysqldump --no-tablespaces -u user -ppass dbname &amp;gt; db_backup_file.sql&lt;/code&gt;
&lt;h2 id="tablespaces"&gt;What are MySQL tablespaces?&lt;/h2&gt;
We are usually only concerned with logical database objects when working with databases. However, the data must be physically stored somewhere. This is where tablespaces come in. Tablespaces are physical datafiles stored in the host file system holding data for one or more tables and indexes.

The diagram below provides a handy illustration. It's from the Oracle Concepts documentation, &lt;a href="https://docs.oracle.com/cd/B19306_01/server.102/b14220/physical.htm" target="_blank" rel="noopener noreferrer"&gt;Introduction to Tablespaces, Datafiles, and Control Files&lt;/a&gt; and refers to Oracle databases. Nevertheless, it may help you understand how tablespaces relate to logical database objects and datafiles.

[caption id="attachment_3378" align="aligncenter" width="522"]&lt;img class="size-full wp-image-3378" src="https://migratecontent.com/wp-content/uploads/Oracle-Introduction-to-Tablespaces-Datafiles-and-Control-Files.gif" alt="Oracle documentation: Introduction to Tablespaces, Datafiles, and Control Files" width="522" height="405"&gt; Diagram source: &lt;a href="https://docs.oracle.com/cd/B19306_01/server.102/b14220/physical.htm" target="_blank" rel="noopener noreferrer"&gt;Oracle Concepts documentation&lt;/a&gt;[/caption]

You can therefore use the &lt;code&gt;--no-tablespaces &lt;/code&gt; option if you don't need to dump tablespace information. This may be the case for routine database dumps, for example when exporting databases for &lt;a href="https://migratecontent.com/tag/migration/"&gt;WordPress migrations&lt;/a&gt;.
&lt;h2 id="process-privilege"&gt;About the access mysqldump denied PROCESS privilege error&lt;/h2&gt;
&lt;code&gt;mysqldump&lt;/code&gt; accesses tablespace information in the FILES table. Prior to MySQL 5.7.31 and 8.0.21, your user could run &lt;code&gt;mysqldump&lt;/code&gt; without the PROCESS privilege. However, users running &lt;code&gt;mysqldump&lt;/code&gt; after the update need PROCESS privileges to access the INFORMATION_SCHEMA.FILES table. Running &lt;code&gt;mysqldump&lt;/code&gt; without PROCESS privilege ends up giving you an &lt;em&gt;Access denied&lt;/em&gt; error.
&lt;h2 id="process-privilege-dangers"&gt;Be careful with the PROCESS privilege&lt;/h2&gt;
According to the MySQL documentation, the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html#priv_process" target="_blank" rel="noopener noreferrer"&gt;PROCESS privilege&lt;/a&gt; controls access to information about statements being executed by sessions.

It is a server administration privilege and should not be given to all users. This is because it may show text from currently executing queries. Any user with the PROCESS privilege may therefore see queries issued by others. Here's the danger: these queries, such as &lt;code&gt;UPDATE user SET password=PASSWORD&lt;/code&gt;, may show secrets.

For more information, see &lt;a href="https://www.oreilly.com/library/view/mysql-reference-manual/0596002653/ch04s02.html" target="_blank" rel="noopener noreferrer"&gt;General Security Issues and the MySQL Access Privilege System&lt;/a&gt; from the O'Reilly MySQL Reference Manual.</description><category>database</category><category>mysql</category><category>sys admin</category><category>troubleshooting</category><category>upgrades</category><guid>https://migratecontent.com/how-to-fix-the-mysqldump-access-denied-process-privilege-error/</guid><pubDate>Fri, 23 Oct 2020 15:23:45 GMT</pubDate></item><item><title>A guide to WordPress Backups and Staging</title><link>https://migratecontent.com/wordpress-backups-and-staging-guide/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;div style="margin: 2em 0 2em 0; padding: 1em 2em 1em 2em; font-weight: 400; text-align: center; color: #444; background-color: #f5f5f5; border: 3px solid #e9ecef;"&gt;&lt;em&gt;This &lt;strong&gt;WordPress Backups and Staging Guide&lt;/strong&gt; is a guest post by &lt;a href="https://blogvault.net/author/melinda/" rel="author"&gt;Melinda Bartley&lt;/a&gt;.&lt;/em&gt;&lt;/div&gt;

&lt;p&gt;If you've run a WordPress site long enough, you'd know how making changes to it can be tricky. Sometimes, even minor changes can cause major glitches. This makes backups and staging such lifesavers!&lt;/p&gt;
&lt;p&gt;Every WordPress site should have backup and staging solutions in place. And not just any solution, one that actually works! I say this because in my experience, relying on host backups and staging environments have too many limitations and a tedious process. So I turned to plugins, but there too, I found so many options, it was hard to pick the right one.&lt;/p&gt;
&lt;p&gt;In my quest to get a permanent solution, I stumbled upon BlogVault. It was easy-to-use and reliable with a great support team behind it. Ever since, it has been my go-to for WordPress backups and staging.&lt;/p&gt;
&lt;p&gt;So today, I'm sharing everything what I think WordPress site owners should know about backups and staging and why BlogVault works best.&lt;/p&gt;
&lt;p&gt;Let's begin with a few basics.&lt;/p&gt;
&lt;h2&gt;Difference Between Backup and Staging&lt;/h2&gt;
&lt;p&gt;Many ask If I have a backup, why do I need staging? Well, the two solve very different problems. Backups are for reverting to a previous version when a problem arises on the site.&lt;/p&gt;
&lt;p&gt;For example, you run an update on your website and it causes your site to malfunction. You find that plugins are not compatible with the new version of WordPress. It would take considerable time to update these plugins or find replacements. To solve the issue immediately and get your site back to normal, you can restore your backup.&lt;/p&gt;
&lt;p&gt;Backups come in handy when things go wrong such as botched updates, human errors, presence of malware, and so on.&lt;/p&gt;
&lt;p&gt;Coming to staging, it enables you to create a clone of your WordPress website. This is done specifically for development. You can try out new themes, plugins, designs and layouts. You can test out updates and even test restore your backup! None of the changes you make will affect your live site.&lt;/p&gt;
&lt;p&gt;There are staging solutions that have a feature to merge your changes. This is extremely handy because you might make multiple changes and it would take time to replicate the same on your live site. So you can just push the changes to your live site. Simply put, staging enables progress!&lt;/p&gt;
&lt;p&gt;Now that you know why you need both solutions, let's check out the backup solutions available for WordPress sites.&lt;/p&gt;
&lt;h2&gt;WordPress Backup Solutions&lt;/h2&gt;
&lt;p&gt;There are many options to backup your WordPress site, but not all of them are easy to use or reliable. The main options available to back up your site are – manually, using a plugin, or through your web host.&lt;/p&gt;
&lt;h3&gt;Manual Backups&lt;/h3&gt;
&lt;p&gt;For this, you need to access your web hosting account. Once you've logged in, go to&lt;em&gt; cPanel &amp;gt; File Manager &amp;gt; Public_Html&lt;/em&gt;. Here, you'll see all your WordPress files. Simply compress and download them.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/Hosting-Control-Panel-Manual-Backups.png" class="figure-img img-fluid rounded" alt="Hosting Control Panel Manual Backups" width="653" height="408"&gt;
    &lt;figcaption class="figure-caption text-center"&gt;(Image source: &lt;a href="https://wpengine.com/"&gt;WP Engine&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It seems simple enough. But there are issues with this method. For one, the process is time-consuming. Spending time taking manual backups regularly is simply not feasible when you have tons of other things to focus on. Plus, you need to take responsibility to encrypt your data and store the backup locally. A backup has all the information on your website and needs to be stored securely. If hackers get their hands on an unencrypted backup, it's already a data breach, but you can be sure your site will be hacked as well.&lt;/p&gt;
&lt;p&gt;But above all, the biggest hassle with this method is the restoration process. Sometimes, the backup just doesn't work at all. Other times, you restore your site only to find it malfunctioning or missing functionalities. Which means more time wasted on troubleshooting and debugging troubles. This is why I prefer using a plugin. But among these too, there are so many options available, how do you choose one?&lt;/p&gt;
&lt;p&gt;Well, after trying out a couple of them, I stuck with BlogVault. It's great for backups and even offers inbuilt staging at no additional cost.&lt;/p&gt;
&lt;h3&gt;Backups with a WordPress Plugin – &lt;a href="https://blogvault.net/"&gt;BlogVault&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To start off, setting up BlogVault was easy to use – with a simple install and activate process. Once you sign up, the backup automatically runs. It gives you the following options which I think is not only cool but essential for WordPress:&lt;/p&gt;
&lt;ul&gt;
&lt;li style="list-style-type: none;"&gt;
&lt;ul&gt;
&lt;li&gt;The option to schedule your backups. Plus, you can take a backup on demand whenever you want, any number of times. This is good to have when you want to make major changes to your site or roll out big updates. Taking a backup before any major change is absolutely necessary.&lt;/li&gt;
&lt;li&gt;It's all automated so you don't have to worry about the technicalities.&lt;/li&gt;
&lt;li&gt;The restore process is just a few clicks. It takes a few minutes and it's guaranteed to work. So you needn't worry about your site breaking or losing data.&lt;/li&gt;
&lt;li&gt;The process is handled offsite on their own servers so it doesn't affect the performance or speed of your site. Plus, it doesn't take a full backup every single time. It smartly copies one full backup and then subsequently, only the changes made each time are backed up.&lt;/li&gt;
&lt;li&gt;Lastly, your backup is encrypted and multiple copies of it are stored securely. That takes away the pain of storage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/BlogVault-WordPress-Backup-Plugin.png" class="figure-img img-fluid rounded" alt="Creating a backup using the BlogVault WordPress Backup Plugin" width="818" height="378"&gt;
&lt;/figure&gt;

&lt;p&gt;Apart from this, there are handy features like 365-day archives, real-time backups, website management, &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-service/"&gt;site migrations&lt;/a&gt;, multiple site management, uptime monitoring, and staging.&lt;/p&gt;
&lt;p&gt;Next, you can also back up your website using your web host itself. I've checked out two of the most popular ones.&lt;/p&gt;
&lt;h3&gt;Backups with your Host – &lt;a href="https://wpengine.com/"&gt;WP Engine&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WP Engine takes backups for all environments by default. This includes production staging, development, and legacy staging. It's automated, encrypted, and stored offsite on Amazon S3. You can also take manual backups. It keeps up to 40 backup points. Older data up to 60 points may be accessible but you need to contact their support team for that.&lt;/p&gt;
&lt;p&gt;To access a backup, log into your user portal. Go to &lt;em&gt;sites &amp;gt; environment name &amp;gt; backup points&lt;/em&gt;. You'll find your backups here. You can also create a backup on demand.&lt;/p&gt;
&lt;p&gt;To restore, simply click on the backup point you want and click the Restore button.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/WP-Engine-Backups.png" class="figure-img img-fluid rounded" alt="Creating backups in WP Engine" width="768"&gt;
    &lt;figcaption class="figure-caption text-center"&gt;(Image source: &lt;a href="https://wpengine.com/"&gt;WP Engine&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;


&lt;p&gt;The process seems simple enough. But WP Engine also has some drawbacks. The restore process can take several minutes to several hours. And it's important to note that they do not copy all files of your site. The following files aren't included:&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/WP-Engine-Backups-Excluded-Files.png" class="figure-img img-fluid rounded" alt="Files excluded with WP Engine backups" width="505" height="384"&gt;
&lt;/figure&gt;

&lt;p&gt;Additionally, it's a destructive backup which means, during the restoration process, all content is overwritten. So, if you have files on your website that are not present in your backup, they will be wiped out. Your site will be restored to the contents of the backup alone.&lt;/p&gt;

&lt;h3&gt;Backups with your Host – &lt;a href="https://kinsta.com/"&gt;Kinsta&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Kinsta provides daily automatic backups for your WordPress site. It also has system-generated backups for all the sites listed in your account. The backup is a snapshot of your website's files, database, redirects, and Nginx configuration. When you restore your backup up, all of these elements will be rolled back to when the backup was taken.&lt;/p&gt;
&lt;p&gt;You can also create manual backups if you want one immediately and don't want to wait for the scheduled one to run. You need to visit the 'Backups' tab, click on the 'Manual' tab. Here, you'll find the 'Backup Now' button for on-demand backups.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/Kinsta-Backups-1024x603.png" class="figure-img img-fluid rounded" alt="Creating backups on Kinsta" width="640" height="377"&gt;
    &lt;figcaption class="figure-caption text-center"&gt;(Image source: &lt;a href="https://kinsta.com/"&gt;Kinsta&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The duration for which your backups are stored depends on your hosting plan. It can vary between 14 days and 30 days. Kinsta also allows you to increase the frequency of your backups to hourly and 6-hour backups at a premium.&lt;/p&gt;
&lt;p&gt;When it comes to restoring your site, you can simply click on the 'Restore' button next to the backup of your choice. While the restore takes place, you cannot access your site. The process can take a few minutes to a few hours.&lt;/p&gt;
&lt;p&gt;What I liked about Kinsta is that it takes a backup of your site before restoration. So you can undo the restore and get back your site to as it was.&lt;/p&gt;
&lt;p&gt;That brings up to the end of backups. With a backup solution in place, we can move on to staging. Here, I'll touch upon – the manual method, show you how you can do this with the BlogVault plugin, and also talk about staging with your hosting provider.&lt;/p&gt;

&lt;h2&gt;WordPress Staging Solutions&lt;/h2&gt;
&lt;p&gt;Staging a site can be done manually through your hosting account. But it's riddled with problems. The process to create one is quite technical, and for a regular WordPress user, it's not a feasible option.&lt;/p&gt;
&lt;p&gt;Next, if you want to merge the changes you made, you need to download the updated files from your staging site and upload them to you live site. This is risky business as you could wipe out data and even crash your site.&lt;/p&gt;
&lt;p&gt;Fortunately, there are other options! You can create a staging site with your host or by using a plugin. Coming back to BlogVault, it also offers a staging feature that makes the job much easier.&lt;/p&gt;
&lt;h3&gt;Staging with BlogVault&lt;/h3&gt;
&lt;p&gt;If you've already installed BlogVault, staging is a free feature compatible with any web host. On the BlogVault dashboard, you'll see an option to 'Add staging site'. It takes a few minutes, and you'll be notified when it's done.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/BlogVault-WordPress-Staging-Plugin.png" class="figure-img img-fluid rounded" alt="Creating a WordPress  staging site with the BlogVault Plugin
        width=" 640" height="377"&gt;
    &lt;figcaption class="figure-caption text-center"&gt;(Image source – &lt;a href="https://blogvault.net/wordpress-staging/"&gt;BlogVault&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The plugin handles migrating your site to a dev environment, so you don't have to bother about the file transfer and the database export and import. The staging site is password protected and blocked off from search engines so &lt;a href="https://migratecontent.com/preserving-seo-drupal-wordpress-migration/"&gt;migration does not affect your SEO&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With everything taken care of, you simply need to start using your staging site. Once you're happy with the changes you've made, you can simply merge the changes to your live site. There's no need to upload files or replicate changes.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/BlogVault-WordPress-merging-tool.png" class="figure-img img-fluid rounded" alt="BlogVault WordPress merge tool" width="671" height="344"&gt;
    &lt;figcaption class="figure-caption text-center"&gt;(Image source – &lt;a href="https://blogvault.net/wordpress-staging/"&gt;BlogVault&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;You can also do a selective merge. BlogVault gives you a comparison of your live site and your staging site. You can then select which changes you want to merge to your live site. In the example below, I made changes to my plugins, themes, uploads, and a few other files. But I wanted only the changes made to plugins. By clicking on the '+' sign, I could see the list of plugins I added or modified. I selected the ones I wanted and merged in just two clicks.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/BlogVault-WordPress-file-comparison-tool.png" class="figure-img img-fluid rounded" alt="BlogVault WordPress file comparison tool" width="926" height="396"&gt;
    &lt;figcaption class="figure-caption text-center"&gt;(Image source – &lt;a href="https://blogvault.net/wordpress-staging/"&gt;BlogVault&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;The best part is that you can create as many staging sites as you want. So that's BlogVault. It's straightforward and easy to use. It won't break your site when you merge the changes so your site is in safe hands.&lt;/p&gt;
&lt;p&gt;Next, let's take a look at staging options with web hosting providers.&lt;/p&gt;
&lt;h3&gt;Staging with WP Engine&lt;/h3&gt;
&lt;p&gt;WP Engine gives you options to create three kinds of environments – production, staging, and development.&lt;/p&gt;
&lt;p&gt;To carry out the staging process, you first need to add your site to the user portal. Next, log into the user portal and access Sites &amp;gt; Name of your site &amp;gt; Add staging. Your staging site will be created using the backup point of the existing environment.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/WP-Engine-WordPress-staging.png" class="figure-img img-fluid rounded" alt="WP Engine WordPress staging" width="1024" height="492"&gt;
    &lt;figcaption class="figure-caption text-center"&gt;(Image source – &lt;a href="https://blogvault.net/wordpress-staging/"&gt;BlogVault&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;In case you don't see the staging option, you need to &lt;a href="https://wpengine.com/support/convert-single-environment-sites/"&gt;convert a single environment site&lt;/a&gt; into a multi-environment site.&lt;/p&gt;
&lt;p&gt;Once you've made the changes you want, you can copy the changes from staging to your production environment.&lt;/p&gt;
&lt;p&gt;WP Engine also allows you to copy changes from a staging environment of one site to another website. This means you can roll out updates or changes to all your sites without repeating the staging process for each site. However, this can get a bit complicated and isn't recommended for those new to WordPress.&lt;/p&gt;

&lt;h3&gt;Staging with Kinsta&lt;/h3&gt;
&lt;p&gt;Creating a staging site with Kinsta is quite easy. Access your Kinsta dashboard and select your site. Here, on the top right, you have the option to create a staging environment for your website. It takes around 10-15 minutes to create a staging site.&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/Kinsta-WordPress-staging-1024x553.png" class="figure-img img-fluid rounded" alt="Kinsta WordPress staging" width="640" height="346"&gt;
&lt;/figure&gt;

&lt;p&gt;Once you refresh the page, you will see your staging details. You can make the changes you like to your staging site and then push them to your production environment. To do this, under the 'Staging Environment' tab, there's a 'Push Staging to Live' button. Simply click on it and all the changes will be made visible on your live site.&lt;/p&gt;
&lt;p&gt;There's no selective merge option here. So if you're pushing changes to live, be aware that all changes will be merged.&lt;/p&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;That's a wrap on backups and staging for your WordPress site. To summarize, hosts may offer free versions of backup and staging, but you're limited in terms of features and functionality. As your site grows bigger, you would need to upgrade to premium plans which are quite expensive. However, when you opt for a plugin like BlogVault, it's reasonably priced, gives you access to premium features, and above all, it works seamlessly.&lt;/p&gt;
&lt;p&gt;Whichever be your choice, make sure you can rely on your backup to work and be restored easily. Finally, always carry out changes in a staging environment before updating your live site. This will keep you out of trouble and ensure your site is always up and running.&lt;/p&gt;</description><category>backups</category><category>blog</category><category>blogvault</category><category>development</category><category>help</category><category>hosting</category><category>kinsta</category><category>staging</category><category>wordpress</category><category>wp engine</category><guid>https://migratecontent.com/wordpress-backups-and-staging-guide/</guid><pubDate>Tue, 11 Feb 2020 12:59:11 GMT</pubDate></item><item><title>Ubercart to WooCommerce migration notes</title><link>https://migratecontent.com/ubercart-to-woocommerce-migration/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;p&gt;I've now had several Ubercart to WooCommerce migration projects so it's time to start documenting the process. As with all my documentation, I'll start off this post as rough notes and improve it over time. If this topic interests you, be sure to check back every so often to see the updates. Please keep in mind that I'm writing this from the standpoint of &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-guide/" title="Drupal to WordPress Migration Guide"&gt;Drupal to WordPress migrations&lt;/a&gt;. In other words, the main objective for the projects were to migrate a Drupal site to WordPress but there was also an Ubercart to WooCommerce component.&lt;/p&gt;

&lt;h2&gt;Key differences between Ubercart and WooCommerce&lt;/h2&gt;

&lt;p&gt;There's one key difference between Ubercart and WooCommerce from an architectural point-of-view. Ubercart stores products as nodes and orders are stored in a separate table &lt;code&gt;uc_orders&lt;/code&gt;. Orders have an &lt;code&gt;order_id&lt;/code&gt; and there's no direct relationship in &lt;code&gt;uc_orders&lt;/code&gt; to a product's node ID. Instead, the &lt;code&gt;uc_order_products&lt;/code&gt; table stores the relationship between orders and products purchased with the order.&lt;/p&gt;

&lt;p&gt;WooCommerce stores both products and order transactions as posts in the &lt;code&gt;wp_posts&lt;/code&gt; table. The post ID is used as the order's transaction ID. Products purchased with the order are stored in &lt;code&gt;wp_woocommerce_order_items&lt;/code&gt;, with additional product metadata being strored in &lt;code&gt;wp_woocommerce_order_itemmeta&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Obviously there are many more differences but this information architecture is the key thing to keep in mind when migrating the data.&lt;/p&gt;

&lt;img style="margin:10px 0 10px 0" src="https://migratecontent.com/images/ubercart-woocommerce-01.png" alt="Ubercart to WooCommerce table mapping" width="481" height="155" class="aligncenter size-full wp-image-3069"&gt;

&lt;h2&gt;Database tables&lt;/h2&gt;

&lt;p&gt;Here are the main database tables that you'll need to migrate Ubercart content to WooCommerce.&lt;/p&gt;

&lt;h3&gt;Ubercart&lt;/h3&gt;

&lt;table width="100%" class="table-bordered" style="padding:5px"&gt;
&lt;caption&gt;Table: Drupal Ubercart tables&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th width="50%"&gt;Table&lt;/th&gt;
&lt;th width="50%"&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="odd row-first"&gt;
&lt;td&gt;node&lt;/td&gt;
&lt;td&gt;Products are stored in the Drupal &lt;code&gt;node&lt;/code&gt; table.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;uc_orders&lt;/td&gt;
&lt;td&gt;Stores the individual Ubercart transactions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;uc_order_products&lt;/td&gt;
&lt;td&gt;Stores the products purchased during the transaction.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;uc_order_line_items&lt;/td&gt;
&lt;td&gt;Line items for an order. This includes tax and shipping fees applied to an order.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;uc_order_comments&lt;/td&gt;
&lt;td&gt;Customer or administrator notes associated with each order.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;uc_order_log&lt;/td&gt;
&lt;td&gt;Comments about the order status by the shop administrator.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;uc_zone&lt;/td&gt;
&lt;td&gt;Country zone codes for customer billing and delivery.&lt;/td&gt;
&lt;/tr&gt;&lt;tr class="even"&gt;
&lt;td&gt;uc_countries&lt;/td&gt;
&lt;td&gt;Countries and zone codes in ISO 3166-1 Alpha-2 and Alpha-3 code format for customer billing and delivery.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;



&lt;h3&gt;WooCommerce&lt;/h3&gt;

&lt;table width="100%" class="table-bordered"&gt;
&lt;caption&gt;Table: WordPress WooCommerce tables&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th width="50%"&gt;Table&lt;/th&gt;
&lt;th width="50%"&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="odd row-first"&gt;
&lt;td&gt;wp_posts&lt;/td&gt;
&lt;td&gt;Stores products and transactions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;wp_postmeta&lt;/td&gt;
&lt;td&gt;Transaction meta data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;wp_woocommerce_order_items&lt;/td&gt;
&lt;td&gt;Stores the line items for a transaction in the &lt;code&gt;wp_posts&lt;/code&gt; table.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td&gt;wp_woocommerce_order_itemmeta&lt;/td&gt;
&lt;td&gt;Stores the meta data for line items, such as quantity, price and tax information.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td&gt;wp_comments&lt;/td&gt;
&lt;td&gt;Order notes.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Order transactions and products are saved as WordPress posts. One or many order item meta entries can be linked to an order.&lt;/p&gt;

&lt;h2&gt;WooCommerce shop orders&lt;/h2&gt;

A WooCommerce transaction is saved as a shop order in the &lt;code&gt;wp_posts&lt;/code&gt; table.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;post_status = wc_completed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;post_type = shop_order&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;WooCommerce subscriptions&lt;/h2&gt;

&lt;p&gt;WooCommerce subscriptions are saved in &lt;code&gt;wp_posts&lt;/code&gt;. A subscription is made up of two entries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The transaction order for a subscription.&lt;/li&gt;
&lt;li&gt;The subscription itself.&lt;/li&gt;
&lt;/ol&gt;


&lt;h3&gt;Subscription transaction order&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;post_status = wc_completed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;post_parent = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;post_type = shop_order&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;The subscription&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;post_status = wc_active&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;post_parent = [post ID to the transaction shop order]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;post_type = shop_subscription&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!--
When adding a subscription order's product data to the &lt;code&gt;post_type=shop_subscription&lt;/code&gt; it's important to attach products to the &lt;code&gt;shop_subscription&lt;/code&gt; ID not the &lt;code&gt;shop_order&lt;/code&gt; ID, otherwise the subscription title will not be displayed in the user's &lt;em&gt;My Account&lt;/em&gt; page.
--&gt;
&lt;h2&gt;Products&lt;/h2&gt;

Purchased products are saved as line items in the &lt;code&gt;wp_woocommerce_order_items&lt;/code&gt; and &lt;code&gt;wp_woocommerce_order_itemmeta&lt;/code&gt; tables.

&lt;p&gt;A WooCommerce product can be of any post type. The product post is linked to a shop order transaction by setting the product's post ID in the &lt;code&gt;wp_woocommerce_order_itemmeta&lt;/code&gt; table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;meta_key = _product_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;meta_value = [post ID to the product]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr style="margin-top:5em"&gt;
&lt;h3 id="notes"&gt;Notes&lt;/h3&gt;

&lt;p&gt;My apologies if you've come here looking for more complete documentation. I've been planning to write this post for more than two years but have been putting it off due to my work schedule. I figure the best way to finally get it done is to just make a start and update it as time allows.&lt;/p&gt;

&lt;p&gt;The most-viewed articles here started off as notes for my own use and evolved over time. This one is no different. Hopefully it will still be of use to some people in its draft state.&lt;/p&gt;

&lt;p&gt;In the meantime, you might want to take a look at these other articles and plugins.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.webtoffee.com/export-woocommerce-orders-import-back-new-website/"&gt;How to Export WooCommerce Orders and Import Them Back into New Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sgwebpartners.com/moving-orders-in-woocommerce/"&gt;How To Migrate WooCommerce Customers and Orders (Like A Pro!)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.skyverge.com/blog/moving-woocommerce-orders-sites/"&gt;Moving WooCommerce Orders Between Sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://woocommerce.com/products/ordercustomer-csv-export/#"&gt;WooCommerce Customer / Order / Coupon Export&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wordpress.org/plugins/woocommerce-sequential-order-numbers/"&gt;WooCommerce Sequential Order Numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://woocommerce.com/products/customerorder-csv-import-suite/#"&gt;Customer/Order/Coupon CSV Import Suite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><category>drupal</category><category>ecommerce</category><category>migration</category><category>ubercart</category><category>woocommerce</category><category>wordpress</category><guid>https://migratecontent.com/ubercart-to-woocommerce-migration/</guid><pubDate>Fri, 24 Jan 2020 12:14:07 GMT</pubDate></item><item><title>How We Migrate: The Technical Process Behind a Drupal to WordPress Migration</title><link>https://migratecontent.com/how-we-migrate-technical-process/</link><dc:creator>Aiden</dc:creator><description>&lt;p class="intro"&gt;Every Drupal site is different. Custom content types, unique field configurations, contributed modules with their own database tables, and years of accumulated content that doesn't fit neatly into any template. This is why I don't use off-the-shelf migration tools. Instead, I write custom scripts tailored to each site's specific data model, and run the migration iteratively until the output is clean.&lt;/p&gt;

&lt;h2&gt;Why Custom Scripts, Not Plugins&lt;/h2&gt;

&lt;p&gt;Automated migration tools like FG Drupal to WordPress work by mapping Drupal's core database tables to their WordPress equivalents. For a basic site with standard posts and pages, this can work. However, most Drupal sites that need professional migration have outgrown standard content types.&lt;/p&gt;

&lt;p&gt;Custom content types, field collections, entity references, paragraphs modules, and bespoke database tables. These are the structures that make Drupal powerful and that make automated migration unreliable. My approach works directly against the databases, with scripts that understand your site's specific data relationships.&lt;/p&gt;

&lt;h2&gt;Phase 1: Content Audit and Mapping&lt;/h2&gt;

&lt;p&gt;Before writing any migration code, I need to understand your Drupal site's data model in detail. This means mapping every content type, field, taxonomy vocabulary, and relationship in your database.&lt;/p&gt;

&lt;h3&gt;What the Audit Covers&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Content types and their fields.&lt;/strong&gt; Every node type and its associated field definitions: text, image, file, entity reference, date, address, and any custom field types.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taxonomy vocabularies.&lt;/strong&gt; The vocabulary structure, term hierarchies, and how terms relate to content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User roles and permissions.&lt;/strong&gt; Which roles exist, what they can access, and how they map to WordPress capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media and files.&lt;/strong&gt; How files are referenced, where they're stored (public vs private filesystem), and any image style derivatives that need handling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom modules and tables.&lt;/strong&gt; Bespoke functionality that stores data outside Drupal's standard schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output is a mapping document that pairs each Drupal data structure with its WordPress equivalent. This document drives every subsequent decision.&lt;/p&gt;

&lt;h2&gt;Phase 2: Database Mapping&lt;/h2&gt;

&lt;p&gt;Drupal and WordPress store content in fundamentally different database architectures. Understanding these differences is essential to writing reliable migration scripts.&lt;/p&gt;

&lt;h3&gt;Core Table Mapping&lt;/h3&gt;

&lt;p&gt;At the most basic level, Drupal's &lt;code&gt;node&lt;/code&gt; table maps to WordPress's &lt;code&gt;wp_posts&lt;/code&gt;. Node IDs become post IDs, creation timestamps convert to WordPress date format, and the node status field translates to WordPress publish states. Content bodies come from a separate revisions table in Drupal and need joining before insertion.&lt;/p&gt;

&lt;h3&gt;Taxonomy Mapping&lt;/h3&gt;

&lt;p&gt;Drupal's &lt;code&gt;term_data&lt;/code&gt; (Drupal 7) and vocabulary tables map to WordPress's &lt;code&gt;wp_terms&lt;/code&gt; and &lt;code&gt;wp_term_taxonomy&lt;/code&gt;. The relationship tables that connect content to terms require their own mapping. Drupal allows multiple vocabularies with custom fields. WordPress uses categories, tags, and custom taxonomies, each with different behaviour.&lt;/p&gt;

&lt;h3&gt;Custom Fields&lt;/h3&gt;

&lt;p&gt;This is where the complexity lives. Drupal stores custom field data across multiple tables, typically one table per field, with separate columns for each property (value, format, language). WordPress stores custom fields as key-value pairs in &lt;code&gt;wp_postmeta&lt;/code&gt;, or in structured formats if using Advanced Custom Fields or similar plugins.&lt;/p&gt;

&lt;p&gt;Each custom field needs individual mapping logic. A Drupal entity reference field that links to another node might become a WordPress post relationship managed by ACF, or a simple post meta value, or a custom taxonomy, depending on how the relationship is used in the front end.&lt;/p&gt;

&lt;h2&gt;Phase 3: Migration Scripts&lt;/h2&gt;

&lt;p&gt;With the mapping document complete, I write custom scripts (typically a combination of SQL and PHP) that handle the actual data transfer. The scripts work against a copy of your production database, never against the live site.&lt;/p&gt;

&lt;p&gt;Key considerations in the scripting phase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data type conversions.&lt;/strong&gt; Drupal stores timestamps as Unix integers; WordPress uses &lt;code&gt;DATETIME&lt;/code&gt; strings. Status values, user roles, and content types all need transformation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Character encoding.&lt;/strong&gt; Drupal and WordPress may use different encoding for special characters, accented text, and HTML entities. The scripts handle normalisation to prevent garbled content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relationship integrity.&lt;/strong&gt; Content-to-taxonomy, content-to-author, and content-to-content relationships must transfer as a connected dataset. Migrating entities in isolation breaks these links.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media file handling.&lt;/strong&gt; File references in the database need updating to point to WordPress's upload directory structure. Physical files are copied separately via rsync or similar tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Phase 4: Iterative Testing&lt;/h2&gt;

&lt;p&gt;This is the phase that separates professional migration from a best-effort attempt. I run the migration scripts repeatedly (typically 5 to 20 cycles per project), with each iteration refining the output.&lt;/p&gt;

&lt;h3&gt;What Each Test Cycle Checks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data completeness.&lt;/strong&gt; Did every piece of content come across? Are any fields missing or truncated?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relationship integrity.&lt;/strong&gt; Are taxonomy terms correctly assigned? Do author attributions match? Are related content links valid?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual accuracy.&lt;/strong&gt; Does the content render correctly in the WordPress theme? Are images displaying, embeds working, and formatting intact?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Edge cases.&lt;/strong&gt; Content with unusual characters, extremely long fields, empty values, or draft states. These are the entries that break on the first pass and get fixed in subsequent cycles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each cycle produces a test report documenting what was fixed and what needs attention in the next run. The site owner reviews key content at each stage to confirm accuracy.&lt;/p&gt;

&lt;h2&gt;Phase 5: URL Mapping and Redirects&lt;/h2&gt;

&lt;p&gt;Once the content migration is stable, I build the redirect map. Every Drupal URL alias is paired with its new WordPress URL, and 301 redirects are configured at the server level.&lt;/p&gt;

&lt;p&gt;This phase works in parallel with the SEO preservation strategy. For sites with significant organic traffic, I audit the URL list against analytics data to prioritise the pages that matter most. The redirect rules are tested before launch to ensure no high-value URLs return 404 errors.&lt;/p&gt;

&lt;h2&gt;Phase 6: Zero-Downtime Launch&lt;/h2&gt;

&lt;p&gt;For business-critical sites, downtime during migration isn't acceptable. The launch process uses a staged approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Build on staging.&lt;/strong&gt; The WordPress site is built and populated on a staging server, with all test cycles completed there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Final delta migration.&lt;/strong&gt; A last-pass script migrates any content created or updated since the previous full migration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DNS cutover.&lt;/strong&gt; DNS records are updated to point to the new WordPress server. The old Drupal site remains available as a fallback until the transition is verified.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Post-launch verification.&lt;/strong&gt; Content spot-checks, redirect testing, analytics confirmation, and search console monitoring in the first 48 hours.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The total migration timeline typically runs 4 to 12 weeks, depending on the complexity of the content model, the volume of data, and the number of test cycles needed to achieve clean output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/why-automated-migration-tools-fail/"&gt;Why Automated Migration Tools Fail for Complex Drupal Sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/preserving-seo-drupal-wordpress-migration/"&gt;Preserving Your SEO During a Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/content-migration-process/"&gt;How the migration process works&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Want to Understand What Your Migration Involves?&lt;/h2&gt;

&lt;p&gt;I provide a detailed content audit and migration plan before any work begins. Get a free consultation to discuss your Drupal site's technical requirements.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your Drupal to WordPress migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>database</category><category>drupal</category><category>migration</category><category>technical</category><category>wordpress</category><guid>https://migratecontent.com/how-we-migrate-technical-process/</guid><pubDate>Wed, 20 Mar 2019 09:00:00 GMT</pubDate></item><item><title>Migrating  Drupal events to WordPress Events Calendar (Tribe Events)</title><link>https://migratecontent.com/migrating-drupal-events-to-wordpress-events-calendar-tribe-events/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>The &lt;a href="https://theeventscalendar.com/"&gt;The Events Calendar&lt;/a&gt;, sometimes known as Tribe Events, is a popular plugin for managing event content in WordPress. It's so popular that it's often the first choice when clients ask me to &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-service/"&gt;migrate Drupal&lt;/a&gt; event content into WordPress.

Here is some sample SQL queries if you need to do something similar.

&lt;h2&gt;Sample SQL queries&lt;/h2&gt;

These are example queries only. Be sure to edit them for your own configuration.

&lt;h3&gt;Event date and time&lt;/h3&gt;

The event date and time is in &lt;a href="https://en.wikipedia.org/wiki/ISO_8601"&gt;ISO 8601&lt;/a&gt; without the &lt;code&gt;T&lt;/code&gt; character. See how WordPress prefers to &lt;a href="https://wordpress.org/support/article/formatting-date-and-time/"&gt;format times and dates&lt;/a&gt;.

&lt;pre&gt;&lt;code&gt;
INSERT INTO wp_postmeta (
    post_id,
    meta_key,
    meta_value
)
SELECT
	nid,
    '_EventStartDate',
	REPLACE(field_eventdate_value, 'T', ' ')
FROM drupal_content_field_eventdate;


INSERT INTO wp_postmeta (
     post_id,
     meta_key,
     meta_value
)
SELECT
	post_id,
	'_EventEndDate',
    meta_value
FROM wp_postmeta WHERE meta_key="_EventStartDate";


INSERT INTO wp_postmeta (
     post_id,
     meta_key,
     meta_value
)
SELECT
	post_id,
	'_EventTimezone',
    'UTC+0'
FROM wp_postmeta WHERE meta_key="_EventStartDate";

INSERT INTO wp_postmeta (
     post_id,
     meta_key,
     meta_value
)
SELECT
	post_id,
	'_EventTimezoneAbbr',
    'UTC+0'
FROM wp_postmeta WHERE meta_key="_EventStartDate";


INSERT INTO wp_postmeta (
     post_id,
     meta_key,
     meta_value
)
SELECT
	post_id,
	'_EventOrigin',
    'events-calendar'
FROM wp_postmeta WHERE meta_key="_EventStartDate";
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Event details&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
INSERT INTO wp_postmeta (
    post_id,
    meta_key,
    meta_value
)
SELECT
    nid,
    '_EventURL',
    field_eventorgs_url
FROM drupal_content_field_eventorgs;


INSERT INTO wp_postmeta (
    post_id,
    meta_key,
    meta_value
)
SELECT
    nid,
    '_OrganizerOrganizer',
    field_eventorgs_title
FROM drupal_content_field_eventorgs;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Custom fields&lt;/h3&gt;

This query will save the filepath of associated files, such as a logo, into a custom field.

&lt;pre&gt;&lt;code&gt;
INSERT INTO wp_postmeta (
     post_id,
     meta_key,
     meta_value
)
SELECT
    nid,
    'field_eventlogo',
    REPLACE(f.filepath, 'sites/default/files/', '/wp-content/uploads/legacy/')
FROM drupal_content_field_orglogos c
INNER JOIN drupal_files f
ON c.field_orglogos_fid = f.fid;

&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;The Events Calendar meta key cheatsheet&lt;/h3&gt;
For all the meta keys, take a look at The Events Calendar's &lt;a href="https://theeventscalendar.com/knowledgebase/k/events-calendar-pro-wordpress-post-meta-data/"&gt;WordPress Post Meta Data Cheatsheet&lt;/a&gt;.</description><category>events calendar</category><category>migration</category><category>mysql</category><category>tribeevents</category><category>wordpress</category><guid>https://migratecontent.com/migrating-drupal-events-to-wordpress-events-calendar-tribe-events/</guid><pubDate>Fri, 15 Feb 2019 12:04:58 GMT</pubDate></item><item><title>How to fix a 'Object of class WP_Error could not be converted to string' error in WordPress</title><link>https://migratecontent.com/how-to-fix-a-object-of-class-wp_error-could-not-be-converted-to-string-error-in-wordpress/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>If you see a blank page while trying to log in to your WordPress site, check your web server's error logs. You may get the following error:

&lt;pre&gt;stderr: PHP Catchable fatal error:  Object of class WP_Error
could not be converted to string in
/var/[PATH TO YOUR DOCUMENT ROOT]/wp-includes/default-constants.php on line 139
&lt;/pre&gt;

Note that the line number may be different depending on your version of WordPress but the code generating the error is as follows:

&lt;code&gt;function wp_plugin_directory_constants() {&lt;br&gt;
    if ( !defined('WP_CONTENT_URL') )&lt;br&gt;
        define( 'WP_CONTENT_URL', get_option('siteurl') . '/wp-content');&lt;/code&gt;...

Do not be tempted to debug by editing the code as it's not the source of the error. Your problem will very likely be that the &lt;code&gt;siteurl&lt;/code&gt; option value in your WordPress database does not contain a valid entry. In this case, the error message is telling you that &lt;code&gt;get_option()&lt;/code&gt; receives a WP_Error object rather than a string that it's expecting.

To fix this:

&lt;ol&gt;
&lt;li&gt;
First check the &lt;code&gt;siteurl&lt;/code&gt; option to verify that the value is indeed incorrect. Run the following SQL:
&lt;code&gt;SELECT * FROM `wp_options` WHERE option_name = 'siteurl';&lt;/code&gt;

You will likely find a serialized array containing a WP_Error object.
&lt;/li&gt;

&lt;li&gt;Correct the option value by setting it with your domain's URL:
&lt;code&gt;UPDATE wp_options SET option_value = '[YOUR URL]' WHERE option_name = 'siteurl';&lt;/code&gt;
&lt;/li&gt;

&lt;/ol&gt;

I'm not sure what overwrites the &lt;code&gt;siteurl&lt;/code&gt; option value. Most likely there is a misbehaving plugin installed or malware has infected your installation. Be sure to run a scan on your server.</description><category>troubleshooting</category><category>wordpress</category><guid>https://migratecontent.com/how-to-fix-a-object-of-class-wp_error-could-not-be-converted-to-string-error-in-wordpress/</guid><pubDate>Sun, 16 Sep 2018 11:04:15 GMT</pubDate></item><item><title>Why is Drupal the second most dreaded platform?</title><link>https://migratecontent.com/drupal-the-dreaded-cms/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;p&gt;According to the Drupal Shell site, &lt;a href="https://drupal.sh/drupal-hated-sharepoint-platform-stack-overflow"&gt;Drupal is the second most hated CMS platform&lt;/a&gt;. I think this sounds a little harsh. Digging into the &lt;a href="https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted"&gt;source survey on stackoverflow&lt;/a&gt;, we find that it's actually listed as the second most &lt;em&gt;dreaded&lt;/em&gt; platform. While perhaps more even-handed, I'm still not at all surprised as a large chunk of my business is made up of people &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-service/" title="Drupal to WordPress migration service"&gt;migrating from Drupal to WordPress&lt;/a&gt;. To be fair, WordPress fans don't have much to cheer. Their platform of choice appears as number three of the Content Management Platforms (CMS) listed in the poll. Still, Drupal had (has!) a loyal following so why does it draw out such a reaction from respondents?&lt;/p&gt;

&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img class="figure-img img-fluid rounded" src="https://migratecontent.com/images/dreaded-drupal-can-of-worms.png" title="The dreaded Drupal can of worms - Photo by Bill Craighead on Unsplash" alt="The dreaded Drupal can of worms" width="800" height="444"&gt;
&lt;/figure&gt;

&lt;h2&gt;First-mover advantage&lt;/h2&gt;
&lt;p&gt;Let's take a quick look at the history of the major CMS platforms currently in use. Drupal was, in the first decade of the 2000s, arguably the top CMS for building websites. It had first-mover advantage, having launched as an open source project in 2001 - years before its contemporary competitors. Drupal 4 was released in mid-2002 and started appearing on most developers' radar by around 2004-2005. Its only real competitor was Movable Type which offered simple blogging capability. WordPress was at version 1 in 2004 and was then also more of a blogging tool than a CMS. Magento and Joomla would come around quite a few years later, launching in 2007 and 2009 respectively.&lt;/p&gt;
&lt;table width="50%" class="table-striped"&gt;
&lt;caption&gt;CMS version 1 release timeline&lt;/caption&gt;
&lt;tbody&gt;
&lt;tr class="odd row-first"&gt;
&lt;td style="vertical-align:center;font-weight:bold;font-style: italic;width:20%;white-space:nowrap;"&gt;2001&lt;/td&gt;
&lt;td style="vertical-align:center;font-weight:bold;font-style: italic;width:10%;white-space:nowrap;"&gt;→&lt;/td&gt;
&lt;td style="width:75%;white-space:nowrap;"&gt;Drupal&lt;br&gt;
Movable Type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td style="font-weight:bold;font-style: italic;"&gt;2004&lt;/td&gt;
&lt;td style="font-weight:bold;font-style: italic;"&gt;→&lt;/td&gt;
&lt;td&gt;WordPress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="font-weight:bold;font-style: italic;"&gt;2007&lt;/td&gt;
&lt;td style="font-weight:bold;font-style: italic;"&gt;→&lt;/td&gt;
&lt;td&gt;Magento&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td style="font-weight:bold;font-style: italic;"&gt;2009&lt;/td&gt;
&lt;td style="font-weight:bold;font-style: italic;"&gt;→&lt;/td&gt;
&lt;td&gt;Joomla&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;A legacy of custom website generators&lt;/h2&gt;
&lt;p&gt;I remember my first foray into Drupal development in 2003. A freelancer colleague kept raving about how great it was and that I should give it a try. (Incidentally, he subsequently became very active in the Drupal community and ended up having his theme bundled in with core.) At that time, I'd been hand-coding websites and building custom 'site generators'. CMS platforms hadn't taken off so people were coming up with their own solutions for managing site content.&lt;/p&gt;
&lt;p&gt;For example, I worked with a top-tier mobile operator in the early 2000s. They asked me to build a web-based knowledge management system that stored content in Microsoft Access and used VBA to publish static HTML. One leading market intelligence agency I worked with at the end of the 1990s had an online customer database. It delivered web pages using Apache modules. We had to code in C++ and query a flat file database to deliver new functionality. That was fun. Imagine having to deal with memory allocation just to output a web page. Just like coding on stone tablets, right?&lt;/p&gt;
&lt;p&gt;When PHP appeared on the scene, it rapidly became the preferred way to deliver dynamic web content. PHP simplified web development but people still had to cobble together their own site generators. You'd need to write your own authentication system and all the other things we now take for granted. Developing for the web became easier but you still had to jump through lots of hoops before getting to the interesting work.&lt;/p&gt;
&lt;p&gt;It's not difficult to see why, shortly after release, Drupal captured the entire range of the market: hobby sites; small businesses; small and large charities; multi-nationals. They all adopted Drupal because it so quick and easy to deliver complex features.&lt;/p&gt;
&lt;h2&gt;Features for free&lt;/h2&gt;
&lt;p&gt;Eventually, my colleague's insistence overcame my resistance to learning new technology. I found that Drupal, in comparison to hand-coding from scratch, was an absolute dream. I could now build feature-rich websites with login functionality, &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete" title="CRUD: create, read, update, and delete"&gt;CRUD&lt;/a&gt; and custom layouts in maybe one-fifth of the time and cost. Like my colleague, &lt;em&gt;I&lt;/em&gt; started raving about Drupal and began recommending it to clients and colleagues.&lt;/p&gt;
&lt;p&gt;Drupal was, without any doubt, the most powerful website development platform available. Nothing else in the open-source market could touch it. It was also &lt;em&gt;fun&lt;/em&gt; building websites with Drupal. You could get instant gratification by installing and playing with the many available modules. Every developer facing a deadline and budget loves &lt;em&gt;Features for Free&lt;/em&gt; when the alternative is hours of coding and debugging. &lt;em&gt;Features for Free&lt;/em&gt; is fantastic...unless you have to maintain all those features. More on this later.&lt;/p&gt;
&lt;p&gt;Similarly, site owners - who often don't care that much about the technology - loved that their developer could deliver a widgety-thingamajig-feature at a reasonable price. They'd request some functionality and the developer would say, &lt;em&gt;"Yeah, we can do that with Views." "Yeah, there's a module for that, no problem." "Oh, no module for that but we can build one without a huge site overhaul."&lt;/em&gt; It was great until, well...&lt;/p&gt;
&lt;h2&gt;The Drupal can of worms&lt;/h2&gt;
&lt;p&gt;Well, fast-forward to 2018 and nearly every Drupal site I encounter is a huge can of worms. Those great &lt;em&gt;Features for Free&lt;/em&gt; aren't so great when the modules have been abandoned. They're not great when, years after installation, no-one remembers which module controls what and how everything ties together. Sure, documentation and well-commented source code commits are best practice. Perhaps enterprises can afford to maintain a stable of diligent developers. But many sites are cobbled together on a legacy of little to no budget and a revolving door of low-cost developers with varying skills.&lt;/p&gt;
&lt;p&gt;Over time, each person adds their own hacks and disappears. No-one willingly runs updates and upgrades because who enjoys having a nervous breakdown? Run an update and risk a WSOD. Spend hours tracking down some obscure, unsupported and misbehaving module that's absolutely crucial to the way &lt;em&gt;this particular site&lt;/em&gt; works...for free? No thanks!&lt;/p&gt;
&lt;p&gt;Fully-documented sites and well-specified upgrades is the industry ideal. However, real-life tends to go something like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Site owner:&lt;/strong&gt; Hey, remember that site you built for me a couple of years ago? I'd like to...&lt;br&gt;
&lt;strong&gt;Developer:&lt;/strong&gt; mumble...mumble...upgrade to Drupal 5...mumble...[PRICE]....&lt;br&gt;
&lt;strong&gt;Site owner:&lt;/strong&gt; Hmmm, I'm good for now...kthxsbye...&lt;br&gt;
&lt;strong&gt;&lt;br&gt;
A couple of years later...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Site owner:&lt;/strong&gt; Hey, this guy built a site for me. I'd like to...&lt;br&gt;
&lt;strong&gt;Developer:&lt;/strong&gt; mumble...mumble...upgrade to Drupal 6...mumble...[PRICE]....&lt;br&gt;
&lt;strong&gt;Site owner:&lt;/strong&gt; [PRICE]???!!! kthxsbye...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A couple of years later...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Site owner:&lt;/strong&gt; Hey, I have this site...&lt;br&gt;
&lt;strong&gt;Developer:&lt;/strong&gt; Erm...Drupal 7...rebuild the site...&lt;br&gt;
&lt;strong&gt;Site owner:&lt;/strong&gt; What???!!! kthxsbye...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A couple of years later...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Developer:&lt;/strong&gt; Oh, how many thousands of monies did you say is burning a hole in your pocket? Because, you know, Drupal 8...&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2&gt;Upgrades and backward compatibility&lt;/h2&gt;
&lt;p&gt;Of course, poorly documented, buggy and abandoned add-ons are all too common in the WordPress world. The big difference is &lt;em&gt;backward compatibility&lt;/em&gt;. WordPress has been great with ensuring problem-free updates: you see core, plugin or theme updates available; you click &lt;em&gt;Update Now&lt;/em&gt;; a few seconds (or minutes at most) later you're done. You can move on with your day and not give it another thought.&lt;/p&gt;
&lt;p&gt;In contrast, updating Drupal can &lt;em&gt;ruin your day&lt;/em&gt;. (Or night if you're scheduling the work during off-peak hours.) Drupal updates can go horribly wrong. During the pre-Drupal 8 days, it wasn't unusual to spend hours of site rebuilding after one of the module updates crashed the site. Which module? Well, you'd have some trial-and-error testing on a series of modules, one-by-one, until you find the culprit. Updating Drupal is often a &lt;em&gt;dreadful&lt;/em&gt; experience.&lt;/p&gt;
&lt;p&gt;Sensible developers test updates on a development server first, then get the site owner to test on staging before rolling out to live. This is best-practice. Everyone should be following this workflow regardless of the platform. Yes, if there's money for it. This effort comes at a price and many, if not the majority, of smaller businesses, not-for-profits and hobby sites just don't have the cash. People have found that WordPress lets them cheat the recommended workflow. If they see updates they just go ahead and do it live because there are rarely any problems.&lt;/p&gt;
&lt;p&gt;Core upgrades for major Drupal versions are another level of pain for the site owner. Drupal 6, 7 and 8 are all so different in architecture from previous releases that upgrading essentially means re-building the site from scratch. This is too much to expect for many. No wonder site owners would rather hobble along with their outdated and duct-taped CMS.&lt;/p&gt;
&lt;h2&gt;The dread&lt;/h2&gt;
&lt;p&gt;Keeping Drupal up-to-date is expensive for the owner and time-consuming for the developer. Site owners dread to think about the fees. Maintainers dread jumping through hoops just to run simple module updates. Newly hired developers dread what they might find when they peek under the hood.&lt;/p&gt;
&lt;p&gt;I started Another Cup of Coffee as a Drupal development shop because it allowed us to offer powerful functionality at a reasonable price. Years later, although I'm no longer in the business of building Drupal sites, I do remember the feeling of dread when time came to tinker with a mature installation. I have every sympathy for those who list Drupal as their second most dreaded platform. It seems that everyone feels The Drupal Dread. Unless of course, they make lots of money from Drupal support.&lt;/p&gt;

&lt;div class="footnotes"&gt;
Photo by &lt;a href="https://unsplash.com/photos/IpJ5j4ox9BE?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="nofollow"&gt;Bill Craighead&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/worms?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/drupal-7-end-of-life-migration-options/"&gt;Drupal 7 End of Life: Your Migration Options in 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/why-automated-migration-tools-fail/"&gt;Why Automated Migration Tools Fail for Complex Drupal Sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-we-migrate-technical-process/"&gt;How We Migrate: The Technical Process Behind a Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Ready to Leave Drupal Behind?&lt;/h2&gt;

&lt;p&gt;I specialise in complex Drupal to WordPress migrations, including e-commerce, custom content types, and business-critical sites that need zero-downtime launches. Get a free, no-obligation consultation to discuss your options.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your Drupal to WordPress migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>drupal</category><category>migration</category><category>wordpress</category><guid>https://migratecontent.com/drupal-the-dreaded-cms/</guid><pubDate>Sun, 18 Mar 2018 13:29:15 GMT</pubDate></item><item><title>Why Automated Migration Tools Fail for Complex Drupal Sites</title><link>https://migratecontent.com/why-automated-migration-tools-fail/</link><dc:creator>Aiden</dc:creator><description>&lt;p class="intro"&gt;Automated migration tools promise a straightforward path from Drupal to WordPress: install a plugin, point it at your database, and watch your content appear. For a simple blog with standard posts and pages, they might even deliver. However, for sites with custom content types, complex field relationships, e-commerce data, or meaningful SEO requirements, these tools consistently fall short. Here's why.&lt;/p&gt;

&lt;h2&gt;What Automated Tools Actually Do&lt;/h2&gt;

&lt;p&gt;The most common tools (FG Drupal to WordPress, CMS2CMS, WordHerd) work by mapping Drupal's core database tables to their WordPress equivalents. They handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basic nodes.&lt;/strong&gt; Standard Drupal posts and pages migrate as WordPress posts and pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Taxonomy terms.&lt;/strong&gt; Drupal vocabularies map to WordPress categories or tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Users.&lt;/strong&gt; Basic user accounts transfer with login credentials.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comments.&lt;/strong&gt; Comment threads attached to nodes migrate to WordPress comments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embedded images.&lt;/strong&gt; Images within content bodies are usually downloaded and re-linked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For these core data types, automated tools are reasonably effective. The problems start when your Drupal site uses anything beyond the default content model.&lt;/p&gt;

&lt;h2&gt;Where They Break Down&lt;/h2&gt;

&lt;h3&gt;Custom Content Types and Fields&lt;/h3&gt;

&lt;p&gt;Drupal's content type system is one of its greatest strengths. It's also the primary reason automated tools fail. A typical business site might have content types for projects, case studies, team members, events, and products, each with dozens of custom fields including entity references, date ranges, address fields, and file attachments.&lt;/p&gt;

&lt;p&gt;Automated tools treat all content as either posts or pages. Custom fields are either ignored entirely or dumped into a single text block.&lt;/p&gt;

&lt;p&gt;Entity reference fields (the relationships connecting a project to a team member, or an event to a venue) are lost. The data arrives in WordPress, but the structure that makes it meaningful doesn't.&lt;/p&gt;

&lt;h3&gt;Complex Taxonomy Structures&lt;/h3&gt;

&lt;p&gt;Drupal supports multiple vocabulary systems with hierarchical terms, custom fields on terms, and cross-references between vocabularies. WordPress offers categories and tags by default, with custom taxonomies available through code or plugins.&lt;/p&gt;

&lt;p&gt;Automated tools typically flatten Drupal's taxonomy system into WordPress categories or tags without preserving hierarchy, term relationships, or custom term fields. For sites where taxonomy drives navigation, filtering, or search functionality, this produces a broken information architecture.&lt;/p&gt;

&lt;h3&gt;Media and File Handling&lt;/h3&gt;

&lt;p&gt;The most common post-migration complaint is duplicate images. Drupal's media system, particularly in Drupal 7 with modules like Media, File Entity, and IMCE, lets a single image serve dozens of content items through file entity references. Automated tools don't understand that reference structure.&lt;/p&gt;

&lt;p&gt;They download and re-upload each instance separately, so a product photo used on ten pages becomes ten copies in the WordPress media library. File metadata, alt text stored at the field level, and image crop configurations are typically lost in the process.&lt;/p&gt;

&lt;h3&gt;E-commerce Data&lt;/h3&gt;

&lt;p&gt;Drupal Commerce stores products, orders, customers, and payment records across interconnected entity types with complex relationships. A single order connects to a customer account, multiple product variations, shipping information, payment transactions, and billing addresses.&lt;/p&gt;

&lt;p&gt;No automated tool handles Drupal Commerce data. The relationship structure is too complex and too specific to each store's configuration. E-commerce migration always requires custom scripting. There's no shortcut.&lt;/p&gt;

&lt;h3&gt;URL Structure and SEO&lt;/h3&gt;

&lt;p&gt;Missing redirects are the most common cause of SEO damage after a platform migration. Drupal's &lt;code&gt;url_alias&lt;/code&gt; system allows multiple URL paths per node, including paths with forward slashes and special characters that WordPress can't replicate in its slug field. Automated tools may import content, but they don't generate the 301 redirect map needed to preserve search rankings. For a site with hundreds or thousands of indexed pages, that gap means losing organic traffic that took years to build.&lt;/p&gt;

&lt;h2&gt;The Real Cost of a Failed Migration&lt;/h2&gt;

&lt;p&gt;The appeal of automated tools is understandable. They're cheap and fast. However, the cost of fixing a failed automated migration often exceeds the cost of doing it properly in the first place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data loss.&lt;/strong&gt; Custom fields, relationships, and metadata that weren't migrated can't always be recovered. If the original Drupal site has been decommissioned, that data may be gone permanently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Broken content.&lt;/strong&gt; Pages that display correctly in Drupal but render as unstructured text blocks in WordPress require manual reconstruction, page by page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO damage.&lt;/strong&gt; Missing redirects cause immediate ranking drops. The longer the gap between launch and redirect implementation, the harder it is to recover lost positions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lost revenue.&lt;/strong&gt; For e-commerce sites, corrupted product data, broken customer accounts, or lost order history directly impacts business operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team time.&lt;/strong&gt; Someone has to fix all of this. The time your team spends cleaning up automated migration output is time not spent on business activities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;When Custom Scripting Is Necessary&lt;/h2&gt;

&lt;p&gt;If any of the following apply to your site, automated tools won't produce acceptable results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Custom content types.&lt;/strong&gt; Any content type beyond basic posts and pages with custom field configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E-commerce.&lt;/strong&gt; Drupal Commerce or Ubercart stores of any size.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex taxonomy.&lt;/strong&gt; Multiple vocabularies, hierarchical terms, or terms with custom fields.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large media libraries.&lt;/strong&gt; Thousands of files with structured metadata and multiple references.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO-critical sites.&lt;/strong&gt; Any site where organic search drives meaningful business value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User accounts.&lt;/strong&gt; Sites with authenticated user features, member areas, or role-based access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Custom scripting means writing migration code that understands your specific data model: the relationships between content types, the custom field structures, and the business logic that automated tools don't know about. It's more work upfront, but the output is a clean, complete WordPress site rather than a partially migrated dataset that needs weeks of manual cleanup.&lt;/p&gt;

&lt;h2&gt;When Automated Tools Might Work&lt;/h2&gt;

&lt;p&gt;To be fair, automated tools have their place. They can be a reasonable option if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Your site is simple.&lt;/strong&gt; Standard blog posts, basic pages, and default Drupal fields only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No custom content types.&lt;/strong&gt; Everything uses Drupal's built-in Article and Basic Page types.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO isn't critical.&lt;/strong&gt; You're not reliant on organic search traffic and can absorb a temporary ranking drop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No e-commerce.&lt;/strong&gt; No product catalogues, order histories, or customer accounts to migrate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Small media library.&lt;/strong&gt; A manageable number of images that can be manually reviewed after migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this describes your site, an automated tool followed by manual cleanup may be cost-effective. For everything else, custom migration is the reliable path.&lt;/p&gt;

&lt;h2&gt;Making the Right Choice&lt;/h2&gt;

&lt;p&gt;The decision between automated tools and custom migration comes down to risk tolerance. If the data is replaceable and the SEO stakes are low, an automated tool is a reasonable gamble. If the data is business-critical, the relationships between content items matter, or your search rankings drive revenue, custom scripting is the only approach that delivers predictable results.&lt;/p&gt;

&lt;p&gt;I assess every project individually and recommend the approach that fits the site's actual complexity. For simple sites, I'll tell you an automated tool will do the job. For complex ones, I'll explain exactly what custom scripting involves and why it's worth the investment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/migrating-drupal-commerce-to-woocommerce/"&gt;Migrating Drupal Commerce to WooCommerce: What You Need to Know&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/how-we-migrate-technical-process/"&gt;How We Migrate: The Technical Process Behind a Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://migratecontent.com/preserving-seo-drupal-wordpress-migration/"&gt;Preserving Your SEO During a Drupal to WordPress Migration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Not Sure If Your Site Needs Custom Migration?&lt;/h2&gt;

&lt;p&gt;Send me your site URL and I'll give you an honest assessment: whether automated tools will work for your situation or whether custom scripting is the way to go. No obligation, no sales pitch.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a free migration assessment"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>automated-tools</category><category>drupal</category><category>migration</category><category>wordpress</category><guid>https://migratecontent.com/why-automated-migration-tools-fail/</guid><pubDate>Wed, 11 Oct 2017 09:00:00 GMT</pubDate></item><item><title>Post-migration troubleshooting: Gateway timeout when enabling plugins</title><link>https://migratecontent.com/post-migration-troubleshooting-gateway-timeout-enabling-plugins/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;p&gt;Here's one that caught me out on a recent Drupal to WordPress migration. As is common with my projects, there were three parties involved: the client, an external development team and myself. The WordPress site was first built on the development team's server, after which it was migrated to my local environment. When everything was ready for beta testing, we moved the site over to the client's staging server on a newly activated account over at &lt;a href="https://kinsta.com/"&gt;Kinsta&lt;/a&gt;. Eventually, we'd move it over to a live server, also hosted on Kinsta.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://migratecontent.com/images/drupal-to-wordpress-migration-team-structure.jpg" title="Drupal to WordPress migration workflow" alt="Diagram of Drupal to WordPress migration workflow for this project" width="600" height="273" class="aligncenter size-full wp-image-1980"&gt;&lt;/p&gt;

&lt;p&gt;After some initial tests on staging, I found that deactivating and reactivating plugins would cause the site to hang and show a &lt;em&gt;'504 Gateway Time-out'&lt;/em&gt; error. This happened when re-enabling some but not all plugins.&lt;/p&gt;

&lt;p&gt;I initially suspected some misconfiguration at the hosting end because there were some hitches with the newly create account. At the outset, the account's server had an issue which Kinsta support needed to fix. For convenience, we'd also made use of Kinsta's free site migration service. This is where they'll migrate an existing WordPress site into their environment. Though it would have been easy enough for me to do, we thought to give it a try. In hindsight, this was a bit of a mistake. The site migration service itself was fine but it did end up causing some confusion. First, a miscommunication in the migration request caused them to create a temporary domain we didn't want. They helpfully solved this by giving us a second temporary domain. However, they'd also upgraded everything to PHP 7 in the process. All of these issues were possible suspects for the time-out error but turned out to be red-herrings.&lt;/p&gt;

&lt;p&gt;It took some time to pinpoint the cause behind the Gateway Time-out error. I do have to say that Kinsta support were very responsive throughout the troubleshooting process. They eventually put a senior engineer on the case who found the problem. It turned out the problem wasn't to do with Kinsta at all. There was a leftover setting from the original development team's server. It was a valid format so didn't cause an issue on either my local server or my staging server. However, it apparently can cause issues with plugins and did on the Kinsta environment.&lt;/p&gt;

&lt;p&gt;What was the setting? The WordPress upload path directory was set to the development team's server path e.g. &lt;code&gt;/home/dev/public_html/sitename&lt;/code&gt;. Throughout the migration, I'd been doing a database search-and-replace looking for their development domain. Somehow, as the site moved from different servers, that server path string remained in the database, only to cause a problem when the site landed in the destination server on Kinsta.&lt;/p&gt;

&lt;p&gt;I'm not sure if there would have been any way to have caught this problem earlier. It's one of those obscure errors that are easy to overlook and take time to resolve. There's also no practical way to do a database search-and-replace for every imaginable string. I'll have to rack this one up to experience. &lt;/p&gt;</description><category>drupal</category><category>help</category><category>migration</category><category>troubleshooting</category><category>wordpress</category><guid>https://migratecontent.com/post-migration-troubleshooting-gateway-timeout-enabling-plugins/</guid><pubDate>Mon, 05 Jun 2017 09:35:07 GMT</pubDate></item><item><title>How to change the WordPress table prefix prior to a migration</title><link>https://migratecontent.com/change-wordpress-table-prefix-prior-migration/</link><dc:creator>Anthony Lopez-Vito</dc:creator><description>&lt;p&gt;When working on a &lt;a href="https://migratecontent.com/drupal-to-wordpress-migration-service/"&gt;Drupal to WordPress migration&lt;/a&gt; project, I like to migrate into a set of intermediary WordPress tables that live in the Drupal database. These are working tables where I can run various scripts to process and clean up the content before exporting to a working WordPress installation. It's not &lt;em&gt;necessary&lt;/em&gt; to do this but I find it convenient to run scripts on the same database rather than deal with two separate database connections.&lt;/p&gt;


&lt;figure class="figure d-flex flex-column align-items-center"&gt;
    &lt;img src="https://migratecontent.com/images/gavin-allanwood-q92hWEdK8p8-unsplash.jpg" alt="Overhead image of cafe tables" class="figure-img img-fluid rounded" width="800" height="533"&gt;
&lt;/figure&gt;

&lt;p&gt;Note that some people suggest renaming the table prefixes to improve security. My use of the table prefixes is simply to create temporary containers for the migration. While non-standard prefixes might help prevent 'script kiddie' attacks, I find it isn't worth the disadvantages that come with this sort of &lt;a href="https://en.wikipedia.org/wiki/Security_through_obscurity"&gt;security through obscurity&lt;/a&gt; (or more precisely, &lt;a href="https://en.wikipedia.org/wiki/Security_through_obscurity#Security_through_minority"&gt;security through minority&lt;/a&gt;) approach. Here are two articles give a deeper explanation of topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wordfence.com: &lt;a href="https://www.wordfence.com/blog/2016/12/wordpress-table-prefix/"&gt;WordPress Table Prefix: Changing It Does Nothing to Improve Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;wpkrauts.com: &lt;a href="https://web.archive.org/web/20150129082218/http://wpkrauts.com/2015/the-database-prefix-is-not-a-security-feature/"&gt;The database table prefix is not a security feature&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SQL queries to change the WordPress table prefixes&lt;/h2&gt;
&lt;p&gt;You can start with a freshly installed WordPress database. Dumping this and importing to your Drupal migration database will give you all the tables with the correct WordPress schema. I use the &lt;em&gt;acc_&lt;/em&gt; prefix but you can use whatever you want.&lt;/p&gt;
&lt;p&gt;Rename the tables with these queries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RENAME table `wp_commentmeta` TO `acc_commentmeta`;
RENAME table `wp_comments` TO `acc_comments`;
RENAME table `wp_links` TO `acc_links`;
RENAME table `wp_options` TO `acc_options`;
RENAME table `wp_postmeta` TO `acc_postmeta`;
RENAME table `wp_posts` TO `acc_posts`;
RENAME table `wp_terms` TO `acc_terms`;
RENAME table `wp_termmeta` TO `acc_termmeta`;
RENAME table `wp_term_relationships` TO `acc_term_relationships`;
RENAME table `wp_term_taxonomy` TO `acc_term_taxonomy`;
RENAME table `wp_usermeta` TO `acc_usermeta`;
RENAME table `wp_users` TO `acc_users`;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Testing the migration results&lt;/h2&gt;
&lt;p&gt;If you need to point a WordPress installation to these tables for testing, you'll need to do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update the &lt;em&gt;$table_prefix&lt;/em&gt; setting in the &lt;em&gt;wp-options.php&lt;/em&gt; file&lt;/li&gt;
&lt;li&gt;Update the &lt;em&gt;options&lt;/em&gt; and &lt;em&gt;usermeta&lt;/em&gt; tables&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Updating the &lt;em&gt;$table_prefix&lt;/em&gt; setting in the &lt;em&gt;wp-options.php&lt;/em&gt; file is straightforward. Open the file and edit the line:&lt;/p&gt;
&lt;pre&gt;$table_prefix  = 'acc_';&lt;/pre&gt;
&lt;p&gt;In WordPress, prefixes are saved as entries in the &lt;em&gt;options&lt;/em&gt; and &lt;em&gt;usermeta&lt;/em&gt; table. Check for entries containing the prefix:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM `acc_options` WHERE `option_name` LIKE '%wp_%';
SELECT * FROM `acc_usermeta` WHERE `meta_key` LIKE '%wp_%';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you have all the entries, update them with the new prefix. The query will probably look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UPDATE `acc_options` SET `option_name` = 'acc_user_roles' WHERE `option_name` = 'wp_user_roles';
UPDATE `acc_usermeta` SET `meta_key` = 'acc_capabilities' WHERE `meta_key` = 'wp_capabilities';
UPDATE `acc_usermeta` SET `meta_key` = 'acc_user_level' WHERE `meta_key` = 'wp_user_level';
UPDATE `acc_usermeta` SET `meta_key` = 'acc_user-settings-time' WHERE `meta_key` = 'wp_user-settings-time';
UPDATE `acc_usermeta` SET `meta_key` = 'acc_user-settings' WHERE `meta_key` = 'wp_user-settings';
UPDATE `acc_usermeta` SET `meta_key` = 'acc_dashboard_quick_press_last_post_id' WHERE `meta_key` = 'wp_dashboard_quick_press_last_post_id';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A word of warning:&lt;/strong&gt; it's easy to forget to change the prefixes back to match the final WordPress installation. If you do, the WordPress user accounts will have problems, such as the Dashboard controls not being visible after logging in. Because of this, I tend to have a separate testing installation that gets an import of the working tables.&lt;/p&gt;

&lt;div class="footnotes"&gt;
&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@gavla?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" target="_blank" rel="nofollow"&gt;Gavin Allanwood&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/aerial-photo-of-grey-tables-q92hWEdK8p8?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" target="_blank" rel="nofollow"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;


&lt;section class="breakout-white"&gt;
&lt;div class="breakout-inner text-center"&gt;

&lt;h2&gt;Need Help With Your Drupal to WordPress Migration?&lt;/h2&gt;

&lt;p&gt;I specialise in complex Drupal to WordPress migrations, including database preparation, table prefix management, and post-migration testing. Get a free, no-obligation consultation.&lt;/p&gt;

&lt;div class="button-container" style="margin:2em 0;"&gt;
&lt;a class="cta-button" href="https://migratecontent.com/contact/" title="Get a quote for your Drupal to WordPress migration"&gt;Get a Free Quote&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/section&gt;</description><category>database</category><category>drupal</category><category>migration</category><category>sql</category><category>wordpress</category><guid>https://migratecontent.com/change-wordpress-table-prefix-prior-migration/</guid><pubDate>Thu, 16 Mar 2017 13:12:02 GMT</pubDate></item></channel></rss>