This was a long and winding path. Every couple of years I go through the same problem. New PHP version, determine installation method, feverishly Google. Sigh.
For my own sanity. I thought it was best to record my workflow. I tried installing PHP via a tried-and-true method:
brew upgrade
brew install php
Awesome. Easy enough right? I now should have PHP 7.4 (as of writing it should be 7.4, that is) installed via Homebrew. Yet when I ran php -v the terminal output was infuriating incorrect:
PHP 7.3.3 (cli) (built: Mar 30 2019 08:43:01) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.3, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.3.3, Copyright (c) 1999-2018, by Zend Technologies
What gives? Why is it still showing the system pre-installed PHP? I Googled and searched for answers frantically to no avail. Then, finally it hit me. My damn .zshrc file. I still have the old installation in my $PATH. To update, I simply removed the old line. Next I added the php keg, so it’s in my $PATH:
I reloaded my shell with source ~/.zshrc and now, when I run php -v I see some results:
PHP 7.4.9 (cli) (built: Aug 7 2020 19:23:06) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.9, Copyright (c), by Zend Technologies
Hope this helps someone else who just wanted to install a damn PHP version but may have overlooked their shell configuration “run commands,” after upgrading with Homebrew π
If you build or customize WordPress themes, coming across Namespaces are going to become more and more commonplace. I think they’re pretty cool. I have never enjoyed having to write (or parse for that matter),Β custom_functions_with_a_weird_long_name.
Steve GrunwellΒ has a fantastic primer on Namespaces, and how to use them in WordPress. I also learned about SingletonsΒ (and their problems in a OOP environment) and why Namespaces are effective.
In short, functions are typically defined in plugins a variety of ways. Not long ago, developers might have written a function like this:
Function name collisions are were pretty likely to occur, so we got longer and longer functions which led to Class encapsulations, so these functions began to make a mess of your codebase with global variable declarations. Steve goes on:
From here, developers seem to have split into two factions: the first, dead-set on removing global variables, moved towardΒ the Singleton pattern:
class MyPlugin() {
protected static $instance;
protected function __construct() {
// Made protected to prevent `new MyPlugin()` calls.
}
public function get_instance() {
if ( ! self::$instance ) {
self::$instance = new MyPlugin();
}
return self::$instance;
}
public function get_recent_posts( $limit = 5 ) {
return new WP_Query( /* ... */ );
}
}
# Usage:
$plugin = MyPlugin::get_instance();
$recent_posts = $plugin->get_recent_posts();
Yikes, what a pickle… But, behold! The proper (and more maintainable effort) with Namespaces:
Okay, so it’s been a while since last time I wrote about Roots (shoutout to Rob for pointing it out). The last time I wrote about the Roots Stack, things were more or less the same. But I felt compelled to write this guide ever since Sage got a version bump.
Secondly, no one enjoys spending precious hours configuring their local setup using a MAMP GUI or fucking up your machine’s hosts file or deliberating on how to fix the dreaded error establishing a database connection. What I love most about Roots is the priority on convention over configuration.
Productivity bonus, spend more time hacking and less time crying
The Roots framework has huge benefits for beginners, and even bigger returns for WordPress veterans. Mainly because you’ll no longer have to FTP your deployments like a goddamn barbarian. But I’ll go into more detail on remote server setup in my next post.
Before I get side-tracked, let’s just dive right in shall we?
Requirements
Let’s talk about requirements and assumptions. I’m assuming you’re using Sublime Text 3 (all other versions make sure you have this enabled) and you understand how to use your terminal. Follow the links below and install the following software.
Below is what we want our project too roughly look like:
example.com/ # β Root folder for the project
βββ trellis/ # β You'ver clone of Trellis
βββ site/ # β A Bedrock-based WordPress site (cloned as well)
βββ web/
βββ app/ # β WordPress content directory (themes, plugins, etc.)
βββ wp/ # β WordPress core (don't touch!)
Create a Sites folder if you havenβt already. I typically put all of my web projects in a Sites folder in my home directory on my Mac. To get started, we’re going to make a directory called example.com β you can name yours whatever project name you’d like:
cd ~/Sites && mkdir example.com && cd example.com
You should be inside the example.com directory at this point. Next we’re going to clone Trellis:
Then we’re going to clone Bedrock (which contains WP Core and our web app, etc.):
git clone --depth=1 git@github.com:roots/bedrock.git site && rm -rf site/.git
At this point, our example.com directory should look like this:
example.com/ # β Root folder for the project
βββ trellis/ # β You'ver clone of Trellis
βββ site/ # β A Bedrock-based WordPress site (cloned as well)
You’ve’re doing great!
Trellis vars
Now let’s get into something a bit more challenging. We’re going into the Trellis directory and need to edit some variables to bring this local WordPress installation to life. I’m assuming you have Sublime Text 3 installed and you’re still in the root of example.com
Then just make sure it looks like this. Replace example.com with the name of the project you have chosen. This is pretty important at this point, as we start getting into the nitty-gritty.
# Make sure your file looks like this
wordpress_sites:
example.com:
site_hosts:
- canonical: example.test
redirects:
- www.example.test
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
admin_email: admin@example.test
multisite:
enabled: false
ssl:
enabled: false
provider: self-signed
cache:
enabled: false
Now go ahead and edit the vault.yml file as well:
subl trellis/group_vars/development/vault.yml
# Make sure the site name (`example.com`) must match up with the site name
# in the file we previously edited: `group_vars/development/wordpress_sites.yml`
# By default Trellis will provision a user `admin` too, below you can set a different
# password if you'd like
vault_wordpress_sites:
example.com:
admin_password: admin
env:
db_password: example_dbpassword
Don’t worry about the other .yml files in the development folder for now.
Vagrant
Vagrant is our savior. It sits between us and the VirtualBox, and does most of the talking. To get our machine running our new local setup we configured (in the wordpress_sites.yml and vault.yml files), we have to go down into our trellis directory and get vagrant running:
cd trellis && vagrant up
By now you should see this a few commands trickling in. At some point vagrant will ask for your sudo password because it needs root permissions.
Enter your password and vagrant will begin installing, provisioning and start running tasks your virtual-machine.
At this point, take a break and chill. The total installation/provision time varies from machine to machine, but it takes around 10-15 minutes on a mid-2015 13″ MacBook Pro. Once the provisioner is done (provided that no errors stopped the installation), you can open your browser and navigate to example.test and you should see this:
Getting started with theme development with Sage
Now that we have a local development environment setup and running, we can move onto creating our first theme! The Roots team put together an awesome starter-theme to speed up development.
Remember our project structure? We’re going to cd our way into the themes directory:
example.com/ # β Root folder for the project
βββ trellis/ # β Trellis
βββ site/ # β A Bedrock-based WordPress site
βββ web/
βββ app/ # β WordPress content directory (themes, plugins, etc.)
| βββ mu-plugins/ # Must-use plugins live here
| βββ plugins/ # Plugins live here, managed by composer.json in the `site` folder
| βββ themes/ # We're going to create our theme HERE.
| βββ uploads/ # WordPress will put uploads here (I wouldn't mess with these)
|
βββ wp/ # β WordPress core (don't touch! Like ever!)
Once we’re in the themes directory, we’re going to run a composer command:
create a composer project with the the roots/sage package
name the theme, “example-theme”
choose the 8.5.3 version of the roots/sage package
As of October 17, 2017 the LTS Sage version is at 8.5.3 which is why I chose that version. You should see composer downloading the packages (be patient, sometimes composer can be slow)
Sage requires Node.js to function. Make sure you are up-to-date.
npm install -g npm@latest
We’re going to use Gulp to build assets (styles, scripts, etc) and Bower will handle any front-end packages such as Bootstrap or Flickity. To get started, cd inside our new theme example-theme. We’re going to install Gulp and Bower globally (if you haven’t already)
npm install -g gulp bower
Now, were’ going to install all the dependencies listed in the package.json
npm install && bower install
Next, let’s open our manifest.json in Sublime Text and configure BrowserSync to proxy our dev URL
subl assets/manifest.json
Make sure the devURL reflects the canonical hostname we wrote in wordpress_sites.yml earlier since our vagrant machine will be listening for traffic at that URL.
At this point, we can go to example.test/wp-admin, and login. From the dashboard, choose Appearance > Themes. Pick your Sage Theme and Visit Site. Everything will look broken now, as no styles exist π
But don’t fret! Next, we go back to the terminal (make sure you’re still in the new theme directory), and run gulp watch. A new tab should open on your browser. That’s BrowserSync loading style changes in real-time (no more βR in Chrome). Save any of the SCSS files in the assets/styles directory and your webpage should reload with the changes. Also watch your terminal π
Gulp literally watches all PHP, SCSS and JS files changes. And BrowserSync will reload your browser window. Pretty nifty. Assuming you didn’t get any errors, your homepage should load with basic styles thanks to Normalizer and Bootstrap.
From here on out, the world is your oyster!
Sage doesn’t give you everything you need for WordPress development but it’s speedy, it’s git-friendly, and it’s modern. I’m not kidding when I say this… the Roots Stack is literally my favorite way to interface with WordPress. Any other way just feels primitive and old.
It gets even better with deployments and remote provisioning which I will cover in my next post.
Wouldn’t it be neat to embed your Unsplash photography on your WordPress site? Unfortunately, there’s no WordPress plugin available. If you’re not familiar, Unsplash is a huge library of photographs for commercial and noncommercial purposes. It’s an awesome resource for designers, prototypers, and developers alike.
So yeah, I figured it would be cool to add a showcase of my Unsplash photos on my website. Upon closer inspection of the Composer wrapper, it looked like it was overkill for my use. But if you’re gonna make a WordPress plugin using Unsplash, you’ll want to use it.
So I began here β first I made a quick blueprint on how I wanted this to go down:
Just a simple page, and a two column grid layout of my photos.
Seems easy yeah? Next, I went to check out what kind of HTTP Response I get from the API with hurl.it and everything is looking hunky-dory so far.
So at this point I realized a few things:
I need to make a simple HTTP request
Decode the JSON
Loop through the array and echo the goodies
I decided on making a simple snippet below:
If you leave line 19 uncommented, you can see the full array and figure out what you want to use from the HTTP request. You can copy/paste that snippet in any template or PHP file and it should work. NOTE: make sure to replace my username and swap YOUR_APPLICATION_ID for your actual App ID from Unsplash.
After a few layers of paint my Photography page now looks like this:
It’s quick and dirty, but at least I won’t have to upload my Unsplash photos to my website manually anymore. It’s all programmatic baby! I’m really happy how this turned out. I tried to make this as simple as possible and under 15 lines of code I think this rocks. But I hope someone else finds this useful!
Let me know how if you have any feedback, improvement or philosophy on this implementation in the comments below. π