Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Custom Controls in the Theme Customizer

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

In the last article, we explored the advanced controls available in the Theme Customizer, and how to implement them.

We’re going to look at how to create our own custom control, allowing you to choose which Category of Posts are displayed on the home page.

To get started, download version 0.6.0 of our Theme Customizer Example.

Existing Theme Customizer Controls

WordPress supplies several controls, each with their own PHP class. We explored these in the last part of our series:

  • Plain Text Input: WP_Customize_Control
  • Color Picker: WP_Customize_Color_Control
  • File Upload: WP_Customize_Upload_Control
  • Image: WP_Customize_Image_Control
  • Background Image: WP_Customize_Background_Image_Control
  • Header Image: WP_Header_Image_Control

Apart from the Plain Text Input, all Customizer Controls extend the WP_Customize_Control class.

Extending WP_Customize_Control

Each Customizer Control will define some or all of its own class functions to override those supplied by WP_Customize_Control.

For example, WP_Customize_Control contains the following function to output HTML used in the Theme Customizer:

protected function render_content() {
	switch( $this->type ) {
		case 'text':
			?>
			<label>
				<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
				<input type="text" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); ?> />
			</label>
			<?php
			break;
		case 'checkbox':
			?>
			<label>
				<input type="checkbox" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); checked( $this->value() ); ?> />
				<?php echo esc_html( $this->label ); ?>
			</label>
			<?php
			break;
		case 'radio':
			if ( empty( $this->choices ) )
				return;

			$name = '_customize-radio-' . $this->id;

			?>
			<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
			<?php
			foreach ( $this->choices as $value => $label ) :
				?>
				<label>
					<input type="radio" value="<?php echo esc_attr( $value ); ?>" name="<?php echo esc_attr( $name ); ?>" <?php $this->link(); checked( $this->value(), $value ); ?> />
					<?php echo esc_html( $label ); ?><br/>
				</label>
				<?php
			endforeach;
			break;
		case 'select':
			if ( empty( $this->choices ) )
				return;

			?>
			<label>
				<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
				<select <?php $this->link(); ?>>
					<?php
					foreach ( $this->choices as $value => $label )
						echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
					?>
				</select>
			</label>
			<?php
			break;
		case 'dropdown-pages':
			$dropdown = wp_dropdown_pages(
				array(
					'name'              => '_customize-dropdown-pages-' . $this->id,
					'echo'              => 0,
					'show_option_none'  => __( '&mdash; Select &mdash;' ),
					'option_none_value' => '0',
					'selected'          => $this->value(),
				)
			);

			// Hackily add in the data link parameter.
			$dropdown = str_replace( '<select', '<select ' . $this->get_link(), $dropdown );

			printf(
				'<label class="customize-control-select"><span class="customize-control-title">%s</span> %s</label>',
				$this->label,
				$dropdown
			);
			break;
	}
}

The function detects the $type defined to determine what to output (a plain text input, a checkbox, a radio button, a select dropdown or a dropdown of WordPress Pages).

However, none of the aboves types are useful for WP_Customize_Color_Control, which needs to render a color picker. Because all Customizer Controls extend WP_Customize_Control, the color control can override the above function with its own output:

public function render_content() {
	$this_default = $this->setting->default;
	$default_attr = '';
	if ( $this_default ) {
		if ( false === strpos( $this_default, '#' ) )
			$this_default = '#' . $this_default;
		$default_attr = ' data-default-color="' . esc_attr( $this_default ) . '"';
	}
	// The input's value gets set by JS. Don't fill it.
	?>
	<label>
		<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
		<div class="customize-control-content">
			<input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php esc_attr_e( 'Hex Value' ); ?>"<?php echo $default_attr; ?> />
		</div>
	</label>
	<?php
}

This is an important concept, which we will now apply when creating our custom control.

Creating a Category Control

At the bottom of functions.php, add the following block of code:

if (class_exists('WP_Customize_Control')) {
	class WP_Customize_Category_Control extends WP_Customize_Control {
		/**
		 * Render the control's content.
		 *
		 * @since 3.4.0
		 */
		public function render_content() {
			$dropdown = wp_dropdown_categories(
				array(
					'name'              => '_customize-dropdown-categories-' . $this->id,
					'echo'              => 0,
					'show_option_none'  => __( '&mdash; Select &mdash;' ),
					'option_none_value' => '0',
					'selected'          => $this->value(),
				)
			);

			// Hackily add in the data link parameter.
			$dropdown = str_replace( '<select', '<select ' . $this->get_link(), $dropdown );

			printf(
				'<label class="customize-control-select"><span class="customize-control-title">%s</span> %s</label>',
				$this->label,
				$dropdown
			);
		}
	}
}

