Web & Software Developer

Using WordPress Customizer To Customize Image Colors For An Image Output With PHP imagepng

This page is for WordPress plugin authors who want to allow users of their plugin to use the WordPress Customizer to customize image colors in an image. Specifically, this is for an image that is created dynamically with PHP and output with the imagepng function. This will allow you to “live preview” that image in the WordPress customizer, and edit its colors.

(Although this is done successfully with an image output with imagepng, it should work as well with images output with imagejpeg.)

This assumes you are creating a plugin with some script which generates an image with PHP, and this image is displayed somewhere on a page or post. Here I will show you how you can allow users of your plugin to customize the colors of this image in the WordPress customizer.

This will create a new tab section in the WordPress customizer, and when this customizer tab is opened, the customizer will display the image, and it will allow custom colors to be previewed live, as they are selected in the customizer settings. This means the PHP-generated image will be refreshed automatically in the customizer with the new colors. The user will be able to use the customizer settings to preview new colors on the image before saving any changes.

  1. Step 1: Make Sure Your Image Script Works

    To begin with, this assumes you already have some script that creates an image with PHP. It’s not my purpose to show how to create an image with PHP; my purpose is to show you how the image colors can be customized in the WordPress customizer.

    So, before we continue, make sure that your image is displayed properly. As an example, I’ll use this sample script to create an image with PHP:

    <?php
    header ('Content-Type: image/png');
    
    $x = 400;
    $y = 250;
    $offset	= 30;
    
    // Create the image
    
    $im = @imagecreatetruecolor( $x, $y ) or die( 'Cannot initialize new GD image stream' );
    
    // Define colors
    
    $black = imagecolorallocate($im, 0, 0, 0);
    $red = imagecolorallocate($im, 207,0,15);
    $blue = imagecolorallocate($im, 65,105,225);
    $orange = imagecolorallocate($im, 245, 171, 53);
    $gray = imagecolorallocate($im,200,200,200);
    
    // Color the image
    
    imagefilledrectangle( $im, 0, 0, $x, $y, $blue );
    imagefilledrectangle( $im, $offset, $offset, $x - $offset, $y - $offset, $orange );
    imagefilledrectangle( $im, $offset * 2, $offset * 2, $x - ($offset * 2), $y - ($offset * 2), $gray );
    
    // Add text to the image
    
    imagestring( $im, 5, 8+($offset * 2), 16+($offset * 2), 'This text is one color', $red );
    imagestring( $im, 5, 8+($offset * 2), 40+($offset * 2), 'This text is another color', $black );
    
    // Output the image
    
    imagepng( $im );
    
    imagedestroy( $im );
    ?>
    

    The sample script creates this image:

    Image created with PHP imagecreatetruecolor and imagepng

    Image created with PHP imagecreatetruecolor() and imagepng()

    The image script, above, is saved in a separate file called image.php. This file would be placed inside your plugin.

    For this example, I’ll use the following function which calls that script to get the HTML image element:

    /**
     * Returns the HTML image element
     */
    function my_get_image() {
    	$src = plugin_dir_url( __FILE__ ) . 'image.php';
    	$out = '<img src="' . esc_url( $src ) . '" class="my-custom-image" alt="my image" />';
    	return $out;
    }
    

    For your own image, you need to have some function that gets and returns your image as an HTML string, just like the one above. This function will be necessary later, in order to show the image in the customizer. For this example, we will use the function, my_get_image().

    Important: notice that I gave the image a class attribute of my-custom-image. It’s necessary for you to give your image element a class selector because we will use that class selector later in our customizer script.

    To display the image, you would use this:

    <?php echo my_get_image(); ?> 
  2. Step 2: Add a Custom Tab Section To The WordPress Customizer

    Now, we are going add a custom tab to the WordPress customizer for the purpose of customizing the colors for our image.

    The sample image script, above, creates a gray rectangle, within an orange rectangle, within a blue rectangle. The image also has some red text and some black text. That makes 5 different colors that we want to be able to edit in the customizer.

    We’ll set up 5 customizer settings, one for each of the colors that I want to allow to be changed in the image. The following PHP class takes care of this.

    The 5 default colors for the 5 settings are on lines 11–34 (below). For each setting, I give a unique key (no spaces), the HTML hex color code for the default color, and a human-readable name. For example, on line 11, the unique key is outer_rectangle_color. On the next line is its default color, #4169e1. On the next line is the human-readable name, Outer Rectangle Color. You can add to this array as many colors as you need.

    Notice that we are using hex color codes here, but the image script in Step 1 uses rgb values for the colors. To get the default colors to enter here, I had to look up the rgb colors from my image script, and get the hex equivalents. You will have to do the same for your own colors that you use in your image script. You will find the rgb values in the imagecolorallocate calls in your image script.

    Another thing that may have to be edited in the following class is line 112. On line 112, we use the function my_get_image() to get our image. You can change my_get_image() to the function that gets your own image. (Or leave it as is, if you’re using my sample image script and my sample my_get_image() function from Step 1.)

    The following class can be saved in its own file, named class-my-image-customize.php. Then you can include the class in your plugin using:

    require_once plugin_dir_path( __FILE__ ) . 'class-my-image-customize.php';

    And this is the class:

    <?php
    /**
     * Adds an image color editor to the Customizer.
     */
    class My_Image_Customize {
    	/**
    	 * Get default colors
    	 */
    	private static function default_colors() {
    		$defaults = array(
    			'outer_rectangle_color'		=> array(
    											'#4169e1',
    											__( 'Outer Rectangle Color', 'textdomain' )
    											),
    
    			'middle_rectangle_color'	=> array(
    											'#f5ab35',
    											__( 'Middle Rectangle Color', 'textdomain' )
    											),
    
    			'inner_rectangle_color'		=> array(
    											'#c8c8c8',
    											__( 'Inner Rectangle Color', 'textdomain' )
    											),
    
    			'first_text_color'			=> array(
    											'#cf000f',
    											__( 'First Text Color', 'textdomain' )
    											),
    
    			'second_text_color'			=> array(
    											'#000000',
    											__( 'Second Text Color', 'textdomain' )
    											),
    
    		);
    
    		return $defaults;	
    	}
    
    	/**
    	 * Setup the Customizer settings and controls
    	 */
    	public static function register( $wp_customize ) {
    
    		$wp_customize->add_section( 'my_image_colors', array(
    			'title'		=> __( 'My Custom Image', 'textdomain' )
    		) );
    
    		foreach( self::default_colors() as $key => $value ) {
    			$wp_customize->add_setting( "my_image_customizer[$key]", array(
    				'type'				=> 'option',
    				'default'			=> $value[0],
    				'sanitize_callback'	=> 'sanitize_hex_color',
    				'transport'			=> 'postMessage'
    				)
    			);
    
    			$wp_customize->add_control(
    				new WP_Customize_Color_Control( $wp_customize, "my_image_$key", array(
    					'settings'	=> "my_image_customizer[$key]",
    					'label'		=> $value[1],
    					'section'	=> 'my_image_colors'
    				) )
    			);			
    		}
    
    	}
    	// Load the js to handle the live preview
    	public static function scripts() {
    		wp_enqueue_script(
    			'my-image-customize',
    			plugin_dir_url( __FILE__ ) . 'assets/js/my-image-customize.js',
    			array( 'customize-controls' )
    		);
    
    		wp_localize_script( 'my-image-customize', 'my_image_colors', array(
    			'root' => esc_url_raw( rest_url() ),
    			'nonce' => wp_create_nonce( 'wp_rest' ),
    			'page_title' => __( 'My Image Preview', 'textdomain' ),
    			'ajaxurl' => admin_url( 'admin-ajax.php' )
    		) );
    		
    	}
    
    	/**
    	 * Merge settings with defaults to use default colors for any blank settings
    	 */
    	public static function merge_settings( $settings ) {
    		// array of default values
    		foreach( self::default_colors() as $k => $v ) {
    			$defaults[ $k ] = $v[0];
    		}
    
    		$merged = array_merge( array_filter( $defaults, 'strval' ), array_filter( $settings, 'strval' ) );
    
    		return $merged;
    	}
    
    	/**
    	 * Gets My Image customizer settings.
    	 */
    	public static function get_settings() {
    		$settings = get_option( 'my_image_customizer', array() );
    		return apply_filters( 'my_image_customizer_get_settings', $settings );
    	}
    
    	/**
    	 * The shortcode to display a live preview of the image in the customizer when it is first opened
    	 */
    	public static function preview_shortcode( $atts ) {
    		return wp_kses_post( my_get_image() );
    	}
    
    }
    // Setup the Customizer settings and controls
    add_action( 'customize_register', array( 'My_Image_Customize', 'register' ) );
    
    // Take care of any settings left blank
    add_filter( 'my_image_customizer_get_settings', array( 'My_Image_Customize', 'merge_settings' ) );
    
    // Enqueue live preview javascript in Theme Customizer admin screen
    add_action( 'customize_controls_enqueue_scripts' , array( 'My_Image_Customize', 'scripts' ) );
    
    add_shortcode( 'my_image_customizer_preview', array( 'My_Image_Customize', 'preview_shortcode' ) );
    
  3. Step 3: Add The JavaScript For The Customizer To Handle Live Previews

    The class, above, loads a .js file on line 73. Notice that it is named my-image-customize.js and its path is assets/js/. We are going to create that file, now. You should edit line 73, above, according to where you’ll place this .js file in your plugin.

    Our customizer JavaScript file will do more than handle live previews of the colors. It also makes sure that when you click on the “My Custom Image” tab inside the customizer, the customizer preview pane will open to our custom image. Then, when you close the “My Custom Image” tab, it will return to whatever page the customizer was previously showing.

    To make this work, we use the WordPress REST API to create a temporary draft of a page from within the customizer JavaScript. This page draft is created “on the fly” when our tab section is opened. This page will display our image. When our customizer tab is closed, this temporary page draft will be deleted (using the WordPress REST API). It may sound like a better idea to simply use a back-end admin page for this purpose, but that will not work because, currently, the WordPress customizer will not allow a live preview of admin pages. It only allows live preview of public-facing pages.

    Save the following JavaScript and name it my-image-customize.js. (Remember to edit line 73 in Step 2, above, according to where you place this file.)

    In the following JavaScript, you would only have to edit 2 things.

    First, lines 17 and 18 have the list of unique keys for our customizer settings. These should be exactly the same as the unique keys on lines 11–34 in Step 2. If you added settings there, then you should also add the keys here.

    Second, you would have to change my-custom-image at the end of line 44, to the class selector that you gave your image. Remember the important note from the end of Step 1, above: It’s necessary for you to give your image element a class selector because we will use that class selector later in our customizer script. Well, this is where you need to use the class selector for your image. If you’re using my sample image script, you can leave my-custom-image as it is on line 44.

    ( function( $ ) {
    	'use strict';
    	wp.customize.section( 'my_image_colors', function( section ) {
    
    		// Set a custom Preview URL only for My Image section
    		var previousUrl, clearPreviousUrl, previewUrlValue, previewPageID;
    		previewUrlValue = wp.customize.previewer.previewUrl;
    		clearPreviousUrl = function() {
    			previousUrl = null;
    		};
    			
    		section.expanded.bind( function( isExpanded ) {
    			var keys, myGetSettings, replaceImage;
    
    			if ( isExpanded ) {
    
    				keys = ['outer_rectangle_color','middle_rectangle_color','inner_rectangle_color',
    							'first_text_color','second_text_color'];
    
    				// Grab all our live customizer 'My Image' settings, even those not saved yet
    				myGetSettings = function () {
    					var settings = {};
    
    					keys.forEach(function(element) {
    						settings[element] = wp.customize.value('my_image_customizer[' + element + ']')();
    					});
    
    					return settings;
    				};
    
    				// Replaces the image with a new image with new colors
    				replaceImage = _.debounce(function (e) {
    
    					// Get new image
    					$.ajax({
    						url: my_image_colors.ajaxurl,
    						type: "POST",
    						data: {
    							action: 'my_image_customize_preview_image',
    							post_data: myGetSettings()
    						},
    						dataType: "json",
    						success: function( data ) {
    							var myImageElement = $('#customize-preview iframe').contents().find('.my-custom-image');
    							myImageElement.replaceWith( data.image );					
    						}
    					});
    				}, 1000);
    
    				// Hide the close-customizer button since I need to detect when this section closes 
    				// which can only be detected upon closing the section, not closing the customizer.
    				$( '.customize-controls-close' ).hide();
    
    				// Create the page for our live preview
    
    				$.ajax({
    					method: "POST",
    					url: my_image_colors.root + 'wp/v2/pages',
    					data: {
    						title: my_image_colors.page_title,
    						content: '[my_image_customizer_preview]',
    						type: 'page',
    						status: 'draft'
    					},
    					beforeSend: function ( xhr ) {
    						xhr.setRequestHeader( 'X-WP-Nonce', my_image_colors.nonce );
    					},
    					success : function( response ) {
    						// save the page id so we can delete it when finished
    						previewPageID = response.id;
    						// set the live preview URL
    						previousUrl = previewUrlValue.get();
    						previewUrlValue.set( response.link );
    						previewUrlValue.bind( clearPreviousUrl );
    					}
    				});
    
    				// Update colors in real time
    
    				keys.forEach(function(element) {
    					wp.customize( 'my_image_customizer[' + element + ']', function( value ) {
    						value.bind( replaceImage );
    					});
    				});
    
    			} else {
    
    				// When section closes...
    
    				$( '.customize-controls-close' ).show();
    
    				// Upon closing the 'My Image' section, return to the previous preview URL
    				previewUrlValue.unbind( clearPreviousUrl );
    				if ( previousUrl ) {
    					previewUrlValue.set( previousUrl );
    				}
    
    				// delete the My Image preview page
    				if ( previewPageID ) {
    					$.ajax({
    						method: "DELETE",
    						url: my_image_colors.root + 'wp/v2/pages/' + previewPageID + '?force=true',
    						beforeSend: function ( xhr ) {
    							xhr.setRequestHeader( 'X-WP-Nonce', my_image_colors.nonce );
    						}
    					});
    				}
    
    			} // end section closes
    		} );
    	} );
    
    } )( jQuery );
    
  4. Step 4: Create AJAX Handler To Update The Image In The Customizer

    The JavaScript file, which we created above, uses AJAX to handle live previews in the customizer. It uses AJAX to replace the image with a new image, with updated colors. Now, we need a function to handle our AJAX request to get an updated image.

    You will need to add the following AJAX handler to your plugin. The only thing to edit here is line 11, in which you have to replace my_get_image( $colors ) with your own function that gets your own image (unless you’re using my samples). Notice that this function must have $colors passed to it.

    /**
     * Handles ajax request to get an updated image for the live color preview for customizer.
     */
    function my_ajax_get_customizer_image() {
    	$colors = array();
    
    	foreach( $_POST['post_data'] as $k => $color ) {
    		$colors[ $k ] = sanitize_hex_color( $color );
    	}
    
    	$image = wp_kses_post( my_get_image( $colors ) );
    	echo json_encode( array( 'image' => $image ) );
    	wp_die();
    }
    add_action( 'wp_ajax_my_image_customize_preview_image', 'my_ajax_get_customizer_image' );
    add_action( 'wp_ajax_nopriv_my_image_customize_preview_image', 'my_ajax_get_customizer_image' );
    
  5. Step 5: Modify my_get_image() To Allow Custom Colors

    Now, we have to modify the my_get_image() function to allow custom colors to be passed to the function, so that the colors can be passed to the image.

    I’m going to modify my my_get_image() function from Step 1. You can make the changes in your own function that gets your image, as needed.

    The first change is to add a parameter to the function: $colors. The function now begins like this:

    function my_get_image( $colors = false ) { 

    Inside the function, at the very top, insert this to check for colors:

    	if ( empty( $colors ) ) {
    		$customizer_settings = My_Image_Customize::get_settings();
    	} else {
    		// incorporate live customizer colors that are not yet saved
    		$customizer_settings = My_Image_Customize::merge_settings( $colors );
    	}
    
    	$encoded_settings = rawurlencode( serialize( $customizer_settings ) );
    

    The last line, above, serializes and encodes the customizer color settings so that we can pass these customizer settings to the image script.

    Next, we are going to change the image src. The original one (line 5 in the my_get_image() function in Step 1) looks like this:

    $src = plugin_dir_url( __FILE__ ) . 'image.php';

    We are going to add a query string that passes the customizer settings to the image script. To do this, change that line to this:

    $src = plugin_dir_url( __FILE__ ) . 'image.php?mycustomimage=' . $encoded_settings;

    So, the entire function now looks like this:

    /**
     * Returns the HTML image element
     */
    function my_get_image( $colors = false ) {
    	if ( empty( $colors ) ) {
    		$customizer_settings = My_Image_Customize::get_settings();
    	} else {
    		// incorporate live customizer colors that are not yet saved
    		$customizer_settings = My_Image_Customize::merge_settings( $colors );
    	}
    
    	$encoded_settings = rawurlencode( serialize( $customizer_settings ) );
    
    	$src = plugin_dir_url( __FILE__ ) . 'image.php?mycustomimage=' . $encoded_settings;
    	$out = '<img src="' . esc_url( $src ) . '" class="my-custom-image" alt="my image" />';
    	return $out;
    }
    
  6. Step 6: Modify The Image Script To Accept Custom Colors

    We have to modify the image script to allow for custom color choices. Our image script in this example is the file image.php from Step 1.

    The first change we are going to make is to insert this at the very top of the image script, above the header line:

    if ( isset( $_GET['mycustomimage'] ) ) {
    	$customizer_raw = unserialize( $_GET['mycustomimage'] );
    	foreach ( $customizer_raw as $key => $value ) {
    		$hex = my_custom_image_sanitize_data( $value );
    		// Convert customizer hex colors to rbg values
    		$customizer_rgb[ $key ] = my_custom_image_hex2rgb( $hex );
    	}
    }
    

    That makes the image script check for customizer settings which are being passed to it as a query string. It sanitizes the values and converts the hex color codes to rgb values so that our image script can use these colors. Here, we’ve introduced two new functions, so we will add those function to the very end of the image script. Add the following to the end of the image script, after the imagedestroy line:

    /**
     * Strip all tags and whitespace
     */
    function my_custom_image_sanitize_data( $data ) {
    	$data = preg_replace( '@<(script|style)[^>]*?>.*?</1>@si', '', $data );
    	$data = strip_tags($data);
    	$data = preg_replace('/[rnt ]+/', ' ', $data);
     	return trim( $data );
    }
    
    /**
     * Convert hex color code into array of rgb values
     * @return array with the r,g,b values
     */
    function my_custom_image_hex2rgb( $hex ) {
    	$hex = ltrim( $hex, '#');
    	if(strlen($hex) == 3) {
    		$r = hexdec(substr($hex,0,1).substr($hex,0,1));
    		$g = hexdec(substr($hex,1,1).substr($hex,1,1));
    		$b = hexdec(substr($hex,2,1).substr($hex,2,1));
    	} else {
    		$r = hexdec(substr($hex,0,2));
    		$g = hexdec(substr($hex,2,2));
    		$b = hexdec(substr($hex,4,2));
    	}
    	return array($r, $g, $b);
    }
    

    Now, we have to set default colors and make sure that customizer settings will override the defaults. We are going to create some abstraction to allow for this.

    To do this, we’ll create a variable for each of our customizer settings. The variable will be set to the default color for that setting, unless a customizer setting is found for that setting.

    Remember that you can see our settings in Step 2, lines 11–34. We have 5 settings, so here are the 5 variables that I’ll use:

    // Set default colors and override with Customizer colors
    
    $outer_rectangle_color = isset( $customizer_rgb['outer_rectangle_color'] ) ?
    				imagecolorallocate($im,$customizer_rgb['outer_rectangle_color'][0], $customizer_rgb['outer_rectangle_color'][1],$customizer_rgb['outer_rectangle_color'][2]) :
    				$blue;
    
    $middle_rectangle_color = isset( $customizer_rgb['middle_rectangle_color'] ) ?
    				imagecolorallocate($im,$customizer_rgb['middle_rectangle_color'][0], $customizer_rgb['middle_rectangle_color'][1],$customizer_rgb['middle_rectangle_color'][2]) :
    				$orange;
    
    $inner_rectangle_color = isset( $customizer_rgb['inner_rectangle_color'] ) ?
    				imagecolorallocate($im, $customizer_rgb['inner_rectangle_color'][0], $customizer_rgb['inner_rectangle_color'][1], $customizer_rgb['inner_rectangle_color'][2]) :
    				$gray;
    
    $first_text_color = isset( $customizer_rgb['first_text_color'] ) ?
    				imagecolorallocate($im, $customizer_rgb['first_text_color'][0], $customizer_rgb['first_text_color'][1], $customizer_rgb['first_text_color'][2]) :
    				$red;
    
    $second_text_color = isset( $customizer_rgb['second_text_color'] ) ?
    				imagecolorallocate($im, $customizer_rgb['second_text_color'][0], $customizer_rgb['second_text_color'][1], $customizer_rgb['second_text_color'][2]) :
    				$black;
    

    It’s necessary for the array keys for $customizer_rgb to match the unique ids for our customizer settings. For example, line 3, above, is the variable for our “Outer Rectangle Color” setting. It checks for $customizer_rgb['outer_rectangle_color']. Yes, outer_rectangle_color is the exact key for that customizer setting.

    And notice on line 5, the default color is set to $blue. The rest of the variables are set to their own default colors. These color variables, of course, were already defined in the script in the // Define colors section (see the script in Step 1).

    So, now, this block of code with these 5 variables will be inserted into the image script, after the // Define colors section. In other words, right before the // Color the image section on line 20 (in the script in Step 1).

    Now, we are going to modify the // Color the image section. There are 3 imagefilledrectangle which have their color passed as the last argument. The first is $blue, the second one is $orange, the third one is $gray. We are going to change those 3 colors; instead, we are going to use the variables we just created.

    • Change $blue to $outer_rectangle_color.
    • Change $orange to $middle_rectangle_color.
    • Change $gray to $inner_rectangle_color.

    In the image script, after the // Color the image, you’ll see the // Add text to the image section. In this section, there are two imagestring which have their color passed as the last argument. The first is $red, the second one is $black. We are going to change those 2 colors to use the variables we just created.

    • Change $red to $first_text_color.
    • Change $black to $second_text_color.
  7. We are finally finished. Now, you can go to the WordPress customizer at “Appearance –> Customize” and click on the “My Custom Image” tab. You’ll be able to live preview the colors in the image. When you save your changes, these color changes will take effect wherever you use the image script in the plugin.

By

Questions and Comments are Welcome

Your email address will not be published. All comments will be moderated.

Please wrap code in "code" bracket tags like this:

[code]

YOUR CODE HERE 

[/code]