[{"data":1,"prerenderedAt":217},["ShallowReactive",2],{"seo-verification":3,"blog-wordpress-client-staging-build-it-test-updates-then-deploy-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-wordpress-client-staging-build-it-test-updates-then-deploy-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":27,"featuredImage":29,"bgImage":30,"posterImage":31,"relatedSolution":32,"intro":35,"sections":36,"ctaTitle":160,"ctaBody":161,"ctaButton":162,"ctaUrl":163,"relatedPosts":164},545,"wordpress-client-staging-build-it-test-updates-then-deploy",{"fr":12,"en":10,"ar":13,"es":14},"environnement-preproduction-wordpress-client-agence","بيئة-تجريبية-لموقع-ووردبريس-لعميل-أنشئها-واختبر-قبل-الإنتاج","preproduccion-wordpress-de-cliente-montarla-y-probar-antes","WordPress client staging: build it, test updates, then deploy","Isolated subdomain, cloned database, noindex and password: build a staging site for a client WordPress, test updates one by one, then ship them safely.",12,0,false,"2026-10-31T00:00:00+00:00","2026-10-31T19:07:30+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},3,"Deployment","deploiement","bg-success\u002F10 text-success",[28],{"id":23,"name":24,"slug":25,"color":26,"icon":25},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fenvironnement-preproduction-wordpress-client-agence-poster.svg",{"categorySlug":33,"appSlug":34},"cms-websites","wordpress","A core or plugin update takes seconds and can cost hours, in front of a client who sells online. Yet a badly isolated staging site is worse than none: it gets indexed, sends real emails to the site's customers, or overwrites production URLs on the way back. This guide builds a safe copy of a client WordPress site step by step, tests updates one at a time, reads errors in `debug.log`, then moves the changes to production without overwriting the live database, with a rollback ready.",[37,41,51,54,88,91,94,104,107,110,118,150,153,157],{"type":38,"title":39,"body":40},"h2","Why a staging site rather than testing on the live site","A form plugin that no longer initialises, a theme that loses its layout, the screen \"There has been a critical error on this website\": these failures follow an update that looked harmless. With three sites to manage, caution is enough. With thirty, you either update in the dark or stop updating, and then the unpatched vulnerability is what costs you.\n\nA staging site is a live copy of the site, on a separate address, with its own database. You can break what you like, read the errors, fix them, then replay the already validated step on production. It does not replace the backup: it makes restoring one rarely necessary.",{"type":42,"title":43,"items":44},"ul","What a staging site gives you",[45,46,47,48,49,50],"**Updates without surprises** — every core, theme or plugin change is seen on screen before it reaches visitors.","**A readable diagnosis** — errors go to a log, not in front of the client, and the cause is found before they call.","**A shared review** — the client or their project manager signs off on a separate address, without touching the public site.","**A change log** — you note the version before and after for each plugin, and replay exactly the same on production.","**A trial for new things** — new theme, new page builder, new payment module: everything is judged on a copy.","**A prepared rollback** — the backup is made and checked before the test, not after the incident.",{"type":38,"title":52,"body":53},"Prerequisites, with numbers, before copying","Count three times the size of the live site in disk space: the site, its copy and the database export. Read the size of `wp-content` with `du -sh wp-content` and that of the database in phpMyAdmin or with `wp db size`. Plan one subdomain per client, for example `staging.your-domain.com`, and the same PHP version as production: a staging site on a newer PHP validates a configuration that is not the client's. That version is shown under Tools › Site Health › Info, and the versions still supported are kept up to date at php.net\u002Fsupported-versions.php.\n\nYou also need a terminal with `wp-cli` (SSH on an account that allows it, or a VPS). This guide describes the manual copy, files then database, which shows exactly what is copied. If WP Toolkit is available on your account, its cloning produces that copy for you (see the guide \"Install WordPress from cPanel\"); the rest of the guide (noindex, authentication, emails switched off, tests) then applies unchanged. For installing a new site from cPanel, see the dedicated guide.",{"type":55,"title":56,"steps":57},"steps","Build the staging site, step by step",[58,61,64,67,70,73,76,79,82,85],{"title":59,"body":60},"Back up production before any write","From the live site's folder:\n`mkdir -p ~\u002Fpreprod-backups`\n`wp db export ~\u002Fpreprod-backups\u002Fbefore-staging.sql --single-transaction`\n`tar -czf ~\u002Fpreprod-backups\u002Ffiles-before-staging.tar.gz -C ~\u002Fpublic_html .`\nCheck that both files exist and are not empty with `ls -lh ~\u002Fpreprod-backups`. The plan's own backups do not replace this step: their frequency depends on the plan, so they may be several days old.",{"title":62,"body":63},"Create the subdomain and its folder","Create `staging.your-domain.com` in cPanel (the guide \"Create a subdomain in cPanel\" details the screen) with its own document root, preferably outside `public_html`, for example `~\u002Fstaging.your-domain.com`. A folder placed inside `public_html` would also be reachable through an address of the live site. Wait until the subdomain's TLS certificate is issued before testing.",{"title":65,"body":66},"Copy the files","`rsync -a --exclude='wp-content\u002Fcache\u002F' ~\u002Fpublic_html\u002F ~\u002Fstaging.your-domain.com\u002F`\nAdapt the source path to the client site's document root. Without a terminal, the cPanel file manager lets you compress the folder, move it, then extract it into the subdomain's folder.",{"title":68,"body":69},"Create a dedicated database and user","In the MySQL databases section of cPanel, create a new database and a user, and give it all privileges on that database only. Then open the copy's `wp-config.php` and change `DB_NAME`, `DB_USER` and `DB_PASSWORD`. This is the costliest mistake in this guide: copying `wp-config.php` without changing those three lines makes the staging site write into the production database.",{"title":71,"body":72},"Import the database","From the copy's folder:\n`cd ~\u002Fstaging.your-domain.com`\n`wp db import ~\u002Fpreprod-backups\u002Fbefore-staging.sql`\n`wp option get siteurl`\nThe last command should still show the production address: that is normal, the URLs have not been replaced yet. If it fails, `wp-config.php` still points to the wrong database.",{"title":74,"body":75},"Replace the URLs, as a dry run first","`wp search-replace 'https:\u002F\u002Fyour-domain.com' 'https:\u002F\u002Fstaging.your-domain.com' --all-tables --skip-columns=guid --dry-run`\nRead the report: it lists the tables and the number of replacements. Then run the same command without `--dry-run`. WordPress stores many settings as serialized data, where each string carries its length: a `sed` on the export changes the URL length without fixing that count, and the settings become unreadable. `wp search-replace` understands this data and rewrites it correctly.",{"title":77,"body":78},"Set the staging settings in wp-config.php","Add, above the line \"That's all, stop editing\":\n`define('WP_ENVIRONMENT_TYPE', 'staging');`\n`define('DISABLE_WP_CRON', true);`\n`define('DISALLOW_FILE_EDIT', true);`\n`define('WP_DEBUG', true);`\n`define('WP_DEBUG_LOG', true);`\n`define('WP_DEBUG_DISPLAY', false);`\nErrors go to `wp-content\u002Fdebug.log` without showing to visitors. `WP_ENVIRONMENT_TYPE` has existed since WordPress 5.5 and accepts `local`, `development`, `staging` and `production`: it lets themes and plugins adapt, but it does not hide the site from search engines, hence the next step.",{"title":80,"body":81},"Close access and request noindex","Under Settings › Reading, tick \"Discourage search engines from indexing this site\", or from the command line: `wp option update blog_public 0`. Then add HTTP authentication to the copy's folder: a `.htpasswd` file created with `htpasswd -c ~\u002F.htpasswd-staging client`, then in the folder's `.htaccess` the directives `AuthType Basic`, `AuthName \"Preproduction\"`, `AuthUserFile` pointing to that file and `Require valid-user`. Failing that, restrict access to an IP list.",{"title":83,"body":84},"Check the copy the way a robot would","`curl -sI https:\u002F\u002Fstaging.your-domain.com\u002F`\nThe response should be a `401`. Then, with the credentials:\n`curl -s -u client https:\u002F\u002Fstaging.your-domain.com\u002F | grep -i robots`\nYou should see a `meta name='robots'` tag containing `noindex`. If a cache or SEO plugin replaces it, that is the one to configure. Finally, check that the theme contains no hard-coded production address: `grep -r \"https:\u002F\u002Fyour-domain.com\" wp-content\u002Fthemes`.",{"title":86,"body":87},"Attach staging to your agency routine","Turn this setup into a template: one subdomain per client, in the client's cPanel account, with the same checklist. The order of operations for moving a site to another host is covered by the guide \"Migrate a client WordPress site without downtime\"; the staging site described here is a lasting tool, not a cutover step.",{"type":38,"title":89,"body":90},"Really isolate it: noindex is not enough","Noindex asks search engines not to keep a page; it stops nobody from reading it. A staging site open to everyone ends up in a link pasted in a ticket, in a sitemap or in a screenshot, and it then publishes content duplicated from production. The two protections complement each other: noindex tells engines not to index, HTTP authentication or an IP list forbids access.\n\nOne trap: if you block the subdomain with `robots.txt`, a robot no longer reads the page and therefore never sees the noindex tag. With authentication in place, that file is of no use.",{"type":38,"title":92,"body":93},"Neutralise emails, payments and scheduled tasks","The copy contains the site's real customers: subscribers, buyers, order addresses. Everything that sends itself must be switched off before the slightest test, otherwise an abandoned-cart reminder, an appointment reminder or a subscription renewal goes out twice from the copy. WordPress scheduled tasks are triggered by visits: on staging, disable them with `DISABLE_WP_CRON` and run them by hand with `wp cron event run --due-now` when you want to test them.",{"type":42,"title":95,"items":96},"Checklist before touching a single plugin",[97,98,99,100,101,102,103],"**Emails** — sending plugin in test mode or redirected to a review mailbox, shop notifications switched off.","**Payments** — gateway in test mode, production keys removed from the copy, callback addresses (webhooks) not declared for staging.","**Scheduled tasks** — `DISABLE_WP_CRON` set, pending events listed with `wp cron event list`.","**File editing** — `DISALLOW_FILE_EDIT` active so code cannot be edited from the admin.","**Error log** — `WP_DEBUG_LOG` active and `WP_DEBUG_DISPLAY` set to `false`.","**Third-party integrations** — CRM, directories, analytics tools and production API keys replaced or removed.","**Search engines** — noindex set and authentication in place, checked with `curl` as above.",{"type":38,"title":105,"body":106},"Test updates, one at a time","List what is waiting for an update with `wp plugin list --update=available`. Then update one plugin at a time: `wp plugin update plugin-name`, browse the pages that matter (home, contact form, cart, login) and read the end of the log with `tail -n 30 wp-content\u002Fdebug.log`. Move on to the next one only when the log is quiet. Do the same for the theme with `wp theme update theme-name`, then for core with `wp core update`.\n\nIn a change log, note for each line the version before and the version after. That is the list you will replay on production, version by version, instead of copying anything.",{"type":38,"title":108,"body":109},"When the update breaks: reading debug.log","The classic symptom is the screen \"There has been a critical error on this website\". WordPress then enters recovery mode and sends a link to the admin address, which assumes email sending works: on staging it is neutralised, so do not wait for it. The cause is in the log: `tail -n 40 wp-content\u002Fdebug.log`. Look for the last line starting with `PHP Fatal error`, such as `Call to undefined function` or `Cannot declare class`, and note the file path: the folder under `wp-content\u002Fplugins\u002F` names the faulty plugin. Deactivate it without going through the admin using `wp plugin deactivate plugin-name`, and the site comes back and you know who to blame.",{"type":42,"title":111,"items":112},"Troubleshooting: the other symptoms you really meet",[113,114,115,116,117],"**The site redirects to production** — `wp option get siteurl` and `wp option get home` still show the old address, or a page builder keeps hard-coded URLs; run the replacement again, with `--precise` if needed.","**\"Error establishing a database connection\"** — the copy's `DB_NAME`, `DB_USER`, `DB_PASSWORD` or `DB_HOST` are wrong, or the user has no rights on the new database.","**Images or styles loaded from production** — escaped URLs, such as `https:\\\u002F\\\u002F` in page builders' JSON data, escaped the replacement; run it again with that form.","**Login loop or immediate logout** — the cookies belong to the old domain; clear them and check `siteurl` and `home`.","**The staging site shows up in a search engine** — noindex was set too late or a plugin overrides it; switch to HTTP authentication and request removal of the address.",{"type":119,"title":120,"headers":121,"rows":125},"comparison","Files or database: what moves, and how",[122,123,124],"Item","Where it lives","How to move it to production",[126,130,133,136,139,143,147],[127,128,129],"Theme and child theme","Files","Deploy the validated folder, or replay `wp theme update` at the tested version",[131,128,132],"Plugins","Replay `wp plugin update plugin-name --version=X` with the tested version",[134,128,135],"Must-use plugins (mu-plugins)","Copy the validated file, with the old one saved alongside",[137,128,138],"Uploaded media (uploads)","Never push from staging to production: production keeps receiving new media",[140,141,142],"Plugin settings","Database (options)","Redo the setting by hand on production, or `wp option update`, naming the option",[144,145,146],"Orders, forms, accounts, comments","Database","Never overwrite: this data lives on the production side",[148,145,149],"Tables created by an update","Let the plugin create them by replaying the update on production",{"type":38,"title":151,"body":152},"Moving to production, and being able to go back","On a transactional site, never import the staging database into production: during your tests, orders, sign-ups and form entries arrived online, and an import erases them. Replay the validated changes instead. Sequence: a fresh backup (`wp db export` and a files archive, as in step 1), `wp maintenance-mode activate`, updates in order and at the versions in the log, a check of the key pages, then `wp maintenance-mode deactivate`.\n\nTo go back, restore the files first: `wp plugin install plugin-name --version=old --force` or the archive from step 1. Restore the database only as a last resort, and only if the update changed tables: everything entered since the backup would be lost, so the export must then be only minutes old. Keep the backup until the client has approved the live site.",{"type":154,"title":155,"body":156},"tip","The hardening reflex","Once the update is validated, delete the copy of the production database left in `~\u002Fpreprod-backups` and on staging: a full export holds customers' addresses, orders and password hashes. Never leave `WP_DEBUG` on for the live site, the log can contain paths and queries.",{"type":38,"title":158,"body":159},"A routine that holds at portfolio scale","A staging site is judged by its discipline: always the same setup, the same checklist, the same log. For an agency, the routine fits in a procedure template: one subdomain per client, a dedicated database, noindex plus authentication, emails switched off, updates one at a time, replay to deploy. It works all the better when each client site lives in its own account, with its own backups and separate access.","One staging site per client, on isolated infrastructure","Each client site is better off in its own cPanel account: a staging subdomain, backups depending on the plan and separate access, all from a single reseller plan and one agency space, under your brand. You keep ownership of the client relationship; the infrastructure under every site is ours.","Discover the agency space","\u002Fsolutions\u002Fagences",[165,182,201],{"id":166,"slug":167,"slugs":168,"title":172,"excerpt":173,"readTime":174,"views":18,"isPinned":19,"publishedAt":175,"updatedAt":176,"category":177,"categories":178,"featuredImage":29,"bgImage":30,"posterImage":180,"relatedSolution":181},538,"migrate-client-wordpress-site-new-host-no-downtime",{"fr":169,"en":167,"ar":170,"es":171},"migrer-site-wordpress-client-nouvel-hebergeur-sans-coupure","نقل-موقع-ووردبريس-عميل-استضافة-جديدة-دون-توقف","migrar-sitio-wordpress-cliente-nuevo-hosting-sin-cortes","Migrate a Client WordPress Site With No Downtime: The Method","Copy, hosts-file test before DNS, write freeze, search-replace, cutover and rollback: the method for moving a client WordPress site to a new host.",11,"2026-10-30T00:00:00+00:00","2026-10-31T01:54:05+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[179],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Fmigrer-site-wordpress-client-nouvel-hebergeur-sans-coupure-poster.svg",{"categorySlug":33,"appSlug":34},{"id":183,"slug":184,"slugs":185,"title":189,"excerpt":190,"readTime":191,"views":18,"isPinned":19,"publishedAt":192,"updatedAt":193,"category":194,"categories":198,"featuredImage":29,"bgImage":30,"posterImage":200,"relatedSolution":29},469,"install-wordpress-wp-toolkit-cpanel",{"fr":186,"en":184,"ar":187,"es":188},"installer-wordpress-wp-toolkit-cpanel","تثبيت-ووردبريس-باستخدام-wp-toolkit-في-cpanel","instalar-wordpress-wp-toolkit-cpanel","Install WordPress from cPanel","Install WordPress in a few minutes from cPanel: Websites & Apps, Manage, Build with WordPress, then Launch My Website.",4,"2026-10-19T00:00:00+00:00","2026-10-20T07:26:24+00:00",{"id":17,"name":195,"slug":196,"color":197,"icon":196},"Guides","guides","bg-emerald-500\u002F10 text-emerald-400",[199],{"id":17,"name":195,"slug":196,"color":197,"icon":196},"\u002Fblog\u002Fcovers\u002Finstaller-wordpress-wp-toolkit-cpanel-poster.svg",{"id":202,"slug":203,"slugs":204,"title":208,"excerpt":209,"readTime":210,"views":211,"isPinned":19,"publishedAt":192,"updatedAt":212,"category":213,"categories":214,"featuredImage":29,"bgImage":30,"posterImage":216,"relatedSolution":29},474,"create-subdomain-cpanel",{"fr":205,"en":203,"ar":206,"es":207},"creer-sous-domaine-cpanel","إنشاء-نطاق-فرعي-في-cpanel","crear-subdominio-cpanel","Create a subdomain in cPanel","Create a subdomain such as blog.yourdomain.com in cPanel, choose its folder and point its DNS, in both the Meridian and Jupiter interfaces.",5,1,"2026-10-20T20:26:34+00:00",{"id":17,"name":195,"slug":196,"color":197,"icon":196},[215],{"id":17,"name":195,"slug":196,"color":197,"icon":196},"\u002Fblog\u002Fcovers\u002Fcreer-sous-domaine-cpanel-poster.svg",1793480386215]