When I work with web tools, I always prefer to do things the manual way; in my opinion, it’s the only approach to truly understand a process. After you master the manual process, then, you can start to automate it with other tools and services.
This is why I never trust the tools out there that “just do things”. Ok, ok, a bit generic, I understand; so let’s dive deep into what I’m talking about here.
I’m using a CentOS Linux server, so everything in this article is based on Unix systems; I’m saying this because Plesk is available for Windows servers as well.
Unix FTW
I always prefer downloading and installing my new WordPress installations without relying on ‘automatic installation tools’ built inside Plesk (or CPanel, if you like). This way, I can have 100% control on it. I know exactly ‘what is what’, why, and where, leaving the long-time maintenance without hidden corners.
Every time I want to start a new WordPress installation, I have to download the WordPress zip file from wordpress.org, configure the wp-config.php and so on.
Since I like things ‘clean and simple’, every time I clean up the wp-config.php file leaving it with just the basic info, without comments at all, and with a few hidden lines of code that, sometimes, can be handy, for example, a variety of standard WordPress directives like ‘define(“XYZ”)’.
Via command line this is not a very long process but, when you create a lot of new WordPress installations (both for clients or just testing), it’s important not to waste time in these repetitive tasks.
Let’s Automate!
I then decided to automate the process with the help of our good friend Bash scripting. Nothing very fancy, just a sequence of commands that, eventually, helped me a lot with the management of manual WordPress installation.
Here’s the list of tasks I manually do every time:
- Download WordPress zip or tgz from WordPress.org website (latest version).
- Extract the archive.
- Rename wp-config-sample.php.
- Remove all comments in wp-config.
- Add WordPress salts.
- Change database prefixes.
- Move all the files from wordpress folder to the root directory of the domain.
- Change recursively user permissions to the files according to the main domain user and group (because I’m working as a root. I know what you are thinking, but sometimes it’s just faster this way).
- Change recursively r/w permissions to be sure that everything is 644 / 755, according to the WP guidelines.
- Fill the wp-config.php file with the freshly created database name, username and password.
Done, NOW I’m ready to go to my new website page and finally start the installation of WordPress itself.
It’s clear that there’s space to improve the process.
Here, you can see the standard WordPress wp-config-sample.php file.
<?php /** * The base configuration for WordPress * * The wp-config.php creation script uses this file during the * installation. You don't have to use the web site, you can * copy this file to "wp-config.php" and fill in the values. * * This file contains the following configurations: * * * MySQL settings * * Secret keys * * Database table prefix * * ABSPATH * * @link https://codex.wordpress.org/Editing_wp-config.php * * @package WordPress */ // ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define('DB_NAME', 'database_name_here'); /** MySQL database username */ define('DB_USER', 'username_here'); /** MySQL database password */ define('DB_PASSWORD', 'password_here'); /** MySQL hostname */ define('DB_HOST', 'localhost'); /** Database Charset to use in creating database tables. */ define('DB_CHARSET', 'utf8'); /** The Database Collate type. Don't change this if in doubt. */ define('DB_COLLATE', ''); /**#@+ * Authentication Unique Keys and Salts. * * Change these to different unique phrases! * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service} * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again. * * @since 2.6.0 */ define('AUTH_KEY', 'put your unique phrase here'); define('SECURE_AUTH_KEY', 'put your unique phrase here'); define('LOGGED_IN_KEY', 'put your unique phrase here'); define('NONCE_KEY', 'put your unique phrase here'); define('AUTH_SALT', 'put your unique phrase here'); define('SECURE_AUTH_SALT', 'put your unique phrase here'); define('LOGGED_IN_SALT', 'put your unique phrase here'); define('NONCE_SALT', 'put your unique phrase here'); /**#@-*/ /** * WordPress Database Table prefix. * * You can have multiple installations in one database if you give each * a unique prefix. Only numbers, letters, and underscores please! */ $table_prefix = 'wp_'; /** * For developers: WordPress debugging mode. * * Change this to true to enable the display of notices during development. * It is strongly recommended that plugin and theme developers use WP_DEBUG * in their development environments. * * For information on other constants that can be used for debugging, * visit the Codex. * * @link https://codex.wordpress.org/Debugging_in_WordPress */ define('WP_DEBUG', false); /* That's all, stop editing! Happy blogging. */ /** Absolute path to the WordPress directory. */ if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); /** Sets up WordPress vars and included files. */ require_once(ABSPATH . 'wp-settings.php');
My Script
And here’s my script, and then I’ll explain it in detail.
Please bear in mind that I’m not a coder myself. I usually say that I can ‘handle code’; so don’t expect anything fancy at all, just a bunch of commands.
In fact, if you have any suggestion on how to improve this script, please write in the comments section.
# Download Latest WordPress archive from WP org wget https://wordpress.org/latest.tar.gz #Extract the archive showing the progress pv latest.tar.gz | tar xzf - -C . #Copy the content of WP Salts page WPSalts=$(wget https://api.wordpress.org/secret-key/1.1/salt/ -q -O -) #generate a random string; lower and upper case letters + numbers; maximun 9 characters TablePrefx=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 9 | head -n 1)_ #Copy the current directory user name WWUSER=$(stat -c '%U' ./) #Add the following PHP code inside wp-config cat <<EOF > wordpress/wp-config-sample.php <?php /***Managed by Kaiten Support - Leonardo Gandini***/ define('DB_NAME', ''); define('DB_USER', ''); define('DB_PASSWORD', ''); define('DB_HOST', 'localhost'); define('DB_CHARSET', 'utf8'); define('DB_COLLATE', ''); /*WP Tweaks*/ #define( 'WP_SITEURL', '' ); #define( 'WP_HOME', '' ); #define( 'ALTERNATE_WP_CRON', true ); #define('DISABLE_WP_CRON', 'true'); #define('WP_CRON_LOCK_TIMEOUT', 900); #define('AUTOSAVE_INTERVAL', 300); #define( 'WP_MEMORY_LIMIT', '256M' ); #define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) ); #define( 'FS_CHMOD_FILE', ( 0644 & ~ umask() ) ); #define( 'WP_ALLOW_REPAIR', true ); #define( 'FORCE_SSL_ADMIN', true ); #define( 'AUTOMATIC_UPDATER_DISABLED', true ); #define( 'WP_AUTO_UPDATE_CORE', false ); $WPSalts \$table_prefix = '$TablePrefx'; define('WP_DEBUG', false); if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); require_once(ABSPATH . 'wp-settings.php'); EOF #Now that we are good, let's rename the wp-config sample mv wordpress/wp-config-sample.php wordpress/wp-config.php #Move wordpress folder content in the current directory and remove the leftovers mv ./wordpress/* ./ && rm -rf latest.tar.gz && rm -rf ./wordpress #Apply the definer user name to all the new freshly created wordpress files, plus the group (here the main on for Plesk Virtual Hosts) chown -R $WWUSER:psacln ./* #Just to be sure, let's fix files and directories permissions find . -type f -exec chmod 644 {} \; find . -type d -exec chmod 755 {} \; #Fancy message with colored background echo "$(tput setaf 7)$(tput setab 6)---|-WP READY TO ROCK-|---$(tput sgr 0)"
Here we are, so let’s start from the beginning of the script, this is what happen.
With wget, download the tgz and extract it with pv command to show the progress.
Define a WPsalts variable which copies the content of the WordPress salts page (if you don’t know what I’m talking about, then you want to read this article).
Define a variable called TablePrefx to change the default wp_ prefix of WordPress database tables, for security reasons. It creates a random string of no more than 9 characters and numbers, plus an underscore ‘_’ at the end.
Creates a variable called CDUSER, and copies the current directory owner username (I’ll come back to this later).
Now with the useful command <<EOF EOF, I first define which file I want to target, and the content I want to insert in that file. In this case, I want to add a predefined wp-config.php file, with variables inside, and compile it.
In case you missed it, the line \$table_prefix = ‘$TablePrefx’; has a \ at the very beginning to escape the character $. This is because we want the $ sign rendered in the resulting file because it’s a WordPress variable itself.
After this part, the script just moves the content of the wordpress directory to the main (current) directory of the website and cleans leftovers.
Now, the files permissions. The script applies recursively, to all files and directories, the default WordPress permissions (just to be 200% sure that everything will be fine!) and also applies the previously defined user and group.
In my case, the group will always be the same: psacln; since this is the standard one used by Plesk; based on your server this value can vary (it can be Apache or httpd), anyway the good old ls -ls or stat . command can tell you this information.
Finally here’s the resulting wp-config.php file: clean, simple and ready to be filled with database information.
Resulting File
<?php /***Managed by Kaiten Support - Leonardo Gandini***/ define('DB_NAME', ''); define('DB_USER', ''); define('DB_PASSWORD', ''); define('DB_HOST', 'localhost'); define('DB_CHARSET', 'utf8'); define('DB_COLLATE', ''); /*WP Tweaks*/ #define( 'WP_SITEURL', '' ); #define( 'WP_HOME', '' ); #define( 'ALTERNATE_WP_CRON', true ); #define('DISABLE_WP_CRON', 'true'); #define('WP_CRON_LOCK_TIMEOUT', 900); #define('AUTOSAVE_INTERVAL', 300); #define( 'WP_MEMORY_LIMIT', '256M' ); #define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) ); #define( 'FS_CHMOD_FILE', ( 0644 & ~ umask() ) ); #define( 'WP_ALLOW_REPAIR', true ); #define( 'FORCE_SSL_ADMIN', true ); #define( 'AUTOMATIC_UPDATER_DISABLED', true ); #define( 'WP_AUTO_UPDATE_CORE', false ); define('AUTH_KEY', '(7X!tvzGF&/Aqk9:/lNQn=r_{4X&6.s-Sw`bekb-esb)}.wGt_nW`+W+jFUnSG+n'); define('SECURE_AUTH_KEY', 'ajNH;M@~!Vv|G1x}Ybo_}-vf`R-S*$-#:77+/pMJRrsUDkG~Nw$uy+gYCstPb ?_'); define('LOGGED_IN_KEY', '$TgP-- fL6YT`Z]XX5-ejH^d1k~S>kFlQKTa*7A%MSQpbzLaUZ,ko8AF>-Z4f}t='); define('NONCE_KEY', 'MuIe-$cF|mG;1||_F*g_I]SvYR9fo1A@bAk(cky{iFVD@6_fmkQpVkiYO-K,tcB)'); define('AUTH_SALT', '=BGErN{T;--3b**/M;`kw-s~z*}PMC-5`j1r7|x~69_WlA`uUDC*/f^IYc+%e=+u'); define('SECURE_AUTH_SALT', '+]+%:6VSvOT7bn.-n,gDXOA*L~/aol763v]|9^vR0ToD}b<weG0Pqn<Hjb(excOg'); define('LOGGED_IN_SALT', 'J*^=CXb,Yg~{~!M|$SX|NmFo~XWcx6+{q]!`ECXF27m#`fK=R)7wZXtB`]E~'); define('NONCE_SALT', '?X=!$>O}/|GYd-G-O-d{l++1[;a D1?GTTNLs}R+c$([+>jlgnu<!r`949mDXIL~'); $table_prefix = 'rodnfcEBG_'; define('WP_DEBUG', false); if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); require_once(ABSPATH . 'wp-settings.php');
As I previously said, this is very basic stuff and there are many ways to improve this code. However, until now, this script served me well.
Every time I have to install a new WordPress, I’m ready to go in seconds, knowing that the wp-config.php is clean and easy to manage and to maintain in the future.
I hope you find it useful, I ‘d like to hear your ideas to expand and optimize this script. Feel free to leave a comment here or on GitHub Gist.
Also, here’s the script in action, just because GIF! 😉