Editing the README

In the previous post of this WordPress Plugin Boilerplate series, we created the WP Starter Plugin using the plugin generator. However, before we begin developing, there is at least one thing we need to edit: the README file.

The plugin generator barely touches the README file (remind me to file a bug report), leaving it incomplete. Since we want to learn to develop plugins properly as we go, we start by editing the README.

Examining the Parts

The README consists of several parts which are typical for most plugin README files:

  • Tags (at the top)
  • Description
  • Installation Instructions
  • Frequently Asked Questions
  • Screenshot List
  • Changelog
  • Upgrade Notices
  • Arbitrary Section

Tags

The tags populate much of the information you see in a plugin listing on the WordPress Plugin Directory.

For starters, correct the === Plugin Name === to your plugin’s name.

The contributors tag needs your wordpress.org username and any other developer’s usernames as well.

The Donate link should already be your Author URI. If you have a specific site where people can donate money for your plugin, use that instead.

Tags helps classify your plugin in the directory. Its similar to how news websites use categories like World, Sports, Entertainment, etc. If you need to use more than one, be sure to separate them with commas.

WordPress uses the Requires At Least and Tested Up To tags for compatibility checks. If a plugin requires a specific version of WordPress, then users below that version will not receive automatic updates.

Stable Tag is the current version of your plugin. Update this every time you create a new version. Since this is a new plugin, change this to 1.0.0.

License and License URI tags should remain “GPL-2.0” and the URL given. To remain compatible with the GPL 2 license, you can use a more permissive license, like the MIT license, but not a more restrictive one.

Description

There are actually two descriptions in the README file. There’s a short description above the === Description === header and a long description just below the header.

Limit the short description to 150 characters or less and do not use markup. Think of this as a tweet describing your plugin.

The long description explains the details of your plugin. This section uses Markdown formatting so you can dress it up with lists, links, headings, and even videos. It can be as long as you prefer and can include just about anything. Many developers use this section to convince users to choose this plugin, up-sell paid versions of this plugin, provide documentation for simpler plugins, and/or usage instructions.

As an example, the Yoast SEO plugin uses the long description to convince users to install the plugin, up-sell the paid version of the plugin, then detail the plugin features. Others simply provide a link to the plugin’s website where the details are provided.

I would advise using this space to add as much information as possible about your plugin. Give people reasons to use your plugin and list out the features. Then, provide more detailed documentation on your website or on a dedicated plugin site.

Installation Instructions

Give people the instructions what they need to get your plugin working. Some plugins only require installation and activation to work. Others need shortcodes placed into content. Some may require template tags. I saw one recently on github that required moving a folder into your theme.

Most of the time, the first two instructions in the example list are consistently the same. For the rest, give step-by-step details. Be sure to test this out on a new WordPress install to make sure you don’t miss anything.

Frequently Asked Questions

This is your chance to provide some basic documentation to users. If your plugin uses a shortcode, give the basic usage instructions in an FAQ. Same for template tags or any other major plugin feature. Try to anticipate what people may ask and answer it here first. Be sure to pay attention to the example’s formatting.

Screenshot List

Provide some screenshots of your plugin in action. These could be the settings pages or examples of the output. For example, if you provide 3 screenshots, name the image files screenshot-1.jpg, screenshot-2.jpg, and screenshot-3.jpg. Then the screenshot descriptions in this list match the corresponding file based on the list order. Since this is a new plugin, leave the examples alone. We’ll add screenshots later and edit these accordingly.

Changelog

The changelog provides details about the changes from one version to the next. I recommend providing as much as detail as you can. For example, if the next version has 10 commits, use the commit messages as list items in the changelog for this version. If you don’t use the commit messages, at least tell what major things changed in this new version. For a new plugin, there isn’t a changelog yet, so remove the examples and enter something like:

= 1.0.0 =
* New plugin.

Upgrade Notices

At first it seems like the upgrade notice is the same as the changelog entry. However, these notices are considerably shorter. I think of them like a mini-sales pitch for why a user should update to this new version. Keep them short, the limit is 300 characters. New plugins also don’t need an upgrade notice, so you can delete the examples here. The formatting is the same as the changelog, so we can look there for an example later.

Arbitrary Section

You can add additional sections to the README and they can be whatever you need. They use the same heading formatting as the other headings and also use Markdown formatting. I’ve seen just a handful of plugins that use another section. They are usually for something really outside the norm or where the plugin requires additional information outside not classified under the provided headings. In this case, remove the entire section.

Wrapping Up the README

