Mar 15 2008

How to highlight code in WordPress

Tag: Chili, EnzymesAndrea Ercolino @ 01:48:47

WordPress Editing Tabs

Although it’s easy to use WP Chili out of the box, WordPress does have some limitations, like the following:

  • you need to change to the Code editor before adding a snippet to your post
  • you need to make your snippet postable yourself, escaping all HTML entities
  • even if snippets are very short, they are intermingled with their explanations and it’s tricky to concentrate on writing the best post with so many distractions in between

Using WP Chili & Enzymes

Now I’ll show you a better approach by using together WP Chili 1.0 and Enzymes 2.2.
All you need to be up and running is the classical roundtrip: download, unzip, upload, and activate.

How to highlight code snippets

You can start by writing a simple enzyme for automating things, like the following hilite custom field:

return 
'<pre><code class="' . $this->substrate . '">'
. htmlspecialchars( $this->pathway ) 
. '</code></pre>';

hilite can be used with the following patterns:

  1. {[ =snippet= | .hilite( =language= ) ]}
  2. {[ .snippet | .hilite( =language= ) ]}

The first pattern comes in handy when you want to highlight some very short and naive snippet
{[ =echo htmlentities( $name );= | .hilite( =php= ) ]} renders

echo htmlentities( $name );

So far, so good, but if the snippet has a character that WP texturizes, then hilite seems to fail. In fact
{[ =$welcome \= "Hello ".$name;= | .hilite( =php= ) ]} renders

$welcome = "Hello ".$name;

The above issue is not a hilite’s bug but it could be fixed by adding new code to it, or with new enzymes along the pathway, like the following requote custom field:

$from = array( '&#8216;', '&#8217;', '&#8220;', '&#8221;' );
$to = array( "'", "'", '"', '"' );
return str_replace( $from, $to, $this->pathway );

which makes that
{[ =$welcome \= "Hello ".$name;= | .requote() | .hilite( =php= ) ]}
renders

$welcome = "Hello ".$name;

The best option is to add another custom field for hosting your snippet and use the second pattern: in fact hilite’s snippet has been rendered by {[ .hilite | .hilite( =php= ) ]} and requote’s one by {[ .requote | .hilite( =php= ) ]}.

How to highlight code files

Sometimes you have a file that you want to show in its entirety, and having to copy it into a custom field is annoying or maybe not an option, if the file is alive, for example.

In such cases you can use an enzyme like the following file custom field:

return file_get_contents( $this->substrate );

It’s use is again very simple and very similar to the above patterns:
{[ .file( =blog/wp-content/plugins/hello.php= ) | .hilite( =php= ) ]} renders

<?php
/*
Plugin Name: Hello Dolly
Plugin URI: http://wordpress.org/#
Description: This is not just a plugin, it symbolizes the hope and enthusiasm of an entire generation summed up in two words sung most famously by Louis Armstrong: Hello, Dolly. When activated you will randomly see a lyric from <cite>Hello, Dolly</cite> in the upper right of your admin screen on every page.
Author: Matt Mullenweg
Version: 1.5
Author URI: http://ma.tt/
*/

// These are the lyrics to Hello Dolly
$lyrics = "Hello, Dolly
Well, hello, Dolly
It's so nice to have you back where you belong
You're lookin' swell, Dolly
I can tell, Dolly
You're still glowin', you're still crowin'
You're still goin' strong
We feel the room swayin'
While the band's playin'
One of your old favourite songs from way back when
So, take her wrap, fellas
Find her an empty lap, fellas
Dolly'll never go away again
Hello, Dolly
Well, hello, Dolly
It's so nice to have you back where you belong
You're lookin' swell, Dolly
I can tell, Dolly
You're still glowin', you're still crowin'
You're still goin' strong
We feel the room swayin'
While the band's playin'
One of your old favourite songs from way back when
Golly, gee, fellas
Find her a vacant knee, fellas
Dolly'll never go away
Dolly'll never go away
Dolly'll never go away again";

// Here we split it into lines
$lyrics = explode("\n", $lyrics);
// And then randomly choose a line
$chosen = wptexturize( $lyrics[ mt_rand(0, count($lyrics) - 1) ] );

// This just echoes the chosen line, we'll position it later
function hello_dolly() {
	global $chosen;
	echo "<p id='dolly'>$chosen</p>";
}

// Now we set that function up to execute when the admin_footer action is called
add_action('admin_footer', 'hello_dolly');

