Where I’ve Been + Redesign

Apr 25, 2009

News

2 Comments

I feel sorry for my poor blog. As new things piled up, I put him to the side and forgot to update him. I didn’t exactly forget about him, I just didn’t have the time to pay any attention to him.

So, where exactly have I been? Well, for one, I’ve been busy with school. It’s getting near the end of the semester, so coursework is getting more compressed. Also, I’ll be starting finals soon. I’m also working more. Besides my work at LSU ITS, I’ve started freelancing for the Gatorworks crew. Additionally, my company recently released the Baton Rougean. It’s a hyperlocal news site for my hometown. For our first site, I’m pretty proud of what it’s become so far. I’ve been doing a lot of writing over there, so if you really just want to read my writing, I recommend subscribing.

To make it up to my blog, I spent last night redesigning it. The last theme was becoming too cluttered and deviated far from the minimalism that I had envisioned. This time, I stuck to my vision and thus named this theme “clean.” It’s nice and simple, yet really intelligent. I really like how it turned out. There are two important milestones that I hit in this theme. Starting web developing for an actual web design firm really pushed me to finally learn Photoshop. I’ve put if off all this time because I’d rather just code. This made me a lot better at HTML and CSS, but ultimately I feel behind my peers because I just couldn’t use it. But at the behest of Mr. Chase Swindler, I finally learned, so this design was done entirely in Photoshop. The second milestone is that it validates in strict XHTML. Of course I need a disclaimer on that because Wordpress markup is weird and on some pages it won’t be. However, the overall design does. And so does the CSS. Plus, it works in every major browser from IE 5.5, which was a bet I took up with Bryan Culver. Overall, I’m satisfied with the design. Like I said, nice and clean. (On a side note, I made the Wordpress comment form validate strict XHTML, which took a little time, but it works. I’ll post the code at a later date.)

In any case, I’ll be finishing the school year soon, so you’ll likely see more overall activity from me.

How to: Build and Extend a Wordpress Lifestream

Dec 26, 2008

Tutorial

8 Comments

Introduction

Recently, I reinstalled Wordpress and began blogging again.  Initially, I didn’t add many plugins—just the basics.  Since then, I’ve gone back and added some very cool and important ones.  I’ll blog about the full list and my choices thereof later.  But now, I want to highlight one plugin: wp-Lifestream by iBegin.  It creates a simple “lifestream,” which is a stream of one’s activity across different social networks.  My lifestream can be viewed here.

Wordpress Lifestream with wp-Lifestream Plugin

Wordpress Lifestream with wp-Lifestream Plugin

I looked into a couple different ways to create this lifestream, but this plugin offered the best option by far.  For one, it’s something that I didn’t have to build myself.  I could’ve easily rolled a solution using all of the APIs, but that’s kind of sloppy and certainly not elegant—at least not like this.  Secondly, it integrates with Wordpress and is fast and efficient.  Plus, I really liked the way it created the stream, so very few customization was necessary.  What also impressed me was its extensibility.  It has a built-in framework for adding new feeds.  I found that most of the websites I used were already included, but I came across two that weren’t included: Readernaut and ScrnShots.  I decided to dive right in and build these two plugins.  Since the documentation was kind of confusing—at least for me—I decided to write another step-by-step guide.  Each feed had a different solution, so I’ll walk you through each.  As my Christmas present to you, I’ve also included for download my feeds.inc.php file (this is the file we’ll be appending to activate these new sites) at the end of this post, which you are free to use.

Note: I use the word “plugin” to refer to wp-Lifestream.  wp-Lifestream uses the word “plugin” to refer to the feed modules, which I refer to as extensions.  This seemed to be more apt and I hope this clarifies more than it confuses.

Readernaut

Introduction

Readernaut is a social network for readers.  You can add books you’ve read, are reading, and want to read.  Moreover, you can make and share lists of books.  You can also make recommendations and interact within the community.  I think the succinct description on their homepage is the best: “Readernaut is my library, my notebook, my book club.”1  It’s currently in beta, but I highly recommend it for any avid reader.  You can sign up for an invite on their homepage.  If you’re a member, add me as a friend.

Extension

Readernaut offers a RSS feed to syndicate when you add a book to your library.  It’s formatted with the date, title of the book, and an image of the bookcover pulled from Amazon—this is my only complaint because it’s not always the exact book cover, but it’s close enough.  I decided that it was important to pull in the title of the book and not the cover, so I followed the documentation and examples of the other extensions.  The only advanced bit of this code is the username option.  Since Readernaut’s user feeds are predictable—unlike Facebook, for example—and since I knew that I’d be publishing it for the community, I added an option to take a username.  This just adds a field for the username on the page when you’re adding the feed.  These are all functions built into the framework and documented.  The comments are inline with the code.
[code]
class LifeStream_ReadernautFeed extends LifeStream_Feed {
// This is just a unique ID that is used internally; make sure it doesn't conflict with others.
const ID = 'readernaut';
// The verbose name for your feed. This is what is displayed.
const NAME = 'Readernaut';
// An optional URL for more information about this feed. This is displayed on the page to add the feed.
const URL = 'http://www.readernaut.com/';
// A description for the feed, shown in the add feed and edit feed dialogs.
const DESCRIPTION = 'Readernaut is my library, my notebook, my book club.';
// The label for showing a single event. It follows the <a href="http://php.net/sprintf">sprintf()</a> format and parameters are: feed url, feed name
const LABEL_SINGLE = 'Added a book to his collection on <a href="%s">%s</a>.';
// The label for showing a group of events. It follows the <a href="http://php.net/sprintf">sprintf()</a> format and parameters are: number of items, feed url, feed name.
const LABEL_PLURAL = 'Added books to his collection on <a href="%s">%s</a>.';
// This is for a plural form of the label.
function __toString() {
return $this->options['username'];
}
// This is what puts the form field for the username on the add feed page. This option is now available in subsequent lines. You can add other options as well.
function get_options() {
return array( 'username' => array('Username:', true, '', ''), );
}
// This is an array of arrays that defines the options for this feed.
function get_url() {
return 'http://readernaut.com/rss/'.$this->options['username'].'/books/';
}
// This is the actual URL that the information for the lifestream is pulled from. Like I said, the Readernaut RSS feeds are predictable so I could use the username option instead of asking for a feed URL. It's just much simpler.
function get_public_url() {
return 'http://readernaut.com/'.$this->options['username'];
}
// This is the URL that is put to the lifestream for linking purposes. Again, I used the username option.
}
register_lifestream_feed('LifeStream_ReadernautFeed');
// This is the last line of the extension and is what registers the extension with the plugin.
[/code]
The first step is to declare the class; the last step is to register the feed.  This is important.  Because of the nature of the feed and the information I wanted to pull from it, this is a relatively simple example.  I didn’t need to manipulate any of the data or switch any of the defaults.  One observation: you might want to change the gender of the entry to fit your needs.

ScrnShots

Introduction

Scrnshots is a social network to share screenshots of design for inspiration.  You can either upload from your computer through the website or from their desktop application.  I use Paparazzi, a Mac utility for making images of webpages. It’ll take a screenshot of the entire page or you can specify a crop area. It even creates thumbnails for these shots. You can add me as a contact on ScrnShots here.

Extension

This one was slightly more complicated, mainly because of the poorly organized RSS feed, but also because of the information I wanted to pull from it—namely, the screenshot.  I ran into several road blocks.  First, I couldn’t determine the exact source of the images.  I figured out that they were hosted on Amazon S3 and I knew there were suffix options for determining size—e.g. large, full-sized, medium rectangular-sized, or small square-sized.  However, I couldn’t figure out the nomenclature for the image sources—there is a unique ID and a seemingly arbitrary description (is it the automatically generated or user generated?)  There was an API, but aside from documenting the suffix options, it didn’t help much.  Finally, I just resorted to using PHP’s built-in functions and some regular expressions to build around the—again, poorly formatted—RSS feed.  Here’s the code:
[code]
class LifeStream_ScrnShotsFeed extends LifeStream_PhotoFeed
{
// A unique ID for your feed. Must not conflict with any other feed plugins.
const ID = 'scrnshots';
// The verbose name for your feed.
const NAME = 'Scrnshots';
// An optional URL for more information about this feed.
const URL = 'http://www.scrnshots.com/';
// A description for the feed, shown in the add feed and edit feed dialogs.
const DESCRIPTION = 'ScrnShots is the best way to take and share screenshots of web and screen based design. Upload as many screenshots as you want, embed them in your blog, discuss them with your contacts and become a better designer!';
// The label for showing a single event. It follows the <a href="http://php.net/sprintf">sprintf()</a> format and parameters are: feed url, feed name
const LABEL_SINGLE = 'Added a new screenshot to &amp;lt;a href="%s"&amp;gt;%s&amp;lt;/a&amp;gt;.';
// The label for showing a group of events. It follows the <a href="http://php.net/sprintf">sprintf()</a> format and parameters are: number of items, feed url, feed name
const LABEL_PLURAL = 'Added new screenshots to &amp;lt;a href="%s"&amp;gt;%s&amp;lt;/a&amp;gt;.';
const LABEL_SINGLE_USER = '&amp;lt;a href="%s"&amp;gt;%s&amp;lt;/a&amp;gt;.' added a new screenshot to &amp;lt;a href="%s"&amp;gt;%s&amp;lt;/a&amp;gt;.';
const LABEL_PLURAL_USER = '&amp;lt;a href="%s"&amp;gt;%s&amp;lt;/a&amp;gt;.' added new screenshots to &amp;lt;a href="%s"&amp;gt;%s&amp;lt;/a&amp;gt;.';
function __toString() {
return $this-&amp;gt;options['username'];
}
function get_options() {
return array('username' =&amp;gt; array('Username:', true, '', ''),);
}
function get_url() {
return 'http://scrnshots.com/users/'.$this-&amp;gt;options['username'].'/screenshots.rss';
}
function get_public_url() {
return 'http://scrnshots.com/users/'.$this-&amp;gt;options['username'];
}
function yield($row) {
$description = $row-&amp;gt;get_description();
$title = strip_tags($description);
$img = strip_tags($description,'&amp;lt;img&amp;gt;');
$src = str_replace($title,'',$img);
$large = preg_replace('/.*src=([\'"])((?:(?!\1).)*)\1.*/si','$2',$src);
$small = str_replace('large','med_rect',$large);
$arr = array(
'title' =&amp;gt; strip_tags(html_entity_decode($row-&amp;gt;get_description())),
'date' =&amp;gt; $row-&amp;gt;get_date('U'),
'link' =&amp;gt; html_entity_decode($row-&amp;gt;get_link()),
'thumbnail' =&amp;gt; $small,
);
return $arr;
}
}
register_lifestream_feed('LifeStream_ScrnshotsFeed');
[/code]
Most of the code is the same as Readernaut’s, save two important pieces.  First, notice that the top says extend “PhotoFeed.”  This sets it up to take the screenshots and display them in the lifestream.  The last bit—function yield($row)—is what is returning the data to the plugin to be processed.  I didn’t have to do this with Readernaut because I didn’t need to override the default entry.  Each element in the array $arr is a property of the RSS feed.  To use this function, you must return at least date and link, but there are numerous options to chose from, including title and thumbnail—which you must return for PhotoFeed.  You return this entire array to the plugin to be written to the lifestream.  At the top is where I used some PHP magic to get the content from the RSS feed I wanted. Here’s the breakdown:

$description = $row->get_description();

This gets the description from the RSS feed.
$title = strip_tags($description);

By default, the plugin was writing the date I uploaded the screenshot to the lifestream.  This isn’t suitable—I wanted the description of the screenshot instead.  But, the description in the RSS feed was filled with other data—e.g. the HTML image source tag.  I used the PHP strip_tags() function to get rid of this tag, and all that’s left is the description.  One hurdle down.
$img = strip_tags($description,'<img><img>');

Here’s where some great stuff happens.  Like I said above, the image link is hidden within the description, so I need to strip everything else.  First, I took the description from the RSS feed and removed all of the HTML tags besides the image tag . . .
$src = str_replace($title,'',$img);

then I deleted the description that I already used . . .
$large = preg_replace('/.*src=([\'"])((?:(?!\1).)*)\1.*/si','$2',$src);

then I used some regular expression magic to delete the HTML image tags.  I can’t use strip_tags() because it also strips the content of the tags, which I need.
$small = str_replace('large','med_rect',$large);

Finally, I deleted the large suffix and added the suffix which yields the medium rectangular shape.  I also edited the _lifestream.php file, line 769, to make the width of the inline image bigger.  You can see the final result at my lifestream.

Conclusion

This plugin is very well written.  It covers nearly every social network and then includes a framework for extending it to those that it didn’t include.  I congratulate the writer and thank him for such a great plugin.  I highly recommend installing this plugin and it’s definitely on my top 10 list of Wordpress plugins—that article is in the works.  I hope these additions help you as they’ve helped me.  If you have any questions or can recommend a better way of doing this—I’m sure there is one—please leave a comment.

As promised, here is my feeds.inc.php file which includes the above additions.

Merry Christmas!

loganleger.com Renaissance

Dec 22, 2008

Narrative· News

6 Comments

Introduction

Several years ago when I first came of age on the internet, I had a blog. It began as a Blogger account and was then upgraded to a full-fledged Wordpress blog on my newly purchased domain—loganleger.com. The blog was a living historical account of my progression through the internet phenomenon. Moreover, you could see my maturation in writing and thought. Some of this data has been lost—some in part to my carelessness, some in part to time.

Now, as I enter a new stage in my career, I decided to reopen the blog. When I went to LSMSA, I decided to shut it down and make my site a static portfolio because I simply hadn’t the time to devote to it. Now that I’m out of the hectic bubble of Natchitoches, I finally have time to write again. This time, I plan to fill this space with all sorts of content. I’ll discuss whatever is on my mind, and these days it’s far more than just technology. There will be thought-provoking articles that’ll make you think and there will be funny articles to lighten your day and there will be technology discussions and tutorials. This time through, I plan on sticking to it and making regular posts. Nevertheless, I’ll never sacrifice quality for quantity. I care about my writing, so you can expect to see nothing less than some of the best writing on the internet. I also plan on bringing in some of my colleagues to make guest posts. These colleagues are friends that I have accumulated in my academic circles and I assure you that their writing will be nothing less, if not more, than my own.

Design

Recently, I’ve really invested in the minimalist aesthetic. From the arrangements of my living space, to the designs in my portfolio, everything is done with one thing in mind: simplicity. One reason for this is my love for Apple, but I’ve found a great quote to support this. You can see it in the footer on my website, but here it is: “Everything should be made as simple as possible, but no simpler.” Albert Einstein said this. Einstein was unequivocally a genius and when geniuses speak, you listen.

So, I knew from the beginning that I wanted a minimalist design. I did some reading around and perused some minimalist galleries. I drew lots of inspiration from Khoi Vinh Subtraction.  My site is even in more or less grid-form, which Vinh created. I also drew inspiration from the newly redesigned http://www.criterion.com/, the online home of the Criterion Collection. Once I had an idea of what I wanted it to look like, it was just a matter of sitting down and coding.

Now, I have a confession: This is the first time I’ve ever coded a Wordpress theme from scratch. Yes, I’ve used templates before and modified them—that’s how I learned HTML, CSS, and PHP to begin with—, but I’ve never gone from start to finish with my own acumen. I won’t lie: It wasn’t an easy task. I began locally using Coda and MAMP in basic HTML. 37signals recommends this in their book Getting Real, which I highly recommend for anyone, much less those building web applications. They call this process “wireframing,” and it’s basically to get a feel for what the site will feel like.

After the wireframing was complete, I still had to build out the Wordpress template structure. To do this, I downloaded a blank Wordpress theme as a guide and began filling in the template.  I thought using the blank theme as a guide would be relatively easy, but the structure of my site is much different from a traditional blog. This required lots of time to translate, if you will, to my structure. I had to do lots of research into using multiple loops and custom fields for the homepage (more on that later). The main post title is one loop; the recent blogs is another loop; and the quotes is yet another. I had to exclude the quotes from the other two and make sure that if one post was at the headline, then it wouldn’t be in the others. I also used custom fields for the source of each quote and used CSS3 specifications to open and close the quotes around it, so this might not be visible in your browser. All of these were explained in the Wordpress Codex. Another CSS trick I used was a “sticky footer,” which I got here.  This was really helpful and while I think it’s broken on some of the pages, it works quite well.

Conclusion

Because I’m new to this, my CSS is probably not as organized as it could be and my HTML is riddled with comments. In the coming days, I plan to go back through the files and clean this up a bit. Also, my content thus far is lacking, not only in posts, but also in pages. If you notice, a few of the pages are missing content. In the coming days, this will be filled out as well.  But, I’m really loving Wordpress 2.7.  It’s a big step up from when I last used it.  One last thing: I haven’t even checked this site in IE.  From what I can see in my site statistics, a majority either uses Safari or Firefox, which, on my computer, both render this excellently.  Also, if there’s anything that you were wondering how I did, please let me know and I’ll explain. But, I would like some feedback. How do you like the design? Are there any improvements you could suggest? How does it feel for you? I’d like to improve the design as best I could and, potentially, release it for the community. But, I think I’m a long way from that.