{"id":12704,"date":"2025-07-25T13:02:36","date_gmt":"2025-07-25T07:17:36","guid":{"rendered":"https:\/\/nestnepal.com\/blog\/?p=12704"},"modified":"2025-09-03T13:55:00","modified_gmt":"2025-09-03T08:10:00","slug":"setting-up-wordpress-staging-environment-cpanel","status":"publish","type":"post","link":"https:\/\/nestnepal.com\/blog\/setting-up-wordpress-staging-environment-cpanel\/","title":{"rendered":"Setting Up a WordPress Staging Environment in cPanel Without Extra Plugins"},"content":{"rendered":"\n<p>Most developers know they should test changes before pushing to production, but many skip staging environments because they think it&#8217;s complicated or requires expensive plugins. The truth is, you can create a fully functional <a href=\"https:\/\/nestnepal.com\/wordpress-hosting-in-nepal\/\">WordPress<\/a> staging site using nothing but <a href=\"https:\/\/nestnepal.com\/blog\/how-to-use-cpanel-to-manage-any-hosting-account\/\">cPanel&#8217;s built-in tools<\/a> and a few manual steps that take less than 15 minutes.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" data-src=\"https:\/\/nestnepal.com\/blog\/wp-content\/uploads\/2025\/07\/image-23.png\" alt=\"wordpress-staging\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 730px; --smush-placeholder-aspect-ratio: 730\/380;\" \/><\/figure>\n\n\n\n<p>This approach gives you complete control over your staging environment without monthly subscription fees or plugin dependencies that might break during updates.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Why Skip the Plugins?<\/strong><\/h2>\n\n\n\n<p>While staging plugins like WP Staging or Duplicator Pro are convenient, they come with limitations. They often struggle with large databases, have file size restrictions on shared hosting, and can fail silently, leaving you with incomplete copies. Plus, understanding the manual process makes you a better developer and gives you flexibility when plugins aren&#8217;t available.<\/p>\n\n\n\n<p>The manual approach also means:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>No plugin conflicts or compatibility issues<\/li>\n\n\n\n<li>Works on any cPanel hosting (even restrictive shared hosts)<\/li>\n\n\n\n<li>Complete control over what gets copied and what doesn&#8217;t<\/li>\n\n\n\n<li>Better understanding of your WordPress file structure<\/li>\n\n\n\n<li>No ongoing subscription costs<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Planning Your Staging Setup<\/strong><\/h2>\n\n\n\n<p>Before diving in, decide on your staging structure. Most developers use one of these approaches:<\/p>\n\n\n\n<p><strong>Subdomain Method<\/strong> (Recommended)<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Main site: yoursite.com<\/li>\n\n\n\n<li>Staging: staging.yoursite.com<\/li>\n<\/ul>\n\n\n\n<p><strong>Subdirectory Method<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Main site: yoursite.com<\/li>\n\n\n\n<li>Staging: yoursite.com\/staging<\/li>\n<\/ul>\n\n\n\n<p>The subdomain method is cleaner and avoids potential conflicts with your <a href=\"https:\/\/nestnepal.com\/blog\/change-php-version-using-htaccess-in-cpanel\/\">main site&#8217;s .htaccess<\/a> rules or caching plugins.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 1: Create the Staging Subdomain<\/strong><\/h2>\n\n\n\n<p>In cPanel, navigate to <strong>Subdomains<\/strong> under the Domains section:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Subdomain<\/strong>: Enter staging<\/li>\n\n\n\n<li><strong>Domain<\/strong>: Select your main domain<\/li>\n\n\n\n<li><strong>Document Root<\/strong>: cPanel will auto-populate this (usually public_html\/staging)<\/li>\n\n\n\n<li>Click <strong>Create<\/strong><\/li>\n<\/ul>\n\n\n\n<p>cPanel automatically creates the directory structure. You&#8217;ll see something like \/public_html\/staging in your file manager.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 2: Copy Your WordPress Files<\/strong><\/h2>\n\n\n\n<p>Use cPanel&#8217;s <strong>File Manager<\/strong> for this step. Navigate to your main site&#8217;s directory (usually public_html):<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Method A: Using File Manager Copy Function<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select all files and folders in your main WordPress installation<\/li>\n\n\n\n<li>Click <strong>Copy<\/strong> in the toolbar<\/li>\n\n\n\n<li>Navigate to your staging directory (public_html\/staging)<\/li>\n\n\n\n<li>Click <strong>Paste<\/strong><\/li>\n\n\n\n<li>Wait for the copy operation to complete<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Method B: Using Compressed Archive (Faster for Large Sites)<\/strong><\/h2>\n\n\n\n<p># If you have SSH access, this is much faster:<\/p>\n\n\n\n<p>cd \/public_html<\/p>\n\n\n\n<p>tar -czf wordpress-backup.tar.gz &#8211;exclude=&#8217;*.log&#8217; &#8211;exclude=&#8217;cache&#8217; .<\/p>\n\n\n\n<p>cd staging<\/p>\n\n\n\n<p>tar -xzf ..\/wordpress-backup.tar.gz<\/p>\n\n\n\n<p>rm ..\/wordpress-backup.tar.gz<\/p>\n\n\n\n<p>For file manager users without SSH:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select all WordPress files<\/li>\n\n\n\n<li>Click <strong>Compress<\/strong> and choose <strong>Tar GZip Archive<\/strong><\/li>\n\n\n\n<li>Name it staging-files.tar.gz<\/li>\n\n\n\n<li>Move the archive to your staging directory<\/li>\n\n\n\n<li>Navigate to the staging directory and extract the archive<\/li>\n\n\n\n<li>Delete the archive file when done<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 3: Database Duplication<\/strong><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Create a New Database<\/strong><\/h2>\n\n\n\n<p>In cPanel, go to <strong><a href=\"https:\/\/www.mysql.com\/\" target=\"_blank\" rel=\"noopener\">MySQL Databases<\/a><\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Create New Database<\/strong>: Enter something like staging_db<\/li>\n\n\n\n<li><strong>Create New User<\/strong>: Create staging_user with a strong password<\/li>\n\n\n\n<li><strong>Add User to Database<\/strong>: Assign the user to the database with ALL PRIVILEGES<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Export Your Production Database<\/strong><\/h2>\n\n\n\n<p>Navigate to <strong>phpMyAdmin<\/strong> in cPanel:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select your production database<\/li>\n\n\n\n<li>Click the <strong>Export<\/strong> tab<\/li>\n\n\n\n<li>Choose the <strong>Quick<\/strong> export method<\/li>\n\n\n\n<li>Format: <strong>SQL<\/strong><\/li>\n\n\n\n<li>Click <strong>Go<\/strong><\/li>\n\n\n\n<li>Save the SQL file to your computer<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Import to Staging Database<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In phpMyAdmin, select your new staging database<\/li>\n\n\n\n<li>Click the <strong>Import<\/strong> tab<\/li>\n\n\n\n<li>Choose the SQL file you just downloaded<\/li>\n\n\n\n<li>Click <strong>Go<\/strong><\/li>\n<\/ul>\n\n\n\n<p>The import might take a few minutes, depending on your database size.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 4: Update WordPress Configuration<\/strong><\/h2>\n\n\n\n<p>Edit the wp-config.php file in your staging directory:<\/p>\n\n\n\n<p>define(&#8216;DB_NAME&#8217;, &#8216;staging_db&#8217;);<\/p>\n\n\n\n<p>define(&#8216;DB_USER&#8217;, &#8216;staging_user&#8217;);<\/p>\n\n\n\n<p>define(&#8216;DB_PASSWORD&#8217;, &#8216;your_staging_password&#8217;);<\/p>\n\n\n\n<p>define(&#8216;DB_HOST&#8217;, &#8216;localhost&#8217;); \/\/ Usually stays the same<\/p>\n\n\n\n<p>define(&#8216;WP_DEBUG&#8217;, true);<\/p>\n\n\n\n<p>define(&#8216;WP_DEBUG_LOG&#8217;, true);<\/p>\n\n\n\n<p>define(&#8216;DISALLOW_FILE_EDIT&#8217;, true);<\/p>\n\n\n\n<p>define(&#8216;WP_ENVIRONMENT_TYPE&#8217;, &#8216;staging&#8217;);<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 5: Update URLs in Database<\/strong><\/h2>\n\n\n\n<p>This is the crucial step that trips up many developers. Your staging site still thinks it lives at your production URL, causing broken links and redirect loops.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Using phpMyAdmin Search and Replace<\/strong><\/h2>\n\n\n\n<p>In phpMyAdmin, select your staging database and run these SQL queries:<\/p>\n\n\n\n<p>&#8212; Update site URL<\/p>\n\n\n\n<p>UPDATE wp_options SET option_value = &#8216;https:\/\/staging.yoursite.com&#8217;&nbsp;<\/p>\n\n\n\n<p>WHERE option_name = &#8216;home&#8217;;<\/p>\n\n\n\n<p>UPDATE wp_options SET option_value = &#8216;https:\/\/staging.yoursite.com&#8217;&nbsp;<\/p>\n\n\n\n<p>WHERE option_name = &#8216;siteurl&#8217;;<\/p>\n\n\n\n<p>&#8212; Update content URLs (be careful with this one)<\/p>\n\n\n\n<p>UPDATE wp_posts SET post_content = REPLACE(post_content,&nbsp;<\/p>\n\n\n\n<p>&#8216;https:\/\/yoursite.com&#8217;, &#8216;https:\/\/staging.yoursite.com&#8217;);<\/p>\n\n\n\n<p>&#8212; Update metadata<\/p>\n\n\n\n<p>UPDATE wp_postmeta SET meta_value = REPLACE(meta_value,&nbsp;<\/p>\n\n\n\n<p>&#8216;https:\/\/yoursite.com&#8217;, &#8216;https:\/\/staging.yoursite.com&#8217;);<\/p>\n\n\n\n<p>&#8212; Update comments<\/p>\n\n\n\n<p>UPDATE wp_comments SET comment_content = REPLACE(comment_content,&nbsp;<\/p>\n\n\n\n<p>&#8216;https:\/\/yoursite.com&#8217;, &#8216;https:\/\/staging.yoursite.com&#8217;);<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Using WP-CLI (If Available)<\/strong><\/h3>\n\n\n\n<p>If your host supports WP-CLI, this is much safer:<\/p>\n\n\n\n<p>cd \/public_html\/staging<\/p>\n\n\n\n<p>wp search-replace &#8216;https:\/\/yoursite.com&#8217; &#8216;https:\/\/staging.yoursite.com&#8217;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 6: Handle SSL and Security<\/strong><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>SSL Certificate Setup<\/strong><\/h2>\n\n\n\n<p>Most cPanel hosts provide free SSL certificates through Let&#8217;s Encrypt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Go to <strong>SSL\/TLS<\/strong> in cPanel<\/li>\n\n\n\n<li>Click <strong>Let&#8217;s Encrypt<\/strong><\/li>\n\n\n\n<li>Select your staging subdomain<\/li>\n\n\n\n<li>Click <strong>Issue<\/strong><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Update .htaccess for Staging<\/strong><\/h2>\n\n\n\n<p>Create or modify the .htaccess file in your staging directory:<\/p>\n\n\n\n<p># WordPress staging environment<\/p>\n\n\n\n<p>&lt;IfModule mod_rewrite.c&gt;<\/p>\n\n\n\n<p>RewriteEngine On<\/p>\n\n\n\n<p>RewriteBase \/<\/p>\n\n\n\n<p># Prevent search engine indexing<\/p>\n\n\n\n<p>Header set X-Robots-Tag &#8220;noindex, nofollow&#8221;<\/p>\n\n\n\n<p># Standard WordPress rules<\/p>\n\n\n\n<p>RewriteRule ^index\\.php$ &#8211; [L]<\/p>\n\n\n\n<p>RewriteCond %{REQUEST_FILENAME} !-f<\/p>\n\n\n\n<p>RewriteCond %{REQUEST_FILENAME} !-d<\/p>\n\n\n\n<p>RewriteRule. \/index.php [L]<\/p>\n\n\n\n<p>&lt;\/IfModule&gt;<\/p>\n\n\n\n<p># Additional security for staging<\/p>\n\n\n\n<p>&lt;Files wp-config.php&gt;<\/p>\n\n\n\n<p>order allow, deny<\/p>\n\n\n\n<p>deny from all<\/p>\n\n\n\n<p>&lt;\/Files&gt;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step 7: Staging-Specific Configurations<\/strong><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Disable Email Sending<\/strong><\/h2>\n\n\n\n<p>Add this to your staging wp-config.php to prevent accidental emails:<\/p>\n\n\n\n<p>if (!function_exists(&#8216;wp_mail&#8217;)) {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;function wp_mail() {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Update WordPress Admin<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Visit https:\/\/staging.yoursite.com\/wp-admin<\/li>\n\n\n\n<li>Log in with your regular credentials<\/li>\n\n\n\n<li>Go to <strong>Settings &gt; General<\/strong><\/li>\n\n\n\n<li>Verify the WordPress Address and Site Address URLs are correct<\/li>\n\n\n\n<li>Update if necessary<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Plugin Considerations<\/strong><\/h2>\n\n\n\n<p>Some plugins might need attention:<\/p>\n\n\n\n<p><strong>Caching Plugins<\/strong>: Disable or reconfigure cache paths <\/p>\n\n\n\n<p><strong>SEO Plugins<\/strong>: Disable XML sitemaps and search engine notifications <\/p>\n\n\n\n<p><strong>Backup Plugins<\/strong>: Disable automatic backups to avoid confusion <\/p>\n\n\n\n<p><strong>Security Plugins<\/strong>: Update allowed IP addresses if needed<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Automation Script for Future Updates<\/strong><\/h2>\n\n\n\n<p>Create a simple script to sync changes from production to staging:<\/p>\n\n\n\n<p>#!\/bin\/bash<\/p>\n\n\n\n<p># staging-sync.sh<\/p>\n\n\n\n<p>PROD_PATH=&#8221;\/public_html&#8221;<\/p>\n\n\n\n<p>STAGING_PATH=&#8221;\/public_html\/staging&#8221;<\/p>\n\n\n\n<p>PROD_DB=&#8221;production_db&#8221;<\/p>\n\n\n\n<p>STAGING_DB=&#8221;staging_db&#8221;<\/p>\n\n\n\n<p>echo &#8220;Syncing files&#8230;&#8221;<\/p>\n\n\n\n<p>rsync -av &#8211;exclude=&#8217;wp-config.php&#8217; &#8211;exclude=&#8217;*.log&#8217; \\<\/p>\n\n\n\n<p>&nbsp;&nbsp;$PROD_PATH\/ $STAGING_PATH\/<\/p>\n\n\n\n<p>echo &#8220;Backing up staging database&#8230;&#8221;<\/p>\n\n\n\n<p>mysqldump $STAGING_DB &gt; staging_backup_$(date +%Y%m%d).sql<\/p>\n\n\n\n<p>echo &#8220;Copying production database&#8230;&#8221;<\/p>\n\n\n\n<p>mysqldump $PROD_DB | mysql $STAGING_DB<\/p>\n\n\n\n<p>echo &#8220;Updating URLs&#8230;&#8221;<\/p>\n\n\n\n<p>mysql $STAGING_DB -e &#8220;UPDATE wp_options SET option_value = &#8216;https:\/\/staging.yoursite.com&#8217; WHERE option_name IN (&#8216;home&#8217;, &#8216;siteurl&#8217;);&#8221;<\/p>\n\n\n\n<p>echo &#8220;Staging sync complete!&#8221;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Testing Your Staging Environment<\/strong><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Basic Functionality Tests<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Test<\/strong><\/td><td><strong>Expected Result<\/strong><\/td><td><strong>Notes<\/strong><\/td><\/tr><tr><td>Homepage loads<\/td><td>\u2713 No errors<\/td><td>Check for broken images<\/td><\/tr><tr><td>Admin login<\/td><td>\u2713 Dashboard accessible<\/td><td>Verify all admin functions work<\/td><\/tr><tr><td>Plugin activation<\/td><td>\u2713 No fatal errors<\/td><td>Test critical plugins only<\/td><\/tr><tr><td>Theme switching<\/td><td>\u2713 Themes load correctly<\/td><td>Verify customizations persist<\/td><\/tr><tr><td>Content creation<\/td><td>\u2713 Posts\/pages save<\/td><td>Test editor functionality<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Common Issues and Fixes<\/strong><\/h2>\n\n\n\n<p><strong>Mixed Content Warnings<\/strong>: Update hardcoded HTTP links to HTTPS<\/p>\n\n\n\n<p>UPDATE wp_posts SET post_content = REPLACE(post_content, &#8216;http:\/\/&#8217;, &#8216;https:\/\/&#8217;);<\/p>\n\n\n\n<p><strong>Broken Images<\/strong>: Verify image URLs were updated correctly<\/p>\n\n\n\n<p>SELECT * FROM wp_options WHERE option_value LIKE &#8216;%yoursite.com%&#8217;;<\/p>\n\n\n\n<p><strong>Plugin Conflicts<\/strong>: Deactivate non-essential plugins first, then reactivate one by one<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Maintaining Your Staging Environment<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" data-src=\"https:\/\/nestnepal.com\/blog\/wp-content\/uploads\/2025\/07\/image-24.png\" alt=\"cPanel\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 417px; --smush-placeholder-aspect-ratio: 417\/428;\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Regular Sync Schedule<\/strong><\/h2>\n\n\n\n<p>Establish a routine for keeping staging current:<\/p>\n\n\n\n<p><strong>Weekly<\/strong>: Sync database for content updates <\/p>\n\n\n\n<p><strong>Before Major Changes<\/strong>: Full file and database sync <\/p>\n\n\n\n<p><strong>After Plugin Updates<\/strong>: Test updates in staging first<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Staging-to-Production Workflow<\/strong><\/h2>\n\n\n\n<p>When you&#8217;re ready to push changes live:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Document Changes<\/strong>: Keep notes on what you modified<\/li>\n\n\n\n<li><strong>Export Staging Database<\/strong>: If content was added in staging<\/li>\n\n\n\n<li><strong>Sync Files<\/strong>: Copy modified files to production<\/li>\n\n\n\n<li><strong>Update URLs<\/strong>: Run search-replace to restore production URLs<\/li>\n\n\n\n<li><strong>Test Production<\/strong>: Verify everything works correctly<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Security Best Practices<\/strong><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Access Control<\/strong><\/h2>\n\n\n\n<p># Add to staging .htaccess for IP restriction<\/p>\n\n\n\n<p>&lt;RequireAll&gt;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;Require IP 123.456.789.0&nbsp; # Your office IP<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;Require IP 98.765.432.1 &nbsp; # Your home IP<\/p>\n\n\n\n<p>&lt;\/RequireAll&gt;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Password Protection<\/strong><\/h2>\n\n\n\n<p>Add layers via cPanel&#8217;s <strong>Password Protect Directories<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select your staging directory<\/li>\n\n\n\n<li>Enable password protection<\/li>\n\n\n\n<li>Create a staging-specific username\/password<\/li>\n\n\n\n<li>This adds HTTP authentication before WordPress login<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Troubleshooting Common Problems<\/strong><\/h2>\n\n\n\n<p><strong>Redirect Loops<\/strong>: Usually caused by incorrect URL settings<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Check the wp_options table for home and siteurl values<\/li>\n\n\n\n<li>Verify .htaccess doesn&#8217;t have conflicting redirects<\/li>\n<\/ul>\n\n\n\n<p><strong>File Permission Issues<\/strong>:<\/p>\n\n\n\n<p># Standard WordPress permissions<\/p>\n\n\n\n<p>find \/public_html\/staging -type d -exec chmod 755 {} \\;<\/p>\n\n\n\n<p>find \/public_html\/staging -type f -exec chmod 644 {} \\;<\/p>\n\n\n\n<p>chmod 600 wp-config.php<\/p>\n\n\n\n<p><strong>Database Connection Errors<\/strong>: Double-check wp-config.php database credentials<\/p>\n\n\n\n<p><strong>Missing Images<\/strong>: Often means URLs weren&#8217;t updated correctly in the database<\/p>\n\n\n\n<p>Setting up a staging environment manually might seem like extra work compared to using a plugin, but it gives you complete control and a deep understanding of your WordPress setup. Once you&#8217;ve done it a few times, the entire process takes less than 15 minutes and provides a robust testing environment that won&#8217;t break during plugin updates or hosting changes.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" data-src=\"https:\/\/nestnepal.com\/blog\/wp-content\/uploads\/2025\/07\/image-25.png\" alt=\"wordpress\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\" style=\"--smush-placeholder-width: 959px; --smush-placeholder-aspect-ratio: 959\/719;\" \/><\/figure>\n\n\n\n<p>The skills you learn doing this manually will serve you well throughout your WordPress development career, especially when working with complex setups where automated tools fall short.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Most developers know they should test changes before pushing to production, but many skip staging environments because they think it&#8217;s&#8230;<\/p>\n","protected":false},"author":15,"featured_media":13014,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[369,112],"tags":[370,117,373],"class_list":["post-12704","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cms","category-wordpress-hosting","tag-cms","tag-cpanel","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/posts\/12704","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/comments?post=12704"}],"version-history":[{"count":4,"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/posts\/12704\/revisions"}],"predecessor-version":[{"id":13248,"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/posts\/12704\/revisions\/13248"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/media\/13014"}],"wp:attachment":[{"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/media?parent=12704"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/categories?post=12704"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nestnepal.com\/blog\/wp-json\/wp\/v2\/tags?post=12704"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}