WordPress in 2016

A year ago, I published WordPress in 2015. In retrospect, I’m very happy how the article turned out. The predictions were for the most part accurate, but materialised at varying speeds. You can check it out here.

Looking back, 2015 was another strong year for WordPress and its ecosystem. We saw user adoption breach the 25% barrier (in front of Drupal which has a tenth of that). WordPress itself had big wins such as responsive images and the REST API. The ecosystem around it also thrived; we witnessed the acquisition of WooCommerce by Automattic, a deal rumoured at $30M. There are also over 40,000 other plugins on WordPress.org resulting in more than a billion downloads, one could possibly argue that we’ve even reached peak plugin. It goes without saying that there is a lot of momentum in WordPress today.

So what’s next, where do we focus our energy in 2016? Comments, feedback and other predictions are all welcome at the bottom of the post.

Matt Mullenweg - State of the Word - 2015

JavaScript, not so fast

Learn JavaScript, deeply.” was the phrase that’s been making rounds after Matt’s “State of the Word” talk at WordCamp US. I think it’s great advice, but JavaScript is so vast that you need to find the right entry point. At Human Made, we think the REST API coupled with a front-end JavaScript library (such as React) is the future of many websites and progressive web apps. The flipside, however, is that this sort of setup is simply not yet suited for smaller sites and service providers (the vast majority of WordPress installations). Let’s take the A Day of REST website below for example. We built it using the REST API/React over the winter and its code is open to everyone.

REST API React WordPress

It’s just another website, but the daily development conversations around it are different due to the unconventional setup:

api

Jokes aside, there’s a large disconnect between creating a REST API powered theme (such as the one above) and managing your WordPress sites as you do today. Let’s say I install Yoast SEO, none of the Open Graph/social metadata is going to output on the frontend without additional work. That’s simply not sustainable if you’re a freelancer or agency catering to small and medium-sized businesses.

That shouldn’t preclude you from beginning your learning path though. React is purely a visual layer (and not as complete as Backbone or Angular) and a good place to start interacting with the REST API. React can be frustrating, but there are a numerous tutorials out there to try and make sense of it.

With all that said, JavaScript is still immensely valuable today. REST API aside, you should at the least have a working knowledge. Websites are not static pages anymore, but living canvases. Hard or sudden transitions between different states simply don’t cut it anymore. Users expect subtle motion to not only guide, but also help understand their experience (and I don’t just mean slideToggle). Microinteractions are becoming increasingly important, often using vanilla JavaScript or jQuery (or coupled with libraries such as Velocity.js).

Need some more guidance? Check out Zac’s JavaScript WP Master Course or Remkus’s learning path. As for Human Made, we’re working on a number of our own projects using the REST API and JavaScript; Nomadbase, FrontKit for WordPress, and a P2 replacement.

WordCamp Tokyo 2015 - Contributor Day

The decline of the WordPress Assembler

In 2012, I wrote a piece for WP Candy Quarterly talking about Happytables and mentioning the rise of the web assembler; the pro-consumer/hobby user that assembles a server package, premium theme and plenty of plugins to sell it as something called web design. As I’ve said in the past, it’s certainly not a bad thing, it’s necessary. You need service providers to cater to all price levels.

At the time (and in a similar fashion), the entry of digital cameras shook up the photography industry; amateurs turning “professional” overnight, dumping prices and generally frustrating film photographers which preexisted. But it all turned out for the better and the same has been happening with web design (though digital photographers are now complaining about our smartphones).

As our industry is growing, we’re left with an abundance of assemblers as clients are finding better solutions on either end of the spectrum. On one hand, Squarespace, Wix, Shopify and other website builder solutions have all matured a fair amount. We certainly noticed the increased competitiveness with our own website builder for restaurants, Happytables. The user experience, product features and pricing have all come together to provide more enjoyable platforms for users with vanilla requirements.

A user doesn't need Magento or WooCommerce anymore.

On the other hand, freelancers and agencies have become smarter about running a sustainable business (having good processes and strong rates). The general skill-level is also gearing up towards growing websites with retainers as opposed to pumping out cheap throw-away websites. After all, the first time a website goes live, you’ve only really launched a rough draft. The real iteration towards success begins the day after having launched.

Assemblers have been valuable during the industry’s growth spurt, but it’s time for them to up their game or risk becoming extinct. I don’t have any evidence to back this up, it’s simply based on my observations in the last decade.

DSCF2438_wordcamptokyo

Patterns over Pages

WordPress still ships with an interesting template called sidebar.php. It sets the wrong expectation by giving the recipient the impression that 1) such a file needs to exist, and 2) that it has to have some visual resemblance to an actual sidebar. Even Underscores, my go-to starter theme still ships it. But this is an outdated approach.

website_patterns

Over the years, we’ve started seeing a shift from designing complete pages to a more modularised approach. Starbucks popularised styleguides, Bootstrap was released, we’ve even been introduced to Atomic Design. Everything is moving towards components (though I can’t say we’ve used Polymer in any projects yet). Some of our tools already lend themselves heavily towards a modular approach (SCSS best-practices or React components). We should be seeing more of this mindset seeping into the WordPress ecosystem.

WordCamp US 2015

Centralisation of Community

2015 saw the first WordCamp US (inspired by a successful run of the WordCamp Europe conferences). These growing WordCamps of WordCamps, coupled with the new entity and the chapter account on Meetup.com, are a big push towards the centralisation of community around the foundation (something I incorrectly predicted last year).

In my own opinion, I feel that accessible and open source events are the big idea whilst WordPress is simply a medium for that. Thus, in an ideal world, I wouldn’t advocate foundation ownership and involvement at such a granular level (meetup.com groups). I do however understand the motivations behind such.

Meetups aside, we’ll see an acceleration of big WordCamps. In 2016, we can expect both WCUS and WCEU to have 2000 people in attendance (which is a massive jump compared to previous years). This will set the stage for further growth in 2017 & 2018, whilst also opening the door for the next continental WordCamp (Africa and then Asia if I had to guess). I also wouldn’t rule out a global WordCamp, but that is likely a good five years away. What excites me about these WordCamps of WordCamps, is that they are instrumental in bringing together influencers from various parts of the ecosystem (development, design, business, etc.). Who knows which next great idea/startup (built on WordPress) will be hatched at a future WordCamp (it’s certainly happened countless times before).

Onwards

There are plenty of other (important) areas to WordPress that I haven’t touched on, the items above are simply what is on my mind these days. I’d love to hear your thoughts!

I’m really excited about the upcoming year; all the new things we can build, the big community events and all the new faces I haven’t met yet. Another great year lined up for WordPress and more importantly, all the people that are a part of it. Wishing everyone a great year.

And now that you’ve read this far, use restatease as a 50% discount code to a A Day of REST. They won’t last as there’s only 5, so grab yours now.

Pictures taken at WordCamp US & WordCamp Tokyo

Medium-like Posts for WordPress

Although the single-column full-width style has been around for a while, I think Medium popularised it by putting it out there in a distraction-free manner. There’s few features on the surface and no clutter hampering the content. Because of its simplicity, it isn’t very opinionated and works well for many people (such in the case of Medium, where everyone is “restricted” to the same design).

The key idea behind this sort of design is that it (hopefully) provides a superior reading experience, whereby there’s nothing else standing between the reader and the core content. The design continually leads you into the content, and freely uses the space it has been been granted.

Within WordPress however, we’ve come to recognise a particular style. We often see two columns (content + sidebar) as well as a footer area that has three or four columns for widgets. Even today, default themes are still being shipped with a template component called sidebar.php. This sort of wording sets the wrong expectations.

With our single column approach, instead of having something along the lines of:

.col-content {
    width: 800px; // or % width, flex, etc.
}

We now simply declare nothing at all. The parent container for content simply spans across the entire page. In turn, the child elements (text, images, media, etc.) that make up the content, now have to take on additional properties.

Handling Content

My posts are predominantly made up of text, but it likely isn’t wise to let text stretch like that on larger displays. There are countless articles on the topic, but you’ll generally find that they call for 50 to 75 characters per line. With our new found freedom, this means we’ll need to dial it in and control it. As there are a fair amount of textual elements (more than my other elements), we can tighten them up using something along the lines of:

.entry-content > * {
    max-width: 800px;
    margin-left: auto;
    margin-right: auto;
}

Using the direct descender with a universal selector enables us to set a foundation, but at the same time easily allows anything to change with a bit more specificity, for instance .entry-content > blockquote.

Handling Images

Using the above example, all images will also be limited in width. But what if we wanted to create a full-width image? We could use the full size image format to help target the images we want to show at full width:

.entry-content > img.size-full {
     max-width: 100%
}

There’s only one problem with that, WordPress by default encapsulates images with a Paragraph selector. In my opinion, it doesn’t make sense to have images inside of a paragraph unless they’re providing some form of inline value.
With that in mind, we can remove the P tags in a non-destructive manner using a filter (via CSS-Tricks):

function filter_ptags_on_images( $content ){
    return preg_replace( '/<p>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/p>/iU', '\1\2\3', $content );
}
add_filter( 'the_content' , 'filter_ptags_on_images' );

This means we get a nice result like this now:

Wapuu Pins

We’re not quite in the clear yet, as adding a link or caption (or both) adds additional elements around the image. Unfortunately, via WordPress you can’t specifically target those parent wrappers, nor can you go upstream with CSS (yet). So there’s no way to tell a link apart for example.
To assist us, we should add a class on the parent called wp-image-parent as well as bubble up any additional classes you desire. This allows us to make the same statement as before, but to also account for various image options.

.entry-content > .wp-image-parent.size-full {
    max-width: 100%
}

It’s not the best of solutions as it causes a reflow, but here’s the jQuery I’ve thrown in:

	$( 'a, .wp-caption', '.entry-content' ).each( function( i, e ) {
			if ( $( this ).find( 'img' ).length !== 0 ) {
				$imgClasses = $( 'img', this ).attr( 'class' );
				$( this ).addClass( 'wp-image-parent ' + $imgClasses );
			}
	});

This enables us now to target captions too, like the image below:

Contributor Day at WordCamp Tokyo
Contributor Day at WordCamp Tokyo, having a monitor on each table was a big win.

I’ve been doing all this as part of my own sites redesign, so I’m still working through everything. The code could be cleaner and better organised, but I hope you’re able to understand the idea I’m pursuing and how I’m getting there. Feedback and thoughts welcome.

Book update: Customizing WordPress Admin

If you came here for pictures, there aren’t many yet :) However, I’ll be sending out updates and a launch deal for those that sign up for my newsletter at the bottom of the post.

For the last couple of weeks, I’ve had a lot of fun putting together a book on customizing the WordPress Admin. It’s a sought after topic, yet rarely documented. Customizing the interfaces we use to interact with WordPress is becoming a bigger topic day by day. Be it within the enterprise or for SaaS solutions, WordPress has long since graduated from the blog moniker. This book will tackle the topic of customizing WordPress to meet those ever-growing needs.

Customizing WordPress Admin

Content

For those that have been following the tweets, I wanted to share an outline of the book:

  • Introduction
  • Destroy – The book kicks off with a chapter that tackles the overwhelming UI that is presented to the end-user as they log in for the first time. There will be a number of easy wins in this chapter, hopefully resulting in fewer support tickets and a less intimidating experience for your clients.
  • Rebuild – Writing this next part has been a lot of fun (and I’m also assuming it will be most useful to you). Beyond what you already know with regards to custom post types, this chapter will delve into creating your own interfaces within WP-Admin, discussing various design patterns as well as the general ins and outs of customizing it for specific needs or user types. It will focus heavily on getting your end-users to become happier and more productive.
  • Conquer – At this point, we’ll be breaking out of WP-Admin and discussing the various methods one can use to create entirely new interfaces for WordPress. Beyond the back-end code, we’ll also talk about front-end best practices and how you can get the most out of your user experience there too. This will be more product focused, so you can also expect some case studies.
  • Summary
  • Resources – In addition, there’s some bonus content I’m looking to throw in there to really help this make for a more practical book. Specifically a plugin that implements the code we discuss, as well as video interviews with people that have done similar work.

Distribution

The structure follows the same style to my initial article in .NET (which you can download below). That article is essentially an ultra-light version of what the book will be. As it stands, the book will also be self-published and DRM free (.pdf, .epub & .mobi).

Launch Date

This isn’t set yet, but it’s a few weeks off. Sign up for the newsletter below to get updates of the progress and be informed when the launch deal comes out.

With all that said, I’m really excited to getting this book out there. It’s really meant to be a tool that you can apply to your business or agency, with the hopes of delivering value from day one.

Joining Human Made

Over the past four years I’ve had plenty of fun with client work, open source projects and a fair amount of selling digital goods. At some point during that period I also quit my day job, which freed up a ton of time and further created opportunities. I thoroughly enjoy what I do now, which can really best be described as one large and continuous lab experiment, always leading to further ideas and opportunities. More than anything though, I’ve found myself creating and being involved with an assortment of different online products. I’ve completely stopped doing client work last year and now mostly bounce around two SaaS products and two mobile applications.

I’m ecstatic that they’re all growing at different speeds, each bringing unique challenges. However, there comes a point when they outgrow you in more than one way; I’ve hit hard walls with availability, domain expertise and most importantly, having access to different perspectives.

I started working with Tom and Joe over at Human Made almost two years ago and it’s never really slowed, if anything, our relationship has simply become more intertwined. Despite being under different legal entities and living in different countries, we’ve always considered ourselves colleagues and friends (either through Happytables, Clickbank Powered or other ventures). Time has come for us to once again up our game.

Human Made Partners

I’m proud to announce that I will be joining the Human Made family as a partner, responsible for all products (as opposed to client work/consulting). With this change, comes consolidation. Part of upping our game requires us to mature past the personal attachments of what we’ve built to date. On one side, Happytables will come under Human Made and on the other, Tom, Joe and I will become equals.

We each bring unique strengths, have strong views and are dedicated to pushing this business to the next level. This is further amplified with recent hires Daniel Bachhuber and Paul de Wouters. The motivation and passion of all individuals at Human Made today is truly incredible and I consider myself fortunate to be joining them today.

Be it through our VIP client work or the product side of the business, I’m really looking forward to the opportunity to do some amazing things down the line. Things that simply wouldn’t be possible if we hadn’t combined powers.

Enough rambling from my side, time to get to work.

Read the official post here.

WordSesh Notes: WordPress as SaaS

Thanks to all that participated and joined the WordSesh event. It was a blast, especially since there were around 250-300 people watching live. Here’s our session WordPress as SaaS (Software as a Service), led by Joe and myself:

Here are all the links for our talk:

SaaS Products

Dashboard

We talked briefly about how the dashboard is constructed. It’s not publicly available, but here are some of the tools that helped us build this rather quickly:

Productive Stuff

Outsource Services

If you have any specific questions, just ask them below.

Quick Hits: WordPress and Universal Analytics

Universal Analytics is an upgrade to the Google Analytics we’ve all been using for years, a welcome one at that. You can read more about it here and the KissMetrics blog also has a good write-up here. The gist is, we have more flexibility, in particular for pushing custom data (we had a limit of 5 before, now we have 40).

Whilst I don’t dig into the data on my blog too much, I do use it as a sandbox or place to experiment with new things, especially something like Universal Analytics. So if you’re already adding Custom Dimensions & Metrics to your site, here are a few more (in this case, 3 metrics):

<?php if ( is_single() ) { ?>
 ga('set', 'metric1', <?php echo nt_ga_word_count(); ?>);
 ga('set', 'metric2', <?php echo nt_ga_post_age(); ?>);
 ga('set', 'metric3', <?php echo nt_ga_comment_count(); ?>);
<?php } ?>

As you can see, they’re specific to posts too. That’s the majority of my traffic, so I’ll start there.

Word Count

Is there a magic word count for articles? Does long copy work well? Why not find out? It certainly won’t give you definite answers, but this little snippet may help get you there quicker (rounded to the nearest 100th):

function nt_ga_word_count() {
 global $post;
 $id = $post->ID;
 $count = str_word_count( get_post_field( 'post_content', $id ) );
 return ceil( $count / 100 ) * 100;
}

Age of a Post

How evergreen is your content? Will the bounce rate increase and the average reading time decrease after a few months? This will count the age in months:

function nt_ga_post_age() {
 global $post;
 $id = $post->ID;
 $now = date('Y-m-d');
 $then = get_the_time('Y-m-d', $id);
 return (int)abs((strtotime($now) - strtotime($then))/(60*60*24*30));
}

Comment Count

Does social proof matter? Do more comments increase trustworthiness? A similar concept could be applied to the amount of retweets or other social “counters”. Here’s the snippet (works with 3rd party providers that store comments to WP too, i.e. Disqus):

function nt_ga_comment_count() {
 global $post;
 $id = $post->ID;
 $comments = wp_count_comments( $id );
 return $comments->approved;
}

Here’s the gist with all 3. Are you using any others? Feel free to link them up.

Rethinking WordPress Admin

After having tackled customizing wp-admin with happytables, I’ve once again had the opportunity to go through the motions with an exciting project in a new vertical. The good news is that it’s completely doable:

Custom admin look for a new project.
Custom admin work in progress

The bad; it’s time consuming, hacky and leaves a bad taste in your mouth (similar to doing responsive web design in a rush). Both projects have had me wondering what opportunities exist and what sort of barriers of entry could be lowered with regards to how wp-admin is managed.

14,000 Lines

The first challenge and pain point you’ll encounter when trying to change the way wp-admin looks is the amount of CSS you run into. The core wp-admin styling adds up to at least 13,306 lines (14,000 with the random bits that get loaded in too). Considering the language doesn’t require any structure, that’s a LOT of code. What makes it worse, is that an editor viewport will only display the CSS properties for a fraction of elements at any given time (mine shows 50 lines, or 0.4%). This makes it quite hard to get a feeling for the general inheritance and specificity that governs the overall style (especially at 14,000 lines).

Plain CSS is so forgiving and detached that it becomes exponentially harder to manage with size. Now imagine trying to customize wp-admin away from the “one size fits all” approach, to something that actually speaks to the requirements in front of you. It’s mind-numbing. You can stop wp-admin.css from being loaded and throw in your own custom style, but are then in a very bad spot when an update comes around. So you’re left doing a lot of !important, border:none and display:none on an additional CSS layer. Like said, functional, but hacky.

Static CSS

The amount of lines aside, could the admin area ever become responsive? I do believe so, but not with the current CSS. Whilst I’m not advocating a mobile first approach or complete reorganization, some form of drastic measure will be necessary to make it all work. The reasons for this go beyond size, let’s backtrack a little to understand.

Admin in WordPress 1.5 used to be styled through over 500 lines. The overall DOM structure was also far simpler. In short, the CSS was fine as it was then:

wp_admin_15
WordPress Admin 1.5 – 3D view of DOM structure

Through the versions, the DOM grew and styling was added where necessary. The WordPress UI changed a few times too, getting us here:

wp_admin_35
WordPress Admin 3.5 – 3D view of DOM structure

Today, a number of elements will have issues such as containing relative positioning (example: top:-3px) or absolute values (example: font-size:14px).  This sort of immobile scaffolding means that in order to go responsive, you’d need to create an equal amount of responsive declarations simply to counter the existing code. That’s hard to justify.

Way Forward for the WordPress Admin

It’s painful to imagine that we would have to wait another 5+ years before the benefits of  CSS preprocessors would make their way into standard CSS. In that time, WordPress will certainly grow further, have new features added and become even more complex. New CSS would just be tacked on to the old, band-aids (top:-3px) would be applied to make things fit and the CSS files would burst the 20,000 line marker. It’s always been easier to gain weight then to build muscle. Trying to lose said weight later on is even worse. We have an opportunity for an easy win here.

In short, a preprocessor needs to replace the current CSS structure. Assuming we use the designer-friendly LESS, there is zero impact in migrating from .css to .less files tomorrow. The files simply need to be renamed (as preprocessors support standard CSS just fine) and best practices need to be established for compiling and minification (compilers exist for OSX, Windows, Linux, etc.). From there, work can be broken down into the following initial passes:

  • Variables & Mixins (1-2 days)
  • Nesting (5-10 days depending on accuracy)
  • File Segregation (1-2 days)

I wish I could have provided smaller and more tangible suggestions (fitting the trac mindset), but the problems are larger than that. The challenge here is also less likely to be one of technology, but rather of culture. The large majority of front-end developers, agencies, startups have all made the switch for reasons relating to productivity, workflow, clarity and so forth. We should too.

Recommended Reading

Adaptive Content Images within WordPress

There are plenty of adaptive image solutions out there, but I needed one that understood the relevance of the content area, automatically created re-sized images for various breakpoints and minimized the download impact for end-users. Remember, images that are part of your theme should be solved through the theme files, my goal was to tackle any images that a user uploads (i.e. dynamic content).

Here is an example of my automated plug-in (play around with the browser):

Stingray Bahamas

There are four major breakpoints (with another useless one which I had to add for some legacy images). The results in file-size reduction are quite astounding:

Responsive Images in WordPress

These are the settings I used:

Adaptive Settings

How does it work?

The plugin is called Hammy and you can download it on WP.org. As I’m crap at php, there certainly isn’t any black magic involved. It’s really a mash-up of WPThumb (an awesome image resizing tool) and jQuery Picture (a nifty plugin that serves the best suited image size). It’s also non-destructive, so it will filter your content as opposed to overwrite it, thus taking something like this:

… and transforming it into (stripped out long URL’s to make it easier to read)…

If you’re confused as to why the image name is Stingray, look again. For those wondering what the hell is going on:

  • The standard img element is being replaced with picture (read more about that tag here)
  • Various sizes are automatically generated and stored within a source tag. None of those are downloaded, unless JavaScript is off, in which case the original image is rendered (hence noscript tags).
  • The content width is analyzed and the biggest image which fits within it is then downloaded and shown to the user.

What else?

So to summarize how this plugin Hammy works:

  • No changes required to your theme files, .htaccess or otherwise (plug and play!)
  • Select the container you choose to designate as being the “content” one.
  • Setup your breakpoints in line with how you’ve structured the “responsiveness” of your website. Alternatively target common mobile/tablet resolutions.
  • Add classes you wish to ignore (i.e. “thumbnail”, “nextgen”, other gallery plugins).
  • Retina support (for the 1% of the world)
  • Named after a Squirrel that is really fast, just like your website will be on mobile now (if you haven’t seen Over the Hedge, definitely do).
  • Chose to use WPThumb instead of Photon as image re-sizer (Photon requires users to have JetPack installed which isn’t the case for all).

If you want to contribute on GitHub, here is the page (I simply ask that you don’t try to lump features, fixes all in one big pull request).

Thoughts?

How are other people solving this, what are you using? I’d be interested in hearing your thoughts as this can have quite the performance impact (83% from desktop to mobile for instance). Fire away!

WordPress.com Verticals and the Future

Over the past few weeks, we’ve seen a number of WordPress.com initiatives trying to touch on niche business segments. As happytables is fairly known within the community, some chatter came up when the most recent vertical relating to restaurants was released. I’d like to take this opportunity to clear some things up as well as discuss what lies ahead. I think this is an important discussion to have as many are either interested or curious on the topic of WordPress as SaaS.

Is happytables involved?

We were approached by Automattic earlier this year (2012) to see what possible opportunities existed. Tom, Joe and I went to the drawing board and in turn pitched the wordpress.com/restaurants concept in April ’12 (see the presentation deck here). We were open to ideas where recurring revenue was an option. The only opportunity available at the time was becoming a traditional premium theme partner, which given the nature of our solution didn’t make for a viable business case (certainly not a long term one, more interesting would have been the same partner model but with the recurring element). In other words, we would have seen a potential relationship structured in a more incentivized manner. Whilst we are still open to ideas, there currently is no business relationship between us. We’re happy to see our concept validated though.

Impact for happytables?

A big misconception is that we’re now some sort of “fierce” competitors, which couldn’t be further from the truth. Running a business targeted at a vertical comes with quite some baggage, 90% of which has absolutely nothing to do with WordPress. Whilst we are miles apart in execution and depth, I guess we expect some minor cannibalization given their existing reach and reputation in the overall “website builders” market (they did after all land a TechCrunch TV segment on day two). That said, we’re confident in our business and the foundation we’ve built both online and offline whilst being bootstrapped. With myself being the “face to the client” and evangelist for happytables, I’m grateful for the successes we’ve had to date in the areas where larger companies will find it hard to; developing a relationship with clients, understanding the challenges they face and trying to be part of their growth online.

Map Users

This all leads up to the most important point. That is that we’re genuinely trying to help independent restaurants succeed as small businesses, it’s something that I believe in deeply, this sort of democratization of opportunity. Solutions such as Kiva or Kickstarter provide liquidity and tear down barriers to entry, enabling individuals or groups to overcome the initial hurdles of competing in spaces filled with larger players. It’s the same reason we have a free plan that allows you to connect your domain and doesn’t contain any 3rd party advertisements. This enables us to give a free website to restaurants just starting out, or those in less fortunate countries. Whilst we’re far from having perfected our revenue model, we feel good about what we’re doing and would like to think that we’re adding value to the web as opposed to polluting it further.

This is what motivates us and allows us to approach the problem from a different angle, thus adding value in completely different (and hopefully new) ways. Long story short, you can’t compare the dotcom vertical with happytables, not that easily.

Impact for other WordPress SaaS businesses?

So who has to worry? With these new verticals, Automattic will in my opinion continue eating away at profits generated by “web assemblers”. You’ve heard me use the term before. These are individuals that do not develop, but rather assemble hosting, theme, plugins and basic support to create and sell a “custom” website (in other words a large part of Theme Forest customers). If a WordPress SaaS platform was created as an extension of this mindset, then they won’t last long either. This is because there isn’t a great deal of creativity or specialization involved, it’s easy to replicate and scale. WordPress.com has established itself as the leader in that segment a long time ago and has turned this assembly into a seamless experience (especially with the frequent improvements to onboarding and user experience). That isn’t to say that there aren’t exceptions. If you sell and provide support in a language other then English or are physically present for your user base, you certainly have a unique advantage.

If on the other hand, you’re passionate about the industry you’re targeting and are genuinely interested in finding solutions that can help your customers grow and be more productive, then I believe you don’t have anything to worry about. Automattic is great at what it currently does and is quite amazing for only having a c .130 employees, but even they can’t be everywhere at once. Kudos to bringing Xzibit and others into the music vertical though.

Your thoughts?

I can imagine from the recent news post at WP Realm that there are quite a number of different views and ideas. Where do you think this is going and what sort of impact will it have?

Using LESS with WordPress

Back when I used to have an office job, 80% of the work was repetitive and far from challenging. As a result, I came up with ways to automate various tasks (think Excel Macros, Access, Crystal Reports, etc.). This allowed me to focus on items that actually required some form of judgement or decision-making. When I made the leap to the web industry more permanent, I found myself facing the same mundane work. Vendor prefixes became the new TPS reports. In the process, LESS (or SASS) became my new macros. In this article, I’ll show you how you can also drastically increase your productivity and focus on what matters.

CSS LESS WordPress

Preface – Still using CSS?

LESS allows you to use a syntax style that naturally extends CSS in ways that can drastically optimize your workflow. If you’re a web designer and aren’t using one, you’re probably spending more hours on client projects then you really need too.