This creates a new Theme Customizer Control called WP_Customize_Category_Control, defining its own render_content() function to override the default render_content() function from WP_Customize_Control.

We initially check if the WP_Customize_Control class exists, as otherwise we’d receive the following error on non-Theme Customizer screens:

Theme Customizer Error

Let’s go through this function to understand what it’s doing.

$dropdown = wp_dropdown_categories(
	array(
		'name'              => '_customize-dropdown-categories-' . $this->id,
		'echo'              => 0,
		'show_option_none'  => __( '&mdash; Select &mdash;' ),
		'option_none_value' => '0',
		'selected'          => $this->value(),
	)
);

We use WordPress’ wp_dropdown_categories function to generate a HTML element, listing all Post Categories that have one or more Posts assigned to them.

// Hackily add in the data link parameter.
$dropdown = str_replace( '<select', '<select ' . $this->get_link(), $dropdown );

Next, we add in a data-link parameter to the HTML element. This is specific to the Theme Customizer and important because it tells the Theme Customizer that a change has been made, enabling the Save & Publish button to work.

printf(
	'<label class="customize-control-select"><span class="customize-control-title">%s</span> %s</label>',
	$this->label,
	$dropdown
);

Finally, we output the select dropdown within a label.

Implementing the Category Control

As with any Theme Customizer control, we need to implement it, so it will display within the Theme Customizer.

Add the following code to the end of the tcx_register_theme_customizer() function, to add a new section to the Theme Customizer:

/*-----------------------------------------------------------*
 * Defining our own 'Category' section
 *-----------------------------------------------------------*/
$wp_customize->add_section(
	'tcx_category',
	array(
		'title'     => 'Category',
		'priority'  => 202
	)
);

Next, add the following code right after the code we defined above:

/* Category */
$wp_customize->add_setting(
	'tcx_category'
);

Finally, let’s add our new WP_Customize_Category_Control, binding it to the setting and section above:

$wp_customize->add_control(
	new WP_Customize_Category_Control(
		$wp_customize,
		'tcx_category',
		array(
		    'label'    => 'Category',
		    'settings' => 'tcx_category',
		    'section'  => 'tcx_category'
		)
	)
);

Save your functions.php file, and view your Theme Customizer. You should see a new Category section, with a dropdown box labelled Category:

Theme Customizer: Category Dropdown

Choose a category from the dropdown list, and click Save & Publish.

Reading the Category Setting

Right now, the above code doesn’t change the display of our theme. Let’s add some code to index.php, under get_header(), to display a list of Posts:

<div id="posts">
	<?php
	// The loop
	if (have_posts()) {
		while (have_posts()) {
			the_post();

			the_title();
			the_excerpt();
			the_category();
			echo '<hr />';
		} // while
	} // if
	?>
</div>

Make sure you have some Posts assigned to a Category. You’ll then see something like this:

Theme Customizer: Posts Loop

If you’ve followed our other tutorials in this series, you’ll know that we can use get_theme_mod() to get the setting value for a specific Theme Customizer setting.

Modify the above code to read the value of our Category drop down, so we only display Posts assigned to the chosen Category:

<div id="posts">
	<?php
	// Get category ID from Theme Customizer
	$catID = get_theme_mod('tcx_category');

	// Only get Posts that are assigned to the given category ID
	query_posts(array(
		'post_type' => 'post',
		'cat' => $catID,
	));

	// The loop
	if (have_posts()) {
		while (have_posts()) {
			the_post();

			the_title();
			the_excerpt();
			the_category();
			echo '<hr />';
		} // while
	} // if
	?>
</div>

If no category has been chosen in the Theme Customizer, all Posts will display, regardless of category.

If a category has been chosen, only Posts assigned to that Category will display.

In our example, I’ve chosen ‘News’ as the Category to display:

Theme Customizer: Posts from News Category

Summary

The Theme Customizer is a great alternative to resource-heavy theme option panels or Plugins, and allows site owners to see, in real time, how various settings change the behaviour and style of their WordPress web site.

We've explained the default and custom controls that are available, as well as how a custom control can extend the default Theme Customizer class.

This tutorial has also covered some of the more advanced aspects of using the Theme Customizer, by extending it and allowing you to customize which category of Posts to display on your home page.

Advertisement