Author Archive

How To Become A Top WordPress Developer // advancement to excellence


  

First, let’s set a few things straight: becoming a top WordPress developer is hard work — very hard work. It’s going to take a lot of time, energy and determination. If you’re looking for an easy checklist or some “fast pass” to the top, you’re going to waste your time. Being one of the best is hard, and statistically speaking, the odds are stacked against you.

By the way, installing WordPress, reading a few tutorials and customizing a few themes does not make someone a top developer. They may call themselves an “Expert”, and that’s fine. They may know more than the average person. But a top developer moves far beyond the basics, and pushes the very boundaries of what is possible. They innovate, contribute to the community, and demonstrate mastery in the work they do. So I want you to be more than an “expert”, I want you to be one of the best.

Why Be A Top Developer

Why not? If you work with WordPress (or plan to start), why just settle for being average? There’s too much “average” in life already. “Normal” is highly overrated. There are other reasons, though. For instance, the top WordPress developers:

  • Make the most money
    Demand for WordPress development is high and clients are willing to pay more for developers who are the best in their field.
  • Get the best clients
    When you are at the top, you have the freedom to say “No” to the projects you don’t want, and “Yes” to the projects you do.
  • Have the most influence
    Being at the top means you have influence (and responsibility) and the capability to shape the future of WordPress as well as the ecosystem that is built around it.

One Hour of Reading a Day

If you’re going to make it to the top, then you need to spend at least one hour each workday focused on reading and learning more about WordPress — outside of any development work. There are no shortcuts, and no other ways around it. Learning and mastering WordPress is going to take time. If you watch TV, cut it out — more than 90% of it isn’t good for you anyway. If you’re a gamer, sell your games or throw them away. Reaching the top takes commitment and sacrifice and the best place to start is with the things in life that aren’t doing you any good anyway.

Start with one dedicated, distraction-free hour of reading for each workday. Shut off instant messages, put your phone on silent, and read. Take notes on what you learn along the way. You’ll find the time goes by faster than you would have expected. Keep at it, day after day, week after week, and month after month. And as you start to see success, put in more time for reading.

Alternatively, consider a three-hour block, two to three times a week. The key is to make a commitment to learning and honoring that commitment by setting aside the necessary time to see it through.

Enrolling in WordPress University

There’s never been a better time to learn and master WordPress than right now. There are so many excellent resources available to those willing to put the time and effort into using them. Before you can start gaining experience, you need some education. Sure, you could just jump in and start breaking things. But I suggest you wait, and cultivate the self-discipline it takes to learn — there will be plenty of time to break things later. As you start your education, it’s important to begin with the social aspect of your experience.

Hang Out with the Right Crowd

We become like those we associate with. If you want to be one of the top WordPress developers, start spending time with those at the top. Read their blogs, follow them on Twitter, give feedback on their thoughts and ideas, go to WordCamps to meet them and listen to their talks. Read the interviews on CodePoet. Follow their examples, ask them for advice, follow their advice, and report back.

Here is a small list of WordPress developers to get you started:

Read the Material

The amount of reading material available on WordPress is overwhelming. There are thousands of people talking about WordPress and it is becoming increasingly difficult to filter through the noise. There are authorities, however, and when you commit to mastering WordPress, then you should start your journey by finding the highest quality resources and concentrating your efforts just on those.

Here are a few resources to get you started:

  • WordPress Codex
    The WordPress codex is a community-edited repository for all things WordPress. Start with the very basics and focus on mastering the WordPress interface itself from an end-user’s perspective. Learn the WordPress semantics. Read about theme design and plugin development.
  • Books on WordPress
    There are more than a dozen books available on WordPress. Start off with the titles of greatest interest to you and then work towards the others. Think “WordPress For Dummies” is too basic? Maybe not. Your clients may read it and it’s important to have their perspectives. When you’re finished, thank the author and write a review.
  • Blogs on WordPress
    Find and follow the best blogs about WordPress. Subscribe to their feeds. Read them regularly and give feedback to the authors. A few of my favorite blogs are WordPress on Smashing Magazine, WP Tuts+, and WP Candy.

Understand the Technology

If you’re going to master WordPress as a developer you need to understand the technology. If you’re already a programmer and PHP/MySQL aren’t new to you, great. Make sure your skills are up-to-date. If you’re new to programming, start learning.

Here are some ways to begin:

  • Learn PHP and MySQL
    It’s really important that you know PHP and MySQL and that you learn the best practices. A few out-dated tutorials aren’t going to do it. And if you learned it a few years ago, a lot of the practices you picked up are probably out-of-date. Not sure where to begin? Start with Lynda.com or Learnable.com. Learn about MySQL performance.
  • Explore the Codebase
    Take time to explore the WordPress codebase on Trac and on Xref. Read through the documentation to understand how things work. Look up what doesn’t make sense to you and ask questions. Familiarize yourself with how WordPress is structured.
  • Run The Nightly
    Setup a local development environment and run the nightly build as a way to stay up-to-date on WordPress as it’s being developed.
  • Read “Make WordPress”
    A good way to understand the technology is to follow the development discussions taking place on make.wordpress.org. You can follow discussions about the Core, Plugins, and Themes for starters.

Do the Homework

Put what you’re learning into practice. Start with your own WordPress websites. After you read a tutorial, follow it on your own. Experiment. Break things down. Track what you’ve learned and record your insights and breakthroughs for future reference. Spend as much time as you can taking what you’ve learned and applying it to your own projects and experiments.

Here are a few areas to explore:

  • WordPress APIs
    Start by familiarizing yourself with the list of available APIs on the Codex. Read through the information available for each API and experiment with each (some will be easier than others). Search for tutorials for each of the APIs to give you some real-world perspective and experience on what can be done with each.
  • Ajax in WordPress
    Even if you’re already familiar with Ajax, learn about the use of Ajax in WordPress. Then, move on to tackle using Ajax in plugin development. Search for tutorials to develop your experience further.
  • WordPress PHP Classes
    Familiarize yourself with the list of classes created by WordPress developers. Experiment with them on your own projects and master them. In particular, pay special attention to WP_Query, WP_Theme, and wpdb. Search for tutorials on each of the classes, as well as non-core, community contributed classes like WPAlchemy.

Gaining Experience With WordPress

With your education well underway, it’s time to gain real-world experience — and lots of it. Your path to the top is lined with trials and difficulties and gaining experience outside the safe playgrounds of your own projects is a critical step in the right direction. One of the best ways to get started is doing work for others.

Take On Clients

Working for clients, paid or free, is one of the best ways to gain experience. Clients introduce challenges you would never have to deal with working on your own. If you’re just getting started, learn how to get your first client. While the market focus (large clients vs. small clients) will vary, the heart of the matter is get a lot of experience. The goal is to not just get a few hundred hours working on WordPress, but a few thousand. You need to put the time in with real-world experience and taking on clients is one of the best ways to do this.

Develop a Public Theme

Build a theme you’d actually use. Release it, paid or free. Listen to the feedback you get from developers and end-users who use your theme. Ask for a peer review from theme designers you respect. Update your theme as you get feedback and as your abilities improve. Work hard to make a theme that you can be proud of.

Develop a Plugin

As you learn and work with WordPress you’ll eventually find a need that hasn’t been met. When you do, meet it yourself. Take what you’ve learned about plugin development and put it into practice. Write a plugin that’s secure and that solves a real need, without being another “me too” contribution to the already massive plugin community. Release it, paid or free, and get feedback from the people who put your plugin to use.

Contribute a Patch

Read the Core Contributor handbook and learn how to submit a patch. It can be a daunting process your first time around, but look for a challenge that you can tackle, and stick to it. Contributing a patch is an invaluable experience and an important part of being able to consider yourself a top WordPress developer.

Master Debugging

Learning how to write bug-free code is a critical step in becoming a great developer. Start with the Codex and learn about debugging in WordPress. Read Andrew Nacin’s post on 5 Ways To Debug WordPress. Familiarize yourself with some of the developer oriented plugins, like Core Control, Debug Bar and Log Deprecated Notices.

Joining The WordPress Community

As you continue your education and put what you’ve learned into practice, the next step is to become an active member of the community. You may be a fantastic developer, but it doesn’t count for much if no one knows you exist. Spend time investing in the community. One of the best ways to do so is sharing what you know.

Write Tutorials

I got my start back in 2006 with a simple tutorial I wrote (be warned, it is a little dated). I took what I had just figured out and poured it into a tutorial to help others and save them the time (and headache) I had just experienced. A lot of people read it, a few wrote back and said thank you, and some people even asked me to do some work for them. So write tutorials that take the best of what you’ve just learned and present it to others so they may reap the benefits of your efforts. It’s worth it.

Contribute to the Codex

As you spend time reading through the Codex you will notice areas that need improvement. Learn about becoming a volunteer in the Codex. Dedicate time to improving the quality of the documentation. While documentation in the Codex is continually improving, there are still functions and features in the WordPress core that go undocumented. If an area is beyond your current capabilities, bring it to the attention of others and embrace the opportunity to learn more in the process.

Participate in Forums

Most WordPress beginners start out asking questions on the official support forums. Start there by answering questions (even the silly, basic ones — we all start somewhere). From there, become an active member of the WordPress Stack Exchange community. Answer questions and learn from the answers that other developers are giving.

Present at WordCamps

Attend upcoming WordCamps and look for opportunities to present and give value to the WordPress community. A true sign of your expertise is your ability to take what you know and teach it to someone else. Read the Diary Of A WordCamp. Want even more of a challenge? Become an organizer and start a WordCamp near you.

Reward And Responsibility

The reward at the top is worth the effort. If you’re building a business around WordPress (read 7 reasons why you should), a mastery of WordPress is a critical step to your success. In 2011, according to the official WordPress Survey results, “6,800 self-employed respondents were responsible for over 170,000 websites, personally”. Of those, the average median hourly rate was $50/hour. Based on the Pareto principle, the top 20% of those developers (less than 1,400) are responsible for 80% of the work done (and they make more than $50/hour).

Now, being in that top 20% carries with it a high-level of responsibility. Staying at the top requires a commitment to ongoing education and continual experience. Never stop learning and improving. Being at the top also puts a level of responsibility on your shoulders for the health and future of the WordPress ecosystem. Get involved. Weigh in on important matters. Contribute. Put a percentage of your success back into building up WordPress and ensuring its future.

Conclusion

Becoming a top WordPress developer requires a mindset of continual improvement and a willingness to do the hard work. It starts with an intentional focus on education and then moves to extensive real-world experience. Finally, the title of a “top developer” demands dedication to the WordPress community, as well as recognition of the responsibilities by those who mold and shape the future of WordPress.

What about you? What advice do you have for becoming a top WordPress developer?


© Jonathan Wold for Smashing Magazine, 2012.


Stop Writing Project Proposals


  

After several grueling days I had finally finished the proposal. I sent it off and waited for a response. Nothing. After a few weeks, I discovered that they were “just looking�. Despite the urgency and aggressive timeline for the RFP (Request For Proposal) plus the fact that we had done business with this organization before, the project was a no-go. My days of effort were wasted. Not entirely, though, because the pain of that loss was enough to drive me to decide that it wouldn’t happen again.

I work at a Web development company and we’ve experimented with proposal writing a lot over the years. We’ve seen the good and the bad, and we have found something better. In this article I will share the pains that we have experienced in the proposal writing process, the solution we adopted, and our process for carrying out that solution. I’ll also give you guidelines to help you know when this solution is and isn’t appropriate.

Proposal Writing Causes Pain

After several years of writing proposals, we began to notice that something wasn’t right. As we considered the problem we noticed varying levels of pain associated with the proposal writing process. We categorized those pains as follows:

  • The Rush
    Getting a proposal done was usually about speed. We were racing against the clock and working hard to deliver the proposal as efficiently and as effectively as possible. However, sometimes corners would get cut. We’d reuse bits and pieces from older proposals, checking and double-checking for any references to the previous project. While the adrenaline helped, the rush gets old because you know that, deep down, it’s not your best work. Besides, you don’t even know if you’re going to close the deal, which leads to the next pain.

  • The Risk
    Our proposal close ratio with clients that came directly to us was high. We’d work hard on the proposals and more often than not, we’d close the deal. The risk was still there, however, and I can think of several proposals that we had spent a lot of time and effort on for a deal that we didn’t get. Not getting the deal isn’t the problem — the problem is going in and investing time and energy in a thorough proposal without knowing if there is even the likelihood that you’re going to close the deal.
  • The Details
    The difference between a project’s success and its failure is in the details. In proposal writing, the details are in the scope. What work is included, what is not, and how tight is the scope? Now, this is where the “rush� and the “risk� play their part. The rush typically causes us to spend less time on details and the “risk� says: “Why spell it all out and do the diligence when you might not even get the project?� A self-fulfilling prophecy, perhaps, but a legitimate concern nonetheless. Selling a project without making the details clear is asking for scope creep, and turns what started out as a great project into a learning experience that can last for years.

Now, writing is an important part of the project and I’m not about to say you shouldn’t write. Having a written document ensures that all parties involved are on the same page and completely clear on exactly what will be delivered and how it will be delivered. What I’m saying, though, is that you should stop writing proposals.

Write Evaluations, Not Proposals

Write Evaluations, Not Proposals — And Charge For Them

A few years back, we decided to try something new. A potential client approached us and rather than preparing another project proposal, we offered the client what we now call a “Project Evaluation.” We charged them a fixed price for which we promised to evaluate the project, in all of our areas of expertise, and give them our recommendations.

They agreed, paid the price, and we set out to deliver. We put a lot of effort into that evaluation. We were in new territory and we wanted to make sure that we delivered it well. So we finished the report and sent it to them. The client liked it, agreed with our recommendations, and started a contract with us to do the work.

That project became a game changer for us, starting an on-going relationship that opened doors into a new market. It was the process of the evaluation itself that brought the new market potential to our attention, and gave us the opportunity to develop this business model. It was a definite win, and one that a project proposal couldn’t have delivered.

What Is A Project Evaluation?

A “Project Evaluation�, as we’ve defined it, is a detailed plan for the work that is to be done on a project, and explains how we do it. We eliminate the guess work, and detail the project out at such a level that the document becomes a living part of the development process, being referred back to and acting as the guide towards the project’s successful completion.

The Benefits Of (Paid) Project Evaluations

As we put our proposal writing past behind us and embraced the evaluation process, we noticed a strong number of benefits. The most prominent of those benefits are the following.

  • Qualification

    If a client is unwilling or unable to pay for a project evaluation, it can be an indicator that the project isn’t a match. Now, we may not always charge for evaluations (more on that later). We also recognize a deep responsibility on our part to make sure that we have intelligently and carefully explained the process and value of the evaluation. After all that is done, though, you may run into potential clients who just don’t want to pay what you’re charging, and it’s better to find this out right away then after writing a long proposal.

  • Attention to Details

    Having the time available to do the research and carefully prepare the recommendations means that we are able to eliminate surprises. While the end result may be a rather large document, the details are well organized and thorough. Those details are valuable to both the client (in making sure they know exactly what they’re getting) and to the development team (in making sure that they know exactly what they’re delivering).

  • No Pricing Surprises

    Figuring out all the details and ironing out a complete scope means that we’re able to give a fixed price, without surprises. This gives the client the assurance up front that the price we gave them is the price they’ll pay. In more than a few cases, the time we’ve spent working out the details has eliminated areas of concern and kept our margins focused on profit, not on covering us “just in case.”

  • Testing the Waters

    When a potential client says “Yes” to an evaluation, they are making a relatively small commitment — a first step, if you will. Rather than a proposal that prompts them for the down payment to get started on the complete project, the evaluation process gives us time and opportunity to establish a working relationship. In most cases, the process involves a lot of communication which helps the client learn more about how we work, as we learn more about how they work. All this is able to take place without the pressure of a high-budget development project. And by the end of the evaluation, a relationship is formed that plays a major factor in the decision process to move forward.

  • Freedom to Dream

    Occasionally, we spend more time on an evaluation than we had initially expected. But knowing how our time is valued has given us the freedom to explore options and make recommendations that we might not have made otherwise. In our experience, the extra time and energy that the context of a paid evaluation provides for a project has consistently brought added value to the project, and contributed to its ultimate success.

Write Evaluations, Not Proposals

The Evaluation Writing Process

Over the years we have refined (and continue to refine) a process that works well for us. As you consider the process, look for the principles behind each step, and if you decide to bring this into your business, look for ways to adapt this process and make it your own.

#1 — Do the Research

The heart of the evaluation process is the research. If it’s a website redesign project, we read through each and every page on the website. We take notes and thoroughly absorb as much content as possible. Our objective is to get to the heart of the project and gain as much of the organization’s perspective as possible.

If it’s a custom programming project, we try to get inside the project’s concept, challenge it, look for flaws in the logic, research relevant technologies, and work to make recommendations that keep the goals of the project in mind.

We spend time with the client by phone, over Skype, via email, and sometimes even in person. As our research uncovers problems or finds solutions, we run them by the client and gather their feedback.

The research process allows us to go deep, and in our experience it has always paid off, giving us a thorough grasp of the project and providing a foundation to make intelligent, expertise-driven recommendations.

#2 — Offer Recommendations

Each project evaluation is different. Depending on the nature of the project we may make recommendations regarding technology, content organization, marketing strategies, or even business processes. The types of recommendations we make have varied greatly from project to project, and are always driven by the context and goals of the project.

When it comes to areas of uncertainty for the client, we work hard to achieve a balance between an absolute recommendation and other options. If the answer is clear to us, we’ll say so and make a single, authoritative recommendation. However, when an answer is less clear, we give the client options to consider (along with our thoughts) on why or why not an option might be a match.

We share our recommendations with the client throughout the evaluation process, and when the final report is given, there are rarely any surprises.

#3 — Prepare the Scope

After we’ve worked through our recommendations, we put together a technical scope. This is typically the longest part of the document. In the case of a Web design project, we go through each page of the website, explaining details for the corresponding elements of that page. The level of detail will vary based on the importance of a particular page.

The scope document is detailed in such a way that the client could take it in-house, or even to another developer, and be able to implement our recommendations.

As the project commences, the scope document will often be referred to, and can function as a checklist for how the project is progressing.

#4 — Prepare the Timeline & Estimate

With the scope complete, calculating the cost and preparing an estimate becomes a relatively straightforward process. While how one calculates the price may vary, all the information is now available to see the project through from start to finish, identifying the challenges, and determining the amount of resources required to meet the project’s objectives.

Note: Prior to the start of the evaluation process, we nearly always give the potential client a “ball park� estimate. So far, that estimate typically ends up being about ten times the cost of the evaluation.

We take the estimating process very seriously, both in the ball park stage and especially here within the context of an evaluation. Once we set a price down we don’t leave room for “oops!� and “gotchas!�, and that means we are extra careful to calculate as accurately as possible, both for our sake and for the sake of the client.

Now, because of the nature of the evaluation, we are often able to research and explore options above and beyond what the client originally brought to our attention. In the case of a Web application, this might be an added feature or a further enhancement added onto a requested feature. Within the scope of the evaluation we carefully research these extras, and when appropriate, present them as optional “add-ons� within the timeline and estimate.

They are truly optional, and while always recommended by us, we leave the decision up to the client (there’s no use wasting research energy on an add-on you wouldn’t fully recommend). In cases where the budget allows for them, they are nearly always accepted. In cases where a tighter budget is involved, the add-ons are typically set aside for future consideration.

When Evaluations Are Appropriate

A project evaluation functions like the blueprints for a new office building. Imagine that I own a successful construction company, and I have a number of world-class office construction projects to my credit. A new client comes to me after seeing some of my work and tells me “I want a building just like that!”. Assuming, of course, that I own the rights to the building, I can say “Sure!” and tell them how much it will cost. Why? The blueprints have already been drawn.

Now, there will be variable factors, such as where they choose to have the building built, and any customizations they may request matter. But in most cases no new blueprints will be needed, and I can proceed with construction without charging them for the plans.

Suppose another client comes to me after seeing one of my buildings and asks me to build an entirely new design for them. A new design calls for new blueprints all of their own, and these must be developed before the project begins. Can you imagine a large-scale construction project without any blueprints?

Web development is the same way. In our experience, evaluations are appropriate when a client comes to us and asks us to take on a project outside of our existing set of “blueprints”. Examples where we’ve found a project evaluation necessary include:

  • A redesign of an existing website.
  • Developing a new Web application.
  • Bringing new technology into an existing project.

Without an evaluation you’re either left to go ahead and do the research on your own (with the weight of the rush, and the risk on your shoulders) or you’re stuck making as educated a guess as possible for the scope of the project. This dangerous guessing in a situation where an evaluation is appropriate can leave you with an estimate that is too high (which can mean losing the project) or even worse, an estimate that is too low.

When Evaluations Are Not Appropriate

When a project is familiar, and doesn’t require an evaluation (or fits within the scope of an existing type of evaluation), we give an informal, direct estimate along with a scope of the work. Small to mid-sized Web design projects typically fall into this category. While the content and design are new, the process isn’t. The key here is the experience and confidence in your abilities (and the abilities of your team) that the work will get done within budget to the expected delight of all parties involved.

Conclusion

Project evaluations up until now haven’t been given much attention. I would suggest it is a simple concept that has been overlooked and passed by amidst the rush of a booming Web development industry. I invite you to implement the process, experience the benefits, and stop the pain of proposal writing.

I thank you, dear reader, for your time in considering this concept. And I thank you in advance for your feedback.

(jvb) (il)


© Jonathan Wold for Smashing Magazine, 2012.


How To Build A Media Site On WordPress (Part 2)

Advertisement in How To Build A Media Site On WordPress (Part 2)
 in How To Build A Media Site On WordPress (Part 2)  in How To Build A Media Site On WordPress (Part 2)  in How To Build A Media Site On WordPress (Part 2)

The default “category” and “tag” taxonomies in WordPress offer a lot of flexibility to those with imagination and in my development experience I have seen a wide range of creative implementations. With the introduction of custom taxonomies and their growing ease of use, though, we need no longer be bound to categories and tags. With the ability to create both hierarchical and non-hierarchical taxonomies and with the introduction of several new features in WordPress 3.1, now is the time, if you’re not already, to begin putting custom taxonomies to use.

In part one of this two part series, we learned how to setup custom post types and custom taxonomies. We also learned how to build a template to check for and display media attached to custom posts. Now, we’ll learn how to use custom taxonomy templates to organize and relate our media. Let’s get started!

Wordpress-media-site21 in How To Build A Media Site On WordPress (Part 2)

Organizing Our Media – Working With Custom Taxonomy Templates

Now that we have our media displaying, it’s time to work on how it’s organized. If you tried clicking on one of the custom taxonomy terms, odds are the result weren’t very exciting. You probably saw something like this:

 in How To Build A Media Site On WordPress (Part 2)
A rather unhelpful default view of a term in the “presenter” taxonomy.

What we’re going to do next is create a template that allows us to customize the results and offer a page that will be more useful.

Creating A Custom Taxonomy Template

As with custom posts, the WordPress template engine has a custom taxonomy template hierarchy that it follows to determine what template it uses to display data associated with a custom taxonomy term. We’ll start with our “presenters” taxonomy. In our case, the WordPress hierarchy is as follows:

  • taxonomy-presenters.php – WordPress will check the theme folder for a file named taxonomy-presenters.php. If it exists, it will use that template to display the content. For different custom taxonomies, simple replace “presenters” with the name of your custom taxonomy.
  • taxonomy.php - If no custom taxonomy template is found, WordPress checks for a general taxonomy template.
  • archive.php – If no general taxonomy template is used, the WordPress archive template is used.
  • index.php – If no archive template is found, WordPress defaults to the old standby – the index.

Note: The WordPress template hierarchy structure also allows templates for specific terms. For instance, in a case where “Jonathan Wold” was a term in the “presenters” taxonomy, I could create a custom template called “taxonomy-presenters-jonathan-wold.php”.

Non-Hierarchical Custom Taxonomy Templates

We’ll start with the non-hierarchical “presenters” custom taxonomy. As with the custom post type examples previously, I will be using minimal examples for each of the templates.

To get started with this example, create a file called taxonomy-presenters.php and upload it to your theme folder. Add the following code:

<?php get_header(); ?>

<?php // Get the data we need
	$presenter = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );
?>

	<div id="container">
		<div id="content" class="presenter">
			<h1 class="entry-title"><?php echo $presenter->name; ?></h1>
			<p><?php echo $presenter->description; ?></p>
		</div>
	</div>

<?php get_footer(); ?>

Previewing a term should now show you a rather empty page with the name of the term and the description (if you entered one when creating or editing the term). In my case, on Twenty Ten, accessing the term “Jonathan Wold” (/presenter/jonathan-wold) looks like this:

Jon-wold-wp-screenshot in How To Build A Media Site On WordPress (Part 2)
A rather basic, yet more useful, view of a custom taxonomy term template.

Before moving on, let’s review the code above to learn what it’s doing and what you can do with it.

$presenter = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );

This piece of code may seem intimidating at first, but it’s rather simple. First, we are defining a variable called $presenter. Our goal is to have that variable store everything that WordPress knows about our term.

To do that, we are using the function get_term_by. That function requires three things:

  1. Field – You can access a term by name, ID, or slug. In our case, we are using the slug, which is “jonathan-wold”.
  2. Value – We’ve told WordPress that we want to get our term data by using the “slug” field. Now, it needs a slug to retrieve data. Since we want this to be dynamic, we are using another function called get_query_var. When you access a term in WordPress (e.g. viewing a term by its permalink), a query is run in order to generate the results for that term. Using “get_query_var” allows you to intercept that query and get the data for your own use.
  3. Taxonomy – In addition to the term slug, WordPress also needs the taxonomy name (this is critical in cases where the same name is used across multiple taxonomies). We use “get_query_var” again to retrieve that for us.

If we wanted to access the term data for one specific term in a particular custom taxonomy, we would do it like this:

$presenter = get_term_by( 'slug', 'jonathan-wold', 'presenters');

In our example, we are adding code into our template telling WordPress to give us the data for the term a visitor is currently viewing. WordPress stores that data as an “object”.

To see what data is available to you in an object, add the following within your code:

<?php
	echo '<pre>';
	print_r( $presenter );
	echo '</pre>';
?>

Preview the term again and you should see a block of code that looks something like this:

Tutorial-part2-code-view-550 in How To Build A Media Site On WordPress (Part 2)
An easily readable view of the object attributes and values.

That block of code lets you see what WordPress knows about your particular object and what information you have available to use within your template.

Note: In part one, I referenced a technique for adding custom fields to your custom taxonomies and giving you access to more data within your templates. Just incase you missed the reference, take a look at the advanced tutorial, How To Add Custom Fields To Custom Taxonomies, on the Sabramedia blog.

Displaying Object Data In Templates

Now, let’s look at how we took the data from that object and actually displayed it in the template. Let’s start with the first example:

<?php echo $presenter->name; ?>

In English, we are telling PHP to “echo”, or display, the “name” value of the $presenter object. We would know that the object created with “get_term_by” contains the value for “name” by either looking up the return values for get_term_by in the Codex or by using “print_r” to see for ourselves. We’ll explore this in more detail once we look at the “topics” taxonomy.

To get our description, we do the same thing, changing the “name” value to “description”:

<?php echo $presenter->description; ?>

Displaying Term Results In Custom Taxonomy Templates

Now that we have our term name and description displaying, it’s time to show some actual custom post results.

We are continuing our example with taxonomy-presenters.php. Replace the existing code with the following:

<?php get_header(); ?>

<?php // Get the data we need
	$presenter = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );

	$resources = new WP_Query(
		array(
			'post_type' => 'resource', // Tell WordPress which post type we want
			'posts_per_page' => '3', // Show the first 3
			'tax_query' => array( // Return only resources where presenter is listed
				array(
					'taxonomy' => 'presenters',
					'field' => 'slug',
					'terms' => $presenter->slug,
					)
				)
			)
		);
?>

	<div id="container">
		<div id="content" class="presenter">
			<h1 class="entry-title"><?php echo $presenter->name; ?></h1>
			<p><?php echo $presenter->description; ?></p>

			<div class="resources">
				<h3>Latest Resources</h3>
				<ul id="resource-list">
					<?php while ( $resources->have_posts() ) : $resources->the_post(); ?>
						<li id="resource-<?php the_ID(); ?>" class="resource">
							<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
							<span><?php the_excerpt(); ?></span>
						</li>
					<?php endwhile; ?>
				</ul>
			</div>	

		</div>
	</div>

<?php get_footer(); ?>

Previewing one of your terms should now display the name and description of the term along with a list of custom posts associated with that term. In our case, the results look like this:

Jon-wold-ap-screenshot2 in How To Build A Media Site On WordPress (Part 2)
With a customizable list of related custom posts, the term results template is looking much more useful.

The update to this code block is the addition of our “$resources” query. Let’s take a look at that more closely:

$resources = new WP_Query(
	array(
		'post_type' => 'resource', // Tell WordPress which post type we want
		'posts_per_page' => '3', // Show the first 3
		'tax_query' => array( // Return resources associated with presenter
			array(
				'taxonomy' => 'presenters',
				'field' => 'slug',
				'terms' => $presenter->slug,
				)
			)
		)
	);

For our variable of $resources, we are creating a new instance of the WordPress class, WP_Query. Then, we’re setting values on several parameters, post_type, post_per_page, and tax_query.

The first two are straight forward. With “post_type”, you let WordPress know which types of content you’re wanting to return. We used that in our media example to retrieve attachments. To display multiple posts types, replace the “post_type” line with this:

'post_type' => array( 'resource', 'other_post_type', 'another_post_type' ),

For “posts_per_page”, you are letting WordPress know how many posts to return before triggering pagination. If you want to return all posts, use “-1″ for the value, like this:

'posts_per_page' => '-1', // Show all the posts

Now, “tax_query” is a new parameter added in WordPress 3.1. It is a powerful parameter that lets you return results associated with multiple taxonomies and custom fields.

Let’s take a closer look at it:

'tax_query' => array( // Return resources associated with presenter
	array(
		'taxonomy' => 'presenters',
		'field' => 'slug',
		'terms' => $presenter->slug,
		)
	)

First, we choose our custom taxonomy. In our case, we are hardcoding in “presenters”. If we wanted to make it more dynamic and build, for instance, a general taxonomy template (taxonomy.php) to handle multiple taxonomies in a similar way, we would use “get_query_var” again, like so:

'taxonomy' => get_query_var( 'taxonomy' ),

Note: The “tax_query” function works with one taxonomy at a time. To query multiple taxonomies, simply duplicate the code above (be sure to add the appropriate comma at the end) and change the parameters accordingly.

Next, we have the “field” parameter. This lets WordPress know what field we will be returning our terms by. WordPress accepts “slug” or “id”. I am using “slug” because I prefer recognizing posts by words over numbers.

Then, we have “terms”. In our case, we are using the $presenter variable to pass in the “slug” in the same way we added data directly into our custom post template. If we wanted to make it more dynamic, we could use “get_query_var” again:

'term' => get_query_var( 'term' ),

If we want to return results for multiple terms, we add an array, like this:

'term' => array( 'term_1', 'term_2', 'random_other_term' ),

To modify our results further, we can use an optional “operator” parameter that allows us to specify whether our results are “IN”, “NOT IN”, or “OR”. A simple example, appropriate for use in a single taxonomy, is “NOT IN”.

To modify the query to return results that are “NOT IN” the custom taxonomy and terms that you’ve listed, add the following within your tax_query array:

'operator' => 'NOT IN',

Note: To experiment with results queried against multiple custom taxonomies, take a look at “Multiple Taxonomy Handling” under Taxonomy Parameters on the Codex reference for WP_Query.

Now that we’ve gone through that, we reference our newly created query with a loop. Here’s the code again:

<div class="resources">
	<h3>Latest Resources</h3>
	<ul id="resource-list">
		<?php while ( $resources->have_posts() ) : $resources->the_post(); ?>
			<li id="resource-<?php the_ID(); ?>" class="resource">
				<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
				<span><?php the_excerpt(); ?></span>
			</li>
		<?php endwhile; ?>
	</ul>
</div>

This is another basic instance of The Loop, customized to return results from our $resources query and, in this case, the results returned are “the_ID”, “the_permalink”, “the_title”, and “the_excerpt”.

Checking For Empty Results

In our example above, we have some code (like the <UL>) that appears outside of our loop. If there were no results, the “container” HTML would still show up in the template. To prevent that, we can preface it with a conditional statement like this:

<?php if ( $resources->post_count > 0 ) { // Check to make sure there are resources ?>
// Display your results
<?php } ?>

Replace “$resources” with the name of your custom query and return your results within the conditional statement. If the “post_count” is greater than zero (“> 0″), then the code will appear in your template – otherwise, the page remains free of extra HTML.

Hierarchical Custom Taxonomy Templates

Alright, now that we have a non-hierarchical taxonomy under our belt, let’s move on and tackle hierarchy. We covered the basics in setting up “presenters”, so let’s pick up there where we left off.

Create a file called taxonomy-topics.php and add the following code:

<?php get_header(); ?>

<?php // Get the data we need
	$topic = get_term_by( 'slug', get_query_var( 'term' ), get_query_var( 'taxonomy' ) );    

	$resources = new WP_Query(
		array(
			'post_type' => 'resource', // Tell WordPress which post type we want
			'posts_per_page' => '3', // Show the first 3
			'tax_query' => array( // Return only resources where presenter is listed
				array(
					'taxonomy' => 'topics',
					'field' => 'slug',
					'terms' => $topic->slug,
					)
				)
			)
		);
?>

	<div id="container">
		<div id="content" class="presenter">
			<h1 class="entry-title"><?php echo $topic->name; ?></h1>
			<p><?php echo $topic->description; ?></p>	

			<?php if ( $resources->post_count > 0 ) { // Check to make sure there are resources ?>
				<div class="resources">
					<h3>Latest Resources</h3>
					<ul id="resource-list">
						<?php while ($resources->have_posts()) : $resources->the_post(); ?>
							<li id="resource-<?php the_ID(); ?>" class="resource">
								<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
								<span><?php the_excerpt(); ?></span>
							</li>
						<?php endwhile; ?>
					</ul>
				</div>
			<?php } ?>

		</div>
	</div>

<?php get_footer(); ?>

Previewing a “topic” should now give you a familiar plain template that looks something like this:

Jon-wold-ap-screenshot3 in How To Build A Media Site On WordPress (Part 2)
A basic, yet useful view of another custom taxonomy term.

Creating Parent and Children Links

Now, the thing that is different with this taxonomy is that it can have both “parents” and “children”. What we want to do is check for a parent topic and, if it exists, display a link to it. We also want to check for sub-topics and if they exist, display links to them.

Note: For these examples to work, be sure that you’re working with a post example that has multiple levels of a hierarchical custom taxonomy associated with it. In my example, I have created topics 3 levels deep and associated all of them with the post.

So let’s get started. First, within the PHP section at the top of our template, add the following code:

if ( $topic->parent > 0 ) { // Check to make sure the topic has a parent
	$topic_parent = get_term( $topic->parent, 'topics' ); // Get the object for the topic's parent
} 	

$topic_children = get_terms( 'topics', 'child_of='.$topic->term_id );
$last_topic = end( array_keys( $topic_children ) ); // Mark the last topic

Alright, what do we have going on here? First, we’re checking to make sure the topic has a parent. If a topic does not have a parent, WordPress gives the “parent” attribute a value of zero (“0″). So, the first thing we do is a conditional to check and make sure that the parent has a value greater than zero. If it does, we define the variable $topic_parent and use the get_term function to retrieve the parent topic based on its ID.

Next, we define another variable called $topic_children. This time, we use the get_terms function, which has a special attribute called “child_of”. We pass in the value of the current topic and tell WordPress, in English, to “take the current topic and bring me back a list of all its sub-topics or children”.

Then, we define a variable called $last_topic. The data that $topic_children gives us is in the form of an array. Our $last_topic variable counts to the “end” of the array and keeps track of it. We’re going to use that later to put a comma after each of our sub-topics and then do nothing for the last sub-topic.

Now, to show the results, add the following code within your template:

<?php if ( $topic->parent > 0  ) { ?>
<strong>Parent:</strong> <a href="<?php echo get_term_link( $topic_parent->slug, 'topics' ); ?>"><?php echo $topic_parent->name; ?></a>
<?php } ?>

<?php if ( $topic_children ) { ?>
	<strong>Subtopics: </strong>
	<?php foreach ( $topic_children as $key => $topic_single ) : ?>
		<span><a href="<?php echo get_term_link( $topic_single->slug, 'topics' ); ?>"><?php echo $topic_single->name; ?></a></span><?php if ( $key !== $last_topic ) echo ', '; ?>
<?php endforeach; ?>
<?php } ?>

Each block of code first checks to make sure that a parent topic or sub-topic(s) exists, respectively. Then, in the case of the “parent”, we use the get_term_link function to retrieve the link by the “slug” of the $topic_parent.

For our sub-topics, we create a “foreach” loop to output a list of all sub-topics. At the end, we do a conditional check on the $last_topic in our array using the variable we created earlier. If it is not the last topic, we echo a comma after the close <span> – otherwise, we do nothing.

And there you have it! The result using the Twenty Ten theme will look something like this:

Pets-latest-resources in How To Build A Media Site On WordPress (Part 2)
A view of the “topics” taxonomy, with the parent topic and sub-topics listed.

Relating Taxonomies By Posts

Now, this is where we get a bit fancy. Let’s say we’re working on our template for the “topics” taxonomy and we wanted to show a list of “presenters” who covered that particular topic. How would we do that? In the code that follows, we’re going to use the custom posts themselves as our reference point and bring back the related custom taxonomies.

The rationale is simple. If we had 10 posts associated with a particular term in a given custom taxonomy, those 10 posts will likely have other terms from other custom taxonomies associated with them as well. So, we use the posts themselves to retrieve and compile the term data that would otherwise not be related to our particular term. Here are some examples where this might be especially useful:

  • Events - An “event” taxonomy where we want to show a list of “presenters” at that same event.
  • Movies - A “genre” taxonomy where we want to show a list of “directors” who make that same genre of film.
  • Recipes - A “category” taxonomy where we want to show related “ingredients”.

Alright, let’s dive into the code:

// Retrieve all the IDs for resources associated with the current term
$post_ids = array();
foreach ( $resources->posts as $post ) {
	array_push( $post_ids, $post->ID );
}

// Get presenter data based on the posts associated with the current term
$presenters_by_posts = wp_get_object_terms( $post_ids, "presenters" );

$topic_presenters = array();
foreach ( $presenters_by_posts as $presenter ){
	$topic_presenters[$presenter->term_id] = $presenter;
}
$last_presenter = end( array_keys( $topic_presenters ) );

First, we define an empty array called $post_ids. Then, we create a loop through each of the “resources” associated with our current term using the $resource query we created earlier. We take that loop and “push” each of the post IDs for our resources back into the previously empty $post_ids array.

Next, we define a new variable, $presenters_by_posts. We use the wp_get_object_terms function, which accepts either a single ID or an array of IDs (which we just created) to return a list of terms. In our case, we’re using this function to check all the custom posts associated with this term and bring back a list of all the “presenters”.

Next, we define another empty array called $topic_presenters. We now loop through our $presenters_by_posts and then redefine our $presenter variable to hold the term_id of each $presenter that we returned using our $presenters_by_posts function.

Now, let’s make use of that in the template. Add the following the code:

<?php if ( $topic_presenters ) { ?>
	<strong>Presenters:</strong>
	<?php foreach ( $topic_presenters as $key => $presenter ) : ?>
		<span><a href="<?php echo get_term_link( $presenter->slug, 'presenters' ); ?>"><?php echo $presenter->name; ?></a></span><?php if ( $key !== $last_presenter ) echo ', '; ?>
	<?php endforeach; ?>
<?php } ?>

Now, we simply loop through each of our $topic_presenters using our redefined $presenter. We then access the attribute values of our $presenter object to echo the “slug” for the term link and the term “name”. Finally, we do a check for the $last_presenter and if it is not the last one, we echo a comma.

Here’s how that looks in my example:

Pets-latest-resources2 in How To Build A Media Site On WordPress (Part 2)
The updated view of “Topics”, with a list of presenters related by custom posts.

Conclusion

And that’s a wrap! With part one and part two under your belt you have taken some solid steps above and beyond the basics of WordPress theme development. My goal has been to give you some solid examples that you can follow and to explain what’s been done along the way so you can apply what you’ve learned to your own projects. You’ve learned a lot about custom post types and custom taxonomies and I am looking forward to seeing what you build.

My next area of interest is a tutorial that teaches best practices for customizing the WordPress admin and building new backend interfaces for end-users to manage these increasingly complex media sites. I’m also interested in writing about how to build the front-end filtering interface, demonstrated in the ARISE resource center. If either of those interest you, please let me know.

Credits

As I mentioned in part one, the WordPress Stack Exchange community has been a huge help in sharing techniques and pointing out best practice solutions. If you have a question directly related to this post, ask it here. If you have anything else WordPress related, though, be sure to check out WPSE Also, a big thank you to all my team mates at Sabramedia for their patience with me and all their help testing and providing feedback.


© Jonathan Wold for Smashing Magazine, 2011. | Permalink | Post a comment | Smashing Shop | Smashing Network | About Us
Post tags:


How To Build A Media Site On WordPress (Part 1)

Advertisement in How To Build A Media Site On WordPress (Part 1)
 in How To Build A Media Site On WordPress (Part 1)  in How To Build A Media Site On WordPress (Part 1)  in How To Build A Media Site On WordPress (Part 1)

WordPress is amazing. With its growing popularity and continual development, it is becoming the tool of choice for many designers and developers. WordPress projects, though, are pushing well beyond the confines of mere “posts” and “pages”. How do you go about adding and organizing media and all its complexities? With the introduction of WordPress 3.1, several new features were added that make using WordPress to manage media even more practical and in this tutorial, we’re going to dive in and show you how.

Wordpress-media-site-part1 in How To Build A Media Site On WordPress (Part 1)

In part one, we’re going to setup custom post types and custom taxonomies, without plugins. After that, we’ll build a template to check for and display media attached to custom posts. Then, in part two, we’ll use custom taxonomy templates to organize and relate media (and other types of content).

As we focus on building a media centric site, I also want you to see that the principles taught in this series offer you a set of tools and experience to build interfaces for and organize many different types of content. Examples include:

  • A “Media” center, of any type, added to an existing WordPress site
  • A repository of videos, third party hosted (e.g. Vimeo, YouTube, etc), organized by topics and presenters
  • A music site, with streaming and song downloads, organized by bands and associated by albums
  • An author-driven Q&A site, with user submitted questions organized by topics and geographical location
  • A recipe site with videos and visitor ratings, organized by category and shared ingredients

In a future tutorial, we will focus on customizing the WordPress backend (with clients especially in mind) to manage a media site and in another tutorial we will use the foundation laid to build a dynamic filtering interface that allows visitors to quickly sort their way through hundreds or even thousands of custom posts.

Requirements

  • WordPress 3.1 – With the release of 3.1, several new features related to the use of custom post types and taxonomies were introduced that are essential to the techniques taught in this series.
  • Basic Familiarity with PHP (or “No Fear”) – To move beyond copying and pasting the examples I’ve given will require a basic familiarity with PHP or, at least, a willingness to experiment. If the code samples below are intimidating to you and you have the desire to learn, then I encourage you to tackle it and give it your best. If you have questions, ask in the comments.

Working Example

In April, 2011 we (Sabramedia, of which I am a co-founder) worked with an organization in Southern California to develop a resource center on WordPress to showcase their paid and free media products. On the front-end, we built a jQuery powered filtering interface to allow visitors to filter through media on-page. We’ll cover the ins and outs of building a similar interface in part three.

Screenshot-arise-illu in How To Build A Media Site On WordPress (Part 1)
The “Resource Center” on ARISE, with a custom taxonomy filter (“David Asscherick”) pre-selected.

Working With Custom Post Types

By default, WordPress offers two different types of posts for content. First, you have the traditional “postâ€�, used most often for what WordPress is known best for – blogging. Second, you have “pagesâ€�. Each of these, as far as WordPress is concerned, is a type of “postâ€�. A custom post type is a type of post that you define.

Note: You can learn more about post types on the WordPress Codex.

In this series, we are going to use custom post types to build a media based resource center. I will be defining and customizing a post type of “resource�.

Setting Up Your Custom Post Type

You can setup your custom post types by code or by plugin. In these examples, I will be setting up the post type by code, storing and applying the code directly in the functions file on the default WordPress theme, Twenty Ten. You can follow along by using a plugin to setup the post types for you or by copying the code samples into the bottom of your theme’s custom functions file (functions.php).

Note: As a best practice, unless you use an existing plugin to create the post types, you may want to consider creating your own WordPress plugin. Setting up custom post types and taxonomies separate from your theme becomes important if and when you want to make major changes to your theme or try a new theme out. Want to save some typing? Use the custom post code generator.

Alright, let’s setup our custom post type. Paste the following code into your theme’s functions.php:

add_action('init', 'register_rc', 1); // Set priority to avoid plugin conflicts

function register_rc() { // A unique name for our function
 	$labels = array( // Used in the WordPress admin
		'name' => _x('Resources', 'post type general name'),
		'singular_name' => _x('Resource', 'post type singular name'),
		'add_new' => _x('Add New', 'Resource'),
		'add_new_item' => __('Add New Resource'),
		'edit_item' => __('Edit Resource'),
		'new_item' => __('New Resource'),
		'view_item' => __('View Resource '),
		'search_items' => __('Search Resources'),
		'not_found' =>  __('Nothing found'),
		'not_found_in_trash' => __('Nothing found in Trash')
	);
	$args = array(
		'labels' => $labels, // Set above
		'public' => true, // Make it publicly accessible
		'hierarchical' => false, // No parents and children here
		'menu_position' => 5, // Appear right below "Posts"
		'has_archive' => 'resources', // Activate the archive
		'supports' => array('title','editor','comments','thumbnail','custom-fields'),
	);
	register_post_type( 'resource', $args ); // Create the post type, use options above
}

The code above tells WordPress to “register” a post type called “resource”. Then, we pass in our options, letting WordPress know that we want to use our own labels, that we want our post type to be publicly accessible, non-hierarchal, and that we want it to show up right below “posts” in our admin menu. Then, we activate the “archive” feature, new in WordPress 3.1. Finally, we add in “supports”: the default title field, the WordPress editor, comments, featured thumbnail, and custom fields (I’ll explain that  later).

Note: For more information on setting up the post type and for details on all the options you have (there are quite a few available), refer to the register_post_type function reference on the WordPress Codex.

If the code above was successful, you will see a new custom post type, appearing below “Posts” in the WordPress admin menu. It will look something like this:

Wordpress-screenshot-admin in How To Build A Media Site On WordPress (Part 1)
A view of the WordPress Admin, after adding a custom post type

We’re in good shape! Next, let’s setup our custom taxonomies.

Working With Custom Taxonomies

A “taxonomy” is a way of organizing and relating information. WordPress offers two default taxonomies, categories and tags. Categories are hierarchal (they can have sub-categories) and are often used to organize content on a more broad basis. Tags, are non-hierarchal (no sub-tags) and are often used to organize content across categories.

A “term” is an entry within a taxonomy. For a custom taxonomy of “Presenters”, “John Smith” would be a term within that taxonomy.

In this series, we will be creating two different custom taxonomies to organize the content within our resource center.

  • Presenters – Each media item in our resource center will have one or more presenters. For each presenter, we want to know their name and we want to include a short description. Presenters will be non-hierarchal.
  • Topics – Our resource center will offer media organized by topics. Topics will be hierarchal, allowing for multiple sub-topics and even sub-sub-topics.

Note: Interested in working with more than the title and short description? Take a look at How To Add Custom Fields To Custom Taxonomies on the Sabramedia blog.

Setting Up Presenters

Our goal with presenters is to create a presenter profile, referenced on the respective media pages, that will give more information about the presenter and cross-reference other resources that they are associated with.

Add the following code to your theme’s functions.php file:

$labels_presenter = array(
	'name' => _x( 'Presenters', 'taxonomy general name' ),
	'singular_name' => _x( 'Presenter', 'taxonomy singular name' ),
	'search_items' =>  __( 'Search Presenters' ),
	'popular_items' => __( 'Popular Presenters' ),
	'all_items' => __( 'All Presenters' ),
	'edit_item' => __( 'Edit Presenter' ),
	'update_item' => __( 'Update Presenter' ),
	'add_new_item' => __( 'Add New Presenter' ),
	'new_item_name' => __( 'New Presenter Name' ),
	'separate_items_with_commas' => __( 'Separate presenters with commas' ),
	'add_or_remove_items' => __( 'Add or remove presenters' ),
	'choose_from_most_used' => __( 'Choose from the most used presenters' )
); 

register_taxonomy(
	'presenters', // The name of the custom taxonomy
	array( 'resource' ), // Associate it with our custom post type
	array(
		'rewrite' => array( // Use "presenter" instead of "presenters" in the permalink
			'slug' => 'presenter'
			),
		'labels' => $labels_presenter
		)
	);

Let’s break that down. First, we setup the labels to be used when we “register” our taxonomy. Then, we give it a name, in this case “presenters”, and assign it to the post type of “resource”. If you had multiple post types, you would add them in with a comma, like this:

array( 'resource', 'other-type' ), // Associate it with our custom post types

After that,  we change the URL (or “permalink”) to satisfy our desire for grammatical excellence. Rather than being “/presenters/presenter-name” we update the “slug” (what is a slug?) to remove the “s” so that the permalink will read “/presenter/presenter-name”.

In our example, you should now notice a new menu option labeled “Presenters” under “Resources” in the admin sidebar. When you go to create a new resource you should also notice a meta box on the right side that looks like this:

Meta-box-wp-admin1 in How To Build A Media Site On WordPress (Part 1)
My custom taxonomy of "Presenters" now shows up between the "Publish" box and "Featured Image".

Note: To learn more about setting up custom taxonomies and the options available, take a look at the register_taxonomy function reference on the WordPress Codex.

Setting Up Topics

Our goal with topics is to allow for a hierarchal set of topics and sub-topics, each with their own page, showing the resources that are associated with each respective topic.

Add the following code to your theme’s functions.php file:

$labels_topics = array(
	'name' => _x( 'Topics', 'taxonomy general name' ),
	'singular_name' => _x( 'Topic', 'taxonomy singular name' ),
	'search_items' =>  __( 'Search Topics' ),
	'all_items' => __( 'All Topics' ),
	'parent_item' => __( 'Parent Topic' ),
	'parent_item_colon' => __( 'Parent Topic:' ),
	'edit_item' => __( 'Edit Topic' ),
	'update_item' => __( 'Update Topic' ),
	'add_new_item' => __( 'Add New Topic' ),
	'new_item_name' => __( 'New Topic Name' ),
); 

register_taxonomy(
	'topics', // The name of the custom taxonomy
	array( 'resource' ), // Associate it with our custom post type
	array(
		'hierarchical' => true,
		'rewrite' => array(
			'slug' => 'topic', // Use "topic" instead of "topics" in permalinks
			'hierarchical' => true // Allows sub-topics to appear in permalinks
			),
		'labels' => $labels_topics
		)
	);

That was easy enough! The code above is similar to setting up presenters, except this time we are using a few different labels, specific to hierarchal taxonomies. We set hierarchal to true (it’s set to “false” by default), we update the slug to be singular instead of plural, then, just before referencing our labels, we set the rewriting to be hierarchal. A hierarchal rewrite allows permalinks that look like this: /topic/topic-name/sub-topic-name.

With the above code implemented, you should notice another option below “Resources” in the WordPress admin and a new meta box that looks like this:

Tutorial-admin-4 in How To Build A Media Site On WordPress (Part 1)
My custom taxonomy of "Topics" now shows up, albeit a bit empty looking, below "Presenters".

Adding Custom Fields To Custom Post Types

In many cases, the “title” and “editor” (the default content editor in WordPress) aren’t going to be enough. What if you want to store extra information about a particular custom post? Examples might include:

  • Duration of a media file – HH:MM:SS format, useful to pre-populate your media player with the duration on page load.
  • Original recording date – Stored as a specific date with day, month, and year.

We call this “meta” information and it is a set of details that are specific to the individual item and usually make the most sense to store as meta data, as opposed to terms within a custom taxonomy. While you could put all these details in the “editor” field, it gives you very little flexibility with how this is displayed within your template.

So, let’s setup some custom fields. Use the custom fields interface at the bottom of an individual custom post to add some extra details about your custom post.

For our example, we’re going to add two fields. For each field, I will list the name, then an example value:

  • recording_length - Example: 00:02:34
  • recording_date – Example: March 16, 2011

Here’s how that looks after adding two custom fields:

Tutorial-admin-5 in How To Build A Media Site On WordPress (Part 1)
An example of the custom fields interface after adding two "keys" and their respective "values"

Note: The default custom fields interface can be a bit limiting. If you’d like to make use of a plugin, try More Fields. The functionality is the same (just be mindful of what you name your custom fields) – a plugin typically offers you a better interface. If you want to build your own interface, take a look at WP Alchemy. To learn more about using custom fields, take a look at using custom fields on the WordPress Codex.

Custom Taxonomies vs. Custom Fields

At this point, you may run into a situation where you’re uncertain whether a particular piece of information should be stored as a custom taxonomy or as a custom field. Let’s use the recording date as an example. If we were to log the complete date, then it would probably make the most sense to store it within a custom field on the individual item. If we were to just use the year, though, we could store it as a term within a custom taxonomy (we’d probably call it “year”) and use it to show other resources recorded that same year.

The question is whether or not you want to relate content (in our case, “resources”) by the information you’re considering. If you don’t see any need to relate content (and don’t have plans to) then a custom field is the way to go. If you have a need to relate content or see a potential need down the road, then a custom taxonomy is the way to go.

Media Storage – WordPress vs. Third Party

Now that we have our custom post type and custom taxonomies in place, it’s time to upload some media. Our goal is to make this as simple a process for the end-user as possible. There are two ways that we can manage the media, either directly within WordPress or via third party.

  • WordPress Managed - WordPress has a media management system built-in. You can upload media directly from your post type interface or from the “media” section in the WordPress admin. If storage or bandwidth becomes an issue, you can use a plugin (such as WP Super Cache) to offload the storage of the media to a third party content delivery network (CDN) to optimize delivery speed and save on bandwidth.
  • Third Party – Going this route, you can use a media hosting service like YouTube, Vimeo, Scribd (PDFs), Issuu (ebooks), or any media hosting service that offers you an embed option.

Going the internal route, the media is stored inside of WordPress and associated with the individual custom post. We then access it as an attachment within the template. Going the third party route, we get the embed code (or the media ID) and store it inside of WordPress within a custom field. We’ll look at examples of both options further on.

Note: Working with images? Take a look at a recent Smashing article that covers better image management with WordPress.

Preparing The Stage – Adding New Media

We’re about to start working with the templates. Before we do that, though, we need to have some media to work with within our new custom post type. Before proceeding, make sure you’ve done the following:

  • Create a new “resource” post (or whatever your post type may be) and give it a title and a description in the main content editor.
  • Associate your resource with a non-hierarchical custom taxonomy you’ve created (e.g. A presenter named “Jonathan Wold”).
  • Associate your resource with a hierarchical custom taxonomy you’ve created (e.g. A topic of “Family” and a sub-topic of “Children”)
  • Add one or more custom fields with a unique “key” and “value” (e.g. a key of “recording_duration” and a value of “00:02:34″).
  • Upload a video file to your custom post using the WordPress media manager (click the “video” icon just below the title field and right above the editor).

Note: If you’re hosting your videos via third party, create a custom field to hold either the entire embed code or the ID of the video. I’ll give you an example using Vimeo a bit later that will use the video ID.

Note #2: Depending on your hosting provider, you may run into trouble with a default upload limit, often 2MB or 8MB. Check out how to increase the WordPress upload limit.

After you’ve created a new post, previewing it should show you a screen, depending on your theme, will look something like this:

Tutorial-frontend-1 in How To Build A Media Site On WordPress (Part 1)
A preview of my custom post, displaying title and description, on the Twenty Ten theme.

Note: If you preview your post and get a “404″ error, you may need to update your Permalinks. From the WordPress Admin, Go to “Settings”, then “Permalinks”, and click “Save Changes”. Refresh and you should be good to go.

Displaying Our Media – Working With Custom Post Templates

If you previewed your custom post, you probably saw something similar to what I showed in my example – not much. Where are the custom taxonomy terms, custom fields, and videos? Missing – but not for long! In the following steps, we’re going to create a custom template that tells WordPress what data to display and how to display it.

Creating A Custom Post Type Template

The WordPress template engine has a hierarchy that it follows when deciding what theme template it uses to display data associated with a post. In the case of our “resource” post type, the WordPress hierarchy (as of 3.1) is as follows:

  • single-resource.php – WordPress will check the theme folder for a file named single-resource.php, if it exists, it will use that file to display the content. For different post types, simple replace “resource” with the name of your custom post type.
  • single.php – If no post type specific template is found, the default single.php is used. This is what you probably saw if you did an early preview.
  • index.php – If no single template is found, WordPress defaults to the old standby – the index.

I’ll be using minimal examples for each of the templates, modified to work with Twenty Ten. Each example will replace and build on the previous example. Expand to your heart’s content or copy the essentials into your own theme.

To get started with our example, create a file called single-resource.php and upload it to your theme folder. Add the following code:

<?php get_header(); ?>

	<div id="container">
		<div id="content">
		<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>

			<div class="resource">
				<h1 class="entry-title"><?php the_title(); ?></h1>
				<div class="entry-content">
					<?php the_content();?>
				</div>
			</div>

		<?php endwhile; ?>
		</div>
	</div>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

The code above will give you a rather unexciting, but working template that will display the title and content (drawn directly from the main editor). What about our custom fields? Let’s add them in next.

Replace the code in single-resource.php with the following:

<?php get_header(); ?>

<?php // Let's get the data we need
	$recording_date = get_post_meta( $post->ID, 'recording_date', true );
	$recording_length = get_post_meta( $post->ID, 'recording_length', true );
?>

	<div id="container">
		<div id="content">
		<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>

			<div class="resource">
				<h1 class="entry-title"><?php the_title(); ?></h1>
				<div class="entry-meta">
					<span>Recorded: <?php echo $recording_date ?> | </span>
					<span>Duration: <?php echo $recording_length ?> </span>
				</div>
				<div class="entry-content">
					<?php the_content();?>
				</div>
			</div>

		<?php endwhile; ?>
		</div>
	</div>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

We’re making progress! Now, using the examples above, you should see the date your resource was published and the duration of the media file.

Let’s take a look at how that works. In WordPress, data stored in custom fields can be accessed several ways. Here, we are using a function called get_post_meta. This function requires two parameters, the unique ID of the post you want to get the data from and the name of the field (its “key”) whose data you’re after. Here’s the code again:

$recording_date = get_post_meta( $post->ID, 'recording_date', true );

First, we set a variable with PHP – we name it “$recording_date”. Then, we use the “get_post_meta” function. Remember, it needs two parameters, ID and the “key” of the field we want. “$post->ID” tells WordPress to use the ID of the post it is currently displaying. If we wanted to target a specific post, we’d put its ID instead:

$recording_date = get_post_meta( 35, 'recording_date', true ); // Get the date from post 35

The next parameter is the “key”, or “name” of our custom field. Be sure you get that right. The last parameter tells the function to return the result as a single “string” – something that we can use as text in our template below. To display our data in the template, we write:

<?php echo $recording_date ?>

Ok, let’s keep going and get our custom taxonomies showing up.

Replace the code in single-resource.php with the following:

<?php get_header(); ?>

<?php // Let's get the data we need
	$recording_date = get_post_meta( $post->ID, 'recording_date', true );
	$recording_length = get_post_meta( $post->ID, 'recording_length', true );
	$resource_presenters = get_the_term_list( $post->ID, 'presenters', '', ', ', '' );
	$resource_topics = get_the_term_list( $post->ID, 'topics', '', ', ', '' );
?>

	<div id="container">
		<div id="content">
		<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>

			<div class="resource">
				<h1 class="entry-title"><?php the_title(); ?></h1>
				<div class="entry-meta">
					<span>Recorded: <?php echo $recording_date ?> | </span>
					<span>Duration: <?php echo $recording_length ?> | </span>
					<span>Presenters: <?php echo $resource_presenters ?> | </span>
					<span>Topics: <?php echo $resource_topics ?></span>
				</div>
				<div class="entry-content">
					<?php the_content();?>
				</div>
			</div>

		<?php endwhile; ?>
	 	</div>
 	</div>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Now we’re starting to get more dynamic. You should see your custom fields and, assuming that your custom post has “presenters” and “topics” associated with it, you should see a list of one or more custom taxonomy terms as links. If you clicked the link, you probably saw a page that didn’t look quite what you expected – we’ll get to that soon. Check out get_the_term_list on the WordPress Codex to learn more about how it works.

Adding A Media Player

Now that we have some basic data in place, it’s time to add our media player. In this example, we will be working with the JW Media Player, a highly customizable open-source solution.

Installing JW Media Player

You can access basic installation instructions here. I recommend the following steps:

  1. Download the player from the Longtail Video website.
  2. Create a folder within your theme to hold the player files – In this case, I’ve named the folder “jw”.
  3. Upload jwplayer.js and player.swf to the JW Player folder within your theme.

JW Player is now installed and ready to be referenced.

Now, replace the code in single-resource.php with the following:

<?php get_header(); ?>

<?php // Let's get the data we need
	$recording_date = get_post_meta( $post->ID, 'recording_date', true );
	$recording_length = get_post_meta( $post->ID, 'recording_length', true );
	$resource_presenters = get_the_term_list( $post->ID, 'presenters', '', ', ', '' );
	$resource_topics = get_the_term_list( $post->ID, 'topics', '', ', ', '' );	

	$resource_video = new WP_Query( // Start a new query for our videos
	array(
		'post_parent' => $post->ID, // Get data from the current post
		'post_type' => 'attachment', // Only bring back attachments
		'post_mime_type' => 'video', // Only bring back attachments that are videos
		'posts_per_page' => '1', // Show us the first result
		'post_status' => 'inherit', // Attachments require "inherit" or "all"
		)
	);
?>

	<div id="container">
		<div id="content">
		<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>

			<div class="resource">
				<h1 class="entry-title"><?php the_title(); ?></h1>
				<div class="entry-meta">
					<span>Recorded: <?php echo $recording_date ?> | </span>
					<span>Duration: <?php echo $recording_length ?> | </span>
					<span>Presenters: <?php echo $resource_presenters ?></span>
				</div>
				<div class="entry-content">
					<?php while ( $resource_video->have_posts() ) : $resource_video->the_post(); ?>
						<p>Video URL: <?php echo $post->guid; ?></p>
					<?php endwhile; ?>

					<?php wp_reset_postdata(); // Reset the loop ?>

					<?php the_content(); ?>
				</div>
			</div>

		<?php endwhile; ?>
		</div>
	</div>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Note: You may notice the somewhat mysterious reference to “wp_reset_postdata”. We are creating a loop within a loop and, to prevent strange behavior with template tags like “the_content” (try removing “wp_reset_postdata” to see what happens), we need to run a reset after any new loops we add within the main loop. Learn more about the loop on the WordPress Codex.

Now we’re getting somewhere! If everything went as expected, you should see a direct, plain text URL to your video. That’s not very exciting (yet), but we want to make sure we are getting that far before we add in the next step – the player.

If you’re having trouble at this point, check back through your code and look for any mistakes that may have been made. If you are trying to vary widely from this example, simplify your variations and start as close to this example as you can – get that to work first then branch back out.

With the URL to our video available, we are ready to add in the player. Let’s go!

Replace the code in single-resource.php with the following:

<?php get_header(); ?>

<?php // Let's get the data we need
	$recording_date = get_post_meta( $post->ID, 'recording_date', true );
	$recording_length = get_post_meta( $post->ID, 'recording_length', true );
	$resource_presenters = get_the_term_list( $post->ID, 'presenters', '', ', ', '' );
	$resource_topics = get_the_term_list( $post->ID, 'topics', '', ', ', '' );

	$resource_video = new WP_Query( // Start a new query for our videos
	array(
		'post_parent' => $post->ID, // Get data from the current post
		'post_type' => 'attachment', // Only bring back attachments
		'post_mime_type' => 'video', // Only bring back attachments that are videos
		'posts_per_page' => '1', // Show us the first result
		'post_status' => 'inherit', // Attachments require "inherit" or "all"
		)
	);
?>

	<div id="container">
		<div id="content">
		<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>

			<div class="resource">
				<h1 class="entry-title"><?php the_title(); ?></h1>
				<div class="entry-meta">
					<span>Recorded: <?php echo $recording_date ?> | </span>
					<span>Duration: <?php echo $recording_length ?> | </span>
					<span>Presenters: <?php echo $resource_presenters ?> | </span>
					<span>Topics: <?php echo $resource_topics ?></span>
				</div>

				<div class="entry-content">
				<?php while ( $resource_video->have_posts() ) : $resource_video->the_post(); // Check for our video ?>
					<div id="player">
						<script type="text/javascript" src="<?php bloginfo('stylesheet_directory'); ?>/jw/jwplayer.js"></script>
						<div id="mediaspace">Video player loads here.</div>
						<script type="text/javascript">
						    jwplayer("mediaspace").setup({
						        flashplayer: '<?php bloginfo( 'stylesheet_directory' ); ?>/jw/player.swf',
						        file: '<?php echo $post->guid; ?>',
						        width: 640,
						        height: 360
						    });
						</script>
					</div>
				<?php endwhile; ?>				

				<?php wp_reset_postdata(); // Reset the loop ?>

				<?php the_content(); ?>
				</div>
			</div>

		<?php endwhile; ?>
		</div>
	</div>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Note carefully the assumptions I’m making in the code above. First, I am assuming that you are storing the JW player files in a folder called “jw” inside the WordPress theme folder of the currently activated theme. If you load the page and the player is not working (and you did have the video URL displaying in the previous step), view the source code on your page, copy the URLs that WordPress is generating to your respective JW player files (jwplayer.js and player.swf) and try accessing them in your browser to make sure each is valid. If there is a problem, update your references accordingly.

Otherwise, there you have it! Your video details and the video itself is now displaying on the page and you should see something like this:

Tutorial-frontend-complete-e1305143493456 in How To Build A Media Site On WordPress (Part 1)
A view of the player, complete with title, description, custom field values and custom taxonomies terms.

Note: There is a lot that you can do to customize the appearance and behavior of the JW Player. A good place to start is the JW Player Setup Wizard. Customize the player to your liking, then implement the code changes in your template accordingly.

Using Vimeo Instead

Let’s say you wanted to use Vimeo, instead of uploading the videos into WordPress. First, you need to add a custom field to store the ID of your Vimeo video. Assuming you’ve done that, and assuming that you’ve entered a valid Vimeo ID in your custom field (we named the field “vimeo_id” in our example), the following code will work:

<?php get_header(); ?>

<?php // Let's get the data we need
	$recording_date = get_post_meta( $post->ID, 'recording_date', true );
	$recording_length = get_post_meta( $post->ID, 'recording_length', true );
	$resource_presenters = get_the_term_list( $post->ID, 'presenters', '', ', ', '' );
	$resource_topics = get_the_term_list( $post->ID, 'topics', '', ', ', '' );

	$vimeo_id = get_post_meta( $post->ID, 'vimeo_id', true );
?>

	<div id="container">
		<div id="content">
		<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>

			<div class="resource">
				<h1 class="entry-title"><?php the_title(); ?></h1>
				<div class="entry-meta">
					<span>Recorded <?php echo $recording_date ?> | </span>
					<span>Duration: <?php echo $recording_length ?> | </span>
					<span>Presenters: <?php echo $resource_presenters ?> | </span>
					<span>Topics: <?php echo $resource_topics ?></span>
				</div>

				<div class="entry-content">
					<?php if ($vimeo_id) { // Check for a video ?>
						<iframe src="http://player.vimeo.com/video/<?php echo $vimeo_id; ?>?byline=0&title=0&portrait=0" width="640" height="360" frameborder="0" class="vimeo"></iframe>
					<?php } ?>

					<?php the_content(); ?>
				</div>
			</div>

		<?php endwhile; ?>
		</div>
	</div>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

We use “$vimeo_id” to retrieve and store the ID from our custom field (named “vimeo_id”, in this case) and then, in the code below, we first check to make sure the $vimeo_id field has data in it, then we use Vimeo’s iframe code (details here) to load the video.

Tutorial-vimeo-id in How To Build A Media Site On WordPress (Part 1)
In Vimeo's case, the ID is a series of numbers (notice the selected text) after "vimeo.com/".

Conclusion

And that concludes part one! You’ve learned how to setup custom post types and custom taxonomies without using plugins. You’ve also learned how to setup custom fields and display their data, along with a video player and custom taxonomy terms, within a custom post template. In part two, we’ll look at how to customize the custom taxonomy templates and make them a whole lot more useful. Stay tuned!

Credits

Though this article keeps things basic, the conclusions in part two and a lot of the techniques developed in conjunction with the projects that inspired this series would have been much more difficult without the help of the WordPress Stack Exchange community. If you have a question directly related to this post, ask it here. If you have anything else WordPress related, though, WPSE is the place to go. Also, a big thank you to Joshua, Nick, CJ, and Matt for their many hours spent reviewing, testing code samples, and providing feedback while I worked on this series.


© Jonathan Wold for Smashing Magazine, 2011. | Permalink | Post a comment | Smashing Shop | Smashing Network | About Us
Post tags: ,


  •   
  • Copyright © 1996-2010 BlogmyQuery - BMQ. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress