WordPress Customization for Open Planet Culture

I am just wrapping-up a second sprint for a customized WordPress site called Open Planet Culture: Re-Thinking Globalization.

The code is on Gitlab and unfortunately I had to make private the theme as its got hard-coded Mapbox API keys.

It’s been an interesting experience pushing the envelope for myself and WordPress and I’ve tried to use a lot of the latest trends (for better or worse) in web-development.


The site is developed and hosted in the Roots.io WordPress devops platform. Overall I must say this platform is super impressive. The list of Roots.io features is long.

I wrote a long detailed post about my Composer and GIT repo based workflow for Roots. I am dev’ing on Mac Sierra.

  • Composer for PHP package management, including WordPress itself
  • Ansible, Vagrant and NFS for local virtual machine dev environment, staging and production
  • Ansible for staging and production server deployment and possibility to add more environments
  • Ability to add multiple sites within a single repo
  • Deployment versions and ability to roll-back
  • Yarn for npm package management
  • Browsersync for live-reload in development between devices
  • GIT based code workflow
  • Sage 9 theme is based on Bootstrap 4
  • Blade template engine from Laravel
  • Awesome Discourse support forums
  • Ansible Vault encrypted secrets

If I do more with Roots.io I’d actually try to contribute a back-up Ansible play / role. i.e. use WP CLI to do a backup/export of the live database, and rsync that back to a backup. This might be combined or separated into a second role that makes a kind of hot-spare live site on a low-spec server.

Bootstrap 4 for Material Design by Daemonite

I used the Bootstrap 4 for Material Design SASS framework for the styling. This allowed me to use some of the Material Design niceties like the Wave Javascript effects for buttons i.e. that organic ripple effect. Of course the cards are nice also and becoming a kind of UI standard.

It also allowed for using Bootstrap 4 conventions such as flex-box. On the homepage and video template pages, the narrow screen display doesn’t include the video. No need to download a 100+ mb mp4 or mov file when on a mobile. This was handled by Bootstrap breakpoints and the extensive classes handling responsiveness.

Custom WordPress Post Types

Having worked a lot with Drupal I wanted to explore the WordPress custom post type features. I wanted to do as much from code and use as few plugins. I created 6 custom post types i.e. Solutions, Problems, Actions, Learnings, Nation States and Places. I also created two custom taxonomies i.e. Scale and Topics.

These custom post type definitions are in a WordPress plugin on Gitlab.

CMB2 for Custom Metaboxes and custom fields

ACF is great, but the developer experience is via the web UI and then you export to JSON. I wanted a code first approach. I found CMB2 Custom Meta Boxes 2 via a blog post by Bill
Erikson (creator of the WordPress Genesis Framework) and used that to create custom metaboxes and custom fields for Places.

I created another sub-plugin, within the plugin package, for Metaboxes and Custom fields.

Automated Data Feeds

I started work on a few different ways to programmatically create posts from JSON and CSV.

In a raw stage of development, in dev, I enabled a plugin that on cron every hour takes Earthquake news and creates posts from a JSON feed.

I have another experiment taking REST Countries JSON feed and auto creating Nation State posts.

In production, is a plugin that programmatically creates Place post types from the City List from Open Weather Map.

This custom code is still raw, but inserts a new post and also updates the meta fields for Long and Lat and also Country Code.

I need to do more helper functions i.e. check if post exists and if so update and not insert etc.

I think also it needs to be batched so it can handle imports of 200,000 places. I think its timing out.

Custom Mapbox Maps

The Places custom post type uses the Long/Lat data to call the Mapbox API via their Javascript widget and each place has its own map.

I tried to make the map style kind of bold and abstract like the overall style of the site.

Each Place also calls the Mapbox Static API and has a PNG image of the place from a regional perspective.

I’d like to make my own map server. Ultimately I think I need to if I am going to do anything at scale. Otherwise I will end up spending quite a bit of $ on Mapbox.


Its becoming very common to see the use of the video tag. Palantir, Paypal, Cloudflare, Globalchange.gov etc etc.

Through quite a bit of trial and error I implemented a custom full width WordPress video template for the front-page and Pages, that displays a static image for mobile devices. The front-page also has a large rotating planet video which is visually stunning. Thanks NASA!

I must admit for the first few days I was kind of mesmerized by this effect.

Transparent Megamenu

I used the WordPress Megamenu fremium plugin and made it transparent and integrated with the jumbotron image and video header.

There is a lot that can go into the megamenu, I started on the Earth megamenu section. A megamenu can become a key element of a site.

Animated CSS

I used animate.css, but backed out of that for now, I was getting awkwards sideways scrolling-off-screen side-effects.

I will implement some kind of CSS animation with either that jQuery or perhaps CSS keyframes or SVG animation. Maybe D3.js.


Not sure when I will next get a chance to work on this again. But I’d like to add the custom fields for Places to the REST API and then use the Ember WordPress library to create a rich interface to places. Perhaps I will implement the interactive App aspect of the site with Ember JS.

I’ve been searching around and doing some small experiments and have decided that Ember JS and jQuery are good bets. React JS is fragile and fragmented and I don’t like the Patent additions. AngularDart looks great but again I don’t want to deal with Patent additions. Elm is interesting, and I’ll maybe try something with it, but there are no big commercial free software examples. Whereas Ember has Discourse and a number of projects.

Hosting by Prgmr.com

The VPS is a XEN vm by Prgmr.com is Santa Clara. They ROCK !

WordPress Roots.io and Semantic UI Sass

After building a custom theme with Understrap and Material Design for Bootstrap 4 I wanted to quickly, i.e. within a few days, build a WordPress site using the Roots.io framework and Semantic UI.

Semantic UI has a community ownership model i.e. its not Facebook, or Google or Twitter or Microsoft and has ports into NPM, gems, Elm, Ember etc

Assign Domain OpenPlanetCulture.com

The website domain will be Open Planet Culture, openplanetculture.com. The idea for this project is a site about the planet Earth, but without the New Age baggage of Gaia Hypothesis and hopefully more accessible to the science on the subject. I want to try to use language that bridges the left-right culture-wars divide on subjects such as climate change etc. We assign the domain in Dynadot to Cloudflare and set-up DNSSEC.

Development Set-up on Mac Sierra

Install Trellis, the Ansible devops based toolchain. Locally for development it uses Vagrant and remotely on production uses Ansible.

We install Virtualbox, the Virtualbox extensions pack and Vagrant, direct from the vendor.

WordPress building on (a) Trellis

Trellis a dev-prod 12 factor app style toolchain.

We need to install Ansible which first requires PIP on Mac.

sudo easy_install pip
sudo pip install ansible

we also need Vagrant plugins

vagrant plugin install vagrant-bindfs
vagrant plugin install vagrant-hostmanager

we change the to Project directory, make our project folder

cd ~/Projects
mkdir www.openplanetculture.com
cd www.openplanetculture.com/

and now clone from Github and remove the .git folder, we dont need these .git history files

git clone --depth=1 [email protected]:roots/trellis.git && rm -rf trellis/.git

Bedrock a boilerplate base for WordPress site development

We now git clone Bedrock which contains boilerplate and modern development tools such as Facebook’s Nodejs client Yarn.

git clone --depth=1 [email protected]:roots/bedrock.git site && rm -rf site/.git

Next, we use Ansible Galaxy to install our Roots.io ecosystem roles, which are in turned sourced from the Ansible ecosystem of community roles.

cd trellis && ansible-galaxy install -r requirements.yml

install worked fine

cd trellis && ansible-galaxy install -r requirements.yml
- downloading role 'composer', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-composer/archive/1.5.0.tar.gz
- extracting composer to /Users/devekko/Projects/www.openplanetculture.com/trellis/vendor/roles/composer
- composer was installed successfully
- downloading role 'ntp', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-ntp/archive/1.3.0.tar.gz
- extracting ntp to /Users/devekko/Projects/ww.openplanetculture.com/trellis/vendor/roles/ntp
- ntp was installed successfully
- downloading role 'logrotate', owned by nickhammond
- downloading role from https://github.com/nickhammond/ansible-logrotate/archive/e7a498d.tar.gz
- extracting logrotate to /Users/devekko/Projects/www.openplanetculture.com/trellis/vendor/roles/logrotate
- logrotate was installed successfully
- downloading role 'swapfile', owned by kamaln7
- downloading role from https://github.com/kamaln7/ansible-swapfile/archive/0.4.tar.gz
- extracting swapfile to /Users/devekko/Projects/www.openplanetculture.com/trellis/vendor/roles/swapfile
- swapfile was installed successfully
- downloading role 'daemonize', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-daemonize/archive/1.1.1.tar.gz
- extracting geerlingguy.daemonize to /Users/devekko/Projects/www.openplanetculture.com/trellis/vendor/roles/geerlingguy.daemonize
- geerlingguy.daemonize was installed successfully
- downloading role 'mailhog', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-mailhog/archive/2.1.0.tar.gz
- extracting mailhog to /Users/devekko/Projects/www.openplanetculture.com/trellis/vendor/roles/mailhog
- mailhog was installed successfully
- dependency geerlingguy.daemonize is already installed, skipping

WordPress Site development

Now we have our fundament, we have our Roots, our Trellis and our Bedrock, lets build a site.

According to the excellent Roots docs, the “site” is the basic unit of organization and a server can host 1 or more, sites.

This is excellent !

We control the sites using Ansible Group Variables and other settings, so our code is our infrastructure.

Site and Secrets organization

Sounds a bit like a spy novel, but instead we have sites defined in

and the sites secrets in www.openplanetculture.com/trellis/group_vars/development/vault.yml

Personally, I am not convinced Ansible Vault is not a risk, but its widely used and we will go with it for now. Its certainly better than clear text passwords.

Lets generate some passwords using command line pwgen, or alternatively, my preference Password Safe.

brew install pwgen

and set them in our secrets (which I changed after publishing this blog post!)

vault_mysql_root_password: uoquiGh8Sego2hee

admin_password: admin
db_password: oonaNgo5eeP4eich

Notice, also that Roots.io preferences openplanetculture.com as canonical, NOT www.openplanetculture.com. This is actually not recommended by Cloudflare, but let’s go with this for now, we “should” be able to just change config and it will work, but for now, lets stay close to defaults so we don’t trip ourselves up.

There are loads of Ansible settings that we can use as we progress.

Complete Local Development Setup

We complete our local dev setup from the detailed official docs.

We check-list ourselves and looks good, so lets run vagrant up, I’ll grab a coffee and expect to do some further trouble-shooting. Vagrant rarely works the first time imho….

Dev site installed

Now I can visit the site on http://openplanetculture.dev

Open Planet Culture DEV site
Open Planet Culture DEV site

Create a new theme with Sage

Sage is the custom starter theme and its used by some interesting sites, including Data.gov.

cd /Users/devekko/Projects/openplanetculture.com/site/web/app/themes

lets install Sage master (9-dev) and we first need Composer installed globally

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"\nphp -r "if (hash_file('SHA384', 'composer-setup.php') === '55d6ead61b29c7bdee5cccfb50076874187bd9f21f65d8991d46ec5cc90518f447387fb9f76ebae1fbbacf329e583e30') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"\nphp composer-setup.php\nphp -r "unlink('composer-setup.php');"
mv composer.phar /usr/local/bin/composer

now we install using Composer and the interactive prompts

