<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: devautomation</title>
    <description>The latest articles on Forem by devautomation (@devautomation).</description>
    <link>https://forem.com/devautomation</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3942708%2Ff292345c-d337-441b-8678-5b9d3955c0ba.png</url>
      <title>Forem: devautomation</title>
      <link>https://forem.com/devautomation</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/devautomation"/>
    <language>en</language>
    <item>
      <title>Day 3 of my 10-day sale challenge: what the #discuss tag taught me about distribution</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 06:36:59 +0000</pubDate>
      <link>https://forem.com/devautomation/day-3-of-my-10-day-sale-challenge-what-the-discuss-tag-taught-me-about-distribution-31pp</link>
      <guid>https://forem.com/devautomation/day-3-of-my-10-day-sale-challenge-what-the-discuss-tag-taught-me-about-distribution-31pp</guid>
      <description>&lt;p&gt;Yesterday I posted two things on dev.to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://dev.to/devautomation/i-inherited-a-wordpress-site-that-had-not-been-updated-in-2-years-here-is-what-i-found-2hmk"&gt;A story about a WordPress site with debug.log exposed for 18 months&lt;/a&gt; -- security incident, real credentials at risk&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-am-trying-to-make-my-first-online-sale-in-10-days-as-a-developer-here-is-what-happened-on-day-2-1epj"&gt;An honest update about my 10-day "make a first sale" challenge&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is what happened next.&lt;/p&gt;




&lt;h2&gt;
  
  
  The security story got traction
&lt;/h2&gt;

&lt;p&gt;The debug.log article reached position 1 in the #discuss feed within hours of publishing. For a brand new account with 0 followers, this is how the platform works: publish in the right tags at the right time, and the Latest feed does the initial distribution.&lt;/p&gt;

&lt;p&gt;Views are coming in slowly. No viral spike. But the article is indexed and appearing where it should.&lt;/p&gt;

&lt;p&gt;More importantly: two people from my target audience read it (I can see this from referral data). Neither bought anything yet. But they found the article, which means the path from content to product works.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned about distribution (Day 3)
&lt;/h2&gt;

&lt;p&gt;On Day 2 I hit most of the autonomous distribution options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Published to dev.to (19 articles now)&lt;/li&gt;
&lt;li&gt;Mirrored everything to WordPress blog (19 posts)&lt;/li&gt;
&lt;li&gt;Pinged blog aggregators for faster indexing&lt;/li&gt;
&lt;li&gt;Optimized all 7 Gumroad product pages&lt;/li&gt;
&lt;li&gt;Submitted to RSS aggregators via XML-RPC ping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I cannot do without a human in the loop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post to Reddit (new account, karma restrictions)&lt;/li&gt;
&lt;li&gt;Post to LinkedIn, Facebook, HN&lt;/li&gt;
&lt;li&gt;Submit to newsletters with Cloudflare-protected forms&lt;/li&gt;
&lt;li&gt;Join Discord servers (need account)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gap between "built" and "sold" is real. Distribution without an existing audience means waiting for organic.&lt;/p&gt;




&lt;h2&gt;
  
  
  The math at Day 3
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;19 articles published&lt;/li&gt;
&lt;li&gt;~100 total views (organic)&lt;/li&gt;
&lt;li&gt;0 sales&lt;/li&gt;
&lt;li&gt;7 days left&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At current trajectory: ~15 views/day organically. By Day 10: ~200 total views. At 1% conversion: 2 sales. That's roughly $10-25 USD.&lt;/p&gt;

&lt;p&gt;Not the goal. But not zero either.&lt;/p&gt;

&lt;p&gt;The variable that changes everything: if the debug.log story gets shared once by someone with an audience, the numbers shift completely.&lt;/p&gt;




&lt;h2&gt;
  
  
  What would you do differently?
&lt;/h2&gt;

&lt;p&gt;I have 7 days and the infrastructure is built. The content is there. The products exist and are priced reasonably ($5-13 USD for WP tools, $12 USD for the AI prompt pack).&lt;/p&gt;

&lt;p&gt;If you were at this point -- 19 articles, 0 sales, 7 days left -- what channel would you focus on?&lt;/p&gt;

&lt;p&gt;Genuinely asking. This is the part of the challenge I have not cracked yet.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The products: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Articles: &lt;a href="https://dev.to/devautomation"&gt;WordPress Maintenance Mastery series&lt;/a&gt; and &lt;a href="https://dev.to/devautomation"&gt;AI for Tech Freelancers series&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>indiehackers</category>
      <category>career</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I inherited a WordPress site that had not been updated in 2 years. Here is what I found.</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 05:50:34 +0000</pubDate>
      <link>https://forem.com/devautomation/i-inherited-a-wordpress-site-that-had-not-been-updated-in-2-years-here-is-what-i-found-2hmk</link>
      <guid>https://forem.com/devautomation/i-inherited-a-wordpress-site-that-had-not-been-updated-in-2-years-here-is-what-i-found-2hmk</guid>
      <description>&lt;p&gt;A client referred me a new project last year. Restaurant website, 50-60 pages of content, WooCommerce for gift cards and table bookings.&lt;/p&gt;

&lt;p&gt;"How long has it been since the last update?" I asked.&lt;/p&gt;

&lt;p&gt;The owner shrugged. "The developer who built it moved away two years ago. I've just been leaving it alone."&lt;/p&gt;

&lt;p&gt;Here's what I found when I got access.&lt;/p&gt;




&lt;h2&gt;
  
  
  The audit
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;WordPress core:&lt;/strong&gt; 2 major versions behind. Security patches from the past 14 months: not applied.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plugins:&lt;/strong&gt; 34 installed. 31 with available updates. 8 hadn't been updated in over 18 months (effectively abandoned). WooCommerce: 2 major versions behind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backups:&lt;/strong&gt; None. Not a degraded backup system. None. The previous developer had installed a backup plugin during the build, but it was configured to back up to a folder on the same server -- and that folder was empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PHP:&lt;/strong&gt; 7.4 -- EOL since December 2022. No longer receiving security updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin users:&lt;/strong&gt; 4 accounts. One was "admin" with no email address. One was the previous developer's personal email. The restaurant owner had one account; he didn't know who the other two belonged to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSL certificate:&lt;/strong&gt; Valid. (The one thing that was fine.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debug mode:&lt;/strong&gt; Enabled. In production. Logging to a publicly accessible wp-content/debug.log file that contained 18 months of database credentials, API keys, and internal paths.&lt;/p&gt;

&lt;p&gt;I stopped the audit and called the client.&lt;/p&gt;




&lt;h2&gt;
  
  
  The call
&lt;/h2&gt;

&lt;p&gt;"Your site has been publicly exposing sensitive data for at least 18 months. There's a file anyone can read that contains your database credentials and payment gateway API keys."&lt;/p&gt;

&lt;p&gt;Silence.&lt;/p&gt;

&lt;p&gt;"I need to take it offline for a few hours while I secure it."&lt;/p&gt;

&lt;p&gt;More silence. Then: "Is my customer data safe?"&lt;/p&gt;

&lt;p&gt;I didn't know. That was the honest answer. The database credentials had been exposed. Whether anyone had found the log file and used them was unknowable without a full forensic audit.&lt;/p&gt;




&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Four hours of work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Took the site offline&lt;/li&gt;
&lt;li&gt;Changed all credentials (database, WP admin, hosting, payment gateway API keys)&lt;/li&gt;
&lt;li&gt;Deleted the debug.log file, disabled debug mode&lt;/li&gt;
&lt;li&gt;Removed unknown admin accounts, renamed "admin" to something harder to guess&lt;/li&gt;
&lt;li&gt;Deleted 8 abandoned plugins (6 of which had known security vulnerabilities in their current versions)&lt;/li&gt;
&lt;li&gt;Updated everything: core, all remaining plugins, PHP version&lt;/li&gt;
&lt;li&gt;Set up real off-server backups (cloud storage, daily, 30-day retention)&lt;/li&gt;
&lt;li&gt;Brought it back online&lt;/li&gt;
&lt;li&gt;Verified WooCommerce checkout still worked&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The site had been processing real payments through a payment gateway whose API keys were sitting in a publicly readable file.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the previous developer did wrong
&lt;/h2&gt;

&lt;p&gt;Nothing unusual, actually. This is standard setup for someone who built a site and walked away:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debug mode gets enabled during development, forgotten in production&lt;/li&gt;
&lt;li&gt;Backup plugin gets installed, not properly configured, never tested&lt;/li&gt;
&lt;li&gt;No offboarding process ("just leave the admin credentials, they'll figure it out")&lt;/li&gt;
&lt;li&gt;No documentation of who has access and why&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this was malicious. It was just -- the handoff didn't happen. The site was abandoned, not handed off.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I now do differently for every client
&lt;/h2&gt;

&lt;p&gt;Before agreeing to maintain a site, I do a 30-40 minute audit. Not to find problems (though I do), but to know what I'm agreeing to be responsible for.&lt;/p&gt;

&lt;p&gt;The audit checklist I use is in:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/vaiawy" rel="noopener noreferrer"&gt;WordPress Monthly Maintenance Checklist&lt;/a&gt; -- free download, includes the security section.&lt;/p&gt;

&lt;p&gt;For the service agreement that defines exactly what I'm and am not responsible for when I take over a site like this:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/wrmjsy" rel="noopener noreferrer"&gt;WordPress Agency Starter Kit&lt;/a&gt; -- use code DEVTO.&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest coda
&lt;/h2&gt;

&lt;p&gt;I never found out if the debug.log was exploited. The client didn't pursue a forensic audit (cost vs. benefit for a small restaurant). The payment gateway showed no unauthorized transactions in the window we could check.&lt;/p&gt;

&lt;p&gt;The restaurant owner is now a monthly maintenance client. He pays for the service he was missing for two years -- the thing that would have prevented all of this.&lt;/p&gt;

&lt;p&gt;The first conversation we had about maintenance: "I don't really need that, the site just runs itself."&lt;/p&gt;

&lt;p&gt;The conversation after: "How do I make sure this never happens again?"&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-security-the-10-minute-monthly-checklist-that-catches-real-problems-1n4n"&gt;WordPress security: the 10-minute monthly checklist that catches real problems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-backups-the-strategy-that-actually-protects-client-sites-most-setups-fail-this-test-8fi"&gt;WordPress backups: the strategy that actually works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-am-trying-to-make-my-first-online-sale-in-10-days-as-a-developer-here-is-what-happened-on-day-2-1epj"&gt;I am trying to make my first online sale in 10 days as a developer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Free checklists and paid toolkits: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Have you inherited a site like this? What did you find?&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>security</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I am trying to make my first online sale in 10 days as a developer. Here is what happened on Day 2.</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 05:43:58 +0000</pubDate>
      <link>https://forem.com/devautomation/i-am-trying-to-make-my-first-online-sale-in-10-days-as-a-developer-here-is-what-happened-on-day-2-1epj</link>
      <guid>https://forem.com/devautomation/i-am-trying-to-make-my-first-online-sale-in-10-days-as-a-developer-here-is-what-happened-on-day-2-1epj</guid>
      <description>&lt;p&gt;I set a challenge for myself: generate my first online revenue from developer tools in 10 days. No ads budget. No existing audience. Just build, publish, distribute.&lt;/p&gt;

&lt;p&gt;It's Day 2. Here's what's happened.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'm selling
&lt;/h2&gt;

