Daily Archives: Sunday, 16th Dec 2012

Weight and Stuff Report – 16 December 2012

Hmmm. Up a pound today, which is probably due to rehydrating after yesterday’s moderately long walk. Well, that’s the best excuse I can think of, anyway.

I’ve been a bit busy with website tweakage today, so all I’ve got to add is this picture of Tynemouth Priory and the Tyne piers, with the light showing from the south pier’s lighthouse. I did try to catch them both, but didn’t quite manage it.

Getting wild

Getting wild

Camera: Canon EOS 5D Mark III
Aperture: ƒ/8
Shutter speed: 1/40s
Focal length: 40mm
ISO: 160
Taken: 15 December, 2012
Location: 55° 1.1816′ 0″ N 1° 25.2762′ 0″ W

I like the subtle colours of the clouds in this one.

Yes, it’s another new look

One of the things that interested me about WordPress 3.5 was the new default theme, Twenty Twelve. This has a minimalist look with a distinct lack of images, some quite tasty typography, and most importantly for my purposes, the option of a full-width layout.

I knew I’d need to make a couple of changes to get it the way I wanted, but as this can be done with a simple child theme, I decided to give it a try. One alteration was to make the footer widgets appear on every page – this needed one line of code, so it was simple enough even for me. I copied footer.php to my child theme and changed this:

<!-- #main .wrapper -->
<footer id="colophon" role="contentinfo">

to this:

<!-- #main .wrapper -->
<footer class="template-front-page two-sidebars"><?php get_sidebar( 'front' ); ?>
</footer>
<footer id="colophon" role="contentinfo">

That <footer…> was needed to get the styles right. Without it, the footer widgets ended up piled up on the right of the screen.

I also moved the block that shows the date of each post from the bottom to the top – and that was a simple cut and paste job. Admittedly, it does leave a section at the head of the post being called a footer, but I can live with that.

At that point, I thought I’d got it. But then I happened to look at an old post that had something like this in it:

Note: It’s really important not to break old stuff when you do something new.

Instead of showing up in a nice box like that, it was just plain text. It was at that point that I recalled that I’d replaced my previous simple styles with the nifty buttons and shortcodes provided by the excellent Graphene theme that I’d been using. Now themes that provide functions like this are generally a Good Thing, but if you ever decide to go for a new look, it can be a bit of a pain to fix things. But I was in the mood to do some research, so I looked through the files of the Graphene theme and worked out how it was adding the buttons to the post editor (something I’ve failed to get my head around in the past) and how the buttons inserted the shortcodes, and finally, how the shortcodes get translated into nicely formatted blocks.

I spend some time fiddling with that on my test site[1] and eventually added a modified version of the code to my Functionality Plugin, together with the JavaScript that talks to the TinyMCE editor, and the little icons. The only remaining bit was copying the CSS to get the appearance right. Now I’ve done that, I can adapt this for other buttons, or indeed change these to look completely different.

For the benefit of anyone wanting to try this, here’s the code for adding the shortcodes:

function warning_block_shortcode_handler( $atts, $content= NULL, $code = '' ) {
    return '<div class="warning_block message-block">' . do_shortcode( $content ) . '</div>';
}
add_shortcode( 'warning', 'warning_block_shortcode_handler' );

function error_block_shortcode_handler( $atts, $content= NULL, $code = '' ) {
    return '<div class="error_block message-block">' . do_shortcode( $content ) . '</div>';
}
add_shortcode( 'error', 'error_block_shortcode_handler' );

function notice_block_shortcode_handler( $atts, $content= NULL, $code = '' ) {
    return '<div class="notice_block message-block">' . do_shortcode( $content ) . '</div>';
}
add_shortcode( 'notice', 'notice_block_shortcode_handler' );

function important_block_shortcode_handler( $atts, $content = NULL, $code = '' ) {
    return '<div class="important_block message-block">' . do_shortcode( $content ) . '</div>';
}
add_shortcode( 'important', 'important_block_shortcode_handler' );

/**
 * Hook the shortcode buttons to the TinyMCE editor
*/
class LCB_Shortcodes_Buttons{

