Sometimes FTP is your only option
In a world where we have such amazing tools like WP-CLI it’s hard to imagine why you’d want to attempt scripting over FTP. WP Engine doesn’t allow SSH access and FTP was really the only option if I wanted to automate things with their service.
One time use mu-plugins
It all starts with a mu-plugin. A mu-plugin or must use plugin is a great way to force some php code to run on a website. All you really need to do is upload a php file to the wp-content/mu-plugins
folder and on the next web request WordPress will auto-activate and run the code.
Must use plugins are special and can not be deactivated through normal means. They appear under a section called Must-Use on the plugins page.
Deploying code with bash script
All of these actions can be automated with a bash script. The following will push a mu-plugin to a web server, run the code, then delete the file. I’ll call it deploy.sh
.
#!/bin/sh
#
# Deploys one time use mu-plugins on remote server via FTP
# Script/deploy.sh
#
### FTP Information
domain=example.com
username=example
password='randompassword123'
ipAddress='example.wpengine.com'
protocol='sftp'
port='2222'
### Configs
mupluginpath=/home/Tmp
muplugin=anchor_load_configs.php
lftpprep='set sftp:auto-confirm yes;set net:max-retries 2;set ftp:ssl-allow no'
### Uploads plugin to mu-plugins
sudo lftp -e "$lftpprep;put -O /wp-content/mu-plugins/ $mupluginpath/$muplugin; exit" -u $username,$password -p $port $protocol://$ipAddress
### Trigger website to run mu-plugins
wget --no-cache --spider $ipAddress/wp-login.php
### Removes plugin
sudo lftp -e "$lftpprep;rm /wp-content/mu-plugins/$muplugin; exit" -u $username,$password -p $port $protocol://$ipAddress
If you can code it in PHP you can do it over FTP
By wrapping custom code into a mu-plugin you can accomplish anything possible in PHP with a FTP deployment script. The following is a static example of a mu-plugin which will do the following.
- Conditionally adds a new admin account if not already created
- Send an email with link to set password
- Conditionally remove default WP Engine admin account if new admin account created and account corrosponding to the install name is found
- Conditionally remove site title if WP Engine’s defaults are detected
- Conditionally remove site description if WP Engine’s defaults are detected
- Sets timezone to New York
This one is called anchor_load_configs.php
.
<?php
### Patch fix email notifications in WordPress 4.6
add_filter( 'wp_mail_from', function( $email ) {
$site = get_site_url();
$parse = parse_url($site);
$email = "wordpress@". $parse['host'];
return $email;
});
function add_admin_acct(){
### Required in order to use wp_delete_user function
require_once(ABSPATH.'wp-admin/includes/user.php' );
global $wpdb;
$tablename = $wpdb->prefix . "users";
### Check for default WP Engine site name and description
if (get_option( "blogname" ) == "Austin Ginder Blog") {
## Update default site title
update_option( "blogname", "installname.wpengine.com" );
}
if (get_option( "blogdescription" ) == "Your SUPER-powered WP Engine Blog") {
## Update default site description
update_option( "blogdescription", "" );
}
if (get_option( "timezone_string" ) == "") {
## Update default time zone
update_option( "timezone_string", "America/New_York" );
}
### Generating primary admin account
if ( !username_exists( "anchorhost" ) && !email_exists( "support@anchor.host" ) ) {
$userdata = array(
'user_login' => 'anchorhost',
'user_email' => 'support@anchor.host',
'display_name' => 'anchorhost',
'first_name' => 'Anchor',
'last_name' => 'Hosting',
'user_nicename' => 'anchorhost',
'nickname' => 'anchorhost',
'role' => 'administrator'
);
$user_id = wp_insert_user( $userdata );
}
### Sending email for primary admin account
if ($user_id) {
wp_new_user_notification( $user_id, null, 'user' );
### Check for default WP Engine account
$user = get_user_by( 'login', 'installname' );
### If found remove and reassign pages/post to new admin
if($user) {
wp_delete_user( $user->ID, $user_id );
}
}
$user_id = null;
}
add_action('init','add_admin_acct');
?>