Quick WordPress install with WP-Cli & Shell Script

I’ve recently been trying to automate more of development process. As a developer you know that you have these powerful skills and you should use them to a greater level to make your life easier. The problem is that it’s often hard to justify taking the time to do this if you’re already on a tight timeline. Needless to say I’ve finally created something that is helping remove 20-30 minutes from my developments.

I’ve been using the Vagrant repository Scotch Box for a while now. It is amazing! It’s a full LAMP stack with heaps of necessary included software. This includes Grunt, Gulp, Bower, Mailcatcher and WP-Cli (plus heaps more without being bloated). WP-Cli a great tool that allows you to run command line queries at your WP installs. I’d began using this plus a good old fashion text file of frequent install commands to speed up my process. It was finally this week that I put it into a script that I could easily run and have an install up in under 1 minute (it could be less if you have better download speeds).


#!/usr/bin/env bash

#  Take User Inputs
read -p "Database name: " db
read -p "Site URL: " url
read -p "Site title: " title
pass=$(date +%s | sha256sum | base64 | head -c 32 ; echo)

# Start Install
mkdir /var/www/public/$url
cd /var/www/public/$url

# Download WP and Config
wp core download
wp core config --dbname=$db --dbuser=root --dbpass=root
wp db create
# Run WP Install
wp core install --url=$url --title="$title" --admin_user=my_admin_user --admin_password="$pass" --admin_email="morganl@6cm.com.au"

# Add and Remove Base Plugins
wp plugin install admin-menu-tree-page-view contact-form-7 akismet advanced-custom-fields
wp plugin delete hello

# Delete installed posts and create homepage
wp post delete $(wp post list --post_type='page' --format=ids) --force
wp post delete $(wp post list --post_type='post' --format=ids) --force
wp post create --post_type='page' --post_title="Home" --post_status="publish" 
wp option update page_on_front 3
wp option update show_on_front page

# Replace Uncategorized with a new Category as default
wp term create category News
wp option update default_category 2
wp term delete category 1

# Set Your Timezone - Most of you will want to change this
wp option update timezone_string Australia/Perth
wp option update blogdescription ""

# Options checkboxes the way I like them
wp option update default_pingback_flag 0
wp option update default_ping_status 0
wp option update default_comment_status 0
wp option update comment_registration 1

# Update rewrite (You'll still need to resave the Settings > Permalinks Page)
wp rewrite structure '/%year%/%monthnum%/%postname%'

# Copy base theme to site
cd wp-content/themes/
git clone https://github.com/morganleek/scm-wp-base.git
mv scm-wp-base 6cm
wp theme activate 6cm

# Create necessary Apache configs
cd /etc/apache2/sites-available/
sudo cp default.conf $url.conf
sudo sed -i "s/localpress/$url/g" $url.conf 
cd ../sites-enabled/
sudo ln -s ../sites-available/$url.conf $url.conf
sudo service apache2 restart

# Update /etc/hosts - You'll need to do this manually for your own machine
sudo sed -i "s/#addmore/$url #addmore/g" /etc/hosts

# Spit out username and password details
echo ""
echo ""
echo "CMS"
echo "---"
echo "User: my_admin_user"
echo "Pass: $pass"
echo ""

In addition you’ll also need to update your /etc/hosts file once to allow the script to add the new domain to your list of local sites. This usually just means adding #addmore to the end of your localhost domains list. localhost mysite anothersite #addmore

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts scotchbox scotchbox

Remove WordPress Theme Update Notifications

I’ve built and maintain many WordPress websites. I really love WordPress’ ease of update, however having to maintain these sites I greatly dislike the constant theme updates. I understand the need to update themes you use, but why do I need to download a new Twenty-x theme every 12 months?

In an effort to lighten my work load I went in search for a quick fix but came up empty handed. A quick poke through the WP core showed a handy filter I could change to quickly get my desired result.

Unfortunately because this is admin core functionality it needed to be in a plugin. If you have a base theme plugin add this to that, otherwise use as is.

 * @package Remove_Theme_Updates
 * @version 1.0
Plugin Name: Remove Theme Updates
Plugin URI: http://morganleek.me/
Description: Remove annoying theme updates from WordPress. Don't use if you need your themes automatically updated.
Author: Morgan Leek
Version: 1.0
Author URI: http://morganleek.me/

add_filter('site_transient_update_themes', 'remove_update_themes', 100, 1);

function remove_update_themes($value) {
    return null;


Advanced Custom Fields and Woocommerce Location Rules

Just a short post about a Git I’ve started up. I recently needed to specify a couple of ACF fields to only appear on a ‘Simple Product’ type in ever popular Woocommerce. To my surprise there wasn’t an existing plugin that extended ACF location rules to integrate with Woo attributes. So I went about writing my very own. Recently deciding I wanted to give more back to the community that gives so much to me I stuck it up of Github.

I will continue to add attributes over the next few weeks. At the time of writing this post I currently have support for the following attributes.

  • Product Types (Simple, Grouped, External, Variable)
  • Product Variations (Downloadable, Virtual, Sold Individually)
  • Product Taxation (Product Taxable, Shipping Taxable)

Please download and comment on the Git should you find any issues. Also please make suggestions for additional features in the issues area.


Shopp Plugin Pinterest Rich Pins

Pinterest’s Rich Pins are a great way for clients to link their shopping cart products more deeply with Pinterest. It allows additional information like price, availability and location to be attached to the pin. I recently had a request to integrate the rich pins into a website and discovered no quick cut and paste solution for my clients (less popular) e-commerce WordPress plugin Shopp. Rich Pins essentially use Facebook’s Open Graph standard to implement the pins, so it didn’t seem like it was going to be a huge process. All the same I thought I’d share it here in hope of saving someone else a few minutes in the future.

Just to note unlike Facebook or Twitter this data will only be referenced once you clear your Rich Pin setup with Pinterest. A member of their team will visit your site and ensure they are set correctly. For more information about this and validating your Rich Pin pages see the Pinterest Rich Pin overview.

You’ll also need to manually set the currency, using the three letter codes available on XE. In my example the currency is set to AUD for Australian Dollars.

// Pinterest OG Tags            
if(function_exists('shopp')) {
    add_action('wp_head', 'shopp_rich_pins_head', 10);

    function shopp_rich_pins_head() {
        // Only run on product pages
        if(shopp('product.found')) {
            print '<meta property="og:type" content="product" />';
            print '<meta property="og:url" content="' . shopp('product.url', 'return=true') . '" />';
            if(shopp('product.has-images')) {
                print '<meta property="og:image" content="' . shopp('product.get-cover-image', 'property=url') . '" />';
            print '<meta property="og:title" content="' . shopp( 'product.name', 'return=true' ) . '" />';
            // Check if price is on sale
            if(shopp('product','onsale')) {
            	// Pinterest treats the 'ammount' as the regular price 
	            // or the sale price if the item is on sale.
            	print '<meta property="og:price:amount" content="' . shopp('product.saleprice', 'number=true&return=true') . '" />';
            	print '<meta property="og:price:standard_amount" content="' . shopp('product.price', 'number=true&return=true') . '" />';
		    else {
		    	print '<meta property="og:price:amount" content="' . shopp('product.price', 'number=true&return=true') . '" />';

            print '<meta property="og:price:currency" content="AUD" />';
            print '<meta property="og:site_name" content="' . get_bloginfo('name') . '" />';
            print '<meta property="og:availability" content="instock" />';
            print '<meta property="product:gender" content="unisex" >';

Australia States & Territories Select Drop Down List

This is a quick one, possibly for my benefit more than anyone. Pretty tired of recreating select lists of the Australian states and territories when building forms. Also thought I’d include a couple of variations as we’ve really got a heap of territories you’re not always going to want.

<!-- States & Territories by Size -->

<select name="state">
	<option name="nsw">New South Wales</option>
	<option name="vic">Victoria</option>
	<option name="qld">Queensland</option>
	<option name="wa">Western Australia</option>
	<option name="sa">South Australia</option>
	<option name="tas">Tasmania</option>
	<option name="act">Australian Capital Territory</option>
	<option name="nt">Northern Territory</option>

<!-- States & Territories Alphabetical -->

<select name="state">
	<option name="act">Australian Capital Territory</option>
	<option name="nsw">New South Wales</option>
	<option name="nt">Northern Territory</option>
	<option name="qld">Queensland</option>
	<option name="sa">South Australia</option>
	<option name="tas">Tasmania</option>
	<option name="vic">Victoria</option>
	<option name="wa">Western Australia</option>

<!-- Complete List of States & Territories Alphabetical -->

<select name="state">
	<option name="aci">Ashmore and Cartier Islands</option>
	<option name="aat">Australian Antarctic Territory</option>
	<option name="act">Australian Capital Territory</option>
	<option name="ci">Christmas Island</option>
	<option name="ki">Cocos (Keeling) Islands</option>
	<option name="csi">Coral Sea Islands</option>
	<option name="himi">Heard Island and McDonald Islands</option>
	<option name="jb">Jervis Bay Territory</option>
	<option name="nsw">New South Wales</option>
	<option name="ni">Norfolk Island</option>
	<option name="nt">Northern Territory</option>
	<option name="qld">Queensland</option>
	<option name="sa">South Australia</option>
	<option name="tas">Tasmania</option>
	<option name="vic">Victoria</option>
	<option name="wa">Western Australia</option>

Theming WordPress Login Page


This is a pretty basic one, often covered on the internet. However today I wanted to record a video more about working out how to solve problems such as these when a Google search doesn’t help. The video discusses the process of locating hooks to make changes to the WordPress core functionality, and making them persistent even after updates.

For all those looking for the code or just want to know a quick way to theme the WP-Login page the code is below.

You’ll need to add the following source to your themes functions.php file.

// filter for altering the login pages WordPress image link url
add_filter('login_headerurl', 'html5_login_headerurl', 10, 1);

function html5_login_headerurl($url) {
    return __('http://morganleek.me');

// filter to enqueue addition css stylesheet
// to overwrite WordPress default image
add_action('login_enqueue_scripts', 'html5_login_enqueue_scripts');

function html5_login_enqueue_scripts() {
	// you'll need to change the location below if your style
	// sheet is located elsewhere
    	get_template_directory_uri() . '/css/admin-style.css', 
    wp_enqueue_style( 'html5_admin_css' );

Finally you’ll need to create and new logo and place it in your themes image folder. In this case my image folder is call ‘img’ and my logo is called ‘new-brand.png’. You’ll also need to create an admin style sheet to place the css in. This style sheet is the one references in the functions file above.

.login h1 a {
	background-image: url('../img/new-brand.png');


Creating administrator user in WordPress with only FTP details (Updated)

I seem to have recently gained a number of clients who were very keen for work to be completed due to bad communication with their previous developers. This usually meant that anything they’d ask for wouldn’t be received for some time. This raises a dilemma in that these clients almost always don’t have all the login info you need.

Today I wanted to grab a backup of a site and all I had was the sites FTP and the clients WP login with insufficient privileges to manage plugins. Easy enough to solve with the little snippet below.

    require('wp-load.php' );
    $username = "my_admin";
    $password = "StrangePassword123!";
    $email = "email@example.com";
 	// create user and return new user id
 	$id = wp_create_user($username, $password, $email);
 	// check create for WordPress error
    if(!is_wp_error($id)) {
    	// update users role to admin - this can't be done on the create
        wp_update_user( array ('ID' => $id, 'role' => 'administrator'));
        print 'User successfully created';
    else {
    	// print WordPress error
    	print $id->get_error_message();

Just fill in your user, pass and email and you’ll be set. You’ll also have to changed the path to wp-load.php depending on where you place this script. Also as a good safety measure don’t forget to delete it when you’re done.

Created myself and user and backed up using BackupBuddy. Easy.

Updated: I updated the code to give more useful error messages.


Hulu + AppleTV + Australia

Recently the quality of Usenet has gone quite far down hill. Despite being the oldest service for obtaining TV content I can think of, it seems it’s finally no longer small enough to go under the radar of big TV networks. So I’ve been looking for alternatives as of lately.

Having had a quick search around I noticed that Hulu were showing a majority of the TV shows I was getting from alternative sources throughout the internet. Hulu also comes standard on the AppleTV. The problem is that I’m in Perth in Western Australia and the service is limited to those users inside the United States. I knew this was not the most difficult thing to overcome. All I needed was decent and affordable VPN service. I looked around the forums and it appeared StrongVPN were sounding the most liked and recommended provider. They offer a massive range of account types as well as servers and locations to choose from.

So I’d overcome the first hurdle and now had a computer that appeared to be in the US. The issue was that usually to run a VPN you use software and this option was not available to me on the AppleTV. One choice would be to buy a VPN enabled router, however this can be expensive and often means you need to run all your Internet traffic through the VPN or select IPs and domains to route. The second and much better choice is to buy a router that can have the DD-WRT software installed on it. DD-WRT is a special Linux based firmware written for many popular routers. Most routers are far more powerful than the poor quality firmware they’re included with. With this option you flash a second routers firmware to be DD-WRT and have it physically connected to primary router/modem. Any device you want to run through the VPN would be connected DD-WRT router and the rest of your computers remain untouched and connected to existing router/modem. You can buy reloaded DD-WRT routers from their own website and even StrongVPN. I was pretty keen to get this whole thing going so I just checked the available range at my local OfficeWorks against the compatiable router list on the DD-WRT website. I picked up a WNR2200 for $100 AU (about $100 US).


Flashing the router was as easy as downloading the software from DD-WRT and using the wizard to update the firmware in the routers management page. Once you’ve done that you simply need to set the WAN settings to those specified to you by StrongVPN. This is actually the only place I had any trouble. StrongVPN have a page on setting up PPTP on your DD-WRT router however their written and video descriptions differ greatly. This ment playing with the settings until they worked. Find below my settings that worked for me. The most important parts were having all three DNS set, PPTP encryption disabled and remembering to reset the router after changing the details.


Hurdle two and perhaps the biggest is Hulu payment. As a second line of defence from people like myself, Hulu won’t let you use a non-US credit card for your payment. Game over you might think (as did I), but not the case.


Just like everything these days, Hulu offer gift cards. How you get these cards is the next difficulty, because unfortunately I don’t have a wonderful solution yet. I got mine when I was just in the US (not a great solution you say). I’ve not tried it but there are some people selling the cards on eBay. As it’s untried BUYER BEWARE! If you do want to buy it this way I’d suggest making sure you get sent a scan of the card number and not just a number in an email as a string of characters (to ensure they’re not just generating the numbers somehow). The seller does appear to have good feed back though. Also ensure you create your account using Facebook and then it won’t ask you to initially enter a credit card.

That’s it. Sit back and enjoy your shows. One other thing to note is the server location on StrongVPN. They tell you to use the closest geographical location to yourself. For me that was the San Fran servers, however they let you do speed tests and I found the NY servers to be much, much quicker for me so I switched and have had no problems at all with buffering now.


WordPress Metadata Media Naming

A client of mine recently ran into a problem. He had a large number of professionally shot photography for his business. Over the years he had gotten into the good habit of renaming his photos so they were easy to manage. The problem was that WordPress’ media manager was naming the photos using metadata that had been attached to the images by the DSLR that shot them. In his case all images where being called ‘SONY DCR’. I essentially needed to remove the metadata title when the image was uploaded so WP wouldn’t use it as the title. After some searching I found exactly what I needed in wp_read_image_metadata.

add_filter( 'wp_read_image_metadata', 'custom_upload_name' );  

function custom_upload_name( $file )
    $file['title'] = "";

    return $file;

Pretty simple solution, but it works nicely. Just add this to your functions.php file.

Random Password Generator for MacOS 10.7

I recently downloaded from the App Store a wonderful tool called Little Ipsum. Simple system tray based app that would allow you to quickly and easily generate 1-3 words, 1-3 lines or 1-3 paragraphs of Lorem Ipsum. This was quite handy as my previous process was opening a new browser tab and heading to HTML-Ipsum, which is still an incredibly handy website but just too slow a process.

This got me thinking of other processes I frequently use websites for that could be replaced by a simple System Tray app. So I went looking for a random password generator. I generate a lot of passwords throughout the day. Some tools (I.e PHPMyAdmin) provide wonderful password generators inline, where as many others don’t. Sadly I couldn’t find anything as simple as I wanted on the App Store, so I saw this as an opportunity to brush up on my Cocoa coding skills. I honestly had not touched Xcode in 5-6 years, but this seemed like a simple enough project to get my hands dirty.

So a couple of hours later, most of which was spent watching Youtube user AppleProgramming super helpful videos I had my app. As simple as it is I haven’t greatly tested it, but it all seems to be working well. My only issue remaining is the Preferences window doesn’t seem to display at the front when initialised, but that’s not the end of the world.

6CM Password Generator 1.0 for MacOS 10.7 (47kb)