At this point, your README should have an accurate set of tags and plugin name at the top, good plugin descriptions (long and short), good installation instructions, no FAQs, no screenshots, no upgrade notices, and one changelog entry. In the next post, we will begin creating the WP Starter Plugin and learning to build plugin parts in the boilerplate.

Using the Plugin Generator

In the previous post of the WordPress Plugin Boilerplate series, we explored the loader class and how to properly register hooks. In this post, we will begin developing the WP Starter Plugin by using the plugin generator.

Enrique Chávez, a full-stack WordPress developer from Valle de Bravo, Mexico, built the WordPress Plugin Boilerplate Generator. You can find the plugin generator at https://wppb.me/.

Generating A Plugin

WordPress Plugin Boilerplate Generator Homepage

The generator operates from a simple form. After hitting the Build Plugin button, the site returns a zip file of a boilerplate-based plugin. Let’s start by looking at the form.

Plugin Name

We start with the name of your plugin. Here’s what I entered for our example plugin: WP Starter Plugin.

Plugin Slug

The plugin slug becomes the translation string, the URL slug, and part of each class file name. Here’s what I entered for our example plugin: wp-starter-plugin.

Plugin URI

The plugin URI is the web address where people can find more information about your plugin. Here are some ideas for this URL:

  • the github repo page
  • a dedicated plugin website URL
  • a page on your site

I create a page on my site for each plugin I publish, so here’s what I entered for our example plugin: https://www.slushman.com/wp-starter-plugin.

Author Name

In this field, enter the name of the plugin developer. This should be your wordpress.org username, especially if you plan to publish your plugin. Otherwise, you could use your proper name (ie Chris Wilcoxson) For our example plugin, I entered my wordpress.org username: slushman.

Author Email

Enter a valid email address. If you plan to publish your plugin to the WordPress Plugin Directory, the directory admins will contact you through this email. Otherwise, people will most likely use this for support requests. For our example plugin, I entered my email.

Author URI

This is simply the author’s website. For our example plugin, I entered the URL of this website: https://www.slushman.com.

Build Plugin

Finally, click the Build Plugin button to build your plugin. The site should allow you to download the zip file of your new plugin.

Examine the Results

Open the zip file and check out the resulting plugin. You can see the plugin uses the boilerplate structure, except the classes now use your plugin slug. If you open some of the class files, you’ll notice the translation strings use your plugin slug as well.

I’m sure you can see the generator saves a good deal of time when starting a new plugin. Finding and replacing each string and filename isn’t overly difficult, but it can be time consuming, especially if you miss one and get errors.

Wrapping Up

In the next post, we’ll look at the final steps needed before actually beginning development. While the generator saved some time and manual labor, there are some parts of the plugin that require attention before moving on to development.

Understanding the Loader Class

In the previous post of the WordPress Plugin Boilerplate series, we walked through the structure. We also examined each file and what they do. The biggest feature of the version 3 rewrite is the new loader class.

The loader class loops through all the hook calls and registers them with WordPress all at once. The class consists of two class variables and four methods.

Class Variables

Each of the class variables are arrays containing the hooks and their corresponding functions.

$actions

An array of the all actions to register with WordPress.

$filters

An array of the all the filters to register with WordPress.

Methods

There are only four methods in the loader class, not counting the constructor.

Constructor

The class constructor simply assigns a blank array to each of those class variables.

add_action()

Adds the action passed to it to the $actions class variable using the add() method.

add_filter()

Adds the filter passed to it to the $filters class variable using the add() method.

add()

Takes the passed in hook and the other parameters and restructures everything into an array.

run()

Loops through the $actions and $filters class variables and registers each hook with WordPress.

Summary

The main plugin class calls add_action() and add_filter() with the hook parameters. Each method passes parameters to the add() method, which collects all the hooks into respective class variables. The main plugin class calls the run() method, loops through the class variables, then registers the hooks with WordPress.

How to Register Hooks

The most confusing part of using the new loader class is properly registering hooks. While the boilerplate has methods named add_action() and add_filter(), they work differently than the WordPress functions.

The boilerplate gathers all the hooks to register them with WordPress all at once. Let’s use the enqueue_styles declaration in define_admin_hooks() as an example.

First, we have to create an instance of the admin class and assign it as the variable $plugin_admin. We also pass the plugin_name and version using the get_plugin_name() and get_version() methods in this class.

$plugin_admin = new Plugin_Name_Admin( $this->get_plugin_name(), $this->get_version() );

Next, we use the add_action method in the Loader instance. Each hook registers separately with the loader class. In the load_dependencies() method, we assigned the instantiated loader class to the $loader class variable.

$this->loader

Since enqueue_styles is an action hook, we use the add_action() method from the loader class.

$this->loader->add_action

This first parameter of the boilerplate’s add_action method is the name of the hook. In this case, admin_enqueue_scripts.

$this->loader->add_action( 'admin_enqueue_scripts',

The second parameter of the add_action method is the class instance of our action.

$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin,

Finally, we put the name of the method in the class where WordPress can find our action. In this case, the name of the method is enqueue_styles.

$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );

Additional Loader Method Parameters

The loader class accepts two additional parameters: the hook priority and the accepted arguments. Both are optional and in this case, we’re not using either. However, a complete example would be:

$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles', 10, 1 );

Finally, in the admin class, the enqueue_styles() method contains:

wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/plugin-name-admin.css', array(), $this->version, 'all' );

This is the standard way to enqueue a CSS file into the WordPress admin through the plugin boilerplate methods.

Summary

We have seen how the loader class works and the proper way to register a hook.

In future posts, we will learn how to create various plugin features using the boilerplate. Let’s start by creating the WP Starter Plugin by using the plugin generator.

The Structure of the WordPress Plugin Boilerplate

In the previous post of the WordPress Plugin Boilerplate series, we looked at why one would use the boilerplate. This post will explore the organized structure in more detail.

The structure makes plugin development more predictable and easier to maintain in the future. The boilerplate organizes files into four main folders:

Plugin Folder

WordPress Plugin Boilerplate Main FolderThe main plugin folder contains basic files for creating a WordPress plugin.

Main Plugin File

This file contains the comments describing what it does, who authored it, the current version, etc. The boilerplate also uses the PHPDoc versions of those same properties.

This file also registers the activation and deactivation hooks, then runs the main plugin file.

readme.txt file

A required file for any WordPress plugin. It describes what the plugin does, who authored it, as well as a changelog and versioning information.

GPL 2.0 license

The boilerplate uses the GPL 2.0 license which is the same license as WordPress. A copy of the license is a wise thing to include in your plugin.

index.php file

The index.php file is internationally blank. Some developers have questioned the necessity of including this file. However, many experienced developers have explained a file like this helps with security concerns.

uninstall.php file

Plugins usually remove settings and other database-related features in the uninstall file.

Languages

WordPress Plugin Boilerplate Languages FolderThe languages folder contains all the files needed for translations. The boilerplate includes an empty .pot file for translations. You can optionally include additional .pot files containing the translated strings.

Admin & Public

WordPress Plugin Boilerplate Public Folder
WordPress Plugin Boilerplate Admin Folder
Since both the admin and public folders have the same structures, I’ll explain both at once. The admin and public classes have the same structure and methods, but keep the different concerns separated.

class-plugin-name-admin.php & class-plugin-name-public.php

This is the main class. Most of the plugin code will reside in one or both of these files.

partials

WordPress Plugin Boilerplate Admin Partials FolderThe partials subfolder contains PHP files with the output HTML code. For example, displaying a settings page in the admin requires using two files. The WordPRess API code resides in the admin class, but the HTML output would be in a partial file.

JS

WordPress Plugin Boilerplate Admin JS FolderThis folder contains all the Javascript files for the plugin.

CSS

WordPress Plugin Boilerplate Admin CSS FolderThis folder contains all the CSS files for the plugin.

Includes

WordPress Plugin Boilerplate Includes FolderThe includes folder is Tom’s answer for where to put code that isn’t exclusive to the admin or public. A common question prior to version three was where to put code for features that are both public and admin, like widgets.

class-plugin-name.php

This is the main plugin file. All the plugin’s WordPress hooks register through the Loader class here. All the class files become available throughout the plugin in this file as well.

The constructor sets the class variables. plugin_name is for naming things, like enqueueing stylesheets, and version is for caching busting scripts and stylesheets. Then these four methods run:

  • load_dependencies(): includes each of the classes used in the plugin. Instantiates the loader class.
  • set_locale(): contains the hooks for translation using methods in the i18n class.
  • define_admin_hooks(): contains the hooks for the plugin admin using methods in the admin class.
  • define_public_hooks(): contains the hooks for the public-facing parts of the plugin using methods in the public class.

class-plugin-name-activator.php

Contains any code that runs during plugin activation.

class-plugin-name-deactivator.php

Contains any code that runs during plugin deactivation.

class-plugin-name-i18n.php

Loads and defines the internationalization files for this plugin so all the strings are ready for translation.

class-plugin-name-loader.php

This is the big new feature of version three. The loader class takes all the hooks defined in the main plugin file and registers them with WordPress.

In the next post, we’ll examine the loader class in detail and how it differs from writing normal WordPress hooks.

Why Use the Boilerplate?

In the first post of the WordPress Plugin Boilerplate series, we covered the history of the project. In this post, we’re going to address a common question. The first question both new and experienced developers ask about the boilerplate is: why should I use this? The boilerplate describes itself as “a standardized, organized, object-oriented foundation for building high-quality WordPress plugins.” Here are at least five different ways the boilerplate helps when building plugins.

Organized

WordPress plugins don’t have a required structure. Many plugins are literally just one file. However, as a plugin gets more complex, better organization keeps it maintainable. The Boilerplate has an existing folder structure for keeping all the parts organized. While you’re able to customize everything, the pre-existing structure offers a predictable format can make building plugins easier.

Object-Oriented

Each class in the boilerplate separates the responsibilities of the methods and functionality. The included classes start with one public-facing object, one admin-facing object, and several classes used in either. You can see included examples to continue the good OOP practices in your custom classes.

WordPress Coding Standards

The boilerplate uses the WordPress Coding Standards. Seeing good examples can only help the code quality of plugins, especially for ones submitted to the plugin directory.

WordPress Documentation Standards

One of the best things you can do while building a plugin is document your code. The boilerplate uses the WordPress Documentation Standards and gives you plenty of really good examples of properly documenting code. I write my documentation to explain to my future self how the code works and why I wrote the code this particular way.

WordPress APIs

Of course, the boilerplate uses standard WordPress APIs so the examples you find in the Codex and every WordPress code blog are still usable.Codex examples would require some minor alterations to work within the boilerplate. We’ll go over those in detail as we build the WP Starter Plugin.

Translatable

The boilerplate includes a blank .pot file so you can add your translatable string easily. As WordPress becomes more popular outside the English-speaking community, making your plugin translatable increases the potential reach of your plugin.

Plugin Generator

The WordPress Plugin Boilerplate has a companion project – a plugin generator. The generator replaces the various strings and file names with your plugin’s information so you don’t have to do all this manually. Its a major head start. You can find the generator at https://wppb.me/.

Coming Next

I hope you see the boilerplate can be a useful tool for building plugins. In the next post, we’ll examine the files and folder structure.

A Guide to Using the WordPress Plugin Boilerplate

For several years now, I’ve been building plugins using the WordPress Plugin Boilerplate project. In 2015, I gave a WordCamp talk about how to use it. Over the past few years, I’ve answered questions about how to build plugins with the boilerplate. Since there is no formal documentation, I hope these posts serve that purpose unofficially. I covered most of this introductory material in my WordCamp talk. However, I’m planning more detailed posts, additional code examples, and topics I didn’t cover in the presentation. I’ll also offer some shortcuts and potential improvements, in case you want to fork the boilerplate.

When I first began writing plugins, I did what most beginning developers do – copy and paste code samples from the Codex and/or another developer’s blog. Each plugin eventually worked, but I still cringe when I look at that code. Many of those first plugins were giant, one-file plugins. Over time, I learned better methods for writing code and eventually discovered the WordPress Plugin Boilerplate. Since then, I’ve used either the boilerplate or my own fork for even the simplest plugins.

What Is The WordPress Plugin Boilerplate?

A good starting place is understanding what the boilerplate is and the history behind it. The boilerplate is a standardized, organized, object-oriented foundation for building high-quality WordPress plugins. There are some simple examples of how the parts work together as examples for building your plugin. In addition, the boilerplate includes easily overlooked plugin features like inline documentation and translation files.

Tom McFarlin, a well-respected developer from Atlanta, GA, developed the boilerplate. He wanted to prevent needlessly writing the same code each time he began a new plugin. The boilerplate is currently on version 3, which included a major restructuring. In March of 2015, the boilerplate project passed to Devin Vinson of Tampa Bay, FL.

How Do We Use The Boilerplate?

Since there is so much information to cover, we’ll cover each subject in a separate post. This introductory post will serve as a table of contents for the series. Throughout this series, we’ll build an example plugin titled “WP Starter Plugin”. It will include typical plugin parts like settings pages, widgets, metaboxes, etc. This gives you a major head start when creating plugins in the future.

Posts In This Series

  • Why Use the Boilerplate?
  • The Structure of the WordPress Plugin Boilerplate
  • Understanding the Loader Class
  • Using the Plugin Generator
  • Editing the README

Parker and WordPress Menus

As a sort-of follow up to my previous posts, I ran across an issue with styling menu items and found a great way to add classes so I can style those items directly.

Many of our designs have a vertical bar between menu items. While there are several ways to accomplish this, I’ve been using something like this in recent projects to style the top-level menu items:

.primary-menu-item-0 :not(:first-child) a {
 border-left: 1px solid;
 padding-left: 1em;
 }

Basically, add a left border and some padding to every menu item, except the first child. This results in a vertical bar between each menu item and the first child just has nothing. You can further refine it by targeting the first and last children to remove the outside padding as well.

Since using Parker to style as directly as possible, it struck me that having a selector that complex shouldn’t be necessary. Thankfully, there’s a simple way around it.

Adding Menu Item Classes

In the menus part of the Parker series, we added classes to each menu item and menu item link. The functions we used can have up to 4 parameters, which are passed in from the filter.

In the nav_menu_css_class hook, the $item parameter is the menu item object. We’re going to check the menu_order property value and if its either the first or last menu item, we’ll add classes so we can style those two menu items directly.

/**
  * Adds a class with the menu name and depth level to each menu item.
  * Makes styling menus much easier.
  *
  * @hooked nav_menu_css_class 10
  * @param array $classes The current menu item classes.
  * @param object $item The current menu item.
  * @param array $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item classes.
  */
 function example_add_menu_order_to_menu_item_classes( $classes, $item, $args, $depth ) {

 if ( empty( $item ) ) { return $classes; }

 if ( 1 === $item->menu_order ) {

 $classes[] = $args->menu_id . '-item-first';
  $classes[] = $args->menu_id . '-item-' . $depth . '-first';

 }

 if ( $args->menu->count === $item->menu_order ) {

 $classes[] = $args->menu_id . '-item-last';
  $classes[] = $args->menu_id . '-item-' . $depth . '-last';

 }

 return $classes;

} // example_add_menu_order_to_menu_item_classes()

 add_filter( 'nav_menu_css_class', 'example_add_menu_order_to_menu_item_classes' ), 10, 4 );
 

To add the “first” classes, we check is $item->menu_order equals 1. If so, add a class that will allow for styling any first menu item and a second class that allow for styling the first menu item at that particular menu depth. Now, we can style all the first menu items and any first menu item at any depth directly using single class.

To add the “last” classes, we compare the menu item count from the menu $args object against the $item->menu_order. If they are equal, we’re on the last menu item, so we can add the appropriate classes.

Adding Menu Link Classes

However, my first example was actually styling the menu item link. We can add classes using the nav_menu_link_attributes filter, just like we did when we added the depth classes.

/**
  * Adds classes to menu item links.
  *
  * Adds the depth class to make styling easier.
  * Adds the "coin" class if the menu item has the text-coin class.
  *
  * @hooked nav_menu_link_attributes 10
  * @param array $atts The current menu item link attributes.
  * @param object $item The current menu item.
  * @param object $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item link attributes.
  */
 function example_add_menu_order_to_menu_item_links( $atts, $item, $args, $depth ) {

if ( empty( $item ) ) { return $atts; }

 if ( 1 === $item->menu_order ) {

 $atts['class'] .= $args->menu_id . '-item-link-first ';
  $atts['class'] .= $args->menu_id . '-item-link-' . $depth . '-first ';

 }

 if ( $args->menu->count === $item->menu_order ) {

 $atts['class'] .= $args->menu_id . '-item-link-last ';
  $atts['class'] .= $args->menu_id . '-item-link-' . $depth . '-last ';

 }

return $atts;

} // example_add_menu_order_to_menu_item_links()

 add_filter( 'nav_menu_link_attributes', 'example_add_menu_order_to_menu_item_links' ), 10, 4 );

This function follows the same basic pattern, except how the class is added. Now, the first menu item links and last menu item links can be styled using a single class. We can also style the first or last menu item link at any depth using a single class.

Wrapping Up

So instead of this:

.primary-menu-item-0 :not(:first-child) a {
 border-left: 1px solid;
 padding-left: 1em;
 }

We do this:

.primary-menu-item-link-0 {
  border-left : 1px solid $teal;
  padding : 0 1em;
}

.primary-menu-item-link-0-first {
 border-left: none;
 padding-left: 0;
}

These are much simpler selectors, so maintainability and troubleshooting will be easier. We also have some really useful classes for styling menu items as needed. Admittedly though, its not as fun as doing it all in one selector.

How to Pass Variables with get_template_part

I’ve had several occasions where I needed to use variables in a file called using get_template_part, like one of the files in the template-parts folder in _s. It took a while for me to find the proper answer, so I’m documenting it here. Just before you use get_template_part(), add set_query_var(). As the arguments, add the name of the variable, then the value. Like:

set_query_var( 'user_id', $user_id );

In the template file, you can then use $user_id as you would any other variable.

Finishing the Underscores Stylesheet

Summary

In the previous posts in this series about Parker, we used the stylesheet analysis tool to optimize the stylesheet for the _s starter theme. We also used hooks and functions to customize the WordPress menus and as a result we have a simpler stylesheet. Here are the goals we were trying to achieve:

  • Reduce stylesheet complexity
  • Increasing maintainability
  • Making more CSS classes reusable

After using Parker’s metrics and optimizing, lets compare our baseline results to our final results:

Baseline

  • Total Stylesheets: 1
  • Total Stylesheet Size: 15432
  • Total Rules: 134
  • Total Selectors: 280
  • Total Identifiers: 508
  • Total Declarations: 243
  • Selectors Per Rule: 2.08955223880597
  • Identifiers Per Selector: 1.8285714285714285
  • Specificity Per Selector: 10.446428571428571
  • Top Selector Specificity: 120
  • Top Selector Specificity Selector: #content[tabindex=”-1″]:focus
  • Total Id Selectors: 1
  • Total Unique Colors: 15
  • Unique Colors: #FFFF00,#000000,#C0C0C0,#404040,#EEEEEE,#666666,#FFF9C0,#FFFFFF,#CCCCCC,#BBBBBB,#E6E6E6,#AAAAAA,#111111,#F1F1F1,#21759B
  • Total Important Keywords: 2
  • Total Media Queries: 1
  • Media Queries: screen and (min-width: 37.5em)

Final

  • Total Stylesheets: 1
  • Total Stylesheet Size: 14405
  • Total Rules: 134
  • Total Selectors: 240
  • Total Identifiers: 350
  • Total Declarations: 243
  • Selectors Per Rule: 1.791044776119403
  • Identifiers Per Selector: 1.475
  • Specificity Per Selector: 8.566666666666666
  • Top Selector Specificity: 30
  • Top Selector Specificity Selector: .infinite-scroll.neverending .site-footer
  • Total Id Selectors: 0
  • Total Unique Colors: 15
  • Unique Colors: #FFFF00,#000000,#C0C0C0,#404040,#EEEEEE,#666666,#FFF9C0,#FFFFFF,#CCCCCC,#111111,#BBBBBB,#E6E6E6,#AAAAAA,#F1F1F1,#21759B
  • Total Important Keywords: 2
  • Total Media Queries: 1
  • Media Queries: screen and (min-width: 37.5em)

After all these optimizations and changes, lets finally look at how we did.

  • We reduced our stylesheet size from 15432 to 14405. That’s an over 1kb reduction!
  • We reduced the Total Selectors from 280 to 240.
  • We reduced the Total Identifiers from 508 to 350.
  • We reduced the Selectors Per Rule from 2.08955223880597 to 1.791044776119403.
  • We reduced the Identifiers Per Selector from 1.8285714285714285 to 1.475.
  • We reduced the Specificity Per Selector from 10.446428571428571 to 8.566666666666666.
  • We reduced the Top Selector Specificity score from 120 to 30.
  • We reduced the Total Id Selectors from 1 to 0.

Wrapping Up

Those are some pretty good results for a stylesheet that doesn’t really contain much. You’ll see much better results when working on a fully developed them. Having done all this work though, what does it all mean?

Reducing the size helps the site load faster. When a browser asks a server for a web page, a single roundtrip request is about 14kb in size. Our newly optimized stylesheet, at 14.4kb, is almost small enough to fit into a single request.

We’ve made the stylesheet much easier to read by refactoring the code to eliminate the longer selectors, so it should be easier to maintain in the future.

Finally, we’ve increased the reusability of our classes and made the rest of our rules less specific. Ideally, as a new theme is built from this optimized stylesheet, more thought it put into creating reusable classes and tweaking the default WordPress code to allow for more direct access to elements.

I’ll be submitting some pull requests to the _s repo based on some of these tweaks, so some of these changes may already be completed in future versions of _s. I highly recommend running Parker on your finished stylesheets to find ways to get these metrics as close to the ideals as possible. While Parker isn’t a solve-everything kind of tool, it is useful to constantly improve what we do and know how and why it’s an improvement.

I’m hooked on using Parker and plan to integrate it into my workflow during my next project. Integrating Parker into my gulpfile has been the simplest way to run it at the same time I pre-process my SASS files. Let me know how Parker is changing your stylesheets and/or development process!

Simplifying Menu Styling

In the previous post in this series about Parker, we optimized parts of the _s stylesheet and improved our Parker scores. However, one of the more difficult optimizations by working on the menus. This isn’t just a stylesheet tweak though, we’ll need to add some code to _s that adds classes to each menu ul tag, menu item, and menu item link.

The Menu

The styling for menus in _s involves some pretty insane selectors, like this one:

.main-navigation ul ul li:hover > ul

Lets look at how to add classes to each menu ul tag, menu item, and menu item link so we can reduce how many identifiers we use in each selector, improve our Parker scores, and simplify our stylesheet.

Menu Items and Links

In the inc/extras.php file, we’re going to create two functions. The first adds classes to the menu items and the second adds classes to the links in each menu item.

ADD DEPTH AS A MENU ITEM CLASS

The following function adds two classes, derived from the menu name and the menu item depth, to each menu item.

/**
  * Adds a class with the menu name and depth level to each menu item.
  * Makes styling menus much easier.
  *
  * @hooked nav_menu_css_class 10
  * @param array $classes The current menu item classes.
  * @param object $item The current menu item.
  * @param array $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item classes.
  */
 function _s_add_depth_to_menu_items( $classes, $item, $args, $depth ) {

    if ( empty( $item ) ) { return $classes; }

    $classes[] = $args->menu_id . '-item';

    $classes[] = $args->menu_id . '-item-' . $depth;

    return $classes;

} // _s_add_depth_to_menu_items()
 

add_filter( 'nav_menu_css_class', '_s_add_depth_to_menu_items', 10, 4 );

The function first checks if the item is empty and returns if it is. We’re not going to work invalid menu items.

The $classes parameter is an array, so we create the two new classes, add them to the array, and return the modified array. Here are examples of the resulting class names for a menu titled “Primary Menu”:

.primary-menu-item

.primary-menu-item-0

The class that includes the depth changes for each menu item according to its depth in the menu:

.primary-menu-item-1

.primary-menu-item-2

.primary-menu-item-3

So instead of using:

.primary-menu ul ul ul li

We could use this to style just the menu items at this depth:

.primary-menu-item-2

Or this to style the menu items at this depth and all its descendants:

.primary-menu-item-1 li

This works great for the menu item, but what about the link inside the menu item?

ADD DEPTH TO MENU ITEM

The following function adds two classes, derived from the menu name and the menu item depth, to each menu item link.

/**
  * Adds classes to menu item links.
  * Adds the depth and menu name to make styling easier
  *
  * @hooked nav_menu_link_attributes 10
  * @param array $atts The current menu item link attributes
  * @param object $item The current menu item
  * @param object $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item link attributes.
  */
 function _s_add_depth_to_menu_item_links( $atts, $item, $args, $depth ) {

    if ( empty( $item ) ) { return $atts; }

    $atts['class'] .= $args->menu_id . '-item-link ';
    $atts['class'] .= $args->menu_id . '-item-link-' . $depth . ' ';

   return $atts;

} // _s_add_depth_to_menu_item_links()

add_filter( 'nav_menu_link_attributes', '_s_add_depth_to_menu_item_links', 10, 4 );

The function first checks if the item is empty and returns if it is. We’re not going to work with invalid menu items.

Since the classes for menu item links aren’t arrays, like the menu items, we append each newly created class to the existing class string. In this case, I’m adding two new classes:

  • menu-name-item-link
  • menu-name-item-link-depth

This allows for styling menu links in this menu and menu links in this menu at any particular depth. So we can apply styles to:

.primary-menu-item-link-2 

Rather than:

.primary-menu ul ul ul li > a

Custom Menu Walker

Now that we have the depth and menu name added to each menu item (li tag) and menu item link (a tag), we still need to add it to each menu level (the ul tag). Unfortunately, there’s not a filter for the menu ul tags, so we’ll need to create a new file in the “inc” folder called “main-menu-walker.php”. In functions.php. copy the last require statement and paste it at the bottom of the file. Change the file name to main-menu-walker.php and change the comment to “Load main menu walker”.

In the main-menu-walker.php file, we’re going to create a simple class that only includes one method. This method replaces the one used by the default menu walker class used in WordPress and inserts the new classes in each menu and submenu. Here’s the entire main-menu-walker.php file code:

<?php

/**
  * Custom walker for adding a wrapper around submenus in the main menu
  *
  * @since 1.0.0
  * @package Rosh
  * @subpackage Rosh/classes
  */
 class _s_Main_Menu_Walker extends Walker_Nav_Menu {

    /**
      * Adds classes to the each menu.
      * Offsets the depth by one to allwo for the top-level menu to be level 0.
 *
      * @see Walker_Nav_Menu::end_lvl()
      *
      * @param string $output Passed by reference. Used to append additional content.
      * @param int $depth Depth of menu item. Used for padding.
      * @param array $args An array of arguments. @see wp_nav_menu()
      */
     public function start_lvl( &amp;amp;$output, $depth = 0, $args = array() ) {

        $indent = str_repeat( "\t", $depth );
 $offsetdepth = $depth + 1;
         $output .= "\n$indent<ul class=\"$args->menu_id-items $args->menu_id-items-$offsetdepth\">\n";

   } // start_lvl()

} // class

The function adds two classes to each ul tag in the menus:

  • menu-name-items
  • menu-name-items-depth

Before we can optimize our stylesheet with all these new classes, open the header.php file and find the wp_nav_menu function call (around line 45). We need to tell the primary menu to use our new walker class and add two classes to the top-level ul tag. Add the following just after ‘menu_id’ => ‘primary-menu’ and save the files:

, 'menu_class' => 'primary-menu-items primary-menu-items-0', 'walker' => new _s_Main_Menu_Walker()

At this point, you should have classes that include the menu name and depth on each menu item list, menu item, and menu item link, allowing us to apply styles to the correct element using a few identifiers per selector as possible.

Change the Stylesheet

Since we can now access each part of the menu directly with a class, lets look at what needs to change in the current stylesheet.Here are the rules we can change in the Menus section:

  • .main-navigation ul
  • .main-navigation li
  • .main-navigation a
  • .main-navigation ul ul
  • .main-navigation ul ul ul
  • .main-navigation ul ul a
  • .main-navigation ul ul li
  • .main-navigation li:hover > a, .main-navigation li.focus > a
  • .main-navigation ul ul :hover > a, .main-navigation ul ul .focus > a
  • .main-navigation ul ul a:hover, .main-navigation ul ul a.focus
  • .main-navigation ul li:hover > ul, .main-navigation ul li.focus > ul
  • .main-navigation ul ul li:hover > ul, .main-navigation ul ul li.focus > ul
  • .main-navigation .current_page_item > a, .main-navigation .current-menu-item > a, .main-navigation .current_page_ancestor > a, .main-navigation .current-menu-ancestor > a
  • @media screen and (min-width: 37.5em) { .main-navigation ul

We’re going change these, respectively, to:

  • .primary-menu-items
  • .primary-menu-item
  • .primary-menu-item-link
  • .primary-menu-items-0 ul
  • .primary-menu-items-1 ul
  • .primary-menu-items-1 a
  • .primary-menu-items-1 li
  • .primary-menu-item:hover > a, .primary-menu-item.focus > a
  • .primary-menu-items-1 :hover > a, .primary-menu-items-1 .focus > a
  • .primary-menu-items-1 a:hover, primary-menu-items-1 a.focus
  • .primary-menu-item:hover > ul, .primary-menu-item.focus > ul
  • .primary-menu-item-1:hover > ul, .primary-menu-item-1.focus > ul
  • .current_page_item > .primary-menu-item-link, .current-menu-item > .primary-menu-item-link, .current_page_ancestor > .primary-menu-item-link, .current-menu-ancestor > .primary-menu-item-link
  • @media screen and (min-width: 37.5em) { .primary-menu-items

As you can see, we can get now apply styles to elements deep in a menu without needing to add more identifiers to select them. This also allows us to get rid of qualifying identifiers like “.main-navigation … ” because the menu name is now in a class in each item.

A quick note about the numbering before we move on. Computers start counting at 0, rather than 1, so the top-level menu items will be level 0, the next level is 1, etc.

Here are the results from our changes:

  • Total Stylesheet Size: 14405, up from 14344, but this expected since the class names are longer, therefore increase the byte size.
  • Total Identifiers: 350, down from 389
  • Identifiers Per Selector: 1.475, down from 1.6375
  • Specificity Per Selector: 8.566666666666666, down from 8.729166666666666

Wrapping Up

We’ve now performed the more difficult optimizations and seen the improvements in our Parker scores. In the final post, we’ll look back at our changes and see the overall improvement in our Parker scores. We’ll also talk about where to go from there.