A New Journey at Finder.com

I remember about 5 years ago, I was building themes for StudioPress. I had near daily meetings with wonderful people like Brian, Rafal, and Lauren. That was the last time I worked on a product.

For the last 5 years since that time I’ve worked exclusively in client services. At first this was nice, but (like with all things) I began to get tired of the continuous rhythm of starting from scratch every time a new project came in.

At times this was beneficial, of course — but that’s only if I hated my current project. More often, a sadness would overshadow any excitement whenever a new project came along; mocking my effort to create something beautiful, only to hand it off to someone else.

That’s why, when Finder.com reached out with an opportunity to build a large-scale application on top of WordPress, I couldn’t resist.

A True WordPress-Powered Application

Finder.com is many things, but most relevant to my area of expertise is the CMS portion. Hinging on countless comparisons that drive its value, Finder.com prides itself on being the first in most emerging markets. Behind this effort is a massive publication team utilizing WordPress to independently drive engagement in their respective “niche”.

The bulk of my responsibility is to make this process as easy and seamless as possible, and the most obvious way at the moment is through custom Gutenberg blocks.

These blocks range form simple to complex, locally retrieving data as well as communicating with several external APIs to gather product, niche, and consumer data for comprehensive comparisons.

Beyond Gutenberg, Finder is exploring new ways to delivery dynamic content to consumers through headless architecture, with major upgrades coming down the pipeline to improve speed, interaction, and interoperability.

All of this makes me incredibly excited to work with such a talented team, and push WordPress literally to the bleeding edge of innovation.

What About This Blog?

Some of you may be wondering what is going to happen with this blog and why I can’t seem to update it like I keep saying I will. The truth is, I’ve learned by now not to actually say, because history has shown me that I really don’t know.

I do want to revamp it on Gatsby or Next, and begin either doing podcasting/videos or selling products/ebooks. But whether I have bandwidth or time for that, I have yet to find out.

In the meantime, maybe you can tell me what you’d like to hear or learn from me? Any comments will go a long way toward helping me decide.

Till next time!

Black Lives Matter

The United States of America burns, and if you didn’t see it coming then you weren’t paying attention.

Before you berate me for “justifying” violence, hear me out. For starters, I don’t agree with looting. I don’t agree with violence against innocent people.

Yet, in this day, I completely understand it.

Setting aside all conspiracy theories for a second, you’d have to be living under a rock to not notice the growing voice of a hurting and disheartened Black community. To ignore such a cry for so long can and will only end in violence — it is the last resort, the last straw of a desperate people group who have to scream louder in order to be heard (or taken seriously).

I’m 100% white. About as white as it gets, and I’ve heard the cries of injustice for most of my adult life. I’ve also seen just about every cry for justice be ignored (or written off) by my Christian and white brothers and sisters for nearly as long.

In the beginning, I wasn’t sure what to believe. Was racism really still a thing? I thought this ended after Abraham Lincoln became the hero of our history books and ended the oppression of slavery.

And yet, here we are.

I’m not sure where to stand or what to say. On the one hand, I decry the mindless destruction happening within our country, tearing us apart — but I also wonder if we’ve been torn apart for quite some time, and it’s only now boiling to the surface.

America is no longer the beacon of hope in the world that I grew up believing and hoping it was. And humanity? Well — we’re not exactly winning either. As much as I wish it wasn’t so, there is no clean slate when we enter this world — we all have to pick up the pieces of those who came before us. To pretend otherwise is to cause more pain.

I dream of a better day, where everyone is healed of their hate and pain, ego and pride, and numbed apathy. But that day is not today.

Whatever your disposition to recent events, I hope you take a moment of silence, and acknowledge the brokenness of our generation — not that of your neighbor, but your own.

People are always hurting, but the people hurting in front of us right now — through the shattering sound of protest, and yes, violence — are Black. They deserve our compassion, our empathy, and validation. Just because you may not understand or see the racism does not mean it doesn’t exist for them on a daily basis.

I’m not sure how to start picking up the pieces. But I will, until the day I die, join and champion any voice that says Black Lives Matter.

Because they do.

The Good Side of Pendulum Swings

I used to hate that I’d jump from creative explosion to near-dormant existence (one might argue that I’m currently in the latter stage). Still, the “pendulum swing”, as some may call it, was alive and visibly well.

Then one day, it all stopped. I burnt out. I couldn’t quite put my finger on why, but I basically cancelled everything (including my newsletter I had spent years trying to build).

I was tired of the endless back-and-forth.

A New Kind of Swing

The beautiful thing about pendulums is that they just keep going. The momentum of one leads to the momentum of the other — and endless circle of give and take, rest and effort, rinse and repeat.

Recently, my wife and I took our 3 very restless boys (6 and under) to the woods. It was my wife’s birthday as well, so the 4-day trip was wonderfully celebratory in nature. But more than that, it was unplugged.

There was no cell-service, and we drove up a Forest Service road that had no camping facilities whatsoever. We packed in everything, and packed everything out.

The Right Pendulum

The one thing I realized on this trip was that I had the wrong swing for many years. I tried so hard to be creative and build something beautiful — the hustle usually lasting for several months — before I crashed and took a break zoning out on XBOX and Netflix. My swing was that of production/consumption, and while it certainly was a swing, it wasn’t rejuvenating.

The beauty of “roughing” it in the wild is that it’s the exact opposite of my modern and technologically-fat normal day life. It’s the other end of my pendulum swing.

The more I stay in my normal life of digital interaction, the more I yearn for the other end of my pendulum; and the longer I spend in the rough and wild side of life, the more I yearn for the modern conveniences that I take for granted.

The pendulum swing is balanced.

Find Your Swing

Naturally, not everyone loves the outdoors, nor is their normal life so heavily influenced by digital devices as mine.

The point of this post is to encourage you to find that pendulum swing that can become an endless cycle, where burnout is tamed through balance.

Whatever it is, I’m sure you’ll find it. Just keep looking.

p.s. We roughed it about as much as you can in a camper, but I was really impressed that we got it up a treacherous canyon dirt road. My three boys had a total blast, as did Tanya and I.

Introducing Proxy-State

On a recent project, I needed to handle some global state and make sure a couple elements on the DOM responded reactively to any changes in that state.

The temptation to reach for a library or framework like React is all-to-tempting a lot of the time — while it’s easy and familiar, loading a giant framework like can be (and usually is) excessive.

In the end, I opted for building somewhat of a rigid solution with vanilla JS, and it was clear that future flexibility and any added side-effects to the global state would become heavy to manage.

Enter Proxy-State

To prevent this in the future, I built a lightweight package for managing global state and subscribing to its changes over time.

The underpinning of the package is the Proxy Object (hence the name), which allows setting custom behavior on normal operations. I won’t get into the details of the interface here, as Proxy-State acts as an abstraction layer on top to make things easier.

Currently, Proxy-State has no support for Internet Explorer. If you find a polyfill, I’d love to see it in the comments!

Using Proxy-State

Install the package via npm or yarn:

npm i proxy-state

In your main entry file, create a store with the following:

import Store from 'proxy-state'

const myStore = Store({
  count: 0

The default import of the package gives you a constructor function, which takes a single argument: an object representing your default state.

The constructor will return an object, with 4 properties:

state: {}

The current global state object.

listen: (fn( newState, oldState), ?key)

Applies a callback for when state changes. Optionally can pass a unique key as a secondary argument to only run the callback when a property that matches the key changes.

detach: (key)

Removes a registered callback by its the key that was used to register it.

fetch: (key, ...rest)

Fetches an array of registered subscribers by their keys.


For now, you can only have one callback per key. I did this to force consideration of what is done within a listener, but I may allow more in the future.

That’s it! I would love to hear your thoughts or special use-cases that aren’t covered. This is in an initial version, but I hope it makes managing state a simpler experience for basic projects.

Code-Splitting in WordPress

I’m sure you’ve been here before: you’ve just been assigned to this large project on a major client website. It includes a cohesive component-driven design system, and strives to reuse and inherit those components throughout the application.

You think to yourself, “This is going to be great!”

You open up your code editor of choice, and gleefully start the new project (this articles assumes a 10up Theme Scaffold structure, but the principles apply anywhere).

You’re ready to make some engineering magic.

Fast-forward 8 weeks and you’re about done. Each component is nestled nicely in a theme partial, and equally segmented in your CSS and JS folders, under a unified naming scheme.

Everything works great. Except one small, or shall we say large, problem: your JavaScript file is just over 2 megabytes in size, even when it’s compressed.

We’ve all been here, and there’s nothing like the feeling of months of quality module building getting nullified by poor performance.

It’s usually at this point that we begin wishing we were using React as our main application infrastructure, depressingly watching as other applications, just like ours, code-split their dependencies on the fly and deliver (if done correctly) resources to the browser half the size of ours.

The Problem

Take heart though. In many cases, the performance gains achieved by JS frameworks in terms of asset size are lost by the sheer size of the frameworks themselves, often-times hitting sizes upwards of 2-3mb.

Still, code-splitting asset delivery is the great envy of the WordPress stack. But delivering only what’s necessary to the user is an uphill battle, and usually results in multiple conditionals throughout the code-base, if not just as many JavaScript files.

When modern WordPress sites rely on JavaScript almost as much as they do PHP, we begin to dance with two resources that are not inherently aware of each other. Conditionals duplicate between languages, and if we try to achieve true dynamic asset delivery we usually pay the price in terms of technical debt.

Recently, I experimented with a method for achieving on-demand components while keeping complexity to a minimum. I’d love to hear your feedback!

Code-Splitting to the Rescue

Webpack comes with a great feature known as code-splitting. Without getting into too much configuration detail, you can enable code-splitting in the 10up Theme Scaffold with 3 basic changes:

1. Update Output Config

The first thing we need to do is configure where Webpack should store our modules. Within /config/webpack.common.js, update the output parameter with the following directives:

module.exports = {
  output: {
    chunkFilename: '[name].bundle.js',
    publicPath: '/wp-content/themes/{your-theme-name}/{your-build-folder}/'

There are two things happening here:

  1. We’re telling Webpack what kind of name to use for chunk files. The [name] here is a Webpack variable that gets replaced at build time.
  2. We’re telling Webpack where these chunk files are located (it will default to the build destination).

2. Configure Dynamic Imports

The second thing we’ll do is add the @babel/plugin-syntax-dynamic-import dependency to our project. Do this by running:

npm install @babel/plugin-syntax-dynamic-import -D

Next, we need to make sure that Webpack knows that dynamic imports require Promise support (since internally it will fetch the module via a Promise request). We can do this with the @babel/preset-env preset by defining a couple of options.

In your /config/webpack.commons.js ensure the following is present on your babel-loader options (this might also be defined in your .babelrc file, so check there too):

loader: 'babel-loader',
options: {
  presets: [
        'useBuiltIns': 'usage',								 
        'corejs': 3,

This tells the @babel/preset-env preset to include polyfills on a per-use basis, as encountered in your code files. When the babel-loader comes across our dynamic import, it will automatically include a Promise polyfill across the application.

3. Create an On-Demand Component

Creating an on-demand component is a fancy way of telling the JavaScript to scan the page (after loading) for any pre-defined identifier that we can check against to automatically fetch required dependencies.

For example, I recently worked on a project where we had a Subscription component. It was fairly large in terms of size, but was only present on certain pages.

Normally, in this scenario, you’d probably build the component as a separate file, compile it as a separate Webpack entry, and then do your conditional checks via PHP before loading it on the page.

With dynamic module imports, all this can happen client-side with minimal impact to file-size. Let me show you what I mean:

Let’s assume a directory structure like this:

Inside frontend.js we have all our normal logic like any normal application. The /components/ directory is where we keep (you guessed it) all our on-demand components.

Inside frontend.js we import these components like normal:

import './components/SubscribeForm';

Normally, this would end up importing the entire component, but because we are adopting a dynamic loading infrastructure, the actual file being imported is minimal.

Let’s take a look at what’s inside /components/SubscribeForm:

The component includes a lot of inner-workings, which is normal of most components. But by having the entry file as index.js, we can name the actual component file (where the real stuff happens) the same as the parent folder.

This keeps things more clear, and if you were looking at this folder without context, you might assume SubscribeForm.js is the actual component, while index.js is simply the entry file.

And this structure makes on-demand components so simple to maintain. Each component is, essentially, an isolated application. We simply include it in our main stack by calling the index.js file (this is assumed when calling a folder, as we did in frontend.js). Everything else in the component folder handles itself.

So, let’s see what’s in index.js:

 * Dynamically import form dependencies and initialize.
 * @type {NodeListOf<Element>}
const forms = document.querySelectorAll( '.SubscribeForm' );
if ( forms.length ) {
  import( './SubscribeForm' )
    .then( ( { default: SubscribeForm } ) => {
      SubscribeForm.initialize( forms );

Here we are doing three things:

  1. Getting all elements in the document with the class SubscribeForm.
  2. If the length of forms is greater than 0 (0 is interpreted as false, anything more is true), then we import the main SubscribeForm.js file from the relative root of the component folder, dynamically.
  3. Upon success, and with access to the new component, we initialize all the forms on the page.

In Summary

There’s more to dissect here, and this is an admittedly over-simplified tutorial on dynamic imports — but the possibilities of adopting this pattern are great:

  1. A unified component-loading pattern, in the form of a helper method, could simplify component imports. Imagine something like Components.onDemand( [ 'SubscribeForm', 'OtherComponent', 'Another' ] ).
  2. The first application JavaScript file delivered to the client could theoretically be in the ~10kb range, assuming every component was dynamic.

And there’s more, I’m sure. When I originally built this component system, I matched the patterns across PHP and JS, so that each component utilized classes and shared naming conventions, lowering the cost of shifting between backend and frontend code.

If you’ve done something similar to this before, I’d love to hear about it!

An Accessible Autocomplete Input

Recently on a project, I had to implement an accessible autocomplete input on a search form. Tim Wright suggested I used Accessible Autocomplete, and I’m glad he did because it’s pretty great.

The library targets an element as its render wrapper. The benefit here is that it not only defaults to no dependencies, but also easily incorporates into other frameworks like React. The downside is that you’ll have to handle the fallback for non-JavaScript implementation.

The implementation and configuration are very extendible and was fairly straightforward to incorporate, and I would definitely recommend it.

The library hinges on a source parameter to read a list of data and match the current query to the most relevant results.

From the docs:

import autocomplete from 'accessible-autocomplete';

const results = [
    'United Kingdom'

    target: document.querySelector( '#my-input' ),
    source: results

Now, when a user types into the input, an accessible list (with optional keyboard navigation) will populate the closest matching results.

Asynchronous Source

In my particular scenario, the results were determined through a third-party source, where the query was sent as a parameter string:


Thankfully, the library supports a function argument for the source parameter, with two useful arguments:

    element: document.querySelector( '#my-input-wrapper' ),
    source: ( query, populateResults ) => {
        // Do something.

This allows us to do something with the query. But more importantly, it gives us a manual update function that we can push results to.

This lets us do an asynchronous function and push the new source array once we get the response back:

autocomplete( {
    source: async ( query, populateResults ) => {
        const res = await fetchSource( query );
        populateResults( res );

 * @function fetchSource
 * Fetch the source array and return it's JSON response.
 * @param {string} query
async function fetchSource( query ) {
    const res  = await fetch( `https://external-url.com/?query=${encodeURIComponent( query )}` );
    const data = await res.json();
    return data;

Of course, this assumes that the response is in the correct format (an array of strings to sift through). If it’s not, you can update it before sending it back and updating the results.


One thing to note is that this library doesn’t debounce the typing of the keyboard. It does offer a minimum character count before firing off the results. While this is nice, retrieving an external source array seemed as though it required a bit more conservatism:

import debounce from 'debounce'

    source: debounce( async ( query, populateResults ) => {
	const res = await fetchSource( query );
	populateResults( res );
    }, 300 )


The major downsides to this library are that the autocomplete constructor does not return an instance for later reference. Therefore, tracking the autocomplete instance is nearly impossible.

Another major hurdle is that the autocomplete library exposes no internal methods of any kind in order to manipulate the lifecycle, behavior, or state of the input.

These actually ended up being major blockers for use in this project, and I ended up having to hack together a reluctantly “good-enough” solution that will be more difficult to maintain.

Since this library is so close, however, it’s likely a great candidate for open source contribution. You can see an open issue for instance creation here.

A Survival Guide to Full-Time Freelancing with No Savings

Recently, I was put in a position (through my own doing) of full-time freelancing with absolutely no preparation or savings to support it.

I know what you’re thinking, “No savings? That’s insane.

You’re absolutely right — it is insane.

What follows is not an endorsement of jumping into the deep end without a life-jacket (although maybe it should be). Instead, through my own experience, I thought that a post about what to do in this situation would be very helpful to individuals who may find themselves in similar situations.

You might find yourself staring at full-time freelancing if:

  1. You were laid off of your job.
  2. You were fired from your job (yours, truly).
  3. You can’t find a job.
  4. You’re single and live with your mom.

After a week of being thrust into full-time freelancing, here are some tips on how to book up the next 3 months with work as fast as possible (within a few days I was booked till the beginning of August with full-time work), and how to plan for an all-of-a-sudden uncertain future.

Photo by Tabea Damm on Unsplash

First Thing’s First

Before you begin the journey of anxiety and utter-thrill—if you’re entrepreneurial, then suddenly being full-time self-employed is both of those all the time—it makes sense to prioritize what areas to tackle first.

After all, your “security” is now gone and it’s up to you to restore that safety-net as quickly as possible. Developing security comes in many forms, but here’s my opinion on the top 5, in order of most important:

1. Determine Your Lowest Estimated Income

You should immediately determine the lowest estimated income of your freelancing gig. Since you have no history of full-time freelancing, this is going to be a stab in the dark.

Start uncomfortably small. This will adjust over time after you get real data from each month’s income. Until then, it is essential that you operate on a realistic expectation of what you can make in a month on a fairly consistent basis.

2. Determine Your Base Expenses

Next, you’ll want to determine your base expenses. Don’t skimp, here. This is survival mode with no guarantee you’ll have a place to sleep in a month, so cut out as much cruft as possible.

Netflix? Pause it. Side-project expenses? Pause it. Coffee outings a regular thing? Pause them. Eating out? Nope.

Photo by Jp Valery on Unsplash

You’re stripping all these down until you can justify them again based on actual experience. Note that I said “pause” a lot. Adopting this mentality helps a lot with being able to turn off your luxuries because you start to see it as temporary.

Keeping stripping these down until you fall below your lowest estimated income. If you can’t do that, then it might be required for you to take on a part-time coffee shop job or something to cover the difference. It doesn’t matter if you’re working 60–80 hours a week because, as I said, this is temporary. It’s survival.

3. Emergency Fund First, Debt Second

Once you get Step 2 figured out, the next couple months of your life are going to be very tiring. But that’s okay because it’s for a purpose.

You’ll work your ass off in order to build your emergency fund.

If you were paying debt prior to full-time freelancing, that momentum has to be transferred to savings. Your emergency fund is going to help your life go back to normal, and allow for high-and-low fluctuations in your income to be mitigated. Pay the minimum payments until you get your emergency fund.

In my opinion, freelancers should have 3–6 months of your base expenses stored in the bank before they start tackling debt again.

When you have a low month, you can pull from this to cover the difference. When you have a high month, you can replenish this fund for the future.

This is your new normal.

4. Make Some Noise

Next, you’re going to want a strategy for letting people know that you’re taking on work. Lucky for me, the thing that got me fired was also the noise I was making. Some people will have to start from scratch.

Regardless, there are a few things you’ll need to set up immediately (or amplify, if you already have them):

  • Point-of-Contact: I use this term because it’s medium-agnostic. But for many people, this would be a personal or professional website that you send prospects to. Sometimes these the same, other times they are not. It doesn’t really matter as much as making sure people can find you.
  • Networking Presence: As much as we hate social media these days, it is invaluable. I have used Twitter for nearly 8 years and built some semblance of a network on there (enough to get a project from a single tweet). Regardless, choose the network your prospects are likely to hang out on and start engaging multiple times a day.
  • Cold Email: Be annoying. Be persistent. Email just about every possible client you can think of and offer them whatever they want in order to secure their business. At this point, you’re going from a client roster of zero and trying to build it to around 25 in a single month. That takes a lot of cold emailing, calling, and Slack pinging.

I’m sure there are other ways to make noise, but those three will get you really far and do most of the work for you.

5. Mix Projects with Contracts

Finally, a lot of people think of freelancing as one-off projects for clients. This can be very lucrative and is, of course, something that should be pursued.

But many freelancers just starting out tend to forget about contracting opportunities. If you’re not sure what that is, just think of it as a job from your old employer but without the taxes, restrictions, or long-term commitment. Some contracts vary, but that basically covers it.

Hit the job boards and start looking for contract opportunities in the 3–6 month range with agencies and/or companies that could use your skills.

You’ll generally work at a lower rate but you’ll be able to calculate your income on a much more predictable scale. You can even go a step further and begin emailing agencies and asking for overflow work.

If you can, sprinkle projects throughout your contract term (be careful not to overcommit, it’s painful). Doing this will help you reach your 3–6 months of base expenses emergency fund much quicker.

Things That Help

What follows is a brief list of things that can seriously help when going full-time freelance and may be the difference between eviction and paying your mortgage.

Photo by Helena Lopes on Unsplash

Your Network Will Save You

I’m fortunate to have had an existing network that I built over the course of several years, namely within the WordPress community. Many employees do not have a network, but any employee can begin creating that network for future events exactly like this one.

Building a network means being involved. For me, the WordPress community is huge—but the way you build a network is to build open-source software that the community can use. I do this on my personal and professional GitHub profiles, but also via Twitter.

The Right Freelancer Networks

There is a slew of freelancer networks out there that connect you with clients. Most of them have a bad reputation, but if you can get into the Toptal Network (.aff) then you’re going to be much better off.

I’ve been a member there for a year and had my availability turned off until the day I was fired. I turned it on and had 4 client interviews within 2 days, one of them full-time for 3–6 months.


In summary, jumping into full-time freelancing without any savings is not recommended. I don’t enjoy working 80 hours a week, but it’s necessary to restore security and predictability in my business.

Feel free to reach out on Twitter if you have questions. I’d love to chat and hear about your own experiences. Good luck!