Adding a select box with categories into WordPress’ theme customizer

WP_themecusto

Note: for some awesome examples written by the WP team, check out their Github page with some great examples.

No more option pages

The WordPress theme customizer is the coolest thing since sliced bread. Maybe now, we as developers can all get on the same page when making WordPress themes. I’ve been playing with the theme customizer API and I think the days of theme options are numbered. I mean, do we really need pages and pages of theme options? I guess I can see it for overly complex WordPress as a giant CMS project. But the average blogger only needs a few powerful options.

If you’re starting a theme from scratch, I highly recommend working with Underscores, the starter theme from Automattic. This article assumes you’re using it. If you’re not, it still may work, you may just need to make some adjustments.

Keeping it modular

I wouldn’t recommend polluting your functions.php file with all this customizer code. If you’re using Underscores, they already scaffold out inc/customizer.php, then import it into function.php, which is super convenient.

If you didn’t know, there’s 3 parts to using WordPress’ theme customizer. You need a section, a control and a setting. I’ll explain more as we go.

Go into inc/customizer.php and lets make a section. Add this within the themename_customize_register( $wp_customize ) function

$wp_customize->add_section('mytheme_options', array(
  'title'    => __('Front Page Categories', 'themename'),
  'priority' => 120,
));

This creates a section for our control to live in. The control is literally the thing that you’ll be clicking on and selecting your category. So lets add the control to the section we just made:

$wp_customize->add_control( 'cat_1', array(
  'settings' => 'cat_1',
  'label'    => 'Left Box',
  'section'  => 'mytheme_options',
  'type'     => 'select',
  'choices'  => get_categories_select()
));

To do this correctly, in my opinion, we want 'choices' to take associative array in this form:

array (
  'slug' => 'Category Name'
)

If we do it like this we can use the ‘slug’ for the WP_Query (and to lookup anything else we want about the category) and ‘Category Name’ for what is displayed to the user. So here’s the function I referenced above called get_categories_select()

function get_categories_select() {
  $teh_cats = get_categories();
  $results;

  $count = count($teh_cats);
  for ($i=0; $i < $count; $i++) {
    if (isset($teh_cats[$i]))
      $results[$teh_cats[$i]->slug] = $teh_cats[$i]->name;
    else
      $count++;
  }
  return $results;
}

Awesome, now we need to create a place to store this setting. Thus, we should create the last part of the theme customizer’s holy trinity, the setting. This is what lets you retrieve the data you entered into the control.

$wp_customize->add_setting('cat_1', array(
  'default'        => 'uncategorized',
  'capability'     => 'edit_theme_options',
));

Using this method, after we save something within the theme customizer, we can access it using get_theme_mod('cat_1');. In my front-page.php, here’s how I’m grabbing these customizations that you see in my example.

<?php
  $args = array(
    'category_name' => get_theme_mod('cat_1'),
    'posts_per_page' => 5
  );

  // Displays the category's name
  echo "<h3>" . get_category_by_slug($args['category_name'])->name . </h3>;
  $the_query = new WP_Query( $args );

  // The Loop
  if ( $the_query->have_posts() ) :
    echo "<ul>";
    while ( $the_query->have_posts() ) : $the_query->the_post();
      $link = get_permalink();
      $title = get_the_title();
      echo '<li><a href="' . $link . '">'  . $title . '</a></li>';
    endwhile;
    echo "</ul>";
  endif;

  // Reset Post Data
  wp_reset_postdata();

?>

There you have it, that’s how I did it! For your reference, here’s my full customizer.php

<?php

function get_categories_select() {
 $teh_cats = get_categories();
    $results;
    $count = count($teh_cats);
    for ($i=0; $i < $count; $i++) {
      if (isset($teh_cats[$i]))
        $results[$teh_cats[$i]->slug] = $teh_cats[$i]->name;
      else
        $count++;
    }
  return $results;
}

/**
 * Add postMessage support for site title and description for the Theme Customizer.
 *
 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
 */
function basic_bootstrap_customize_register( $wp_customize ) {
  $wp_customize->get_setting( 'blogname' )->transport         = 'postMessage';
  $wp_customize->get_setting( 'blogdescription' )->transport  = 'postMessage';
  $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';

  $wp_customize->add_section('mytheme_options', array(
    'title'    => __('Front Page Categories', 'basicbs'),
    'priority' => 120,
  ));

  $wp_customize->add_setting('cat_1', array(
    'default'        => 'uncategorized',
    'capability'     => 'edit_theme_options',
  ));
  $wp_customize->add_control( 'cat_1', array(
    'settings' => 'cat_1',
    'label'   => 'Left Box',
    'section' => 'mytheme_options',
    'type'    => 'select',
    'choices' => get_categories_select()
  ));

  $wp_customize->add_setting('cat_2', array(
    'default'        => 'uncategorized',
    'capability'     => 'edit_theme_options',
  ));
  $wp_customize->add_control( 'cat_2', array(
    'settings' => 'cat_2',
    'label'   => 'Center Box',
    'section' => 'mytheme_options',
    'type'    => 'select',
    'choices' => get_categories_select()
  ));

  $wp_customize->add_setting('cat_3', array(
    'default'        => 'uncategorized',
    'capability'     => 'edit_theme_options',
  ));
  $wp_customize->add_control( 'cat_3', array(
    'settings' => 'cat_3',
    'label'   => 'Right Box',
    'section' => 'mytheme_options',
    'type'    => 'select',
    'choices' => get_categories_select()
  ));

}
add_action( 'customize_register', 'basic_bootstrap_customize_register' );

/**
 * Binds JS handlers to make Theme Customizer preview reload changes asynchronously.
 */
function basic_bootstrap_customize_preview_js() {
  wp_enqueue_script( 'basic_bootstrap_customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), '20130508', true );
}
add_action( 'customize_preview_init', 'basic_bootstrap_customize_preview_js' );

WordPress Development Workflow Tips

Wordpress logoWordPress is becoming increasingly popular amongst web developers. If you’re new to developing with WordPress, here are some quick tips that could save you a little bit of time.

Get Version Controlled

If you’re not comfortable with git yet, I highly recommend you get up and running with it. There are tons of great tutorials out there. The one I used can be found here. It’s a 70 min video but is very good at explaining how git works.

What files should I version control?
Here is a gist I yanked from github that is everything you need to know about version controlling WordPress.

*.log
.htaccess
sitemap.xml
sitemap.xml.gz
wp-config.php
wp-content/advanced-cache.php
wp-content/backup-db/
wp-content/backups/
wp-content/blogs.dir/
wp-content/cache/
wp-content/upgrade/
wp-content/uploads/
wp-content/wp-cache-config.php

Source: https://github.com/github/gitignore/blob/master/WordPress.gitignore

If you find a different/better WordPress .gitignore, let me know in the comments.

This gist has saved me a lot of time of fiddling with different .gitignore configurations.

Work Locally

XAMPP or MAMP both work great. Or if you want to use OS X’s built in apache, that’s fine too. Whatever allows you to run apache, MySQL, and PHP will work.

I use MAMP when I’m at work on a Mac and XAMPP when I’m home on a PC. They both achieve the same goal. I can work locally on my WordPress site. I can tinker with PHP and test without worrying about bringing down my production server or bogging it down.

Local configuration vs. production configuration
Now, chances are, the settings within your wp-config.php file will be different on your local server than your production server. There are multiple ways to handle this.

The way I use was posted by Mark Jaquith on his blog. It’s a clever way of dealing with the local vs production dilemma that all WordPress devs have encountered at least once.

Another quite good reference point on the matter is this article, which takes into account version control as well.

Use Node.js & Grunt

If you want to completely supercharge your WordPress workflow, look into using Node.js and Grunt to run repetitive tasks. I might write my own article on this eventually, but until then I would highly recommend looking at an article by Matt Banks about WordPress development and deployment with Grunt.

Making wp_nav_menu work with Bootstrap 3 navbar

Notice! This only works with single level navigation. If your nav needs a dropdown, follow this tutorial which uses a custom nav walker. If you’re using a single level nav, this will do the trick.


I’m currently re-designing my homepage functionally and aesthetically and I wanted to use the Bootstrap 3 navbar on the re-design. After wrestling with the code for a little bit, I finally got it to work.

The following is in header.php

Leave any questions in the comments below.