2018 year end review

Highlight of my 2018 summer was visiting Zion, Bryce Canyon, and the Grand Canyon.

As 2018 comes to a close, I’m doing what I do every year and reflecting on the year gone by and looking ahead to 2019. This was a year where I believe I struck more of a work/life balance than previous years when I may have been a bit too ambitious. I learned a few things about technology and had many “first” experiences.

Dove into front-end frameworks (finally)

I’ve dipped my toes in the water during years past, but this is the first year I really got going. I have a working prototype of several apps, all connected to Firebase or FireStore. Vue is definitely my framework of choice right now, I find it very approachable. It might help that I got a subscription to VuevMastery which has taught me a TON. So I feel like I understand this framework better than React for that reason.

Dog log – Prototype built with React to demo an idea. The idea was to have an application that my wife and I can both login to that would allow us to see the last time the dog has been outside.Ego education – Prototype application built with React to allow me to keep track of ACIM Workbook lessons. The lessons help me with mindfulness and keep me focused on what is truly important throughout the day.

Yoga app – Prototype built with VueJS. This application allows you to do Routines comprised of different Asanas. You can name and save your Routines. The app uses Firebase to store the information.


Dining menu – This prototype is from work and was built with VueJS. Data is coming from a vendor’s service and being “massaged” with a piece of middleware, then stored in FireStore before Vue grabs it. Prototype has the ability to login, and add “Favorites”.

New marketing pages at work – With the help of the Digital Services and Marketing teams, we were able to get some awesome work done, including a new “Academics” section of the site, Program Finder, and a revised program page template. This process also gave us a rough blueprint for how to tackle the rest of the higher-level pages on the site. Links and pictures are in tweets below.

Beyond technology, I had some good life experiences that were significant. Visiting the Grand Canyon, Bryce Canyon, and Zion National Park were among the experiences. As was hosting our first Thanksgiving (successfully).

Got a new desk setup (I have still yet to get a dimmer)

That about wraps up the highlights of 2018 (that I can think of currently). Here’s to a great 2019. 🥂🍾

Switching my WordPress sites to https on GreenGeeks

I’ve used GreenGeeks hosting for years now and I really enjoy their services. I’m going to briefly talk about my experience moving two of my WordPress sites to SSL on GreenGeeks shared hosting. Moving to https used to be a little more of a pain in the butt, however thanks to Let’s Encrypt and forward-thinking web hosting providers, it’s now a breeze

First, I simply submitted a ticket to GreenGeeks to have them set up a Let’s Encrypt SSL cert for the sites that I wanted https on. In my situation, I had one site whose domain name was run through their nameservers and in that case they immediately were able to enable https. On my second site, however, I am using Google domains for DNS management. In this case, I just had to get a couple of DNS records from GreenGeeks support and viola, I was up and running. Their support team did a great job explaining what I needed to do.

There was one small problem remaining. I could still access the sites on http as well as https. So the last piece of this was to redirect http traffic to https. I did this in 2 steps.

  1. Change the site and home URL in your WordPress site to reflect the new https URL.
  2. Using .htaccess add a few lines to your WordPress htaccess file (shown below)
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://josephfitzsimmons.com/$1 [R,L]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

I am a professional

I’ve been a professional programmer for about 6 years now and I thought I’d share a story about something stupid I did. I think a lot of new programmers or people just trying to get into the field of web development feel dumb or get frustrated easily when things don’t work.

When I was just starting out, I considered someone who had 6 years of experience something of a “guru” who knew everything about the terminal and could code their way out of any situation.

I decided to sit down and continue learning Vue. Before starting, I was trying to make it so VS Code would launch from the terminal, so I did what I normally do and Googled it. Now I could’ve done it right from VS Code, but instead I tried to do it manually by editing my .bash_profile to add VS Code to the $PATH.

Turns out I didn’t actually append it to the path, I replaced it. So that means the only thing in my PATH was `code`. Needless to say, this completely screwed up my environment and my Mac terminal became essentially useless.

  • `ls` wouldn’t work
  • `git` wouldn’t work
  • every basic command wouldn’t work

I couldn’t launch code editors, drush didn’t work, composer didn’t work, node didn’t work, npm didn’t work. I thought the only way to get out of this mess was to factory reset. Before I did that, I Googled the issue “screwed up my $path mac” and luckily found an answer that made sense. I found a working solution for how to “reset” my $PATH variable so things would be usable again. Once my basic utilities were back, I was able to reconnect my dotfiles and I was back up in running.

The situation was a good reminder that even people who seem to know what they’re doing really don’t. 🤪 The only difference is that I have 6 years experience of Googling my way out of problems with computers.

Design is never done

“People are time bound entities transiting from cradle to grave. Any “solved problem” that involves human beings solves a problem whose parameters must change through time.
– Bruce Sterline, 2005

