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.


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”:



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




So instead of using:

.primary-menu ul ul ul li

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


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?


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:


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:


  * 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.

Improving Underscores Stylesheet Using Parker

In the previous post in this series about Parker, we created a baseline for the _s stylesheet and went through the results to understand them better. We also get some ideal scores for each metric. Now that we understand what we’re trying to do and why, let’s see how we can change the default _s stylesheet to get better scores from Parker and create a simpler, more maintainable stylesheet.

Changing the _s Stylesheet

When examining the baseline results, we can spot several places where the results differ from the ideal score and we can achieve:

  • Reduced Total Stylesheet Size
  • Reduced Total Selectors
  • Reduced Total Identifiers
  • Reduced Selectors Per Rule
  • Reduced Identifiers Per Selector
  • Reduced Specificity Per Selector
  • Reduced Top Selector Specificity
  • Reduced Total ID Selectors

Top Selector Specificity

Let’s start with the Top Selector Specificity. This one actually knocks out the Total ID Selectors as well since its the same selector. In style.css (and/or sass > modules > accessibility.scss), remove the “#content” at line 682 to become:

[tabindex="-1"]:focus {

There’s no reason any element with a tabindex value of -1 would need an outline. It’s simply more efficient to apply this style to any and every element with that attribute value, so this is an easy win.

Now, if we rerun Parker on the style.css file, we get:

  • Total Identifiers: 507
  • Identifiers Per Selector: 1.825, down from 1.8285714285714285
  • Specificity Per Selector: 10.089285714285714, down from 10.446428571428571
  • Top Selector Specificity: 30, down from 120
  • Total Id Selectors: 0

In addition to improving several of our stats, the Top Selector Specificity Selector has changed to the next “worst offending” selector. However, all the infinite-scroll classes fall into the “we can’t control what other coders give us” category, so we’ll leave that alone.

Identifiers Per Rule

Another fairly easy tweak will decrease the Identifiers Per Rule and the Selectors Per Rule. In the style.css, we’re going to remove all input selectors before a [] selector. Look at the Forms section, which starts around line 420. Many of the selectors here are structured like: input[input=”sometype”]. Parker and browser see two selectors here: “input” and “[type=”sometype”]”. However, its extraordinarily rare that any other element is going to use the type=”text” attribute or any of the others listed here, so the prefix of “input” can be removed entirely.

While that’s all well and good for the button selectors, the field selectors are another story. Do we really need to specify each type of field here? Its more efficient to take all the input[type=”text”], input[type=”password”], etc and make the entire selector just: “input, textarea”. Then move all the button selectors below this edited selector, so they get different styling than the generic “input” styling. If we need different styling for a particular input type, we can add that in after the input selector’s declaration. So the Forms sections goes from this:

Forms Screenshot Before

To this:

Forms Screenshot After

When we rerun Parker on the updated stylesheet, we get:

  • Total Stylesheet Size: 14647, down from 15424
  • Total Selectors: 252, down from 280
  • Total Identifiers: 423, down from 507
  • Selectors Per Rule: 1.8805970149253732, down from 2.08955223880597
  • Identifiers Per Rule: 1.6944444444444444, down from 1.825
  • Specificity Per Selector: 9.305555555555555, down from 10.089285714285714


We can reduce that even further by changing the Normalize.css section to update it closer to the current version (v 5.0.0 as of this writing). Remove all the “input” prefixes in the Normalize section at the top. This changes results in:

  • Total Identifiers: 413
  • Identifiers Per Selector: 1.6547619047619047
  • Specificity Per Selector: 9.265873015873016


Another easy win is in the Clearings section. Currently, the stylesheet has 12 selectors in the first declaration, and 6 in the second. Almost all of the selectors besides “clear” can be removed by adding the “clear” class to the elements in the theme. The one exception is the comment-content class since the comments content is output from WordPress and there isn’t currently a way to add the clear class to that output.

Open the template-parts/content-page.php and template-parts/content.php files, add the clear class to the entry-content div. Then remove the corresponding “.entry-content” selectors from the Clearings section of the stylesheet.

Open header.php and add the clear class to the header element and the .site-content element. Then remove the “.site-header” selectors and the “.site-content” from the Clearings section in the stylesheet.

Open footer.php and add the clear class to the footer element, then remove the “.site-footer” selectors from the Clearings section in the stylesheet.

The results from this change have no affect on the styling or appearance, but we get much better stats from Parker:

  • Total Selectors: 240, down from 252
  • Total identifiers: 389, down from 413
  • Selectors Per Rule: 1.791044776119403, down from 1.8805970149253732
  • Identifiers Per Selector: 1.6375, down from 1.6547619047619047
  • Specificity Per Selector: 8.729166666666666, down from 9.265873015873016

Wrapping Up

We’ve gone through the majority of the _s stylesheet and optimized it to improve our Parker scores. However, the biggest optimization we can make is with the menus. In the next post, we’ll go through all the code and changes we’ll need to add, in addition to the changes to the stylesheet.

Creating a Baseline for Parker

In the previous post in this series about Parker, we installed the stylesheet analysis tool and all its dependencies. Now, we’re going to create a baseline measurement of the default _s stylesheet and explain the results from Parker.

Create a Baseline

First, open Finder/Windows Explorer and navigate to the folder where you cloned _s. Open Terminal (or your preferred command line app), type in:


Note the space at the end! Drag the _s stylesheet file to Terminal. This puts the path to the stylesheet in Terminal. Hit enter to run Parker. The results will be something like this:


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)

Before we move on, let’s briefly go through the terminology in the results so we understand everything and what may need to change.

Selector vs Declaration vs Identifier vs Rule

If you’re like me and find all the terms confusing, this diagram maps it out. At minimum, I’m adding this for my future self who doesn’t remember what’s what.

This entire thing is a rule.

Parker Results, Explained

Total Stylesheets

The total quantity of stylesheets Parker examined. You can add multiple stylesheets at once and Parker will spit out results for all of them. If you do examine multiple stylesheets at once, Parker combines the results into one set of results. I’d advise testing each sheet separately.

Total Stylesheet Size

The size, in bytes, of the stylesheet. While there’s not really an “ideal” size, smaller is better.

Total Rules

The total quantity of CSS rules in the stylesheet. A “rule” is the selector and the styles applied to it. There’s not an ideal number of total rules to achieve, but a smaller number means the stylesheet is simpler.

Total Selectors

The total quantity of selectors used in the stylesheet. Selectors are combinations of identifiers for selecting an element on the site to which styles are applied. There’s not an ideal number of total selectors to achieve, but a smaller number means the stylesheet is simpler. Here are some examples, each of these counts as one selector:

  • .this-is-a-class
  • .this-is-a-class a
  • .this-is-a-class a:hover
  • .main-navigation ul ul ul li a

Total Identifiers

The total quantity of identifiers used in the stylesheet. Not to be confused with IDs, identifiers are each part of a selector. There’s not an ideal number of total identifiers to achieve, but a smaller number means the stylesheet is simpler. Here are some examples with their identifier count:

  • .this-is-a-class – 1
  • .this-is-a-class a – 2
  • .this-is-a-class:hover- 2 (pseudo selectors count separately)
  • .main-navigation ul ul ul li a – 6

Total Declarations

The total quantity of declarations in the stylesheet. Declarations are the CSS property and value. There’s not an ideal number of total declarations to achieve, but a smaller number means the stylesheet is simpler. An example declaration is:

color: #fff;

Selectors Per Rule

The total quantity of selectors used in each rule. Rules can apply to more than one selector, like “.this-is-a-class, .this-is-another-class”. This metric shows the mean of selectors used for each rule. Ideally, this number would 1 and each class would be reusable and only contain the styles needed for that class. This is one of those opinionated things I mentioned before. In Harry’s opinion, using multiple selectors like this should be avoided:

button, [type="button"], [role="button"], [type="reset"], [type="submit"]

We should create a single class and apply that class to all elements requiring those styles. However, as theme developers, we are often stuck having to cover all possible bases, since we can’t control the code output from plugins and sometimes WordPress itself.

The ideal for this value is 1, but I would advise getting as close to 1 as possible. Getting this number under 2 is doing really well.

Identifiers Per Selector

The total quantity of identifiers per selector. An ideal value is between 1 & 2. A single identifier per selector makes the minimum score of 1: “.this-is-a-class” is one identifier and one selector. This is one of the more challenging metrics to achieve the ideal score since we can’t control the code and classes we get from plugins and sometimes WordPress. Particularly, the default WordPress menu classes cause many developers to use selectors like: “.nav-primary ul ul ul li a”. While this gets the job done, it also results in an abysmal score for this metric: 6. Later, we’ll go over a method to reduce this particular selector down to a 1.

Specificity Per Selector

The mean of the specificity score of each selector. The easiest way to explain specificity is through examples:

a { color: #000; }

Applies to all links, so its not very specific.

.link-to-home {color: #000; }

Applies to any element with the class “link-to-home”. More specific than styling all the “a” tags, but less specific than using an ID.

#link-to-home {color: #000; }

Only applies to the element with the ID “link-to-home”. There should only be one of these elements, so it is extremely specific.

Parker is intended to help make your CSS classes reusable, so your specificity score should be as low as possible. This means your styles are reusable and don’t apply to super-specific elements. Typically, between 10 and 20 is doing pretty well, since we’ll mostly use classes for applying styles. Here’s the scoreboard used by Parker:

  • Universal selectors (like *): 0
  • Element selectors (like input or a): 1
  • Classes, attributes, and pseudo selectors: 10
  • IDs: 100

Top Selector Specificity

The highest specificity score in the stylesheet. There’s not really an ideal, but I’d say if you’re most specific selector is 30 or less, you’re doing pretty good.

Top Selector Specificity Selector

The selector with the highest specificity score in the stylesheet. This makes is easier to find the “worst offender” and refactor your code to eliminate it.

Total Id Selectors

Total quantity of IDs used in the stylesheet. Ideally, this is 0 since we shouldn’t style using IDs – they are too specific and the style rule cannot be reused.

Total Unique Colors

The total quantity of colors used in the stylesheet. This could be useful to spot small color variances (like multiple shades of light gray) and refactor them to use fewer colors throughout. A stylesheet with fewer colors is a simpler stylesheet.

Unique Colors

A comma-separated list of all the color codes used in the stylesheet.

Total Important Keywords

The total quantity of the use of “!important” in the stylesheet. Ideally, this number would be 0, but there are still valid uses of !important, so make sure your usage is justified.

Total Media Queries

The total quantity of media queries in the stylesheet. There’s no ideal number, but a smaller number of total media queries means a simpler stylesheet.

Media Queries

A comma-separated list of all the media queries used in the stylesheet. Useful for refactoring media queries for simplicity.

Wrapping Up

Now that we’ve learned what each result from Parker means and the ideal scores for each metric, we can start tweaking the _s stylesheet to get better scores and create a simpler, more maintainable stylesheet. In the next post, we’ll cover some easy wins to get closer to our goal.

Installing Parker

In my introductory post, I shared about the CSS analysis tool named Parker. In this post, we’ll cover installing Parker on your local machine so you are able to analyze your own code.

Before performing any of the following steps, you’ll need to install Parker and its dependencies. Parker runs from the command line, so you’ll need to open your favorite terminal app. I’m on a Mac, so I’ll be using Terminal. I’ll provide the instructions here for installing everything on a Mac, sorry Windows peeps. If you need assistance or run into difficulties with installing any particular thing, visit that tool’s site or try StackExchange. Here’s what you’ll need to install to follow along:

  • Xcode dev tools
  • Homebrew
  • node.js & npm
  • Parker
  • _s


Installing Xcode and the Developer Tools

Install Xcode before installing ParkerOpen Terminal and hit enter after typing/pasting:

xcode-select --install

This should open an application installer wizard for the developer tools. Go through the prompts and install the package. (Source: OS X Daily)

Installing Homebrew

Once that’s finished, install Homebrew, which makes installing packages on OS X easier. In Terminal, hit enter after typing/pasting:

/usr/bin/ruby -e "$(curl -fsSL"

This script installs Homebrew. It will ask for confirmation that you want to install it. Follow the prompts. (Source: Homebrew)

Installing node.js and npm

Once Homebrew is installed, installing node.js is fairly simple. In Terminal, hit enter after typing/pasting (Source: George Ornbo):

brew install node

Installing Parker

Installing Parker at this point should be fairly simple. In Terminal, hit enter after typing/pasting:

npm install -g parker

The “-g” installs Parker globally, so you can access it from anywhere in your system (rather than just inside a specific project or folder). (Source: Harry Roberts)

Copy _s

Lastly, we’ll need a copy of _s. Open Finder and decide where you want to save _s. This can be any folder; I put my copy of _s in Dropbox. In Terminal type/paste:


Be sure to leave a space at the end! Drag your work folder from Finder to Terminal. This puts the path to your work folder into Terminal. Hit enter and your working directory in Terminal changes to your work folder. Use git to clone the _s repo from Github and work with it on your computer. In Terminal, hit enter after typing/pasting:

git clone

Wrapping Up

In the next post, we’ll use Parker to create a baseline measurement so we can see if any of our optimizations are effective. I’ll also explain what each  result in the report from Parker means.

Parker and WordPress Theme Development

Lately, I’ve been playing with a CSS analysis tool called Parker created by Katie Fenn. Parker examines your stylesheet and gives a treasure trove of metrics. While some of these metrics are merely interesting factoids (like the number of CSS rules), others offer constructive criticism for improvement. The general philosophy is to create more maintainable CSS by simplifying your stylesheet.

Harry Roberts, of, has an excellent write-up about using Parker. He explains some of the options and offers some ideal scores to shoot for, which I’ll list and explain in later posts. WordPress developers will need additional code to change the WordPress-generated code, like in menus.

In the following posts, I’m going to use Parker to test my fork of the _s starter theme and made optimize it based on the results. I’ve based every project over the past two years on _s and advise anyone learning theme development to start there. This post will serve as a sort of table of contents; I’ll link to each post as they are published.

Why Use Parker?

As I mentioned above, Parker is good for reducing the size and complexity of your stylesheet. While that’s not a big concern for small projects, for larger projects, this can be a lifesaver. Maybe other developers come along and start adding new features, new CSS methods (floats vs flexbox vs grid) or using different methods (BEM vs Atomic vs random…) and your stylesheet gets more and more complex.

Ideally, the newer developer(s) would check the stylesheet for existing styles that accomplish what they want. Since this doesn’t happen many times, Parker can at least tell them whether their code and existing code can be simpler.

Posts in This Series

ArtistDataPress Expiration

In case you haven’t heard, ArtistData is shutting down. Since AritstDataPress merely re-displays the feed from ArtistData, the plugin will also be shutting down. The final date is October 14.

I recommend checking out either BandsInTown or GigPress. BandsInTown covers the online service bit; GigPress keeps everything on your site. I’ve seen good results from both, so you can’t lose.

How to Add a Select Menu of Formidable Forms in Customizer

I recently had a need to list all the published Formidable forms as a select control in Customizer. Formidable doesn’t spell out how to get this list, but I eventually stumbled on this method.

$forms = FrmForm::get_published_forms();
$choices = array();
foreach ( $forms as $form ) {
$choices[$form->id] = $form->name;
// Formidable Forms Select Field
'capability' => 'edit_theme_options',
'default' => '',
'transport' => 'postMessage',
'type' => 'theme_mod'
'active_callback' => '',
'choices' => $choices,
'description' => esc_html__( '', 'text-domain' ),
'label' => esc_html__( 'Formidable Forms Select', 'text-domain' ),
'priority' => 10,
'section' => 'your-section',
'settings' => 'formidable_form_select',
'type' => 'select'
$wp_customize->get_setting( 'formidable_form_select' )->transport = 'postMessage';

Brief explanation

Use the get_published_forms() static function in the FrmForm class from Formidable to get an array of public form objects.

Loop through them and add each to the $choices array, which is used for the choices in the Customizer select control.

This control will return the form ID. You could tweak this to use the form key or any other data from the form object.

How to Link to the Customizer

I recently needed to link to a custom panel in the Customizer and had to figure it out. Devin Price pointed me in the right direction, but I ended up looking in the WordPress core to see how they do it and this is how.

This a simple link to Customizer:

<a href="<?php echo esc_url( admin_url( 'customize.php' ) ); ?>">Link to Customizer</a>

Linking to Panels, Sections, and Controls in the Customizer

If you want to link to a specific panel in the Customizer, you’ll want to use this:

$query['autofocus[panel]'] = 'nav_menus';
 $panel_link = add_query_arg( $query, admin_url( 'customize.php' ) );
 ?><a href="<?php echo esc_url( $panel_link ); ?>">Link to Panel</a>

If you aren’t familiar with add_query_args, its worth reading up on it. I learned about it from Fränk Klein for how to properly add Google Fonts to WordPress. Pippin Williamson also has a good post about write-up about using add_query_args too. We’ll see later how you can use it to create more advanced links into the Customizer.

One warning: always specify the URL parameter and always escape the output. The core developers discussed this issue in April of 2015. If you don’t specify the URL and don’t escape the output of this function, then someone might be able to use it as a XSS attack vector. If you’ll notice, I’m including the esc_url() function in the output of each of the examples above and the URL parameter is specified too.

In the $query array, the key is tells the Customizer what to do, then the value tells it where we’re going. The this example: autofocus in a panel called “nav_menus”. You can change the value to the panel of your choice. Here’s a list of the default panels included in WordPress (as of version 4.5.2):

  • widgets = Widget panel
  • nav_menus = Menus panel

If you want to link to a section instead, you can change part of the key:

$query['autofocus[section]'] = 'title_tagline';
 $section_link = add_query_arg( $query, admin_url( 'customize.php' ) );
 ?><a href="<?php echo esc_url( $section_link ); ?>">Link to Section</a>

Here are the IDs for the default sections in WordPress:

  • static_front_page = Static Front Page section
  • title_tagline = Site Identity section

Some of the default themes like Twenty Sixteen add their own sections and any theme can add the following sections by declaring theme support for them:

  • background_image = Background Image section
  • header_image = Header Image section

The real magic is linking to the customizer and autofocusing on a specific field (aka control):

$query['autofocus[control]'] = 'blogname';
 $control_link = add_query_arg( $query, admin_url( 'customize.php' ) );
 ?><a href="<?php echo esc_url( $control_link ); ?>">Link to Control</a>

This links to the Site Title field in the Site Identity section. If you’re asking people to go to a specific place and make an edit, go ahead and link this way to make it easier.

After the Customizer

In addition to linking to somewhere within the Customizer, you can also specify where to go after you exit. Core uses the page you’re currently on by default. You can check the link to the Customizer from different places in the admin and see that return value changes.

$query['return'] = admin_url();
 $link_with_return = add_query_arg( $query, admin_url( 'customize.php' ) );

That will link to the Customizer and return you to the Dashboard.

FYI, you cannot specify any old URL to go to afterwards. For instance, this does not work:

$query['return'] = '';
 $link = add_query_arg( $query, admin_url( 'customize.php' ) );
 ?><a href="<?php echo esc_url( $link ); ?>">Go to CNN after</a>

The Customizer runs these return URLs through the function wp_validate_redirect(). By default, the only allowed URL is the home_url(). Additional URLs can be added using the allowed_redirect_hosts() filter. The wp_validate_redirect() function is used for many parts of WordPress, so I’d advise caution when adding URLs to this allowed list.

Now, we can build more specific URLs for the Customizer. This could be especially useful if you’re walking a site admin through performing several steps:

$query['autofocus[control]'] = 'blogname';
 $query['return'] = admin_url( 'post-new.php' );
 $link = add_query_arg( $query, admin_url( 'customize.php' ) );
 ?><a href="<?php echo esc_url( $link ); ?>">Set title, then write post</a>

This links into the Customizer, autofocuses on the Site Title field, then once you’re done, takes you to the new post page.

Set the Preview Page

If you have Customizer controls that only apply to specific pages, you can specify which page appears in the previewer:

$query['url'] = site_url( '/news' );
 $link = add_query_arg( $query, admin_url( 'customize.php' ) );
 ?><a href="<?php echo esc_url( $link ); ?>">News Page in Preview</a>

In this case, the Previewer will display the News page instead of the home page. I’m planning to do additional testing to see if this could be used to style a plugin-specific page.

All Together Now!

Those are all the parameters currently available for the Customizer. Now you can get really crazy (and specific) about your links to the Customizer. For example, go to the Menu Locations, show the About page in the previewer, then when you’re done, add a new page:

$query['autofocus[section]'] = 'menu_locations';
 $query['return'] = admin_url( 'post-new.php?post_type=page' );
 $query['url'] = site_url( '/about-us' );
 $link = add_query_arg( $query, admin_url( 'customize.php' ) );
 ?><a href="<?php echo esc_url( $link ); ?>">Craziness!</a>

To wrap up, there are three parameters you can use to link into the customizer: return, url, and autofocus. Use add_query_arg to build the URL and esc_url to display it. You can use the autofocus parameter to focus on a panel, a section, or a specific field. You can use the url parameter to display a specific page in the Previewer. You can use the return parameter to go to a particular place after going to the Customizer. Happy linking!

Here’s a gist of all the code, if you prefer that.

How to Change the Featured Image Labels

When creating a site for a client or creating a plugin, I’ve found its helpful to customize things as much as possible to the intended usage. This is especially important for client work since most clients have an internal language, or terminology they use for things. In the case of Featured Images, the site or plugin might be using the featured image differently than how one might use it on a news or blog post.

I’m currently writing a plugin with a custom post type and using the featured image as a headshot for an employee. While “featured image” may work fine, “headshot” is more specific and makes more sense in this context. I haven’t been able to find anything recent about how to change the labels on the existing Featured Image metabox. The most commonly referenced code only works some of the time. Specifically, when one removes a featured image, the label for the link changes back to referencing “featured image” instead of the customized label.

I dug through the core and found the post_type_labels_{$post_type} filter, which was added in version 3.5. This filter makes customizing the featured image labels super easy:

* Changes strings referencing Featured Images for a post type
* In this example, the post type in the filter name is "employee"
* and the new reference in the labels is "headshot".
* @see
* @param object $labels Current post type labels
* @return object Modified post type labels
function change_featured_image_labels( $labels ) {
$labels->featured_image = 'Headshot';
$labels->set_featured_image = 'Set headshot';
$labels->remove_featured_image = 'Remove headshot';
$labels->use_featured_image = 'Use as headshot';
return $labels;
} // change_featured_image_labels()
add_filter( 'post_type_labels_employee', 'change_featured_image_labels', 10, 1 );
view raw gistfile1.txt hosted with ❤ by GitHub

The labels are in an object and we then reset the values of each specific item to what we want. Then return the object.

Avoiding get_theme_mod Errors

If you’re getting an error related to get_theme_mod, its most likely from how you’re checking if the returned result is empty. Most developers will probably do the same thing I did: make a variable and assign it to the result of get_theme_mod. Then check if its empty using PHP’s empty() method. Sadly, this is where you’re getting an error. Instead, check if the result is equal to ”, or blank.

* Do this
if ( '' == get_theme_mod( 'something' ) ) { ... }
* Not this
if ( empty( get_theme_mod( 'something' ) ) ) { ... }