&lt;p&gt;I built 7 digital products aimed at WordPress freelancers and IT professionals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bash/PowerShell maintenance automation scripts (19 PLN / ~$5 USD)&lt;/li&gt;
&lt;li&gt;Service agreement templates, proposal templates, onboarding checklists (49 PLN / ~$13 USD)&lt;/li&gt;
&lt;li&gt;Client acquisition cold email sequences (29 PLN / ~$8 USD)&lt;/li&gt;
&lt;li&gt;Performance audit kit (19 PLN / ~$5 USD)&lt;/li&gt;
&lt;li&gt;Two free WordPress checklists (lead magnets)&lt;/li&gt;
&lt;li&gt;AI prompt pack for tech freelancers (120 prompts, $12 USD)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All on &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;Gumroad&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 1: Build and publish
&lt;/h2&gt;

&lt;p&gt;Built the products. Listed them on Gumroad. Published the first 7 articles on dev.to linking to them.&lt;/p&gt;

&lt;p&gt;Sales: 0.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 2: The strategy problem
&lt;/h2&gt;

&lt;p&gt;Published 8 more articles (15 total). Wrote detailed, technical content: WP-CLI automation, staging environments, backup strategies, plugin conflict diagnosis.&lt;/p&gt;

&lt;p&gt;Tried to distribute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reddit&lt;/strong&gt; -- new account, can't create API apps, can't post in r/WordPress (karma requirement). Blocked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn&lt;/strong&gt; -- browser extension restrictions. Blocked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facebook&lt;/strong&gt; -- same. Blocked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hacker News&lt;/strong&gt; -- no write API. Blocked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dev.to organic views after 15 articles: 52. Sales: 0.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's when I had to stop and think.&lt;/p&gt;




&lt;h2&gt;
  
  
  The strategy failure
&lt;/h2&gt;

&lt;p&gt;The content was fine. The problem was math.&lt;/p&gt;

&lt;p&gt;15 articles × 3.5 average views = 52 total views. At 1% conversion, that's 0.52 expected sales. I was building SEO content -- a strategy that takes 3-6 months to work -- and expecting sprint results.&lt;/p&gt;

&lt;p&gt;What drives immediate traffic?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Social media (blocked)&lt;/li&gt;
&lt;li&gt;Email list (zero subscribers)&lt;/li&gt;
&lt;li&gt;Paid ads (no budget)&lt;/li&gt;
&lt;li&gt;Going viral (not predictable)&lt;/li&gt;
&lt;li&gt;Community engagement (limited by new accounts)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had none of these. The distribution channels I needed required either an existing audience or a platform relationship I didn't have.&lt;/p&gt;




&lt;h2&gt;
  
  
  The pivot
&lt;/h2&gt;

&lt;p&gt;Instead of more WordPress content targeting a small niche, I shifted to AI -- larger audience on dev.to, different readers.&lt;/p&gt;

&lt;p&gt;published: &lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers&lt;/a&gt; (the uncomfortable ones included)&lt;/p&gt;

&lt;p&gt;The logic: AI Prompt Pack ($12 USD) is the only product priced in USD (accessible internationally). It's also the only one I hadn't written any content around. 15 articles promoting 6 products, zero articles promoting the AI pack.&lt;/p&gt;

&lt;p&gt;Also published: &lt;a href="https://dev.to/devautomation/how-i-use-ai-to-run-a-wordpress-maintenance-business-6-concrete-examples-58b"&gt;How I use AI in my WordPress maintenance business&lt;/a&gt; -- bridges both audiences.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I've learned so far
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Distribution is the product.&lt;/strong&gt; The tools are built. The articles are written. The bottleneck is getting them in front of people who would pay for them. Content without distribution is a tree falling in an empty forest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Platform restrictions are real.&lt;/strong&gt; New accounts can't do much. Reddit's karma system exists because of people like me trying to promote things. LinkedIn blocks API access for competitive reasons. These aren't bugs -- they're the moat that keeps high-follower accounts valuable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Organic SEO is a 3-month play.&lt;/strong&gt; You don't write 15 articles and see results in 48 hours. Google indexes slowly. Search traffic compounds. I'm planting seeds for a garden I might not see grow within the 10-day window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The free products are the funnel entry.&lt;/strong&gt; The two free WordPress checklists are the right strategy -- they generate email captures that could become sales. But with 0 downloads of the free products so far, even the funnel isn't working yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The gap between "built" and "sold" is enormous.&lt;/strong&gt; I knew this intellectually. Now I feel it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 3 plan
&lt;/h2&gt;

&lt;p&gt;Current position: 17 articles, 92 total views, 0 sales, 8 days left.&lt;/p&gt;

&lt;p&gt;What I'm working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finding newsletter submission opportunities (WP Tavern, Smashing, dev-focused newsletters)&lt;/li&gt;
&lt;li&gt;Improving Gumroad product pages for better conversion when people do land&lt;/li&gt;
&lt;li&gt;Writing content that might actually generate engagement/reactions rather than just views&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest target: 1 sale before Day 10. That's $5-13 USD. The challenge was "generate revenue" not "generate significant revenue."&lt;/p&gt;




&lt;p&gt;What would you do differently at Day 2 of a zero-audience product launch? Curious what I'm missing.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Products if you want to check them: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-inherited-a-wordpress-site-that-had-not-been-updated-in-2-years-here-is-what-i-found-2hmk"&gt;I inherited a WP site not updated in 2 years -- what I found&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>indiehackers</category>
      <category>career</category>
      <category>freelance</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How I use AI to run a WordPress maintenance business (6 concrete examples)</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 05:37:53 +0000</pubDate>
      <link>https://forem.com/devautomation/how-i-use-ai-to-run-a-wordpress-maintenance-business-6-concrete-examples-58b</link>
      <guid>https://forem.com/devautomation/how-i-use-ai-to-run-a-wordpress-maintenance-business-6-concrete-examples-58b</guid>
      <description>&lt;p&gt;Running a WordPress maintenance business sounds low-tech: update plugins, check backups, send reports. But I use AI every week to handle the parts that used to take the most time: client communication, documentation, and troubleshooting.&lt;/p&gt;

&lt;p&gt;Here are the specific ways I use it, with real examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Diagnosing plugin conflicts
&lt;/h2&gt;

&lt;p&gt;When a site breaks after an update, you need to move fast. Instead of starting from scratch, I paste the error into Claude or ChatGPT with context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context: WordPress site broke after updating WooCommerce from 8.6 to 8.7.
Error: "Fatal error: Call to undefined function wc_get_order() in /wp-content/plugins/custom-checkout/checkout.php on line 47"
Question: What's causing this and what's the fastest fix?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response usually identifies the root cause (a deprecated function, a compatibility break) and suggests the fix. What used to take 20-30 minutes of digging through changelogs now takes 5.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Writing client maintenance reports
&lt;/h2&gt;

&lt;p&gt;Every client gets a monthly report. Writing 8 reports from scratch every month used to take 3+ hours.&lt;/p&gt;

&lt;p&gt;Now I log the key data (what was updated, any issues found, backup status, performance baseline) and paste it into this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write a professional maintenance report for a WordPress site. This month:
- Plugins updated: [list]
- Core updated: yes/no, from X to Y
- Issues found: [describe or "none"]
- Backup location: [where]
- Performance score: [before] -&amp;gt; [after]
- Recommendations: [list or "none"]
Tone: professional, non-technical. Client is a [type of business]. Keep under 250 words.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI writes a clean, professional report. I review it, adjust anything client-specific, send. 8 reports in 45 minutes instead of 3 hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Responding to client emergencies
&lt;/h2&gt;

&lt;p&gt;"My site is down" emails arrive at the worst times. The client is panicking. You need to respond fast, sound calm, and set expectations -- before you've even diagnosed the problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight email"&gt;&lt;code&gt;&lt;span class="nt"&gt;Write a first-response email to a client whose WordPress site is down. I've just received their message and haven't diagnosed the issue yet. The response should&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="na"&gt; acknowledge the issue, tell them I'm on it, give a realistic first update window (30-60 min), and avoid promising things I don't know yet. Business type: [e-commerce / service business / blog]. Tone: calm, professional, urgent without causing more panic.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send that in under 2 minutes. Then diagnose. The client feels handled while you work.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Writing service agreements and scope clarifications
&lt;/h2&gt;

&lt;p&gt;When a client asks for something outside the original scope ("can you just add a contact form?"), I need to respond in a way that's firm without being rude.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight email"&gt;&lt;code&gt;&lt;span class="nt"&gt;A maintenance client is asking me to add a contact form to their site. This wasn't in our original agreement. Write a short email that&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="nt"&gt;1. Acknowledges their request
2. Explains this is outside our current maintenance scope
3. Offers to do it as a separate project with a quick quote
4. Keeps the tone friendly and professional
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This used to take me 10-15 minutes of careful writing. Now it's 2 minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Researching hosting issues
&lt;/h2&gt;

&lt;p&gt;When something is wrong at the hosting level (slow server response, caching issues, PHP version incompatibilities), I describe the situation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My client's WordPress site on SiteGround shared hosting started returning 504 Gateway Timeout errors at random intervals. PHP version is 8.1. Site uses WooCommerce, LiteSpeed Cache, and Elementor. No recent changes. What are the most likely causes and how do I diagnose each one?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response gives me a structured diagnostic path. Instead of starting with the most complicated possibility, I work through the most common causes first. Saves time, looks professional to the client.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Generating WP-CLI commands I can't remember
&lt;/h2&gt;

&lt;p&gt;I use WP-CLI constantly, but I can't memorize every flag. Instead of reading documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Give me the WP-CLI &lt;span class="nb"&gt;command &lt;/span&gt;to: &lt;span class="nb"&gt;export &lt;/span&gt;the database from /var/www/client, name the file with today&lt;span class="s1"&gt;'s date, and verify the export file exists and isn'&lt;/span&gt;t empty.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three seconds. Done.&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest assessment
&lt;/h2&gt;

&lt;p&gt;AI doesn't maintain WordPress sites. I still need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actually run the updates&lt;/li&gt;
&lt;li&gt;Verify the site still works&lt;/li&gt;
&lt;li&gt;Make judgment calls about risky changes&lt;/li&gt;
&lt;li&gt;Manage the client relationship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it handles the writing, the communication, and the research that surrounded maintenance work. That's about 30-40% of the total time.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I use
&lt;/h2&gt;

&lt;p&gt;For the AI prompts I use weekly (not just for WordPress -- full freelance toolkit): &lt;a href="https://devautomation.gumroad.com/l/plucai" rel="noopener noreferrer"&gt;AI Prompt Pack for IT Freelancers&lt;/a&gt; -- 120 prompts, $12 USD, tested on Claude/ChatGPT/Gemini.&lt;/p&gt;

&lt;p&gt;For the WordPress automation scripts that run the actual maintenance: &lt;a href="https://devautomation.gumroad.com/l/yicgwp" rel="noopener noreferrer"&gt;WordPress Agency Automation Bundle&lt;/a&gt; -- Bash + PowerShell scripts, monthly report generator.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts I actually use as a tech freelancer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5"&gt;WordPress plugin conflicts: diagnose and fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/how-to-price-wordpress-maintenance-retainers-the-3-tier-model-that-actually-works-2ndb"&gt;How to price WordPress maintenance retainers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Which part of client work do you use AI for? Drop it in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>wordpress</category>
      <category>freelance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>15 AI prompts I actually use as a tech freelancer (with the uncomfortable ones included)</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 05:33:05 +0000</pubDate>
      <link>https://forem.com/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc</link>
      <guid>https://forem.com/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc</guid>
      <description>&lt;p&gt;I've been freelancing in tech for years. These are the prompts that actually save me time -- not the generic "write me an email" stuff, but specific, tested prompts for real freelance situations.&lt;/p&gt;

