Excel: Cells have left padding space (but it’s not an indent)

Working in Microsoft Excel (2013 and 2016) I noticed what looked like padding (space between the left side of the cell and the text) in some cells in my sheet.

(See the highlighted cell J39)

I didn’t have text indentation in the cell, and “Format Cells > Alignment > Text alignment > Indent” was set to zero.

The cause was the formatting based on the selected cell data type (in the “Number” section of the ribbon).

I had “Accounting” selected which automatically adds some padding.
Changing it to “General” returned it to normal (removed the space) for a cell with just text.

An easy mistake to make but hard to spot.

PHP: “Fatal error: Can’t use function return value in write context in …”

I just received the following PHP error.

Fatal error: Can’t use function return value in write context in /path/to/file.php on line 595

And I had no fucking idea what the problem was. I had a “sense” of it, but I didn’t understand the “in write context” part (that’s what happens when you get geeks to write error messages).

The line causing the error was this:

if (strtolower($append_value) = strtolower($base_value))

It’s one of those classic programmer errors that is in your face but is easily lost in the code.

Here’s the fixed line

if (strtolower($append_value) == strtolower($base_value))

Yeap – I missed an equals sign to make it an equality expression rather than an assignment (i.e. “=” changed to “==”).


Interestingly, this error was thrown without actually being executed. It must have been while the script was being parsed. I’m using PHP 7.3 in WordPress in the Codeanywhere online IDE.

Application Security: Validate uploaded files before processing them

This is not a “how to” but a “what to”.

If you’re a software developer working on a system that allows file uploads, before you allow any code to process the file (i.e.  the file has uploaded, now you want to do something with it), you first need to check the file extension matches the “content” of the actual file.

A simple example: A user may upload a file with an “.ico” file extension, but it’s actually an image file with EXIF data, and your system has an EXIF data vulnerability. You can’t trust the underlying software libraries you use will first validate the file extension matches the actual data embedded in the file.

What this means is the software libraries you use may see the .ico extension, think that it’s OK (just an icon), not run any checks that would ordinarily be run to verify the file on file extensions containing EXIF data, but while processing the file it will still executes EXIF functions and processes the vulnerability.

You think that won’t happen? Think again. That’s an attack vector Black hat hackers use. And it works.

As a software developer, when you think about security you have to assume all the things that are “not likely” to happen are going to be the most likely attack vectors for hackers.


Our job as software developers is harder than ever. We have to think every “not likely to happen” scenario is going to be a step in an attack by someone malicious.

PHP: Recursively zip a folder/directory structure

Status: Draft (31 May 2019)

This is a work in progress. I want to record my working as I go.

What I Want

I need to zip a folder structure – ultimately, theme and plug-in folder in WordPress – using PHP.

I’m currently developing and testing on a Windows 10 PC. Ultimately it will need to work in Linux (Ubuntu), but the first step is to it working in Windows.

I started with solutions from https://gist.github.com/MarvinMenzerath/4185113/72db1670454bd707b9d761a9d5e83c54da2052ac and https://stackoverflow.com/questions/1334613/how-to-recursively-zip-a-directory-in-php but the zip file was being created, however, not files were added.

I realised the problem was the relative path for folders/files within the zip. My solution below is a modification of the referenced solutions, where I strip the source path from the fill file path of each folder and file to give the relative path to the source.

So far this works in Windows, next step is to test in Linux. I’m actively working the problem so stay tuned.


I created a file “D:\Temp\php\test_zip.php” with the code below.
I execute with the following command (I have XAMPP installed with includes PHP): “D:\Temp\php>D:\xampp\php\php.exe test_zip.php”.

The Code

