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.

Roots.io

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.

Video

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.

Ideas

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 !

An Open Source Hardware Personal Computer Made in Silicon Valley, USA ?

I am on a mission to find an Intel style, open-source hardware, personal computer, made in Silicon Valley, USA.

I want to run Ubuntu or Redhat and have the mainline device drivers support for commercial peripherals.

I do not want Raspberry PI or Beaglebone, I want mainline PC architecture.

I do not want a Maker gadget or a DIY toy.

I know there is the high end Open Compute project, and that is for BIG INTERNET companies and government systems.

I asked Scott McNeally via Twitter.

I asked the question on Can I buy an open-source hardware computer assembled and manufactured in Silicon Valley? Quora.

I know of the Minnow Board project, which is an Intel project and was manufactured by a Texas company.

But, I want a Silicon Valley made personal computer. Not assembled or designed in Silicon Valley. But made in the Silicon Valley, USA.

I want to build an open source hardware and software commercial project on such a computer.

Any leads, email me at [email protected]

Composer, source code from private Gitlab and public Github for Sage 9 and Roots for WordPress Plugin & Theme Development

I want to split out my custom plugins and themes from my Roots repo so I can make it private, I just dont trust Ansible Vault enough, and there is always the chance of forgetting to encrypt with the key and committing the secrets and putting it into the git history.

I also want to manage the THEMES as well as the plugins to the git repo’s via Composer and GIT i.e. gitlab and doing this was surprisingly complicated and not well documented.

Bedrock i.e. site folder composer.json

my composer.json folder for Bedrock, the site scaffolding, looks like this


{
"name": "roots/bedrock",
"type": "project",
"license": "MIT",
"description": "WordPress boilerplate with modern development tools, easier configuration, and an improved folder structure",
"homepage": "https://roots.io/bedrock/",
"authors": [
{
"name": "Scott Walkinshaw",
"email": "sco[email protected]",
"homepage": "https://github.com/swalkinshaw"
},
{
"name": "Ben Word",
"email": "[email protected]",
"homepage": "https://github.com/retlehs"
}
],
"keywords": [
"bedrock", "roots", "wordpress", "stack", "composer", "vagrant", "wp"
],
"support": {
"issues": "https://github.com/roots/bedrock/issues",
"forum": "https://discourse.roots.io/category/bedrock"
},
"config": {
"preferred-install": "dist"
},
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
},
{
"type": "package",
"package": {
"name": "MWDelaney/acf-complex-titles",
"version": "1.11",
"type": "wordpress-plugin",
"source": {
"type": "git",
"url": "https://github.com/MWDelaney/acf-complex-titles.git",
"reference": "1.11"
},
"require": {
"composer/installers": "*"
}
}
},
{
"type": "package",
"package": {
"name": "openplanetculture/openplanetculture-wp",
"version": "master",
"type": "wordpress-plugin",
"source": {
"type": "git",
"url": "[email protected]:openplanetculture/openplanetculture-wp.git",
"reference": "master"
},
"require": {
"composer/installers": "*"
}
}
},
{
"type": "package",
"package": {
"name": "openplanetculture/openplanetculture-litera",
"version": "master",
"type": "wordpress-theme",
"source": {
"type": "git",
"url": "[email protected]:openplanetculture/openplanetculture-litera.git",
"reference": "master"
},
"require": {
"composer/installers": "*"
}
}
},
{
"type": "package",
"package": {
"name": "openplanetculture/openplanetculture",
"version": "master",
"type": "wordpress-theme",
"source": {
"type": "git",
"url": "[email protected]:openplanetculture/openplanetculture.git",
"reference": "master"
},
"require": {
"composer/installers": "*"
}
}
}
],
"require": {
"php": ">=5.6",
"composer/installers": "~1.0.12",
"vlucas/phpdotenv": "^2.0.1",
"johnpbloch/wordpress": "4.7.3",
"oscarotero/env": "^1.0",
"openplanetculture/openplanetculture-wp": "@dev",
"openplanetculture/openplanetculture-litera": "@dev",
"wpackagist-plugin/megamenu": "2.3.5",
"MWDelaney/acf-complex-titles": "1.11",
"wpackagist-plugin/advanced-custom-fields": "4.4.11",
"roots/wp-password-bcrypt": "1.0.0"

},
"require-dev": {
"squizlabs/php_codesniffer": "^2.5.1"
},
"extra": {
"installer-paths": {
"web/app/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
"web/app/plugins/{$name}/": ["type:wordpress-plugin"],
"web/app/themes/{$name}/": ["type:wordpress-theme"]
},
"wordpress-install-dir": "web/wp"
},
"scripts": {
"test": [
"vendor/bin/phpcs"
]
}
}

