<?xml version="1.0" encoding="utf-8" standalone="no"?><feed xmlns="http://www.w3.org/2005/Atom"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="http://jjgrainger.co.uk/atom.xml" rel="self" type="application/atom+xml"/><link href="http://jjgrainger.co.uk/" rel="alternate" type="text/html"/><updated>2026-01-25T12:41:38+00:00</updated><id>http://jjgrainger.co.uk/atom.xml</id><title type="html">jjgrainger</title><subtitle>Web Developer, Falmouth, Cornwall, UK</subtitle><author><name>jjgrainger</name></author><xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><entry><title type="html">Two thousand seven hundred and twenty-one</title><link href="http://jjgrainger.co.uk/2025/08/28/two-thousand-seven-hundred-and-twenty-one/" rel="alternate" title="Two thousand seven hundred and twenty-one" type="text/html"/><published>2025-08-28T00:00:00+00:00</published><updated>2025-08-28T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2025/08/28/two-thousand-seven-hundred-and-twenty-one</id><content type="html" xml:base="http://jjgrainger.co.uk/2025/08/28/two-thousand-seven-hundred-and-twenty-one/"><![CDATA[<p>That’s how many days it’s been since I last posted here.</p>

<p>I won’t go into why it’s been so long. There are reasons, and if I’m honest, it’s something I should explore and understand better.</p>

<p>I also won’t go into why I’ve decided to start again now.</p>

<p>Again, there are reasons, but these are the ones I want to explore, as they should lead to some interesting things in the future.</p>

<p>Hopefully, I follow through this time.</p>

<p>I will. 🙃</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[That’s how many days it’s been since I last posted here.]]></summary></entry><entry><title type="html">Relaunching Oh That’s Nice</title><link href="http://jjgrainger.co.uk/2018/03/17/oh-thats-nice/" rel="alternate" title="Relaunching Oh That’s Nice" type="text/html"/><published>2018-03-17T00:00:00+00:00</published><updated>2018-03-17T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2018/03/17/oh-thats-nice</id><content type="html" xml:base="http://jjgrainger.co.uk/2018/03/17/oh-thats-nice/"><![CDATA[<p>I launched <a href="https://ohthatsnice.net">Oh That’s Nice</a> back in June 2016. It was a side project setup to bookmark websites I like and share them with the world.</p>

<p>I’d first built the site with WordPress. I would create screenshots using various browser extensions, upload the posts to WordPress and have a plugin to schedule out tweets. This setup was fine to begin with but soon things started to fall apart.</p>

<p>The whole process of updating the site was taking forever. The screenshots I was creating were inconsistant sizes and the scheduled posts would fail. In the end it was taking up a lot of my time and the whole thing became a chore.</p>

<p>I had given up on the project for several months but eventually came back with the drive to make things easier.</p>

<h2 id="oh-thats-nice-v20">Oh Thats Nice v2.0</h2>

<p>It was around summer 2017 I decided to do something about it. I’d had enough of spending hours updating the site only to run into problems that would take up more of my time.</p>

<p>After a bit of research, and few months of development, I relaunched <a href="https://ohthatsnice.net">Oh Thats Nice</a> in September 2017.</p>

<p>The main focus of the new site was <em>to automate as much as possible</em>. This forced me to refine the process of updating the site and offload as many of the steps to a variety of scripts and tools.</p>

<p>Now, the time it takes to update the site has been drastically reduced. Automating the different steps involved has made things more consistant and easier to maintain.</p>

<p>Here’s a brief list of the components involved in running Oh That’s Nice.</p>

<ul>
  <li>Taking screenshots with <a href="https://github.com/jjgrainger/webshot">webshot.js</a></li>
  <li>Hosting screenshots to <a href="https://aws.amazon.com/s3/">S3</a> with <a href="https://github.com/jjgrainger/webshot">webshots.js</a></li>
  <li>Static site built with <a href="https://jekyllrb.com/">Jekyll</a></li>
  <li>Automated builds and deploys with <a href="https://travis-ci.org/jjgrainger/ohthatsnice">Travis CI</a></li>
  <li>Hosting with <a href="https://surge.sh">Surge</a></li>
  <li>Further automation with <a href="https://github.com/jjgrainger/nicebot">nicebot</a></li>
</ul>

<p>I’ll go into more detail about some of steps taken in future blog posts, but in the mean time, <a href="https://ohthatsnice.net">visit the site</a>, check it out on <a href="https://github.com/jjgrainger/ohthatsnice">Github</a> and follow the project on <a href="https://twitter.com/OhThatsNice_">Twitter</a>.</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[I launched Oh That’s Nice back in June 2016. It was a side project setup to bookmark websites I like and share them with the world.]]></summary></entry><entry><title type="html">Twenty Seventeen</title><link href="http://jjgrainger.co.uk/2018/01/02/twenty-seventeen/" rel="alternate" title="Twenty Seventeen" type="text/html"/><published>2018-01-02T00:00:00+00:00</published><updated>2018-01-02T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2018/01/02/twenty-seventeen</id><content type="html" xml:base="http://jjgrainger.co.uk/2018/01/02/twenty-seventeen/"><![CDATA[<p>A Happy New Year to you all!</p>

<p>It’s that time of year again for looking back to see how far we’ve come. 2017 was a rather productive year for me where I have tackled some big tasks.</p>

<p>Here are some of the highlights of my 2017.</p>

<h4 id="released-posttypes-v20">Released PostTypes v2.0</h4>

<p>This year I set about adding unit tests to <a href="https://github.com/jjgrainger/posttypes">PostTypes</a>. This was an interesting endeavour and I learnt a lot in the process.</p>

<p>Adding unit tests to a project that works with WordPress can be a tricky task at best. I did a lot of research and documented my thoughts in an <a href="https://github.com/jjgrainger/PostTypes/issues/9">issue on Github</a>. There I expressed the problems I was facing along with potential solutions.</p>

<p>In the end it took some time but it turned out to be rather painless, and in October I released <a href="https://github.com/jjgrainger/posttypes">PostTypes</a> 2.0. Now I need to create better documentation for it.</p>

<h4 id="rebuilt-oh-thats-nice">Rebuilt Oh Thats Nice</h4>

<p>I released <a href="https://ohthatsnice.net/">Oh Thats Nice</a> back in 2016. I built it on WordPress but soon came to realise that was a mistake. The process of adding a new site to the gallery was taking far too long and hosting was becoming an issue.</p>

<p>Wanting to automate a lot of the work, I made a decision to rebuild the site using <a href="https://jekyllrb.com/">Jekyll</a>. This allowed me to manage posts using <a href="https://github.com/jjgrainger/ohthatsnice">git</a>, have the site built with <a href="https://travis-ci.org/jjgrainger/ohthatsnice">Travis CI</a> and deployed to <a href="http://surge.sh/">Surge</a>.</p>

<p>I automated things further by creating and uploading screenshots programatically with <a href="https://github.com/jjgrainger/webshot">Webshot</a>. I then went automation crazy and started work on a twitter bot for the <a href="https://twitter.com/OhThatsNice_">@OhThatsNice_</a> account.</p>

<p>I’ll be working on this project more in the year to come.</p>

<h4 id="cleaned-up-hosting">Cleaned up hosting</h4>

<p>I occasionally make websites for friends which I also host. The hosting I was using for several years had become slow, outdated and a complete mess.</p>

<p>The process took a lot longer than I’d like to admit but I finally finished migrating all sites to a new setup. Using Pixeno’s reseller hosting has cleaned everything up. Each site has it’s own cPanel making things much easier to manage and setup new sites.</p>

<p><em>If you’re looking for a new host <a href="https://pixeno.com/account/aff.php?aff=70">Pixeno</a> (affiliate link) is a great company offering developer friendly hosting with good support.</em></p>

<h4 id="looking-forward-to-2018">Looking forward to 2018</h4>

<p>I’m stepping into 2018 with a lot of excitement. I’ve got some new projects lined up which I’m eager to get into and will be a lot of fun to build.</p>

<p>I’m planning on writing more for this blog giving insights into some of the things I have been working on. So keep coming back over the year to get a sneak peak at the projects I’ll be building.</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[A Happy New Year to you all!]]></summary></entry><entry><title type="html">A scaffold for creating scaffolds</title><link href="http://jjgrainger.co.uk/2017/04/09/a-scaffold-for-creating-scaffolds/" rel="alternate" title="A scaffold for creating scaffolds" type="text/html"/><published>2017-04-09T00:00:00+00:00</published><updated>2017-04-09T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2017/04/09/a-scaffold-for-creating-scaffolds</id><content type="html" xml:base="http://jjgrainger.co.uk/2017/04/09/a-scaffold-for-creating-scaffolds/"><![CDATA[<p>Scaffolding is nothing new, but is still a powerful way to get setup on any type of project. It generates a starting point by creating the basic file and folder structure. All done faster than if you were to start building the project from scratch.</p>

<p>There are plenty of tools out there with <a href="http://yeoman.io/">Yeoman</a> being the most popular. Yet, my go-to tool for scaffolding is <a href="http://gruntjs.com/project-scaffolding">Grunt</a>. It’s simplicity and flexibility is what makes it very easy to set up a scaffold to your liking.</p>

<p>I’ve abused this flexibility by creating scaffolds for many types and projects. I have even gone so far to create a <a href="https://github.com/jjgrainger/scaffold">scaffold for scaffolds</a>.</p>

<h2 id="a-scaffold-for-scaffolds">A scaffold for scaffolds</h2>

<p>This quick and dirty scaffold…</p>

<ul>
  <li>Prompts you for some basic info</li>
  <li>Creates and populates a <code class="language-plaintext highlighter-rouge">README.md</code> from the prompts provided</li>
  <li>Creates a basic <code class="language-plaintext highlighter-rouge">teamplate.js</code> to help you get started</li>
  <li>Creates an empty <code class="language-plaintext highlighter-rouge">root</code> directory for all the files you want to process and copy</li>
</ul>

<p>It’s very basic, but enough to get you creating a scaffold for whatever your needs. I’ve also included a brief <a href="https://github.com/jjgrainger/scaffold/blob/master/Creating-Scaffolds.md">document</a> with some useful tips to help get you started.</p>

<p>Happy scaffolding!</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[Scaffolding is nothing new, but is still a powerful way to get setup on any type of project. It generates a starting point by creating the basic file and folder structure. All done faster than if you were to start building the project from scratch.]]></summary></entry><entry><title type="html">Twenty Sixteen</title><link href="http://jjgrainger.co.uk/2017/01/03/twenty-sixteen/" rel="alternate" title="Twenty Sixteen" type="text/html"/><published>2017-01-03T00:00:00+00:00</published><updated>2017-01-03T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2017/01/03/twenty-sixteen</id><content type="html" xml:base="http://jjgrainger.co.uk/2017/01/03/twenty-sixteen/"><![CDATA[<p>Here are the highlights of my 2016</p>

<h4 id="hit-5-blood-donations">Hit 5 Blood donations</h4>
<p>I gave my 5th blood donation in July and have given blood 7 times to date. Next donation is booked in for March.</p>

<h4 id="best-man-at-wedding">Best man at wedding</h4>
<p>On a beautiful, sunny day in July, a friend and I were best men for two of our life long friends.</p>

<h4 id="moved-into-a-new-flat">Moved into a new flat</h4>
<p>My girlfriend and I moved into our new flat in November and hosted Christmas for our friends.</p>

<h4 id="posting-a-little-more">Posting a little more.</h4>
<p>I’ve published 6 posts in 2016, that’s double the amount published in 2015, but not as much as I would like. We’ll see how 2017 goes.</p>

<h4 id="released-posttypes">Released PostTypes</h4>
<p>I released <a href="https://github.com/jjgrainger/PostTypes">PostTypes</a> in August. Today it has 38 stars and 5 forks.</p>

<h4 id="started-a-million-side-projects">Started a million side projects</h4>
<p>I’ve started a million side projects throughout the year. To get them finished, I plan to work through them one by one over the year.</p>

<p>Let’s see what happens for 2017.</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[Here are the highlights of my 2016]]></summary></entry><entry><title type="html">Kitten Therapy</title><link href="http://jjgrainger.co.uk/2016/11/03/kitten-therapy/" rel="alternate" title="Kitten Therapy" type="text/html"/><published>2016-11-03T00:00:00+00:00</published><updated>2016-11-03T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2016/11/03/kitten-therapy</id><content type="html" xml:base="http://jjgrainger.co.uk/2016/11/03/kitten-therapy/"><![CDATA[<p>Recently it was National Stress Awareness Day and <a href="https://twitter.com/hashtag/NationalStressAwarenessDay">Twitter</a> was full of videos, articles and tips on how to combat stress.</p>

<p>People manage stress in a variety of ways. Some meditate to level themselves by watching their breath. Others exercise to work out the stress they’re feeling. And a simple walk in the park can make you feel calm.</p>

<p>What about fluffy kittens? Cute, tiny, fluffy kittens!</p>

<p><img src="http://i.giphy.com/AF3xMm5xbp8k0.gif" alt="kitten" /></p>

<p>If kittens are your thing, and you use <a href="https://hubot.github.com/">Hubot</a> as your chatbot, I’ve created a script that delivers gifs of cute kittens on demand.</p>

<script src="https://gist.github.com/jjgrainger/2e7f814b2fc0113e3bfb79e00716c2fc.js"></script>

<p>Once installed, simply type <code class="language-plaintext highlighter-rouge">hubot kittens</code> to receive a dose of kitten therapy. You will feel the stress escape you as you watch gifs of adorable kittens.</p>

<p>Enjoy!</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[Recently it was National Stress Awareness Day and Twitter was full of videos, articles and tips on how to combat stress.]]></summary></entry><entry><title type="html">Homebrew, Casks and a Brewfile</title><link href="http://jjgrainger.co.uk/2016/10/25/homebrew-casks-and-a-brewfile/" rel="alternate" title="Homebrew, Casks and a Brewfile" type="text/html"/><published>2016-10-25T00:00:00+00:00</published><updated>2016-10-25T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2016/10/25/homebrew-casks-and-a-brewfile</id><content type="html" xml:base="http://jjgrainger.co.uk/2016/10/25/homebrew-casks-and-a-brewfile/"><![CDATA[<p>My Macbook air keeps crashing and over the 3 years owning it I’ve had to wipe the hard drive and reinstall everything at least 10 times.</p>

<p>Ignoring the computer issues, I believe there are benefits to starting fresh once in a while. It’s as though you clear away the cobwebs, making things run soother. It’s as if you’ve bought a brand new machine.</p>

<p>But, as nice as it can be, it is a pain the ass to go through and install everything you had before. All you’re apps, preferences, scripts like node and git, there’s a lot to get through. However, there is a eloquent solution available.</p>

<h2 id="homebrew">Homebrew</h2>

<p><a href="http://brew.sh/">Homebrew</a> is the missing package manager for Mac OS and it makes installing things a breeze. Gone are the days of searching, downloading and installing the things you want manually.</p>

<p>Its simple to use and all done via the command line. As an example, to install git, you would run the following in your terminal.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew intsall git
</code></pre></div></div>

<h2 id="casks">Casks</h2>

<p>Homebrew doesn’t just install developer scripts, it can also install a lot of your favourite apps with the help of <a href="https://caskroom.github.io/">Homebrew Casks</a>. So, to install Spotify you would simply run the following in your terminal.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew cask install spotify
</code></pre></div></div>

<h2 id="homebrew-bundle">Homebrew Bundle</h2>

<p><a href="https://github.com/Homebrew/homebrew-bundle">Homebrew Bundle</a> is a great way to manage the apps and scripts you want to install. By creating a single <code class="language-plaintext highlighter-rouge">Brewfile</code>, you can list out everything you want to install, then simply run <code class="language-plaintext highlighter-rouge">$ brew bundle</code>. Homebrew will work through the dependecies listed and install them if they haven’t been already.</p>

<p>Here’s an example of what a <code class="language-plaintext highlighter-rouge">Brewfile</code> might look like.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Configure where our applications go
cask_args appdir: '/Applications'

# install scripts we want
brew 'wget'
brew 'git'
brew 'hub'
brew 'heroku-toolbelt'
brew 'node'

# get brew cask for apps
tap 'caskroom/cask'

# install the apps we want
cask 'sublime-text'
cask 'google-chrome'
cask 'iterm2'
cask 'alfred'
cask 'dropbox'
cask 'spotify'
cask 'flux'
cask 'caffeine'
cask 'slack'
</code></pre></div></div>

<h2 id="lets-automate-it-all">Lets automate it all</h2>

<p>Combining all three we can create a small script that will install homebrew and all our apps and dependencies automatically for us.</p>

<p>First, lets create a quick <code class="language-plaintext highlighter-rouge">install.sh</code> script. This will check to see if homebrew is installed, If it’s not we’ll install it. Once Homebrew is installed we’ll run <code class="language-plaintext highlighter-rouge">$ brew bundle</code>, installing all the dependencies inside our Brewfile.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
#
# Install all the things with Homebrew, Casks and a Brewfile
#

# If Homebrew is not installed
if ! which brew &gt; /dev/null; then
     # Install Homebrew 
     /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
fi;

# Update brew
brew update

# Install everything in Brewfile
brew bundle
</code></pre></div></div>

<p>With everything done, when we come to setup a new machine all we have to do is download the <code class="language-plaintext highlighter-rouge">install.sh</code> and <code class="language-plaintext highlighter-rouge">Brewfile</code>, and run the following.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./install.sh
</code></pre></div></div>

<p>Then go make yourself a brew and enjoy, leaving homebrew to handle the rest. All the code used here can be found on <a href="https://github.com/jjgrainger/Brew">Github</a>. Fork it, make it your own and enjoy Homebrew handling your Mac setup for you.</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[My Macbook air keeps crashing and over the 3 years owning it I’ve had to wipe the hard drive and reinstall everything at least 10 times.]]></summary></entry><entry><title type="html">Write everything down</title><link href="http://jjgrainger.co.uk/2016/10/17/write-everything-down/" rel="alternate" title="Write everything down" type="text/html"/><published>2016-10-17T00:00:00+00:00</published><updated>2016-10-17T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2016/10/17/write-everything-down</id><content type="html" xml:base="http://jjgrainger.co.uk/2016/10/17/write-everything-down/"><![CDATA[<p>When the busyness of our day overloads our minds with information, any attempt to remember it all in our heads is futile. As one item comes in, two get pushed out. Things are forgotten and reappear when it’s all too late. Oh, and that interesting article you wanted to read later? Well, it’s now lost in the vast sea of the internet.</p>

<p>So if you’re trying to keep a track of anything solely in your head, you’re setting yourself up for a fall.</p>

<p>But, what can we do to help us keep track of all this information? The answer is simple.</p>

<p><em><strong>Write</strong></em>. <em><strong>Everything</strong></em>. <em><strong>Down</strong></em>.</p>

<p>It seem’s obvious but how often do we actually take the time jot something down? I used to believe I could remember it all in my head, but as things began to slip, something needed to change.</p>

<p>I made a promise to myself that I would write everything down. Any tasks, notes, important dates, thoughts and ideas, I would write them down. I’ve stuck with it and over the years the benefits have been great.</p>

<p>Here a few key points I’ve learnt by simply writing everything down.</p>

<h2 id="thoughts-become-real">Thoughts become real</h2>

<p>When you commit something to paper, you’re making it <em>real</em>. It no longer exists in your headspace floating around waiting to be forgotten. Instead, it becomes permanent. Something you can trust will be there waiting for you when you need it.</p>

<p>Writing down your ideas and goals is the first step to making them a reality. They’re no longer just an idea you hope to achieve, but a gentle reminder to start working and make them real.</p>

<h2 id="your-mind-becomes-clear">Your mind becomes clear</h2>

<p>By taking each item out of your head and onto paper you’re making space for other things. You’re no longer wasting energy as thoughts battle for your brains attention. Instead, you clear your mind. Creating space for new ideas.</p>

<p>When your mind is clear you’re able to focus on the task at hand. If not your focus is pulled in all directions as you juggle everything in your head, leading to burnout. But, with everything out of your head, you can approach anything with a clear mind. Giving it the focus it deserves.</p>

<h2 id="pick-a-tool-and-stick-with-it">Pick a tool and stick with it</h2>

<p>There are plenty of apps out there designed to help you with this. All boasting and competing with one another. This makes it easy to jump around each of them trying to find the perfect one.</p>

<p>My advice would be to pick one and stick with it. And stick with it for quite some time.</p>

<p>I started with <a href="http://evernote.com">Evernote</a> only using it to manage tasks and after a few days, it felt like it wasn’t working. But I stuck with it.</p>

<p>Now I use it for <em>everything</em>. It holds tasks, lists, ideas, blog posts, bookmarks, articles I want to read later and more. It’s become a crucial part of my day to day, allowing me to capture and recover whatever I need, whenever I need it.</p>

<p>So whatever you pick, stick with it for a while. Push its boundaries and really trial it out before jumping onto the next thing.</p>

<h2 id="remember-pen-and-paper">Remember Pen and Paper?</h2>

<p>Don’t forget about the traditional methods too. Pen and paper can still be just as effective as any fancy app. I believe in most cases pen and paper provides more freedom. You can draw out ideas in whatever form they may take, which most apps fail to provide as a feature.</p>

<p>I have a <a href="/2015/02/23/a-developers-sketchbook/">sketchbook</a> that sits on my desk that I use it for exactly that reason. I can sketch complex ideas and map out my thought process as I go. Sometimes, ideas are better expressed visually.</p>

<h2 id="make-a-commitment">Make a commitment</h2>

<p>You can’t do this half-hearted. If you want to make this change, you have to commit to it 100%. You want to be consistent, doing this each day.</p>

<p>I didn’t use Evernote for everything from the start, but I used it every day. By writing tasks down each day I was building a habit, and overtime it began to stick and things got easier.</p>

<h2 id="get-started">Get started</h2>

<p>So, go ahead, pick and app, or maybe a sketchbook or journal. Whatever you choose, start writing. Turn your thoughts into reality. Clear your mind and make a commitment to write everything down.</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[When the busyness of our day overloads our minds with information, any attempt to remember it all in our heads is futile. As one item comes in, two get pushed out. Things are forgotten and reappear when it’s all too late. Oh, and that interesting article you wanted to read later? Well, it’s now lost in the vast sea of the internet.]]></summary></entry><entry><title type="html">Introducing PostTypes</title><link href="http://jjgrainger.co.uk/2016/10/02/introducing-posttypes/" rel="alternate" title="Introducing PostTypes" type="text/html"/><published>2016-10-02T00:00:00+00:00</published><updated>2016-10-02T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2016/10/02/introducing-posttypes</id><content type="html" xml:base="http://jjgrainger.co.uk/2016/10/02/introducing-posttypes/"><![CDATA[<p>I released the <a href="https://github.com/jjgrainger/wp-custom-post-type-class">WordPress custom post type class</a> back in May 2013. Since then it has been received well by the community with over 250 stars on Github and growing. People have made some great contributions, helping to take it further and make it what it is today. It has even been recommended by other open source projects like <a href="http://getherbert.com/0.9/custom-post-types">Herbert</a>.</p>

<p>Over the years I have looked at ways to try and Improve the class. I began to identify things I would have done differently as well as things I wanted to add. It took some time, but I decided to release a completely new version of the project, <a href="https://github.com/jjgrainger/PostTypes">PostTypes</a>.</p>

<p>Here are just a few things that PostTypes does to make it easier to use than its predecessor.</p>

<h2 id="psr-4-autoloading">PSR-4 Autoloading</h2>

<p>The custom post type class was set up for <a href="http://www.php-fig.org/psr/psr-0/">PSR-0</a> autoloading which is now deprecated. You can download the file and add it to your project by hand, but that seems a bit old fashioned.</p>

<p>To take full advantage of <a href="https://getcomposer.org/">Composer</a>, PostTypes uses <a href="http://www.php-fig.org/psr/psr-4/">PSR-4</a> autoloading. This makes it quick and easy to install, setup and get started.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// include Composers autoloader</span>
<span class="k">require</span> <span class="k">__DIR__</span> <span class="mf">.</span> <span class="s1">'/vendor/autoload.php'</span><span class="p">;</span>

<span class="kn">use</span> <span class="nc">PostTypes</span><span class="o">/</span><span class="nc">PostType</span><span class="p">;</span>

<span class="c1">// ready to use class</span>
</code></pre></div></div>

<h2 id="a-better-api">A Better API</h2>

<p>When I created the custom post type class I designed it from the API back. In an empty file, I wrote out how I wanted to use the class and its methods. And from that, I started working on the functionality. I believe this lead to its ease of use, but now parts of it feel.. icky.</p>

<p>I admire <a href="https://laravel.com/">Laravels</a> API. It’s simple, easy to read and feels human and with PostTypes, I wanted to achieve the same thing.</p>

<p>What seemed simple enough ended up becoming quite difficult as you start to pick at minor details. But yet, it’s the small things that can make a huge difference.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// create a book post type</span>
<span class="nv">$books</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PostType</span><span class="p">(</span><span class="s1">'book'</span><span class="p">);</span>

<span class="c1">// add a genre taxonomy</span>
<span class="nv">$books</span><span class="o">-&gt;</span><span class="nf">taxonomy</span><span class="p">(</span><span class="s1">'genre'</span><span class="p">);</span>

<span class="c1">// set the menu icon</span>
<span class="nv">$books</span><span class="o">-&gt;</span><span class="nf">icon</span><span class="p">(</span><span class="s1">'dashicons-book-alt'</span><span class="p">);</span>
</code></pre></div></div>

<h2 id="better-column-management">Better column management</h2>

<p>One issue with the original class was there was no efficient way to manage columns. To add one column you would have to define them <em>all</em>, which made the process painfully tedious.</p>

<p>Now PostTypes has a column manager that handles this more efficiently. There are a handful of new methods that allow you to add, hide and order columns giving you more flexibility. The original methods to set, populate and define sortable columns, are now part of the column manager.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// hide multiple columns</span>
<span class="nv">$books</span><span class="o">-&gt;</span><span class="nf">columns</span><span class="p">()</span><span class="o">-&gt;</span><span class="nf">hide</span><span class="p">([</span><span class="s1">'author'</span><span class="p">,</span> <span class="s1">'date'</span><span class="p">]);</span>

<span class="c1">// add custom columns</span>
<span class="nv">$books</span><span class="o">-&gt;</span><span class="nf">columns</span><span class="p">()</span><span class="o">-&gt;</span><span class="nf">add</span><span class="p">([</span>
    <span class="s1">'price'</span> <span class="o">=&gt;</span> <span class="nf">__</span><span class="p">(</span><span class="s1">'Price'</span><span class="p">),</span>
    <span class="s1">'rating'</span> <span class="o">=&gt;</span> <span class="nf">__</span><span class="p">(</span><span class="s1">'Rating'</span><span class="p">),</span>
<span class="p">]);</span>

<span class="c1">// set the order for particular columns</span>
<span class="nv">$books</span><span class="o">-&gt;</span><span class="nf">columns</span><span class="p">()</span><span class="o">-&gt;</span><span class="nf">order</span><span class="p">([</span>
    <span class="s1">'rating'</span> <span class="o">=&gt;</span> <span class="mi">2</span><span class="p">,</span>
    <span class="s1">'genre'</span> <span class="o">=&gt;</span> <span class="mi">4</span>
<span class="p">]);</span>
</code></pre></div></div>

<h2 id="whats-next">What’s next?</h2>

<p>One of the many reasons for creating PostTypes was to help future-proof the project. I believe the changes made will make it easier make changes and improvements in the long run.</p>

<p>So why not give <a href="https://github.com/jjgrainger/PostTypes">PostTypes</a> a try the next time you need to make a custom post type in WordPress.</p>

<p>The books example used in this post is available in full <a href="https://github.com/jjgrainger/PostTypes/blob/master/examples/books.php">here</a>.</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[A big update to the WordPress custom post type class]]></summary></entry><entry><title type="html">Htaccess trick for syncing WordPress uploads</title><link href="http://jjgrainger.co.uk/2016/05/02/htaccess-trick-for-syncing-wordpress-uploads/" rel="alternate" title="Htaccess trick for syncing WordPress uploads" type="text/html"/><published>2016-05-02T00:00:00+00:00</published><updated>2016-05-02T00:00:00+00:00</updated><id>http://jjgrainger.co.uk/2016/05/02/htaccess-trick-for-syncing-wordpress-uploads</id><content type="html" xml:base="http://jjgrainger.co.uk/2016/05/02/htaccess-trick-for-syncing-wordpress-uploads/"><![CDATA[<p>When working with WordPress it can be a pain keeping your local version up to date with the production site, especially all the images and files contained in the uploads folder.</p>

<p>Having to download the uploads via FTP can take some time, fortunately with a simple .htaccess trick you can use the live version of images when they’re not available locally.</p>

<p>Simply create a <code class="language-plaintext highlighter-rouge">.htaccess</code> file inside the <code class="language-plaintext highlighter-rouge">/uploads</code> folder with the following code, replacing the URL with the production sites address.</p>

<div class="language-apache highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Attempt to load files from production if they're not in our local version</span>

<span class="nc">RewriteEngine</span> <span class="ss">on</span>
<span class="nc">RewriteCond</span> %{REQUEST_FILENAME} !-d
<span class="nc">RewriteCond</span> %{REQUEST_FILENAME} !-f
<span class="nc">RewriteRule</span> (.*) http://domain.com/wp-content/uploads/$1
</code></pre></div></div>

<p>Make sure you put this file inside the <code class="language-plaintext highlighter-rouge">/uploads</code> directory and change the URL to the production sites address.</p>

<p>What this will do is first look for the local version of the file, if that doesn’t exists it will then attempt to grab the production version and use that.</p>

<p>This isn’t a full proof solution, its a simple trick to avoid having to go through the tedious task of syncing your local site with production.</p>

<p>For a more professional solution I would check out <a href="https://deliciousbrains.com/wp-migrate-db-pro">WP Migrate DB Pro</a> and its <a href="https://deliciousbrains.com/wp-migrate-db-pro/#addons">Media files addon</a>.</p>]]></content><author><name>jjgrainger</name></author><summary type="html"><![CDATA[When working with WordPress it can be a pain keeping your local version up to date with the production site, especially all the images and files contained in the uploads folder.]]></summary></entry></feed>