Settings API – generating field value based on a different field?

I store my themes settings using Settings API.

If I create a new setting using add_settings_field() is it possible to create another setting that will be based on the first one?

Read More

Why? Imagine I have three settings:

main_color
lighter_color
darker_color

User opens Theme Options page and sets main_color to #444. Now I want lighter_color and darker_color to automagically change values based on main_color value (#444) so after all it looks like this:

main_color = #444
lighter_color = #777
darker_color = #111

Of course I could make 3 different settings and let user pick all the colors, but it won’t be that user-friendly and the whole theme will look messy if he sets lighter_color to something darker than main_color. etc.

Any ideas? 🙂 Maybe using a callback?

UPDATE

Starting bounty.
In short words – I have some settings stored in Settings API and I want to store their slightly modified versions somewhere else, I need full and easy access to these modified values, and they should update every time their Settings API “parents” do.

Related posts

1 comment

  1. First of all you need function to calculate lighter and darker colors.

    Once you have values in hex form a fast way is:

    1. convert hex to rgb
    2. conver rgb to hsl
    3. lighter and darker hsl (that is easy)
    4. revert lighter and darker colors from to hsl to hex (hsl > rgb > hex)

    Settings API use update_option to store data, and so a update_option_{$option} is triggered after saving.

    Assuming you are saving main color to an option called ‘main_color’ I created a class that implement this steps:

    1. hook update_option_{$option} and add_option_{$option} and run a function that:
    2. get current saved option for main color
    3. create lighter and darker (steps above)
    4. save options also for these colors

    Here the class:

    class MyColorSettingsClass {
    
      var $default_main_color;
    
      var $lighther_perc;
    
      var $darker_perc;
    
      function __construct( $default_main_color = '#444444', $lighther_perc = 33, $darker_perc = 33 ) {
          $this->default_main_color = $default_main_color;
          $this->lighther_perc = $lighther_perc;
          $this->darker_perc = $darker_perc;
          add_action('add_option_main_color', array($this, 'set_conversion'), 20, 2 );
          add_action('update_option_main_color', array($this, 'set_conversion'), 20, 2 );
          // if not exists the main color option, set colors to default
          if ( ! get_option('main_color') ) update_option('main_color', $default_main_color );
      }
    
      function set_conversion($option_name_or_old_value = '', $newvalue = null ) {
          $main = $newvalue ? : $this->default_main_color;
          $this->lighther_and_darker( $main );
      }
    
      function lighther_and_darker( $color = null ) {
          $main_hls = self::rgbToHsl( self::hexToRgb($color) );
          if ( is_array($main_hls) && count($main_hls) == 3 ) {
              $main_hls = array_values($main_hls);
              $l = floor( $main_hls[2] * 100 );
              $lighther_l = $l + round( $l * ( $this->lighther_perc / 100 ) );
              if ( $lighther_l > 100 ) $lighther_l = 100;
              $darker_l = $l - round( $l * ( $this->darker_perc / 100) ) ? : 0;
              $lighther_hls = array('h' => $main_hls[0], 's' => $main_hls[1], 'l' => round($lighther_l/100, 2) );
              $darker_hls = array('h' => $main_hls[0], 's' => $main_hls[1], 'l' => round($darker_l/100, 2) );
              $lighther = self::rgbToHex( self::hslToRgb( $lighther_hls ) );
              $darker = self::rgbToHex( self::hslToRgb( $darker_hls ) );
              update_option('lighter_color', $lighther);
              update_option('darker_color', $darker);
          }
      }
    
      static function hexToRgb( $hex = '000000') {
        if ( empty($hex) || ! is_string($hex) ) return;
        // strip '#' if present
        $hex = str_replace('#', '', $hex);  
        // accept only hexadecimal strings in 3 and 6 digit format
        if ( ( strlen($hex) != 3 && strlen($hex) != 6 ) || ! ctype_xdigit ( $hex ) ) return;    
        if ( strlen($hex) == 3) {
          $r = $hex{0} . $hex{0};
          $g = $hex{1} . $hex{1};
          $b = $hex{2} . $hex{2};
        } else {
          $r = substr($hex, 0, 2);
          $g = substr($hex, 2, 2);
          $b = substr($hex, 4, 2);
        }
        $rgb = array_map('hexdec', compact('r', 'g', 'b'));
        return $rgb;
      }
    
    
      static function rgbToHex( $rgb = array(0, 0, 0) ) {
        if ( ! is_array($rgb) || count($rgb) != 3 ) return;
        $rgb = array_map('intval', $rgb);
        $hex = implode('', array_map('dechex', $rgb) );
        if ( ! ctype_xdigit ( $hex ) ) $hex = $this->default_main_color;
        return '#' . $hex;
      }
    
    
      // coming from http://www.brandonheyer.com/2013/03/27/convert-hsl-to-rgb-and-rgb-to-hsl-via-php/
      static function rgbToHsl( $rgb = array(0, 0, 0) ) {
        if ( ! is_array($rgb) || count($rgb) != 3 ) return;
        $rgb = array_values( array_map('intval', $rgb) );
        $oldR = $r = $rgb[0];
        $oldG = $g = $rgb[1];
        $oldB = $b = $rgb[2];
        $r /= 255;
        $g /= 255;
        $b /= 255;
        $max = max( $r, $g, $b );
        $min = min( $r, $g, $b );
        $h = $s = 0;
        $l = ( $max + $min ) / 2;
        $d = $max - $min;
        if( $d != 0 ) {
            $s = $d / ( 1 - abs( 2 * $l - 1 ) );
            switch( $max ){
              case $r :
                $h = 60 * fmod( ( ( $g - $b ) / $d ), 6 );
                break;
    
              case $g:
                $h = 60 * ( ( $b - $r ) / $d + 2 );
                break;
    
              case $b:
                $h = 60 * ( ( $r - $g ) / $d + 4 );
                break;
            }
        }
        $hsl = array();
        foreach ( compact('h', 's', 'l') as $i => $var ) $hsl[$i] = round($var, 2);
        return $hsl;
      }
    
    
      // coming from http://www.brandonheyer.com/2013/03/27/convert-hsl-to-rgb-and-rgb-to-hsl-via-php/
      static function hslToRgb( $hsl = array(0, 0, 0) ) {
        if ( ! is_array($hsl) || count($hsl) != 3 ) return;
        $hsl = array_values($hsl);
        $h = (float)$hsl[0];
        $s = (float)$hsl[1];
        $l = (float)$hsl[2];
        $r = null;
        $g = null;
        $b = null;
        $c = ( 1 - abs( 2 * $l - 1 ) ) * $s;
        $x = $c * ( 1 - abs( fmod( ( $h / 60 ), 2 ) - 1 ) );
        $m = $l - ( $c / 2 );
        if ( $h < 60 ) {
          $r = $c;
          $g = $x;
          $b = 0;
        } else if ( $h < 120 ) {
          $r = $x;
          $g = $c;
          $b = 0;            
        } else if ( $h < 180 ) {
          $r = 0;
          $g = $c;
          $b = $x;                    
        } else if ( $h < 240 ) {
          $r = 0;
          $g = $x;
          $b = $c;
        } else if ( $h < 300 ) {
          $r = $x;
          $g = 0;
          $b = $c;
        } else {
          $r = $c;
          $g = 0;
          $b = $x;
        }
        $r = ( $r + $m ) * 255;
        $g = ( $g + $m ) * 255;
        $b = ( $b + $m  ) * 255;
        $rgb =  array();
        foreach ( compact('r', 'g', 'b') as $i => $var ) $rgb[$i] = floor($var);
        return $rgb;
      }
    
    }
    

    Once you have this class included in theme or plugin just use it like so:

    new MyColorSettingsClass('#444444', 30, 30);
    

    Where 1st argument is default main color 2nd is the lighter percentual and 3rd is darker percentual.

    First argument accept hex colors in both 3 and 6 digits form and with or without ‘#’.

    Bonus functionality is that this code create the default option for all 3 colors based of 1st argument when the user has not setted nothing yet.

    Convert function from rgb to hsl and reverse are taken from here and just a little bit adapted.

    Edit

    On stackoverflow I found an function that convert lighter and darker hex colors direcly. I think is a bit slower than my solution (maybe), but is much easier to implement.

    Code is here https://stackoverflow.com/questions/3512311/how-to-generate-lighter-darker-color-with-php#11951022 If you want, edit my class to generate lighter and darker colors using that function.

    Only note that stackoverflow function accept ligh increase/decrease in a form from -255 to 255 (negative = darker / positive = lighter) my class accepts percentual values that maybe are more intuitive.

Comments are closed.