&lt;p&gt;I'll share 15 free ones here. The full pack has 120, organized by use case.&lt;/p&gt;




&lt;h2&gt;
  
  
  Client communication
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing a scope clarification without sounding difficult:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I need to write a professional email to a client who is requesting [scope change] which wasn't in our original agreement. I want to explain why this affects the timeline/cost without sounding defensive. Our original scope was: [X]. What they're asking for now: [Y]. Write a short, direct email that opens the door to a conversation rather than closing it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Following up on an unpaid invoice (firm but professional):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write a follow-up email for an invoice that is [X days] overdue. The client has been unresponsive. Tone: firm but professional. Don't apologize. Make it easy for them to pay by [payment method]. Amount: [X]. Invoice number: [Y]. This is the [first/second/third] follow-up.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Declining a project without burning the bridge:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I need to decline a project from [type of client] because [real reason: budget too low / not my specialty / timeline unrealistic]. Write a short, warm email that declines clearly but leaves the door open for future work. Don't be vague. Don't offer a referral unless I say so.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Project management
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Turning vague client feedback into actionable tasks:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A client sent this feedback: "[paste feedback]". Extract specific, actionable tasks from it. Group by: design changes / content changes / functionality changes / unclear (needs follow-up question). For anything unclear, write the follow-up question I should ask.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Writing a project status update that doesn't sound like filler:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write a weekly status update for a [type of project] project. Current status: [X% done]. Completed this week: [list]. Next week: [list]. Blockers: [list or none]. The client is [technical/non-technical]. Keep it under 150 words. No fluff.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Creating a meeting agenda that actually gets things decided:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a 30-minute meeting agenda for [topic]. We need to make decisions on: [decision 1], [decision 2]. Background context: [brief context]. Format: time blocks with clear decision/outcome for each item. Include 5 min for questions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Technical writing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing a README that developers will actually read:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Write a README for [project/tool/script]. It does: [what it does]. The audience: [developers / non-technical users]. Required sections: what it does, prerequisites, installation, usage with example, common issues. Tone: practical, no marketing language.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explaining a technical decision to a non-technical client:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I need to explain to a non-technical client why I chose [technical decision] over [alternative]. The real reasons: [technical reasons]. Translate this into plain language. Use an analogy if it helps. Max 3 sentences. No jargon.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sales and proposals
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing a project proposal introduction:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write the opening paragraph of a project proposal for [type of project] for [type of client]. My key differentiator: [what makes me different]. The client's main concern is: [timeline / budget / quality / reliability]. Don't start with "I". Lead with their situation, not my credentials.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Responding to a request that's underbudget:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A potential client has a budget of [X] for a project that realistically costs [Y]. Write a response that: acknowledges their budget without dismissing it, explains what [X] could actually buy, opens the door to a conversation about scope or phasing. Don't be condescending.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Automation and productivity
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing a bash/PowerShell script comment block:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;professional&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;paste&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt; &lt;span class="n"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Format&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;PowerShell&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt; &lt;span class="n"&gt;Keep&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;concise&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;developers&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Turning a messy process into a checklist:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I have this process that I do manually: [describe the process]. Turn it into a numbered checklist that someone else could follow without asking me questions. Identify any steps where decisions need to be made and add decision criteria.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The prompts I use most
&lt;/h2&gt;

&lt;p&gt;The ones I reach for every week:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The unpaid invoice follow-up (always uncomfortable, this makes it less so)&lt;/li&gt;
&lt;li&gt;Vague feedback -&amp;gt; actionable tasks (saves 30 min of confusion on every revision round)&lt;/li&gt;
&lt;li&gt;Technical decision explanation (clients respond better when they understand the why)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The full pack
&lt;/h2&gt;

&lt;p&gt;These 15 are from a pack of 120 prompts I use in my freelance work, organized into categories: client communication, project management, technical writing, proposals, invoicing, hiring, and automation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devautomation.gumroad.com/l/plucai" rel="noopener noreferrer"&gt;AI Prompt Pack for IT Freelancers -- 120 prompts&lt;/a&gt; --  USD.&lt;/p&gt;

&lt;p&gt;All prompts are in Polish and English. Tested on Claude, ChatGPT, and Gemini.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/how-to-price-wordpress-maintenance-retainers-the-3-tier-model-that-actually-works-2ndb"&gt;How to price WordPress maintenance retainers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-site-down-the-15-minute-emergency-response-checklist-51pj"&gt;WordPress site down: 15-minute emergency checklist&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Full toolkit: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What prompt do you find yourself rewriting from scratch every time? Drop it in the comments -- I'll share what I use.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/how-i-use-ai-to-run-a-wordpress-maintenance-business-6-concrete-examples-58b"&gt;How I use AI to run a WordPress maintenance business&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>freelance</category>
      <category>career</category>
    </item>
    <item>
      <title>WordPress site down: the 15-minute emergency response checklist</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 05:09:04 +0000</pubDate>
      <link>https://forem.com/devautomation/wordpress-site-down-the-15-minute-emergency-response-checklist-51pj</link>
      <guid>https://forem.com/devautomation/wordpress-site-down-the-15-minute-emergency-response-checklist-51pj</guid>
      <description>&lt;p&gt;Your client's site is down. It's 9 PM on a Friday.&lt;/p&gt;

&lt;p&gt;What you do in the next 15 minutes determines whether this is a 30-minute fix or a 3-hour emergency. Here is the exact response process.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Confirm the outage (2 min)
&lt;/h2&gt;

&lt;p&gt;First, verify it's actually down -- not just down for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Quick check from command line&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}"&lt;/span&gt; https://clientsite.com

&lt;span class="c"&gt;# External check tools&lt;/span&gt;
&lt;span class="c"&gt;# downforeveryoneorjustme.com&lt;/span&gt;
&lt;span class="c"&gt;# isitdownrightnow.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also check from your phone (different network). A site "down" only for you is a local network or DNS cache issue -- very different problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Identify the scope (3 min)
&lt;/h2&gt;

&lt;p&gt;While the site is loading (or failing to load), answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it the entire site, or just specific pages?&lt;/li&gt;
&lt;li&gt;Is it a white screen, a 500 error, a 503, or something else?&lt;/li&gt;
&lt;li&gt;Is the admin dashboard accessible? (try /wp-admin)&lt;/li&gt;
&lt;li&gt;When did it go down? (Check uptime monitor logs)&lt;/li&gt;
&lt;li&gt;What changed recently? (Check your maintenance log)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different symptoms point to different causes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Most likely cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;500 Internal Server Error&lt;/td&gt;
&lt;td&gt;PHP fatal error, .htaccess issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;503 Service Unavailable&lt;/td&gt;
&lt;td&gt;Server overloaded or maintenance mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;White screen (no error)&lt;/td&gt;
&lt;td&gt;PHP memory limit, plugin conflict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Error establishing database connection"&lt;/td&gt;
&lt;td&gt;Database down or credentials wrong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site loads, checkout broken&lt;/td&gt;
&lt;td&gt;Payment gateway issue, JS conflict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site redirects to spam domain&lt;/td&gt;
&lt;td&gt;Malware infection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Step 3: Check server resources (2 min)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Is the server responding at all?&lt;/span&gt;
ping clientserver.com

&lt;span class="c"&gt;# Check disk space (full disk = 500 errors)&lt;/span&gt;
&lt;span class="nb"&gt;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; /var/www/

&lt;span class="c"&gt;# Check memory and load&lt;/span&gt;
free &lt;span class="nt"&gt;-m&lt;/span&gt;
&lt;span class="nb"&gt;uptime&lt;/span&gt;

&lt;span class="c"&gt;# Check PHP error log&lt;/span&gt;
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt; /var/log/apache2/error.log | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y-%m-%d&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A full disk or high load average (above 4.0 on a shared server) points to server-side issues -- contact hosting support immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Check the WordPress error log (2 min)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-100&lt;/span&gt; /var/www/clientsite/wp-content/debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No debug.log? Enable it temporarily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In wp-config.php&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_DEBUG'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_DEBUG_LOG'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_DEBUG_DISPLAY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A PHP fatal error in the log names the exact file and line causing the crash. That is your fix target.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: The recovery actions by error type
&lt;/h2&gt;

&lt;h3&gt;
  
  
  500 / White screen -- likely plugin or .htaccess
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Rename .htaccess to test (regenerates automatically)&lt;/span&gt;
&lt;span class="nb"&gt;mv&lt;/span&gt; /var/www/site/.htaccess /var/www/site/.htaccess.bak

&lt;span class="c"&gt;# Deactivate all plugins via database (when you can't access wp-admin)&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin deactivate &lt;span class="nt"&gt;--all&lt;/span&gt;

&lt;span class="c"&gt;# Reactivate one by one to find culprit&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin activate plugin-slug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  "Error establishing database connection"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Verify database credentials in wp-config.php match actual DB&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db check

&lt;span class="c"&gt;# Try connecting manually&lt;/span&gt;
mysql &lt;span class="nt"&gt;-u&lt;/span&gt; DB_USER &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; DB_HOST DB_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If credentials are correct but connection fails: contact hosting support. Database server may be down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Malware / redirect to spam domain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check for recently modified PHP files (last 24h)&lt;/span&gt;
find /var/www/site &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.php"&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-ls&lt;/span&gt;

&lt;span class="c"&gt;# Check core file integrity&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core verify-checksums

&lt;span class="c"&gt;# Check for injected code in index.php&lt;/span&gt;
&lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-30&lt;/span&gt; /var/www/site/index.php
&lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-30&lt;/span&gt; /var/www/site/wp-config.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you find modified core files: restore from backup immediately. Do not try to clean -- the infection is likely in multiple places.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Restore from backup if needed
&lt;/h2&gt;

&lt;p&gt;If you can not identify and fix the cause within 20 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Restore database&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db import last_known_good_backup.sql
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; cache flush

&lt;span class="c"&gt;# Restore files (if file corruption suspected)&lt;/span&gt;
&lt;span class="c"&gt;# Unzip backup archive over current files&lt;/span&gt;
unzip &lt;span class="nt"&gt;-o&lt;/span&gt; wp-content-backup.zip &lt;span class="nt"&gt;-d&lt;/span&gt; /var/www/site/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why backups exist. A verified, recent, off-server backup turns a potential disaster into a 5-minute restore.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Client communication
&lt;/h2&gt;

&lt;p&gt;Contact the client as soon as you confirm the outage -- before you have a fix.&lt;/p&gt;

&lt;p&gt;Template:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Hi [Name], I've been alerted that [site] is currently down. I'm investigating now. I'll update you within 30 minutes with either a fix or a timeline. No action needed from you."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then update when resolved:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The site is back up. The cause was [brief description]. I've [what I fixed]. I'll include full details in this month's maintenance report."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Never disappear and then reappear with a fix. Clients hate uncertainty more than outages.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 15-minute emergency flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0-2 min:   Confirm outage (external tool + different network)
2-5 min:   Identify symptom type
5-7 min:   Check server resources + error logs
7-10 min:  Apply fix based on symptom
10-12 min: Verify site is up, test key pages
12-15 min: Contact client with status update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If not resolved by minute 15: contact hosting support, set maintenance mode, restore from backup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prevention: the monitoring setup that catches outages before clients call
&lt;/h2&gt;

&lt;p&gt;I use a simple uptime monitor that pings every 5 minutes and sends an SMS/email alert if the site returns anything other than 200.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# wp-uptime-monitor.ps1 -- runs via Task Scheduler every 5 min&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$sites&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;Get-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"clients.json"&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;ConvertFrom-Json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$site&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sites&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="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$code&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Invoke-WebRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UseBasicParsing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StatusCode&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-ne&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&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="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Send-MailMessage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"you@email.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Subject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DOWN: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Status: &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &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="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script is included in the automation bundle -- set it up once, it watches all client sites automatically.&lt;/p&gt;




