Last year I talked about how I made icons for my taxonomy terms. When you have a limited number of terms, that makes sense. When you have a taxonomy with the potential for a high volume of terms, like nations (192), or worse an unlimited number of terms, this approach looses its value.

Instead, I realized what I needed for a particular project was a custom icon for each taxonomy. Not the term.

I split this up into two files because I used a slightly different setup for my settings API, but the tl;dr of all this is I made a settings page under themes called “Taxonomy Icons” which loads all the public, non-default taxonomies and associates them with an icon.

For this to work for you, you will need to have your images in a folder and define that as your IMAGE_PATH in the code below. Also mine is using .svg files, so change that if you’re not.

File 1: taxonomy-icons.php

The one gotcha with this is I usually set my default values with $this->plugin_vars = array(); in the __construct function. You can’t do that with custom taxonomies, as they don’t exist yet.

class TaxonomyIcons {

	private $settings;
	const SETTINGS_KEY = 'taxicons_settings';
	const IMAGE_PATH   = '/path/to/your/images/';

	/*
	 * Construct
	 *
	 * Actions to happen immediately
	 */
    public function __construct() {

		add_action( 'admin_menu', array( $this, 'admin_menu' ) );
		add_action( 'admin_init', array( $this, 'admin_init' ) );
		add_action( 'init', array( $this, 'init' ) );

		// Normally this array is all the default values
		// Since we can't set it here, it's a placeholder
		$this->plugin_vars = array();

		// Create the list of imagess
		$this->images_array = array();
		foreach ( glob( static::IMAGE_PATH . '*.svg' ) as $file) {
			$this->images_array[ basename($file, '.svg') ] = basename($file);
		}

		// Permissions needed to use this plugin
		$this->plugin_permission = 'edit_posts';

		// Menus and their titles
		$this->plugin_menus = array(
			'taxicons'    => array(
				'slug'         => 'taxicons',
				'submenu'      => 'themes.php',
				'display_name' => __ ( 'Taxonomy Icons', 'taxonomy-icons' ),
			),
		);
    }

	/**
	 * admin_init function.
	 *
	 * @access public
	 * @return void
	 * @since 0.1.0
	 */
	function admin_init() {
		// Since we couldn't set it in _construct, we do it here
		// Create a default (false) for all current taxonomies
		$taxonomies = get_taxonomies( array( 'public' => true, '_builtin' => false ), 'names', 'and' );
		if ( $taxonomies && empty( $this->plugin_vars ) ) {
			foreach ( $taxonomies as $taxonomy ) {
				$this->plugin_vars[$taxonomy] = false;
			}
		}
	}

	/**
	 * init function.
	 *
	 * @access public
	 * @return void
	 * @since 0.1.0
	 */
	function init() {
		add_shortcode( 'taxonomy-icon', array( $this, 'shortcode' ) );
	}

	/**
	 * Get Settings
	 *
	 * @access public
	 * @param bool $force (default: false)
	 * @return settings array
	 * @since 0.1.0
	 */
	function get_settings( $force = false) {
		if ( is_null( $this->settings ) || $force ) {
			$this->settings = get_option( static::SETTINGS_KEY, $this->plugin_vars );
		}
		return $this->settings;
	}

	/**
	 * Get individual setting
	 *
	 * @access public
	 * @param mixed $key
	 * @return key value (if available)
	 * @since 0.1.0
	 */
	function get_setting( $key ) {
		$this->get_settings();
		if ( isset( $this->settings[$key] ) ) {
			return $this->settings[$key];
		} else {
			return false;
		}
	}

	/**
	 * Set setting from array
	 *
	 * @access public
	 * @param mixed $key
	 * @param mixed $value
	 * @return void
	 * @since 0.1.0
	 */
	function set_setting( $key, $value ) {
		$this->settings[$key] = $value;
	}

	/**
	 * Save individual setting
	 *
	 * @access public
	 * @return void
	 * @since 0.1.0
	 */
	function save_settings() {
		update_option( static::SETTINGS_KEY, $this->settings );
	}

	/**
	 * admin_menu function.
	 *
	 * @access public
	 * @return void
	 * @since 0.1.0
	 */
	function admin_menu() {

		foreach ( $this->plugin_menus as $menu ) {
			$hook_suffixes[ $menu['slug'] ] = add_submenu_page(
				$menu['submenu'],
				$menu['display_name'],
				$menu['display_name'],
				$this->plugin_permission,
				$menu['slug'],
				array( $this, 'render_page' )
			);
		}

		foreach ( $hook_suffixes as $hook_suffix ) {
			add_action( 'load-' . $hook_suffix , array( $this, 'plugin_load' ) );
		}
	}

	/**
	 * Plugin Load
	 * Tells plugin to handle post requests
	 *
	 * @access public
	 * @return void
	 * @since 0.1.0
	 */
	function plugin_load() {
		$this->handle_post_request();
	}

	/**
	 * Handle Post Requests
	 *
	 * This saves our settings
	 *
	 * @access public
	 * @return void
	 * @since 0.1.0
	 */
	function handle_post_request() {
		if ( empty( $_POST['action'] ) || 'save' != $_POST['action'] || !current_user_can( 'edit_posts' ) ) return;

		if ( !wp_verify_nonce( $_POST['_wpnonce'], 'taxicons-save-settings' ) ) die( 'Cheating, eh?' );

		$this->get_settings();

		$post_vars = $this->plugin_vars;
		foreach ( $post_vars as $var => $default ) {
			if ( !isset( $_POST[$var] ) ) continue;
			$this->set_setting( $var, sanitize_text_field( $_POST[$var] ) );
		}

		$this->save_settings();
	}