(Aide: I used https://www.freeformatter.com/html-escape.html to convert raw PHP code to something I can past in between <pre> tags in the Classic WorPress content editor).

// Make sure the script can handle large folders/files
ini_set('max_execution_time', 600);

// Start the backup!
Zip('D:\\Temp\\php\\Source\\', './compressed.zip');
Zip('D:\\Temp\\hildas_prod_logs\\', 'D:\\Temp\\php\\backup-test.zip');
testOne('D:\\Temp\\php\\Source\\debug.log', 'D:\\Temp\\php\\compressed_testOne.zip');

echo "Finished" . "\n";

// A quick, reduced test.
// This works in Windows.
function testOne($source, $zipTo)
	$zip = new ZipArchive;
	if (file_exists($source) === false)
		echo "Sourece does not exist" . "\n";
	if ($zip->open($zipTo, ZIPARCHIVE::CREATE) === true) 
		$zip->addFile($source, 'source\newname.txt');
		echo "OK" . "\n";
		echo "FAILED" . "\n";

// This works in Windows.
// Source and inspiration: https://gist.github.com/MarvinMenzerath/4185113/72db1670454bd707b9d761a9d5e83c54da2052ac - Marvin Menzerath. (http://menzerath.eu)
// Additional source and inspiration: https://stackoverflow.com/questions/1334613/how-to-recursively-zip-a-directory-in-php
function Zip($source, $destination)
    if (!extension_loaded('zip')) 
		echo "Zip extension not loaded\n";
        return false;
	if (!file_exists($source)) 
		echo "Source not found:" . $source . "\n";
        return false;

    $zip = new ZipArchive();
    if (!$zip->open($destination, ZIPARCHIVE::CREATE)) 
		echo "Zip not created or opened\n";
        return false;
	$raw_source = $source;

    $source = str_replace('\\', '/', realpath($source));
	echo "Raw source: " . $raw_source . "\n";
	echo "Clean source: " . $source . "\n";

    if (is_dir($source) === true)
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
		$sourceWithSeparator = $source . DIRECTORY_SEPARATOR;
        foreach ($files as $file)
            $file = str_replace('\\', '/', $file);

            // Ignore "." and ".." folders
            if( in_array(substr($file, strrpos($file, '/')+1), array('.', '..')) )

            $file = realpath($file);

            if (is_dir($file) === true)
				$dir_path = str_replace($sourceWithSeparator, '', $file . DIRECTORY_SEPARATOR);
				echo "Directory: " . $file . " (Path: " . $dir_path . ")\n";
                //$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
            else if (is_file($file) === true)
				$zip_relative_path = str_replace($sourceWithSeparator, '', $file);
				$zip_relative_path = remove_from_start($zip_relative_path, $raw_source);
				echo "File: " . $file . " (Path: " . $zip_relative_path . ")\n";
                //$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
				//$zip->addFile($file, str_replace($source . '/', '', $file));
				$zip->addFile($file, $zip_relative_path);
    else if (is_file($source) === true)
        $zip->addFromString(basename($source), file_get_contents($source));

    return $zip->close();

function remove_from_start($full_string, $prefix)
	if (substr($full_string, 0, strlen($prefix)) == $prefix) 
		$full_string = substr($full_string, strlen($prefix));
	return $full_string;



WordPress Shortcode: “Show If” for conditional content display

Here’s the code for a simple WordPress shortcode to conditionally display content within pages based on supplied usernames or roles.


Example Usage

Display to a specified user:

Display to a specified role:

Display to both a user and a role:

Display to multiple roles (comma separated list. “username” works the same):



It’s in a GitHub gist at https://gist.github.com/vylesk/64ca3e6d3da77fb853ca7af181165e6b and below:

* Plugin Name: "Show If" Shortcode
* Plugin URI: https://jsnelders.com/
* Description: Shortcode to conditionally display content if the user is in a specified role or has a specified username.
* Author: Jason Snelders
* Author URI: http://jsnelders.com
* Version: 190529.1

namespace JasonSnelders\Shortcodes;

*	Show the content only if the current user is one of the specified username(s) or in one ofthe role(s).
*	Attributes:
*		role: comma separated list of allowed roles to view the content.
*		username: comma separated list of allowed usernames to view the content.
*	Attrubtes combine as an OR expressess - content is displayed if they user is in the "role" list OR the "username" list.
add_shortcode('show_if', 'JasonSnelders\Shortcodes\show_if_handler');

function show_if_handler($atts = [], $content = null)
	// Get supplied shortcode attributes.
	$show_if_role = "";
	$show_if_username = "";
	if(isset($atts["role"])) $show_if_role = $atts["role"];
	if(isset($atts["username"])) $show_if_username = $atts["username"];
	$show_if_role = explode(',', $show_if_role);
	$show_if_username = explode(',', $show_if_username);
	// Get the current user.
	$wp_user = \wp_get_current_user();
	$wp_user_roles = $wp_user->roles;
	$wp_user_username = $wp_user->user_login;
	// Check if current user can view content/
	$show_to_user = false;
	foreach ($wp_user_roles as $role_slug)
		if ($role_slug != "" && in_array_case_insensitive($atts, $role_slug))
			$show_to_user = true;
	if ($show_to_user == false)
		foreach ($show_if_username as $show_username)
			if ($show_username != "" && strtolower($show_username) == strtolower($wp_user_username))
				$show_to_user = true;

	if ($show_to_user == true)
		// Show the content
		$content = do_shortcode($content);
		echo $content;
		// Hide the content
		echo "";

	return ob_get_clean();

*	Case-insensitive check if a value is in the array.
*	(Source: https://gist.github.com/sepehr/6351397)
function in_array_case_insensitive($array, $check_value)
	return in_array(strtolower($check_value), array_map('strtolower', $array));

Codeanywhere: Setup a WordPress environment from GitHub repo

Updated: 27 May 2019 (Added “Troubleshooting” at the end).


A quick guide to setting up a WordPress development environment in the Codeanywhere online IDE (https://codeanywhere.com/) and linking to an existing GitHub (or other) source control repository (which I assume also contains the WordPress core code).
It’s not entirely obvious so hopefully this helps.

I’m assuming

  • You have already created an account a Codeanywhere.
  • You have already linked Codeanywhere to to your GitHub (or other) source repository.


Step 1: In your Codeanywhere Editor page, right-click “Connections” in the left-hand pane and select “New Connection”.


Step 2: A “Connection Wizard” dialogue will open. Select “GitHub” (or your relevant source) from the left-side list. A list of repositories will be displayed in the dialogue.

Step 3: Select the repository you want to use. Then un-tick the “Autodetect stack” option below the list (this is what I missed the first time – autodetect doesn’t actually work that well).


Step 4: In the next step of the “Connection Wizard” dialogue, scroll down (or search) until you see a “PHP” stack containing “PHP Develppment Stack with Apache, PHP, MySQL, phpMyAdmin and Composer installed”. You can select either Ubuntu or Centos (I work with Ubuntu).
Then select “Create”.


That’s it!

A new LAMP environment connected to your GitHub repository should soon available and showing.

Note: I’m new to Codeanywhere (13 May 2019). I’m switching to this IDE from the soon-to-be-closed-and-fucked-by-AWS Cloud9 (c9.io) as my primary IDE for WordPress and so far I’ve only followed the above steps and managed to work [so far successfully] in the SSH terminal. I’m not yet sure about the lifecycle of the Codeanywhere environments yet, or how to run multiple in the editor.



If you have trouble updating WordPress core or plug-ins within your account and receive a message like this:

To perform the requested action, WordPress needs to access your web server.
Please enter your FTP credentials to proceed.
If you do not remember your credentials, you should contact your web host.

Then add the following line to to wp-config to allow updates:

define( 'FS_METHOD', 'direct' );

See: https://wordpress.stackexchange.com/questions/228591/to-perform-the-requested-action-wordpress-needs-to-access-your-web-server-pleas

Setting up XAMPP for WordPress Development on Windows


I’ve spent the last 3-4 years doing my WordPress development in the Cloud9 IDE (c9.io) until Amazon AWS bought it, fucked up a perfectly good and extremely simple, usable IDe, and now shut down the original service.

I am in the process I switching over to the Codeanywhere IDE as my replacement WordPress development environment, however, I decided it’s time to setup a secondary/backup environment. And being a user of Windows I needed an WAMP (Windows, Apache, MySQL, PHP) style solution to suite.
In the past I’d tried WampServer on my secondary laptop but after leaving and coming back to it, it worked no more. Also, I found it more complicated than I wanted to configure (I hate complicated, particularly in development environments.

So this time I tried something different: XAMPP.


System/XAMPP Setup and Configuration

Setup it really easy. Just go to https://www.apachefriends.org/, select the download for you operating system (in my case Windows) and install.

For Windows do the default install, as the following screenshots show.

Step 1:

Step 2:

Step 3:

Step 4:

Step 5:

Step 6:

Step 7:

Step 8:

Step 9 (select your language – English or German):

Step 10: If you ticked “Do you want to start the Control Panel now?” in step 8 then the control panel should start and appear. Services will not start by default (there is an option for that in the control panel Config though).

See the next section for running Apache beside IIS.


Conflicts with IIS

If you have IIS installed (as many software developers with Windows will) then you will have conflicts on Port 80. The XAMPP FAQ suggests disabling IIS, but if you’re also a .NET developer like me then you most likely need IIS.

I chose to instead change the port XAMPP uses and this page – How to: Change Your Apache Listen Port Number in XAMPP – Alex Justesen – has all the information you need.

When XAMPP Control Panel first loads you will probably see the following errors:

This is the full log text:

When following the “Alex Justesen” blog post above, the following screenshot show the Apache “Config” and httpd.conf option you need to select.

The general configuration screen for XAMPP (note: I changed my editor from notepad.exe to Notepad++). This is the screen with the “Service and Port Settings” button the “Alex Justesen” post references:

The “Service and Port Settings” screen referenced by the “Alex Justesen” post. I changed “Main Port” to 8080 and “SSL Port” to 4443

Once you finish the the “Alex Justesen” post you can come back to the main XAMPP Control Panel and start Apache and MySQL using the “Start” buttons beside each service:

When starting Apache for the first time you will see the following Windows Security Alert. Select “Allow access” for the service to run:

When starting MySQL for the first time you will see the following Windows Security Alert. Select “Allow access” for the service to run:

You should now see the following success status and logs in XAMPP Control Panel after starting Apache and MySQL:

Select the “Admin” button on the MySQL line to easily open phpmyadmin (you will need this in the section “Setup WordPress”). Note it loads in localhost on your new port:

Select the “Admin” button on the Apache line to easily open XAMPP Dashboard page:


XAMPP Control Panel Shortcuts

There are no shortcuts installed to the XAMPP Control Panel (as far as I can tell), so look for xampp-control.exe in your XAMPP installation directory – likely C:\xampp if you use the default install directory.
You will need to run the .exe directly or create your own shortcut to it.


Setup Multiple Sites/Ports in XAMPP

Setting up multiple sites in XAMPP (running localhost on multiple ports) was easy.

I followed the following 2 pages:

What you nee to do:

  1. Open “C:\xampp\apache\conf\httpd.conf” (you can do this via the Apache “Config” button in the XAMPP Control Panel.
  2. Look for the line “Listen 80”. Add new Listen lines for any other ports you want to listen for (e.g. I started with 8080 to replace 80, and now I’m adding 8081).
  3. Open “C:\xampp\apache\conf\extra\httpd-vhosts.conf”.
  4. Everything will be commented out, but at the end there is a VirtualHost example like this:
    ##<VirtualHost *:80>
    ##ServerAdmin webmaster@dummy-host2.example.com
    ##DocumentRoot "D:/xampp/htdocs/dummy-host2.example.com"
    ##ServerName dummy-host2.example.com
    ##ErrorLog "logs/dummy-host2.example.com-error.log"
    ##CustomLog "logs/dummy-host2.example.com-access.log" common
  5. Copy and un-comment the entry, then adjust as needed. I created a new site root folder at “C:/xampp/htdocs/8081”, so my entry looks like:
    <VirtualHost *:8081>
        ServerAdmin webmaster@dummy-host2.example.com
        DocumentRoot "D:/xampp/htdocs/8081"
        ServerName dummy-host2.example.com
        ErrorLog "logs/dummy-host2.example.com-error.log"
        CustomLog "logs/dummy-host2.example.com-access.log" common
  6. “Stop” then “Start” Apache in XAMPP Control panel and you should be good.


Setup a DocumentRoot outside of XAMPP ‘htdocs’

I needed to the root document of a site to a folder outside the standard XAMPP installation ‘htdocs’ folder (i.e. pointing to a workspace for my source controlled files).

I followed all the steps above but received the following 2 errors when setting up another environment:

Access forbidden!
You don't have permission to access the requested directory. There is either no index document or the directory is read-protected.

If you think this is a server error, please contact the webmaster.

Error 403
Apache/2.4.39 (Win64) OpenSSL/1.1.1b PHP/7.3.5

(Resource used: https://stackoverflow.com/questions/17816732/xampp-access-forbidden-php)

and later followed by:

Object not found!
The requested URL was not found on this server. The link on the referring page seems to be wrong or outdated. Please inform the author of that page about the error.

If you think this is a server error, please contact the webmaster.

Error 404
Apache/2.4.39 (Win64) OpenSSL/1.1.1b PHP/7.3.5


(Resource Used: https://stackoverflow.com/questions/17129612/xampp-localhost-returns-object-not-found-after-installing-laravel)

To resolve the issues I ended up with the following VirtualHost configuration:

<VirtualHost *:8081>
    DocumentRoot "C:/Workspaces/my-project"
    ErrorLog "logs/8081-error.log"
    CustomLog "logs/8081-access.log" common
    <Directory C:/Workspaces/my-project/> 
        AllowOverride All
        Require all granted 

Note the <Directory></Directory> element with ‘AllowOverride’ and ‘Require’ lines. That fixed it.


Setup WordPress

Note: I have core WordPress and all plug-ins under source control.

Steps to get WordPress running:

  1. Login to phpmyadmin for MySQL. You can do this via the “Admin” button beside MySQL in the XAMPP Control Panel.
  2. Create a new database for your WordPress installation.
  3. (I tried creating a new user to user as the DB user in WordPress but couldn’t get it working, so I’m just using root in this environment.
  4. Setup your site files in the website folder. In my environment C:\xampp\htdocs is the root web folder. I created a sub-folder for my WordPress site and cloned my Git repo in there.
  5. Browser to your site. My apache is running under for 8080 and my site is in a folder called “portal”, so I browser to http://localhost:8080/portal.
  6. Go through the usual process for setting up a new WordPress website.
    1. In the screen for database settings, enter the name of the database you created.
    2. Set the username to “root” and leave password blank.
    3. Leave host name as “localhost”.
  7. Your WordPress site should be good to go!


The following screenshots show the standard setup screens for a new WordPress site.

Step 5a – Select a language:

Step 5b – Enter your database connection details. I went with the “root” user (no password) that is created when installing MySQL with XAMPP. You will need to first create a database via the phpmyadmin interface (see steps 1 and 2):

Step 5c – WordPress should now be good to setup:

Step 5d – Create your first admin user:

Step 5e – WordPress should be successfully setup:

Step 5e – And now you can login with your new admin user:



Resolving display of /var/www/html/dportal.com/wp-content/plugins/query-monitor/wp-content/db.php

After getting WordPress running I immediately started to see “/var/www/html/dportal.com/wp-content/plugins/query-monitor/wp-content/db.php” echoed to every page.

A quick search lead me to HTML Output on site migration · Issue #101 · johnbillion/query-monitor and this comment gave me the answer.

I deleted wp-content/db.php file and no more text.

As this stage I’m not sure what is going to happen when I do this for real and start working in both Windows and my Linux-based IDE.



XAMPP FAQ – https://www.apachefriends.org/faq_windows.html

How to Install XAMPP and WordPress Locally on PC/Windows – WPMU DEV

How to Troubleshoot and Fix Common XAMPP and WordPress Issues – WPMU DEV


The thing about micro-services

You might decrease the complexity of a monolithic application (I’m not actually sure that’s even a valid statement, that a “monolith application” is “complex”) but conversely you increase the complexity by adding in all the network hops, latency, asynchronicity, and having to debug strange timeout errors.

It doesn’t matter what architecture you user, you’re still going to encounter an equal number of problems to think about, debug and solve.

WordPress: Changing File Upload and Processing Sizes

[This is a post for self-reference]

Up front I’m going to say I got exactly the help I need from here: https://www.wpbeginner.com/wp-tutorials/how-to-increase-the-maximum-file-upload-size-in-wordpress/.
The author of that post deserves all my credit.

I’m creating this post to summarise it in my own words and to give it a little educational context.

When allowing file uploads on a website there are 3 big things you need to think about:

  • The size of each file.
  • The total size of all files in an upload.
  • The time it takes to process the upload.

Actually, there are a couple of things to consider that are worthy of mention but I won’t cover in this post:

  • Asynchronous uploads (AJAX as we used to call them) can change the figure of an upload, because instead of uploading multiple files at one, you upload one file at a time (even if they are in parallel) so the “total size of all files” number will be different.
  • Tell users about the limits they face before they upload. Also, when uploading images a bit of guidance around things like “27MB images are a stupid side for most sites because 27MB isn’t going to be better than 7MB, and the site will trim the size down to a couple of hundred KB at most anyway.”
  • Trap, log and respond to any errors. This is on my mind because WordPress/PHP seems to like gobbling errors and not telling anyone about it (I’m in the process of hunting down how to handle this and will be a topic of another post).


There are 3 main ways in PHP to affect file upload sizes and times:

  • @set_init() in a PHP script itself.
  • php.ini file
  • .hataccess file.

Be aware, as a PHP/Linux novice I reckon there are other defaults and hierarchies that come into play.
This article is spawned by a situation where I was changing php.ini without realising .htaccess had a value overriding it.


How do you implement these values?

This is where I rip from the wpbeginner site I mentioned above for quick reference:

1. PHP script file (e.g. functions.php in WordPress themes)

@ini_set( 'upload_max_size' , '64M' );
@ini_set( 'post_max_size', '64M');
@ini_set( 'max_execution_time', '300' );

(I haven’t tried this approach yet, but I have used @ini_set() in other instances (e.g. ‘memory_limit’) and it’s worked well.

2. php.ini

upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300

I’ve used this approach in development and it did the trick.

3 .htaccess

php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value max_execution_time 300

Before writing this post I had to fix a production issue and after trying php.ini I got lucky and discovered .htaccess was where the value was coming from.
So the moral: .htaccess overrides php.ini.

Also, I did not need to restart apache for this change to take affect.


DISCLAIMER: I haven’t actually read in-depth how all this works. I’m a typical developer who expects other people’s shit to work, and when it doesn’t I’m usually in the middle of my own concerns so it’s a case of “search and scan by keyword until someone else’s solution works for me”.
Such is this age of software development.


Need to know what your current settings are?

It’s helpful in debugging and verification to know what your actual PHP settings are so you know what your starting point is (and  you have a number to search your files for).

A good way is to call phpinfo();.

For example, create a file in your site (I call mine info.php) and add the following PHP code:


You should see something like the following when you run it. This screenshot shows some output from the section titled “Core”, and the 3 columns are (from left to right): “Directive”, “Local Value” and “Master Value”. I can say from experience the “Local Value” is the one that matters.

phpinfo() output

Change a WordPress site URL (when copying or migrating a WordPress site)

This is a post for quick reference. But given 25% (or more) of the Interwebs run on WordPress I want to give it some love too.


Moving (migrating) or copying a WordPress site has some hidden complexity.

While it is easy, there are 3 things you need to do:

  1. Copy the whole website structure, starting with the folder than contains the wp-config.php and other files (it also contains the  “wp-admin”, “wp-content” and “wp-includes” folders).
  2. Change the URL of the site as defined in WordPress (ordinarily set during setup, or within the Settings area).
  3. Update all the saved URLs within the database.

Step 3 is the real gotacha. When you add a link to another page within your site, or insert media, or set a navigation item, it saves the full URL of that item in the database.

For example, if you have a site “https://MySite.com” but want to change it to “https://MySite.com” (or as a software developer, you may want to create a copy of the production site at “https://test.MySite.com”) then after you change the actual URL of the site, all the internal links and images will still be pointing to the original MySite.com.



Many sites have covered how to change a WordPress site URL before, including the official Codex at https://codex.wordpress.org/Changing_The_Site_URL.

I like to keep things simple, so this post is my process:

  1. Backup your site database if you can (I connect directly to the database and run backup scripts, or use phpmyadmin and export).
  2. Update your site URLs by adding the following lines to the top of your active theme’s functions.php file:
    update_option( 'siteurl', 'https://MyNewSite.com' );
    update_option( 'home', 'https://MyNewSite.com' );
    1. Browser to your new site (via the IP or URL).
    2. Browse to it again and make sure it’s OK.
    3. Remove the lines from functions.php
    4. Browser to the site again one more time to make sure you can access it now you’ve removed the lines from functions.php.
  3. Upload the interconnect/it “Database Search and Replace Script” script to our site, found at https://interconnectit.com/products/search-and-replace-for-wordpress-databases/.
    1. Install it in a “not easily guessed” sub-directory of the site. This is for security reasons (so other people can’t scan and execute the scripts).
    2. Most fields are filled in. In the “search for…” enter your old URL or IP address, including “http” or “https” (e.g. “https://MySite.com” – you should be using https by now). I don’t end with a trailing forward slash.
      In the “replace with…” field enter the new URL or IP Address (e.g. “https://MyNewSite.com”). Again, not trailing forward slash.
    3. Make sure you do “dry run” to start. This should tell you if you have any problems.
    4. If all is good, do a “live run” and update your database.
    5. At the end, delete the “Database Search and Replace Script” from your site. This is important. If you leave it there bad people may find it and execute it and break your site.