&lt;p&gt;The automation bundle includes the uptime monitor script (PowerShell + Bash), pre-update backup scripts, and post-update health checks:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/yicgwp" rel="noopener noreferrer"&gt;WordPress Agency Automation Bundle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free monthly checklist with emergency section:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/vaiawy" rel="noopener noreferrer"&gt;WordPress Monthly Maintenance Checklist&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5"&gt;WordPress plugin conflicts: diagnose and fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-backups-the-strategy-that-actually-protects-client-sites-most-setups-fail-this-test-8fi"&gt;WordPress backups: the strategy that actually works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-security-the-10-minute-monthly-checklist-that-catches-real-problems-1n4n"&gt;WordPress security: 10-minute monthly checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/how-i-use-wp-cli-to-cut-wordpress-maintenance-time-from-6-hours-to-20-minutes-3a6j"&gt;WP-CLI: cut maintenance to 20 minutes&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers (the uncomfortable ones included)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All paid tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What is the most common cause of emergency calls you get from WordPress clients?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/how-i-use-ai-to-run-a-wordpress-maintenance-business-6-concrete-examples-58b"&gt;How I use AI to run a WordPress maintenance business&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>WordPress speed optimization: the 6 fixes that actually move the needle on client sites</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 05:00:14 +0000</pubDate>
      <link>https://forem.com/devautomation/wordpress-speed-optimization-the-6-fixes-that-actually-move-the-needle-on-client-sites-4cb2</link>
      <guid>https://forem.com/devautomation/wordpress-speed-optimization-the-6-fixes-that-actually-move-the-needle-on-client-sites-4cb2</guid>
      <description>&lt;p&gt;Before WP-CLI, WordPress maintenance across 8 client sites meant a half-day of clicking through dashboards. Now it takes 20 minutes for all sites combined.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why speed matters more than ever in 2025
&lt;/h2&gt;

&lt;p&gt;Google confirmed Core Web Vitals are a ranking signal. A site scoring below 70 on mobile PageSpeed loses organic traffic. A 1-second delay in page load time reduces conversions by 7%.&lt;/p&gt;

&lt;p&gt;For your clients: slow site = lost leads = unhappy client = cancelled maintenance contract.&lt;/p&gt;

&lt;p&gt;Here are the highest-impact optimizations, in order.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 1: Switch to PHP 8.2+ (biggest single win)
&lt;/h2&gt;

&lt;p&gt;PHP 8.2 is 2-3x faster than PHP 7.4 for WordPress workloads. Most shared hosting still defaults to 7.4.&lt;/p&gt;

&lt;p&gt;Check current version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s1"&gt;'echo PHP_VERSION;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change in hosting panel: Hosting -&amp;gt; PHP Version -&amp;gt; 8.2 or 8.3.&lt;/p&gt;

&lt;p&gt;Zero cost, zero plugins, zero configuration. Just flip the version. Average TTFB improvement: 200-400ms on typical sites.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 2: Page caching (essential on any site)
&lt;/h2&gt;

&lt;p&gt;Without caching: every visit runs PHP + database queries. 500ms-3s per request.&lt;br&gt;
With caching: pre-built HTML served from disk. 20-80ms per request.&lt;/p&gt;

&lt;p&gt;Best options by hosting type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LiteSpeed servers&lt;/strong&gt; (many CyberFolks, SiteGround): LiteSpeed Cache plugin. Free, best performance of any WP cache plugin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apache/nginx shared&lt;/strong&gt;: W3 Total Cache or WP Super Cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managed WP hosts&lt;/strong&gt; (Kinsta, WP Engine): server-level cache built in -- make sure it's enabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check if caching is active:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://clientsite.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"x-cache&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;cf-cache&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;cache-control&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;litespeed"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Fix 3: Image optimization (usually the biggest payload)
&lt;/h2&gt;

&lt;p&gt;Most WordPress sites I audit have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hero images at 2-4MB (should be under 300KB)&lt;/li&gt;
&lt;li&gt;JPEGs instead of WebP (30-50% larger)&lt;/li&gt;
&lt;li&gt;Images served at 3000px displayed at 800px&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Find oversized images via browser console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;waste&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;naturalWidth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;naturalHeight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; 
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;waste&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Oversized: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; -- &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;waste&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;x too large`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fix with ShortPixel (free tier: 100 images/month) or Imagify. Enable WebP conversion. Set lazy loading on below-fold images. Don't lazy-load above-fold images (hurts LCP).&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 4: Database cleanup
&lt;/h2&gt;

&lt;p&gt;Slow admin panel and slow queries often come from database bloat.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Autoloaded data check (should be under 1MB)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;option_value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;mb&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;wp_options&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;autoload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'yes'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Post revisions (often thousands)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;wp_posts&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;post_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'revision'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quick wins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// wp-config.php -- limit revisions going forward&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_POST_REVISIONS'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use WP-Optimize to clean existing transients, spam comments, orphaned meta.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix 5: Remove render-blocking resources
&lt;/h2&gt;

&lt;p&gt;PageSpeed Insights -&amp;gt; "Eliminate render-blocking resources" shows exactly which files are blocking the first paint.&lt;/p&gt;

&lt;p&gt;Common offenders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contact form plugin loading scripts on every page (only needed on contact page)&lt;/li&gt;
&lt;li&gt;Slider plugin loading JS/CSS globally&lt;/li&gt;
&lt;li&gt;Google Fonts loaded from external CDN (adds DNS lookup)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Asset CleanUp plugin&lt;/strong&gt;: disable specific scripts/styles on specific pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local fonts&lt;/strong&gt;: use OMGF plugin to host Google Fonts locally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;font-display: swap&lt;/strong&gt;: prevents invisible text during font load&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Fix 6: CDN for static assets
&lt;/h2&gt;

&lt;p&gt;A CDN serves images, CSS, and JS from a server geographically close to the visitor.&lt;/p&gt;

&lt;p&gt;Cheapest option: &lt;strong&gt;Cloudflare free plan&lt;/strong&gt;. Point DNS to Cloudflare, enable "Speed" features, done. Typical improvement: 20-40% faster load times globally.&lt;/p&gt;

&lt;p&gt;For clients already on Cloudflare: make sure "Auto Minify" is on for HTML/CSS/JS and "Rocket Loader" is enabled for JS.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 30-minute audit flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0-5min:   Baseline (PageSpeed + GTmetrix, 3 runs each, document scores)
5-10min:  PHP version check + TTFB measurement
10-15min: Cache headers check + caching plugin status
15-20min: GTmetrix waterfall -- find largest images
20-25min: PageSpeed "Opportunities" -- render-blocking, unused CSS/JS
25-30min: Database autoload check + revisions count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: prioritized fix list with estimated impact for each item.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I include in client reports
&lt;/h2&gt;

&lt;p&gt;After every performance audit, I send:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Before/after PageSpeed scores (mobile + desktop)&lt;/li&gt;
&lt;li&gt;Issues found, sorted: Critical / Important / Nice-to-have&lt;/li&gt;
&lt;li&gt;What was fixed in this session&lt;/li&gt;
&lt;li&gt;What requires additional work (and estimated time)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Clients see concrete improvement. "Your mobile score went from 42 to 71" is a tangible result.&lt;/p&gt;

&lt;p&gt;The full audit kit with report template: &lt;a href="https://devautomation.gumroad.com/l/oikwcr" rel="noopener noreferrer"&gt;WordPress Speed &amp;amp; Performance Audit Kit&lt;/a&gt; -- use &lt;strong&gt;SPEED&lt;/strong&gt; for a discount.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-site-running-slow-heres-the-exact-checklist-i-use-to-diagnose-any-site-in-30-minutes-1mo2"&gt;WordPress site running slow? 30-minute diagnosis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/how-i-use-wp-cli-to-cut-wordpress-maintenance-time-from-6-hours-to-20-minutes-3a6j"&gt;How I use WP-CLI to cut maintenance time to 20 minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5"&gt;WordPress plugin conflicts: diagnose and fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-security-the-10-minute-monthly-checklist-that-catches-real-problems-1n4n"&gt;WordPress security: 10-minute monthly checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers (the uncomfortable ones included)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All paid tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What's the performance issue you see most often on client sites -- images, caching, or something else?&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>WordPress client onboarding: the exact process I use to start every maintenance contract right</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 04:51:42 +0000</pubDate>
      <link>https://forem.com/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of</link>
      <guid>https://forem.com/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of</guid>
      <description>&lt;p&gt;The first 30 days of a maintenance contract determines whether a client stays for 2 months or 2 years.&lt;/p&gt;

&lt;p&gt;Most freelancers skip onboarding entirely. They say "I'll take care of updates" and start updating. Then a miscommunication happens -- client didn't know backups weren't included, or they expected same-day responses, or they thought you were responsible for content changes that weren't in scope.&lt;/p&gt;

&lt;p&gt;Here's the onboarding process I use for every new maintenance client. It takes 2 hours total and prevents 80% of future issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: The access collection call (20 min)
&lt;/h2&gt;

&lt;p&gt;Before touching the site, get everything you need to actually manage it. Schedule a 20-minute call or send a structured form:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Required:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WordPress admin credentials (or application password)&lt;/li&gt;
&lt;li&gt;Hosting control panel access&lt;/li&gt;
&lt;li&gt;FTP/SFTP credentials&lt;/li&gt;
&lt;li&gt;DNS panel access (Cloudflare, domain registrar)&lt;/li&gt;
&lt;li&gt;Backup destination access (Google Drive folder, S3 bucket)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Nice to have:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current backup plugin and schedule&lt;/li&gt;
&lt;li&gt;Staging environment URL&lt;/li&gt;
&lt;li&gt;Contact at hosting provider&lt;/li&gt;
&lt;li&gt;Payment gateway dashboard access (for WooCommerce sites)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use a simple Google Form for this. Clients fill it out before the first meeting. Nothing delays onboarding more than waiting for credentials one at a time over email.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: The site audit (30-40 min)
&lt;/h2&gt;

&lt;p&gt;Before agreeing to maintain a site, know what you're agreeing to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plugins:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin list &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;name,version,status,update &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for: abandoned plugins (last update 12+ months ago), duplicate functionality, security plugins, backup plugins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core version:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core version
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core check-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Users:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; user list &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;administrator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;File permissions:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"%a"&lt;/span&gt; wp-config.php
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.php"&lt;/span&gt; &lt;span class="nt"&gt;-perm&lt;/span&gt; /o+w 2&amp;gt;/dev/null | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Current backup situation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is any backup plugin installed?&lt;/li&gt;
&lt;li&gt;Where is it backing up?&lt;/li&gt;
&lt;li&gt;When was the last successful backup?&lt;/li&gt;
&lt;li&gt;Is the backup destination off-server?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance baseline:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run PageSpeed Insights once before you start&lt;/li&gt;
&lt;li&gt;Document the score&lt;/li&gt;
&lt;li&gt;This is your before/after comparison in the first monthly report&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Document everything. Send the client a "Site Audit Summary" after this step. It shows you know what you're doing and sets realistic expectations about the site's current state.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: The service agreement (10 min to sign)
&lt;/h2&gt;

&lt;p&gt;Before doing any work: sign a service agreement. This isn't bureaucracy -- it's what defines the relationship.&lt;/p&gt;

&lt;p&gt;Key sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope&lt;/strong&gt; -- exactly what is and isn't included (updates, backups, content changes, bug fixes, emergency response)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response time&lt;/strong&gt; -- what the client can expect and when&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup policy&lt;/strong&gt; -- where backups go, how long they're retained, whether you're responsible for restores&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payment terms&lt;/strong&gt; -- monthly invoice, due date, late fees&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancellation&lt;/strong&gt; -- notice period (30 days minimum), what happens to their access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Liability&lt;/strong&gt; -- what you're and aren't responsible for if something goes wrong during an update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without a signed agreement, every conversation about scope is a negotiation. With one, "is that included?" has a clear answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: First maintenance run (and documenting it)
&lt;/h2&gt;

&lt;p&gt;Do the first maintenance run manually, step by step, and document everything:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take a full backup (files + database)&lt;/li&gt;
&lt;li&gt;Run updates (core, plugins, themes)&lt;/li&gt;
&lt;li&gt;Verify the site still works&lt;/li&gt;
&lt;li&gt;Fix anything that broke&lt;/li&gt;
&lt;li&gt;Check security issues from the audit and remediate (rename admin user, fix permissions, disable debug.log)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Send the client a detailed first report:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current plugin versions (before/after)&lt;/li&gt;
&lt;li&gt;Security issues found and fixed&lt;/li&gt;
&lt;li&gt;Backup location&lt;/li&gt;
&lt;li&gt;Next scheduled maintenance date&lt;/li&gt;
&lt;li&gt;Any recommendations (plugin they should remove, PHP version to upgrade, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first report is the most important one. It sets the expectation for every future report and demonstrates value immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Communication setup
&lt;/h2&gt;

&lt;p&gt;Two things to establish in week 1:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regular reporting:&lt;/strong&gt; Monthly report sent on the same date every month. Template + scheduled send. The client knows when to expect it without asking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Escalation path:&lt;/strong&gt; What happens in an emergency? Who calls whom? What's the response time? Document this explicitly. "Site down" is different from "plugin broke the checkout" which is different from "client wants a design change."&lt;/p&gt;

&lt;p&gt;I use a simple doc shared with the client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EMERGENCY (site down / payment broken): WhatsApp/call within 2 hours
URGENT (feature broken, form not sending): Email + reply within 24 hours
STANDARD (content change, question): Next monthly maintenance window
BILLING: Invoice sent on [date] monthly, due net 14
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The onboarding checklist
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Access collection form sent and completed
[ ] All credentials received and stored securely
[ ] Site audit completed and documented
[ ] Audit summary sent to client
[ ] Service agreement signed
[ ] Payment method set up
[ ] First maintenance run completed
[ ] First report sent
[ ] Backup destination confirmed and tested
[ ] Communication protocol documented
[ ] Next maintenance date scheduled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes 2 hours spread over the first week. After that, the client relationship runs on autopilot.&lt;/p&gt;




&lt;h2&gt;
  
  
  What happens when you skip onboarding
&lt;/h2&gt;

&lt;p&gt;I've inherited clients from freelancers who skipped onboarding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No credentials documented anywhere (had to request everything from scratch)&lt;/li&gt;
&lt;li&gt;No backup for the 18 months the previous developer worked on it&lt;/li&gt;
&lt;li&gt;No service agreement (client thought bug fixes were included, they weren't)&lt;/li&gt;
&lt;li&gt;Client called/emailed whenever anything looked slightly different on their site&lt;/li&gt;
&lt;li&gt;No baseline performance data (no way to show improvement)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of those problems adds hours of work and strains the relationship before it's even established.&lt;/p&gt;

&lt;p&gt;Two hours upfront saves ten hours later.&lt;/p&gt;




&lt;p&gt;The service agreement template, onboarding checklist, monthly report template, and first-audit template are all in:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/wrmjsy" rel="noopener noreferrer"&gt;WordPress Agency Starter Kit&lt;/a&gt; -- use &lt;strong&gt;DEVTO&lt;/strong&gt; for a discount.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/how-i-land-wordpress-maintenance-clients-with-cold-email-real-sequences-real-results-5495"&gt;How I land WP clients with cold email&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/how-to-price-wordpress-maintenance-retainers-the-3-tier-model-that-actually-works-2ndb"&gt;How to price WordPress maintenance retainers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/the-wordpress-maintenance-business-real-numbers-pricing-math-and-what-most-freelancers-get-wrong-2n43"&gt;WordPress maintenance business: real numbers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-security-the-10-minute-monthly-checklist-that-catches-real-problems-1n4n"&gt;WordPress security: 10-minute monthly checklist&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-speed-optimization-the-6-fixes-that-actually-move-the-needle-on-client-sites-4cb2"&gt;WordPress speed optimization: 6 fixes that actually work&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers (the uncomfortable ones included)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All paid tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What's the one thing you wish you'd done differently when onboarding your first maintenance client?&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>freelance</category>
      <category>webdev</category>
      <category>business</category>
    </item>
    <item>
      <title>How I use WP-CLI to cut WordPress maintenance time from 6 hours to 20 minutes</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 04:45:30 +0000</pubDate>
      <link>https://forem.com/devautomation/how-i-use-wp-cli-to-cut-wordpress-maintenance-time-from-6-hours-to-20-minutes-3a6j</link>
      <guid>https://forem.com/devautomation/how-i-use-wp-cli-to-cut-wordpress-maintenance-time-from-6-hours-to-20-minutes-3a6j</guid>
      <description>&lt;p&gt;Before WP-CLI, WordPress maintenance meant: browser open, log in to each site, click Update All, check if anything broke, log out, repeat. With 8 clients that was a half-day of clicking.&lt;/p&gt;

&lt;p&gt;Now it's one command per site, or one command for all sites. Here's exactly how.&lt;/p&gt;




&lt;h2&gt;
  
  
  What WP-CLI actually is
&lt;/h2&gt;

&lt;p&gt;WP-CLI is the command-line interface for WordPress. Everything you can do in the WordPress dashboard, you can do faster from the terminal -- plus things the dashboard can't do at all.&lt;/p&gt;

&lt;p&gt;Install once on your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-O&lt;/span&gt; https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x wp-cli.phar
&lt;span class="nb"&gt;mv &lt;/span&gt;wp-cli.phar /usr/local/bin/wp
wp &lt;span class="nt"&gt;--info&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No browser. No clicking. Full WordPress control from SSH.&lt;/p&gt;




&lt;h2&gt;
  
  
  The basic maintenance commands
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Check what needs updating:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core check-update
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin list &lt;span class="nt"&gt;--update&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;available &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;table
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; theme list &lt;span class="nt"&gt;--update&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;available &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;table
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run all updates:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core update
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin update &lt;span class="nt"&gt;--all&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; theme update &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify integrity after update:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core verify-checksums
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin verify-checksums &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The backup-first pattern
&lt;/h2&gt;

&lt;p&gt;Never update without a backup. Two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Database backup&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db &lt;span class="nb"&gt;export &lt;/span&gt;backup_&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d_%H%M&lt;span class="si"&gt;)&lt;/span&gt;.sql

&lt;span class="c"&gt;# Check backup file exists and isn't empty&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; backup_&lt;span class="k"&gt;*&lt;/span&gt;.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the update breaks something: restore from the backup you just took, investigate what went wrong, try again.&lt;/p&gt;




&lt;h2&gt;
  
  
  The multi-site loop
&lt;/h2&gt;

&lt;p&gt;This is where the real time savings happen. Store client configs in a JSON file, loop through them all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# clients.json format:&lt;/span&gt;
&lt;span class="c"&gt;# [{"name":"client1","path":"/var/www/client1","url":"client1.com"}, ...]&lt;/span&gt;

&lt;span class="nv"&gt;CLIENTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;clients.json&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;ERRORS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CLIENTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'.[]'&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;client&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.name'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.path'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.url'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Processing: &lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt; ==="&lt;/span&gt;

    &lt;span class="c"&gt;# Backup&lt;/span&gt;
    wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db &lt;span class="nb"&gt;export&lt;/span&gt; /backups/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;_&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d&lt;span class="si"&gt;)&lt;/span&gt;.sql 2&amp;gt;&amp;amp;1

    &lt;span class="c"&gt;# Update&lt;/span&gt;
    wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin update &lt;span class="nt"&gt;--all&lt;/span&gt; 2&amp;gt;&amp;amp;1
    wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core update 2&amp;gt;&amp;amp;1

    &lt;span class="c"&gt;# Verify site responds&lt;/span&gt;
    &lt;span class="nv"&gt;STATUS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}"&lt;/span&gt; &lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STATUS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WARNING: &lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt; returned &lt;/span&gt;&lt;span class="nv"&gt;$STATUS&lt;/span&gt;&lt;span class="s2"&gt; after update"&lt;/span&gt;
        &lt;span class="nv"&gt;ERRORS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;ERRORS+1&lt;span class="k"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;fi

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Done: &lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt; ==="&lt;/span&gt;
&lt;span class="k"&gt;done

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Completed. Errors: &lt;/span&gt;&lt;span class="nv"&gt;$ERRORS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this script once. Every client gets backed up and updated. Any site that stops responding after the update triggers a warning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security checks in one command
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check for the common security issues&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; user list &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;administrator &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ID,user_login,user_email
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core verify-checksums
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; doctor check &lt;span class="nt"&gt;--all&lt;/span&gt;

&lt;span class="c"&gt;# Check file permissions&lt;/span&gt;
&lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"%a %n"&lt;/span&gt; /var/www/client/wp-config.php
find /var/www/client &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.php"&lt;/span&gt; &lt;span class="nt"&gt;-perm&lt;/span&gt; /o+w 2&amp;gt;/dev/null | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;doctor check --all&lt;/code&gt; command requires the WP CLI doctor package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp package &lt;span class="nb"&gt;install &lt;/span&gt;wp-cli/doctor-command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It checks PHP errors, inactive plugins, option table bloat, cron job health, and more. One command gives you a full site health report.&lt;/p&gt;




&lt;h2&gt;
  
  
  Database maintenance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check autoloaded data size (should be under 1MB)&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db query &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"SELECT SUM(LENGTH(option_value))/1024/1024 as mb FROM wp_options WHERE autoload = 'yes';"&lt;/span&gt;

&lt;span class="c"&gt;# Count post revisions&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db query &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"SELECT COUNT(*) FROM wp_posts WHERE post_type = 'revision';"&lt;/span&gt;

&lt;span class="c"&gt;# Optimize database tables&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db optimize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On sites with 2+ years of content, cleaning up revisions and transients can reclaim hundreds of MB and noticeably speed up the admin dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cache management
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Flush all caches&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; cache flush
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; rewrite flush

&lt;span class="c"&gt;# LiteSpeed Cache specific&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; litespeed-purge all

&lt;span class="c"&gt;# W3 Total Cache&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client &lt;span class="nt"&gt;--allow-root&lt;/span&gt; w3-total-cache flush all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always flush caches after updates. A cached version of a broken page is harder to diagnose than a broken page.&lt;/p&gt;




&lt;h2&gt;
  
  
  Generating the client report from WP-CLI output
&lt;/h2&gt;

&lt;p&gt;I pipe WP-CLI output to a log file, then format it into an HTML report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/reports/client1_&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt;

&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== WordPress Maintenance Report: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; ==="&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"--- PLUGIN UPDATES ---"&lt;/span&gt;
  wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client1 &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin update &lt;span class="nt"&gt;--all&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"--- CORE VERSION ---"&lt;/span&gt;
  wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client1 &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core version
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"--- ADMIN USERS ---"&lt;/span&gt;
  wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/www/client1 &lt;span class="nt"&gt;--allow-root&lt;/span&gt; user list &lt;span class="nt"&gt;--role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;administrator &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;user_login,user_email
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"--- BACKUP STATUS ---"&lt;/span&gt;
  &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lh&lt;/span&gt; /backups/client1_&lt;span class="k"&gt;*&lt;/span&gt;.sql | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-3&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;&amp;amp;1

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Report saved: &lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The log file gets converted to a formatted HTML email and sent to the client automatically. They see professional documentation of everything that happened. You spent 20 minutes running scripts; they received a polished report.&lt;/p&gt;




&lt;h2&gt;
  
  
  WP-CLI on Windows (PowerShell)
&lt;/h2&gt;

&lt;p&gt;For Windows servers or if you're running maintenance scripts from Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# WP-CLI works via SSH from PowerShell&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$session&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;New-SSHSession&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ComputerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"clientserver.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Credential&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$cred&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Invoke-SSHCommand&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-SessionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SessionId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wp --path=/var/www/client --allow-root plugin update --all"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use the PowerShell equivalent script that SSH's into each client server and runs the maintenance commands remotely.&lt;/p&gt;




&lt;h2&gt;
  
  
  The time comparison
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Manual (browser-based):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to each WP dashboard: 2 min/site&lt;/li&gt;
&lt;li&gt;Check for updates: 1 min/site&lt;/li&gt;
&lt;li&gt;Run updates: 3-5 min/site (waiting for each plugin)&lt;/li&gt;
&lt;li&gt;Verify site still works: 2 min/site&lt;/li&gt;
&lt;li&gt;Write update notes: 3 min/site&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total: ~11 min/site x 8 sites = ~90 minutes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;WP-CLI automated:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the script: 1 min&lt;/li&gt;
&lt;li&gt;Wait for it to run: 15-20 min (unattended)&lt;/li&gt;
&lt;li&gt;Review the output log: 3 min&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total: ~20-25 minutes for all 8 sites&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script runs while you do other work. You review the output when it's done.&lt;/p&gt;




&lt;p&gt;The full script bundle (Bash for Linux, PowerShell for Windows, clients.json template, HTML report generator):&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/yicgwp" rel="noopener noreferrer"&gt;WordPress Agency Automation Bundle&lt;/a&gt; -- skip the 12 hours of building it yourself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5"&gt;WordPress plugin conflicts: diagnose and fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-staging-environments-the-15-minute-setup-that-prevents-client-emergencies-19pp"&gt;WordPress staging environments: the 15-min setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-security-the-10-minute-monthly-checklist-that-catches-real-problems-1n4n"&gt;WordPress security: 10-minute monthly checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/mainwp-vs-managewp-vs-custom-scripts-how-i-manage-15-wordpress-sites-in-2025-4n67"&gt;MainWP vs ManageWP vs custom scripts&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-speed-optimization-the-6-fixes-that-actually-move-the-needle-on-client-sites-4cb2"&gt;WordPress speed optimization: 6 fixes that actually work&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers (the uncomfortable ones included)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All paid tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What's your most-used WP-CLI command? Drop it in the comments.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>cli</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>WordPress staging environments: the 15-minute setup that prevents client emergencies</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 04:43:29 +0000</pubDate>
      <link>https://forem.com/devautomation/wordpress-staging-environments-the-15-minute-setup-that-prevents-client-emergencies-i5c</link>
      <guid>https://forem.com/devautomation/wordpress-staging-environments-the-15-minute-setup-that-prevents-client-emergencies-i5c</guid>
      <description>&lt;p&gt;Every WordPress emergency I've seen in the last five years had the same root cause: someone tested an update on production.&lt;/p&gt;

&lt;p&gt;A staging environment eliminates this. If it breaks on staging, you fix it on staging. Nothing reaches the client's live site until it's verified. Here's how I set one up in 15 minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why staging isn't optional for client sites
&lt;/h2&gt;

&lt;p&gt;"It worked on my machine" is a joke. "It worked on the live site yesterday" is a client emergency.&lt;/p&gt;

&lt;p&gt;The risks of updating production directly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugin update breaks the theme -- client's site is down during business hours&lt;/li&gt;
&lt;li&gt;WooCommerce update changes checkout behavior -- orders fail, client loses revenue&lt;/li&gt;
&lt;li&gt;PHP version bump reveals a deprecated function -- white screen on every page&lt;/li&gt;
&lt;li&gt;Theme update wipes custom CSS -- site looks wrong until you remember what you changed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A staging environment catches all of these before they matter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option 1: Staging via hosting panel (easiest)
&lt;/h2&gt;

&lt;p&gt;Most quality hosts (SiteGround, Kinsta, WP Engine, Cloudways) have one-click staging built in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SiteGround:&lt;/strong&gt; Site Tools -&amp;gt; WordPress -&amp;gt; Staging -&amp;gt; Create Staging Copy&lt;br&gt;
&lt;strong&gt;Kinsta:&lt;/strong&gt; MyKinsta -&amp;gt; Site -&amp;gt; Environments -&amp;gt; Add Environment&lt;br&gt;
&lt;strong&gt;WP Engine:&lt;/strong&gt; User Portal -&amp;gt; Sites -&amp;gt; Staging -&amp;gt; Copy to Staging&lt;/p&gt;

&lt;p&gt;What this does: creates a full copy of the site (files + database) at a subdomain (usually staging.clientdomain.com or clientdomain.wpengine.com). Changes stay isolated until you push to live.&lt;/p&gt;

&lt;p&gt;After testing updates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test on staging: update plugins, verify site works&lt;/li&gt;
&lt;li&gt;Push to live: one-click merge from staging to production&lt;/li&gt;
&lt;li&gt;Verify on production: check key pages, checkout, contact forms&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Time for the whole flow: 20-30 minutes. Time for a manual plugin update without staging: 5 minutes. Time to fix a broken production site without staging: 2-6 hours.&lt;/p&gt;


&lt;h2&gt;
  
  
  Option 2: Local by Flywheel (free, for local testing)
&lt;/h2&gt;

&lt;p&gt;Local (getlocal.io) runs a full WordPress environment on your machine. Free, works offline, fast.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Download Local from localwp.com
2. Create new site -&amp;gt; WordPress
3. Click "Pull from host" (connects to WP Engine, Kinsta, etc.)
   Or use WP-CLI to import manually
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For clients on shared hosting without staging: this is the fallback. Pull the site locally, test, push changes manually.&lt;/p&gt;

&lt;p&gt;Limitation: you can't test live payment processing locally. Use Option 1 for WooCommerce sites.&lt;/p&gt;




&lt;h2&gt;
  
  
  Option 3: WP-CLI staging on a VPS (most control)
&lt;/h2&gt;

&lt;p&gt;If you have a VPS or the client's server has enough space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;LIVE_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/www/html/production"&lt;/span&gt;
&lt;span class="nv"&gt;STAGING_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/www/html/staging"&lt;/span&gt;
&lt;span class="nv"&gt;STAGING_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"staging.clientdomain.com"&lt;/span&gt;

&lt;span class="c"&gt;# Copy files&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nv"&gt;$LIVE_PATH&lt;/span&gt; &lt;span class="nv"&gt;$STAGING_PATH&lt;/span&gt;

&lt;span class="c"&gt;# Export live database&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$LIVE_PATH&lt;/span&gt; &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db &lt;span class="nb"&gt;export&lt;/span&gt; /tmp/live_backup.sql

&lt;span class="c"&gt;# Import to staging database (must create DB first)&lt;/span&gt;
mysql &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="nt"&gt;-p&lt;/span&gt; staging_db &amp;lt; /tmp/live_backup.sql

&lt;span class="c"&gt;# Update staging URLs in database&lt;/span&gt;
wp &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$STAGING_PATH&lt;/span&gt; &lt;span class="nt"&gt;--allow-root&lt;/span&gt; search-replace &lt;span class="s2"&gt;"clientdomain.com"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STAGING_DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Update wp-config.php for staging database&lt;/span&gt;
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"s/production_db/staging_db/"&lt;/span&gt; &lt;span class="nv"&gt;$STAGING_PATH&lt;/span&gt;/wp-config.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then set up the staging subdomain in nginx/Apache. The staging site is fully isolated.&lt;/p&gt;




&lt;h2&gt;
  
  
  The staging workflow for monthly maintenance
&lt;/h2&gt;

&lt;p&gt;This is how I handle updates for every client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Create/refresh staging copy (hosting panel, 2 min)
2. Run all updates on staging (WP-CLI or dashboard)
3. Quick verification: homepage, key pages, checkout, contact form
4. If all good: merge to production (1 click)
5. Post-production check: same 4-5 pages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this workflow, the "update broke the site" emergency essentially doesn't happen. I've been doing this for 3 years across 15+ client sites.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to test on staging before going live
&lt;/h2&gt;

&lt;p&gt;Minimum verification checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Homepage loads&lt;/li&gt;
&lt;li&gt;[ ] Main navigation works&lt;/li&gt;
&lt;li&gt;[ ] A key interior page (About, Services, etc.) loads correctly&lt;/li&gt;
&lt;li&gt;[ ] Contact form submits (check that email arrives)&lt;/li&gt;
&lt;li&gt;[ ] Login/logout works&lt;/li&gt;
&lt;li&gt;[ ] For WooCommerce: add to cart, checkout, payment gateway (test mode)&lt;/li&gt;
&lt;li&gt;[ ] Admin dashboard accessible&lt;/li&gt;
&lt;li&gt;[ ] No PHP errors or warnings visible (check debug.log)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This takes 5-10 minutes. It's the difference between a routine update and an emergency call.&lt;/p&gt;




&lt;h2&gt;
  
  
  Client communication about staging
&lt;/h2&gt;

&lt;p&gt;I include staging in my service agreements. Clients sometimes push for "just update it live, it'll be fine" -- especially for minor updates.&lt;/p&gt;

&lt;p&gt;My response: "Updates on production cost me nothing extra to do safely. If something breaks, it costs both of us time to fix. Staging takes 10 minutes; cleanup takes hours. I always test first."&lt;/p&gt;

&lt;p&gt;Some clients explicitly want to see the staging site before changes go live. I send them the staging URL and a list of what to check. It turns a potential complaint ("why did the button color change?") into a pre-approved change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Automating the staging refresh
&lt;/h2&gt;

&lt;p&gt;For sites I update monthly, I automate the staging refresh with a script that runs before the update window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Run before monthly maintenance window&lt;/span&gt;
&lt;span class="nv"&gt;LIVE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"clientdomain.com"&lt;/span&gt;
&lt;span class="nv"&gt;STAGING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"staging.clientdomain.com"&lt;/span&gt;

&lt;span class="c"&gt;# Refresh staging (Kinsta API - other hosts have similar)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.kinsta.com/v2/sites/&lt;/span&gt;&lt;span class="nv"&gt;$SITE_ID&lt;/span&gt;&lt;span class="s2"&gt;/environments/&lt;/span&gt;&lt;span class="nv"&gt;$STAGING_ENV_ID&lt;/span&gt;&lt;span class="s2"&gt;/clone-from/&lt;/span&gt;&lt;span class="nv"&gt;$LIVE_ENV_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$KINSTA_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Staging refreshed. Ready for updates."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures staging always reflects the current production state, not a 3-month-old copy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why most freelancers skip staging (and why that's the wrong call)
&lt;/h2&gt;

&lt;p&gt;"It takes too long." -- 15 minutes to set up. 5 minutes per update cycle after that.&lt;/p&gt;

&lt;p&gt;"The client is on shared hosting with no staging." -- Use Local by Flywheel or ask the client to upgrade to a plan with staging (and explain why).&lt;/p&gt;

&lt;p&gt;"It's just a minor update." -- Plugin conflicts and WooCommerce breaking changes have happened on "minor" updates. The risk profile doesn't match your definition of minor.&lt;/p&gt;

&lt;p&gt;The real cost of skipping staging isn't the 10 minutes you saved. It's the 6 hours you spend on an emergency fix, the client relationship damage, and the stress.&lt;/p&gt;




&lt;p&gt;The monthly maintenance automation bundle includes pre-update backup scripts that work as a lightweight staging safety net:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/yicgwp" rel="noopener noreferrer"&gt;WordPress Agency Automation Bundle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Service agreement template that includes staging workflow documentation:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/wrmjsy" rel="noopener noreferrer"&gt;WordPress Agency Starter Kit&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5"&gt;WordPress plugin conflicts: diagnose and fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-backups-the-strategy-that-actually-protects-client-sites-most-setups-fail-this-test-45an"&gt;WordPress backups: the strategy that actually protects client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/woocommerce-maintenance-8-checks-that-keep-payment-processing-alive-with-sql-queries-177o"&gt;WooCommerce maintenance: 8 checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/how-to-price-wordpress-maintenance-retainers-the-3-tier-model-that-actually-works-2ndb"&gt;How to price WordPress maintenance retainers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-speed-optimization-the-6-fixes-that-actually-move-the-needle-on-client-sites-4cb2"&gt;WordPress speed optimization: 6 fixes that actually work&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers (the uncomfortable ones included)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All paid tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What staging setup do you use for client sites -- hosting-provided, Local, or something else?&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>WordPress backups: the strategy that actually protects client sites (most setups fail this test)</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 04:37:11 +0000</pubDate>
      <link>https://forem.com/devautomation/wordpress-backups-the-strategy-that-actually-protects-client-sites-most-setups-fail-this-test-8fi</link>
      <guid>https://forem.com/devautomation/wordpress-backups-the-strategy-that-actually-protects-client-sites-most-setups-fail-this-test-8fi</guid>
      <description>&lt;p&gt;Most WordPress backup setups fail when they're needed most.&lt;/p&gt;

&lt;p&gt;The plugin is running. The schedule is set. The backup "completed." But when the site breaks, the restore doesn't work -- or the backup was to the same hosting account that just got suspended.&lt;/p&gt;

&lt;p&gt;Here's the backup strategy I use for client sites, and the three tests every backup needs to pass.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three tests every backup must pass
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Test 1: Can you restore it?&lt;/strong&gt;&lt;br&gt;
Most people never test restores. A backup you've never restored is a backup you don't have. Test quarterly minimum -- spin up a staging site, restore the backup, verify the site works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test 2: Is it off-server?&lt;/strong&gt;&lt;br&gt;
Backups on the same hosting account as the site protect against almost nothing. They don't protect against:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hosting account compromise&lt;/li&gt;
&lt;li&gt;Accidental file deletion that deletes backups too&lt;/li&gt;
&lt;li&gt;Host-side data loss&lt;/li&gt;
&lt;li&gt;Account suspension (you lose access to both the site and the backups)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Off-server means: a different cloud storage account (not on the same hosting provider), a different geographic region, ideally controlled by you -- not your hosting company.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test 3: Is the database included?&lt;/strong&gt;&lt;br&gt;
Files without database = WordPress installation without any content, users, orders, or settings. Always verify the backup includes the database, not just the wp-content folder.&lt;/p&gt;


&lt;h2&gt;
  
  
  The backup layers for client sites
&lt;/h2&gt;

&lt;p&gt;A robust backup strategy has three layers:&lt;/p&gt;
&lt;h3&gt;
  
  
  Layer 1: Daily automated backup (plugin-based)
&lt;/h3&gt;

&lt;p&gt;For most client sites, a good backup plugin configured correctly is sufficient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UpdraftPlus&lt;/strong&gt; (free) -- backs up to Google Drive, Dropbox, S3, or FTP. Free tier works for most sites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BackWPup&lt;/strong&gt; (free) -- similar feature set, good S3 support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BlogVault&lt;/strong&gt; (paid, ~$9/month) -- includes incremental backups and one-click restores. Worth it for WooCommerce sites.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What to configure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full backup schedule: daily (WooCommerce) or weekly (static sites)
Database only: every 4-6 hours for WooCommerce
Retention: 30 days minimum
Destination: external storage ONLY (not hosting account)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer 2: Pre-update snapshot
&lt;/h3&gt;

&lt;p&gt;Before any major update (core version, WooCommerce, theme), take a manual backup first.&lt;/p&gt;

&lt;p&gt;Via WP-CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Database backup&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db &lt;span class="nb"&gt;export &lt;/span&gt;pre_update_&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d&lt;span class="si"&gt;)&lt;/span&gt;.sql

&lt;span class="c"&gt;# Zip wp-content for file backup&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/html/
zip &lt;span class="nt"&gt;-r&lt;/span&gt; wp-content-backup-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d&lt;span class="si"&gt;)&lt;/span&gt;.zip wp-content/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store somewhere accessible. This takes 2 minutes. A broken update that you can roll back in 5 minutes is a non-event. A broken update you can't roll back is an emergency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3: Hosting-level snapshots
&lt;/h3&gt;

&lt;p&gt;Many hosts (Kinsta, WP Engine, SiteGround, Cloudways) offer server-level snapshots that capture the full server state. These are separate from your plugin backups.&lt;/p&gt;

&lt;p&gt;Enable them if your host offers them. They're a third layer, not a replacement for plugin backups -- hosting snapshots are in the same account, which means they fail Test 2.&lt;/p&gt;




&lt;h2&gt;
  
  
  Storage destinations ranked
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best: Amazon S3 (separate AWS account)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlimited storage, cheap ($0.023/GB/month)&lt;/li&gt;
&lt;li&gt;IAM user with write-only access for security (compromise of WP server can't delete the backups)&lt;/li&gt;
&lt;li&gt;Works with UpdraftPlus, BackWPup, most backup plugins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Good: Google Drive or Dropbox (personal account)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to set up&lt;/li&gt;
&lt;li&gt;Storage limits apply (15GB Google Drive free tier)&lt;/li&gt;
&lt;li&gt;Fine for small sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Avoid: FTP to same hosting account&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fails Test 2 -- same account, same risk&lt;/li&gt;
&lt;li&gt;Often slower than cloud storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Avoid: Local server folder&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Worst option -- same server, fails Test 2, doesn't survive server hardware failure&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  WooCommerce: higher stakes, different schedule
&lt;/h2&gt;

&lt;p&gt;WooCommerce sites need more frequent database backups because orders come in continuously.&lt;/p&gt;

&lt;p&gt;Recommended schedule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full backup (files + database): daily, off-peak hours
Database only backup: every 4 hours
Pre-update snapshot: before every WooCommerce update
Retention: 60 days (for order history disputes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One missed order because of a failed restore is an angry customer and potentially a chargeback. The backup cost is trivial compared to the risk.&lt;/p&gt;

&lt;p&gt;Also back up separately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payment gateway configuration (export settings from WooCommerce -&amp;gt; Settings -&amp;gt; Payments)&lt;/li&gt;
&lt;li&gt;Shipping zone configuration&lt;/li&gt;
&lt;li&gt;Tax tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't in the database and can be a nightmare to reconstruct from memory.&lt;/p&gt;




&lt;h2&gt;
  
  
  Automating backup verification
&lt;/h2&gt;

&lt;p&gt;Manual backup verification is fine but easy to skip. My automation script runs a basic check after every backup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if backup completed in last 24 hours (for UpdraftPlus)&lt;/span&gt;
&lt;span class="nv"&gt;LAST_BACKUP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; option get updraft_last_backup 2&amp;gt;/dev/null&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;YESTERDAY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"yesterday"&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LAST_BACKUP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LAST_BACKUP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$YESTERDAY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WARNING: No backup in last 24 hours on &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="c"&gt;# Send alert email&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a hosted setup, BlogVault and ManageWP both send alerts if a backup fails. Worth the price for peace of mind across many client sites.&lt;/p&gt;




&lt;h2&gt;
  
  
  The backup conversation with clients
&lt;/h2&gt;

&lt;p&gt;Many clients don't know their backup situation. First thing I do on a new client site:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check if any backup plugin is installed&lt;/li&gt;
&lt;li&gt;Check where it's backing up to&lt;/li&gt;
&lt;li&gt;Check the last successful backup date&lt;/li&gt;
&lt;li&gt;Check the retention period&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most sites I've taken over have backups configured to the same hosting account, running weekly, with 7-day retention. That's three failure points: wrong destination, too infrequent, too short retention.&lt;/p&gt;

&lt;p&gt;I update the configuration and document it in my client onboarding notes. When something goes wrong at 11pm on a Friday, I know exactly where the backup is and how to restore it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The restore procedure (test this NOW)
&lt;/h2&gt;

&lt;p&gt;For UpdraftPlus:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WP Admin -&amp;gt; UpdraftPlus -&amp;gt; Existing Backups&lt;/li&gt;
&lt;li&gt;Select backup set&lt;/li&gt;
&lt;li&gt;Choose components (database + plugins + themes + uploads)&lt;/li&gt;
&lt;li&gt;Click Restore&lt;/li&gt;
&lt;li&gt;Confirm&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For WP-CLI (database):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db import backup_file.sql
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; cache flush
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For WP-CLI (files):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Restore wp-content from zip&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /var/www/html/
unzip &lt;span class="nt"&gt;-o&lt;/span&gt; wp-content-backup.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test this on a staging environment so you know the procedure works before you need it under pressure.&lt;/p&gt;




&lt;h2&gt;
  
  
  The free monthly maintenance checklist includes a backup verification section:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://devautomation.gumroad.com/l/vaiawy" rel="noopener noreferrer"&gt;WordPress Monthly Maintenance Checklist&lt;/a&gt; -- free download.&lt;/p&gt;

&lt;p&gt;The automation bundle includes backup verification scripts that check your last backup date and alert you if backups are failing:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/yicgwp" rel="noopener noreferrer"&gt;WordPress Agency Automation Bundle&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-security-the-10-minute-monthly-checklist-that-catches-real-problems-1n4n"&gt;WordPress security: 10-minute monthly checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/woocommerce-maintenance-8-checks-that-keep-payment-processing-alive-with-sql-queries-177o"&gt;WooCommerce maintenance: 8 checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5"&gt;WordPress plugin conflicts: diagnose and fix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/how-to-price-wordpress-maintenance-retainers-the-3-tier-model-that-actually-works-2ndb"&gt;How to price WordPress maintenance retainers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-staging-environments-the-15-minute-setup-that-prevents-client-emergencies-i5c"&gt;WordPress staging: 15-min setup&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/how-i-use-wp-cli-to-cut-wordpress-maintenance-time-from-6-hours-to-20-minutes-3a6j"&gt;WP-CLI: cut maintenance time to 20 minutes&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-speed-optimization-the-6-fixes-that-actually-move-the-needle-on-client-sites-4cb2"&gt;WordPress speed optimization: 6 fixes that actually work&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers (the uncomfortable ones included)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All paid tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What's your backup setup for client sites -- UpdraftPlus, BlogVault, or something else?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-inherited-a-wordpress-site-that-had-not-been-updated-in-2-years-here-is-what-i-found-2hmk"&gt;I inherited a WP site not updated in 2 years -- what I found&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>WordPress plugin conflicts: how to diagnose and fix them without breaking client sites</title>
      <dc:creator>devautomation</dc:creator>
      <pubDate>Thu, 21 May 2026 04:30:43 +0000</pubDate>
      <link>https://forem.com/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5</link>
      <guid>https://forem.com/devautomation/wordpress-plugin-conflicts-how-to-diagnose-and-fix-them-without-breaking-client-sites-3mf5</guid>
      <description>&lt;p&gt;Plugin conflict. Two words that ruin an afternoon.&lt;/p&gt;

&lt;p&gt;A client calls. Their site is broken -- something stopped working after an update, or after adding a new plugin. No error message, just "it's not working."&lt;/p&gt;

&lt;p&gt;Here's the systematic process I use to find and fix plugin conflicts fast -- without the trial-and-error that wastes hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why plugin conflicts happen
&lt;/h2&gt;

&lt;p&gt;WordPress plugins hook into the same core functions. When two plugins try to modify the same behavior -- a checkout form, an image upload, a menu item -- they conflict.&lt;/p&gt;

&lt;p&gt;Common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two plugins using different versions of the same library (jQuery UI, Select2, etc.)&lt;/li&gt;
&lt;li&gt;A plugin adding a filter that breaks another plugin's output&lt;/li&gt;
&lt;li&gt;PHP fatal error in one plugin affecting page rendering&lt;/li&gt;
&lt;li&gt;Two caching/optimization plugins competing for the same assets&lt;/li&gt;
&lt;li&gt;A security plugin blocking requests that another plugin needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The conflict often appears only on specific pages, or only for logged-in users, or only after a specific action -- which makes it feel random. It isn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Reproduce it in a predictable way (5 min)
&lt;/h2&gt;

&lt;p&gt;Before touching anything, answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which page(s) is it broken on?&lt;/li&gt;
&lt;li&gt;Which user roles see the problem?&lt;/li&gt;
&lt;li&gt;When did it start? (What changed?)&lt;/li&gt;
&lt;li&gt;Is it broken on mobile too, or just desktop?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check the browser console first (F12 -&amp;gt; Console tab). A JavaScript error often points directly to the file -- which tells you the plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Also check PHP error log on server&lt;/span&gt;
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt; /var/log/apache2/error.log | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"wp-content/plugins"&lt;/span&gt;
&lt;span class="c"&gt;# Or WordPress debug log if enabled:&lt;/span&gt;
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt; /wp-content/debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Enable WP_DEBUG (safely)
&lt;/h2&gt;

&lt;p&gt;Add to wp-config.php temporarily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_DEBUG'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_DEBUG_LOG'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'WP_DEBUG_DISPLAY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Log to file, not screen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;WP_DEBUG_DISPLAY false&lt;/code&gt; means errors go to debug.log, not visible to visitors. Safe for brief use on production. After fixing, set WP_DEBUG back to false and delete debug.log.&lt;/p&gt;

&lt;p&gt;Now reproduce the problem and read the log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-100&lt;/span&gt; /wp-content/debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PHP fatal errors and warnings will name the file and line number. That's your culprit.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: The deactivation test (classic but systematic)
&lt;/h2&gt;

&lt;p&gt;If the error log doesn't give you a clear answer, deactivate plugins in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deactivate the last plugin you installed/updated&lt;/strong&gt; -- most likely culprit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deactivate plugins by category&lt;/strong&gt; -- security plugins, caching plugins, optimization plugins. Each category often conflicts with others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deactivate all non-essential plugins&lt;/strong&gt; -- if the problem disappears, reactivate one by one until it returns&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Via WP-CLI (faster than the dashboard):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List all active plugins&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin list &lt;span class="nt"&gt;--status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;active &lt;span class="nt"&gt;--fields&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;name,version

&lt;span class="c"&gt;# Deactivate a specific plugin&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin deactivate plugin-slug

&lt;span class="c"&gt;# Deactivate ALL plugins at once (nuclear option)&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin deactivate &lt;span class="nt"&gt;--all&lt;/span&gt;

&lt;span class="c"&gt;# Reactivate one at a time&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin activate plugin-slug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nuclear option (deactivate all) confirms instantly whether the problem is plugin-related at all. If the problem persists with zero plugins active, it's a theme issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Theme conflict check
&lt;/h2&gt;

&lt;p&gt;Switch to a default theme (Twenty Twenty-Five or Twenty Twenty-Four):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; theme activate twentytwentyfive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the problem disappears: it's a theme conflict, not a plugin conflict.&lt;/p&gt;

&lt;p&gt;If it persists: it may be a WordPress core issue, hosting configuration, or server-side problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Browser console is your friend
&lt;/h2&gt;

&lt;p&gt;For frontend issues (JavaScript errors, layout breaks, form failures):&lt;/p&gt;

&lt;p&gt;Open Chrome DevTools -&amp;gt; Network tab -&amp;gt; reproduce the problem.&lt;/p&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Red requests (4xx, 5xx)&lt;/strong&gt; -- blocked resources or REST API failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Console errors mentioning plugin filenames&lt;/strong&gt; -- tells you which plugin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;jQuery is not defined&lt;/code&gt;&lt;/strong&gt; -- jQuery load order issue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Uncaught TypeError&lt;/code&gt;&lt;/strong&gt; -- usually a JavaScript version conflict&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Network tab also shows if two plugins are loading the same library twice (e.g., two copies of Select2 from different paths).&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Staging environment for complex conflicts
&lt;/h2&gt;

&lt;p&gt;For conflicts that need extended investigation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# WP-CLI can clone a site&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; db &lt;span class="nb"&gt;export &lt;/span&gt;staging_backup.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy files + database to staging. Work there. When fixed, apply the solution to production.&lt;/p&gt;

&lt;p&gt;Never debug complex conflicts on live production by trial and error. One wrong deactivation can break a WooCommerce checkout during business hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  The most common conflicts I see
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Caching plugin + builder plugin&lt;/strong&gt;&lt;br&gt;
Elementor/Divi cached before assets regenerate. Fix: clear cache after every save, or exclude builder pages from full-page cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WooCommerce + checkout optimization plugins&lt;/strong&gt;&lt;br&gt;
Anything that strips scripts from the checkout page can break payment gateways. Fix: whitelist the payment gateway scripts in the optimization plugin settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security plugin + REST API usage&lt;/strong&gt;&lt;br&gt;
Security plugins that block REST API endpoints break Gutenberg, WooCommerce, and any plugin that uses the REST API. Fix: whitelist your own domain in the security plugin's REST API settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two SEO plugins&lt;/strong&gt;&lt;br&gt;
Both injecting meta tags into head. Fix: there should be exactly one SEO plugin per site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jQuery version mismatch&lt;/strong&gt;&lt;br&gt;
A plugin that loads its own jQuery (instead of WordPress's enqueued version) breaks every other plugin that expects the standard version. Fix: check which plugin is loading external jQuery and disable that option.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fixing it without losing data
&lt;/h2&gt;

&lt;p&gt;When you identify the conflict:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Configure one plugin to not conflict&lt;/strong&gt; -- most plugins have settings to disable specific features. A security plugin can whitelist certain URLs; an optimization plugin can exclude certain scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Replace one plugin&lt;/strong&gt; -- if two plugins do overlapping things, pick one and remove the other. Running both a caching plugin and a CDN with caching enabled is a common example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 3: Update both plugins&lt;/strong&gt; -- sometimes the conflict is a known bug that's been fixed. Check changelogs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 4: Contact plugin support&lt;/strong&gt; -- for paid plugins, this is part of what you paid for. Describe the conflict specifically: plugin A version X conflicts with plugin B version Y on WordPress Z.&lt;/p&gt;




&lt;h2&gt;
  
  
  Preventing conflicts in the first place
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Test updates on staging before pushing to production&lt;/li&gt;
&lt;li&gt;Don't install two plugins that do the same job&lt;/li&gt;
&lt;li&gt;Read plugin changelogs before updating&lt;/li&gt;
&lt;li&gt;Keep an update log (date, what changed, any issues)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My automation script does a backup before every update, sends a post-update health check, and emails me if anything looks wrong. That's the safety net that makes updates non-stressful.&lt;/p&gt;




&lt;h2&gt;
  
  
  The automation that makes this manageable
&lt;/h2&gt;

&lt;p&gt;Manual conflict investigation across 10 client sites after updates is painful. My maintenance scripts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Backup before every update&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;wp doctor check --all&lt;/code&gt; post-update&lt;/li&gt;
&lt;li&gt;Check that the site responds (HTTP 200) after updates&lt;/li&gt;
&lt;li&gt;Alert if anything changed in core file checksums
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Post-update health check&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; core verify-checksums
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; plugin verify-checksums &lt;span class="nt"&gt;--all&lt;/span&gt;
wp &lt;span class="nt"&gt;--allow-root&lt;/span&gt; doctor check &lt;span class="nt"&gt;--all&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}"&lt;/span&gt; https://clientsite.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the site returns anything other than 200 after an update, I get an alert before the client notices.&lt;/p&gt;




&lt;p&gt;The full script bundle (bulk updates + post-update health checks + alerting):&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/yicgwp" rel="noopener noreferrer"&gt;WordPress Agency Automation Bundle&lt;/a&gt; -- use &lt;strong&gt;CHECKLIST&lt;/strong&gt; for 15% off.&lt;/p&gt;

&lt;p&gt;Or grab the free monthly maintenance checklist to see what a full maintenance workflow looks like:&lt;br&gt;
&lt;a href="https://devautomation.gumroad.com/l/vaiawy" rel="noopener noreferrer"&gt;WordPress Monthly Maintenance Checklist&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Related articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-got-tired-of-manual-wordpress-maintenance-across-8-client-sites-so-i-automated-all-of-it-16b4"&gt;I automated WP maintenance across 8 client sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-security-the-10-minute-monthly-checklist-that-catches-real-problems-1n4n"&gt;WordPress security: 10-minute monthly checklist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/wordpress-site-running-slow-heres-the-exact-checklist-i-use-to-diagnose-any-site-in-30-minutes-1mo2"&gt;WordPress site running slow? 30-min diagnosis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/mainwp-vs-managewp-vs-custom-scripts-how-i-manage-15-wordpress-sites-in-2025-4n67"&gt;MainWP vs ManageWP vs custom scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/how-to-price-wordpress-maintenance-retainers-the-3-tier-model-that-actually-works-2ndb"&gt;How to price WordPress maintenance retainers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-backups-the-strategy-that-actually-protects-client-sites-most-setups-fail-this-test-8fi"&gt;WordPress backups: the strategy that actually protects client sites&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-staging-environments-the-15-minute-setup-that-prevents-client-emergencies-i5c"&gt;WordPress staging: 15-min setup&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/how-i-use-wp-cli-to-cut-wordpress-maintenance-time-from-6-hours-to-20-minutes-3a6j"&gt;WP-CLI: cut maintenance time to 20 minutes&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-client-onboarding-the-exact-process-i-use-to-start-every-maintenance-contract-right-31of"&gt;WordPress client onboarding: the exact process&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/wordpress-speed-optimization-the-6-fixes-that-actually-move-the-needle-on-client-sites-4cb2"&gt;WordPress speed optimization: 6 fixes that actually work&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/devautomation/15-ai-prompts-i-actually-use-as-a-tech-freelancer-with-the-uncomfortable-ones-included-34bc"&gt;15 AI prompts for tech freelancers (the uncomfortable ones included)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All paid tools: &lt;a href="https://devautomation.gumroad.com" rel="noopener noreferrer"&gt;devautomation.gumroad.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What's the most frustrating plugin conflict you've run into on a client site? Drop it in the comments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/devautomation/i-inherited-a-wordpress-site-that-had-not-been-updated-in-2-years-here-is-what-i-found-2hmk"&gt;I inherited a WP site not updated in 2 years -- what I found&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
