Posts tagged ‘PHP’

Been a while since I wrote something. Let’s talk about some of the new stuff available in the Customizer.

Forget about some of part two

First, back in part two, I had a bit about Surfacing the Customizer. That bit is outdated now, WordPress does this for you in later versions. So, yeah, skip that.

Shiny new thing: Panels

Okay, so Panels aren’t that new. They were added in WordPress 4.0. Basically, they’re sliding containers for sections. Having trouble fitting all your settings on the screen? Group the various sections up into Panels. Panels show up as an item in the main list, and when you click the arrow next to them, the whole list glides off screen to show only those sections.

So, now we have four things: Panels, Sections, Controls, and Settings.

  • Panels group Sections together
  • Sections contain Controls
  • Controls are what the user changes
  • Settings define what the Controls change

Creating a panel is easy:

$wp_customize->add_panel( 'some_panel', array(
	'title' => 'Panel 1',
	'description' => 'This is a description of this panel',
	'priority' => 10,
) );

Adding a section to that panel is just as easy:

$wp_customize->add_section( 'themedemo_panel_settings', array(
	'title' => 'More Stuff',
	'priority' => 10,
	'panel'	=> 'some_panel',
) );

All that’s new is a panel setting to tell the section to go into that panel. Simple.

Active Callbacks

One of the problems with the Customizer was that it displayed settings and showed them changing on the site to your right, but the site being displayed is the actual site. Meaning that you can navigate on it. Sometimes, the controls being shown don’t necessarily apply to the actual site that you’re seeing.

Example: If you have a control to change the color of something in the sidebar, but then are looking at a page which has no sidebar, then you have no visual feedback to tell you what the change looks like.

To fix this, “active callbacks” are used.

The active_callback is simply a new parameter that you can pass into Panels, Sections, or Controls. It can contain the name of a function, and that function will be called when the page changes. The function should return true or false (or equivalent) to indicate whether or not the element of the customizer should be shown for that page.

So, if you have a whole Panel that only make sense when the user is looking at Front Page of the site (and not an individual post), then you can do this:

$wp_customize->add_panel( 'front_page_panel', array(
	'title' => 'Front Page Stuff',
	'description' => 'Stuff that you can change about the Front Page',
	'priority' => 10,
	'active_callback' => 'is_front_page',
) );

And voila, when the user is not looking at the front page, the panel simply disappears.

You can use any of the normal WordPress Template Tags for this, or write your own function if you want to be more specific about it.

Fun with Active Callbacks

If you do need to write your own callback function, note that the function receives the object in question when it’s called. So, if you attach an active_callback to a Panel, your function will get a argument of the WP_Customize_Panel object in question passed to it. Sections get WP_Customize_Section and such. You can use the information in these to decide whether the panel (or whatever) should be shown for that page.

So, how do we use that object? Well, you can use this to make whether certain controls show or not dependent on the values of other settings. All the various items you can use this on have a link back to the main WP_Customize_Manager. That class has a get_setting function, which you can use to determine what to do.

So, let’s make a control that causes other controls to appear, dependent on a setting.

First, let’s make a simple radio selection control:

$wp_customize->add_setting( 'demo_radio_control', array(
	'default'        => 'a',
) );

$wp_customize->add_control( 'demo_radio_control', array(
    'label'      => 'radio_control',
    'section'    => 'themedemo_panel_settings',
    'settings'   => 'demo_radio_control',
    'type'       => 'radio',
    'choices'    => array(
	'a' => 'Choice A',
	'b' => 'Choice B',
	),
) );

Now, we need to make two other controls, one for each choice. You can actually make as many as you like, we’ll keep it simple.

First, the control for choice A. Let’s make it a simple text control.

$wp_customize->add_setting( 'choice_a_text', array(
	'default' => '',
) );

$wp_customize->add_control( 'choice_a_text', array(
    'label'      => 'Choice A: ',
    'section'    => 'themedemo_panel_settings',
    'type'       => 'text',
    'active_callback' => 'choice_a_callback',
) );

We’ll need that callback function to detect if choice A is selected in the radio control, and return true if it is, and false otherwise. Like so:

function choice_a_callback( $control ) {
	if ( $control->manager->get_setting('demo_radio_control')->value() == 'a' ) {
		return true;
	} else {
		return false;
	}
}

You can simplify that if you like, I spelled it out with an if statement so as to be clear as to what is happening.

panel1

Now for choice B, let’s make it display a color control instead:

$wp_customize->add_setting( 'choice_b_color', array(
	'default' => '#123456',
) );

$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'choice_b_color', array(
	'label'   => 'Choice B',
	'section' => 'themedemo_panel_settings',
	'settings'   => 'choice_b_color',
	'active_callback' => 'choice_b_callback',
) ) );

And its callback:

function choice_b_callback( $control ) {
	if ( $control->manager->get_setting('demo_radio_control')->value() == 'b' ) {
		return true;
	} else {
		return false;
	}
}

panel1-b
Now, note that the callbacks are very similar. Seems like repeated code, doesn’t it? Well, it is, but remember that the $control here is the whole WP_Customize_Control object. We can use the same callback and simply check which control is calling it here instead.

function choice_callback( $control ) {
	$radio_setting = $control->manager->get_setting('demo_radio_control')->value();
	$control_id = $control->id;
	
	if ( $control_id == 'choice_a_text'  && $radio_setting == 'a' ) return true;
	if ( $control_id == 'choice_b_color' && $radio_setting == 'b' ) return true;
	
	return false;
}

So, instead of using two different callbacks, we just point our controls to this callback, which figures out what should show up for which setting. I’m sure you can simplify this further, depending on your particular needs.

One more thing: Customizing the Customizer

Not everybody likes the style of the Customizer. Maybe it clashes with your theme. Maybe you just want to tweak it a bit. Maybe you dislike that gray background color, and a more soothing blue would go better for your theme.

add_action( 'customize_controls_enqueue_scripts', 'themedemo_customizer_style');
function themedemo_customizer_style() {
	wp_add_inline_style( 'customize-controls', '.wp-full-overlay-sidebar { background: #abcdef }');
}

Or maybe you don’t think the Customizer area is wide enough… be careful with this one though, consider mobile users as well.

add_action( 'customize_controls_enqueue_scripts', 'themedemo_customizer_style');
function themedemo_customizer_style() {
	wp_add_inline_style( 'customize-controls', '.wp-full-overlay-sidebar { width: 400px } .wp-full-overlay.expanded { margin-left: 400px } ');
}

You can enqueue whole extra CSS files instead, if you like. Or, if you have special needs for javascript in some of your controls, and there’s libraries necessary to implement them, then you can enqueue those libraries here as well.

 

Shortlink:


So in my last post about Internationalization, I covered some non-obvious things that you should consider when adding translation capabilities to your code.

Today, let’s add to that by covering some non-obvious translation functions. You’re probably not using these, since they don’t get talked about as much. But there’s probably places where you should be using them, so knowing about them is the first step. And knowing is half the battle.

Basic functions, again

Last time I talked about these functions:

  • __()
  • _e()
  • _x()
  • _ex()
  • _n()

Let’s cover the ones I didn’t talk about.

Escaping output

In practice, you tend to use these mostly when outputting things onto the main page or in the admin. But, one thing you also use a lot when outputting text is the standard escaping functions. These are things like esc_html(), which outputs text in a way that makes it “safe” to go onto a webpage, without being interpreted as HTML. If the text comes from user input, then this is a good idea.

Now, if you think about it, then the text you have may be translated in some other file, which you don’t control either. So escaping that text might be a good idea too. If somebody snuck bad code into a translation file, a user might get bad things displayed without being able to easily find it.

So you could write something like echo esc_html(__('text','text-domain')), but that’s a bit wordy. Let’s talk about some shortcuts.

The esc_html__() function is the equivalent of esc_html(__(...)). It does the escaped html and the double-underscore translation all in one go. Similarly, the esc_html_e() function does the same thing, but it echoes the result, just like the _e() function would. And there’s also esc_html_x(), which is the equivalent of combining esc_html() and _x().

Along with those three are the three identical equivalents for attributes: esc_attr__(), esc_attr_e(), and esc_attr_x(). As the name implies, these combine the translation functions with esc_attr(), which is the escape function specifically intended when you’re outputting text into html attributes.

Also note there’s no shortcut for the equivalent of _ex(). It’s just not used that much, or at least not enough to need something special for it. Use an echo esc_html_x() instead.

There are no shortcuts for the other escaping functions as yet, but these can save a few keystrokes and make your code that much more readable.

The Numerical No-op

So we’ve got some shortcuts for escaping with those three functions, but where’s the love for _n()?

One of the problems with _n() is that it tends to require the strings to be in the same place that the PHP variable is. For all the other functions, you could have a big file of strings in an array, and then reference those strings by name or something elsewhere because they don’t require any PHP variables. Nothing about them is computed at the time of the output.

But not so with _n(), that $number to decide which string to use means that the strings have to be right there, they can’t be translated separately and referenced.

This is where _n_noop() comes in. The _n_noop() function basically takes the singular and plural strings for something, along with the text domain, and stores them in an array so that they can be referenced later by a function named translate_nooped_plural().

Perhaps an example is in order. Let’s go back to the tacos:

$string = sprintf( _n('You have %d taco.', 'You have %d tacos.', $number, 'plugin-domain'), $number );

What if we wanted those strings somewhere else? Like in a big file with all of our strings. Here’s a way to separate the strings from the _n() call:

$taco_plural = _n_noop('You have %d taco.', 'You have %d tacos.', 'plugin-domain');
$string = sprintf( translate_nooped_plural( $taco_plural, $number) , $number );

Now, that $taco_plural can be defined anywhere. Note that it contains no references to PHP variables. It’s basically static and unchanging. This allows us to separate it, then reference it elsewhere for the actual translation. The translate_nooped_plural() function performs the same job as _n() does, choosing which string to use based on the $number of tacos. The sprintf then pushes the $number into the chosen string, replacing the %d with the number.

Thus, that lets us extract the translatable strings out and put them anywhere we choose.

Also of note: The _nx_noop() function is a cross between _n_noop() and _x(). It takes a context for the translators as the third argument, and the domain becomes the fourth argument. Useful if you need to explain to the translators the context surrounding the pluralization choice.

Numbers and Dates

The number_format_i18n() function is functionally equivalent to the PHP number_format function. It lets you format numbers with commas at the thousands mark and so forth, except that it also takes localization into account. Not everybody uses commas for thousands and periods for decimals. This function will do the translation appropriately for that aspect.

The date_i18n() function is functionally equivalent to the PHP date function. It will handle all the same string formatting parameters as date() will, but it will cause output to be translated for month names, day-of-week names, and so forth. Of note is that it doesn’t change the format requested. If some places put days before months, for example, it won’t handle that. But it will output the month name in the native language (if the translation pack has the right month name in it). So you may want to run the date formatting string through __() as well, to let translators adjust the date format accordingly.

Wrap up

And that’s pretty much all the rest of the translation functions that I didn’t cover before. I may have forgotten a few useful ones here or there. Feel free to comment about anything I missed, or what you see most often, especially if you’re doing translations yourself.

Shortlink:

My post about how to customize WordPress images with tricks like greyscale and such got me lots of feedback, so I figured I might as well turn it into a plugin.

The ImageFX plugin allows you to customize the image sizes from WordPress or custom ones for your theme, by applying filters to them.

The way it works is basically identical to my original post on the topic, only it allows the filters to be defined on a per-image-size level. It also allows the addition of a “slug” to be appended to the image filename, which is useful for cases where you want to have two images at the same size, but with different filters.

Since it was easy to do, I went ahead and created several other simple image filters that you can use for your images:

  • Greyscale (black and white)
  • Sepia tone (old-timey!)
  • Colorize with red, yellow, green, blue, or purple
  • Photonegative
  • Emboss
  • Brighten
  • Greyscale except red, green, or blue (classy!)

Here’s some examples. This a pic of me, Nacin, Rose, and Matt at WordCamp San Francisco. I ran it through the sepia, blue colorize, and grey-except-red filters.



These are some of the default filters included, but since I could, I went ahead and made it easily expandable too. All you have to do to define a filter is to create a function to do the image filtering you want, then call the imagefx_register_filter() function to add it.

To implement your own custom filter, you can do it like this:

imagefx_register_filter('custom-name','my_custom_filter');
function my_custom_filter(&$image) {
 // modify the $image here as you see fit
}

Note that the $image is passed by reference, so you don’t have to return it. This is because the $image resource takes up a lot of memory, so to save on memory usage, you are manipulating it in place, sort of thing.

You can use any of the image functions in PHP to change the image however you like. The filters I’ve implemented are mostly pretty simple. You can see them all in the filters.php file, in the plugin.