custom theme

my custom theme is on Gitlab and public and the composer.json for the theme looks like this


{
"name": "openplanetculture/openplanetculture",
"type": "wordpress-theme",
"license": "MIT",
"description": "Open Planet Culture Bootstrap 4 for Material Design",
"homepage": "http://openplanetculture.com",
"authors": [
{
"name": "Nicholas Roberts",
"email": "[email protected]",
"homepage": "https://github.com/devekkoio"
}
],
"keywords": [
"wordpress"
],
"support": {
"issues": "https://gitlab.com/openplanetculture/openplanetculture.com-theme/issues"
},
"autoload": {
"psr-4": {
"Roots\\Sage\\": "src/lib/Sage/"
}
},
"require": {
"php": ">=5.6.4",
"composer/installers": "~1.0",
"illuminate/view": "~5.3.0",
"illuminate/config": "~5.3.0"
},
"require-dev": {
"squizlabs/php_codesniffer": "^2.5.1"
},
"scripts": {
"test": [
"vendor/bin/phpcs"
],
"post-create-project-cmd": [
"Roots\\Sage\\PostCreateProject::updateHeaders",
"Roots\\Sage\\PostCreateProject::selectFramework",
"Roots\\Sage\\PostCreateProject::addFontAwesome"
]
}
}

and the remotes for the theme


➜ openplanetculture-wp git:(master) ✗ git remote -v
composer [email protected]:openplanetculture/openplanetculture-wp.git (fetch)
composer [email protected]:openplanetculture/openplanetculture-wp.git (push)
origin [email protected]:openplanetculture/openplanetculture-wp.git (fetch)
origin [email protected]:openplanetculture/openplanetculture-wp.git (push)

custom plugin

the scaffolding/stub for the custom plugin composer.json looks like


{
"name": "openplanetculture/openplanetculture-wp",
"version": "1.0.1",
"description": "Open Planet Culture WordPress plugin",
"type": "wordpress-plugin",
"dependencies": {},
"devDependencies": {},
"scripts": {},
"repository": {
"type": "git",
"url": "git+https://gitlab.com/openplanetculture/openplanetculture-wp.git"
},
"authors": [
{
"name": "Nicholas Roberts",
"email": "[email protected]"
}
],
"license": "GPL3",
"bugs": {
"url": "https://gitlab.com/openplanetculture/openplanetculture-wp/issues"
},
"homepage": "https://gitlab.com/openplanetculture/openplanetculture-wp#readme"
}

Gitignore

I added themes to the plugins in gitignore