composer create-project roots/sage openplanetculture.com dev-master
Installing roots/sage (dev-master 35edef6ae75280d060f3ef022feaf77b6d1cdb54)
- Installing roots/sage (dev-master master) Cloning master from cache
Created project in openplanetculture.com
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 14 installs, 0 updates, 0 removals
- Installing composer/installers (v1.2.0) Downloading: 100%
- Installing doctrine/inflector (v1.1.0) Downloading: 100%
- Installing paragonie/random_compat (v2.0.7) Downloading: 100%
- Installing illuminate/contracts (v5.4.13) Downloading: 100%
- Installing illuminate/support (v5.4.13) Downloading: 100%
- Installing illuminate/config (v5.4.13) Downloading: 100%
- Installing psr/log (1.0.2) Downloading: 100%
- Installing symfony/debug (v3.2.4) Downloading: 100%
- Installing symfony/finder (v3.2.4) Downloading: 100%
- Installing illuminate/filesystem (v5.4.13) Downloading: 100%
- Installing illuminate/container (v5.4.13) Downloading: 100%
- Installing illuminate/events (v5.4.13) Downloading: 100%
- Installing illuminate/view (v5.4.13) Downloading: 100%
- Installing squizlabs/php_codesniffer (2.8.0) Downloading: 100%
paragonie/random_compat suggests installing ext-libsodium (Provides a modern crypto API that can be used to generate random bytes.)
illuminate/support suggests installing symfony/process (Required to use the composer class (~3.2).)
illuminate/support suggests installing symfony/var-dumper (Required to use the dd function (~3.2).)
illuminate/filesystem suggests installing league/flysystem (Required to use the Flysystem local and FTP drivers (~1.0).)
illuminate/filesystem suggests installing league/flysystem-aws-s3-v3 (Required to use the Flysystem S3 driver (~1.0).)
illuminate/filesystem suggests installing league/flysystem-rackspace (Required to use the Flysystem Rackspace driver (~1.0).)
Generating autoload files
Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? Y

Define theme headers. Press enter key for default.
Theme Name [Sage Starter Theme]: Open Planet Culture
Theme URI [https://roots.io/sage/]: http://openplanetculture.com
Theme Description [Sage is a WordPress starter theme.]: Open Planet Culture Sage 9-dev theme
Theme Version [9.0.0-beta.2]:
Theme Author [Roots]: Devekko
Theme Author URI [https://roots.io/]: http://blog.devekko.com
Select a CSS framework (Default: Bootstrap)
[0] Bootstrap
[1] Foundation
[2] None
Add Font Awesome? [y,N]? y
Configure build settings. Press enter key for default.
Path to theme directory (eg. /wp-content/themes/sage) [/app/themes/openplanetculture.com]:
Local development URL of WP site [http://example.dev]: http://openplanetculture.dev

tree tells us we have a nice theme

tree openplanetculture.com / -L 1
├── LICENSE.md
├── README.md
├── assets
├── composer.json
├── composer.lock
├── functions.php
├── index.php
├── package.json
├── phpcs.xml
├── screenshot.png
├── src
├── style.css
├── templates
├── vendor
└── yarn.lock

Buy the Book

There is lots more about Sage, and the best way is buy the book and support the project!

Sage 9-dev with yarn npm package manager

cd /Users/devekko/Projects/openplanetculture.com/site/web/app/themes/openplanetculture.com
brew install zsh
brew install yarn

now we use yarn as a replace npm client, no more nom install

openplanetculture.com yarn
yarn install v0.21.3
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 📃 Building fresh packages...
success Saved lockfile.
✨ Done in 38.09s.

now we run yarn run start

yarn run start
yarn run v0.21.3
$ webpack --hide-modules --watch --config assets/build/webpack.config.js

Webpack is watching the files…

[BS] [HTML Injector] Running...
[BS] Proxying: http://openplanetculture.dev
[BS] Access URLs:

   Local: http://localhost:3000

      UI: http://localhost:3001

UI External:

[BS] Watching files...

now we have our SASS compiled into CSS and we have the basic setup for theming with Sage 9-dev and Trellis and Roots


Adding Semantic UI

I want to try Semantic UI and use yarn

openplanetculture.com yarn add semantic-ui-sass
yarn add v0.21.3
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 📃 Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
└─ [email protected]
✨ Done in 8.38s.

next steps will be getting Semantic UI working with Sage

Data.gov as a reference

next few days I will theme and build the Open Planet Culture site, probably referencing Data.gov