	function LCB_Shortcodes_Buttons(){
		if ( current_user_can( 'edit_posts' ) &&  current_user_can( 'edit_pages' ) ) {
			add_filter( 'mce_external_plugins', array(&$this, 'lcb_add_plugin' ) );
			add_filter( 'mce_buttons_2', array(&$this, 'lcb_register_button' ) );
	   }
	}

	function lcb_register_button( $buttons ){
		array_push( $buttons, "separator", "warning", "error", "notice", "important");
		return $buttons;
	}

To avoid things clashing, I changed the function and class names to have my initials at the start. This makes it easier to see what’s going wrong. However, because I needed the shortcode names to be the same as before, there was a problem running this code with the Graphene theme active, so watch out for that.

And here’s the JavaScript that adds buttons to the editor:

(function() {
	tinymce.create('tinymce.plugins.lcbShortCodes', {
		init : function(ed, url) {

			ed.addButton('warning', {
				title : ed.getLang('lcbshortcodes.warningtitle', 'Add a warning message block'),
				image : url+'/warning.png',
				onclick : function() {
					 ed.selection.setContent('
' + ed.selection.getContent() + '
'); } }); ed.addButton('error', { title : ed.getLang('lcbshortcodes.errortitle', 'Add an error message block'), image : url+'/error.png', onclick : function() { ed.selection.setContent('
' + ed.selection.getContent() + '
'); } }); ed.addButton('notice', { title : ed.getLang('lcbshortcodes.noticetitle', 'Add a notice message block'), image : url+'/notice.png', onclick : function() { ed.selection.setContent('
' + ed.selection.getContent() + '
'); } }); ed.addButton('important', { title : ed.getLang('lcbshortcodes.importanttitle', 'Add an important message block'), image : url+'/important.png', onclick : function() { ed.selection.setContent('
' + ed.selection.getContent() + '
'); } }); }, createControl : function(n, cm) { return null; }, }); tinymce.PluginManager.add('lcbshortcodes', tinymce.plugins.lcbShortCodes); })();

This will all work so long as the JavaScript file and the image files are in the same folder as the plugin. If you move it somewhere else, you’ll need to change the paths in the code.

Finally, here’s the CSS for the boxes:

.message-block {
	border-radius: 4px;
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
	padding: 5px 10px 5px 50px;
	background: #eee;
	margin: 10px 0 0;
	min-height: 35px;
	overflow: auto;
}

.message-block p.first-p {
	margin-top: 0;
}

.warning_block,
.error_block {
	background: #FCC url(/wordpress/wp-content/plugins/losingit-functionality-plugin/warning.png) no-repeat scroll 10px 7px;
	border: 1px solid #F99;
	color: #C31B00;
}

.error_block {
	background-image: url(/wordpress/wp-content/plugins/losingit-functionality-plugin/error.png);
}

.notice_block {
	background: #FDEBAE url(/wordpress/wp-content/plugins/losingit-functionality-plugin/notice.png) no-repeat scroll 10px 7px;
	border: 1px solid #E6C555;
	color: #9E660D;
}

.important_block {
	background: #DEE3AB url(/wordpress/wp-content/plugins/losingit-functionality-plugin/important.png) no-repeat scroll 10px 7px;
	border: 1px solid #A3C159;
	color: #5E6F33;
}

And yes, I have spent a lot of time on this over this weekend, but it was fun in and odd sort of way. It was satisfying to be able to find solutions to the problems I had with this and the EXIF matter I mentioned earlier. I’m still nowhere near being an actual coder, but I do occasionally get a little less distant.

[1] It’s always a good idea to have a test site for this kind of thing. I broke it several times while testing. I found the web server’s error logs very helpful in pointing out my mistakes.

EXIF Again

Earlier this year, I talked about how I’d persuaded WordPress to automagically fill in some fields for me when I upload pictures. I was moderately pleased with the results, but the formatting of EXIF data was a bit restricted by the way it was being inserted as part of the image caption. I’d probably have let it go, but the recently released WordPress 3.5 has a shiny new form for uploading images, and in the finest tradition of shiny new things, it broke my bit of borrowed and tweaked code.

In particular, it had stopped filling in the Alternative text field in the form. I tried a few basic tweaks, which helpfully inserted a new field in the form with the data, which wasn’t quite what I wanted at all. So I did some reading, and found where the text was being stored[1], and how to change it. Woo, hoo, etc.

And since I was doing some tweaking anyway, I wondered if I could put the EXIF data in that Description box and leave the Caption to be, well, the caption. I soon found that I could, and ended up with a new function (which you will note is simpler than the mess of code I had previously):

add_action( 'add_attachment', 'lcb_populate_image_fields' );
function lcb_populate_image_fields($id) {
$attachment = & get_post( $id, ARRAY_A );
if ( !empty( $attachment ) ) {
$attachment['post_excerpt'] = $attachment['post_title'];
$attachment['post_content'] = '[exif id="' . $id .'"
    show="camera,aperture,iso,shutter,focus,location,time"]';
update_post_meta($id,'_wp_attachment_image_alt', $attachment['post_title']);
wp_update_post($attachment);
}
}

Which will fill in the boxes based on the title of your image, or the filename if it doesn’t have an actual EXIF Title:

Attachment

Attachment

The next question was how to actually insert that Description into my posts. Once again, a bit of reading turned up some examples, which looked reasonable enough, but didn’t actually work as expected. The way to do it is to replace the standard Caption shortcode function with your own, which is the kind of thing WordPress makes nice and simple. The trouble was that the examples I’d seen were based on an older version of WordPress, and were therefore breaking. It was a reasonably simple matter to copy the standard function, which lives in media.php in the wp-includes folder, and add in the extra code to insert the description. Like the other code, I put this in my own Functionality Plugin rather than in any theme’s functions.php – this means the code will always work even if I change themes for any reason. So here’s that modified shortcode function:

add_shortcode('wp_caption', 'custom_img_caption_shortcode');
add_shortcode('caption', 'custom_img_caption_shortcode');

function custom_img_caption_shortcode($attr, $content = null) {
	if ( ! isset( $attr['caption'] ) ) {
        	if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
			$content = $matches[1];
			$attr['caption'] = trim( $matches[2] );
		}
	}

	// Allow plugins/themes to override the default caption template.
	$output = apply_filters('img_caption_shortcode', '', $attr, $content);
	if ( $output != '' )
		return $output;

	extract(shortcode_atts(array(
		'id'	=> '',
		'align'	=> 'alignnone',
		'width'	=> '',
		'caption' => ''
	), $attr));

	if ( 1 > (int) $width || empty($caption) )
		return $content;

// Grab ID to query post_content [description] field for image
	preg_match('/([\d]+)/', $id, $matches);

	$description = '';
	if ($matches[0]) {

		global $wpdb;
		$custom_description = $wpdb->get_row("SELECT post_content FROM $wpdb->posts WHERE ID = {$matches[0]};");

		if ($custom_description->post_content) {

			$description = '<div class="wp-custom-description">'. $custom_description->post_content . '</div>';

		}
	}

	if ( $id ) $id = 'id="' . esc_attr($id) . '" ';

	return '<div ' . $id . 'class="wp-caption ' . esc_attr($align) . '" style="width: ' . (10 + (int) $width) . 'px">'
	. do_shortcode( $content ) . '<p class="wp-caption-text">' . $caption . '</p></div>' . $description;
}

Then it was just a matter of fiddling with some custom CSS to make it look nice. I decided to slightly adapt some existing CSS that I’ll mention in another post. I fiddled around a bit until I got something that looks reasonable. I put this in the Custom CSS section of the Jetpack plugin rather than in the theme’s style.css for reasons I’ll explain later:

.exif {
	display: block;
	margin: 0 auto 5px;
	border-radius: 4px;
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
	padding: 5px 10px;
	background: #eee;
	width: 400px;
	font-size: 80%;
	color: #333;
}

p.wp-caption-text {
	margin-bottom: 5px;
}

So there it is. Any images I upload have their EXIF data inserted in a nice block below the caption. Now I just have to tidy up older posts to make them consistent. I’ve only got about 200 of those to do…

[1] All the other bits – Title, Caption and the optional Description are stored as part of the record for the image attachment, which is a special kind of post. But the Alt text is stored as metadata in a separate table. There’s probably a Good Reason for that, but I don’t know what it is offhand.