Author: Jerry Jones

  • The Importance of HTML

    In 1917, the artist Michael Duchamp submitted his work, “Fountain” to an art exhibition. It’s a used urinal. And it stirred up yet another conversation about, “What is art?”

    I’ve only taken one art history class, so forgive my simplification here. Essentially, art is subjective. If you personally don’t like Duchamp’s urinal, it doesn’t make it any less art.

    JavaScript and CSS are the focus of most web designer/developer’s learning, but they’re subjective to the end user. There are better and worse ways to write your CSS and JS, but none are 100% right or wrong (as long as your page still works, is secure, etc).

    HTML has clearly right and wrong ways to write it, and this is too often ignored. Here are several examples I’ve seen in the wild:

    • A “button” that’s actually a clickable <div> and not a <button>.
    • A “title” that’s actually a<div> and not a heading element (<h1>, <h2>, etc).
    • A “label” for an <input> that’s actually a <div>.
    • An “input” that’s actually a <div> with keydown listeners.

    Notice a pattern? Looking at you, <div>. 👀

    The essential issue is using a non-semantic element when a semantic element should have been used.

    What Do We Mean by Semantic?

    Semantic means that the element has a meaning. It says something about the content or its relationship to another thing. In HTML, basically anything that isn’t a <div> or <span> is semantic.

    There’s also a continuum to what a tag tells us about the meaning of its content. For example, a <section> tells us less about its contents than an <article>.

    <section> is still semantic, as it tells us that its contents should be considered as a group. But, an <article> tells its contents are grouped together and that it’s a cohesive article.

    For more examples, I’ll walk through the Heading and Button elements to demonstrate how they are semantic.

    Heading Elements

    An <h1> is a title of a page, and an <h2> beneath it gives a hierarchy to the page.

    <!-- h1, the most important part -->
    <h1>The Importance of HTML</h1>
    <!-- "What Do We Mean by Semantic?" is a subsection of "The Importance of HTML" -->
    <h2>What Do We Mean by Semantic?</h2>
    <!-- "Headings" is a subsection of "What Do We Mean by Semantic?" --> 
    <h3>Headings</h3>
    

    Using an appropriate heading structure, you can automatically create a table of contents. Here’s how this article could be built into a table of contents just based off of the heading levels:

    • <h1>: The Importance of HTML
      • <h2>: What Do We Mean by Semantic?
        • <h3>: Headings
        • <h3>: Buttons
      • <h2>: Non-Semantic Elements
      • <h2>: Correct HTML Does Not Bring You Glory, But You Need to Do It

    You can see the structure of the whole article being communicated just via the HTML. If I had used all <div>s, then the structure would look like:

    • <div>: The Importance of HTML
    • <div>: What Do We Mean by Semantic?
    • <div>: Headings
    • <div>: Buttons
    • <div>: Non-Semantic Elements
    • <div>: Correct HTML Does Not Bring You Glory, But You Need to Do It

    There’s no meaning attached to the <div>, so it would be a flat structure. Just by using the correct HTML we bring clarity and structure to the DOM.

    Buttons

    A button submits or changes the state of something. By definition, it’s always:

    • focusable
    • activated on space bar or enter key presses
    • activated on mouse click.

    When you make a <div> with a click listener, you’re not using the semantic interactions that come for free when you use a <button>. You have to manually build out the:

    • focus state
    • keyboard interactions
    • mouse interactions

    Not only that, but when a screen reader comes to a <button>Submit</button>, it will use those semantics and announce, “Submit, button.”

    The same thing using a <div> would look like:

    <!-- Just kidding, I'm not going to make an accessible div button. -->
    <!-- Use a <button> please! 😂-->
    

    When we use semantic HTML elements, we elevate the content’s meaning. It gives the content life.

    Non-Semantic Elements

    <div>s and <span>s are non-semantic elements. The <div> does not give the content any additional meaning. It’s just a <div>.

    I’m not being totally fair, as there is a tiny bit of meaning behind a <div> vs a <span>:

    • A <div> is a block-level element, as in, it should wrap things together.
    • A <span> is an inline element. It should be used within another element, like <p><span class="dropcap">I</span>nline elements</p>.

    If there are no HTML elements that make sense for the content, then use a <div> or <span>. There’s 100% a place for <div>s and <span>s. Not every piece of content or HTML element needs additional semantics.

    When writing HTML, use as specific of an element as makes sense for your content. If there’s nothing specific enough, then keep going for less and less meaningful tags. <div> and <span> are always the last choice.

    Correct HTML Does Not Bring You Glory, But You Need to Do It

    You’re not going to get a Webby Award or thousands of views on Codepen for how amazingly crafted your HTML is. You’ll need to be OK going unrecognized for your work. But know that every time I use a screen reader or keyboard on a site and it works correctly, I have a little spark of joy. I’m sure I’m not alone here.

    In the end, you’ll have to be OK with knowing you did your best to make your work accessible to everyone.

  • Getting Hired at Automattic

    Getting Hired at Automattic

    I started at Automattic on November 20, 2019, and it’s an incredible place to work. I’m constantly impressed by my coworkers kindness, intelligence, and compassion. If you’re looking for a rewarding remote job that you can work from anywhere in the world, definitely apply.

    I’m still overjoyed and amazed I was hired. While going through the hiring process, I devoured the blog posts from people describing their journeys. Here’s my contribution to the catalog. I hope it helps someone.

    The Creed

    Before applying, I would recommend reading through the Automattic creed to see if it aligns with you. I think most companies have a creed to pay lip service to.

    That’s not Automattic. The creed really is embodied in an amazing way. It sounds cliché, but it’s true.

    Recruitment

    End of September, 2019

    I was contacted by a third-party recruiter about applying. I believe this may have been an experimental program, and is not the normal process.

    It was the first time that I was contacted by a recruiter who:

    • was kind and supportive
    • really wanted the job to be a good fit for me
    • had a good job offer

    I had actually applied to Automattic a few years ago for a Product Designer role, but did not get past the application step. They were still incredibly kind and encouraging in their rejection. I was shocked and excited to be contacted by a recruiter asking me to apply this time around.

    I sent my resume in, and they passed it along to the hiring team. Within two days, I heard back that they wanted me to fill out their application questionnaire.

    Questionnaire

    End of September, 2019

    I received a questionnaire that helped them and me evaluate if working at Automattic would be a good fit. Automattic has a very unique and wonderful way of working. It’s definitely not for everyone, but it’s something to be discussed and aware of very early on.

    I don’t remember this part taking too long or being too intense.

    Slack Interview

    Update June 2021: Automattic is removing the interview from the engineering hiring process. Candidates are moved directly to the Code Test.

    Early October, 2019

    Within a week, I heard back that I was being advanced to the Slack Interview. The interview is entirely text based.

    A Text-Based Aside

    The entire hiring process is text based. Seriously.

    Never once did I hear someone’s voice or do a video call. Until my first paycheck arrived, a part of me still believed it was all too good to be true, and it was just an elaborate prank. 😂

    They invited me to a slack channel, and I was free to ask questions and talk with the hiring team. They told me how they do what they call “async communication.” You can ask a question, and you may not get an answer for awhile, as the person may be in a totally different part of the world. For example, the hiring team for my trial process was distributed in Europe, Eastern Europe, Oceania, and the US.

    Slack Interview – Continued

    I really enjoyed the slack interview. It was by far the most enjoyable interview I had ever done. The person I chatted with helped me feel comfortable and confident. They knew what they were talking about and used plenty of emoji responses to keep things light.

    The interview felt more like hanging out and talking with someone you met at a conference about what you do, what processes you use and why, etc. It was friendly and, dare I say, fun.

    By the end of our 1.5 hour chat, they told me I was moving on to the next stage. No waiting required.

    Note: I don’t think a fast answer like this is always the case. Just because you’re not told an answer at the end of the interview doesn’t mean you’re not moving on.

    The Code Test

    Early October, 2019

    It’s getting real now. You can talk the talk, but can you… uh… walk the… code? Well, you know what I mean.

    Within a couple days, they sent me the Code Test. It was a github repo with details on the project and what needed fixing. They said to not spend more than 4-6 hours on the test, but, I did spend a little more than that. 😬

    The impression I got behind the intention of the 4-6 hour limit isn’t to see how fast you can code or to make you crack under pressure. It’s out of respect for your time. They really don’t want to waste your time or their own.

    It was hard. I doubted myself. I put too much pressure on myself. I freaked out. I took a break. I figured part of it out. Repeat.

    Within a day or two of submitting my code test, I got a detailed, kind response about things I did well and things I could improve. The intention behind the message was clearly to help me learn. Fortunately, I was being moved on to the Trial phase.

    The Trial: Hot Take

    Mid October, 2019

    The trial phase is a fixed-rate, paid trial at $25/hour and is intended to last around 40 hours. This is a big commitment, and a controversial one if you read around a bit on forums from people debating the hiring process at Automattic. I think it has changed over the years, so here’s my take after having gone through it:

    • The $25 rate is clearly low for a US-based web developer. It’s not supposed to be a living wage and has no impact on your future salary. It is nice that they believe you are a good enough candidate that they are willing to pay you to continue interviewing with them.
    • It’s not an attempt to get reduced-rate work. You get one of a few standardized trial projects that are not intended to be used in production.
    • It’s supposed to mimic the way Automattic works to see if you’ll enjoy working there.

    You’re allowed to do the trial project spread out over as many weeks/months as you’d like. Just communicate what your schedule is going to be. I decided to do it within two weeks so I could get it out of the way and find out sooner.

    The Trial: How it Happened

    Note: I had originally started as more of a back-end developer during the hiring process, but decided to move to a front-end developer role. I was worried they would make me start the process over. Fortunately, they just said “No problem!” and switched me to a front-end trial.

    When you get to the trial phase, they add you to a few slack channels with everyone else on Trial. You are now officially a Trialmattician. This channel is kind of like a #watercooler channel for others on trial. It was incredibly useful and comforting to chat with others going through the same, difficult thing as you.

    The hiring team makes it clear that you are not competing with anyone else on trial. They have a high hiring capacity, so it’s not about accessing a limited amount of positions, but finding the right people who will thrive at Automattic.

    My trial project was another WordPress plugin, but this time it was React-based. I had never worked with React and told them this ahead of time. They weren’t worried about my lack of React knowledge.

    My impression of the trial wasn’t to evaluate how good of a React developer I was (hint: I wasn’t), but to evaluate (among other things):

    • Communication
    • Documentation and showing work
    • Detailing my thought process
    • General coding style and knowledge
    • Ability to work in an async, distributed way
    • How you adapt to a new, unique codebase

    Since I committed to doing the trial fairly quickly, I went faster than they could really provide feedback (this was also due to my trial lead traveling during the first part of my trial). I believe the process is supposed to be more like the day-to-day of working at Automattic where you have code reviews from teammates coming in within a day of submitting a PR (pull request).

    The trial pushed me in a similar way as the Code Test. I doubted myself. I tried to move quickly but just wound up missing silly mistakes. Taking a breath and moving carefully and considerately was by far the best thing I did.

    Overall, it was extremely tough for me. I’m very glad to be done with it. 😅

    When my trial lead felt like they had seen enough to make a decision, they recommended me to be hired. 🎉

    The Matt Chat

    Early November, 2019

    This is still called the Matt Chat even though I talked with someone from HR. The chat involved talking about my trial process, how I felt about it, the good, the bad, etc. I was impressed with how much they wanted to hear my feedback so that they could improve the hiring process. Overall, I remember really enjoying the chat.

    At Automattic, they really care. A lot. They want this to be the best it can be for the candidates putting the time in. Even though it’s not always perfect, it’s filled with good intention and compassion.

    We talked a little about a potential start date and expected salary, and that evening I received and accepted my offer.

    My Advice

    • Every step along the way, I thought I would get rejected, but I didn’t. Hang in there! The hiring team does not pass people through out of kindness (even though they are very kind). They move people on through the hiring process because they believe they will succeed.
    • Imposter syndrome is real, but you’re there because you deserve it. Believe in yourself like they believe in you.
    • Have a support system. Be prepared to get together with a close friend (or two or three) and just talk about what you’re going through. I’m so thankful for my friends’ encouragement and being willing to listen as I got everything out of my head.

    If you’re considering applying, do it! The process is very difficult, but the reward is so, so worth it. If you’ve already applied, know I’m rooting for you!

    Leave a comment if you have any questions, and if it’s something I can/am allowed to answer, I’m more than happy to help. 🙂

  • Why I’m Using a Site I Didn’t Code

    I make websites for a living. I’ve made hundreds of custom sites. But not this one.

    I think I’m on iteration 4 of my portfolio site. Every 3 years or so I’ll take the time to switch it up. I did that again last week, but instead of redesigning and recoding my site by hand over the course of a week or two, I took two hours and migrated to WordPress.com, picked a theme, and added some minor CSS tweaks.

    Deciding to switch my domain name and choosing a new one was by far the longest part of the process.

    I Want to Write without Distraction

    Before, my writing flow went something like:

    • Have a post idea
    • Log into my site to write it
    • Forget my password
    • Finally get logged in
    • See things that need updating
    • Update the things
    • See things that need fixed
    • Start to fix the things
    • Realize I don’t have the codebase and workflow for the site set-up on my new computer
    • Abandon, resolving to really fix it next time

    Now that I’ve switched to a basic WordPress.com managed site (not an ad for WordPress.com, although I am biased), my writing flow goes:

    • Open my site (on my phone or my computer)
    • Write the post

    I Don’t Have to Update my Portfolio

    I really only update my portfolio whenever I redesign my site, so it’s inevitably out-of-date very quickly. Now, I don’t have to be ashamed of never updating my portfolio, because I don’t have one. 😎

    This also coincides with me getting a full-time job, and leaving a more agency-style freelance contractor role. I don’t really need a portfolio at this point.

    If I do want to keep updating my portfolio though, I can add a post and add it to the “Portfolio” category. Then, if I ever want to make a more specific Portfolio page, I can do that fairly easily in the future.

    It’s One Less Thing to Worry About

    Life is busy, even now in the time of stay-at-home orders and the coronavirus. Every thing I can take of my plate frees up time for myself and my family.

    Now that I can quickly write from anywhere, easily and without distraction, I find myself wanting to write more. Time will tell if this honeymoon phase lasts, but, for now, I couldn’t be happier I made the switch.

  • Shoulder Health for Developers

    At my first team meetup for Automattic, I gave a flash talk on shoulder health. I’m the only US-born person on my team, and they made sure to point out how American this disclaimer is, but here it is anyways:

    I’m not a doctor. Don’t take this article as medical advice. These are things that have helped me, but you need to listen to your body.

    What happens to our shoulders when we work at a desk?

    If we’re not careful about our set-up and posture, we’re prone to slump forward while working, and specifically, sitting.

    Pick up your phone and look at it, as if you’re checking your email. Now, on the arm you’re holding your phone with, note the position your shoulder is in.

    Very likely, your shoulder is rotated forwards. This is the same position we’re generally in while working over a laptop. Slumped forwards a bit with our shoulders internally rotated.

    What happens to our bodies?

    Our bodies are amazing at compensating for the positions we put ourselves in, even if this position is bad in the long run.

    • Pectoralis Minor shortens.
    • Humerus internally rotates and sits at the front of the shoulder joint.
    • Back muscles lengthen.
    • Scapulae rotate forwards.
    • Likely, you’ll end up in a chin-forwards position as well.

    What’s wrong with this?

    The big ones are:

    • Weakened shoulder mobility / pain. You want your shoulders to last 100 years, not 50.
    • Shoulder impingement (where tendons and nerves get pinched by the bones in your shoulder).

    How can we address it?

    A quick note on stretches and exercises.

    • If it pinches, STOP.
    • If it tingles, STOP. You don’t want to mess with nerves.
    • Start slow. Your body will yell at you if you go too hard, too much, too fast at once. Let it adapt to doing new things so you don’t get set-back before you even start.

    Exercises and Stretches

    How can we prevent it?

    • Standing desk
    • Knowing how to properly stand (Video contains the word, s***, but otherwise is a great video on how to stand at a desk properly): Ankles, hips, shoulders, ears all in-line. Shoulders externally rotated and down back.
    • Proper desk set-up: Keyboard and mouse at a proper height with elbows bent and shoulders externally rotated. Monitor at a neutral (eye-level) or slightly looking-up posture.
    • Move! Every 25 – 30 minutes, take a break, stretch, exercise and return.

    Resources/Topics

    • Egoscue Method: Active postural alignment
    • Mobility WOD: Short, informal mobility exercises/stretches for improving flexibility
  • Taxonomy Queries with WordPress v2 REST API

    In order to access posts by a taxonomy query via the v2 WP REST API, you’ll need to do a little set-up first. Let’s say we’re starting a beer blog, and we’re attaching two custom taxonomies to our posts: “styles” and “breweries”.

    Creating the Taxonomies

    When you register the taxonomy using register_taxonomy, you have to make sure you set it to be available via the API. To do this, make sure you have 'show_in_rest' => true to make it accessible in the API and provide thename you want to access it with in the URL with 'rest_base' => 'beers'. Here’s sample code for registering our taxonomies called “styles” and “breweries” that’s accessible via the API:

    
    register_taxonomy(
        'styles',
        [ 'posts' ],
        [
            'labels' => [
                'name'              => 'Styles',
                'singular_name'     => 'Style',
            ],
            'show_in_rest' => true,
            'rest_base' => 'styles'
        ]
    );
    
    register_taxonomy(
        'breweries',
        [ 'posts' ],
        [
            'labels' => [
                'name'              => 'Breweries',
                'singular_name'     => 'Brewery',
            ],
            'show_in_rest' => true,
            'rest_base' => 'breweries'
        ]
    );
    
    

    Now you can find all terms in the Breweries taxonomy with /wp-json/wp/v2/breweries and all the Styles with /wp-json/wp/v2/styles

    WP REST API Taxonomy Query

    In order to get posts attached to a specific beer style in the styles taxonomy, you can query it by style term ID in the URL by appending ?style=[term_id].

    For example, let’s say IPAs have a term_id of 25. To find all posts with the term IPA, you can do: /wp-json/wp/v2/posts/?styles=25

    For multiple terms, add more comma separated IDs, like: /wp-json/wp/v2/posts/?styles=25,26,27

    This is equivalent to the WP_Query:

    
    $args = [
        'post_type' => 'post',
        'tax_query' => [
            'relation' => 'AND',
            [
                'taxonomy'         => 'styles',
                'field'            => 'term_id',
                'terms'            => [25,26,27],
                'include_children' => false
            ]
        ]
    ];
    $query = new WP_Query($args);
    
    

    Note, this will not find all posts that include ALL of the styles (25, 26, and 27) but find posts that have at least one of the terms (25, 26, or 27).

    Multiple Taxonomy Queries

    If we want to find posts by both beer style and brewery, we simply add more parameters to the URL. If we want all posts with the term IPAs (term_id 25) from Boulevard Brewery (term_id 33), we’d do: /wp-json/wp/v2/posts/?styles=25&breweries=33

    This is the WP_Query equivalent of:

    
    $args = [
        'post_type' => 'post',
        'tax_query' => [
            'relation' => 'AND',
            [
                'taxonomy'         => 'styles',
                'field'            => 'term_id',
                'terms'            => [25],
                'include_children' => false
            ],
            [
                'taxonomy'         => 'breweries',
                'field'            => 'term_id',
                'terms'            => [33],
                'include_children' => false
            ]
        ]
    ];
    $query = new WP_Query($args);
    
    

    Complexity Tradeoff for Simple URLs

    Because the structure is so simple, ?[rest_base]=[comma_separated_term_ids], it doesn’t allow you to have all the power of WP_Query(). From looking at the WP core code, it looks like the following are NOT supported out of the box:

    • Relationship "OR" queries
    • Querying by slug instead of term_id
    • Setting include_children to true.
    • Using the operator argument to set if you want it to find posts that are in all the terms you passed (using operator=>'AND') or finding posts that are NOT IN the term(s) you passed.

    As of this writing in WordPress v4.9.4, to do any of those more complicated queries, you’d have to add custom filters to the API to make them accessible.

  • Tutorial: How to Minify & Version a JS File with NPM Scripts

    One of the studies with the Center for Media Engagement needed a straightforward way to maintain and deploy a single JS file. I didn’t want to use a big fancy WebPack or Gulp setup when all we needed was to minify and version a single JS file, so I turned to using npm scripts.

    tl;dr

    The following package.json file, when you do npm run production will:

    1. Check your package.json version and increase it by 0.0.1
    2. Minify your script.js file as script.min.js
    3. Add the new version number and build time to the header of your script.min.js file
    {
      "name": "my-rad-scriptz",
      "version": "0.0.1",
      "description": "This script is the kewlest!",
      "scripts": {
        "minifyJS": "uglifyjs scripts.js --compress --mangle --warn --output scripts.min.js",
        "production": "npm run version:bump --silent && rm -f scripts.min.js && npm run minifyJS --silent && npm run version:add --silent",
        "version:add": "echo "/*! My Rad Scriptz!!!!1!11! v - $(npm run version:extract --silent)n * © Someone probably n * Build time: $(date '+%m-%d-%Y %H:%M:%S')n */n$(cat scripts.min.js)" > scripts.min.js",
        "version:bump": "npm version patch --no-git-tag-version --silent",
        "version:extract": "cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g' | tr -d '[[:space:]]'"
      },
      "author": "Rad D00d",
      "devDependencies": {},
      "dependencies": {
        "uglify-js": "^3.3.11"
      }
    }
    

    Thanks to the A11y Dialog project, as that’s where I got the command for reading the version number from package.json.

    The Set-up

    To get started, create a new directory and script file to host your project. I’ll use terminal commands to do this stuff because it’s useful to know and we’ll need to be in terminal when we start running npm commands anyways.

    # create the directory
    mkdir my-rad-project
    
    # change directory (cd) into your new project directory
    cd my-rad-project
    
    # create a scripts file
    touch scripts.js
    
    # create a package.json file
    touch package.json
    

    Copy and paste the package.json contents above into your package.json file.

    Now, make sure you’re in your my-rad-project directory (you didn’t change it, did you!?!?) and run in terminal:

    npm install
    

    This will install any packages in the devDependencies and dependencies sections of your package.json file. In this case, it’s only uglify-js, which is what we’re using to minify our JavaScript file.

    Now, when you build production assets it will take whatever is in your scripts.js, minify it into scripts.min.js and add the new version number into the header of scripts.min.js.

    While still in your my-rad-project directory to kick off the minification process, run in terminal:

    npm run production
    

    How it Works

    Our package.json file contains a scripts object where we can define shortcuts for running terminal commands. Each of those scripts we could run via terminal, but why would we when can just do npm run production?

    When we do npm run production, it runs whatever is in the production section of the scripts. In our case, it’s this:

    "production": "npm run version:bump --silent && rm -f scripts.min.js && npm run minifyJS --silent && npm run version:add --silent"
    

    This one command, npm run production, ends up running multiple other commands, chaining them together with &&.

    # npm run production runs... (the --silent tag suppresses output to terminal. otherwise you get lots of unnecessary stuff output in your terminal window)
    npm run version:bump --silent && rm -f scripts.min.js && npm run minifyJS --silent && npm run version:add --silent
    
    # which runs npm run version:bump (increase the version of package.json by 0.0.1)
    npm version patch --no-git-tag-version --silent
    
    # and then runs rm -f scripts.min.js to delete our old scripts.min.js file
    
    # and then runs npm run minifyJS to minify the script.js file into script.min.js
    uglifyjs scripts.js --compress --mangle --warn --output scripts.min.js 
    
    # and then runs npm run version:add to prepend a comment to scripts.min.js with the new version number and timestamp
    echo "/*! My Rad Scriptz!!!!1!11! v - $(npm run version:extract --silent)n * © Someone probably n * Build time: $(date '+%m-%d-%Y %H:%M:%S')n */n$(cat scripts.min.js)" > scripts.min.js
    
    # which, during npm run version:add has $(npm run version:extract) that runs to find the new version number
    cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g' | tr -d '[[:space:]]'
    

    Whew! See why it’s lots easier to just do npm run production?

  • WordPress Actions Made Simple

    I was coding WordPress themes for an embarrassingly long time before I fully understood how to use WordPress actions. This is how I wish someone had explained them to me when I was beginning as a developer.

    I’m going to walk through this abstractly, not with actual WordPress hooks. The point of this article is to understand what WordPress actions are, why they’re useful, and how to use them.

    The WordPress Actions of my Dog

    My dog, Sycamore, has a good life. Napping, playing, eating: what’s not to like? Let’s build a schedule of an ordinary day in the life of Sycamore with WordPress actions.

    The set-up of the actions will be one action for each hour of the day: 1 – 24. When a page loads, it will run all of the 24 actions one immediately after another.

    You generally will not add any do_action() to your theme. This is just for demonstration. The important thing to know here is that every time a page loads, it will run 24 actions: one for each hour of the day. So, go to the page, and it will, run, in order:

    do_action('1_oclock');
    do_action('2_oclock');
    do_action('3_oclock');
    // etc, until...
    do_action('24_oclock');
    

    Each time one of those actions runs, it looks for anything else hooked into the action with the same name (like, ‘1_oclock’) and then runs that action at that time.

    The Schedule

    Now that we have our actions for each hour of the day running, we can hook into them to display a schedule of my dog Sycamore’s day.

    • 7 o’clock: Wake up, lick people’s faces, go on a walk
    • 8 o’clock: Eat
    • 9 o’clock: Go to sleep
    • 12 o’clock: Wake up, chew on something that she’s not supposed to chew on
    • 13 o’clock (1pm): Go to sleep
    • 16 o’clock (4pm): Wake up, bark at a squirrel, chase something only discernible to her
    • 17 o’clock (5pm): Eat, go on a walk
    • 18 o’clock (6pm): Go to sleep
    • 21 o’clock (9pm): Wake up, bother the cat, sniff random things all over the house
    • 22 o’clock (10pm): Go to sleep

    We already have our actions for each hour running (do_action('1_oclock'), etc), so all we have to do is hook into them. When we add an action like ‘Wake up’ into our 7_oclock action, we’re simply saying “When the 7_oclock action fires, run any of our code that is hooked into the 7_oclock action.

    In code, using WordPress actions, Sycamore’s schedule above looks like:

    // actions at 7_oclock (7am)
    add_action('7_clock', 'wake_up');
    add_action('7_oclock', 'lick_peoples_faces');
    add_action('7_oclock', 'go_on_walk');
    
    // actions at 8_oclock (8am)
    add_action('8_oclock', 'eat');
    
    // actions at 9_oclock (9am)
    add_action('9_oclock', 'sleep');
    
    // actions at 12_oclock (12pm)
    add_action('12_oclock', 'wake_up');
    add_action('12_oclock', 'chew_something_not_supposed_to');
    
    // actions at 13_oclock (1pm)
    add_action('13_oclock', 'sleep');
    
    // actions at 16_oclock (4pm)
    add_action('16_oclock', 'wake_up');
    add_action('16_oclock', 'bark_at_squirrel');
    add_action('16_oclock', 'chase_something_only_i_detect');
    
    // actions at 17_oclock (5pm)
    add_action('17_oclock', 'eat');
    add_action('17_oclock', 'go_on_walk');
    
    // actions at 18_oclock (6pm)
    add_action('18_oclock', 'sleep');
    
    // actions at 21_oclock (9pm)
    add_action('21_oclock', 'wake_up');
    add_action('21_oclock', 'bother_cat');
    add_action('21_oclock', 'sniff_randomly');
    
    // actions at 22_oclock (10pm)
    add_action('22_oclock', 'sleep');
    

    Let’s take a closer look at the 7am section:

    // actions at 7_oclock (7am)
    add_action('7_clock', 'wake_up');
    add_action('7_oclock', 'lick_peoples_faces');
    add_action('7_oclock', 'go_on_walk');
    

    At 7am, the first thing Sycamore does is wake up. The 'wake_up' part of add_action('7_oclock', 'wake_up'); is matched to a function of the same name: 'wake_up'. The following `wake_up()` function prints the words “Sycamore wakes up” onto the page:

    // output the text 'Sycamore wakes up';
    function wake_up() {
      echo 'Sycamore wakes up';
    }
    // add 'wake_up' to the '7_oclock' action
    add_action('7_clock', 'wake_up');
    
    // run all 7_oclock actions, including 'wake_up'
    // note: you likely will not be adding any do_action statements until you're writing plugins. You're far more likely to use add_action hooks
    do_action('7_oclock');
    

    Ordering Actions

    Great! Sycamore is awake! But… there are multiple things that are supposed to happen at 7 o’clock. How do we make sure that Sycamore doesn’t somehow lick people’s faces before she wakes up?

    We can give each action a priority number, with lower numbers running first. It’s like if you’re waiting in line: if you’re number 1 in line, you’ll go first. The default number for an action is 10. All of the actions above would have a priority of 10, because we didn’t specify any order.

    To make sure Sycamore wakes up before doing anything else, we give the 7 o’clock wake up action a priority of 1.

    // 1 means it will run before anything else
    add_action('7_clock', 'wake_up', 1);
    
    // not having a number means it defaults to a priority of 10
    // Sycamore needs a good round of lickin' everyone's faces after waking up
    add_action('7_oclock', 'lick_peoples_faces');
    
    // wake up: check
    // lick faces: check
    // time for a walk!
    add_action('7_oclock', 'go_on_walk', 20);
    

    Passing Arguments (values) to Actions

    If you have a dog, they might have a similar schedule. Let’s open this up to be available for any dog, not just Sycamore.

    To do this, the actions that run needs to know what dog is doing the action. We can do this by setting a PHP variable and passing it to the action function. Let’s go back to our do_action('7_oclock'); where we register the 7_oclock action that makes it available to hook into.

    // set the $dog_name to equal 'Sycamore'
    $dog_name = 'Sycamore';
    // pass $dog_name to our do_action. This makes $dog_name available to the functions that hook into this
    do_action('7_oclock', $dog_name);
    

    Now that we have a $dog_name variable, we can access it with our functions:

    // $dog_name should equal your dog's name
    function wake_up($dog_name) {
      // if $dog_name = 'Sycamore';
      // it outputs the text 'Sycamore wakes up';
      echo $dog_name.' wakes up';
    }
    // add 'wake_up' to the '7_oclock' action
    // 1 = the priority
    add_action('7_clock', 'wake_up', 1);
    

    So, if your $dog_name is “Fluffy,” then it would output “Fluffy wakes up.”

    Schedules can vary from day to day though. On Saturdays, Sycamore’s walk isn’t at 7am, it’s at 8am. A couple things we’d need to know before we can set the Saturday schedule correctly:

    • What day is it?
    • How to remove her 7am walk and add it in at 8am.

    First, let’s address how to get the $day in there. Back where we set the dog name, let’s add in the $day as well and pass it to the actions.

    $dog_name = 'Sycamore';
    // this will set $day to be the full name of the current day, like 'Saturday' or 'Sunday'
    $day = date('l');
    // pass $dog_name and $day to our do_action. This makes $dog_name and $day available to the functions that hook into this
    do_action('8_oclock', $dog_name, $day);
    

    Similarly to how action priorities default to 10 (the order that actions run), actions default to only having one variable. Now, since there are two variables ($dog_name and $day), we need to tell our actions that we’re using more than one variable. We’ll add our 8am action and make sure it has access to two variables.

    // $dog_name should equal your dog's name
    // $day will be the current day of the week
    function go_on_walk($dog_name, $day) {
      // if $day = 'Monday' and $dog_name = 'Sycamore, it will output: "Monday: Sycamore goes on a walk"
      echo $day. ': '. $dog_name.' goes on a walk';
    }
    
    // if today is Saturday
    if($day === 'Saturday') {
      // add 'go_on_walk' to the '8_oclock' action
      // 10 = the priority. We have to include it here so that we can also add the '2' for the number of arguments
      // 2 = the number of arguments ($dog_name and $day)
      add_action('8_oclock', 'go_on_walk', 10, 2);
    }
    

    Removing Actions

    The last thing we have to do is remove the 7 o’clock action because Sycamore doesn’t go on a walk at 7am and 8am on Saturdays. To do this, we use remove_action(). The one catch here is that we have to use remove_action() after the action we want to remove has already been added, otherwise there’s nothing to remove.

    // per usual, go on a walk at 7_oclock
    add_action('7_oclock', 'go_on_walk', 10, 2);
    
    // if today is Saturday, add in a walk on the 8_oclock action and remove the 7_oclock walk action.
    if($day === 'Saturday') {
      // add 'go_on_walk' to the '8_oclock' action
      add_action('8_oclock', 'go_on_walk', 10, 2);
      // remove the '7_oclock walk. We can do this since it was already added above
      remove_action('7_oclock', 'go_on_walk');
    }
    

    WordPress Action Summary

    We’ve gone over what actions in WordPress are. To summarize in a handy list for review:

    • WordPress has actions that run when the code runs the do_action('action_name') code.
    • You can add your own actions to run when the do_action('action_name') runs with add_action('action_name', 'your_function_name').
    • You can change the order of when actions run by passing a priority number like add_action('action_name', 'your_function_name', 1). 1 means it runs first. 10 is the default priority.
    • If an action has values/arguments that it passes, you can access those in the function you’re using by adding an argument number. If you need more than one argument (the default number), then you can specify the number of arguments you want. For example, to run get three arguments, you’d use add_action('action_name', 'your_function_name', 10, 3).
    • You can remove actions with remove_action('action_name', 'function_you_want_to_remove'), but the action has to have already been added in order to remove it.

    If you have any questions on what WordPress actions are or how to use them, feel free to ask in the comments. I’m planning to write a similar article on WordPress Filters, so be sure to follow me on Twitter if you want to know when I finish it!

  • Basic HTML Boilerplate Structure

    When you only create a new base template every few months (or longer!), it’s hard to remember the little details of the structure that you don’t touch often.

    As of HTML5, the <doctype>declaration and structure has gotten a lot easier, but it’s still easy to forget. Here’s the basics:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <title>Page Title</title>
      <meta charset="utf-8" />
      <!-- other meta, CSS, and custom tags -->
    </head>
    
    <body>
      <header>Site Title</header>
    
      <main>
        <h1>Page Title</h1>
        <p>Body content</p>
      </main>
    
      <footer>Site Footer</footer>
      <!-- load JS here so it doesn't block the rendering of the page -->
    </body>
    </html>
    

    Notes on Easily Forgotten Structural Tags

    • <!DOCTYPE html>: Tells the browser/parser that the file is written in HTML.
    • <html lang=”en”>: Tells screen readers and search engines that the page is written in English. You can look up other language character codes.
    • <main>: Sets the main content for this page. This is generally what makes this page unique. For example, a news article would be wrapped in the HTML tag.

    Copy/Paste this boilerplate HTML and get going!

    Further Reading

  • A Designer’s Response to Seth Godin’s “Working with a designer (four paths)”

    In Seth Godin’s Working with a designer (four paths), he’s educating people on different things to have considered and come to terms with before approaching a designer.

    Go ahead and read his post if you haven’t before continuing here. It won’t take long.

    As a designer, I think he’s spot on about the (at least) four different kinds of clients. I’ve definitely worked with clients of the four different postures he describes. However, a big part of being a designer is teaching your client how to be a good client. You don’t learn that in school, and you’re not often in a situation of being a client on a design project.

    The first thing I do when designing for a project is to establish a goal. What are we actually trying to accomplish with the design, and why? This is incredibly helpful for people to be able to think concretely about different designs.

    For example, if a client is starting a pet grooming business and they need a logo, I’d start with a goal discussion of what they’re trying to do. After a few long discussions, we figure out that their goal is: “Provide a pampered, trustworthy and first-name basis (well, only-name basis for most animals) experience for your animal.”

    Now that the goal is established, we can base design decisions on this instead of a vague “what the client likes.” Without a goal, questions tend to be based on the look, such as “Which logo do you like better?” But, what they “like” isn’t necessarily what the best logo is for what they’re trying to accomplish.

    If you have a goal already defined, then you can ask more useful questions like:

    • “Which logo seems more trustworthy?”
    • “Which logo suggests that you’ll pamper their animal like four-legged royalty?”

    Whichever type of client you are, don’t worry about it too much. A good, experienced designer will help you clarify your goals and teach you how to be a great client.

  • Switch WordPress Database based on Git Branch

    I’m working on a large redesign project where lots of database changes are going to take place. In order to not mix-up the current master branch with the new redesign changes, I made a new database so I can keep things separate. The only trick is to remember to change out the database in wp-config.php when I switch branches.

    That’s not going to happen. I’ll definitely forget. Regularly.

    Fortunately, you can grab the branch you’re on via php with a bit of code from user program247365 on stackoverflow.

    I took that and added a bit to choose the database I want based on the branch I’m on. You’ll need to change out the $db_name and $branch variables to match your own, then you’ll be good to go!

    // get branchname
    function config_get_git_branch() {
        // This assumes you have your .git directory at the same level as wp-config.php.
        // If you don't, then change the path to wherever your .git director is
        $stringfromfile = file('.git/HEAD', FILE_USE_INCLUDE_PATH);
    
        $firstLine = $stringfromfile[0]; //get the string from the array
    
        $explodedstring = explode("/", $firstLine, 3); //seperate out by the "/" in the string
    
        $branch = $explodedstring[2]; //get the one that is always the branch name
    
        return trim($branch);
    }
    
    // choose which db you want to use
    function config_get_db_name() {
        $branch = config_get_git_branch();
    
        // change these $db_name and and $branch strings to match
        // whatever ones you want.
        if($branch === 'child') {
            $db_name = 'child_db';
        } else {
            $db_name = 'site_db';
        }
        return $db_name;
    }
    
    // ** MySQL settings - You can get this info from your web host ** //
    /** The name of the database for WordPress */
    define('DB_NAME', config_get_db_name());
    

    Now you’ll never forgot to switch the DB out when you checkout to a new branch. Happy coding!