The bold emphasis is mine. This quote is from a Luke Wroblewski tweet that resonates strongly with me as a web designer/developer. If the point of design is to solve a problem, it must be accepted that the parameters of that problem must change through time as our environment and people change.

On top of the tweet which mentioned the above quote, Luke Wroblewski has a “Design is never done” series of tweets that further exemplify this idea.

For more examples of the “design is never done” concept, check out this advanced Twitter search.

This concept is an important one to hear, especially within higher education where change is often perceived as scary, unneeded, threatening, and has a number of other negative connotations. There is no “ideal state” that we will reach that will mark a website as “done.”

Investing in personnel who can execute ideas and ensure that digital assets can continue to evolve is extremely important in IT, communication, and marketing efforts within higher education.

Without this investment, organizations are reliant on 3rd party vendors, who may do a fantastic job, but it certainly isn’t the same as having a team on staff who can respond to the evolving needs of stakeholders and visitors.

My Terminus Drupal 7 cheat sheet

The Terminus documentation is amazing. However, I tend to only use a couple commands over and over so I created this post so I can continually reference it and have some “copy/paste” ready commands to use on my projects.

Get a URL to the latest snapshot of my production database

terminus backup:create <site>.live --element db
terminus backup:get <site>.live --element db

Adding a new module and committing it to dev

terminus connection:set <site>.dev sftp
terminus drush <site>.dev -- en paragraphs
terminus env:commit --message "message" <site>.dev

Adding a ‘thousands’ separator to ChartJS’s Y axis and tooltips

I learned the toLocaleString() method for adding thousands separators from this Github issue (https://github.com/chartjs/Chart.js/issues/411)

These options in your options config will add a thousands separator to your tooltips and yAxes.

options: {
  tooltips: {
    callbacks: {
      label: function(tooltipItems, data) {
        return data.labels[tooltipItems.index] + ": " + data.datasets[0].data[tooltipItems.index].toLocaleString();
      }
    }
  },
  scales: {
    yAxes: [{
      ticks: {
        beginAtZero: false,
        callback: function(value, index, values) {
          return value.toLocaleString();
        }
      }
    }]
  }
}

Drupal 7: Implementing designs & patterns using Paragraphs

I know the sun is setting on Drupal 7, but I think it’s still got a few good years left and someone may find this useful.

Design systems and pattern libraries are all the rage now. If you’re on Drupal 7 and using Paragraphs, you may be wondering how you can go about implementing patterns into Drupal for editors or your site builders to take advantage of.

Here’s the end result of the blog post:

I’m not going to get into what CSS I used, but in this post I’ll walk through my process and share some insights of what I learned along the way in regards to implementing the Paragraphs.

Start with a concept

Internally, we use Adobe XD to prototype ideas. A designer on our team analyzed different higher ed sites to come up with common patterns that seem to show up. She then documented those components in an XD document along with some variations.

I took those concepts and built out some pages using different combinations of components and their variations. I got some quick feedback from the team and we decided that I should begin implementing the patterns.

Break down the concept

Try to find common patterns that can act as your Paragraphs container. This ideally should be done after the concept is complete, but you may find that you need to make a couple passes at this.

You can do this on a whiteboard or a piece of paper or within a graphics program or prototyping tool. Doing this could save you a little time. I tried to break it down in my head and ran into some issues that probably could’ve been avoided.

In discussing the components with other people, questions about how similar one component was to another lead me down a path where I realized where I had 2 components, I could actually get away with only 1 component with a variation option (more on that later, but I used the Classy Paragraphs module)

Getting it into Drupal

For this example I’m going to implement 3 Paragraphs types (components) including the ability to choose some options when utilize the components to introduce variety.

  • Full width section container (full_width_section_container)
    • Background options (field_background_options)
      • Image
      • Green
      • Gold
      • Light gray
    • Spacing options (field_spacing_options)
      • Add vertical margin
      • Add margin top
      • Add margin bottom
    • Background image (field_oz_media)
    • Full width content (field_full_width_content)

  • Small feature (a component that is just an image with text to the side of it and buttons if desired)
    • Title (field_title)
    • Image/Video (field_oz_media)
    • Text (field_accompanying_text)
    • Buttons (field_buttons)
    • Variations (field_variations)
      • Center
      • Move right
      • Image on right

  • Button (button)
    • Title
    • URL
    • Variations (field_variations)
      • Green
      • Light
      • Arrow

Once you get your components broken down into a format like is shown above, it’s just a matter of clicking a few buttons within Drupal to create the Paragraphs types.

Reminder: Make sure you go to “Manage Display” and hide all the labels

Protip: Use the fences module to remove Drupal 7’s plethora of divs (divitis)

Protip: Use the classy paragraphs module to easily provided a dropdown list that can be used to add classes for use in your $classes array in .tpl.php files.

Add logic within a custom module

I made a module called “paragraphs_pages” to store the logic and templates of the components.

function paragraphs_pages_classy_paragraphs_list_options($options, $field, $instance) {
    if ($instance['field_name'] === 'field_background_options') {
        $options['bg-lg'] = t('Light gray background (soft)');
        $options['bg-gr'] = t('Green background (strong)');
        $options['bg-ye'] = t('Gold background (loud)');
    }

    if ($instance['field_name'] === 'field_spacing_options') {
        $options['mv5'] = t('Add vertical margin');
        $options['mb5'] = t('Add margin bottom');
        $options['mt5'] = t('Add margin top');
    }

    if ($instance['field_name'] === 'field_variations') {
        if ($instance['bundle'] === 'small_feature') {
            $options['center'] = t('Center text');
            $options['right'] = t('Right side');
            $options['img-right'] = t('Image on right side');
        }
        if ($instance['bundle'] === 'button') {
            $options['btn-green'] = t('Green');
            $options['btn-white'] = t('Light');
            $options['btn-arrow'] = t('Text with arrow');
        }
    }

    return $options;
}

/**
 * Implements hook_theme().
 */
function paragraphs_pages_theme($existing, $type, $theme, $path) {
    $theme = array();
    $theme['paragraphs_item__small_feature'] = array(
        'render element' => 'content',
        'base hook' => 'entity',
        'template' => 'paragraphs-item--small-feature',
        'path' => drupal_get_path('module', 'paragraphs_pages') . '/templates',
    );
    $theme['paragraphs_item__full_width_section_container'] = array(
        'render element' => 'content',
        'base hook' => 'entity',
        'template' => 'paragraphs-item--full-width-section-container',
        'path' => drupal_get_path('module', 'paragraphs_pages') . '/templates',
    );
    $theme['paragraphs_item__button'] = array(
        'render element' => 'content',
        'base hook' => 'entity',
        'template' => 'paragraphs-item--button',
        'path' => drupal_get_path('module', 'paragraphs_pages') . '/templates',
    );
    return $theme;
}

For the hook_classy_paragraphs_list_options() that the classy paragraphs module provides, I check to see what the field name of the classlist is and provide options that can be selected. If you’d like a UI for this, check out classy paragraphs ui module.

If I want the variations to differ based on what Paragraphs type is being used, I can check the bundle before setting the options, as shown above.

For the hook_theme() implementation, you’ll see that I am telling Drupal to use custom templates for our paragraph types that reside within the ‘paragraphs_pages’ custom module folder.

A template implementation example

full-width-section-container.tpl.php
<?php $bg = (isset($content['field_oz_media'])) ? "filter-darken cover" : ""; ?>
<?php if (isset($content['field_oz_media'])): ?>
  <?php $imgurl = file_create_url($content['field_oz_media'][0]['#item']['uri']); ?>
  <?php hide($content['field_oz_media']); ?>
<?php endif; ?>

<?php if ($bg === ""): ?>
  <div class="pv5 <?php print $classes; ?>"<?php print $attributes; ?>>
    <?php print render($content); ?>
  </div>
<?php else: ?>
  <div class="pv5 <?php print $bg . " " . $classes; ?>"<?php print $attributes; ?> style="background-image: url('<?php print $imgurl; ?>')">
    <div class="relative z-1">
      <?php print render($content); ?>
    </div>
  </div>
<?php endif; ?>
small-feature.tpl.php
<?php if (isset($content['field_oz_media'])): ?>
  <?php $classes .= " has-media"; ?>

  <div class="small-feature <?php print $classes; ?>">
    <div class="the-media">
      <?php print render($content['field_oz_media']); ?>
    </div>
    <div class="small-feature__content">
      <h3><?php print render($content['field_title']); ?></h3>
      <?php print render($content['field_accompanying_text']); ?>
      <?php print render($content['field_buttons']); ?>
    </div>
  </div>

<?php else: ?>

  <div class="small-feature <?php print $classes; ?>">
    <div class="small-feature__content">
      <h3><?php print render($content['field_title']); ?></h3>
      <?php print render($content['field_accompanying_text']); ?>
      <?php print render($content['field_buttons']); ?>
    </div>
  </div>

<?php endif; ?>

I know it isn’t best practice to put any logic within a tpl.php file but hey, it got the job done.

Most of the classes that I’m using are provided by Tachyons. I find that this framework allows me to rapidly get my components 90% complete. I would highly recommend taking a look at that for quickly building components.

Wrapping up

That is the meat of how to implement some components that can be put into Paragraphs for site builders and editors to create awesome looking, consistent pages using components. Adding just a few variations can help create a large number of combinations of components to create many different looking pages that all have a shared style.