// We need some CSS to position the paragraph
function dolly_css() {
	echo "
	<style type='text/css'>
	#dolly {
		position: absolute;
		top: 2.3em;
		margin: 0;
		padding: 0;
		right: 10px;
		font-size: 16px;
		color: #d54e21;
	}
	</style>
	";
}

add_action('admin_head', 'dolly_css');

?>


Mar 14 2008

WP Chili Released

Tag: ChiliAndrea Ercolino @ 23:04:20

A couple of days ago I released WP Chili, a simple WordPress plugin that installs Chili into WordPress and let’s you add client-side code highlighting to your posts, with extreme simplicity.

After activating WP Chili, it’s just a matter of wrapping your snippets into code or pre-code elements, with the programming language of the snippet as a class, like in the following example:

<pre><code class="php">
echo &quot;Hello $name&quot;;
</code></pre>

When the post reaches your readers, the snippet is unescaped by their browser and highlighted by Chili 1.9 (downloaded from your server). Your readers will see the example rendered as:

echo "Hello $name";


Mar 01 2008

Enzymes 2.2 Released Today

Tag: EnzymesAndrea Ercolino @ 15:59:46
Changes
  • Added the new feature for transcluding a value, rather than a post/key reference to it (which is still available). This comes in handy when you have a “normal” value and it’s a bit annoying to define a custom field just for that.

For example, let’s say that you have a template called mark-template.php with the following code:

<span style="background-color:<?php echo $this->enzyme; ?>;">
	<?php 
		echo $this->pathway; 
		$this->pathway = ''; 
	?>
</span>

Then you could use it {[ =like this= | =cyan= \mark-template.php ]} to get something like this

Download

This version is available for download from wordpress.org


Feb 24 2008

Enzymes 2.1 Released Today

Tag: EnzymesAndrea Ercolino @ 18:51:27
Changes
  • Added the new feature for passing a value as an argument to an evaluation enzyme, rather than a post/key reference to it (which is still available). This comes in handy when you have a “normal” value and it’s a bit annoying to define a custom field just for that.

For example, let’s say that you have a custom field with the key mark and the following value:

return 
	'<span style="background-color:yellow;">' 
		. $this->substrate 
	. '</span>';

Then you could use it {[ .mark( =like this= ) ]} to get something like this

Download

This version is available for download from wordpress.org


Dec 09 2007

HotChili 1.2 Released Today

Tag: Chili, HotChiliAndrea Ercolino @ 17:33:59
Changes
Known Issues
  • Sometimes a website (http://developer.mozilla.org) uses an old version of Prototype that makes jQuery fail even if jQuery.noConflict() is used.
  • Sometimes a browser (IE7) cannot load all needed modules in the given sequence, and you get some JavaScript errors.
    Fix: reload the page and click the bookmarklet again (now the modules will be loaded from your browser cache).

Nov 25 2007

HotChili as a Bookmarklet

Tag: Chili, HotChiliAndrea Ercolino @ 03:33:52

HotChili is now this bookmarklet: HotChili.

Previous release was for Firefox plus GreaseMonkey, but as a bookmarklet you can use it from any browser.

Known issues

Sometimes a browser (IE) cannot load all needed modules in sequence, and you get some javascript errors. The simple fix is to reload the page and click the bookmarklet again. From now on the modules should be available in the browser cache.


Nov 24 2007

WordPress Rendering Troubles

Tag: FixingAndrea Ercolino @ 23:41:59

WordPress has many helpers that allow authors to write down some text and have it nicely formatted for their readers, without having to care about HTML issues. It’s a great job, but sometimes it doesn’t do the right thing.

This bug affects content and custom fields, which means that it’s more of a conceptual bug than a coding bug. I wrote an article with a workaround for the content. Now, let’s see a simple fix for custom fields.

I’ll describe both problems I detected and give a solution based on changing some WordPress code. I know it’s not a perfect solution, but it works and it’s also relatively easy. In the snippets you’ll see the code as it’s supposed to get changed to. (with 3 lines of context before and after changed lines, each preceded by a //noteslog.com comment)

Wordpress Version: 2.3.1

Problem: HTML Entities Conversion

Custom fields that have HTML entities in their key or value are treated by WordPress weirdly. Frustration will appear soon after realizing that WordPress won’t return what you put in before.

If I write &para; inside the visual editor of a post, WordPress should assume that I want to visualize &para;. In fact it will pretend to do the right thing the first time I save the post. All subsequent times it will show a where I put a &para;.

If I write &para; inside the code editor of a post, WordPress should assume that I want to visualize , and it does the right thing (sort of, because I now have a inside the code too).

If I write &para; inside a custom field’s key or value, WordPress should assume that I want to visualize for my readers, and &para; for myself when I’m authoring the custom field. In fact Wordpress does the wrong thing here again, because it’ll immediately convert &para; to .

Solution

This fix requires changing four lines in two files. We’ll use the PHP function htmlspecialchars in place of the WordPress function attribute_escape. After the fix, filters for “attribute_escape” won’t get applied to custom fields keys and values. (this shouldn’t be a problem)

Open: wp-admin/admin-ajax.php
Search: function wp_ajax_meta_row

add_action( 'shutdown', 'get_out_now', -1 );

function wp_ajax_meta_row( $pid, $mid, $key, $value ) {
//noteslog.com
	$value = htmlspecialchars( $value ); //attribute_escape($value);
	$key_js = addslashes(wp_specialchars($key, 'double'));
//noteslog.com
	$key = htmlspecialchars( $key ); //attribute_escape($key);
	$r .= "<tr id='meta-$mid'><td valign='top'>";
	$r .= "<input name='meta[$mid][key]' tabindex='6' onkeypress='return killSubmit(\"theList.ajaxUpdater(&#039;meta&#039;,&#039;meta-$mid&#039;);\",event);' type='text' size='20' value='$key' />";
	$r .= "</td><td><textarea name='meta[$mid][value]' tabindex='6' rows='2' cols='30'>$value</textarea></td><td align='center'>";

Open: wp-admin/includes/template.php
Search: function list_meta

}

		$key_js = js_escape( $entry['meta_key'] );
//noteslog.com
		$entry['meta_key']   = htmlspecialchars($entry['meta_key']);//attribute_escape($entry['meta_key']);
//noteslog.com
		$entry['meta_value'] = htmlspecialchars($entry['meta_value']);//attribute_escape($entry['meta_value']);
		$entry['meta_id'] = (int) $entry['meta_id'];
		$r .= "\n\t<tr id='meta-{$entry['meta_id']}' class='$style'>";
		$r .= "\n\t\t<td valign='top'><input name='meta[{$entry['meta_id']}][key]' tabindex='6' type='text' size='20' value='{$entry['meta_key']}' /></td>";

Problem: White Space Trimming

Custom fields that begin or end with white space in their key or value are trimmed. I can undestand that a key is more easily dealt with if it is trimmed before saving it into the database. But values should definitely retain all their white space AS IS.

Solution

This fix requires changing four lines in three files. We’ll add a $trim parameter to the wordpress function maybe_serialize, by default set to true. Wherever we do not want a $data value trimmed, we’ll call maybe_serialize with a false second argument.

Open: wp-includes/functions.php
Search: function maybe_serialize

return true;
}

//noteslog.com
function maybe_serialize($data, $trim=true) { //($data)
//noteslog.com
	if ( $trim && is_string($data) ) //( is_string($data) )
		$data = trim($data);
	elseif ( is_array($data) || is_object($data) )
		return serialize($data);

Open: wp-admin/includes/post.php
Search: function add_meta

$metakeyselect = $wpdb->escape( stripslashes( trim( $_POST['metakeyselect'] ) ) );
	$metakeyinput = $wpdb->escape( stripslashes( trim( $_POST['metakeyinput'] ) ) );
//noteslog.com
	$metavalue = maybe_serialize( stripslashes( ( $_POST['metavalue'] ) ), false ); //( stripslashes( trim( $_POST['metavalue'] ) ) );
	$metavalue = $wpdb->escape( $metavalue );

	if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) {
		// We have a key/value pair. If both the select and the

Open: wp-admin/includes/post.php
Search: function update_meta

if ( in_array($mkey, $protected) )
		return false;

//noteslog.com
	$mvalue = maybe_serialize( stripslashes( $mvalue ), false ); //( stripslashes( $mvalue ) );
	$mvalue = $wpdb->escape( $mvalue );
	$mid = (int) $mid;
	return $wpdb->query( "UPDATE $wpdb->postmeta SET meta_key = '$mkey', meta_value = '$mvalue' WHERE meta_id = '$mid'" );


« Previous PageNext Page »