Caveats: The plugin will only filter JPG images, to avoid the overhead of recompressing PNGs and to avoid breaking animated GIF files. Also note that I haven’t tested these filters extensively. They’re only a starting point, sort of thing. I spent all of about 20 minutes writing them, so don’t expect miracles. :)

You can download version 0.1 of the plugin from the WordPress plugin directory: http://wordpress.org/extend/plugins/imagefx/

Enjoy!

Shortlink:

First, WordPress plugin authors: Please don’t do this.

if ( isset($_GET['resource']) && !empty($_GET['resource']) ) {
	$resources = array(
		'icon1.png' => '... base 64 encoded code ...',
		'icon2.png' => '... base 64 encoded code ...',
		);

	if ( array_key_exists($_GET['resource'], $resources) ) {
		$content = base64_decode($resources[ $_GET['resource'] ]);
                header('Content-Length: '.strlen($content));
                header('Content-Type: image/png');
            	echo $content;
		exit;
	}
}

I’ve seen a few different versions of this, and while the idea is nice, this is really the wrong way to go about it.

The idea is to include small icons or images in the plugin file itself, instead of as separate files. This sort of code then lets you reference them by calling a URL of ?resource=icon1.png or whatever. When that resource variable is detected, the plugin kicks in and serves up the image instead of the site.

Advantages to this sort of thing:

  • No need for extra icon files

Disadvantages to this sort of thing:

  • Now every http request to get an icon file on your admin page results in loading up the WordPress code, causing extra CPU usage.

Here’s a better way. It’s called the Data URI.

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

Here’s that code in action, right here: Red dot

Why this is better:

  • Same benefits as before, no need for extra icon files
  • No extra CPU load from loading WordPress to get that icon file
  • No extra HTTP requests at all, in fact, since the data for the tiny icon is contained right there in the code

Disadvantage:

  • Doesn’t work in IE7. You can work around this by detecting IE7 and serving up the image separately, if you really want. Or you can just ignore it like most people do. Seriously. IE7 is insecure (link, link) and nobody should be using it, anywhere. WordPress itself will probably drop IE7 support in the admin in the next couple of versions.

So use Data URIs for small images (under 32KB in size). They’re fast and easy. They’re an idea whose time has come.

Shortlink:

While looking at my backlinks today, I noticed a site in French had linked to my post about making photo galleries. He mentioned that the Google Translate wasn’t great. I took a look, and while I don’t know how good the text translation was, I did notice that Google strangely tried to translate the code as well, thus screwing it all up.

A quick search revealed that all one had to do was to add the “notranslate” class to any wrapping object to prevent its contents from being translated.

Now, I use the Syntax Highligher Evolved plugin to display code on my site (although I use an older version because I like the look and functionality of it better than the latest version). So I edited the plugin and found where it inserts the PRE tag, and added the notranslate class to it. And voila, now my code doesn’t get translated anymore.

Just a helpful tip for anybody who posts code on their sites.

Shortlink:

Saw this post about Chrome voice searching in HTML forms on Google’s blog today. Very cool, so I had to give it a try. If you check the “Search” box in the upper right corner of the page, you’ll see a little icon (if you’re using a dev version of Chrome). Click it to do a search-by-voice.

What I didn’t expect was how totally easy it is to implement. Seriously, it’s less than a line of code.

Example. Say your search box (possibly in your theme’s searchform.php file) looks like this:

<form id="searchform" action="<?php bloginfo('home'); ?>/" method="get">
<input id="s" name="s" size="20" type="text" value="<?php _e('Search') ?>..." />
</form>

All you have to do is to add some bits to the input element box. Specifically, you add x-webkit-speech speech onwebkitspeechchange=”this.form.submit();”. That’s it. Seriously:

<form id="searchform" action="<?php bloginfo('home'); ?>/" method="get">
<input id="s" name="s" size="20" type="text" value="<?php _e('Search') ?>..." x-webkit-speech speech onwebkitspeechchange="this.form.submit();" />
</form>

Note that this won’t validate, if you care about that sort of thing. Works fine though.

You can do a whole lot more with Javascript and events and translations and multiple choices and such, if you’re thinking of developing something cool with it. I’m just shocked and amazed that this is already in my browser and I had no idea it was there. Very cool.

Shortlink: