Creating a WordPress Portfolio

Note: this project journal is not complete. I worked several hours a day for about 2 days in a row then school hit hard and now I’m caught up in work. Portfolio entries are not styled, nor are they linking to any valuable locations at the moment. This will come in time.

My site is finally up, I chose a theme that I liked, installed some plugins, spent a good hour configuring everything, even got to play with the CSS (the search bar in Mantra has some issues by default – not to mention things look ugly if the screen is wider than 1600px). The technical details of how I set up my site will all be available at the About This Site page (soon to come), so I won’t waste time on that here.

Instead, let’s discuss my first project for the new site. I aim to use this site as a central hub for all my programming endeavors. This includes personal projects, hair-brained experiments doomed to failure, and professional examples of my work experience. Of course WordPress isn’t exactly suited to doing more than one thing at a time. It likes to be a blog… and only a blog. But I chose WordPress because it CAN do more than one thing at a time, even if that’s not what it’s meant for.

Entry 1 - The project goal

For my portfolio, I have a couple problems I’ll need to overcome. I’ll update this post as I work in order to keep a running journal of my progress. First, I have three possible “types” of portfolio entries – web applications I’ve developed, desktop applications I’ve developed, and web sites I’ve improved. Note the change of verb on that last one – I’m not an artist, and I don’t design websites. I can, however, take an existing website and re-code it to fix graphical bugs, align content, improve performance, increase usability, and all that fun jazz. Each of these three portfolio types will have a different optimal method for showing it off:

  • Web applications: The best way to show off these is  with a demo. Click this link, see the application in aciton
  • Desktop applications: This is more difficult. Perhaps let them download the application to try it out, but this will cause tin-foil connoisseurs a miniature heart attack. Screenshots are another option, but this may not get across the true usability or utility. For now I think the solution is to say “coming soon” since I have way too many other features of this website to worry about.
  • Web sites: The best way to show this off would be a before and after example. Of course a lot of what I do when I improve a website isn’t immediately visible from two screenshots – I’m not an artist, after all. Rather what I do converts a business website from 1.29% text-to-HTML ratio to 27.07%! How can you truly understand the difference this makes in performance from a screenshot? I have a creative solution to this – a custom before/after application I plan to code.

So each type of portfolio entry is going to be viewed entirely differently. One will launch a web application, completely separate from my WordPress site. One will open a static web application for all web sites, displaying the appropriate before and after pages. One we don’t even know what it does! Our first order of business will be getting WordPress to distinguish between these different types of entries and respond accordingly.

The next problem I have is actually displaying the portfolio in a way that’s easy for me to update. I could manually append new projects to a plain HTML page, however that’s unnecessarily tedious and not why I chose to use a Content Management System. Rather I want to post a new portfolio piece as easily as (or more easily than) I post a new blog post. Thinking of solution to this I’m reminded of CouponPress – a premium theme which replaces WordPress posts with “coupons” and categories with “merchants”. Similar code could likely replace posts with “projects” and divide my three types into different categories.

Finally, I want this portfolio to be the primary focus of my site. It needs to be front and center, not this silly little blog. This will take two steps. The first is easy – adjust the WordPress settings to set the home page to “a static page”, and use the portfolio page. Then put a link to the blog where the current link to the portfolio is. The second step is putting recent portfolio updates at the top of my sidebar instead of recent blog posts. This will require a custom widget.

I’m closing this post for now, as I begin my quest with the search for custom post types. If I can create a “portfolio project” post type then I believe the rest will fall into place. If I can do it as a plugin rather than as part of my theme then I won’t have to modify any Mantra core files, which will be nice if the Mantra theme is ever updated.

Entry 2 - Planning phase

I may be in luck! It turns out that as of WordPress 3 there’s actually a post_type attached to all posts, and custom post types are easy to add. Back when I worked with CouponPress WordPress was only on version 2.2, so I guess my procrastination has paid off again!

Yet more luck, possibly, it turns out that WordPress will not display custom post_types in the loop unless you specifically request them. This means that if I create a “portfolio project” post type it likely won’t get mixed in with my blog posts (unless Mantra does something crazy)

I have experience making a WordPress plugin for a client once, however I don’t work with WordPress very often and my experience was limited. I will pull up the files I created for them to get an understanding for what I did and, more importantly, how I did it. Ultimately I want to create a plugin with the following:

  • Create a custom “portfolio project” post_type
  • Ensure that portfolio projects fit one and only one category of: web site, web app, desktop app
  • List all portfolio projects on a specified page (“Portfolio”) using display code unique to each category
  • List new portfolio updates in the sidebar with a widget
  • Edit details for how it’s displayed in the admin panel
  • Adjust the display for mobile devices

Shouldn’t be too hard… right? For now it’s bed time. I’ll tackle this in the morning.

Entry 3 - Framework

I pulled up an old WordPress plugin that I made for a client and it looks like I put a lot of effort into following every best practice with unbelievable detail. I create a single global instance of the plugin class, encapsulating all functions within that class to prevent global namespace clashes. I have functions for not only handling data input and validation, but functions which let you use pseudo-code to display precisely how it will appear prior to hitting “Save” (using jQuery). I even had i18n support!

The plugin itself was rather complicated, as well, having about 20 settings and having to write a custom Walker for menus.

Since the plugin I’m making now is going to be specifically used on my own website and I can personally guarantee no namespace clashes, I think I’ll take the quicker but sloppier method of globally declaring everything. I also don’t feel like anyone will look down on me for this since it’s the same strategy used by Hotfix, W3 Total Cache, Hello Dolly, and many other very popular plugins. In fact, after browsing through about 30 plugins the ONLY one that used the same OOP practices I did was WP Better Security. Good on ya, mate

So let’s get started with our plugin. We’ll begin like any other:

Since most graphical user interfaces provide a beautiful function for precisely moving the insertion pointer, common referred to as clicking, I can start inserting code and code examples and modify as necessary afterwards. For now I have borrowed snippets for basic plugin structure, custom post typescustom widget creation, and adding administration menus.

The code is already a bit wordy, but here’s what I’ve got for now:

Although I don’t have any custom code yet, everything works thus far:

The admin panel after testing my new plugin

Entry 4 - Validating posts

I’ll focus on one of these sections at a time. First, let’s get the custom post type functioning properly. Obviously a portfolio entry is not going to look just like a blog post. I need to enforce the selection of a single type at the very least. Ideally I would also require an image of the project. In the case of web sites I may want two images.

Making a taxonomy required turned out to be significantly more complicated than I had hoped. I can always check to see if a portfolio entry is being saved and, if so, make sure they entered one and only one taxonomy and, if not, redirect them to the edit form with an error… I just figured it would be less… hacky

Turns out it isn’t.

So far here’s the code I’m looking at for the custom post types section:

As you’ll notice from the comment, this is not preventing auto-saving of an entry with multiple types. I tried simply amending the if() statement to say something along the lines of “if( action = editpost OR action = autosave)”, but to no avail. It turns out init isn’t being called by autosave.

This time the internet wasn’t so helpful. You can disable autosave, change the autosave interval, and delete post revisions… But how do you run a check at autosave time?

There are a few solutions that came to mind immediately:

  1. Edit wp-admin/admin-ajax.php
  2. Read through wp-admin/admin-ajax.php to see what hooks it does call
  3. Edit wp-includes/js/autosave.js
  4. Create a custom version of wp-includes/js/autosave.js

Obviously options 1 and 3 are right out since I never want to edit WP core files. Since I don’t want to constantly update my plugin should WordPress update autosave.js, I’ll begin with option 2.

Only a few seconds in and I may have gotten lucky. Line 41: do_action( ‘admin_init’ );

I updated my plugin to work on admin_init instead of init and was sourly disappointed when it still saved. This time I took a look at the POST headers that Chrome sent with the AJAX request. Not a single mention of taxonomies. No wonder it saved, the WordPress autosave feature doesn’t save taxonomies!

I puzzled over this for a minute wondering if it would cause me any trouble, but I’m fairly certain a portfolio entry won’t even be visible until I’ve saved it manually (setting status to Published). Therefore I gave up on my silly autosave quest.

Entry 5 - Admin menus

The post type is looking good and until I start displaying it I won’t really know what features need to be modified or fixed, so let’s get it displaying!

I want the list of portfolio entries to display on the portfolio page. I heavily modified a plugin for a client once named Popshops, in which there was a setting to specify which page you want it to display on. If you visit that page the plugin hijacked the request and filled the page with custom content. The page itself was technically blank.

This is the method I’m going to pursue. There may be a more streamlined method (like a secondary blog listing for a particular post type without having to waste a blank page) but I’ll opt for the method that works rather than hours of research to look for something that may or may not exist.

For now I borrowed the logic from Popshop’s plugin, removing large chunks of unnecessary code and using options instead of a custom database table. The code looks like so:

In theory we’ll see the text “Got here, at least” when we visit my portfolio page. That is, once portfolio-entry-page is set properly. It’s now time to take a look at the admin menu.

Doing just a minute amount of research, I’m pleased to see a lot has changed since WordPress 2.2

No longer must I manually create the form, process everything, handle everything… It seems like using a very standard template and a couple of functions I can get the job done with no hair pulling.

Well, scratch that. Turns out the page is “in transition” (and has been for 3 years) and it’s quite confusing to read. They say one thing then immediately contradict it. For instance, according to the WordPress codex:

After the settings_fields() call, add this function

This function replaces the form-field markup in the form itself.

However do_settings_fields requires two parameters.

Obviously the instructions in the codex weren’t perfect, so I had to take them with a grain of salt and do some shotgun debugging. Ultimately I had a working solution, though:

Interestingly enough, print_portfolio_entries_section was never called. Huh. The only reason I included the function is because add_settings_section requires a callback. I can set the portfolio page, though, so I’m happy.

Loading up my Portfolio page, it looks like everything worked!

Entry 6 - Listing posts

Let’s step back and look at the original goals for this project to see how I’m doing:

  • Check: Create a custom “portfolio project” post_type
  • Check: Ensure that portfolio projects fit one and only one category of: web site, web app, desktop app
  • List all portfolio projects on a specified page (“Portfolio”) using display code unique to each category
  • List new portfolio updates in the sidebar with a widget
  • Check: Edit details for how it’s displayed in the admin panel
  • Adjust the display for mobile devices

So now we just have to list the portfolio entries then adjust how they display. Simple enough. To begin, I created 3 sample portfolio entries – one of each type. I’ll start by seeing if I can list these on the Portfolio page and in a sidebar widget. Markup will come later.

Impressively this one worked right first try.

Entry 7 - The markup

We’re in the home stretch. Now I just need to style these ugly guys. It’s getting late, though, so I’ll finish this up later.

Wrap-up

It’s been a long time since I’ve worked with WordPress, and I found that quite a lot has changed since then. This project gave me a good excuse to research all the wonderful new ways that WordPress has been updated to make life easier, or more difficult, for developers.

Upon learning about custom post types I realized almost immediately that, if set up correctly, my entire plugin may become invalid. I’m certain I can set up an archive widget to display only posts that match my type, and somehow I can create a blog index which only displays my post type. A small tweak to the theme could then change how these posts were displayed and I’d be set. But what’s the fun in that? Through this project I got hands-on experience making not only custom post types, but custom widgets and admin menu pages. I also got to play with over-riding default page functionality using plugins and validating posts in the editor.

Even if my plugin is unnecessary, the lessons I got to learn will prove useful.