There are also a number of people who hold onto writing CSS for reasons of purity, making preprocessors sound as evil as growth hormones given to animals. Truth be told, there’s nothing sexy about having 10,000 lines of static CSS. Besides, CSS zen doesn’t come from indenting vendor prefixes in a straight line, but finding the right balance with regards to specificity and flow. I feel as we sometimes focus on too many of the small details as opposed to the big picture, which is why we often see alphabetically sorted properties but nothing that resembles an effective table of contents (nothing against the former, but the latter takes precedence).

At the end of the day, once your files are minified, concatenated and stripped of any comments…  we’re all equal. Ready to get started?

1) Setup LESS

The most seamless experience you’ll have using WordPress and LESS is by using wp-less, which acts as bridge between WordPress and less-php (a general PHP compiler for LESS). There are other ways to implement LESS (less.js, node or pre-compiling via a desktop application). I just find the on-the-fly compiling to be the most painless solution for small to mid-sized websites. It compiles only when any of the original LESS files are changed (including anything brought in via @import), so the outputted data will always be the compiled CSS.

To install it, you can either include my front-end starter foundation (more information on that in the next section) or submodule the repository directly and pull it in through your functions.php, like so :

require_once( 'wp-less/wp-less.php' );

To use it, simply enqueue a LESS stylesheet the same way you would CSS. The difference is wp-less runs a filter and checks for any mention of the “.less” extension thus diverting it’s path to the compiler before outputting in the header of your document.

wp_enqueue_style( 'less-style', get_stylesheet_directory_uri() . '/style.less' );

That wasn’t so hard was it?

2) LESS Structure

Like many developers out there, I have my own foundation I use for projects (it includes a template that outputs theme styles like this). I’ve finally taken the time to consolidate it as a github repository so that others can use it if they wish. It’s called prometheus and is my starting point with regards to any front-end development on WordPress. It contains my base LESS files, wp-less, WPThumb (a superior thumbnail solution for theme developers) and the styles template.

As all the LESS data is compiled to a single CSS file, it’s very easy to keep a modular structure that allows for a “table of contents” view through multiple files, folders and prefixing.

You’ll notice on this website that I enqueue two files, screen.less and print.less for their respective purposes. However, print.less is simply a different collection of modular pieces then screen.less is.

functions.php

function nt_less() {
     if ( ! is_admin() ) {
          wp_enqueue_style( 'screen', get_stylesheet_directory_uri() . '/screen.less', null, '2.2', 'screen' );
          wp_enqueue_style( 'print', get_stylesheet_directory_uri() . '/print.less', null, '2.2', 'print' );
     }
}
add_action('wp_enqueue_scripts', 'nt_less');

screen.less

/* Foundation
* ----------------------------------------------------------------- */
@import "prometheus/prometheus.less";
@import "prometheus/less/1140.less";
/* Site
* ----------------------------------------------------------------- */
@import "less/variables.less";
@import "less/typography.less";
@import "less/body.less";
@import "less/mobile.less";
/* Plugins
* ----------------------------------------------------------------- */
@import "less/x_jquery_grid.less";
@import "less/x_wppaginate.less";
@import "less/x_gravityforms.less";
@import "less/x_syntaxhighlighter.less"

print.less

This took another five minutes to put together due to the modular structure (try print preview to see the end result). It’s a stripped down version of screen.less with the added .do-not-print class.

/* Foundation
* ----------------------------------------------------------------- */
@import "prometheus/prometheus.less";
@import "prometheus/less/1140.less";
/* Site
* ----------------------------------------------------------------- */
@import "less/variables.less";
@import "less/typography.less";
/* Print-specific
* ----------------------------------------------------------------- */
.do-not-print {
    display:none;
}

3) LESS Tips

Now that you’re setup with LESS and WordPress, you’re ready to save some serious work time! There are a number of common practices I’ve come up with that I hope will help you out too:

Create duplicate LESS files for your Plugins

You’ll notice in screen.less I have separate LESS files for the plugins I use on this site (all prefixed with “x_” so that they sink to the bottom of my directories). I always turn off plugin styles and copy the contents into a LESS file. This allows me to use variables and mixins right from the start when it comes to customizing their individual styles. It’s a pain to have to edit vendor prefixes within other CSS files or to constantly have be wary of any plugin updates overwriting your files.  Plugin CSS rarely changes in my experience and having them in LESS right from the start is a huge win (and results in less files being outputted, no pun).

Generic and Prefixed Variable Names

During the construction of a website, you’ll easily find yourself changing colors and fonts regularly till you find the right fit. Whilst I used to use variables such as @helvetica or @lightblue, I now use more flexible equivalents, such as @f-body and @c-hover. This comes with the great benefit that you never have to change the variable names across different files, nor do you ever have to wonder what the context is.

Nesting is your friend

This is one of the features I find so powerful yet underused with LESS. Nesting gives us an enhanced workflow for inheritance, one that effectively kills off repetition and provides truly valuable visual structure.

Let’s take a simple example. Check out the responsive version of this website and you’ll notice a navigation toggle. The LESS for this is dead simple, and probably doesn’t feel too remote from standard CSS. However, imagine this with multiple dropdown’s, interaction states and more. Being able to nest in such situations is invaluable (anyone remember superfish.css? ugh, endless .sf-menu declarations).

#mobile-nav-flyout {
   background:rgba(18,38,60,1);
   ul, li {
      margin: 0;
   }
   li {
      text-transform: uppercase;
      font-size:16px;
      border-top: 1px solid rgba(255,255,255,0.05);
      border-bottom: 1px solid rgba(0,0,0,0.15);
         &:first-child {
            border-top:none;
         }
         &:last-child {
            border-bottom:none;
         }
         a {
            display:block;
            padding:10px 20px;
         }
   }
}

Easy Color Changes

Colors change so often during development that it can be time-consuming to constantly go and find the right hex colors.

Instead of having to seek out random hex colors such as this example:

.gradientBar(#FF5536, #ED3314);

We can simply work off a color variable to create a slightly lighter or darker value:

.gradientBar(@c-sec + #111, @c-sec);

Both will output the same in the end:

background-color: #f73d1e;
background-image: -moz-linear-gradient(top,#fe4425,#ed3314);
background-image: -webkit-gradient(linear,0 0,0 100%,from(#fe4425),to(#ed3314));
background-image: -webkit-linear-gradient(top,#fe4425,#ed3314);
background-image: -o-linear-gradient(top,#fe4425,#ed3314);
background-image: linear-gradient(to bottom,#fe4425,#ed3314);

Do you use LESS?

What are your experiences with LESS? Are you using it for WordPress or client projects? Would be interesting to hear how others setup their themes and have increased their CSS productivity.

WordCamps, can we get a Case Studies Track?

I’ve always been of the opinion that WordCamp is about everything that happens outside of the presentations. Whilst that is still the most important to me, I do find myself occasionally looking at the presentation schedule and not feeling particular excited for a number of sessions. Why is that?

Photo by Erno Hannink

I’ve pondered over this question during the past few events and have come to the conclusion that sessions which focus on general knowledge as opposed to specific experiences simply interest me less (full disclaimer: I’ve been guilty of incorporating some of those elements in my presentations too).

Characteristics of such “general knowledge” presentations could be summarized as such:

  • Regurgitating Tutorials / Codex
  • List-based Presentations
  • Product explanations

Said differently, if a few simple searches on Google cover 90% of the talking points, there’s little value (regardless if you’re a beginner or an advanced user). There are so many resources online covering the area of WordPress “general knowledge” that a person can effectively find pages that match their skill level within minutes.

Case Studies

Let’s look at a few presentation topics that keep popping up at WordCamps and see how they could potentially become more interesting:

  • Introduction to Custom Post Types or How we used Custom Post Types & Google Maps to create a University Campus Map
  • WordPress and SEO or WordPress, SEO and how we boosted Donations for our Charity by 361%
  • Introducing SuperEpicPress or Everything that went wrong releasing our Premium Plugin

The fundamental difference here, is that domain expertise by itself doesn’t pique my interest, much less get me excited about an idea. Domain expertise mixed with successes, failures, lessons learned and real experiences however does. It can transform a bland presentation into something that inspires, motivates and further ignites lengthy discussions. More than anything though, these sort of case study presentations add real value and depth to the WordPress ecosystem, especially when we’re already all sitting in the same room.

To further help describe the idea, here are some talks I thought fit this concept of a Case Studies or Lessons Learned track particularly well:

Proposal

In a nutshell, if your WordCamp is a multi-track event, I propose cutting out the linear or general knowledge presentations and add a “Case Studies” or “Lessons Learned” track. Here are some ideas to get the process moving:

  • Before WordCamp, ask attendees to reflect on the past year and to seek out their greatest successes, failures or lessons learned using WordPress.
  • Shoot for 20-30 minutes talking with 5-10 minutes for questions (though insightful presentations always prompt more questions).
  • Smart Snippets: Talk holistically about specific code, but include links to full code Gists within the relevant slides. This way both beginners and advanced users are satisfied.
  • Profit.

Your thoughts?

Do you agree with the overall idea or have a completely different opinion? Any takers? Vote and discuss.

Making sense of the WordPress.com Redesign

In pursuit of awesome conversion rates, I’ve been amazed by all sorts of landing pages over the years. The redesign of WordPress.com in the last day was obviously one to watch out for.  I however can’t help but wonder if they’re going to see the amount of sign-ups decline? The first rule of conversion club is make no assumptions, but I’ll go out on a limb as to why this may not work.

Too heavily inspired by Squarespace

I’ve been a big fan of Squarespace landing pages for years. They constantly A/B test and as a result have been able to evolve significantly over the years. One of the biggest things I’ve learned running happytables, is that you don’t ship code, you ship decisions. So when a company creates a design based off of another’s code, it’s taking action without understanding why. This is the overwhelming feeling I get from the redesign, I have the impression it will work against WordPress.com.

Wordpress dot com landing page

Squarespace migrated to the big background image and simple call to action. WordPress did the same, but turned cold showing only black and white images. To make matters worse, there is not a single human being in any of the frames. It also completely misses on the point that the Squarespace image is in fact a real customer (hidden on the screenshot above, but noted on the website “PARTS AND LABOR DESIGN, Manhattan Design Firm, Squarespace Customer”).

squarespace landing page

Social Proof has been Destroyed

I’m a big believer in using as many third parties as you can to validate your business. I already mentioned human photography being absent, but with the new design I don’t even know if any humans use WordPress.com at all. Let’s look at the old landing page:

Old WordPress.com landing page

There’s a lot I love about it, the biggest being this sense of “activity” and “momentum”. Some noteworthy points:

  • Insane statistics right next to the call to action.
  • Faces, diversity and life as whole. It shows off WordPress at its best, quite literally “trying to make the world a better place”. I’m a sucker for this statement and wish I could copy it for happytables. I think it’s an important part of Automattic’s brand that should continue to be reflected on the new landing page too.
  • Zero clutter, maximum conversion.  I often considered testing this layout for happytables, showing off six to nine real restaurants above the fold (and leaving the sales’y gibberish out).
That’s all gone now.

Final Touches?

The custom domain input isn’t clickable (yet feels like it should), the language block is floating randomly and subsequent call to actions on the page are subdued. I get it, it’s the minimum viable product of a new idea. But if the goal is to test the concept of the Squarespace landing page, it won’t work. Squarespace is a 12’000+ pixel behemoth that has been polished over and over again internally. They’ve taken the long copy landing page (that SEOMoz once crushed) and transformed it into a “long media” landing page. It’s some really innovative stuff that I’m sure sparked a number of internal debates and probably took way more iterations than originally intended  (maybe someone can share?) .

In my opinion, WordPress.com is too big to test this early in the design process, but hopefully someone can prove me wrong.

Your thoughts?

I’ve been wrong many times, even for what I thought were “obvious” A/B experiments. I for one would love to get my hands on the analytics/testing data of WordPress.com, so maybe someone will share hard figures in the near future.

In the meantime, what are your thoughts on this redesign?

Custom Post Types are not Posts

Custom post types are e-commerce products, books, real estate properties and many other things, but the last thing they are, are posts. So why do we continue to use the default posts interface to manage all this awesome additional information we’re storing?

Data.

I was wondering about this issue a while back, as we (Theme Force) use custom post types to store information for a number of the features we maintain (after all, it’s a darn powerful feature of WordPress). Our features are all relatively simple concepts (food, event, slides, etc.), but we were making it far too hard to use. This, simply because we had visually ridiculed information that already had context, to plain old data bound by post_id’s, thus leaving it up to the user to find their way around a table that doesn’t differ much from the SQL one (like the screenshot below):

custom post type customized wordpress

Mind you, the above was an awesome interface to us, but our users let us know in many ways that this wasn’t working for them (in the worst possible way,  not using it at all). The pretty design, easy accessibility to add/update items was really cool, but it didn’t bring enough structure or hierarchy for the user to even remotely feel productive (see my previous article for more on that, WP Admin is an Experience too.). Imagine you order a hamburger in a restaurant, and 20 minutes later you’re served a plate with each individual ingredient laid out flat on the plate in a uniform manner. Not very appetizing right? Neither are the default one-size-fits-all data tables.

Data + Context.

Fast-forward a few months, we’re now taking the time to build an interface for our food menu custom post type that actually reflects the look and feel of a real menu (seems so logical when you think of it now), bringing together context and hierarchy. It is after all our goal to become the top provider of restaurant websites globally, and not every user is as forgiving and patient as our awesome early adopters have been. Whilst it isn’t complete yet and we’ll certainly have changes to make after it goes live, it’s already miles ahead of its predecessor. Watch the video in full-screen below to get a feel for a different kind of post type.

Click on the full-screen icon in the bottom-right hand corner:

Final Thoughts

Whilst some custom post types can easily use the standard interface, there are a number of cases that could be simplified a whole lot more.  In other environments, you may have no end-users and be the sole person responsible for input, in which case it doesn’t make sense either. However, it’d be really interesting to see where the level of customization goes within the WordPress community when representing custom post types within the admin area. With the already included jQuery UI and a handful of functions (wp_insert_post, wp_update_post, wp_delete_post) you’re already 90% of the way there. Less screen clutter, less clicks for the user and more visual hierarchy all lead to a more awesome experience for your users. What are your thoughts?

WP Admin is an Experience too.

Many of us working with WordPress on a daily basis focus all our creative energy on how our solutions interact with the user through the theme. But what about the admin area? According to W3Techs, WordPress is now running 15% of sites, but how many of them have an admin area that is tailored to the user, the same way you craft a theme to evoke certain emotions or create an experience?

When I attended the Frontend Conference ’11, I went to an interface design presentation by Bastian Allgeier (who created and maintains Zootool). He made some great points, one of the concepts I liked the most was taking this customers perspective when evaluating an interface:

  1. Does it have the features I need?
  2. Does it match my workflow?
  3. Does it feel good?

He went on to say that a great interface can make you (feel) more productive. It resonated well with me and it’s something I finally have a little time to experiment with before taking Theme Force out of beta. The challenge with something like Theme Force, a web application built on top of WordPress, is relatively simple to explain: A potential client sees our demo and wants a site exactly like that, but doesn’t want to get lost setting it up. They’ll likely make up their mind whilst working in the admin area. Wouldn’t I want them to feel good and feel productive, when browsing through this area (assuming we can satisfy their business requirements)?

What Experience?

Though it’s not easy to quantify, I’m a firm believer that experiences can be created in a precise manner, and that having the correct features & functionality is only half the battle. Take the Apple store in New York for example. They could have easily done with much less, but no, they create a glass cube and build a shop beneath it. The iPod’s & iPhone’s are still the same, but the experience is worlds apart (see those two circular metal connectors on each step, Apple patented those in 2002, and no, they are not an actual product sold by Apple). Carefully designed experiences attach so much more emotion to the end product. As developers, we should be just as considerate of the experience as we are of the features.


How does this all come back to WordPress? Well, does the current admin UI make your users feel good? Do your solutions even need to make them feel good? In our case (Theme Force), you bet it does, they’ll likely make their purchasing decision whilst hanging out in the admin area. I’m by no means saying you need to create an entirely new UI, but they can be small changes too. For example, I love what Chris Pearson did with the Thesis options page back in the day. Look at the save button below, how can you not feel even the slightest bit more of accomplishment than over a standard browser submit button? When I first clicked it, I probably muttered something like “F*** yeah” under my breath.

Nor Apple’s connectors or Chris’s big ass save button are actually product features, but both are very relevant in creating and maintaining an experience. Even if they both are very small parts of a much larger picture, they both do contribute to this picture. It seems that everyone selling WordPress themes these days has a mascot to parade around their website, but how many are keeping up this engagement throughout the admin area (or worse, are still going Inception on us with a design within a design)?

What Admin?

The WordPress admin area is really beautifully done, the core UI team have managed to design the closest thing you’ll ever get to “one size fits all”, and it’s by no means an easy feat. That being said, as soon as you start working on client projects or other online solutions based on WordPress, your requirements will certainly change (and more importantly, client expectations too). It’s also important to note that developers providing visual themes or function-specific plug-ins can’t exactly take over someones WordPress entire install, so their room for maneuvering is limited. However, if you’re creating a solution to be enjoyed by many, it’s worth taking a few chances. The items below will describe some of the things we’ve done so far with Theme Force.

Branding

To our users, WordPress is just a tool, the same way Google Apps or DropBox is a tool. It solves one of their problems (the last thing a restaurant owner wants to deal with is their website). There’s no point in confusing them by showing them all the different building blocks that make up the entire site.  As such, we’ve replaced any sort of WordPress wording all the way from sales material to the dashboard (except for a credit in the admin footer). Similarly, if we use any plug-ins that have a branded or complicated name, we’d just turn it into something generic. “Ultimate Twitter Badge” would simply become “Twitter”. Whilst, we’re still polishing parts, having a consistent tone & style in your copy throughout the admin area is equally important.

Overall Design

Changing the overall look and feel of the UI is probably where I’ll find the most controversy, but it’s something I feel is important to spend time tailoring for your end user. I personally find the current core UI very compact & well compartmentalized. With Theme Force, I wanted to move into a direction that’s a little warmer and has a bit more breathing room between select elements. My end users are far from being computer experts, so I feel it’s important to emphasize certain structure & hierarchy even more than before. In addition, we’ve also segregated views to create a “Simple View” (below) and an “Advanced View” as part of an onboarding process.  The current image below is all work in progress, but you get the idea.

custom wordpress admin

Editor

Another area we’ve been working on is simplifying the editor. First off, I would never even attempt to use the words TinyMCE or Shortcodes with a client.  So instead of adding a TinyMCE button after a series of other very small buttons, we put the important features for our clients right above the editor. Furthermore, our food menu is quite pretty (example here), however isn’t the easiest concept to explain to a first-time user (and we certainly don’t want them to disconnect 3 minutes into their trial). So WordPress magician Joe Hoyle managed to replace our in-editor shortcodes with images. Customer support queries in respect to this has dropped significantly since.

shortcode image replacement

Less is More

Something else I’ve done is started stripping a bunch of content & elements from the UI for our “Simple View”. A first time user won’t care for certain options. Take creating a page for example, you’ll see characteristics such as “Status:Draft”, “Visibility:Public”, “Publish:immediately”. These are all useless to our type of clientele, hence we’ve hidden them. By eliminating a lot of this fluff, we’re better able to guide/channel user into a certain direction.

Final Thoughts

Whilst I’m only scratching the surface, one thing is already clear: It’s a lot easier to get carried away creating new things, then to go back and question the old. As we’re getting closer to launch, I’m finding it increasingly important to leave the feature-set as it is, and focusing on the glue that bonds new users & the product, or what I hope can be collectively described as an experience (and not a loose set of screens & buttons). I’ll continue to post on our experiences, and if people are also interested, touch on the elements of gamification we’re implementing. What is your opinion on extending the tailored user experience you already provide right into the admin area? Do you have any nice examples or other comments?

Community Reactions on touching the UI

Thanks to the following people for tweeting their opinion:

Custom Post Type – FullCalendar & JSON with WordPress

This tutorial builds on my previous how-to’s relating to creating & using Events with Custom Post Types (all within WordPress). With the first tutorial came a number of comments, a couple of which were looking to integrate the events custom post type with FullCalendar, an extremely well put together jQuery plugin created by Adam Shaw . Today’s guide will do just that (but this can obviously be applied to regular posts too).

fullcalendar wordpress

1) requirements

As stated, our goal is to display a beautiful calendar within WordPress listing our events. FullCalendar accepts event data in a variety of ways (even Google calendars), but for our purpose we will use JSON (JavaScript Object Notation). That may sound foreign to some of you, but it’s actually all very easy. What we will do today, is create a simple JSON feed using our custom post type data that will then be read by FullCalendar. Once that is in place, we will need to make sure FullCalendar is integrated into WordPress and then finally display the calendar!

2) json-feed.php – header

It’s important to note that the file we’ll be creating is standalone, you don’t include it through your functions.php or elsewhere. As such, our header should come as no surprise. The paths listed below also assume that this document will be within a sub-folder of your theme (i.e. /includes/json-feed.php, /functions/json-feed.php).

// - standalone json feed -
header('Content-Type:application/json');
// - grab wp load, wherever it's hiding -
if(file_exists('../../../../wp-load.php')) :
	include '../../../../wp-load.php';
else:
	include '../../../../../wp-load.php';
endif;
global $wpdb;

We declare the document type and then include wp-load to be able to make use of WordPress functionality & data.

3) json-feed.php – query

Now that you’re document is correctly coded and is hooked into WordPress, you’ll run the query you’ve seen in previous tutorials.

// - grab date barrier -
$today6am = strtotime('today 6:00') + ( get_option( 'gmt_offset' ) * 3600 );
// - query -
global $wpdb;
$querystr = "
    SELECT *
    FROM $wpdb->posts wposts, $wpdb->postmeta metastart, $wpdb->postmeta metaend
    WHERE (wposts.ID = metastart.post_id AND wposts.ID = metaend.post_id)
    AND (metaend.meta_key = 'tf_events_enddate' AND metaend.meta_value > $today6am )
    AND metastart.meta_key = 'tf_events_enddate'
    AND wposts.post_type = 'tf_events'
    AND wposts.post_status = 'publish'
    ORDER BY metastart.meta_value ASC LIMIT 500
 ";
$events = $wpdb->get_results($querystr, OBJECT);
$jsonevents = array();
// - loop -
if ($events):
global $post;
foreach ($events as $post):
setup_postdata($post);
// - custom post type variables -
$custom = get_post_custom(get_the_ID());
$sd = $custom["tf_events_startdate"][0];
$ed = $custom["tf_events_enddate"][0];
// - grab gmt for start -
$gmts = date('Y-m-d H:i:s', $sd);
$gmts = get_gmt_from_date($gmts); // this function requires Y-m-d H:i:s
$gmts = strtotime($gmts);
// - grab gmt for end -
$gmte = date('Y-m-d H:i:s', $ed);
$gmte = get_gmt_from_date($gmte); // this function requires Y-m-d H:i:s
$gmte = strtotime($gmte);
// - set to ISO 8601 date format -
$stime = date('c', $gmts);
$etime = date('c', $gmte);
// - json items -
$jsonevents[]= array(
    'title' => $post->post_title,
    'allDay' => false, //  $stime,
    'end' => $etime,
    'url' => get_permalink($post->ID)
    );
endforeach;
else :
endif;
// - fire away -
echo json_encode($jsonevents);

Many of the items should be familiar from the previous tutorials, $today6am to only grab future events (in a human way, not just event >= now), various $gmt variables are to convert the time to GMT+0 (a good practice, and was also done with my iCal export tutorial). What is new here however, is that we’re outputting arrays within an array in order to produce the JSON output. Above the loop, we declare $jsonevents as an array, and then during the loop populate it with individual event arrays containing all our data. See the event object documentation for more information about these parameters.

Finally we grab all the data and encode it in the JSON format. The feed is now done, that was easier than you thought right?

4) json-feed.php – validation

Before, we take another step, lets make sure that our feed validates. To do that, just copy paste your output (by visiting the file’s URL) here JSON Formatter & Validator. Everything should come up green!
fullcalendar wordpress json

You’ll also notice that my event times in the screenshot above have the timezone +00:00, which is exactly what we were striving for.

5) functions.php

I don’t particularly like adding JavaScript files through header.php, and the codex also explicitly states that such scripts should be enqueued. Not only are we doing that below (similar to past tutorials), but also using some PHP to derive the values of one of the JS parameters, in this case the file path to the json feed (we’re using the localize function to do that, storing within $jsonevents). GCal is also optional, unless of course you’d like to use Google Calendars instead of our JSON feed.

function load_themeforce_js() {
// ... my other scripts...
// - fullcalendar -
wp_enqueue_script('fullcalendar', (get_bloginfo('template_url')) . '/js/fullcalendar.js', array('jquery'));
wp_enqueue_script('gcal', (get_bloginfo('template_url')) . '/js/gcal.js', array('jquery'));
// - set path to json feed -
$jsonevents = get_bloginfo('template_url') . '/functions/json-feed.php';
// - tell JS to use this variable instead of a static value -
wp_localize_script( 'fullcalendar', 'themeforce', array(
	'events' => $jsonevents,
	));
}
add_action('wp_print_scripts', 'load_themeforce_js');

Last but not least we add this action to the print scripts hook.

6) header.php

Here, you can choose what you want to do, but to stay in line with the above section, we’ll add the actual jQuery script right into the header file (below wp_head() ):

<script type="text/javascript">// <![CDATA[
    jQuery(document).ready(function() {
    jQuery('#calendar').fullCalendar({
        events: themeforce.events
        });
});
// ]]></script>

You’ll see here that the parameter events is referencing to themeforce.events, a variable that we provided through the localize script in our functions.php. This entire script will essentially tell your browser; load the calendar in the div with ID ‘calendar’ and pull the data from the json path (which is derived from themeforce.events variable).

Also within the header, you’ll want to pull in the CSS file from FullCalendar:

7) fullcalendar.js

Remember how we are converting times to GMT +0? Well FullCalendar doesn’t timezone conversion on by default, so we’ll need to make a small edit to the actual javascript file (as adding it to the URL didn’t seem to function for our scenario). Just go into fullcalendar.js and search ignoreTimezone, find the instance which gives it the value true and then change it to false, like so (line #39 of the full JS file):

ignoreTimezone: false,

8) making it all happen

Yep, you guessed it. To make this all show up now, all you need to do is add the container which is called out in section 6 above. Obviously don’t add this in the ‘Visual’ part of a page, but the ‘HTML‘ segment.

</pre>
<div id="calendar"></div>
<pre>

You are finally done, make sure you style your fullcalendar.css file to give it that final polish! If you’re getting stuck understanding certain elements, just google the terms (if it’s a WordPress concept, search it in the Codex). Copy paste will only take you so far, understanding the underlying concepts (even if only on a higher level) will take you much further.

your turn to speak

Would you like to share your FullCalendar WordPress combo, discuss customizations or add your insights to this article? I’d love to hear what you think on this subject.

Review: Professional WordPress Plugin Development (2011)

Being a theme designer & developer, Professional WordPress Plugin Development is a breath of fresh air in a community where learning material is oftentimes scattered, fragmented or incomplete. Don’t get me wrong, there are plenty of great resources out there, but you’ll need to dig for them. Having a concise reference book and/or ‘best practices’ guide is essential to a more efficient workflow. Brad Williams, Ozh Richard and Justin Tadlock have teamed up to deliver just that for the WordPress community. The content is well structured and gets right to the point, so don’t expect any motivational speeches or manifesto’s in the style of Gary Vaynerchuk or Seth Godin. This is purely related to how to create better WordPress plug-ins, free of any politics or opinions. In other words, a perfect companion for your keyboard.

That being said, I find the following chapters to be of great value to me (being on the theme side of the business):

  • 6) Plugin Security
  • 7) Plugin Settings (mainly dealing with the various API’s)
  • 13) Cron
  • 16) Debugging and Optimizing

This isn’t to say that the other chapters are of lesser value, by no means, but I always had more trouble finding great documentation online for the above matters then topics like custom post types, localization or shortcodes (although the segment on Geocoding was new to me, thank you). It’s an entirely worthwhile investment at this point in time (I get the impression that WordPress moves fast enough to require updated editions periodically). As a theme developer, the only thing that I didn’t see was any mention of the mysql2date() function which is really handy for internationalization (please correct me if I missed out on it).

In terms of print quality, it would have been nice to have color printing (I’m not a developer remember ;) ), this way different syntax can be color-coded and in turn, the <500 pages are more manageable to sift through (but at the same time, I don’t need that sort of guilty conscience with regards to the environment).

Congratulations to the 3 authors, I look forward to more publications by the trio (though I’d also very much like to see Samuel Wood or Andrew Nacin work on some WP books at one point). I don’t have any referral incentive for posting this review, so head over to Amazon and get yourself a copy.

How-to: iCal with Custom Post Types

In line with my previous custom post type tutorials for events (backend & frontend), I’d like to show how easy it is to create an iCal feed of those events (download the full file here). There are a few iCal for WordPress plug-ins out there, but none that will handle custom post types right off the bat. Besides, you’ll be setup in no time.

1) iCal requirements

iCal is Apple’s calendar application, but over time has gained widespread support & functionality in other tools (MS Outlook, GMail, Yahoo, etc.) so depending on your type of crowd, this sort of feature can really come in handy (think how easy it would be to grab and store dates to your mobile phone directly from WordPress).

2) ical.php

As is good practice, this sort of stand-alone functionality should be in its own file. The goal of this document will be to 1) create a function that constructs the output, and 2) registering that output as a feed. Let’s get right into it:

3) header information

<?php
function tf_events_ical() {
// - start collecting output -
ob_start();
// - file header -
header('Content-type: text/calendar');
header('Content-Disposition: attachment; filename="ical.ics"');
// - content header -
?>
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//<?php the_title(); ?>//NONSGML Events //EN
X-WR-CALNAME:<?php the_title(); _e(' - Events','themeforce'); ?>
X-ORIGINAL-URL:<?php echo the_permalink(); ?>
X-WR-CALDESC:<?php the_title(); _e(' - Events','themeforce'); ?>
CALSCALE:GREGORIAN
<?php

As you may have seen in the previous tutorials, we’re using ob_start() to collect all outputted content after that point. We then tell the function that the actual document header should contain certain parameters that will 1) help it be identified as a calendar & 2) actually output as a downloadable .ics file when the feed is called upon. This is the right way about it as the end-user will be prompted for a download. They’ll then accept and open the file in a calendar application of their choice (which will import the events). Otherwise the user would just see a text feed that is unusable in this context.

Next up, we pump out some content header information. This stuff is essentially what meta information is to html (i.e. description, keywords, author), although iCal carries different information. I was lucky enough to stumble upon this site which had plenty of information on the subject.

4) events listing

At this point, we’re ready to list each event item in the correct iCal format. Before we create those items though, we’ll need to run a query to pull all the data in (and as you may recall, this looks just like the one in my previous tutorial):

<?php
// - grab date barrier -
$today6am = strtotime('today 6:00') + ( get_option( 'gmt_offset' ) * 3600 );
$limit = get_option('pubforce_rss_limit');
// - query -
global $wpdb;
$querystr = "
    SELECT *
    FROM $wpdb->posts wposts, $wpdb->postmeta metastart, $wpdb->postmeta metaend
    WHERE (wposts.ID = metastart.post_id AND wposts.ID = metaend.post_id)
    AND (metaend.meta_key = 'tf_events_enddate' AND metaend.meta_value > $today6am )
    AND metastart.meta_key = 'tf_events_enddate'
    AND wposts.post_type = 'tf_events'
    AND wposts.post_status = 'publish'
    ORDER BY metastart.meta_value ASC LIMIT $limit
 ";
$events = $wpdb->get_results($querystr, OBJECT);
// - loop -
if ($events):
global $post;
foreach ($events as $post):
setup_postdata($post);

My 6 am time limit is once again in place to only show relevant events (i.e. nothing that has already passed). The rest of the query is quite straightforward, but we’ll need to do one last thing before returning the individual events. iCal requires a special date format, especially in our case where we’ll be appending the character “Z” (that tells the importing calendar that the date will be set to the GMT+0 timezone). For example, 20100130T134500Z, is the 30th of January, 2010 – 1:45pm GMT+0. Appending the Z is good practice, especially if you only have a single person in another timezone.

// - custom variables -
$custom = get_post_custom(get_the_ID());
$sd = $custom["tf_events_startdate"][0];
$ed = $custom["tf_events_enddate"][0];
// - grab gmt for start -
$gmts = date('Y-m-d H:i:s', $sd);
$gmts = get_gmt_from_date($gmts); // this function requires Y-m-d H:i:s
$gmts = strtotime($gmts);
// - grab gmt for end -
$gmte = date('Y-m-d H:i:s', $ed);
$gmte = get_gmt_from_date($gmte); // this function requires Y-m-d H:i:s
$gmte = strtotime($gmte);
// - Set to UTC ICAL FORMAT -
$stime = date('Ymd\THis\Z', $gmts);
$etime = date('Ymd\THis\Z', $gmte);

Pfew, seems like a lot, but it should all make sense. We’re finally ready to output each event which will carry the following format:

// - item output -
?>
BEGIN:VEVENT
DTSTART:<?php echo $stime; ?>
DTEND:<?php echo $etime; ?>
SUMMARY:<?php echo the_title(); ?>
DESCRIPTION:<?php the_excerpt_rss('', TRUE, '', 50); ?>
END:VEVENT
<?php
endforeach;
else :
endif;
?>
END:VCALENDAR

That wasn’t that hard was it? Our loop completes here and all the content we need to generate is complete.

5) closing off

We then need to turn off output buffering and package it into a single variable that is then echoed. Finally, we register this content as a feed (‘add_feed‘) and add this action once WordPress has completed loading (‘init‘)

// - full output -
$tfeventsical = ob_get_contents();
ob_end_clean();
echo $tfeventsical;
}
function add_tf_events_ical_feed () {
    // - add it to WP RSS feeds -
    add_feed('tf-events-ical', 'tf_events_ical');
}
add_action('init','add_tf_events_ical_feed');

At this point, we’re done and your feed (or rather downloadable file) is accessed through www.yoursite.com/?feed=tf-events-ical.

your turn to speak

Can an iCal feed help your site or do you already use some form of it? Are there any enhancements you’d add, or code you’d write differently? Feel free to share anything you want, always great to get different opinions!

How-to: Custom Post Type for Events Pt. 2

Now that we’ve handled the entire registration and back-end functionality (see Pt. 1) of our events custom post type, it’s time to move on to our design output (download the file for this tutorial here)! There’s no point in having fancy custom post types if you can’t display them properly. As you may remember, the entire reason for me requiring this functionality is for my Pub Theme (Pubforce), so I need to give my clients some flexibility with regards to its use. As you can see from the screenshot below, I have the following designs: 1) Featured (Shown with Big Thumbnail), 2) Full Listing (which groups by day) and 3) Widget Listing (again, grouping by day).

custom post types events pub

I don’t want to hinder my end-users in any way so I’ve chosen to use shortcodes to let them decide where and how they want to deploy events within the main area, so let’s get right to that! My tutorial below will revolve around design #2 above.

1) shortcode structure

Shortcodes remind me a lot of Excel macro’s; very detailed scripts serving a specific purpose, yet simple enough that they allow non-developers the ability to pass parameters and make use of them where and how they want. This is a massive plus over something like a page template which is a lot more rigid in its ways.

Incase you’re not all too familiar with shortcodes, I’ve laid out the basic structure below (but be sure to read the relevant codex article):

function shortcode_function ( $atts ) {
	// - define arguments -
	extract(shortcode_atts(array(
		'name' => '',
	 ), $atts));
	// - spit output -
	$output = 'My name is' . $name;
	return $output;
	}
add_shortcode('introduction', 'shortcode_function');
?>

Thus, if I were to now insert [introduction name=”Noel”] in a post, I’d get “My name is Noel“. Really hard right? As the code is going to get really long after, I’m just going to take it one step further to show you the shell of the shortcode we’ll create today. We’re going to use a nifty little function called Output Buffer (which just collects everything that is produced, starting with ob_start() and ending with ob_get_contents()). This will save us from having to piece everything together a different way (shortcodes require the use of ‘return‘, hence all this messing around):

function tf_events_full ( $atts ) {
	// - define arguments -
	extract(shortcode_atts(array(
		'limit' => '10', // Default amount of events to show
	 ), $atts))
	// - start grabbing output -
	ob_start();
	// - generate output -
	... next step of the tutorial ...
	// - spit output -
	$output = ob_get_contents();
	ob_end_clean();
	return $output;
	}
add_shortcode('tf-events-full', ' tf_events_full');
?>

Now that we have the shell of our shortcode, lets move on to more interesting things shall we.

2) query

Although tradition would have dictated I use a built-in function such as wp_query, I wanted to leave my options down the road without having to rewrite everything. This is why I’m using a custom select query which lets you do anything you want (more or less).

// - hide events that are older than 6am today -
$today6am = strtotime('today 6:00') + ( get_option( 'gmt_offset' ) * 3600 );
// - query -
global $wpdb;
$querystr = "
    SELECT *
    FROM $wpdb->posts wposts, $wpdb->postmeta metastart, $wpdb->postmeta metaend
    WHERE (wposts.ID = metastart.post_id AND wposts.ID = metaend.post_id)
    AND (metaend.meta_key = 'tf_events_enddate' AND metaend.meta_value > $today6am )
    AND metastart.meta_key = 'tf_events_enddate'
    AND wposts.post_type = 'tf_events'
    AND wposts.post_status = 'publish'
    ORDER BY metastart.meta_value ASC LIMIT $limit
 ";
$events = $wpdb->get_results($querystr, OBJECT);

You’ll notice right at the top that I’m defining this variable called $today6am. Given my clients all run Pubs, I figured this would be a good time to make events disappear. I like the concept of removing dates on a daily basis as opposed to when they occur, and seeing as many events go into the early morning, I found 6am to be a happy medium to remove events that happened on the day before. You’ll also see that I’m conscious of the local timezone by multiplying the timezone difference in hours (gmt_offset) by how many seconds there are in an hour (3600). Adding this value to the Unix timestamp means it’s always 6am local time. Also note that I’m comparing against the event end time (as some events are full-day).

It’s also important that we call the postmeta twice (metastart & metaend), this way we can use the start & end time for their respective purposes; start for sorting the events and end for checking if they have expired.

Also, you’ll remember that $limit is a parameter passed through the shortcode (default ’10’).

3) loop

Now the loop itself, as mentioned above this is the final look we’re trying to achieve:

custom post types wordpress

In order to do that, this is the code we’ll require (starting off with the loop declaration itself and any variables we’d like to use in our final output):

// - declare fresh day -
$daycheck = null;
// - loop start -
if ($events):
global $post;
foreach ($events as $post):
setup_postdata($post);
// - custom variables -
$custom = get_post_custom(get_the_ID());
$sd = $custom["tf_events_startdate"][0];
$ed = $custom["tf_events_enddate"][0];
// - determine if it's a new day -
$longdate = date("l, F j, Y", $sd);
if ($daycheck == null) { echo '<h2 class="full-events">' . $longdate . '</h2>'; }
if ($daycheck != $longdate && $daycheck != null) { echo '<h2 class="full-events">' . $longdate . '</h2>'; }
// - local time format -
$time_format = get_option('time_format');
$stime = date($time_format, $sd);
$etime = date($time_format, $ed);
?>

… followed by the XHTML output …

<div class="full-events">
    <div class="text">
        <div class="title">
            <div class="time"><?php echo $stime . ' - ' . $etime; ?></div>
            <div class="eventtext"><?php the_title(); ?></div>
        </div>
    </div>
     <div class="desc"><?php if (strlen($post->post_content) > 150) { echo substr($post->post_content, 0, 150) . '...'; } else { echo $post->post_content; } ?></div>
</div>

… and finally the end of the loop …

<?php
// - fill daycheck with the current day -
$daycheck = $longdate;
// - go back to the top -
endforeach;
else :
endif;

You’re probably wondering what all those ‘day’ variables are? Well they’re there to help us group the events into days like the design above! Let me break it down so it makes more sense (see commenting):

// - declare fresh day -
$daycheck = null;
... loop starts ...
// - convert date -
$longdate = date("l, F j, Y", $sd);
// - if it's our first event, echo date as title -
if ($daycheck == null) { echo '<h2 class="full-events">' . $longdate . '</h2>'; }
// - if the date has changed since the last post, echo date as title -
if ($daycheck != $longdate && $daycheck != null) { echo '<h2 class="full-events">' . $longdate . '</h2>'; }
... output rest of event ...
// - fill daycheck with the current day -
$daycheck = $longdate;
... loop ends and repeats ...

4) bonus: featured loop

Now that we’ve got the regular event listing done, I figured I’d go an extra step to show you how a featured event is displayed. The big difference here is that we’ll be using the custom taxonomy that we created to help filter results. Specifically, the end user will be able to select ‘Featured’ to trigger the required visibility:

Instead of repeating the entire code, I’m just going to show you the actual query, which is the most important change (as it now involves pulling in taxonomy data):

global $wpdb;
$querystr = "
SELECT *
FROM $wpdb->postmeta metastart, $wpdb->postmeta metaend, $wpdb->posts
LEFT JOIN $wpdb->term_relationships ON($wpdb->posts.ID = $wpdb->term_relationships.object_id)
LEFT JOIN $wpdb->term_taxonomy ON($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
LEFT JOIN $wpdb->terms ON($wpdb->terms.term_id = $wpdb->term_taxonomy.term_id)
WHERE ($wpdb->posts.ID = metastart.post_id AND $wpdb->posts.ID = metaend.post_id)
AND $wpdb->term_taxonomy.taxonomy = 'tf_eventcategory'
AND $wpdb->terms.name = '$group'
AND (metaend.meta_key = 'tf_events_enddate' AND metaend.meta_value > $today6am )
AND metastart.meta_key = 'tf_events_enddate'
AND $wpdb->posts.post_type = 'tf_events'
AND $wpdb->posts.post_status = 'publish'
ORDER BY metastart.meta_value ASC LIMIT $limit
";
$events = $wpdb->get_results($querystr, OBJECT);

You’ll notice I’ve also got a new variable in the mix called $group, this is by default ‘Featured’, however can be overridden by the user through the shortcode (maybe they only want to show Soccer matches). This is the sort of flexibility you want to give to your clients.

It would have also been possible to just create a checkbox within the custom post type, but again we’d be limiting user options and not making use of well-functioning WP code.

5) your turn to speak!

Your options are endless with this setup (you can downloaded the entire file here), but you’ll always need to beware of the amount of queries it runs as it can really be taxing on the server (check out my post on my development environment for more information on debugging).

If you have any suggestions, comments or ways you’d do things differently, please let me know by commenting below! I’d love to hear your take on this as well as your experiences. Feel free to ping me on Twitter @noeltock or retweet this message, always appreciated!

Fast & Furious WordPress Theme Development

I’m somewhat of a productivity nut; I automatically track my time through rescuetime, try to automate my workflows and absolutely despise repetitive work. After all, life is short, why spend it doing the same thing over and over again (I’m also fortunate enough to be able to make career choices)?

As a designer, coding has always had more of this “have to get it done” feel to it. Although I respect it (which is why I’m learning), I can’t relate much to the phrase “code is poetry”. I also don’t check into the WordPress Trac all too often or even know a single feature planned for PHP 6.  However, I love developing themes for WordPress and designing functional end-user solutions. This is also why I had taken it upon myself to delve into PHP, some jQuery and plenty of WordPress functionality. My first steps could probably be characterized as the typical NotePad & FTP Client setup, the equivalent of swimming laps in quicksand. The guide below is based on my experiences & needs as a designer,  I hope that you will join in and share yours.

All of the solutions I offer below are free, except for Beanstalk (where I can offer 10% off through this link). So in other words, this setup runs at about $15/month (or $0 if you’re willing to do away with automatic deployments). Before describing my time-savers, let me show you them!

It may seem like a lot of stuff, but I find it very manageable as a one man show. As WordPress is a core part of my daily business (Individual Clients + Theme Development for Theme Force), there’s no more room for inefficient workflows. I work on more than one theme everyday and certainly make more than a single change. It’s important that this process is safe, fast and efficient. Lets discuss the actual applications that help me save time:

1) netbeans (advanced editor)

What Photoshop is to MS Paint, Netbeans is to Notepad. It’s a pimped out code editor (or “integrated development environment”) that provides a project view, supports all the  common languages and even tells you off when you’re typing something funky (“This is your final warning Noel, stop using Excel functions for PHP!“). I had originally transitioned from Notepad to Notepad++, but even that was holding me back when I started getting serious about PHP. It’s really well done and easy to use for the non-developer types like myself, definitely give it a shot:

Time-Saving Features

  • Project View – When you close a project (or the application) it remembers which files you were working on. So when you re-open a project or start Netbeans the next day, you’ve got the same files open again.
  • Code-Assist (Error Checking) – It’s very smart at detecting mistakes or typo’s which can otherwise take you plenty of “investigating”. You can also easily comment lines or assign yourself To-Do’s.
  • SVN Support – You can commit changes directly from Netbeans.
  • Out of the Box Functionality – As soon as the install was complete, I didn’t have to touch anything more; PHP, XHTML, CSS, JS, etc. all recognized perfectly.

Overall and as a “non-developer”, I really enjoy working with this tool and feel like I have a much clearer overview of the items I’m working on.

2) xampp (local testing)

Confession: I actually used to upload my files via FTP for every single change (“overwrite existing file?”), it brings a whole new meaning to pissing in the wind. It gets old quick, especially once this WordPress stuff doesn’t become a hobby anymore. As a result I found XAMPP, and haven’t looked back since. The official website states “XAMPP is an easy to install Apache distribution containing MySQL, PHP and Perl. XAMPP is really very easy to install and to use – just download, extract and start.”. The statement is bang on and WordPress runs flawlessly within the environment:

Time-Saving Features

  • No more uploading / committing for testing – Instead of having  to go through your whole upload process, you just save the file and refresh your browser, voilà! Easily the biggest time-saver on this page (along with the auto-deployment from beanstalk, essentially the same thing).
  • Easy Test Environment Setup – It’s very easy to set up a new site or instance of WordPress (no upload, cpanel or general connection lag)
  • phpMyAdmin – Also included in the package and easily accessible through localhost/phpmyadmin . This sort of easy access is great when you’re troubleshooting database related matters.
  • Out of the Box Functionality – No different from Netbeans here; plug & play.

3) tortoisesvn (version control)

(Optional: As Netbeans can commit changes too, but has fewer features) Tortoise is a straightforward tool, enabling you to have easy version control right within Windows Explorer (given that you’re using a repository). For those who don’t know, the purpose of subversion is what could be summarized as a controlled collaborative environment where every change to the code is tagged as a revision, a full audit trail if you will. I like to keep my repositories on managed servers elsewhere (in my case beanstalk). Although I back up all my files through another provider, version control and collaboration is a massive plus here:

Time-Saving Features

  • Feature Rich – Be it grabbing a newer/older revision, exporting/relocating the repository or just committing your latest goods; its dead simple and integrated within Windows Explorer (i.e. right click access)
  • Windows Integration – Tortoisesvn is not a separate application visually, it integrates into your “right-click” menu within Windows Explorer. That’s a huge plus as it’s always accessible.

4) beanstalk app (subversion hosting)

I really love beanstalk; Have a look at the screenshot below, I did a commit by right clicking a folder within Windows and 16 seconds later it had been saved to my repository as well as deployed to my 2 production environments (as you can see deployment is set to “automatic” once the repository receives an update):

Although I’ve been self-sufficient for a while now, it’s also very helpful for easily verifying changes from other contributors:

Time-Saving Features

  • Automatic Deployment – Really just what I was looking for. Once everything looks good locally, I send it off to the repository which in turn automatically gets deployed (and I only pay $15 a month for this service).
  • Manual Deployments – You can rollback a deployment to any revision or do a full deployment (i.e. all files) at any time.
  • Collaboration – Easy user setup and great overview of what changes or contributions were made.

With a money back guarantee, you have nothing to lose by testing it out (and here’s 10% off).

5) wordpress time-savers

Last but not least, when you’re actually working within WordPress, there are some great tools out there to help you out:

  • WP-Devel (link) – If you want to see what’s going on within the back-end, this is the tool for you. I love using it to call me out on issues (non-existent variables, etc.) or reducing queries.
  • WP Dummy Content (link or a static pack here) – You don’t want to create dummy posts, pages, comments every time you’re testing a new theme. Get smart and use a tool to pre-populate your installation right off the bat, be it for testing design (i.e. unordered lists) or functionality (i.e. protected posts).
  • WP3 Cheat Sheet (link) – This actually has to do more with your actual WordPress knowledge, but the fact that there are consolidated lists out there, that are print-ready was worthy enough for me to mention (and I’m a big fan).

what does your development environment look like?

My method is by no means perfect or the only way of doing things (certainly not), but it fits my work style very nicely. I’d be interested in hearing how you work or develop on WordPress (be it for themes or plug-ins), so comment below and share with everyone else!

How-to: Custom Post Type for Events

Chances are you found this page looking for a tutorial on how to create Events with Custom Post Types within WordPress. I will outline the entire process I’ve used for one of my themes that I’m re-coding (in order to make use of this great feature). You can also download the entire custom post type file that includes the code mentioned here. This is the visual output as is in testing today (please see the second tutorial for the code on outputting the design):

Whilst this tutorial shows all the code, I’ll go over the “default” parts quite quickly and then focus on any code relating to the actual Events component. As a designer, I’ve found it very manageable to put together something that 5 years ago would have been so much more work (and who likes manual work?). So if I can do it, anyone can (really).

1) event requirements

Before hitting the code, it’s important to understand what you really need so that you can strive towards the simplest end solution. For the events custom post type of my theme,  I need to be able to show the following items (beyond the default fields):

  • Start Date
  • Start Time
  • End Date
  • End Time

I debated if I even required an end date (2 more fields to fill out for the user), but figured I’d probably be limiting my options for some of the other ideas I have. The great thing about storing dates is that they’re done so using Unix Time (i.e. seconds elapsed since 1/1/1970 as a single integer). This means that we have tons of flexibility when it comes to extracting and showing the dates with default PHP functions. As such, whilst the end user will see 4 fields, we’re only storing 2 fields (thus my custom post type will only require those 2 extra custom fields).

One thing I wanted to avoid was also feature bloat. There are plenty of event plug-ins out there with advanced functionality (recurrence, rsvp, paypal, etc.). I’ll leave those awesome things to the plug-in designers, there’s absolutely no need to reinvent the wheel there. My primary goal is to design themes, and the out of the box functionality I provide is a simple foundation that works with the design (more on that in my next tutorial). So, onto the good stuff:

2) registering our custom post type

I’ll assume you’re already somewhat familiar with this aspect of the custom post type process (it’s actually very well documented within the WordPress Codex). I’m not doing anything special either, so feel free to have a look or just skip right onto the next section. All we’re doing is providing a set of labels or phrases to be used by the Custom Post Type and then defining the characteristics or behavior of the post type itself. Also, if you want to save yourself an afternoon, make sure the actual name of the custom post type (not label) is 20 characters or less.

// 1. Custom Post Type Registration (Events)
add_action( 'init', 'create_event_postype' );
function create_event_postype() {
$labels = array(
    'name' => _x('Events', 'post type general name'),
    'singular_name' => _x('Event', 'post type singular name'),
    'add_new' => _x('Add New', 'events'),
    'add_new_item' => __('Add New Event'),
    'edit_item' => __('Edit Event'),
    'new_item' => __('New Event'),
    'view_item' => __('View Event'),
    'search_items' => __('Search Events'),
    'not_found' =>  __('No events found'),
    'not_found_in_trash' => __('No events found in Trash'),
    'parent_item_colon' => '',
);
$args = array(
    'label' => __('Events'),
    'labels' => $labels,
    'public' => true,
    'can_export' => true,
    'show_ui' => true,
    '_builtin' => false,
    'capability_type' => 'post',
    'menu_icon' => get_bloginfo('template_url').'/functions/images/event_16.png',
    'hierarchical' => false,
    'rewrite' => array( "slug" => "events" ),
    'supports'=> array('title', 'thumbnail', 'excerpt', 'editor') ,
    'show_in_nav_menus' => true,
    'taxonomies' => array( 'tf_eventcategory', 'post_tag')
);
register_post_type( 'tf_events', $args);
}

3) custom taxonomy

This step is optional, but always a safe play for anyone who’d like the ability to categorize their events. Again, I’m not doing anything out of the ordinary (except maybe making it hierarchical). Don’t forget to attach the taxonomy to the post type:

function create_eventcategory_taxonomy() {
$labels = array(
    'name' => _x( 'Categories', 'taxonomy general name' ),
    'singular_name' => _x( 'Category', 'taxonomy singular name' ),
    'search_items' =>  __( 'Search Categories' ),
    'popular_items' => __( 'Popular Categories' ),
    'all_items' => __( 'All Categories' ),
    'parent_item' => null,
    'parent_item_colon' => null,
    'edit_item' => __( 'Edit Category' ),
    'update_item' => __( 'Update Category' ),
    'add_new_item' => __( 'Add New Category' ),
    'new_item_name' => __( 'New Category Name' ),
    'separate_items_with_commas' => __( 'Separate categories with commas' ),
    'add_or_remove_items' => __( 'Add or remove categories' ),
    'choose_from_most_used' => __( 'Choose from the most used categories' ),
);
register_taxonomy('tf_eventcategory','tf_events', array(
    'label' => __('Event Category'),
    'labels' => $labels,
    'hierarchical' => true,
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array( 'slug' => 'event-category' ),
));
}
add_action( 'init', 'create_eventcategory_taxonomy', 0 );

4) creating & showing columns

This is where it starts to get more interesting. Within the dashboard, custom post types are listed the same way as regular posts & pages are, however we’re the ones who need to make it all happen. This is what our final output will look like:

As you’ll see from the code below, we need to create a function to define our headers (tf_events_edit_columns), and then another function to define with which content we’re going to populate it with (tf_events_custom_columns). Beyond the standard fields (title, description, etc.), I’m also going to show my times here, and this is thought process behind the event-related fields:

  • Dates – Here I’m grabbing the dates and hardcoding which format they should be output in. Dates are more or less universal, whereby times aren’t (i.e. 24hr vs AM/PM). Seeing as (in my case) the end date will almost always be the same as the start, I’ve subdued its visual effect to reduce the clutter a bit.
  • Times – As I mentioned above, 24hr vs AM/PM is an important factor. So to make this easy on the end-user we’ll grab the local format using get_option(‘time_format’) which we can then feed right into the date() function.
// 3. Show Columns
add_filter ("manage_edit-tf_events_columns", "tf_events_edit_columns");
add_action ("manage_posts_custom_column", "tf_events_custom_columns");
function tf_events_edit_columns($columns) {
$columns = array(
    "cb" => "<input type=\"checkbox\" />",
    "tf_col_ev_cat" => "Category",
    "tf_col_ev_date" => "Dates",
    "tf_col_ev_times" => "Times",
    "tf_col_ev_thumb" => "Thumbnail",
    "title" => "Event",
    "tf_col_ev_desc" => "Description",
    );
return $columns;
}
function tf_events_custom_columns($column)
{
global $post;
$custom = get_post_custom();
switch ($column)
{
case "tf_col_ev_cat":
    // - show taxonomy terms -
    $eventcats = get_the_terms($post->ID, "tf_eventcategory");
    $eventcats_html = array();
    if ($eventcats) {
    foreach ($eventcats as $eventcat)
    array_push($eventcats_html, $eventcat->name);
    echo implode($eventcats_html, ", ");
    } else {
    _e('None', 'themeforce');;
    }
break;
case "tf_col_ev_date":
    // - show dates -
    $startd = $custom["tf_events_startdate"][0];
    $endd = $custom["tf_events_enddate"][0];
    $startdate = date("F j, Y", $startd);
    $enddate = date("F j, Y", $endd);
    echo $startdate . '<br /><em>' . $enddate . '</em>';
break;
case "tf_col_ev_times":
    // - show times -
    $startt = $custom["tf_events_startdate"][0];
    $endt = $custom["tf_events_enddate"][0];
    $time_format = get_option('time_format');
    $starttime = date($time_format, $startt);
    $endtime = date($time_format, $endt);
    echo $starttime . ' - ' .$endtime;
break;
case "tf_col_ev_thumb":
    // - show thumb -
    $post_image_id = get_post_thumbnail_id(get_the_ID());
    if ($post_image_id) {
    $thumbnail = wp_get_attachment_image_src( $post_image_id, 'post-thumbnail', false);
    if ($thumbnail) (string)$thumbnail = $thumbnail[0];
    echo '<img src="';
    echo bloginfo('template_url');
    echo '/timthumb/timthumb.php?src=';
    echo $thumbnail;
    echo '&h=60&w=60&zc=1" alt="" />';
}
break;
case "tf_col_ev_desc";
    the_excerpt();
break;
}
}

In order to save space, I’ve combined my start & end dates into one column, as well as my start and end times. Again, this makes it all a little easier on the user. Here is also the CSS used which I’m only calling within the admin area (it’s a great help as it can really reduce those wide columns on larger monitors):

/* Columns CPT Events */
th#tf_col_ev_date, th#tf_col_ev_cat {width:150px}
td.tf_col_ev_date em {color:gray;}
th#tf_col_ev_times {width:150px}
th#tf_col_ev_thumb {width:100px}

5) show meta box

We then need to provide our users with fields they can fill out, for which a custom meta box is required. It’d be nice if WordPress would automatically do that for a predefined set of field types (text, date, checkbox, dropdown, etc.), however this hasn’t made its way into the system yet. So with the current state of things, you’ll need to beautify the look of it yourself. On a positive note, WordPress 3.1 will use jQuery 1.4.4 and jQuery UI 1.8.6., at least we’ll be somewhat up-to-date there. For the purpose of this tutorial, I’ve left out any fancy formatting or branding, this being the final look:

In the code below, we’ll register the meta-box, link it to the custom post type and then create the form. Again, here is the thought process behind the event-related fields:

  • Split the Database Date Value – As you may recall, I’m using 2 custom fields in the database to output 4 visible data-entry fields. I do this by using the date() function for both, but only outputting the *date* within the first variable, and only the *time* within the second.
  • If Empty, show Today – Zero in Unix Time is 1970. Clearly, it’d be tough to scroll through 40 years worth of months for the end-user (talk about the quickest refund in the history of WordPress). As such, if we have no value in the database (i.e. when we’re creating a new event), we’ll populate it with todays date. If you don’t want the current time to be shown (remember how we split 1 database field into 2 meta fields), then we’ll also need to change the new time field to 0.
  • Strong Date Format – You’ll notice here that I predefined the date format to “D, M d, Y“. When we’re going to use the strtotime() function later on to save our data, it needs to function for all sorts of dates. When experimenting with shorter date formats I noticed that often the day & month would get switched (US vs Euro date styles). By using “D, M d, Y” (i.e. “Fri, Feb 11, 2011” I not only have something that is visually functional but also feeds back into the database without any issues.

When looking at the code, you could argue that we need more controls & validation. I understand that to a degree, but people aren’t THAT stupid. If I’m asking them to input “14:00” for 2pm, 99% will do it on the first try and the remaining 1% would have learned it on their second attempt. Label me pragmatic, but don’t call my clients stupid :)

// 4. Show Meta-Box
add_action( 'admin_init', 'tf_events_create' );
function tf_events_create() {
    add_meta_box('tf_events_meta', 'Events', 'tf_events_meta', 'tf_events');
}
function tf_events_meta () {
// - grab data -
global $post;
$custom = get_post_custom($post->ID);
$meta_sd = $custom["tf_events_startdate"][0];
$meta_ed = $custom["tf_events_enddate"][0];
$meta_st = $meta_sd;
$meta_et = $meta_ed;
// - grab wp time format -
$date_format = get_option('date_format'); // Not required in my code
$time_format = get_option('time_format');
// - populate today if empty, 00:00 for time -
if ($meta_sd == null) { $meta_sd = time(); $meta_ed = $meta_sd; $meta_st = 0; $meta_et = 0;}
// - convert to pretty formats -
$clean_sd = date("D, M d, Y", $meta_sd);
$clean_ed = date("D, M d, Y", $meta_ed);
$clean_st = date($time_format, $meta_st);
$clean_et = date($time_format, $meta_et);
// - security -
echo '<input type="hidden" name="tf-events-nonce" id="tf-events-nonce" value="' .
wp_create_nonce( 'tf-events-nonce' ) . '" />';
// - output -
?>
<div class="tf-meta">
<ul>
    <li><label>Start Date</label><input name="tf_events_startdate" class="tfdate" value="<?php echo $clean_sd; ?>" /></li>
    <li><label>Start Time</label><input name="tf_events_starttime" value="<?php echo $clean_st; ?>" /><em>Use 24h format (7pm = 19:00)</em></li>
    <li><label>End Date</label><input name="tf_events_enddate" class="tfdate" value="<?php echo $clean_ed; ?>" /></li>
    <li><label>End Time</label><input name="tf_events_endtime" value="<?php echo $clean_et; ?>" /><em>Use 24h format (7pm = 19:00)</em></li>
</ul>
</div>
<?php
}

Also, some very basic CSS to structure it a little:

/* Metabox */
.tf-meta {  }
.tf-meta ul li { height: 20px; clear:both; margin: 0 0 15px 0;}
.tf-meta ul li label { width: 100px; display:block; float:left; padding-top:4px; }
.tf-meta ul li input { width:125px; display:block; float:left; }
.tf-meta ul li em { width: 200px; display:block; float:left; color:gray; margin-left:10px; padding-top: 4px}

Furthermore, I tweaked the jQuery a little to show 3 months right off the bat as well as the calendar icon. I think this helps the end-user (and especially my clients). Keep in mind that the following code is in a separate .js file, not in the document directly (as you’d need to switch out the $ with jQuery). The last section of the article will also show you how to implement the datepicker:

jQuery(document).ready(function($)
{
$(".tfdate").datepicker({
    dateFormat: 'D, M d, yy',
    showOn: 'button',
    buttonImage: '/yourpath/icon-datepicker.png',
    buttonImageOnly: true,
    numberOfMonths: 3
    });
});

6) save meta box

Saving the custom data deserves a little section of it’s own, but the code is all quite standard. Check Nonce, ok? Check if Current User is allowed, ok? Save the data. The only special part is where we take the 4 events-related input fields and merge them back to the 2 database fields. As we’ve kept everything nice and simple so far, it’s no issue, we’ll just merge the date & time fields and wrap it in a strtotime() function, like so: $fulldate = strtotime ( $date . $time ). As we’ve been using “safe” date & time formats, there’ll be no issue here. Obviously the actual code requires all the other WordPress parameters to make it work, but nothing out of the ordinary:

// 5. Save Data
add_action ('save_post', 'save_tf_events');
function save_tf_events(){
global $post;
// - still require nonce
if ( !wp_verify_nonce( $_POST['tf-events-nonce'], 'tf-events-nonce' )) {
    return $post->ID;
}
if ( !current_user_can( 'edit_post', $post->ID ))
    return $post->ID;
// - convert back to unix & update post
if(!isset($_POST["tf_events_startdate"])):
return $post;
endif;
$updatestartd = strtotime ( $_POST["tf_events_startdate"] . $_POST["tf_events_starttime"] );
update_post_meta($post->ID, "tf_events_startdate", $updatestartd );
if(!isset($_POST["tf_events_enddate"])):
return $post;
endif;
$updateendd = strtotime ( $_POST["tf_events_enddate"] . $_POST["tf_events_endtime"]);
update_post_meta($post->ID, "tf_events_enddate", $updateendd );
}

7) customize update messages

I think this part is often overlooked in custom post types tutorials but makes the usability aspect so much cleaner. Whenever a user updates something, we’d like it to use events or a similar phrase to update the user instead of “post”. My final code is below, but it’s almost an exact match to what’s in the Codex under the register_post_type page.

// 6. Customize Update Messages
add_filter('post_updated_messages', 'events_updated_messages');
function events_updated_messages( $messages ) {
  global $post, $post_ID;
  $messages['tf_events'] = array(
    0 => '', // Unused. Messages start at index 1.
    1 => sprintf( __('Event updated. <a href="%s">View item</a>'), esc_url( get_permalink($post_ID) ) ),
    2 => __('Custom field updated.'),
    3 => __('Custom field deleted.'),
    4 => __('Event updated.'),
    /* translators: %s: date and time of the revision */
    5 => isset($_GET['revision']) ? sprintf( __('Event restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
    6 => sprintf( __('Event published. <a href="%s">View event</a>'), esc_url( get_permalink($post_ID) ) ),
    7 => __('Event saved.'),
    8 => sprintf( __('Event submitted. <a target="_blank" href="%s">Preview event</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
    9 => sprintf( __('Event scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview event</a>'),
      // translators: Publish box date format, see http://php.net/date
      date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
    10 => sprintf( __('Event draft updated. <a target="_blank" href="%s">Preview event</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
  );
  return $messages;
}

8) Custom jQuery UI for Events only

Last but not least, in order to make the jQuery Datepicker work in the WordPress admin area, we’ll want do some configuring. We’ll de-register the default WP jQuery UI file and then register our custom files downloaded from the official jQuery site (or linked to from the Google jQuery CDN). You’ll notice the pubforce-admin.js below, that will contain our datepicker settings mentioned above in the meta box section of this tutorial.

// 7. JS Datepicker UI
function events_styles() {
    global $post_type;
    if( 'tf_events' != $post_type )
        return;
    wp_enqueue_style('ui-datepicker', get_bloginfo('template_url') . '/css/jquery-ui-1.8.9.custom.css');
}
function events_scripts() {
    global $post_type;
    if( 'tf_events' != $post_type )
        return;
    wp_enqueue_script('jquery-ui', get_bloginfo('template_url') . '/js/jquery-ui-1.8.9.custom.min.js', array('jquery'));
    wp_enqueue_script('ui-datepicker', get_bloginfo('template_url') . '/js/jquery.ui.datepicker.min.js');
    wp_enqueue_script('custom_script', get_bloginfo('template_url').'/js/pubforce-admin.js', array('jquery'));
}
add_action( 'admin_print_styles-post.php', 'events_styles', 1000 );
add_action( 'admin_print_styles-post-new.php', 'events_styles', 1000 );
add_action( 'admin_print_scripts-post.php', 'events_scripts', 1000 );
add_action( 'admin_print_scripts-post-new.php', 'events_scripts', 1000 );
}
?>

9) your turn to speak !

It may look like a lot of code (feel free to download the entire code here), but for the functionality and flexibility provided it’s really automated. If you have any questions, feedback or suggestions, feel free to comment below. Like said, I’m not a developer so I’m more then open to ideas and would also update the code above (& provide credit). Re-tweet if you feel like it too ;) Thank you!

I have already released Part 2: Query, Loop & Design Output , check it out!

Here are also the next tutorials planned in connection with this event post type:

other articles in this series

  1. Front-end: Design & Shortcodes
  2. Front-end: iCal Export
  3. Front-end: Implementing FullCalender

related links

Tutorial – WordPress and bxSlider

There are a bunch of jQuery content & image sliders out there. Although I initially gravitated towards Nivo Slider due to the fancy presentation and website, I found that bxSlider was the jQuery content slider I required (as you can see from my example here, work in progress). bxSlider allows you to put anything between the list item tags, hassle-free. A number of other sliders are limited to images & captions, yet still call themselves content sliders. I also noticed that a number of people were wondering how to integrate this within WordPress. So this post will serve as a guide for those interested in merging the two (and it is the only tutorial on the subject out there at the time of being published)!

Once you’ve downloaded the bxSlider package from the website, upload the files to your theme.

1) Functions.php

Instead of loading the files directly into the header, I’m going to load it within the functions file. The codex describes it as “…a safe way of adding javascripts to a WordPress generated page“. Although the CSS could be in the header, it makes more sense to keep everything packaged together.

// LOAD BX SLIDER
// *********************************************************
function loadbxslider()
{
    wp_enqueue_style('bxstyle', '/wp-content/themes/yourtheme/bx_styles/bx_styles.css');
    wp_enqueue_script('bxscript', '/wp-content/themes/yourtheme/js/jquery.bxSlider.min.js', array('jquery'));
}
add_action('init', 'loadbxslider');

2) Header.php

Notice that I haven’t called jQuery itself yet. Obviously you won’t need to reference to jquery-1.x.x.js directly as WordPress has this feature built-in. So the first thing you want to do is use the enqueue function to not only load the jQuery files, but also the bxSlider simultaneously (recall the array(‘jquery’) code above, that brings bxslider into the mix). You’ll want to place this right above the wp_head function to keep everything in good order.

<!--?php wp_enqueue_script('jquery'); ?-->
<!--?php wp_head(); ?-->

Right below wp_head, you’ll want to add the JavaScript code that will control your final output (specifying the unordered list class that will also be used as the container of rotating content). For a full list of options, please see the documentation on Steven’s website. It’s very important here that you replace the $’s with jQuery as it’s not assumed:

<script type="text/javascript">// <![CDATA[
jQuery(document).ready(function(){
  jQuery('#slidebx').bxSlider({
    mode: 'horizontal',
    infiniteLoop: true,
    speed: 2000,
    pause: 8000,
    auto: true,
    pager: false,
    controls: true
  });
});
// ]]></script>

3) BxSlider inside your Content

Now that you have everything in place, all you need to do is add the content to display your slides. In the case above, I defined #slidebx as my class containing all the slides (or more importantly the list structure). Here is a simple example of what this would look like:

</pre>
<ul id="slidebx">
	<li>Slide 1 Content</li>
	<li>Slide 2 Content</li>
	<li>Slide 3 Content</li>
</ul>
<pre>

At this point, you’re all done! And you should have some slides rotating on your website (here is an example of mine). Let me know if you have any questions, I’ll be glad to help where I can.

Tutorial – Custom Post Types for WordPress

With WordPress 3, came a slew of new features, the best one by far being Custom Post Types. I had fun using this to generate a “Dogs” page for the charity “Stiggy’s Dogs” that I manage. Stiggy’s Dogs rehabilitates dogs to pair them with returning veterans. I realize there is an abundance of tutorials out there, but they are all slightly different. Hopefully this will help someone else or give them some ideas: Here is an image of the final product as it is today:

WordPress Custom Post Type

There is a plan to develop it further with links that direct you to a chronological archive of posts related to the individual dog (almost like a diary), however this custom post type has already been very beneficial so far, as this static page gets quite a bit of traffic. For the charity, it’s a great way of showing their “portfolio”. Depending on the choices made when posting, the following various images will be displayed:

WordPress Custom Port Type Images

Now that you’ve seen where we’re going, let me show you how we get there. Custom Post Types only really consist of two files, the back-end which I’ve contained in the functions.php, and the front-end which we’ll use a loop for. As for functions.php, this is what it looks like (please take note that I’ve had to add additional php openers in order for the code to display below, if you want the final code, please download below).

Backend: Functions.php

In first line, we’ll fire up the custom post type fundamentals, defining the basics of our new tool. There are quite a number of parameters, so definitely reference the WordPress Codex if working with this for the first time:

// ************ DOGS START **************
// 1. Initialize
add_action( 'init', 'noeltockdotcom_dogs_register' );
// 2. Register Custom Post Type
function noeltockdotcom_dogs_register() {
	
		$labels = array(
			'name' => __( 'Dogs' ),
			'singular_name' => __( 'Dog' ),
			'add_new' => __( 'Add New' ),
			'add_new_item' => __( 'Add New Dog' ),
			'edit' => __( 'Edit' ),
			'edit_item' => __( 'Edit Dog' ),
			'new_item' => __( 'New Dog' ),
			'view' => __( 'View Dog' ),
			'view_item' => __( 'View Dog' ),
			'search_items' => __( 'Search Dogs' ),
			'not_found' => __( 'No dogs found' ),
			'not_found_in_trash' => __( 'No dogs found in deleted items' ),
			'parent' => __( 'Parent Dog' ),
		);
		
		$args = array( 
		'labels' => $labels,
		'description' => __( 'Your Dogs' ), 
		'public' => true,
		'supports' => array('title','editor','author','thumbnail','excerpt','comments'),
                'rewrite' => true,
                'capability_type' => 'post',
		);
		
	register_post_type( 'noeltockdotcom_dogs', $args);
}

Next up we’ll need to register our custom fields. This is what will make our custom post type so special. In the first instance we’ll tell WordPress which fields we want:

<!--?php
// **** 3. Register Custom Fields **** 
// Initialize
	add_action( 'admin_init', 'noeltockdotcom_dogs_admin' );
	
	// Add Meta Boxes
	
	function noeltockdotcom_dogs_admin(){
		add_meta_box("noeltockdotcom_dog_meta", "Dog Details", "noeltockdotcom_dog_meta", "noeltockdotcom_dogs", "normal", "low");
	}
	
	// Display Dog
	
	function noeltockdotcom_dog_meta (){
		global $post;
		$custom = get_post_custom($post->ID);
		$name = $custom["dog_name"][0];
		$status = $custom["dog_status"][0];	
		$gender = $custom["dog_gender"][0];
		$owner = $custom["dog_owner"][0];
		$branch = $custom["dog_branch"][0];
		$placed = $custom["dog_placed"][0];
	?>
	
	<label>Name of Dog:</label>
	<input name="dog_name" value="<?php echo $name; ?>" />
	<label>Status:</label>
	<select name="dog_status">
		<option value="deployed" <?php if (($status == '') || ($status == 'deployed')) { ?>selected="selected"<?php } ?>>Deployed</option>
		<option value="intraining" <?php if ($status == 'intraining') { ?>selected="selected"<?php } ?>>In Training</option>
		<option value="prospective" <?php if ($status == 'prospective') { ?>selected="selected"<?php } ?>>Prospective</option>	
	</select>	
	<label>Gender:</label>
	<select name="dog_gender">
		<option value="male" <?php if (($gender == '') || ($gender == 'male')) { ?>selected="selected"<?php } ?>>Male</option>
		<option value="female" <?php if ($gender == 'female') { ?>selected="selected"<?php } ?>>Female</option>
	</select>	
	<label>New Owner:</label>
	<input name="dog_owner" value="<?php echo $dog_owner; ?>" />
	<label>From Military Branch:</label>
	<select name="dog_branch">
		<option value="army" <?php if (($branch == '') || ($branch == 'army')) { ?>selected="selected"<?php } ?>>Army</option>
		<option value="marines" <?php if ($branch == 'marines') { ?>selected="selected"<?php } ?>>Marine Corps</option>
		<option value="navy" <?php if ($branch == 'navy') { ?>selected="selected"<?php } ?>>Navy</option>
		<option value="airforce" <?php if ($branch == 'airforce') { ?>selected="selected"<?php } ?>>Air Force</option>
		<option value="coastguard" <?php if ($branch == 'coastguard') { ?>selected="selected"<?php } ?>>Coast Guard</option>
		<option value="none" <?php if ($branch == 'none') { ?>selected="selected"<?php } ?>>None</option>
	</select>
	<label>Date Placed:</label>
	<input name="dog_placed" value="<?php echo $dog_placed; ?>" />
	<?php
	}
	
	// Save Fields
	
	add_action ('save_post', 'save_dogs');
	
	function save_dogs(){
		global $post;
		update_post_meta($post->ID, "dog_name", $_POST["dog_name"]);
		update_post_meta($post->ID, "dog_status", $_POST["dog_status"]);
		update_post_meta($post->ID, "dog_gender", $_POST["dog_gender"]);
		update_post_meta($post->ID, "dog_owner", $_POST["dog_owner"]);
		update_post_meta($post->ID, "dog_branch", $_POST["dog_branch"]);
		update_post_meta($post->ID, "dog_placed", $_POST["dog_placed"]);
	}

Last but not least; The great thing about Custom Post Types is that they also have their own dashboard for viewing all posts at once (which you can customize to show any or all of your custom fields). To display these various columns showing your custom content, whip up the following code:

<!--?php
// **** 4. Show Columns in Admin ****
// Initialize
add_action ("manage_posts_custom_column", "dogs_custom_columns");
add_filter ("manage_edit-noeltockdotcom_dogs_columns", "dogs_edit_columns");
// Display Columns
function dogs_edit_columns($columns){
	$columns = array (
		"cb" => "<input type=\"checkbox\" />",
		"title" => "Dog Name",
		"status" => "Status",
		"gender" => "Gender",
		"owner" => "Owner",
		"branch" => "Military Branch",
		"placed" => "Date Placed",
		"description" => "Description",
	);
	
	return $columns;
}
	
// Define Column Content
	
function dogs_custom_columns($column){
	global $post;
	switch ($column){
		case "status":
			$custom = get_post_custom();
			echo $custom["dog_status"][0];
			break;					
		case "gender":
			$custom = get_post_custom();
			echo $custom["dog_gender"][0];
			break;
		case "owner":
			$custom = get_post_custom();
			echo $custom["dog_owner"][0];
			break;	
		case "branch":
			$custom = get_post_custom();
			echo $custom["dog_branch"][0];
			break;	
		case "placed":
			$custom = get_post_custom();
			echo $custom["dog_placed"][0];
			break;	
		case "description":
			the_excerpt();
			break;		
	}
}

At this point, you’ll have successfully created everything needed in the back-end to make this functional. Good job!

Frontend: The Loop

This is actually the easy part, and I’ve tried to throw in some inline CSS (although not best practice) to show you how it all works.

<?php
//The Query
query_posts('post_type=noeltockdotcom_dogs&meta_key=dog_status&orderby=meta_value&order=ASC');
//The Loop
if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php
	$custom = get_post_custom($post->ID);
	$name = $custom["dog_name"][0];
	$status = $custom["dog_status"][0];
	$gender = $custom["dog_gender"][0];
	$owner = $custom["dog_owner"][0];
	$branch = $custom["dog_branch"][0];
	$placed = $custom["dog_placed"][0];
	$post_image_id = get_post_thumbnail_id($post_to_use->ID);
		if ($post_image_id) {
			$thumbnail = wp_get_attachment_image_src( $post_image_id, 'post-thumbnail', false);
			if ($thumbnail) (string)$thumbnail = $thumbnail[0];
		}
?>
<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<div class="dogblock">
			<div style="float:left;background: url('<?php echo $thumbnail; ?>') no-repeat; width:300px; height:250px;">
				<?php if ($status == "deployed") {
					echo "<img src='http://www.stiggysdogs.org/images/deployed.png' />";
					} elseif ($status == "intraining") {
					echo "<img src='http://www.stiggysdogs.org/images/intraining.png' />";
					} else {
					echo "";
				} ?>
			</div>
			<div class="customdogcontent">
				<h3><?=$name?></h3>
				<?php if ($status == "deployed") {
					echo "<div style=\"background: url('http://www.stiggysdogs.org/images/$branch.png') no-repeat; min-height:60px;;width:320px;padding:20px 0 0 70px;font-size:20px;\">$owner</div>"; } ?>
				<p><?php the_content(); ?></p>
			</div>
</div>
</div>
<div style="padding:20px 0 0 0;width:660px;border-bottom:1px dotted #b49579;clear:both;"></div>
<?php endwhile; ?>
<!-- Stop the post loop and process any code included here only once. This text is generated only if there are posts. Any code included in this part of the document is processed only once. -->
<?php else : ?>
<p>No Dogs :( </p>
<!-- If you are seeing this message, there are no posts to process/display. Any code included in this part of the document is processed only once. -->
<?php endif; ?>

Summary

Custom Post Types for WordPress are incredibly useful as they allow you to create and display content exactly how you want it, making your life as a web designer that much easier. More importantly, they are an excellent way to manage your client’s needs within WordPress (as opposed to custom PHP/MySQL development which may not always be future-proof when considering future versions of WordPress). If you have any questions, please let me know, I’d be glad to help!

Download

Download the two PHP files here (functions.php & loop.php)

Related Links

Client – Spectral Capital Corporation

I’ve recently had the joy of working with a client that has gone through a re-branding, which is quite an administrative matter when they’re listed on multiple stock exchanges. Spectral Capital (previously Fusa Capital) used to have a few media search sites up back in the day but has since gone in a different direction. The features of the website are straightforward:

  • Content Management System – WordPress
  • Multilingual – English / German
  • Stock Ticker with relevant Securities / Quotes
spectral corporate wordpress

As is the case with the majority of my sites these days, I built the web presence using WordPress. There isn’t too much content today, but that will grow in the coming months. However, with that in mind, I built everything in a scalable manner, not trying to restrict in anyway. I was able to leverage a few plug-ins which were very helpful; WordPress Multilingual (WPML) for having being able to use multiple languages with WordPress as well as Stock Quote Sidebar, where I modified the design and way it acts depending on the movement of the stock, see the screenshot below:

stock ticker wordpress

Apart from that, the site is well on it’s way, just waiting for content to start flowing in. The website is also hosted using Page.ly, which I’m obviously happy about as everything is secure and backed up regularly. This way the client can get a good “bang for buck” server that is very well managed.