# Application
web/app/themes/*
web/app/plugins/*
!web/app/plugins/.gitkeep
web/app/mu-plugins/*/
web/app/upgrade
web/app/uploads/*
!web/app/uploads/.gitkeep

# WordPress
web/wp
web/.htaccess

# Dotenv
.env
.env.*
!.env.example

# Composer
vendor/*
!vendor/.gitkeep
node_modules

Deploying a site

every time you update, you need to commit all the repos, themes, plugins, and the roots root folder, if there are changes in references you need to run composer update and update the locks


composer update
git commit -am "source and ref"
git push
ansible-playbook deploy.yml -e "site=openplanetculture.com env=production" -vvv --ask-vault-pass

Open Source Artificial Intelligence: Mycroft.ai from source on Ubuntu Xenial

I want to integrate FolkBot with Mycroft.ai and so I am going to run from source

Source

get the repo from MycroftAI


⟫ git clone https://github.com/MycroftAI/mycroft-core.git
Cloning into 'mycroft-core'...
remote: Counting objects: 5745, done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 5745 (delta 5), reused 2 (delta 2), pack-reused 5725
Receiving objects: 100% (5745/5745), 74.60 MiB | 15.06 MiB/s, done.
Resolving deltas: 100% (3264/3264), done.
Checking connectivity... done.
[email protected]:~/Infra⟫ cd mycroft-core/

Setup

Lets set-up the pre-req’s etc

WARNING: Read these scripts

set-up a Debian/Ubuntu host


./build_host_setup_debian.sh

dev set-up

set-up the dev tools for Ubuntu

NOTE: this took over an hour to complete


./dev_setup.sh

Start Mycroft AI

start mycroft with all the options


./mycroft.sh start
Mycroft service started
Mycroft skills started
Mycroft voice started
Mycroft cli--quiet started

mycroft ai CLI

from the mycroft official docs

interact with mycroft.ai via the CLI, we list the screens


screen -list
There are screens on:
20625.mycroft-cli--quiet (03/10/2017 01:50:50 PM) (Detached)
20552.mycroft-skills (03/10/2017 01:50:50 PM) (Detached)
20514.mycroft-service (03/10/2017 01:50:50 PM) (Detached)
16278.mycroft-skills (03/10/2017 01:50:50 PM) (Detached)
7248.mycroft-skills (03/10/2017 01:50:50 PM) (Detached)
5 Sockets in /var/run/screen/S-devekko.

connect to cli

connect via cli


screen -r 16351.mycroft-cli--quiet
requests.packages.urllib3.connectionpool - DEBUG - https://api.mycroft.ai:443 "GET /v1/device//setting HTTP/1.1" 401 38
requests.packages.urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): api.mycroft.ai
requests.packages.urllib3.connectionpool - DEBUG - https://api.mycroft.ai:443 "GET /v1/auth/token HTTP/1.1" 401 38
ConfigurationSkill - WARNING - Impossible to update configuration because device isn't paired

History Log Output Legend
====================================================================================================== ==================================================================================================
mycroft-skills.log, system debug
mycroft-skills.log, other
mycroft-voice.log

Input (':' for command mode, Ctrl+C to quit):
> What time is it

we learn we need to register, but mycroft can tell the time


requests.packages.urllib3.connectionpool - DEBUG - https://api.mycroft.ai:443 "GET /v1/device//setting HTTP/1.1" 401 38
requests.packages.urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): api.mycroft.ai
requests.packages.urllib3.connectionpool - DEBUG - https://api.mycroft.ai:443 "GET /v1/auth/token HTTP/1.1" 401 38
ConfigurationSkill - WARNING - Impossible to update configuration because device isn't paired

History Log Output Legend
====================================================================================================== ==================================================================================================
mycroft-skills.log, system debug
mycroft-skills.log, other
mycroft-voice.log

Input (':' for command mode, Ctrl+C to quit):
> What time is it

History Log Output Legend
====================================================================================================== ==================================================================================================
>> 04:14, PM mycroft-skills.log, system debug
>> 04:14, PM mycroft-skills.log, other
>> 04:14, PM mycroft-voice.log
>> 04:14, PM
>> It's 04:14, PM

Register

at the mycroft homepage we register a device, it even tells us

NOTE: I made up below information


>> Log in at home dot mycroft dot A.I and enter the pairing code. 'C' as in Charlie. 'A' as in Alfred. 'B' as in Blueberries. 'K' as in Kilogram. 'H' as in Hotel. 'K' as in Kilogram

you are now registered and paired

News from mycroft

we can ask via command line for the news


{"type": "enclosure.eyes.blink", "data": {"side": "b"}, "context": null}
{"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}
{"type": "recognizer_loop:audio_output_start", "data": {}, "context": null}
High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3
version 1.22.4; written and copyright by Michael Hipp and others
free software (LGPL) without any warranty but with best wishes
{"type": "enclosure.eyes.blink", "data": {"side": "b"}, "context": null}
{"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}
{"type": "recognizer_loop:audio_output_start", "data": {}, "context": null}

Directory: http://play.podtrac.com/npr-500005/npr.mc.tritondigital.com/NPR_500005/media/anon.npr-mp3/npr/newscasts/2017/03/10/
Playing MPEG stream 1 of 1: newscast180642.mp3?orgId=1&d=300&p=500005&story=519730168&t=podcast&e=519730168&ft=pod&f=500005 ... MPEG 1.0 layer III, 192 kbit/s, 48000 Hz joint-stereo
Directory: http://play.podtrac.com/npr-500005/npr.mc.tritondigital.com/NPR_500005/media/anon.npr-mp3/npr/newscasts/2017/03/10/
Playing MPEG stream 1 of 1: newscast180642.mp3?orgId=1&d=300&p=500005&story=519730168&t=podcast&e=519730168&ft=pod&f=500005 ...

MPEG 1.0 layer III, 192 kbit/s, 48000 Hz joint-stereo
{"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}
{"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}
requests.packages.urllib3.connectionpool - DEBUG - https://api.mycroft.ai:443 "GET /v1/wa?input=news HTTP/1.1" 200 23080 {"type": "speak", "data": {"utterance": "news (English word) : 1, n"}, "context": null}
{"type": "recognizer_loop:audio_output_start", "data": {}, "context": null}
{"type": "speak", "data": {"utterance": "news (English word) : 1, n"}, "context": null}
requests.packages.urllib3.connectionpool - DEBUG - https://api.mycroft.ai:443 "GET /v1/wa?input=news HTTP/1.1" 200 23080
{"type": "speak", "data": {"utterance": "news (English word) : 1, n"}, "context": null}
{"type": "recognizer_loop:audio_output_start", "data": {}, "context": null} {"type": "speak", "data": {"utterance": "news (English word) : 1, n"}, "context": null} {"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}
{"type": "recognizer_loop:audio_output_start", "data": {}, "context": null}
{"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}
{"type": "recognizer_loop:audio_output_start", "data": {}, "context": null}
{"type": "enclosure.eyes.blink", "data": {"side": "b"}, "context": null}
{"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}
{"type": "enclosure.eyes.blink", "data": {"side": "b"}, "context": null}
{"type": "recognizer_loop:audio_output_end", "data": {}, "context": null}

History Log Output Legend
==================================================================================== ================================================================================
news mycroft-skills.log, system debug
>> Here is this hour's news from NPR. mycroft-skills.log, other
>> Here is the top of the hour news from NPR. mycroft-voice.log
>> news (English word) : 1, n
>> news (English word) : 1, n

Input (':' for command mode, Ctrl+C to quit):
>

play thew news on the speech screen


2017-03-10 19:04:29,897 - mycroft.client.speech.listener - DEBUG - STT: play the news
2017-03-10 19:04:29,897 - SpeechClient - INFO - Utterance: [u'play the news']
2017-03-10 19:04:32,460 - SpeechClient - INFO - Speak: I couldn't get a response for play the news.
Playing WAVE '/tmp/tts.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono
2017-03-10 19:04:35,642 - SpeechClient - INFO - Speak: Maybe you meant play?
Playing WAVE '/tmp/tts.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono
2017-03-10 19:06:32,185 - SpeechClient - INFO - Speak: PLAY (music work) : album, music act, release date, Tree, SEKAI NO OWARI, Thursday, January 15, 2015
Playing WAVE '/tmp/tts.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono
2017-03-10 19:06:55,554 - SpeechClient - INFO - Speak: Jazz (book) : author, Toni Morrison, first publication date, 1992 (25 years ago), publisher, Knopf, original language, English
Playing WAVE '/tmp/tts.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono
2017-03-10 19:08:39,723 - SpeechClient - INFO - Speak: Here is the top of the hour news from NPR.
Playing WAVE '/tmp/tts.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mo

make your own vocabulary

I want to add “radio news” to the vocabulary and change to the cli screen /mycroft-core/mycroft/skills/npr_news/vocab/en-us


radio news
>> Here is the top of the hour news from NPR.
Input (':' for command mode, Ctrl+C to quit):

Phoenix 1.3 Rc0 and Bootstrap 4

Phoenix 1.3 rc0 has just been released and I want to create first versions of new apps for my home-page devekko.io and a political game and push it to a prgmr.com server using HashNukes Ansible.

This is part 1

Setup Elixir


brew install phoenix
brew install elixir

Phoenix 1.3 rc0

From the Elixir Forum the post on Phoenix 1.3 Released rc0 by Chris McCord


mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez

Trumps New Deal

I want to make a political game, Trumps New Deal, at first a super simple voting game. Thumbs up and thumbs down.

This generator is found in the install folder phoenix/installer/lib/mix/tasks/phx.new.ex


mix phx.new trumpsnewdealcom

So, in my Infra folder


➜ Infra mix phx.new trumpsnewdealcom
* creating trumpsnewdealcom/config/config.exs
* creating trumpsnewdealcom/config/dev.exs
* creating trumpsnewdealcom/config/prod.exs
* creating trumpsnewdealcom/config/prod.secret.exs
* creating trumpsnewdealcom/config/test.exs
* creating trumpsnewdealcom/lib/trumpsnewdealcom/application.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/channels/user_socket.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/views/error_helpers.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/views/error_view.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/endpoint.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/router.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/web.ex
* creating trumpsnewdealcom/mix.exs
* creating trumpsnewdealcom/README.md
* creating trumpsnewdealcom/test/support/channel_case.ex
* creating trumpsnewdealcom/test/support/conn_case.ex
* creating trumpsnewdealcom/test/test_helper.exs
* creating trumpsnewdealcom/test/web/views/error_view_test.exs
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/gettext.ex
* creating trumpsnewdealcom/priv/gettext/en/LC_MESSAGES/errors.po
* creating trumpsnewdealcom/priv/gettext/errors.pot
* creating trumpsnewdealcom/lib/trumpsnewdealcom/repo.ex
* creating trumpsnewdealcom/priv/repo/seeds.exs
* creating trumpsnewdealcom/test/support/data_case.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/controllers/page_controller.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/templates/layout/app.html.eex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/templates/page/index.html.eex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/views/layout_view.ex
* creating trumpsnewdealcom/lib/trumpsnewdealcom/web/views/page_view.ex
* creating trumpsnewdealcom/test/web/controllers/page_controller_test.exs
* creating trumpsnewdealcom/test/web/views/layout_view_test.exs
* creating trumpsnewdealcom/test/web/views/page_view_test.exs
* creating trumpsnewdealcom/.gitignore
* creating trumpsnewdealcom/assets/brunch-config.js
* creating trumpsnewdealcom/assets/css/app.css
* creating trumpsnewdealcom/assets/css/phoenix.css
* creating trumpsnewdealcom/assets/js/app.js
* creating trumpsnewdealcom/assets/js/socket.js
* creating trumpsnewdealcom/assets/package.json
* creating trumpsnewdealcom/assets/static/robots.txt
* creating trumpsnewdealcom/assets/static/images/phoenix.png
* creating trumpsnewdealcom/assets/static/favicon.ico

Fetch and install dependencies? [Yn] y
* running mix deps.get
* running mix deps.compile
* running cd assets && npm install && node node_modules/brunch/bin/brunch build

Database

we change directory


➜ Infra cd trumpsnewdealcom
➜ trumpsnewdealcom mix ecto.create
Compiling 12 files (.ex)
Generated trumpsnewdealcom app
The database for Trumpsnewdealcom.Repo has already been created
➜ trumpsnewdealcom iex -S mix phx.server
Erlang/OTP 19 [erts-8.2.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

[info] Running Trumpsnewdealcom.Web.Endpoint with Cowboy using http://0.0.0.0:4000
Interactive Elixir (1.4.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 09:51:00 - info: compiled 6 files into 2 files, copied 3 in 1.0 sec
iex(1)>

Live Reload

By default, Phoenix runs Live Reload and we can make changes to templates, code, styles, scripts, on the fly.

Change Homepage

Now, we change the homepage index template on this on the path

trumpsnewdealcom/lib/trumpsnewdealcom/web/templates/page/index.html.eex

New Style

Strip out the Phoenix default CSS from Bootstrap 3 from trumpsnewdealcom/assets/css/phoenix.css

Now we have a clean slate

Bootswatch 4

Now, I want to strip out Bootstrap 3 and replace with Bootswatch 4 and Bootstrap 4, we will customize from these.

Node Packages

We update package.json which manages our node_modules at trumpsnewdealcom/assets/package.json to include Bootswatch 4 from a branch on Github, its not on npm registry yet.

our /Users/devekko/Infra/trumpsnewdealcom/assets/package.json is now


{
"repository": {},
"license": "MIT",
"scripts": {
"deploy": "brunch build --production",
"watch": "brunch watch --stdin"
},
"dependencies": {
"phoenix": "file:../deps/phoenix",
"bootstrap": "^4.0.0-alpha.6",
"phoenix_html": "file:../deps/phoenix_html",
"bootswatch": "[email protected]:thomaspark/bootswatch.git#v4"
},
"devDependencies": {
"babel-brunch": "6.0.6",
"sass-brunch": "2.10.4",
"brunch": "2.10.7",
"copycat-brunch": "1.1.0",
"clean-css-brunch": "2.10.0",
"css-brunch": "2.10.0",
"uglify-js-brunch": "2.1.1"
}
}

the package.json of Bootswatch 4 confirms this trumpsnewdealcom/assets/node_modules/bootswatch/package.json


{
"_args": [
[
{
"raw": "[email protected]+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"scope": null,
"escapedName": "public",
"name": "public",
"rawSpec": "git+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"spec": "git+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"type": "hosted",
"hosted": {
"type": "github",
"ssh": "[email protected]:thomaspark/bootswatch.git#v4",
"sshUrl": "git+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"httpsUrl": "git+https://github.com/thomaspark/bootswatch.git#v4",
"gitUrl": "git://github.com/thomaspark/bootswatch.git#v4",
"shortcut": "github:thomaspark/bootswatch#v4",
"directUrl": "https://raw.githubusercontent.com/thomaspark/bootswatch/v4/package.json"
}
},
"/Users/devekko/Infra/trumpsnewdealcom/assets"
]
],
"_from": "git+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"_id": "[email protected]",
"_inCache": true,
"_location": "/bootswatch",
"_phantomChildren": {},
"_requested": {
"raw": "[email protected]+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"scope": null,
"escapedName": "public",
"name": "public",
"rawSpec": "git+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"spec": "git+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"type": "hosted",
"hosted": {
"type": "github",
"ssh": "[email protected]:thomaspark/bootswatch.git#v4",
"sshUrl": "git+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"httpsUrl": "git+https://github.com/thomaspark/bootswatch.git#v4",
"gitUrl": "git://github.com/thomaspark/bootswatch.git#v4",
"shortcut": "github:thomaspark/bootswatch#v4",
"directUrl": "https://raw.githubusercontent.com/thomaspark/bootswatch/v4/package.json"
}
},
"_requiredBy": [],
"_resolved": "git+ssh://[email protected]/thomaspark/bootswatch.git#f54154dd2d0dbbc48e858efacf6dd82252f67a05",
"_shasum": "cc78a14f230879f4167b7fdca031a469fe02e1f3",
"_shrinkwrap": null,
"_spec": "[email protected]+ssh://[email protected]/thomaspark/bootswatch.git#v4",
"_where": "/Users/devekko/Infra/trumpsnewdealcom/assets",
"author": {
"name": "Thomas Park"
},
"bugs": {
"url": "https://github.com/thomaspark/bootswatch/issues"
},
"dependencies": {},
"description": "Bootswatch is a collection of themes for Bootstrap.",
"devDependencies": {
"autoprefixer": "^6.5.0",
"bower": "~1.2.8",
"grunt": "^1.0.1",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-connect": "^1.0.2",
"grunt-contrib-sass": "^1.0.0",
"grunt-contrib-uglify": "^2.0.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-exec": "^1.0.1",
"postcss-cli": "^2.6.0",
"postcss-flexbugs-fixes": "^2.0.0"
},
"engines": {
"node": ">= 0.10.0"
},
"scripts": {
"postcss": "postcss --config assets/js/postcss.js --replace */bootstrap*.css"
},
"version": "4.0.0-alpha.6"
}

Copy Asset Files

app.scss

We now need to connect compile and connect to SCSS

we rename app.css to app.scss


/* This file is for your main application css. */
@import "css/bootswatch/_variables.scss";
@import "bootstrap";
@import "css/bootswatch/_bootswatch.scss";

Brunch config

Thanks to this gist I learned how to configure Brunch for Bootstrap 4 on Phoenix


exports.config = {
// See http://brunch.io/#documentation for docs.
files: {
javascripts: {
joinTo: "js/app.js"

},
stylesheets: {
joinTo: "css/app.css"
},
templates: {
joinTo: "js/app.js"
}
},

conventions: {
assets: /^(static)/
},

// Phoenix paths configuration
paths: {
// Dependencies and current project directories to watch
watched: ["static", "css", "js", "vendor"],
// Where to compile files to
public: "../priv/static"
},

// Configure your plugins
plugins: {
babel: {
// Do not use ES6 compiler in vendor code
ignore: [/vendor/]
},
sass: {
options: {
includePaths: ["node_modules/bootstrap/scss"], // Tell sass-brunch where to look for files to @import
precision: 8 // Minimum precision required by bootstrap-sass
}
},
},

modules: {
autoRequire: {
"js/app.js": ["js/app"]
}
},

npm: {
enabled: true,
globals: { // Bootstrap's JavaScript requires both '$' and 'jQuery' in global scope
$: 'jquery',
jQuery: 'jquery',
bootstrap: 'bootstrap' // Require Bootstrap's JavaScript globally
}
}
};

Bootswatch

I manually copy the Bootswatch folders across from node_modules to the assets folders.

It is possible to use npm postinstall cp -ar type solutions, but this becomes complex as I want to strip out some files like gulp build files and dist etc etc. There is no good way to do this imho and its seems to be confirmed by Cloudless Studio.

I also want to modify the Materia Bootswatch theme and I want to keep it simple. I struggled with this for a day and realized a simple copy and paste was best.

app.scss looks like


/* This file is for your main application css. */
@import "css/bootswatch/_variables.scss";
@import "bootstrap";
@import "css/bootswatch/_bootswatch.scss";

and my css assets folder, Bootstrap is in the node_modules folder and is configured via Brunch and compiled via SASS Brunch


tree css
css
├── app.scss
├── bootswatch
│   ├── LICENSE
│   ├── _bootswatch.scss
│   └── _variables.scss
└── phoenix.css

now our site has Bootstrap 4 / Bootswatch 4 styles

Kitchen Sink

To conclude this part of the project, I add a kitchen-sink page from Bootswatch so I can compare and contrast the fidelity of my build, check for missing JS and CSS etc etc.

I add trumpsnewdealcom/lib/trumpsnewdealcom/web/templates/page/kitchen.html.eex with HTML from Bootswatch

Page Controller updated

I add a new atom :kitchen for our kitchen sink


def kitchen(conn, _params) do
render conn, "kitchen.html"
end

and in the router trumpsnewdealcom/lib/trumpsnewdealcom/web/router.ex

I add a new route


scope "/", Trumpsnewdealcom.Web do
pipe_through :browser

get "/", PageController, :index
get "/kitchen", PageController, :kitchen

end

I copy the tag contents from https://bootswatch.com/4-alpha/materia/ and paste into kitchen.index.eex and we now we have a kitchen sink at http://0.0.0.0:4000/kitchen

Change Brand Primary

And of course, to make myself feel like a talented designer I change brand-primary

GOTCHA: and for some reason, I have to stop and restart phoenix server for the css to refresh, no doubt a setting in brunch. Will try to reproduce this and publish a repo.

stay tuned as I build out the game

ALSO, PLEASE DONT FLAME ME, I didn’t vote for Trump, but I do think there is a roll-back of the FDR New Deal, hence, Trumps New Deal

Semantic UI SASS (or NOT) on Sage 9 dev

Part 3 of a series, lets get Semantic UI Sass port working

yarn add semantic-ui-sass

yarn will download semantic-ui-sass from the npm registry and update our package.json


➜ 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 6.26s.

now I run yarn start and get errors, its not looking good for Semantic UI and Sage, especially from a, lets get the site up quickly perspective, so I will roll back to Bootstrap 4.

Some factors

  1. Semantic UI has site templates which requires LESS, apparently SASS doesn’t do import of variables
  2. Roots uses SASS, and so I would either have to use SASS and LESS in Roots or use the Semantic UI Sass port
  3. Semantic UI Sass may or may not be feature complete
  4. Sage imports Bootstrap and so I would need to manually work through and compare and contrast, matching Bootstrap to Semantic UI
  5. Semantic UI Sass doesn’t have the variable for colors or palettes and colors are mixed into the CSS/SCSS, this is a real limitation and for me is a deal killer
  6. perhaps the composer Sage project setup option without a style at all would be better, but there would still be questions about Semantic UI itself and especially the fact that there is no official SASS port now, or possibly ever
  7. Sage webpack config would need to be changed to run LESS, probably not too difficult, but possibly time consuming

so, its a rabbit hole of complexity and something I don’t want, so its back to the default, Bootstrap 4.

I really love the idea of Semantic UI and haven’t given up on it and will come back to again, but right now it looks like I will stick with Bootstrap 4

Maybe will try to come back to Semantic UI LESS on Sage after building a site with the default Bootstrap 4.

Semantic UI and Sage on WordPress

Sage 9 dev Bootstrap 4

Following on from Semantic UI and Roots lets follow-up and get the SASS port of Semantic UI working with and customized into something like a theme.

Baseline with Bootstrap

Since I am new to Sage and Roots and Trellis, and also Facebook’s new npm client called yarn lets get a baseline theme working with the default Bootstrap 4.


➜ themes 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) Loading from cache
- Installing doctrine/inflector (v1.1.0) Loading from cache
- Installing paragonie/random_compat (v2.0.7) Loading from cache
- Installing illuminate/contracts (v5.4.13) Loading from cache
- Installing illuminate/support (v5.4.13) Loading from cache
- Installing illuminate/config (v5.4.13) Loading from cache
- Installing psr/log (1.0.2) Loading from cache
- Installing symfony/debug (v3.2.4) Loading from cache
- Installing symfony/finder (v3.2.4) Loading from cache
- Installing illuminate/filesystem (v5.4.13) Loading from cache
- Installing illuminate/container (v5.4.13) Loading from cache
- Installing illuminate/events (v5.4.13) Loading from cache
- Installing illuminate/view (v5.4.13) Loading from cache
- Installing squizlabs/php_codesniffer (2.8.0) Loading from cache
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

Roots\Sage\PostCreateProject::updateHeaders
Define theme headers. Press enter key for default.
Theme Name [Sage Starter Theme]: Open Planet Cuture
Theme URI [https://roots.io/sage/]: http://openplanetculture.com
Theme Description [Sage is a WordPress starter theme.]: Open Planet Culture WordPress theme
Theme Version [9.0.0-beta.2]:
Theme Author [Roots]: Devekko
Theme Author URI [https://roots.io/]: http://devekko.com
Roots\Sage\PostCreateProject::selectFramework
Select a CSS framework (Default: Bootstrap)
[0] Bootstrap
[1] Foundation
[2] None
0
Roots\Sage\PostCreateProject::addFontAwesome
Add Font Awesome? [y,N]? y
Roots\Sage\PostCreateProject::buildOptions
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

now we run yarn

yarn, Facebook’s new npm client

we run yarn in our theme folder


➜ themes cd openplanetculture.com
➜ 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 23.83s.
➜ openplanetculture.com

yarn and package.json

We can see package.json what commands will do what in openplanetculture.com/site/web/app/themes/openplanetculture.com/package.json

web.config.js


....
"scripts": {
"build": "webpack --progress --config assets/build/webpack.config.js",
"build:production": "webpack --progress -p --config assets/build/webpack.config.js",
"build:profile": "webpack --progress --profile --json --config assets/build/webpack.config.js",
"start": "webpack --hide-modules --watch --config assets/build/webpack.config.js",
"rmdist": "rimraf dist",
"lint": "eslint assets/scripts assets/build",
"test": "yarn run lint"
},
"engines": {
"node": ">= 6.9.4"
},
....

we want to run yarn and get it to watch for changes

➜ openplanetculture.com 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
External: http://10.1.10.51:3000

      UI: http://localhost:3001

UI External: http://10.1.10.51:3001


[BS] Watching files...

checking Chrome developer tools we see 404’s for css and the dist folder is empty

Stop yarn

we stop yarn with CTRL+c

and run yarn build which seems to generate the CSS

yarn build
yarn build v0.21.3
$ webpack --progress --config assets/build/webpack.config.js
Hash: 8736dc5e9e2233db1dc9
Version: webpack 2.2.0
Time: 5979ms
Asset Size Chunks Chunk Names
scripts/main.js 165 kB 0 [emitted] main
vendor/fontawesome-webfont_674f50d2.eot 166 kB [emitted]
vendor/fontawesome-webfont_b06871f2.ttf 166 kB [emitted]
vendor/fontawesome-webfont_af7ae505.woff2 77.2 kB [emitted]
vendor/fontawesome-webfont_fee66e71.woff 98 kB [emitted]
vendor/fontawesome-webfont_912ec66d.svg 444 kB [emitted] [big]
scripts/customizer.js 3.41 kB 1 [emitted] customizer
styles/main.css 247 kB 0 [emitted] main
scripts/main.js.map 274 kB 0 [emitted] main
styles/main.css.map 516 kB 0 [emitted] main
scripts/customizer.js.map 3.24 kB 1 [emitted] customizer
[1] ./scripts/customizer.js 135 bytes {1} [built]
[2] ./scripts/main.js 634 bytes {0} [built]
[3] ./styles/main.scss 41 bytes {0} [built]
[4] ../~/bootstrap/dist/js/bootstrap.js 99.9 kB {0} [built]
[5] ./scripts/routes/about.js 102 bytes {0} [built]
[6] ./scripts/routes/common.js 209 bytes {0} [built]
[7] ./scripts/routes/home.js 203 bytes {0} [built]
[8] ./scripts/util/Router.js 1.39 kB {0} [built]
[9] ./scripts/util/camelCase.js 298 bytes {0} [built]
[10] ../~/tether/dist/js/tether.js 56.4 kB {0} [built]
[11] multi ./scripts/customizer.js 28 bytes {1} [built]
[12] multi ./scripts/main.js ./styles/main.scss 40 bytes {0} [built]
+ 1 hidden modules
Child extract-text-webpack-plugin:
Asset Size Chunks Chunk Names
vendor/fontawesome-webfont_674f50d2.eot 166 kB [emitted]
vendor/fontawesome-webfont_912ec66d.svg 444 kB [emitted] [big]
vendor/fontawesome-webfont_b06871f2.ttf 166 kB [emitted]
vendor/fontawesome-webfont_af7ae505.woff2 77.2 kB [emitted]
vendor/fontawesome-webfont_fee66e71.woff 98 kB [emitted]
[0] ../~/css-loader/lib/css-base.js 1.51 kB {0} [built]
[1] ../~/font-awesome/fonts/fontawesome-webfont.eot 85 bytes {0} [built]
[2] ../~/font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0 85 bytes {0} [built]
[3] ../~/font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0 85 bytes {0} [built]
[4] ../~/font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0 85 bytes {0} [built]
[5] ../~/font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0 87 bytes {0} [built]
[6] ../~/font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0 86 bytes {0} [built]
[7] ../~/css-loader?+sourceMap!../~/postcss-loader!../~/resolve-url-loader?+sourceMap!../~/sass-loader?+sourceMap!./styles/main.scss 800 kB {0} [built]
✨ Done in 7.35s.

Sage 9 dev docs

main.css is not working, so we need to dig into the Sage 9 docs

  1. Theme installation
  2. Theme set-up

ok, to get styles.css rendering properly into into dist folder we need to update sage/main.css to openplanetculture.com/main.css in src/setup.php


add_action('wp_enqueue_scripts', function () {
wp_enqueue_style('openplanetculture.com/main.css', asset_path('styles/main.css'), false, null);
wp_enqueue_script('openplanetculture.com/main.js', asset_path('scripts/main.js'), ['jquery'], null, true);
}, 100);

browsersync and sage 9 dev

now when we update variables such and brand color in openplanetculture.com/site/web/app/themes/openplanetculture.com/assets/styles/common/_variables.scss

we get a change in color instantly !

that’s our baseline with Bootstrap 4

Sage 9 dev Bootstrap 4
Sage 9 dev Bootstrap 4

Part 3

Finally, Semantic UI SASS, working on this now