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' );

Helpful LESS mixin to convert hex value to rgba

Recently I was trying to come up with a way to assign a LESS color variable to an element’s background and give it some transparency (WITHOUT using opacity). The rgba function seemed to be the wisest choice, but I had a bunch of hex colors defined in my LESS sheet, not rgba values. Luckily, I was able to come up with a useful mixin to convert my hex colors into rgba so I could assign an alpha level to them.

.bg-transparent(@color, @alpha: 1) {
  background: rgba( red(@color), green(@color), blue(@color), @alpha);
}

Example

.rule-1 {
  .bg-transparent(#0b3307, .5);
}

will output the following after being compiled by LESS:

.rule-1 {
  background: rgba(11,51,7,0.5);
}

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.

MAMP: Working around phpMyAdmin’s MySQL file size limit when importing a database

Working locally has many advantages. I try to stay away from developing on a production server whenever possible for a number of reasons. The major reason is that I don’t want to make a mistake that can corrupt my data or bring the server down.

I’m currently working on a project that involves calling data from a large database (> 100MB) using some old PHP code a previous developer wrote. I *could* just tinker with it on production but I don’t think that’s a good idea. So I decided to export the database from the production server and then tried bringing it into phpMyAdmin so I could work locally. I kept getting a very ambiguous error saying:

You probably tried to upload too large file. Please refer to documentation for ways to workaround this limit.

Error messages that use the word “probably” kind of irk me, but that’s another post. The documentation was no help either, I tried all the things they recommended but still no luck. I could use a tool they recommended to use in order to split the file up but the disclaimer on the site saying “We are not responsible for lost data” made me not want to use it. It dawned on me that there had to be a way to import this via the command line, and indeed there was. Why didn’t I think of that first.

First create the database you want to import the data to. Either in phpMyAdmin or in the terminal.

To import your abnormally large DB, type this in a terminal:

/Applications/MAMP/Library/bin/mysql --host=localhost -uroot -proot dbname < /path/to/database/you/want/to/import.sql

Obviously if you have a different username, password and database name, change the appropriate parameters. If it is a really large file it may take a while but viola! No more being at the whim of phpMyAdmin, you just took matters into your own hands.

Simple Sticky Footer Using jQuery

I was recently working on a project that required a sticky footer. I needed the footer to always be aligned flush with the bottom of the screen. This was no problem when there was enough content to push the footer against the bottom edge. But what happens when there isn’t enough content? You end up with a floating footer and that’s no fun.

I immediately Googled the problem and found a bunch of various jQuery and CSS solutions. When I tried them though, none of them seemed to do exactly what I wanted them to do. Plus my code was structured a little differently than the examples. I decided to just try to come up with my own solution using jQuery. I’ve had enough of dealing with IE’s quirks, IE understands JQuery so it seemed like the easiest solution.

In order for this to work, the footer can’t be in a wrapper class. The code would have to be structured like this example:

<div id="page"></div>
<footer id="colophon"></footer>

Also, it is required that you set margin and padding for body to 0. These are the only requirements as far as I know of that have to do with CSS.

body {
    margin: 0;
    padding: 0;
    }

The idea behind the jQuery was pretty simple. Check the height of the element, then check the height of the viewport. If the viewport height is greater than #page’s height, then we need to set some CSS on the footer. That CSS will just absolutely position it at the bottom of the frame. It’s a good idea to make sure your footer’s width is 100% so it looks right.

I brought in jQuery and inserted the code.

<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script><script type="text/javascript">
$(document).ready(function() {
  var bodyHeight = $("body").height();
  var vwptHeight = $(window).height();
  if (vwptHeight > bodyHeight) {
    $("footer#colophon").css("position","absolute").css("bottom",0);
  }
});
</script>

In order to make this work with older versions of IE (< IE9), include Google's HTML5 shiv. [html] <!-- Add conditional for IE7 + 8 support --> <!--[if lte IE 8]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> [/html]

See the demo

Worked like a charm for my purposes. Feel free to modify it for your own use. If you have any questions or comments, feel free to leave a comment! 🙂