* I encourage all theme developers who use this feature to use it wisely. At some point, enough is * enough. This is not meant to be a full CSS-replacement script. It wasn't created so that all * themes could have a buttload of color options. Use some common sense when applying this script * and have fun with your designs. A script like this can be limiting to your abilities as a * designer. You don't have to cave to user demands to add more options. Make decisions and have * some faith in your own skills. You are a theme *designer*, right?. * * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * @package ColorPalette * @version 0.2.0-alpha * @author Justin Tadlock * @copyright Copyright (c) 2013, Justin Tadlock * @link http://justintadlock.com * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ /** * Handles custom theme color options via the WordPress theme customizer. * * @since 0.1.0 * @access public */ final class Color_Palette { /** * Theme-supports arguments passed by the theme. * * @since 0.2.0 * @access public * @var array */ public $supports = array(); /** * Array of individual color options and their settings. * * @since 0.1.0 * @access public * @var array */ public $colors = array(); /** * An array of properties and selectors. "$rules[ $color_id ][ $property ][ $selectors ]" * * @since 0.1.0 * @access public * @var array */ public $rules = array(); /** * The allowed CSS properties the theme developer can set a color rule for. * * @since 0.1.0 * @access public */ public $allowed_properties = array( 'color', 'background-color', 'border-color', 'border-top-color', 'border-bottom-color', 'border-right-color', 'border-left-color', 'outline-color' ); /** * Sets up the Custom Colors Palette feature. * * @since 0.1.0 * @access public * @return void */ public function __construct() { /* Get the theme support arguements for 'color-palette'. */ $this->supports = get_theme_support( 'color-palette' ); /* If a callback was set, add it to the correct action hook. */ if ( !empty( $this->supports[0] ) && isset( $this->supports[0]['callback'] ) ) add_action( 'color_palette_register', $this->supports[0]['callback'] ); /* If a wp-head-callback was set, add it to the correct action hook. */ if ( !empty( $this->supports[0] ) && isset( $this->supports[0]['wp-head-callback'] ) ) add_action( 'color_palette_wp_head_callback', $this->supports[0]['wp-head-callback'] ); /* Output CSS into . */ add_action( 'wp_head', array( &$this, 'wp_head_callback' ) ); /* Add a '.custom-colors' class. */ add_filter( 'body_class', array( &$this, 'body_class' ) ); /* Add options to the theme customizer. */ add_action( 'customize_register', array( &$this, 'customize_register' ) ); /* Delete the cached data for this feature. */ add_action( 'update_option_theme_mods_' . get_stylesheet(), array( &$this, 'cache_delete' ) ); /* Hook for registering custom colors and rule sets. */ do_action( 'color_palette_register', $this ); } /** * Add a color option. * * @since 0.1.0 * @access public * @param array $args * @return void */ public function add_color( $args ) { if ( !isset( $args['id'] ) ) return; $args['default'] = isset( $args['default'] ) ? $this->sanitize_hex_color( $args['default'] ) : ''; $this->colors[ $args['id'] ] = $args; } /** * Get a color option. * * @since 0.1.0 * @access public * @param string $id * @return array|string */ public function get_color( $id ) { return isset( $this->colors[ $id ] ) ? $this->colors[ $id ] : ''; } /** * Add a complete rule set for a specific theme color. The color must already be registered. * * @since 0.1.0 * @access public * @param string $color_id * @param array $rules * @return void */ public function add_rule_set( $color_id, $rules ) { $color = $this->get_color( $color_id ); if ( empty( $color ) ) return; foreach ( $rules as $property => $selectors ) { if ( in_array( $property, $this->allowed_properties ) ) { if ( !is_array( $selectors ) ) $selectors = array_map( 'trim', explode( ',', $selectors ) ); $this->rules[ $color_id ][ $property ] = $selectors; } } } /** * Adds the 'custom-colors' class to the element. * * @since 0.1.0 * @access public * @param array $classes * @return array */ public function body_class( $classes ) { $classes[] = 'custom-colors'; return $classes; } /** * Callback for 'wp_head' that outputs the CSS for this feature. * * @since 0.1.0 * @access public * @return void */ public function wp_head_callback() { /* Allow devs to hook in early. This is used for the `wp-head-callback`. */ do_action( 'color_palette_wp_head_callback', $this ); /* If a `wp-head-callback` was set, bail. */ if ( !empty( $this->supports[0] ) && isset( $this->supports[0]['wp-head-callback'] ) ) return; /* Get the cached style. */ $style = wp_cache_get( 'color_palette' ); /* If the style is available, output it and return. */ if ( !empty( $style ) ) { echo $style; return; } /* Loop through each of the rules by name. */ foreach ( $this->rules as $color_id => $properties ) { $color = $this->get_color( $color_id ); /* Get the saved color. */ $hex = get_theme_mod( 'color_palette_' . sanitize_key( $color_id ), $color['default'] ); /* Loop through each of the properties. */ foreach ( $properties as $property => $selectors ) $style .= join( ', ', $selectors ) . " { {$property}: #{$hex}; } "; } /* Put the final style output together. */ $style = "\n" . '' . "\n"; /* Cache the style, so we don't have to process this on each page load. */ wp_cache_set( 'color_palette', $style ); /* Output the custom style. */ echo $style; } /** * Registers the customize settings and controls. We're tagging along on WordPress' built-in * 'Colors' section. * * @since 0.1.0 * @access public * @param object $wp_customize * @return void */ public function customize_register( $wp_customize ) { /* Each control will be given a priority of $priority + 10. */ $priority = 0; /* Loop through each of the defined color options. */ foreach ( $this->colors as $color_id => $args ) { /* Iterate the priority. */ $priority = $priority + 10; /* Sanitize the color option name. */ $color_id = sanitize_key( $color_id ); /* Add a new setting for this color. */ $wp_customize->add_setting( "color_palette_{$color_id}", array( 'default' => "#{$args['default']}", 'type' => 'theme_mod', 'capability' => 'edit_theme_options', 'sanitize_callback' => 'sanitize_hex_color_no_hash', 'sanitize_js_callback' => 'maybe_hash_hex_color', 'transport' => 'postMessage' ) ); /* Add a control for this color. */ $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, "color-palette-control-{$color_id}", array( 'label' => esc_html( $args['label'] ), 'section' => 'colors', 'settings' => "color_palette_{$color_id}", 'priority' => $priority ) ) ); } /* If viewing the customize preview screen, add a script to show a live preview. */ if ( $wp_customize->is_preview() && !is_admin() ) add_action( 'wp_footer', array( &$this, 'customize_preview_script' ), 21 ); } /** * Theme customizer preview script. * * @since 0.1.0 * @access public * @return void */ public function customize_preview_script() { ?>