WordPress: create a widget using code from a plugin class

I’m writing a new WordPress plugin: an audio player written atop the marvellous jPlayer. I wanted to give the user the option to add the audio player via a widget, but as my plugin was written OOP I wasn’t really sure how to register the widget using code from my plugin.

It turns out it wasn’t particularly difficult, but I couldn’t find any documentation about it online, so I figured I’d write this wee post, in the hope that it might come in useful for my fellow WordPressers!

My plugin code is written in OOP:

class MyCoolPlugin {
// All my methods + properties here
}
// Instantiate the class
$cool_plugin = new MyCoolPlugin();

The class contains a method to create the HTML that I want to use for both a shortcode and a widget.

class MyCoolPlugin {
  // Returns the HTML for a shortcode or widget
  function shortcode_widget() {
    return '<p>HTML rocks</p>';
  }
}
// Instantiate the class
$cool_plugin = new MyCoolPlugin();

Register my widget:

class CoolWidget extends WP_Widget {
  function CoolWidget() {
    // Instantiate the parent object
    parent::__construct( false, 'Cool Widget' );
  }
}

Then I can add the HTML from the shorcode_widget method of MyCoolClass like so:

class CoolWidget extends WP_Widget {
  function CoolWidget() {
    // Instantiate the parent object
    parent::__construct( false, 'Cool Widget' );
  }
  function widget($args, $instance) {
    // reuse my plugin's code
    global $cool_plugin;
    echo $cool_plugin->shortcode_widget();
  }
}

Nice. Saves me writing a bunch of code multiple times, which I guess is the main point of OOP!

JavaScript: how to select the first word(s) in a sentence

Recently I had to figure out a way to select the first 2 words in a sentence using JavaScript. I wanted to wrap them in a class so that I could give them some additional CSS styling. I figured it’d be mad easy, but it took a little bit of head scratching until I figured out at least one way to do it.

I’ve got an HTML element with an ID of ‘niceText’ that I’m looking to grab. I’ll save the string as a variable called ‘niceText’.

var niceText = $('#niceText').text();

I’ll also save the opening and closing spans I’m going to wrap the text in as variables like so:

var openSpan = '<span class="grey">', closeSpan = '</span>';

Next, we’ll use the native JavaScript split method. This makes an array out of a string – all you have to do is to specify the separator that’ll be used to divide the string. In this case the separator is a blank space, so we can write:

niceText = niceText.split(' ');

Our variable ‘niceText’ is now an array of strings (go ahead and use your console to take a peek at what’s happened to our variable).

Next we’ll add the span to the start of the array using the unshift method. It you’ve ever used the push method, this is very similar except that it adds elements to the beginning of the array instead of to the end.

niceText.unshift( openSpan );

Fab. We now need to add the closing span to the array. We can do this with the splice method. If you’re not sure how this method works, do have a good read of the docs as it can come in super handy when performing array surgery!

As I want to wrap the first 2 words in my sentence, I’m going to add the closing span as the 4th item in the array. The first item is now my opening span, then comes the two opening words, then my closing span. The second value in splice indicates how many values, if any, to remove from the array. We’re not removing any, just adding, so this will be equal to 0.

niceText.splice( 3, 0, closeSpan );

Next I’ll turn the array back into a string using join. Like split, join accepts a value for the separator, only this time, the separator is what will be printed between every array item. As this is just a sentence, we want to add a space between the words, so we can write:

niceText = niceText.join(' ');

Finally I’ll add the string to my HTML element like so:

$('#niceText').html( niceText );

That’s it! Here’s the whole function.

jQuery( function($){

   /* Get the text of the element I'm after */
   var niceText = $('#niceText').text(),
      openSpan = '<span class="grey">', closeSpan = '</span>';

   /* Make the sentence into an array */
   niceText = niceText.split(' ');

   /* Add span to the beginning of the array */
   niceText.unshift( openSpan );

   /* Add  as the 4th value in the array */
   niceText.splice( 3, 0, closeSpan );					

   /* Turn it back into a string */
   niceText = niceText.join(' ');					

   /* Append the new HTML to the header */
   $('#niceText').html( niceText );

});