	/**
	 * Render admin settings page
	 * If setup is not complete, display setup instead.
	 *
	 * @access public
	 * @return void
	 * @since 0.1.0
	 */
	function render_page() {
		// Not sure why we'd ever end up here, but just in case
		if ( empty( $_GET['page'] ) ) wp_die( 'Error, page cannot render.' );

		$screen = get_current_screen();
		$view  = $screen->id;

		$this->render_view( $view );
	}

	/**
	 * Render page view
	 *
	 * @access public
	 * @param mixed $view
	 * @param array $args ( default: array() )
	 * @return content based on the $view param
	 * @since 0.1.0
	 */
	function render_view( $view, $args = array() ) {
		extract( $args );
		include 'view-' . $view . '.php';
	}

	/**
	 * Render Taxicon
	 *
	 * This outputs the taxonomy icon associated with a specific taxonomy
	 *
	 * @access public
	 * @param mixed $taxonomy
	 * @return void
	 */
	public function render_taxicon ( $taxonomy ) {

		// BAIL: If it's empty, or the taxonomy doesn't exist
		if ( !$taxonomy || taxonomy_exists( $taxonomy ) == false ) return;

		$filename = $this->get_setting( $taxonomy );

		// BAIL: If the setting is false or otherwise empty
		if ( $filename == false || !$filename || empty( $filename ) ) return;

		$icon     = file_get_contents( static::IMAGE_PATH . $filename  . '.svg' );
		$taxicon  = '<span role="img" class="taxonomy-icon ' . $filename . '">' . $icon . '</span>';

		echo $taxicon;
	}

	/*
	 * Shortcode
	 *
	 * Generate the Taxicon via shortcode
	 *
	 * @param array $atts Attributes for the shortcode
	 *        - tax: The taxonomy
	 * @return SVG icon of awesomeness
	 */
	function shortcode( $atts ) {
		return $this->render_taxicon( $atts[ 'tax' ] );
	}

}

new TaxonomyIcons();

File 2: view-appearance_page_taxicons.php

Why that name? If you look at my render_view function, I pass the ID from get_current_screen() to it, and that means the ID is appearance_page_taxicons and that’s the page name.

<div class="wrap">

	<h1><?php _e( 'Taxonomy Icons', 'taxonomy-icons' ); ?></h1>

	<div>

		<p><?php __( 'Taxonomy Icons allows you to assign an icon to a non-default taxonomy in order to make it look damn awesome.', 'taxonomy-icons' ); ?></p>

		<p><?php __( 'By default, Taxonomy Icons don\'t display in your theme. In order to use them, you can use a shortcode or a function:' , 'taxonomy-icons' ); ?></p>

		<ul>
			<li>Shortcode: <code>[taxonomy-icon tax=TAXONOMY]</code></li>
		</ul>

		<form method="post">

		<?php
		if ( isset( $_GET['updated'] ) ) {
			?>
			<div class="notice notice-success is-dismissible"><p><?php _e( 'Settings saved.', 'taxonomy-icons' ); ?></p></div>
			<?php
		}
		?>

		<input type="hidden" name="action" value="save" />
		<?php wp_nonce_field( 'taxicons-save-settings' ) ?>

		<table class="form-table">

			<tr>
				<th scope="row"><?php _e( 'Category', 'taxonomy-icons' ); ?></th>
				<th scope="row"><?php _e( 'Current Icon', 'taxonomy-icons' ); ?></th>
				<th scope="row"><?php _e( 'Select Icon', 'taxonomy-icons' ); ?></th>
			</tr>

			<?php

			foreach ( $this->plugin_vars as $taxonomy => $value ) {
				?>
				<tr>
					<td>
						<strong><?php echo get_taxonomy( $taxonomy )->label; ?></strong>
						<br /><em><?php echo get_taxonomy( $taxonomy )->name; ?></em>
					</td>

					<td>
						<?php
						if ( $this->get_setting( $taxonomy ) && $this->get_setting( $taxonomy ) !== false ) {
							echo $this->render_taxicon( $taxonomy );
						}
						?>

					</td>

					<td>
						<select name="<?php echo $taxonomy; ?>" class="taxonomy-icon">
							<option value="">-- <?php _e( 'Select an Icon', 'taxonomy-icons' ); ?> --</option>
							<?php
							foreach ( $this->images_array as $file => $name ) {
								?><option value="<?php echo esc_attr( $file ); ?>" <?php echo $file == $this->get_setting( $taxonomy ) ? 'selected="selected"' : ''; ?>><?php echo esc_html( $name ); ?></option><?php
								};
							?>
						</select>
					</td>

				</tr><?php
			}

			?>

			<tr valign="top">
				<td colspan="3">
					<button type="submit" class="button button-primary"><?php _e( 'Save', 'taxonomy-icons' ); ?></button>
				</td>
			</tr>
		</table>
		</form>
	</div>
</div>

End Result

And in the end?

An example of Taxonomy Icons

By the way, the image has some wrong text, but that is what it looks like.

Reader Interactions

Comments

  1. … and Mika has deep knowledge about taxonomy. It was one of her strengths in Montessori. Happy Birthday Mika!!!!

%d bloggers like this: