How I Automate My Local Development Craft CMS 2.x Installs

I tend to experiment a lot when it comes to building Craft CMS sites and part of that is setting up a lot of various sites on my local machine while I’ve learned the platform over the years. After a few though it can feel a little bit tedious to download, delete unneeded files, and create the local database for the project. So after awhile I decided to automate the process.

I should note that at this point there are several ways people have solved this problem, including nystudio107’s Yeoman generator which is incredible. For me, a simple bash script on macOS has been enough and it might be enough for you too.

An Overview of What I Wanted

At the core of the script I wanted to be able to do the following:

  1. Create the project folder
  2. Download the latest version of Craft into that folder
  3. Delete the readme.txt file
  4. Rename the htaccess template to .htaccess
  5. Delete the unneeded web.config and other .htaccess files
  6. Set the folder permissions on craft/app, craft/config, and craft/storage
  7. Create the local database with the same name as the project

For some, #5 might not be necessary as web.config is used by IIS as their version of the .htaccess file. Additionally, I don’t have my /craft/ folder as a web accessible folder so deleting those additional .htaccess files was more just about removing the excess.

Creating the Project Name

There were two ways I wanted to accommodate creating a project name. Either passing a single argument into the bash script like craft projectname. Alternatively, I wanted to make the argument optional if I was already in the project folder, to instead take the current folder’s name.

Arguments are passed into bash scripts as $ values so the first argument is $1 and the second is $2 accordingly. You can also check the number of arguments using $#. So here’s what I started with:

if [[ $# -eq 0 ]]; then
elif [[ $# -eq 1 ]]; then
mkdir $project && cd $project
echo "Usage:"
echo -e '\tType "craft [project]" to create [project]'
echo -e '\tType "craft" within a blank project folder'
exit 1

If there are no arguments, the project variable is assigned the current folder name. Else if there is only a single argument that value is used to create a project folder which the script then sets as the active directory. If you try to pass more than one attribute you’ll get usage instructions.

Downloading and Unzipping Craft

Next in the script I download Craft with wget and unzip it into the folder we’re in.

wget -O
unzip -q
echo " ✅ Craft CMS Downloaded"

Passing -q through unzip means the output for the zip file won’t display. When it’s finished it’ll delete the zip file.

Removing Unnecessary Files and Renaming htaccess

This is a fairly simple part of the script. We just delete the files we don’t want, delete the template folder, and then make a new blank template folder ready for our own templates.

# Remove the readme file
rm readme.txt
# Rename the .htaccess file and cleanup unnecessary files
mv public/htaccess public/.htaccess
echo " ✅ Renamed .htaccess file"
rm public/web.config
rm craft/web.config
rm craft/.htaccess
rm craft/config/web.config
rm craft/config/.htaccess
rm craft/plugins/.htaccess
rm craft/plugins/web.config
rm craft/storage/.htaccess
rm craft/storage/web.config
rm -R craft/templates/
mkdir craft/templates/
echo " ✅ Removed unneeded files and emptied templates"

Setting Folder Permissions

Based on the Craft CMS installation instructions three folders should have their permissions set. Since I’m working locally I set the permissions for the same group using 774. Check Craft’s installation instructions to find the permissions that work best in your situation.

# Setup file permissions
chmod 774 craft/app/
chmod 774 craft/config/
chmod 774 craft/storage/
echo " ✅ Set Craft CMS folder permissions"

This works great for my local development environment, but for a much more significant write up on Craft permissions, see nystudio107’s article on Hardening Craft CMS Permissions.

Creating the MySQL Database

I’m usually using MAMP Pro locally, but if you have a local installation of MySQL this process still works just fine.

echo "-----------------------------------"
echo "Please provide your MySQL password."
echo "-----------------------------------"
/Applications/MAMP/Library/bin/mysql -u root -p -e "CREATE DATABASE \`$project\` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci;"
echo " ✅ Database for '${project}' created"
echo " ✅ Your project has been created"

This calls the mysql command available within MAMP and passes the appropriate attributes to login and create the new table using utf8_unicode_ci. When I pass in the $project variable though, I escape the input. This way if I name my project project-name there won’t be an error because of the hyphen. This is done with backslashes and backticks.

See the full Gist for the script on Github ➡️.

Running the Script

I save my script within my Dropbox account in a folder specifically for my setup information named Once it’s saved you’ll want to make sure the script is executable by running chmod +x on it within the terminal. Then I create an alias for the script within my .bash_profile using something like:

alias craft='[fullpath]/'

Where [fullpath] is changed to the actual full path of the file.

Once that’s done, I just setup the project within MAMP Pro or whatever server I’m running, adjust the connection details in craft/config/db.php, and I’m ready to go.

Running the script in real-time

Custom Additions

While that concludes the core of the automation, there are a few other things I’ve done that help me specific to my workflow. First I have a zip file with all of my core templates, Sass files, and custom changes to the Craft configuration files. The zip file has a craft folder and a public folder that mimic the directory structure with the files I’m looking to replace the default files with. Additionally, I include a package.json and gulpfile.js to be placed at the root folder of the project.

- craft
|-- config
|-- db.php
|-- general.php
|-- templates
- public
|-- assets
- gulpfile.js
- package.json

That zip file is stored on a shared Dropbox folder for anyone within the team to access it.

I then add a few lines to my script that look something like this:

wget -O
unzip -o
echo " ✅ Templates installed"

Using the -o option this time I overwrite any files within the local directory with those in the zip file. Finally I wrap up the installation by running Yarn (or NPM if that’s your jam), loading Sublime Text, and running the default gulp task (which is the watcher).

yarn install
subl .

So that gives me a full setup with all of my default prototyping templates, gets all the NPM packages installed and launches gulp. I’m left with my text editor open and ready to go.

Show your support

Clapping shows how much you appreciated Tim Knight’s story.