If you’re not already using jQuery in your site, it might be a bit much to add it for just this tiny function! Rather, you can simply replace

var niceText = $('#niceText').text();

with

var niceText = document.getElementById('niceText').textContent;

and

$('#niceText').html( niceText );

with

document.getElementById('niceText').innerHTML = niceText;

Grand stuff. Hope it comes in useful!

How to split your WordPress posts into two columns

The other day, whilst merrily making a website for an ensemble called Tesserae, I needed to figure out how to display my posts in 2 columns, side by side. In this case, the posts were a custom post type biographies that I used to display the various members biographies on the site.

It wasn’t hard to do, here’s the code I used to display half of the posts:

<?php // Get the number of posts in the custom post type 'biographies'
$count = wp_count_posts( 'biographies' ); ?>

Let’s say the total number of posts is 7.

<?php // Divide the number of published posts by 2 and round up in case we get a fraction
$num_biogs = ceil( $count->publish / 2 ); ?>

This would give us 4. We must round up this number otherwise, we’d get 3.5 and that’s no good!

<?php // Now use this number for the showposts parameter in our query
$biogs = new WP_Query( 'post_type=biographies&showposts=' . $num_biogs );
while ( $biogs->have_posts() ) : $biogs->the_post();
// the_title(); the_content(); etc
endwhile; wp_reset_query(); ?>

And the remaining posts:

<?php // Now use the variable $num_biogs as the offset parameter in another query
$biogs = new WP_Query( 'post_type=biographies&showposts=-1&offset=' . $num_biogs );
while ( $biogs->have_posts() ) : $biogs->the_post();
// the_title(); the_content(); etc
endwhile; wp_reset_query(); ?>

Obviously this is only the PHP, and you’re going to need some HTML there to actually use this! I just floated a couple of <div>s side by side, then popped the first block of code inside the left-hand <div> and the 2nd chunk in the 2nd <div>.

You can see the finished product at http://tesserae-la.com/who/

jQuery mobile events firing multiple times and what to do about it

I’m currently working on my very first iPhone app. I decided I’d build it in HTML5, CSS3, JavaScript and wrap it up all cosy and warm with the amazing PhoneGap. I also decided early on to use jQuery mobile as my framework for the project, because I’m so familiar with jQuery itself. It’s been quite a ride so far and I’ve learnt a LOT!

I soon found out that dynamic content and jQuery mobile is not the easiest of pairings, but I think I’ve found a good solution to the most common problems I encountered and figured it’d be cool to share them with whomsoever might have a use for them.

One of the issues I found with my code early on was that on subsequent visits to a page, events would be fired an increasing number of times. What was happening was that I was binding events to the pagebeforeshow event – I though I had to this, because most of the content I was adding to the page was dynamic and would be updated on subsequent page visits. I did this:

$('#my-page').bind('pagebeforeshow', function(){
  // Add dynamic stuff to the page here, then...
  $('input').bind('change', function(){
    // Do something when this happens
  });
});

This worked for the dynamic content, although I still had to remove my inserted content on pagehide as jQuery mobile saves the page in memory, which drove me to the brink of madness on more than one occasion, but hey. On change, the input event was duly triggered on my first visit to the page (and only once, as I expected), but on my second visit to the page, the event was triggered twice, then 3 times etc. Eek!

The solution was not difficult, it just took a while to figure out. I still added my dynamic stuff to the page using the pagebeforeshow event, but I just added the event listener for my input to pageinit instead. As most of the event listeners were bound to elements that were inserted dynamically, I had to use live instead of bind. In the end my code looks something like this:

$('#my-page').bind('pagebeforeshow', function(){
  // Add dynamic stuff to the page here
}).bind('pageinit', function(){
  $('input').live('change', function(){
    // Do something when this happens
  });
});

That solved it. I might detail how I add and remove dynamic content to the page using pagebeforeshow and pagehide. If it might be of use to anyone, do let me know if so!

A suggested fix for the dreaded FOUT

As a keen typography fan I tend to rely heavily on the use of web fonts for my sites. I generally use Typekit to deliver my fonts, but it does tend to take a little while for the browser to download and display my beautiful fonts.

I noticed that if I simply place the typkit required script tags in the header of my site, it will block my site from loading until the font(s) have been downloaded, leaving visitors with a blank screen for a second or so. With a fast connection it’s not the end of the world in my book, but recently I tried experimenting a little with how to minimize this inconvenience to the user.

First, I tried putting the typekit script tags in the footer of my document, instead of the header. This stopped the delay in the site from loading, but it also caused a ‘Flash of Un-styled Text’ (or FOUT for short), where the fallback font(s) were shown as the web fonts were being downloaded. This can look really messy, especially if you’re using fonts for which there isn’t really any suitable fallback.

It’s a common problem and I’ve seen a couple of solutions offered, but I came up with what I think is quite an elegant solution.

Typekit fonts are delivered via JavaScript that provide event listeners that can tell you whether a font is active, is loading, is inactive or has been loaded. Typekit suggest a solution on their blog at http://blog.typekit.com/2010/10/29/font-events-controlling-the-fout/, but the loading of your site can still be delayed as you wait for the fonts to download and if you put the script tags in your footer, you can still suffer the FOUT. Blurgh.

My solution is to (and bear with me here before you scream ‘but what if JavaScript is disabled!’) hide all the text elements in my CSS by setting their opacity to 0, so as to completely avoid any FOUT. I do this like so:

h1, h2, h3, h4, h5, h6, p, ul, ol, dl, span, a {
opacity: 0;
-webkit-transition: opacity 0.4s ease-in;
-moz-transition: opacity 0.4s ease-in;
-o-transition: opacity 0.4s ease-in;
transition: opacity 0.4s ease-in;
}

Obviously you may well have more elements of text that should be hidden, such as blockquotes, cites etc. I’ve also added some CSS3 transitions, so that when the web fonts have finished loading they’ll fade in smoothly (this in itself is really quite a nice effect) rather than just being spat out! I then added the following to my CSS:

.wf-active h1, .wf-active h2, .wf-active h3, .wf-active h4, .wf-active h5, .wf-active h6, .wf-active p, .wf-active ul, .wf-active ol, .wf-active dl, .wf-active span, .wf-active a {
opacity: 1;
}

The .wf-active class is added to the <html> tag of my document via JavaScript when the font has finished loading. If we set the opacity here to 1 then our web fonts will be displayed and not our fallback fonts.

The problem with this method is obviously that it relies on JavaScript. If users view the site with JavaScript disabled, the wf-active class won’t be added to the <html> tag and the fonts will remain invisible. My solutions is to add the following to my document head after our other CSS files have been included.

<noscript><style>h1, h2, h3, h4, h5, h6, p, ul, ol, dl, span, a {
opacity: 1;
} </style></noscript>

This will overwrite our previous declaration where we set the opacity to 0 and therefore make our fallback fonts visible to the user without JavaScript.

The other problem with this method if the Typekit fonts are not available, or if the browser does not support web fonts. In this case, you could also use the .wf-inactive class which Typekit adds to the <html> tag in either of these cases and set the opacity to 1 like so:

.wf-inactive h1, .wf-inactive h2, .wf-inactive h3, .wf-inactive h4, .wf-inactive h5, .wf-inactive h6, .wf-inactive p, .wf-inactive ul, .wf-inactive ol, .wf-inactive dl, .wf-inactive span, .wf-inactive a {
opacity: 1;
}

As far as I can see this pretty much covers all bases, but I may well have missed something here and am very happy to have this pointed out to me!